sequence
The eighteen set-ups of *Stained Glass Day* and its whole mix, both as pure functions of film time. Registered with `demo.film` as the slice `sequence`.
sequence — the camera and the sound
The eighteen set-ups of Stained Glass Day and its whole mix, both as pure
functions of film time. Registered with demo.film as the slice sequence.
local Seq = require("demo.sequence")
Seq.check() -- every claim this slice makes about itself, as data
Seq.station(9, 0.5) -- eye, look, fov, up at the middle of shot 9
Seq.lens(t) -- { fov, focusDistance, shot } — for whoever racks focus
Seq.mix(t) -- every level in the mix at film time t
Seq.patch(t) -- where the window's image lands, and on what surface
The set-ups
SETUPS[n] carries the frame shot n opens on (eyeA / lookA / fovA), the
frame it ends on when it moves (eyeB / lookB / fovB), and how it travels
between them (ease: linear for a constant-velocity creep, smooth for a
push or a descent). Two shots take their pose from a function of film time
instead:
- 6 dollies east at exactly the projection's own velocity, so the patch is still and the room slides past it.
- 11 arcs on a circle around the wedge rather than on a chord, so the move reads as an orbit and not as a slide.
Shot 18 is shot 1, by table identity — the same Setup appears at both
indices, so no later nudge can separate the film's first station from its last.
check().shot18IsShot1 asserts it with rawequal, and the two mid-frames come
back bit-identical.
Shot 8 looks straight up, which has no yaw to derive a roll from, so it states
its image-up explicitly (up = { 0, 0, 1 }, north at the top of frame) and is
posed from Transform.quatFromBasis rather than lookAtQuat.
Where the light is
Shots 5 and 6 are anchored to the projection, not to a mark on the floor, so the
camera and the light cannot drift apart. The landing point comes from
Film.sunDirection(t) with its z component negated: as demo.film returns
it, solar noon (azimuth 183.9) gives dz = -0.485, which sends the light south
through the window rather than north into the hall. The window is the south wall
at z = -6 and the mezzanine is the north side at z = +6.
The mix
Ten sources, built once and never restarted; only their levels move, and every
level is a pure function of t.
| source | what it is | what moves it |
|---|---|---|
tone_dry / tone_full | the room's own air, dead and thick | Film.air(t), crossfaded |
town | a town on the other side of a windowless wall | a day curve, waking to working to quiet |
stone | limestone taking the sun and giving it back | ` |
swallow_w / swallow_e | the colony in the mezzanine capitals | a keyframed schedule: waking, working, streaming back at dusk, settling |
score1 … score4 | four movements, one per act | raised-cosine windows crossing inside each other's fades |
The clips are baked by /source/demo/sequence/bake_audio.luau into
sounds/sequence — mono 24 kHz, each loop-seamed by an equal-power crossfade of
its own tail over its own head, each peak-normalised. Re-bake one at a time:
execute { file = "/source/demo/sequence/bake_audio.luau", args = { only = "score_3" } }
The ears are the AudioListener on film_camera, so every spatial source is
heard from wherever the lens is standing.
Scoped to this part · feeds back into the world's score.