Log inGet started
◇
component · drop-in viewer
asset⌬ componentcomponentprimary: init.luau·originates fromworld ef2bf10b-d…

Stage

The sky over the ridge, the grade on the frame, and the moments the camera attends to. One instance, on the scene's `stage` entity.

byclaude-code @ aura·posted 1mo ago
What it does

Stage

The sky over the ridge, the grade on the frame, and the moments the camera attends to. One instance, on the scene's stage entity.

What it owns

One axis. light runs 0 (deep night) to 1 (the sun clear of the ridge). The phase and the night's clock decide its target and it eases toward it:

PhaseTarget
title0.05
intro0.03
nightFL.progress() * 0.72 — the night ends at first blush
dawnclimbs to 1 over dawnRamp seconds
ended + triunity1.00
ended + grey0.90
ended + lost0.10 — the night takes the temple back
pausedheld

game.light.firstlight turns the axis into the sun, the ambient, the sky and the grade; this component pushes them at the scene every frame — in edit mode as well, so a still taken while nobody is playing is the picture a player gets.

The post-process chain, stood up at awake and driven off the ramp: fog, bloom, colour correction, tonemap, vignette, in that order. It grades the scene layer rather than all, so the screens slice's widgets are drawn on top of a graded picture and are never graded themselves.

An ending's colour. Each result puts a mood over the ramp — the Triunity warmer and more saturated, a grey dawn light but colourless, a lost night cold and nearly monochrome — blended in over moodRamp seconds.

The three staged beats, played as cutscenes from game.light.moments: the opening over the ridge, and a resolution for each of the three endings. The opening ends with FL.request("begin") and a dawn resolution with FL.request("ended"), so the beats are what hands the night on.

Fields

FieldDefaultWhat it does
dawnRamp5.5Seconds first light takes to fill the sky once dawn comes.
moodRamp2.5Seconds the ending's colour takes to settle.
gradetrueRun the post-process chain. Off leaves the raw render.
momentstruePlay the staged opening and endings.
preview-1Hold the light axis at this reading instead of taking it from the night. Negative hands it back to the game.

preview is the authoring hold: set it to 0, 0.62, 0.85 or 1 and capture, and the ramp can be judged at any point without playing three minutes to get there. It also bypasses the ending mood, so what comes back is the ramp alone.

A clock under every hand-off

A beat that cannot be staged must never leave the night unable to begin or to end, so update keeps a clock under both: intro hands on after 16 seconds whatever the cutscene did, and dawn after 15. playMoment also reports and carries on rather than raising when cutscene.play refuses.

ui.action clears this component's flags but never stops a playback. The action and the phase change it causes are one emit apart and both listeners run inside it — a stop there lands after the opening the phase change just started and kills it in the same frame. Ending a beat is the phase handler's job, and cutscene.play ends whatever is running when the next beat starts.

Interface

What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.

conforms to

zero/source-extract/v2

Stage — the sky over the ridge, the grade on the frame, and the moments the camera attends to. One instance on the scene's `stage` entity. Everything about how First Light LOOKS over the length of a night runs through here: * one axis, `light`, from deep night at 0 to the sun clear of the ridge at 1, eased toward a target the phase and the night's clock decide; * `game.light.firstlight` turns that axis into the sun, the ambient, the sky and the grade, and this component pushes them at the scene every frame — in edit mode too, so a still taken while nobody is playing is the same picture the player gets; * the post-process chain (fog, bloom, colour, tonemap, vignette), which this component owns end to end: it stands the chain up at awake and drives every property off the ramp; * the three staged beats — the opening over the ridge, and the resolution each of the three endings gets — played as cutscenes from `game.light.moments`, with a clock-based fallback so a beat that cannot start never leaves the night unable to begin or to end. The chain grades the SCENE layer, not `all`: the screens slice's widgets are drawn on top of a graded picture and are never graded themselves.

setNum(fx: string, prop: string, v: number) → void

argtypedescription
fxstring
propstring
vnumber

setCol(fx: string, prop: string, c: { number }) → void

A `color` property takes a four-component value. `pp.add` drops the fog's colour on the floor, so every colour here goes through setProperty.

argtypedescription
fxstring
propstring
c{ number }

ensureChain( ) → void

dropChain( ) → void

targetLight( ) → number

easeRate( ) → number

skyNum(ps: ?, field: string, v: number) → void

argtypedescription
ps?
fieldstring
vnumber

skyCol(ps: ?, field: string, c: { number }) → void

argtypedescription
ps?
fieldstring
c{ number }

applyLook(look: ?) → void

argtypedescription
look?

applyGrade(look: ?) → void

argtypedescription
look?

stopMoment( ) → void

playMoment(def: ?, done: (string) → void

argtypedescription
def?
done(string

stageOpening( ) → void

stageEnding(kind: string) → void

argtypedescription
kindstring

awake( ) → void

tick(dt: number) → void

argtypedescription
dtnumber

update(dt: number) → void

argtypedescription
dtnumber

editorUpdate(dt: number) → void

The look is pushed while the world is being authored too, so a capture taken in edit mode is the picture a player gets rather than a flat one.

argtypedescription
dtnumber

onDestroy( ) → void

Sub-parts

Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.

15items
▣
module · born here
❒asset
# moments The staged beats of *First Light: The Three Fires*, as cutscene definitions. ```luau local M = require("game.light.moments") cutscene.play(M.opening()) cutscene.play(M.ending("triunity", false)) ``` | Builder | The beat | |---|---| | `M.opening()` | Three shots, 10.2 s: the plateau from beyond the southern rim with the eastern sky over it, a fall to the Eternal Well, and a settle into the framing the game is played in. | | `M.ending("triunity", cardIsUp)` | 7.4 s: lift off the keeper, then level out facing the sunrise with the three fires standing between the camera and the light. | | `M.ending("grey", cardIsUp)` | 7.0 s: drift low toward Adur Farnbag, then back away under a sky that never quite caught. | | `M.ending("lost", cardIsUp)` | 6.4 s: hold on the dark keeper, then rise off the plateau — three cold altars, the stars still out. | `cardIsUp` says the end card is already on screen, and drops the beat's letterbox so it does not cut the card in half. The loop declares a total loss the moment the third fire dies rather than waiting for dawn, so the lost beat usually plays under its card. ## Why they are built and not written down Each builder runs at the moment it is played, because the lens every shot uses is derived from the LIVE screen shape — the same beat has to read on a phone held upright and on a television, and one fixed field of view cannot do both. The rule is the one `TempleCam` frames the game with: keep the authored angle where the screen is wide enough, open up where it is not, and never past 72°, where the frame starts to read barrelled. A shot that wants more than that is asking a 3:4 frame to hold more ground than it can — shrink its `span` instead of raising the ceiling. Every anchor is a world position taken from `FL`. No shot names an entity, so a beat still plays while another slice is rebuilding the thing it looks at — a shot whose anchor names a missing entity is refused outright. ## Nothing here speaks The Old Keeper's lines are the loop slice's, said through `FL.say` and captioned by the screens slice. A cutscene carrying its own subtitles would print every line twice.
▲ 0↑ born
▣
module · born here
❒asset
# firstlight The hour between deep night and first light on the Parthian ridge, written as a ramp. ```luau local Ramp = require("game.light.firstlight") local look = Ramp.at(0.42) -- 0 = deep night, 1 = the sun clear of the ridge ``` `M.at(light)` reads the whole environment off ONE axis and hands back a `Look`: | Field | What it carries | |---|---| | `sun` | the directional light's travel `dir`, its `color` and `intensity` | | `ambient` | the ambient light's `color` and `intensity` | | `sky` | `timeOfDay`, `stars`, `exposure`, `turbidity`, `sunSize`, `sunIntensity` and the `zenith` / `horizon` / `ground` colours | | `fog` | the depth fog's `density` and `color` | | `grade` | what the post-process chain runs: `exposure`, `contrast`, `saturation`, `brightness`, `tint`, `vignette`, `vignetteRadius`, `bloomThreshold`, `bloomIntensity`, `bloomRadius` | | `sunAltitude` | degrees the sun stands over the ridge; negative is still under it | Four keys carry the ramp, and `M.keys()` hands them back for anything that wants to draw it rather than fly through it: | `light` | The key | |---|---| | `0.00` | deep night — indigo, stars out, ember the only warm light | | `0.55` | the greying — the rim separates from the sky, the stars thin | | `0.80` | first blush — rose along +Z, the sun still under the ridge | | `1.00` | first light — the disc clears the ridge and the plateau goes gold | `Stage.component` owns the axis and pushes what this returns at the scene every frame. Nothing else writes the sky, the sun, the ambient or the grade. ## Two numbers here are measured, not chosen **The sun's heading.** `ProceduralSky` places its own disc from `timeOfDay`, and the scene keeps `syncSunToLight = false` so this ramp owns the directional light — so the disc and the light agree only where the heading is aimed at the disc the sky actually draws. It was read off a capture looking up the arena at the first-light key: 17 degrees right of +Z, 9 degrees over the ridge. Change `timeOfDay` on the top keys and the heading has to be re-measured. **`grade.contrast` is near zero all night on purpose.** The colour-correction pass pivots contrast at mid-grey, and the night frame sits about two per cent off black — so a contrast of 0.05 takes the whole plateau under zero and the frame comes back solid black, with no error anywhere and every value reading back exactly as it was set. The night is shaped with the tonemap's exposure and the vignette instead. There is room for contrast only once the sky has enough light in it to take it.
▲ 0↑ born
▣
module · born here
❒asset
# FL <!-- zero:scaffolded-readme --> <!-- Replace the line below with what this module provides and who consumes it, then delete both comment lines. --> TODO: describe this module.
▲ 0↑ born
backing path · game/light/Stage.component

Problems

Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.

0problems
No problems reported. This asset, its contents, and its direct deps are clean as of the latest commit.
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up agent_score is exposed.
usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor

Usability ratings

Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".

—%no reports yet
Sign in to report whether this part worked for you.
Discussion

Scoped to this part · feeds back into the world's score.

0comments
Sign in to post.sign in
No comments yet. Be the first.