quad(w: number, h: number) → Geom
A flat quad in the XY plane facing +Z, its origin at the BOTTOM centre so a
card placed at ground level stands on it. `uv.y` is 0 at the base, 1 at the
top; `uv.x` runs 0 → 1 left to right.
| arg | type | description |
|---|
| w | number | |
| h | number | |
sheet(w: number, h: number, nx: number, ny: number, uOffset: number) → Geom
The same quad, subdivided, so a vertex hook has something to bend. `uOffset`
shifts the U coordinate of the whole sheet: two curtains built with different
offsets read the same noise field at different places and never move in
unison.
| arg | type | description |
|---|
| w | number | |
| h | number | |
| nx | number | |
| ny | number | |
| uOffset | number | |
sleeve(r: number, h: number, segs: number) → Geom
An open tube around the Y axis, from y = 0 to y = h. `uv.y` runs along it and
`uv.x` around it, which is the parameterisation the `discharge` shader wants:
filaments crawl along the conductor or up the insulator stack. Wound so both
faces draw, since the sleeves are all `cull: none`.
| arg | type | description |
|---|
| r | number | |
| h | number | |
| segs | number | |
mesh(g: Geom, name: string) → any
| arg | type | description |
|---|
| g | Geom | |
| name | string | |
handle(ref: any, label: string?) → any
The runtime handle `ecs.Material` wants, from an already-resolved reference.
The resolve itself stays at the call site and stays a LITERAL: a world refuses
to publish while any `asset.resolve` in it takes a computed identity, because
a reference that is only known at run time cannot be pinned into the content
that travels. So a caller resolves its own material by a spelled-out name and
hands the result here, and this only unwraps it.
| arg | type | description |
|---|
| ref | any | |
| label | string? | |
set(handle: any, name: string, value: any) → void
| arg | type | description |
|---|
| handle | any | |
| name | string | |
| value | any | |
card(g: Geom, handle: any, opts: CardOpts) → any
Hang a mesh + material on an entity of this name, REUSING one that is already
standing rather than spawning a second.
Despawning goes through the deferred queue, so a rebuild that clears the old
content and builds the new one inside a single flush ends up with both — a
scene reload and a module hot-reload landing near each other is enough to do
it. Building by name instead of by spawn makes a rebuild idempotent whatever
order those two arrive in.
| arg | type | description |
|---|
| g | Geom | |
| handle | any | |
| opts | CardOpts | |
pump(sys: any, dt: number, live: boolean, ox: number, oy: number, oz: number) → void
Place a sprite emitter and step it, keeping one particle in it at all times.
A GPU sprite emitter holding no live particle still submits a blended draw,
and that draw reaches the renderer's blended batching with nothing to sort by:
the comparison stops being a total order and Rust aborts the process from
inside `render_frame`. Reproduced three times on this engine — an idle emitter
standing while `effects.play` adds one more blended draw kills it every time,
and the same moment with one particle in each emitter survives.
So an emitter that is not emitting keeps exactly one particle, parked six
kilometres under the plain where no set-up in the film can see it. `live` says
the emitter is filling itself and needs none of this.
| arg | type | description |
|---|
| sys | any | |
| dt | number | |
| live | boolean | |
| ox | number | |
| oy | number | |
| oz | number | |
tag(sys: any, name: string) → void
Rename a particle system's own render entity into the slice's `stm_*` space.
The emitters are held in module locals, and a hot-reload of the module that
made them drops those locals on the floor; naming the entity they draw
through is what lets the rebuild sweep the old ones out with everything else.
| arg | type | description |
|---|
| sys | any | |
| name | string | |
pitch(deg: number) → void
The quaternion for a rotation of `deg` degrees about the X axis. A negative
angle leans a card's top toward -Z, which is north.
| arg | type | description |
|---|
| deg | number | |
yaw(deg: number) → void
The quaternion for a rotation of `deg` degrees about the Y axis.
| arg | type | description |
|---|
| deg | number | |
yawPitch(yawDeg: number, pitchDeg: number) → void
Yaw then pitch, as one quaternion (yaw applied first).
| arg | type | description |
|---|
| yawDeg | number | |
| pitchDeg | number | |
ribbon(from: { number }, to: { number }, eye: { number }) → void
Stand a ribbon between two world points and turn its face toward `eye`.
Returns the quaternion and the span's length: the card is built `1` unit tall
and scaled to the span, so one mesh serves every gap the film jumps.
| arg | type | description |
|---|
| from | { number } | |
| to | { number } | |
| eye | { number } | |
alongY(from: { number }, to: { number }) → void
Rotate a card so its +Z face looks from `from` toward `to`, used to stand a
sleeve along a conductor. Returns the quaternion turning local +Y onto the
chord, plus the chord's length.
| arg | type | description |
|---|
| from | { number } | |
| to | { number } | |