Cold Start
README.md
preseed/tides/light.module — THE FARJAN, LIGHT
Part 9's sun, fill, shadows, exposure and grade, under the SKY lane's weather.
What it owns
- the scene's directional key and ambient fill, driven every frame from
preseed.tides.state, and restored on the way out; - the key's occlusion, measured through the part's own cloud volume rather than scheduled;
- the tonemap's exposure ramp and the bloom drive;
- the print stage (
preseed.shaders.tid_print) — chromatic aberration, the print black and the output dither; - the reflection probe's recapture schedule.
Three things that are not obvious
It drives the SCENE's sun and ambient, not lights of its own.
/runtime/lighting resolves exactly one directional and one ambient, and in
this scene they are the persistent sun and ambient entities. A part that
spawns its own pair authors something nothing reads: measured mid-part with
tid_sun at 3.0 and tid_ambient at 2.0 on their own entities, the resolved
config was the scene sun at 0.12 and the scene ambient at 0.14. So this lane
drives the scene's, remembers what it found, and puts it back in M.exit.
It WRITES the sun's direction, which reads backwards until you know why.
src/engine/systems/sky.rs refuses to sync the sun onto the lighting config
while a directional Light entity exists — the Light is "the sole authoritative
writer" — so a Light left alone keeps its default straight-down direction while
the visible disc goes wherever the sky puts it. State.sunDirection(t) is the
vector toward the disc; a Light's direction is the way light TRAVELS, so the
value written is its negation.
The key is measured, not scheduled. tid_key_probe.computeShader marches
the SKY lane's own cloud volume from the ship toward the sun every frame and
reports the mean transmittance over eight rays, and the key is
keyOpen(t) * (1 - KEY_DEPTH * occlusion). State.light(t).keyOcclusion01 is
only a FLOOR under that measurement, and it is zero until t = 24 — so for
twenty-four seconds the key is the weather's answer and nothing else. The one
exception is the slot at bar 22, which is authored and says so: the wedge of
clear air is carved at the horizon, beyond 2.2 km, and the ship stands inside
that radius under the rain veil, so the probe marching outward never sees the
hole.
The order in P.update is load-bearing
CAMERA → LIGHT → SKY. LIGHT must come before SKY because it probes the volume SKY filled; SKY must be last because its raymarch builds its ray basis from the camera pose.
The print stage
Fx.grade matches its table against PP.PRESETS, which has no
chromatic_aberration entry, so the brief's 0.0018 was read and dropped in
silence. The shared fx.module is read by twelve other parts and is not this
lane's to change, so the pass is added here from a tides-owned shader at
priority 75 — after tonemap (60) and vignette (70), before the letterbox and
fade (200). It also carries the part's print black and its dither, both
driven per frame from printGrade(t): measured, round 1 put 21-57% of every
frame at exactly (0,0,0) with the 25th percentile on zero in all twelve, which
the brief forbids by name.
Budgets published for the FERRY lane
M.PRACTICAL_BUDGET = { points = 18, spots = 4, shadowCasting = 2 }.
MAX_POINT_LIGHTS is 64 for the whole scene and over-cap lights are dropped
silently rather than merged — and this part is not alone in it.