game/staging/staging.module — the beats KESSREL LINE stages around the
battle, and the voice on the net that narrates them.
Four jobs, all of them driven by `ui.screens.Screens` calling `update(dt)`:
1. THE OPENING. A camera move from the Gate of Harrow, up the line, to the
Maw at the canyon head, and back to the commander's station, while
brief_1..3 are spoken and subtitled. Skippable at any moment.
2. THE BEATS. The wave call, the titan's arrival (the camera holds on it),
and the resolution — the ship lifting over the Gate, or the breach.
3. THE NET. Lieutenant Oyelaran answers what the battle reports: a wave
releasing, a regiment breaking, the Gate taking hits, an ability away.
One speaker, one line at a time, in priority order, never stacked.
4. THE CAMERA. A beat TAKES the commander's rig: it stands the
`game.command.CommanderCam` behaviour down, drives the rig's pose
itself in world space through `@builtin::controller.camera_rig`, and
stands the behaviour back up when the beat is over — so the camera
returns to wherever the commander had it, and this module never
depends on which fields that behaviour happens to carry.
local Stage = require("game.staging.staging")
Stage.attach() -- once, from Screens.awake
Stage.update(dt) -- every frame
Stage.view() -- the StageView the overlay is built from
at(camX: number, camY: number, camZ: number, lookX: number, lookY: number, lookZ: number) → Pose
| arg | type | description |
|---|
| camX | number | |
| camY | number | |
| camZ | number | |
| lookX | number | |
| lookY | number | |
| lookZ | number | |
commanderPose( ) → Pose
Where the commander's own behaviour would put the camera. Every field is
read softly with a fallback, so this composes with whatever shape the
command slice's behaviour has settled on.
num(name: string, fallback: number) → number
| arg | type | description |
|---|
| name | string | |
| fallback | number | |
writePose(p: Pose) → void
lerpPose(a: Pose, b: Pose, t: number) → Pose
| arg | type | description |
|---|
| a | Pose | |
| b | Pose | |
| t | number | |
smooth(t: number) → number
| arg | type | description |
|---|
| t | number | |
startTrack(from: Pose, legs: { Leg }, cues: { Cue }, onDone: (() → void
| arg | type | description |
|---|
| from | Pose | |
| legs | { Leg } | |
| cues | { Cue } | |
| onDone | (( | |
tickTrack(dt: number) → void
| arg | type | description |
|---|
| dt | number | |
speak(id: string) → void
The subtitle is set on this stack, so a line reaches the screen even when the
voice does not; the spoken half goes out on a stack of its own, because an
audio implementation that raises must never stop a beat.
| arg | type | description |
|---|
| id | string | |
lineSeconds(id: string) → number
| arg | type | description |
|---|
| id | string | |
say(id: string, priority: number) → void
priority: 0 chatter, 1 wave call, 2 briefing / ending — the ones that must
never be dropped or cut off by anything else.
| arg | type | description |
|---|
| id | string | |
| priority | number | |
clock( ) → number
Seconds of staging time that have passed — how far `update(dt)` has been driven.
speaking( ) → boolean
Whether the net is mid-line right now.
banner(word: string, sub: string?, seconds: number) → void
| arg | type | description |
|---|
| word | string | |
| sub | string? | |
| seconds | number | |
owned( ) → boolean
Whether a beat currently owns the commander's camera.
setCamEnabled(on: boolean) → void
Taking the camera stands the commander's behaviour down; handing it back
stands it up, and it re-poses the rig on its very next tick.
| arg | type | description |
|---|
| on | boolean | |
take(reason: string) → void
| arg | type | description |
|---|
| reason | string | |
startOpening( ) → void
Play the opening: the Gate, the line, the Maw, and back, with brief_1..3 on the net.
skipOpening( ) → void
Cut the opening short — the SKIP row, Space, or the pad's confirm.
titanArrival(x: number, z: number) → void
Hold the camera on an arriving titan, then hand the camera back.
| arg | type | description |
|---|
| x | number | Where across the canyon it came out. |
| z | number | How far up the canyon it came out. |
endResolution( ) → void
The resolution ends the way every other beat does: the track stops, the
stage goes idle, the bars run out and the commander's camera comes back up.
Without this the staging holds the camera and the letterbox for the rest of
the session, the end card sits over whatever the last leg was pointing at,
and a second playthrough's resolution is refused by the `mode == "ending"`
guard at the top of playEnding.
endingReady( ) → boolean
Whether the resolution beat has finished and the end card may come up.
endingOutcome( ) → string
The outcome the resolution is playing, once one is.
playEnding(outcome: string, reason: string?) → void
Play the resolution: the ship lifting over the Gate, or the breach.
| arg | type | description |
|---|
| outcome | string | "victory" or "defeat". |
| reason | string? | Why, from the sim — "army" picks the other defeat line. |
attach( ) → void
Subscribe the staging to the battle. Idempotent; Screens calls it at awake.
reset( ) → void
Put the staging back to how a fresh play finds it.
detach( ) → void
Drop every subscription. Screens calls it from onDestroy.
update(dt: number) → void
Advance the staging one frame.
| arg | type | description |
|---|
| dt | number | Seconds since the last frame. |
view(skipLabel: string, skipFocused: boolean) → any
The StageView the overlay screen is built from.
| arg | type | description |
|---|
| skipLabel | string | What the SKIP row reads, for the device in the player's hands. |
| skipFocused | boolean | Whether SKIP holds the focus. |
opening( ) → boolean
Whether the opening is running right now.
busy( ) → boolean
Whether any beat is on screen (a banner, the bars, or a camera move).