Staging — NINE BELLS
The camera, and the three moments Ashcross is remembered by.
The moments
The opening. The shot begins where the run ends — up at the lazaretto gate — and cranes down the whole district in one slow vertical move: shutters, hanging sheets, unlit lanterns, a street with nobody in it. Then the first bell, which the frame answers with a kick and a flash. Then the physician arrives, and only then does the street become playable. Portrait screen, so the move is vertical; the crane runs fourteen seconds and the whole opening twenty-three.
The decisive beat. The first lantern lit. The shot leaves the follow, pushes from sixteen world units of frame down to ten and a half, holds while it takes, kicks and flashes amber, gives the physician his line, and hands the street back. Bells seven, eight and nine get a shorter version of the same attention.
The resolution. The gate. Bands in, a push, a long hold with a slow upward drift so the frame is alive rather than nailed down, the Warden's line, and a fade — not a screen that simply appears. There is a losing version of the same shot, closer and greener.
What it puts on screen
Four quads, parented under StageRoot and held in front of the orthographic
camera every frame, sized from the camera's own live orthoHeight:
| Quad | Material | What it is |
|---|---|---|
stage_bar_top / stage_bar_bottom | art.stage.cinemabar | the cinema bands |
stage_veil | art.stage.veil | the wash a cut, a bell flash or a miasma swell fades through |
stage_vignette | art.stage.vignette | the ink at the edge of every frame, deepening on a beat |
They are geometry rather than the engine's cutscene post-process overlay, which
means they survive an offscreen capture — this game ends its life as
screenshots and a trailer, both of which are taken that way.
Events
Emits
| Event | Payload | Meaning |
|---|---|---|
phase | { from, to } | via NB.setPhase: title → opening → play → won/lost |
say | { who, text, clip } | via NB.say — the Physician, the Bellman, the Warden |
stage.cinema | { active, letterbox, veil } | the frame is being staged |
stage.beat | { name } | a staged sequence starts |
stage.resolved | { outcome } | the ending has FINISHED playing |
stage.firstBell | { n } | the opening's bell |
stage.doctorArrives | { x, y } | the physician steps into the shot |
stage.opening.done | {} | the street is playable |
Two requests to the kit slice. The bands and the veil are world geometry and
the UI draws over them, so: hide or inset the HUD while stage.cinema.active is
true, and put the end card up on stage.resolved rather than on the phase
change — otherwise the card lands on top of the shot that earns it.
Listens for patient.treated · gate.reached · bell · hurt · phase
(won/lost from the rounds slice) · ui.click (an id containing
start/begin/play/newgame leaves the title) · stage.skip.
Holding Space, Enter or Escape skips the opening, and the title advances itself after twenty seconds so a recording is never wedged on a menu.
Rehearsing it
Every moment can be watched without entering play — Camera2D ticks this slice
in edit mode too, so the VFS stays unlocked for the other slices.
local Stage = require("game.stage")
Stage.start() -- arm it (the scene entrypoint does this at load)
Stage.rehearse() -- forget what has already happened
Stage.beginOpening() -- watch the opening
Stage.status() -- phase, sequence, clock, letterbox, veil, lens
Stage.resolveWon() -- watch the ending
Stage.beginPlay() -- skip to a playable street, no opening
Stage.clear() -- take the staged frame back off the screen
Stage.setFrame { letterbox = 0.13, veil = 0.4, veilColor = { 0.9, 0.6, 0.2 },
vignette = 0.7, instant = true } -- hold a look, for a recording
Camera
game.Camera2D is this slice's, and it is the only camera in the game:
:panTo(x, y, seconds, ease) · :zoomTo(height, seconds, ease) ·
:setDrift(vx, vy) · :kick(amount) · :snapTo · :driveTo · :release ·
:setBounds · :isPanning · :pose. The city slice calls :setBounds; a
driven shot ignores those bounds on purpose, because a staged moment is allowed
to look above the roofline.
Design
/zero/source/design/spec.md, slice H.
Scoped to this part · feeds back into the world's score.