preseed/parts/p_tesla.module — DISCHARGE: a tesla coil in an industrial
high-voltage test hall (preseed.teslahall builds the environment). Sixteen
plasma arcs share one GPU mesh whose vertices a compute pass (ptes_arcs)
rewrites every frame: two standing power arcs into grounded strike masts,
four strikers that leader-grow to the hall's grounded equipment and hold
as re-striking power arcs, two dim violet air streamers, two ground
crawlers, four toroid brush-corona fans and two upward connecting leaders
that rise from the target a striker is about to hit — plus twenty
re-rolling branches. Channels are frozen between re-strikes (dart clock,
50-100 ms) and drift buoyantly upward while held (banjo). Music stabs
surge the arcs and snap their endpoints; every attach throws a spark
burst, flares the hall shaders, browns out the high-bay lamps and chases
the impact light to the contact.
The part is a power run-up: the coil enters thin and sputtering and
overdrives across POWER_T seconds — width, brightness, strike rate and
reach all climb (displacement noise never scales; frozen channels must
not breathe). Past OBJ_PW the strikers' target pool grows to include
loose props staged around the pad: hits throw sparks, embers, smoke and
debris and knock the props over (frozen kinematic bodies go dynamic with
a kick), and struck drums cook off — fireball, smoke column, shock ring,
blast light and a radial impulse that scatters everything nearby.
claim(name: string, elem: string, len: number, usage: { string }?) → any
Editing this module resets the handles above, so a copy that always allocated
would leave the previous one's buffers with nothing holding them and hand the
GPU a fresh set every reload — while the ribbon on screen still draws from the
old ones. The shader remembers what it made under each name, so a buffer of the
right length is taken over and reused; only a changed length allocates, and the
old one goes when it does.
| arg | type | description |
|---|
| name | string | |
| elem | string | |
| len | number | |
| usage | { string }? | |
topEdge(toward: ?) → void
| arg | type | description |
|---|
| toward | ? | |
domePoint(az: ?, el: ?, r: ?) → void
| arg | type | description |
|---|
| az | ? | |
| el | ? | |
| r | ? | |
initArcs(targets: ?) → void
| arg | type | description |
|---|
| targets | ? | |
restrikeDart(a: ?, dt: ?) → void
dart clock: while a channel holds, it re-strikes every 50-100 ms — fine
path detail and the branch set re-roll, brightness pulses, and every so
often the channel blanks for a couple of frames
driveArcs(ctx: ?, t: ?, dt: ?) → void
| arg | type | description |
|---|
| ctx | ? | |
| t | ? | |
| dt | ? | |
pushParams(ctx: ?, t: ?) → void
| arg | type | description |
|---|
| ctx | ? | |
| t | ? | |
buildMast(ctx: ?, rod: ?, ri: ?, mastSteel: ?) → void
| arg | type | description |
|---|
| ctx | ? | |
| rod | ? | |
| ri | ? | |
| mastSteel | ? | |
add(geom: ?, pos: ?, rot: ?) → void
| arg | type | description |
|---|
| geom | ? | |
| pos | ? | |
| rot | ? | |
tadd(geom: ?, pos: ?) → void
| arg | type | description |
|---|
| geom | ? | |
| pos | ? | |
applyHallLook( ) → void
The sky, the sun, the ambient and the clear colour are the ROOM's, not the
part's content, and the director may call build up to a second before the cut
while the outgoing part is still on screen. Setting them from build paints
another part's last second with this hall's midnight. They belong in enter,
which is always called at the boundary, and this is where they live.
maps(set: ?, opts: ?) → void
| arg | type | description |
|---|
| set | ? | |
| opts | ? | |
put(list: ?, geom: ?, pos: ?, rot: ?) → void
| arg | type | description |
|---|
| list | ? | |
| geom | ? | |
| pos | ? | |
| rot | ? | |
tubeTo(list: ?, a: ?, b: ?, r: ?, segs: ?) → void
| arg | type | description |
|---|
| list | ? | |
| a | ? | |
| b | ? | |
| r | ? | |
| segs | ? | |
phys(name: ?, pos: ?, half: ?) → void
frozen kinematic bodies on box colliders; a hit flips them dynamic
with a kick, drums cook off. Invisible static floor + pad boxes give
the tumbling props something to land on
| arg | type | description |
|---|
| name | ? | |
| pos | ? | |
| half | ? | |
victim(kind: ?, geomList: ?, matSpec: ?, pos: ?, yaw: ?, half: ?, mass: ?, strikeY: ?, boom: ?) → void
matSpec is { props, textures } — a struck prop is the closest thing to the
camera in this part, so it carries the same real surface maps as the hall
| arg | type | description |
|---|
| kind | ? | |
| geomList | ? | |
| matSpec | ? | |
| pos | ? | |
| yaw | ? | |
| half | ? | |
| mass | ? | |
| strikeY | ? | |
| boom | ? | |
light(name: ?, pos: ?, color: ?, intensity: ?, radius: ?, shadows: ?) → void
lights: coil flash, roving impact, motivated hall rig (flood, high-bays,
beacons, console) and warm service uplights on the coil base
| arg | type | description |
|---|
| name | ? | |
| pos | ? | |
| color | ? | |
| intensity | ? | |
| radius | ? | |
| shadows | ? | |
moonSpot(name: ?, pos: ?, target: ?, brightness: ?, range: ?, angle: ?) → void
The north wall carries six panes at y 16.5, z -19.9, spaced 7 m from
x -17.5. `tes_floor` already draws the pools those panes throw on the
slab; nothing was throwing the beam that makes them, so the wall, the
deck, the gantry and the truss chords above head height had no source at
all and read as black. One spot per pane, aimed down-and-in the way the
moon actually falls through a window that high, plus two wide shadowless
fills riding the truss line so the roof structure has a value to sit at
between discharges. Every one is part-local: they light this hall and
reach nothing in the parts either side of it.
The cone is the entity's own forward, so each pane's spot is spawned,
placed, and then AIMED at the patch of slab the floor shader already
draws a pool on — `Transform.lookAt` writes the rotation that puts
Front on that point, which is the axis SpotLight reads.
| arg | type | description |
|---|
| name | ? | |
| pos | ? | |
| target | ? | |
| brightness | ? | |
| range | ? | |
| angle | ? | |
claimProbes(ids: ?) → void
Probes are registered by `probeId`, and a probe already standing under that
id is a leftover from a previous entry: the slot table holds eight, so a part
re-entered a few times exhausts it and a LATER part silently gets no probe at
all. Claiming the ids means an entry always starts from none of its own.
unfreezeVictim(v: ?) → void
knockFx(ctx: ?, wp: ?, big: ?) → void
| arg | type | description |
|---|
| ctx | ? | |
| wp | ? | |
| big | ? | |
kickVictim(ctx: ?, v: ?, speed: ?) → void
kick a prop away from the coil, freeing anything stacked on or against it
| arg | type | description |
|---|
| ctx | ? | |
| v | ? | |
| speed | ? | |
explode(ctx: ?, v: ?) → void
| arg | type | description |
|---|
| ctx | ? | |
| v | ? | |
hitVictim(ctx: ?, vi: ?, t: ?) → void
| arg | type | description |
|---|
| ctx | ? | |
| vi | ? | |
| t | ? | |
update(ctx: ?, t: ?, dt: ?) → void
| arg | type | description |
|---|
| ctx | ? | |
| t | ? | |
| dt | ? | |