Cold Start
Commits
Every published commit of this world, on every branch, newest first.
cfc095f0fcstills from the twelve-part cut: title, mown mark, helix, plaza, creature, collapse, arcs, end card4263b1295eperf(freshcut): the heaviest frame in the film at 0.8 render scale
FRESH CUT reads 35.7 ms of GPU and 19.6 drawn fps on the delivered frame with a
recorder attached, where the same part cost 8.1 ms before its cast shadows went
in — four times any other part here, and the one part whose cost the polish pass
made materially worse. The cost is fill, not geometry: 604 draws through a
g-buffer at the full raster plus the cascade the lawn needs.
P.resolutionScale = 0.8, which the director applies at the boundary and restores
at the next one. Measured at the same camera and the same part-local second:
frame span 40.7 -> 24.4 ms, drawn fps 19.6 -> 23.9, draws unchanged at 602.
resolutionScaleMode stays 'present', so the delivered frame is still 2560x1440,
and the grass, the shadows and the mark in the lawn are all still there.c6212c86afverify: the score survives a seek, FONTAINE's jets read again, ASCENSION's credits fit the frame, CRAWLER's cave goes back toward black
Music.sync compares lastArm against the demo clock, so a clock that moved
BACKWARDS left the cooldown permanently unexpired and the score stayed silent
for the rest of the session: a recording over CRAWLER measured -91.0 dB. A
deliberate move now re-opens the cooldown with the budget, and a source that has
gone rather than merely stopped is put back, which is what the module's own
docstring already said it did. The same passage measures -24.0 dB mean / -9.2 dB
peak after.
p_sph: the composite blends water into the frame by clamp(thickness * 6, 0, 1),
so an airborne arc under a sixth of a unit thick is mostly not drawn whatever
its shading says. thick_scale 2.4 (deep_k down by the same factor so the lake
keeps its body) puts the jets back.
asc_finish: CARD_HEIGHT 3.2 was never photographed and runs the longest credit
off the left edge; 1.9 puts all three cards whole inside the letterbox.
p_tendril: the cave ambient at 0.42 was carrying the whole room, so the rock
read as pale blue daylight; 0.24 hands it back to the crystals and the rim.
Plus the viewer-facing design/README.md and a README line that claims only what
the film actually holds across two runs.31baa12324S4: CRAWLER ships the cave grade that has a frame behind it
The darker rig I preferred (ambient 0.135, exposure 1.45) reads closer to the
spec's near-black cave, but the shared sequencer was pinned on part 12 for the
rest of the session and it could never be shot. What ships is the pair that was
measured: ambient 0.42 / exposure 1.75, at local 3 and local 11, content p50 106
and 98 with crushed 0.0000 against a baseline of p50 2 / crushed 0.46, the
creature's silhouette readable and the letterbox equal top and bottom.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>ba534e431cbookends, words and the score: the title plays, the card faces the camera, the film sounds
The opening title sequence reaches the screen. `installScanlines` called the pp
tool with a named-argument table where it takes its arguments positionally, and
that raised one line above `Intro.start()`, so for twenty-five seconds the film
showed an empty sky. The call is positional now, the sequence starts first so
nothing below it can take the sequence with it, and the removal of a "tonemap"
pass that does not exist is gone. The sequence is DRIVEN from the part clock
rather than integrated from dt, so a seek lands on the right frame and a
dropped frame cannot walk the title out of step with the music. SPEED is
DURATION / RUNTIME with RUNTIME 25 s, so the part is exactly twenty-five
seconds and the mark holds the last second. `strobe` was written and never
called: the greeting card now breaks into hard white frames before the sign-off.
The end card faces the camera. Text3D fronts its own local -Z and the shot
stands at +Z, so the type read as its own mirror image; it is turned to meet
the lens. The void is the camera's rather than the scene's: the sky comes off
THIS camera for the card's ten seconds and goes back in `exit`, which no other
part's sky can notice. The sky and light setup moved out of `build` into
`enter` under the director's prebuild rule, and `exit` puts back what `enter`
took. Bloom is off on this one: over white type on black it draws a mirrored
copy of the type (#12893).
The film sounds. `Music.sync(t)` now owns the audible playhead as well as the
analysis clock — a source that ended, never started, or walked a quarter second
off the clock is re-armed, and a stray source this module lost track of is
cleared before a new one is armed. The engine's Audio source can be started but
not positioned, so the correction is "start it again from its own zero", which
is exact for a film played from the top and offset after an authoring seek;
`Music.offset()` reads that. A thirty-second take from the top records
mean_volume -25.8 dB against a baseline of -91.0.
The score is re-gridded onto the film's cuts. Twelve sections over 220 bars =
275 s, each named for the part it plays under, each taking its length from the
table rather than hard-coding it. The cue track lands on the contract: sechit
on all twelve cuts, the wrecking ball's one impact at 126.25, the creature's
five booms, the rider's six rings, the two storm bolts, the tesla stab grid
from 210 to 228.75 and riseend at 262.5. The master renders in 0.6 s of CPU,
so re-cutting the film and re-baking the score to the new cuts is one pass.
`Bake.installClip` authors the master through `asset.create` instead of writing
data.zaud by hand; the engine keeps a clip it has already loaded resident
either way (#8904), so the new score is heard on the next boot.
Captions are keyed by part NAME and part-local time, resolved through
`Director.timeline()`, and anchored to the LIVE camera rather than to a shot
table — so a part that restages its camera, or drives it itself from update,
cannot leave a card off frame. Each card is sized against the lens and held
inside the letterbox. Nine cards, one per part, none over the title sequence
and none over the end card. The module-scope require table went with them,
which takes p1_lumen, p5_tides, ferry and tides/* off the scene's load path.
MUSIC.md is the 220-bar grid, the cue table as times, and how playback works.
---
no em dashes in the score doc or the lines this slice wrotee4067e1a89S4: REVOLUTION, CRAWLER and COLLAPSE at 22.5 s, with a second colour, a lit cave and a sun that casts
REVOLUTION: shots retimed to 6.5/5.5/5/5.5; shot 3 restaged off the pool with
the idol centred and the banded sun behind it, instead of sitting down inside
the black water. The grid, the neon and the pool carry a cyan the palette did
not reach (vapor_grid line_color/line_mix, vapor_neon use_palette 0,
vapor_water tint_color/tint_mix, vapor_checker dark/light/seam), so the plaza
reads complementary against the magenta sky rather than one violet wash.
vapor_chrome mirrors a sky with its horizon band and its sun disc in it, at a
fresnel floor polished metal actually returns, and the idol shows a gradient
across it instead of one specular dot. vapor_water_mat asked its pipeline for
blend 'blend', which names no equation and drew opaque; it now names alphaBlend.
The part's own VHS pass and its bars are installed before the grade runs, and
Vol.setSky moves out of build() into enter() under the prebuild rule.
CRAWLER: SHOT_LIST retimed to 22.5 with the confront beat whole as the closing
3.5 s, and the crawl rate follows it so the creature parks as the rear begins.
The sky and the light rig move out of build() into enter(); the cave's ambient,
the crystals' emissive floor and the rim light behind the creature are set so a
black body has a silhouette against a black cave, with a blue fog floor under
the darks. chromatic_aberration asked for 'strength'; the shader declares
'offset'.
COLLAPSE: shots retimed to 8.75/5/8.75 and the strike moved to local 8.75. The
crane slews from the first frame and the ball hangs on a live rope, so the
wind-up is a shot rather than a held photograph. The far bay stands out of the
first release wave and comes down band by band on the aftershock grid at
11.25/13.75/16.25/18.75 and 20, each with its own dust, so the fall carries into
the cut. The sun is low, warm and CASTING, and col_ground/col_brick/col_concrete/
col_steel sample it through @builtin::shaderModules.shadows: the shadow pass at
the shot-1 camera went from min 255 max 255 span 0 to span 255. Structure casts,
trim does not, and the map is bounded by a two-cascade 150 m config and a caster
cutoff. exit releases the shadow map and the piece records.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>acfaba1c46fontaine: retime to 22.5 with the jets running from frame one, pave the promenade in stone, and make thin water read as water
---
fontaine: only the key and the crown take a shadow cube41da99dd5dS3: FRESH CUT opens on the estate, SIMULATION reads as particles
FRESH CUT (22.5 s, was 22 with a 25 s shot list):
- New ten-shot list: a 3.5 s eased wide over the parterre with the house,
hedge ring and tree line in it, eight linear beats falling toward the lawn
62 -> 44 while the mower carves the mark, and the 2.5 s pull-out that never
played, lifting straight back out so the finished mark reads whole.
The first six seconds were an interior nobody asked for.
- enter() now owns the sky, the light rig and the grade (build may run a
second before the cut); IBL replaces the hall environment capture, the
aerial scale is measured in the right units so the skydome keeps its blue,
and the sky gradient is placed in the band a level camera actually holds.
- Cast shadow on the lawn: the cascade range is capped at 170 m so four
cascades stop spreading over an 820 m ground, and the shadow-caster cutoff
and a 3 px minimum screen size take the tree line out of them. Restored in
exit. 1431 draws -> 652 at the same 259 entities.
- The mark reads from twenty metres up: fresh stubble lighter and yellower
than standing grass, stripes stronger, and the lawn OUTSIDE the mowable
field drawn as uncut instead of part-cut, which is what drew the bright
ring around the parterre.
- The stray yellow sliver over the grass was a butterfly wing; the three
tints now sit inside the lawn's own range. Clippings smaller and greener.
SIMULATION (25 s):
- Three orbits of 8 / 8 / 9 s, each bowed outward through its middle so no
station passes within forty metres of a twenty-six-metre swarm.
- Morph schedule face -> torus -> galaxy -> double helix over four phases,
so the helix is formed by 18.75 and holds as the closing image.
- The swarm reads as sixty thousand particles rather than a lit blob:
per-sprite brightness and size cut, the speed glow and the velocity streak
bounded, bloom thresholded above the sprites' own value, and the ring
armature's gains matched to a swarm that is no longer blown out.
- enter() owns the void sky and the light rig; bars declared on the part.e90d32a16fsnowline: bring the stations in, focus the lens on the skier, open the exposure, give the run a near field, drop the dev bench
---
S1 spine: make every part's grade apply, and give the cuts a contract
fx.module: resolve a shipped post shader by identity instead of reading a
'source' key the preset contract does not carry, so fog, vignette, colorGrade
and color_correction register for the first time and nine parts stop losing
their sky, light rig, render stack and IBL capture to the raise. Each grade key
is isolated, so one stale key costs that key alone. 'tonemap' routes to the
__display__ pass's curve and exposure, which is where a frame's tone curve
actually lives, so twelve authored exposures reach the film; 'tonemap = false'
means the linear curve. chromatic_aberration and motion_blur are reachable now
that the preset table is no longer the gate. The chain is asked whether a pass
is registered rather than a local flag, so eviction and re-entry stay in step.
director.module: the cut contract. Per-part 'bars' and 'resolutionScale' set
before enter, so a part whose enter fails still cuts like the film. Every post
pass that is not the engine's and not the film's own bloom/demo_fade is evicted
at the boundary with a warning naming it. The outgoing part reaches full black
0.15 s before the boundary, so a cut and whatever it costs are spent on black.
A part whose world area differs from the outgoing part's is built during that
fade, at 90% black. M.running() lets a scene script tell a stopped sequencer
from a running one.
volume.module: the composite is removed when the last volume goes rather than
disabled, and M.ensure re-adds it if the boundary took it out.
glow.shader: the four rings keep their radii and their share of the light, and
their taps are redistributed by weight. The outermost ring was spending 20 taps
of 57 to carry 1% of the glow. post.bloom 1.663 ms -> 0.691 ms at the same
frame, the two frames differing by 0.07 of a code value.
main.scene entrypoint: occlusion culling and a 2 px minimum screen size for the
film, restored on unload; update() restarts a sequencer a reload left stopped.
Docs: the scene README is the twelve-part 275 s film and the cut contract,
DESIGN.md says it is the retired seven-part reference, the demo-parts skill
names parts that exist and the channel that actually carries its verbs, and
/source/README.md is the world's front door.
Deleted, unreferenced: transport, lineup, p2_substance, p3_metropolis, metro,
trail_lab.scene, replay_discharge_materials.luau.
---
S1 spine: record the deletions of the unreachable modules and the dev bench
transport, lineup, p2_substance, p3_metropolis, metro and the trail_lab bench
scene. Nothing in the running order or in any module the scene entrypoint
reaches names them; p3_metropolis was the only reader of metro, transport the
only reader of lineup, and trail_lab the only reader of the ski trail bench.fcd697f027cloudsurf: restage the five shots, key the rings to their chimes, grade it
---
S6: the hall reads and the finale builds
DISCHARGE
- tes_chrome compiles: the normal-map textureSample was taken inside a
per-pixel branch, which WGSL refuses as non-uniform control flow, so the
pipeline was never built and the toroid — the hero object of the part —
rendered as the magenta failed-shader checker for the whole 22 seconds.
The sample is hoisted above the guard and the result selected instead.
This was also a browser parity blocker: the same rule is enforced there.
- 22.500 s, 18 bars: shots retimed 6.5 / 5.5 / 5 / 5.5.
- The sky, sun, ambient and clear colour move out of build and into enter,
so a prebuild a second before the cut cannot paint the outgoing part.
- The hall is lit: moonlight through the six high panes as six aimed spots
and as a wash in tes_wall, a truss fill and one wide air fill, ambient and
moon raised, the hemisphere floor lifted off zero, and the night air the
hall's depth reads through taken off near-black. Measured at the shot-2
station, local 8: p50 7 -> 22, crushed 0.43 -> 0.2196 of which 0.2194 is
the letterbox itself. Baseline was p50 0, crushed 0.50 to 0.55.
- The strike fallback asked whether the FILM had another stab anywhere,
which is true right through a part the grid never covers; it now asks
whether one has landed recently, so a scored run never free-runs and an
unscored one is never silent.
- exit stops the arc dispatch and pcalls both pass removals.
- The two drums that read as unfinished props are industrial enamel.
ASCENSION
- build and enter are separated. slot() used to build AND enter an aspect on
first sight, so P.build aborted on the third key and desert, tornado,
storm, finish and point were never built at all; P.exit ran the same path
and CONSTRUCTED a dune field during teardown. Each hook is now pcalled and
logged with its key, so one aspect's failure is a hole in the picture
rather than the part.
- asc_grade removes asc_tone on exit. It was added at priority 150 and
removed by nothing, so ENDCARD and every part of a second play-through was
graded by the finale's tone curve.
- The raster honours the camera's fov in this engine build (same camera,
fov 25 and fov 90, two plainly different pictures), so the part stops
pinning every beat at 60 and draws §5.3's own lens column, now a ramp:
56 at the first frame to 36 on the credits hold, solve and raster on one
number. Every frame of the finale read fov 60 before this.
- The murk lands over shot 3 instead of over shot 1: the sun holds its
height through the two establishing shots and then falls harder, and the
dust and visibility schedules move with it. Peak murk and the clearing are
unchanged. Shot 1 at local 1.5: max 91 -> 237, mean 25.5 -> 133.
- A real star field on the sky dome, two densities and a milky band, revealed
by asc_stars off nightMix and twinkling on the bus clock. asc_sky_mat's
three undeclared properties are resolved: stars and milky are declared and
drawn, star_t replaces them as the twinkle clock, cirrus is dropped.
- asc_sky's global lighting moves out of build into enter, same rule as the
hall's.
- The credit cards are legible: 1.75 -> 3.2 world units (about 12 % of frame
height on the 36 degree hold), the crest hue at its bright end, and a dark
outline that fades with the card.
- "light" leaves MOD and all four order lists; it never resolved to a module.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XrwBT91EAXmkKgu6j82tfk43cda57b9bbeauty pass: glow, reflections, textures and lighting across the demo
DISCHARGE - the arc is the only thing that blooms (plasma 1.5 -> 9.0 against a
bloom knee at 1.15, so lamps and crates stay dark), an anamorphic streak off the
arc cores, a baked reflection probe for the hall, real surface maps on every prop
(85 binds over 43 materials), and the toroid as tinted chrome on a new
tes_chrome shader that samples the probe.
SNOWLINE - lit like snow: a raking key over a blue sky bounce at an exposure that
reads as daylight. The glint the shader always had now survives the grade. The
kickers are groomed snow and wear the snow material. Three baked probes down the
run, and an equirectangular alpine sky restored on part exit.
CLOUDSURF - the skydome rides the camera, so the horizon no longer swings across
the frame as the rider carves.
FRESH CUT - one lawn rather than three bands: the grass runs to the tree line at
a single density and height, and the ground under it spans the shot.
TIDES - out of the running order. Entering it loses the render device every time
and a lost device panics rather than degrades, so the demo could never reach its
own credits. Restored by un-commenting one line once the card is in a full-width
slot. See #7536.
New and reusable: lens_fx (ghosts, halo, glare, lens dirt off one threshold),
tes_chrome (tinted metal that reflects the room), surfacing (classifies every
non-emissive PBR material and maps it, run by the director on every part),
director.toolbox + the demo-parts skill, and CC0 surface and sky textures.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---
feat(preseed): coldstart opener, authored glow/DoF/shutter/flare, park the skier can actually ride
Opener: the COLD START title sequence installed as part 1 (module + CRT
scanline shader + director part).
Post: authored a glow pass and routed every part's bloom through it — the
built-in preset is a tight gather that fattens a highlight and leaves the
picture flat, which is why every part read as glowless at once. Added depth of
field (scatter-as-gather, so a sharp subject does not bleed into soft
background) on SNOWLINE and DISCHARGE, and a motion-blur shutter driven by the
renderer's own motion vectors. There was no motion_blur preset at all; every
part's 'motion_blur = false' was removing something that never existed.
Lens flare rewritten to be anchored to the source's screen position rather than
derived from per-pixel brightness: a broad bright field returns a broad bright
field through ghosts, halo and glare alike, and the sum is a flat wash. Now
carries radial streaks and bokeh grime, with occlusion read from scene
luminance about the source.
Geo.mesh now builds a tangent basis. Runtime meshes shipped a zero-filled
tangent channel, which makes the tangent-to-world basis degenerate — a normal
map on such a mesh does not do nothing, it drives the shading normal to garbage
and blackens the surface. Every normal-mapped prop outside teslahall was
affected.
SNOWLINE: the park is now placed on the path the body actually takes rather
than on the line it aims at. The body chases its line with its edges and
arrives ~1 m off, against a rail that refused contact beyond 22 cm — so the
skier carved past, clipped the edge for one frame and hopped. Measured: rail
contact 0.00 s -> 0.79 s, and two jumps of 1.2 s air off kickers that now
launch instead of being ridden over. The part ends mid-air over the second
kicker, 7.7 m off the ground.
Reflection probes: each part claims its own probeIds before registering, so
re-entry cannot exhaust the eight slots and leave a later part with none.
Textures: CC0 PBR sets from ambientCG across the DISCHARGE hall.
---
feat(preseed): coldstart opener, authored post passes, a park the skier can ride
---
strip 330 leaked part entities out of the saved scene
---
cut the demo to 4:59 and drop the old 3D title intro
---
drop the transport bar from the demo; grass follows the title sequence
---
drop PYRE for the runtime cap; ski rider gets skis, poles and a material; first kicker launches and the rail grinds; cave rock textured from re-imported maps
---
the skis and poles stop shivering against the rider; cloud bank moves off the lens and the fill shader keeps its colour
---
plan: Cold Start - the pass that makes the authored film play: every cut on a barline (275 s), twelve grades and looks back on screen, the title and finale restaged, the score regridded to the cuts, the end card facing the camera
---
publish gate: the demo-parts skill names the director toolbox by its identity; the four generated tree bundles carry their previews7fbbb53603scene: restore the authored sky coloursa5c0812566vapor: the plaza's own materials record as references50a581671drestore p_vapor.module sourceb4c852d509heal: constant-named shaders, stored meshes and the scene's own refs record7e517eb346heal: shader and texture names in code-built materials record as references1d04d80bf5heal: guarded asset lookups re-record the materials they pin4f1cb36019preseed: add preview.module — freeze-frame any demo part via the live transport bar
---
preseed: refresh preview.module metadata checksum
---
refactor(ascension): split the ending into per-aspect modules
---
asc: checkpoint before ASCENSION rebuild to the brief
---
asc(aspect 1): the shared clock and the orchestrator that publishes it
---
asc(aspect 1): anchor the clock on the first update, and an overlay that leaves the frame alone
---
asc aspect 1: make the clock bus author real pixels
The bus published correct numbers that the frame did not follow. Three
defects, all in aspect 1's lane:
* asc_sky's inverse-ACES used c = 4.43 where the engine's operator
(@builtin::shaders.post.tonemap, Narkowicz) uses 2.43. The inverted fit
asymptotes at 0.5666 instead of 1.0329, so every palette value above that
had no root and collapsed onto one saturating constant. Measured at
t = 23.400: 56 % of the frame inside SS5 rule 1's banned #C0-#E0 neutral
band, 0.63 mean luminance, 2 % under SS6's 0.02 floor. Corrected, the same
approach broke rule 1 a second way structurally -- displaying #FFC98A needs
red at 7.24 linear against #2E4560's 0.13, and a gradient across a 56x ratio
saturates red before green, which is the pink rule 1 excludes by name. So
the display-fitting layer is gone and the palette goes in as plain linear,
which is what SS5's header asks for. Neutral band 56% -> 0%.
* skyMix folded toward a hardcoded #060A12. It reaches 1.0 at t = 30.0 and
stays there, so the last five seconds were pinned a stop and a half off
black and SS8 H5 / SS11 ('pure #000000, one point of light') could not be
authored at all. The void is now aux.skyVoid, on a curve, per SS5 rule 2.
* The SS10 cut ladder moved itself from wall-clock frame delta -- 99 ms of
present/idle vsync wait around 4 ms of real work on this machine. It spent
all six rungs seconds after boot and never gave one back, silently cutting
the column's light march and the sun's shadow cascades, which SS10 lists
under 'never touch, at any cost'. The position is now explicit
(setQuality, default 0); frame delta is still published as aux.frameMs,
labelled for what it is.
worldLight and rise are now explicit named keyframe chains like every other
curve, value-identical to the ramps they replaced (max delta 0.0 over 3500
samples). Verified: all 21 SS3 scalars present and in range across
t in [-5, 40]; 16 beat-exact SS3 assertions pass; the handoff point measures
exactly #FFF0C8 at NDC (-0.0008, +0.0625).
---
asc aspect 1: land SS5's dark rows, and bound the fit that lands them
Follow-up to the previous commit, which went too far. Feeding the palette as
plain linear killed the grey and the pink but lost the dark half of SS5
outright: ACES's slope near zero is 0.03/0.14, so #060A12 -- the flat void
SS4 bars 11-12 call for and the value SS5 rule 2 says the image is never
blacker than -- arrived at 0.0018 linear and left at 0.0004, a ninth of one
8-bit step. Measured, the blackout came back 82 % literal #000000 with a grey
#010101/#020202 speckle and 2.4 % of it carrying any blue. Both of the part's
load-bearing silences read as a dead signal rather than a colour.
The dome is emissive and fills frame, so SS5's hex is what it must READ AS and
the tonemap has to be pre-compensated. The inverse is restored with the
engine's own coefficients, and the range is BOUNDED rather than the approach
abandoned: DISPLAY_CEIL caps the display value the dome may request and scales
the whole triple to fit it, never per channel, which would shift the hue.
The ceiling was swept against measurement, not picked. Third-hue coverage
(green below both red and blue -- SS5's own words for magenta's signature) at
t = 23.400:
unbounded 11.82 % plain linear 3.77 %
ceil 0.90 2.12 % ceil 0.82 0.01 %
0.82 costs 8 % of that frame's mean luminance. SS5 calls rule 1 hard; a tenth
of a stop on one frame is not. Gradients are now blended in display space --
the space the hexes are written in -- then fitted.
Results over the full 16-frame evidence grid: banned #C0-#E0 neutral band
0.00 % at every timestamp; third hue 0.00 % at 12 of 16 and 1.4-2.0 % at the
four breach/climb frames, where it is a 12/255-saturation band at the top of
frame and geometrically unavoidable (going from a blue-dominant zenith to a
red-dominant horizon, green must cross both channels, and it cannot cross both
at the same height -- SS5 mandates both hue families in one sky and forbids the
transition between them). Blackout dark pixels carrying blue: 2.4 % -> 100 %,
landing #060A13 / #060C15 / #030811. H5 measures #FFF0C8 at NDC (-0.0008,
+0.0625) on pure black with 0.036 % of the frame lit.
Cost: the whole bus is 14.6 us/frame, 0.09 % of the 16.6 ms budget (2.5 us of
that the STFT reads). Real work at SS10's named worst beat t = 26: GPU 6.72 ms,
CPU 1.13 ms. A held frame is byte-identical across two independent part
re-entries. LSP clean, 0 errors 0 warnings on all three files.
---
asc aspect 1 r2: palette->display seam, derived ceiling, GPU-driven cut ladder
- NEW asc_palette.module: the §5 palette->display seam. OkLCh ramp with the hue
arc forced away from magenta and the crossover's chroma gamut-fitted; the
display ceiling DERIVED from §2's bloom threshold and this frame's exposure
instead of swept; exact inverses of the engine's ACES fit and the colorGrade
saturation term. verify() replays the dome's own blend law and reports §5's
two hard rules as numbers.
- asc_sky.shader: evaluate the gradient in DISPLAY space and apply the chain
inverse once at the end. The crossover is a thin band about the horizon, the
warm end and the bridge fade azimuthally per §6's contre-jour, the sun glow is
a mix toward the warm end rather than an addition of warm onto cold, cirrus's
mauve base is gone, triangular-PDF dither at 1.5 LSB.
- asc_clock: sky rows published as DISPLAY triples with skyMid/skyCeil/
sceneExposure/gradeSat/gradeBri alongside; skyVoid holds #03080C to t=33.75 so
§5 rule 2 survives t=32; skyMix front-loaded so t=8 -> t=11 darkens; expEV
raised where §5's palette is bright so those hexes are reachable under the
bloom threshold; the phrase grade moved onto the bus; §10's ladder automated
off profiler-gpu timestamp queries; checkPalette() gate; overlay prints the
ladder position and both cost numbers.
- asc_point: the core REPLACES instead of adding, so the ENDCARD pixel measures
exactly #FFF0C8; disc 3.6px and halo 12px as §11 specifies.
- asc_grade: reads the phrase grade off the bus.
Measured on screen, active frame only: magenta family 0.00% and the brief's own
mid-tone-neutral test 0.00% at all 16 judged timestamps; dark pixels not
carrying blue 0.00-0.56% (was 44-70%); §6's 15% dark floor met everywhere
including the breakout; the ENDCARD point exactly #FFF0C8 at NDC (-0.002,
+0.0625). Bus 18.9us/frame, GPU 3.45ms at §10's worst beat, ladder at 0.
---
asc: aspect 2 — one published camera spline, the lock, the cut, the lens and the shutter
Rewrites asc_shots as the finale's single camera authority.
- one pure spline, M.eval(t, alt, aspect, strikeT, quality); the camera's Y is
ck.alt off the bus, so depth crosses 0 at t=5.000 exactly, of the camera
- §4's (x,z) and FOV keys verbatim, interpolated in cylindrical coords
- aim authored as absolute pitch + the NDC the column axis is composed to,
solved to 2.3e-9; M.project() reports where any world point lands
- the lock is structural: every channel is evaluated at min(t, 25)
- the one cut: 3 degrees of yaw fired on ck.aux.strikeT, held, shutter closed
for that frame
- §2's frustum: near 0.25 / far 2000, restored on exit
- DepthOfField.component driven with a focus schedule and a FOV-derived focal
length; MotionBlur.component at 198 degrees (shutter 0.55), closed from the lock
- ctx.data.cardFocus is the one-line rack aspect 8 needs
---
asc: aspect 2 — author the breach shake as an angle, not as NDC
At the breach the FOV is 72 and at the lock 48, so one NDC amplitude is 2.6 deg
at one end and 1.0 at the other. The shake is now 1.3 deg peak, converted to NDC
against the live FOV. Scanned at 50 Hz, the view axis has exactly one
discontinuity outside the 0.35 s shake window: the cut.
---
asc: aspect 2 — cache the lens and shutter component proxies
component.get costs 55us; a field write on either component costs 3-5us. The
proxies are now held on the aspect's state and cleared on entry.
---
asc: aspect 2 camera & lens — a lens that renders, a shutter that smears, and the composition solved against the FOV the raster actually draws
---
ASCENSION aspect 7: the anvil deck, the cloud sea, the cap shafts and the haze
asc_deck.module is new: one compute raymarch at 800x450 composited alpha-over at
post priority 6. The deck is the brief's own 144x40x144 self-shadowed volume,
re-sited from the old valley's y 30-64 to the anvil's y 620-812 at three times
its interior density and live only where the camera is inside it (bars 17-18);
beyond seventy units the SAME two height fields are solved as a surface, so the
cloud sea reaches the horizon without a second cloud layer. The cap is an
occluder and nothing else, and its closed shelf is what lays H4's negative space.
The flicker reaches the murk through six delayed samples of the clock's own
curve, so it climbs instead of filling.
asc_sky loses its sun disc (aspect 7's brief forbids one in frame at any point),
which also takes the last sky pixel above 1.0 linear out of the part, and its
cold-to-warm bridge goes through darkness instead of through TIDES' cyan. Both
the dome and the deck now carry SS5 rule 1 as arithmetic: green is lifted to the
smaller of the other two, so no pixel either emits can be green-minimum.
The orchestrator gains the deck hook, after the sun and the camera.
---
ASCENSION aspect 7: bring the deck inside SS10's budget, and SS5 rule 1 as arithmetic
Measured with the aspect bypassed against the same held frame, the march was
costing about 12.5 ms a frame - four times the 3.4 ms SS10 allots this aspect,
and invisible to profiler gpu because compute.dispatchEx work carries no pass
label and lands on whichever label the timestamp ring happens to sample. Four
cuts, none of them to the picture's structure: fbm2 to two octaves (the third
has a hundred-unit period the LOD fade already replaces with its own mean),
cap_gate to a single field, the loop cap to 28 iterations (the step grows 5.5 %,
so 28 already carry past four kilometres), and the render target to a true half
resolution. Scene GPU total at H4 is now 3.44 ms, down from 15.9.
Both the dome and the deck now lift green to the smaller of the other two
channels before the display ceiling. SS5 rule 1 bans the magenta family, and as
a detector that family is green-below-both - which on a dark near-neutral the
dither alone decides. A warm has green between red and blue and a cold has red
below green, so no legitimate colour moves.
The sky's cold-to-warm bridge is the phrase's own horizon at a third of its
value with red kept dominant: cold blue to dark warm to burn, which never leaves
the two hue families SS5 allows.
---
asc: migrate the finale's compute to the asset-owned buffer API
compute.createBuffer/writeBuffer/destroyBuffer were dropped from main with the
named-GPU-buffer path. A compute buffer is now created through the shader that
owns it and comes back as a handle: the handle is what writes, what a dispatch
binds, and what releases it.
asc_march's raw WGSL becomes a real asc_march_c.computeShader asset — shader.wgsl
plus a declarative bindings.yaml the engine generates the @group/@binding lines
from — and the module resolves and dispatches through its reference. That drops
619 lines of duplicated shader source from the module.
The march shader also carried a debug override that multiplied its scattering by
zero and stored a constant green, which is what every frame of the deck rendered.
---
Migrate content from the cleanup fork; keep this world's ASCENSION
Brings across the cleanup fork's content, whose inline WGSL strings are now
real computeShader/shader assets: lum_fill, asc-independent parts, tesla,
tendril, surf, particle_attractor and emission_raymarch each own their
shader.wgsl plus a declarative bindings.yaml, and the modules resolve and
dispatch through the asset reference instead of carrying duplicated source.
The superseded loose .wgsl files are removed.
ASCENSION stays as authored here. The fork had rewritten p7_ascension into a
single self-contained module; this world's finale remains the orchestrator
that delegates to the preseed/asc aspects, so p7_ascension.module, asc_sky.module
and asc_sky.shader are unchanged, the asc aspect tree is untouched, and the
fork's asc_fill.computeShader is dropped as unreferenced.
---
Point the third_person controller reference at its current path
The component moved to controller/legacy/third_person.component, so the
world entrypoint's @builtin::controller.third_person no longer resolves.
---
ASCENSION/DESERT: a deforming dune sea, and the desert clock bus
The dune field deforms in the mesh VERTICES, on the GPU, every frame, as a pure
function of the clock bus. asc_dune.computeShader is a kind: vertices pass over a
224x224 grid (50 176 vertices, ~99 k triangles) across 1400 units, and its height
is the sum of exactly four terms: transverse dunes with a gentle windward ramp and
a steep lee slip face; the migration of that whole train downwind by
windAccum x CREST_RATE; scour lowering and rounding the crests as the storm planes
them off; and the tornado's passage, swept along the 24-sample ground track up to
torTrackN as a trench with twin berms and radial rake. Normals are recomputed in
the same pass from four extra evaluations of the height law rather than from reads
of the neighbouring vertices, which within one dispatch would race.
No accumulation buffer, and that is the point: seeking to t = 12 and back to t = 2
returns a byte-identical frame (matching md5), so a held preview frame is the same
desert however it was arrived at. Measured: boundsSource = compute, 0 dispatch
failures, field relief 43.6 u at t = 3 falling to 26.0 u at t = 25 as the crests
are planed off, an 8 u trench with a 5 u berm at +/-36 u across the track, and
TYPE_PAN flat to 0.00 +/- 0.00 by t = 29.
asc_sand.shader lights it: engine PBR plus a hemispheric sky-dome fill whose upper
half is the zenith colour and whose lower half is the sand's own bounce (in a
sandstorm the sky is the lamp), the 1.4 u wind-aligned ripple in the normal, a
mid-band relief between the 6.28 u mesh cell and that ripple, a grain glint inside
40 u, and the aerial perspective the whole part shares at the bus's visRange.
Measured at H1 against the palette's P1 row: p50 106 (#8A6237), p95 165
(#C89A62), zero per cent green, cyan and magenta.
asc_clock gains the WIND / TORNADO / STORM contract the other four lanes read -
windDir, windStr, windAccum (a cumulative table, not a running sum), gust, torX,
torZ, torR, torH, torSpin, ignite, fireKey, dustDen, visRange, scour, plus
shadowStrength, sunDiscScale, emberLights, dustLitByFire, typeReveal, typeGlow,
torTrack and torTrackN - and the world conventions those need. The light and sky
tables are retuned to the desert, and the phrase rows now HOLD and cross on their
boundary instead of ramping between phrase starts, which is what puts each hero
frame on the row it was authored in.
asc_palette's crossover carries no third hue any more: between sand ochre and dust
brown-violet there is no legal arc, and the old descending one put #002A56 and
#091E2A in the sky. checkPalette gains a green/cyan detector at a 0.00 per cent
budget; it reads 0.00 at every judged timestamp.
asc_shots gets the explicit six-shot camera track with its two cuts and its
absolute lock, and stands the eye on the sand: a y of 2.2 in a field with 42 u of
relief is only meaningful above the surface, and DESERT publishes that surface.
The shutter is closed for the whole track - across a cut or a seek its reference
is a camera somewhere else and the frame came back smeared corner to corner.
asc_terrain, asc_deck, asc_march and asc_march_c are deleted; their composite
passes were painting an unwritten render target over every frame.
Attributed GPU at H4: 3.79 ms median, against 4.32 before this round and a 13.5 ms
target. DESERT's own share measures 0.08 ms against its 1.8 ms allocation.
---
ASCENSION/DESERT: fold in the remaining dune-field source
The same round as the previous commit; these files were rewritten by the play
shadow's promotion after they were first staged.
---
desert(round 2): band-limit the sand, put the sun back in the picture
Round 1 was rejected by all three critics on the same three things — the
ripple read as corrugated iron, P1 and P6 had no cast-shadow contrast, and
the sand was brick red at the fire accent's saturation. All three are fixed
at their cause rather than trimmed.
asc_sand.shader
- A CONTRAST LIMITER on surface detail. A low sun is a normal-perturbation
amplifier whose gain is 1/tan(elev): capping the tilt (normal_cos) never
capped what was seen, so the cap is now on the direct term's modulation
(ripple_contrast). Measured peak-to-trough on a lit face falls from 108 to
under 22 grey levels while the ripple stays visible.
- The 1.4 u ripple is patchy, asymmetric and carries a finer second train, so
a train of ripples reads as sand rather than as a machined sine. Its
wavelength was never wrong — a phase-and-footprint diagnostic showed 1.4 u
at S1's 10 u near ground through a 38 lens genuinely projects at 70-90 px.
- THE KEY IS ELEVATION-NORMALISED, which is what rescues P6. At 2.2 degrees
N.L on a horizontal plain is 0.038, so 4's sunInt 3.4 delivered an eighth
of the frame and every berm, trench lip and shadow vanished into one value.
sunInt now reads as ground illuminance; relief comes from ndl's variation,
bounded by key_relief_max. H5's luma spread goes 29.7 -> 90.4.
- A five-tap penumbra on the cascade, whose texel at 2.2 degrees is the size
of a berm.
- The hue floor is on (G-B)/(R-B) — which IS the hue — instead of on two
channels independently, which only bound at full chroma and delivered
19.6 degrees. The chroma ceiling moved AFTER the fog so it constrains the
delivered pixel. Sand now measures hue 22-36 at saturation <= 0.70 where it
measured hue 13-18 at 0.91.
- Aerial perspective is azimuthal, matching the dome's own ANTI_SUN law, and
the outer ring carries its own extinction so a 1400 u field never shows an
edge.
- The dome is linear in hemi, not squared: a warm bounce times a warm albedo
squared the warmth and made shadows the most saturated thing in frame.
asc_dune.computeShader
- EVERY WAVELENGTH IS NOW MEASURED IN MESH CELLS. Normals are central
differences at +/-6.28 u, so a 26 u term quantises to the grid and at a
2.2 degree sun that arrives as hard dentate plateaus — which survived
turning the cast shadow off, proving they were geometry. Nothing under
seven cells remains; the sub-cell detail moved into the fragment normal
where it is band-limited per pixel.
- The radial scour rays are phased on ARC LENGTH, not angle: fifteen angular
cycles put them two cells apart near the axis.
asc_palette.module
- skyMid is clamped to the horizon's own chroma. Above 1 it hit the gamut
boundary, where the ochre hue has BLUE = 0 — the published mid carried zero
blue for P2-P7 and dragged the lower dome toward yellow-grey.
- The magenta detector is a hue test. "Green below both others" flags 3's own
Dominant B and read 23-85% on the rows 3 wrote.
- 3 rule 5 gets its own detector at its own threshold, budget 0.00%.
- M.PHRASES carried the retired sunset's teal and blue rows.
asc_shots.module
- S5's look is lowered to y 58/62. Solved against the pose, 5.3's own numbers
put the view axis 41 degrees above horizontal at t=22.50, so 7 H4's crest
silhouettes and trench were outside the frustum, not merely dim — which is
why the demo's loudest frame delivered an empty card.
- FAR 2000 -> 30000. A depth clip at constant distance is a circle, and it was
the visible edge of the world at t=26.
Measured at H4: 3.20 ms attributed GPU (round 1: 3.79), ladder at rung 0,
against an 1.8 ms allocation. boundsSource = compute, 1806 dispatches,
0 failures. desert_r2_t02 and desert_r2_repeat_t02 are md5-identical, so the
deform is still a pure function of t.
---
desert(round 2): the sky bridge stays inside the gamut
MID_C 1.70 ran the fit to the sRGB gamut boundary, where the ochre hue's
boundary at this lightness has BLUE = 0 — the published skyMid was
#684007 / #512C02 / #441F00 for P2-P6, colours 3 contains nowhere, and the
magenta detector then read 84-87 percent at P3 and P6 on intermediate mixes
between that zero-blue orange and a violet zenith. At 0.85 the bridge is
inside both ends and delivers #644C32 / #4C3826 / #61492F.
3 rule 5's own detector now reads 0.00 percent at every phrase in the sky's
blend law, while the delivered frame at t=17 measures 59.6 percent neutral —
which localises that defect downstream of the rows, in asc_sky.shader or the
post chain, and is the number to hand LIGHT.
---
ASCENSION lane 3: the fire tornado
asc_pyre.computeShader a 96x192x96 rotating vortex fill. Every noise field is
sampled in a cylindrical frame un-spun by aux.torSpinAccum, with differential
shear and a height-linear twist, so the surface features wrap around the axis
and visibly turn. Skirt at 1.9x the waist, waist at 80/240, a separate
noise-radiused anvil across the top fifth, three helical flame ropes, a
white-hot core, and a base debris torus keyed to the spin peak. ignite is fire
COVERAGE from the root, so one scalar carries both the 0.30 s ignition sweep
and the top-down collapse; aux.torTear separates the ropes from the axis.
asc_tornado.module spawns the volume on the DEFORMED sand via DESERT's
duneGroundAt, composites through preseed/volume at post priority 5, drives one
fireKey point light plus eight embers (nine, no more, none casting), and flies
a 2400-point spark swarm entirely in the vertex stage. Outside t in [10, 28.2]
it clears the texture once and hands the march a degenerate AABB.
asc_spark.shader the entrained spark swarm, on fyr_ember's pattern but
sized to a 240 u vortex and reading the column's live profile.
asc_clock two aux amendments under lane 3's append-only right:
torSpinAccum (the integral of torSpin, in revolutions) and torTear.
Measured: 4.80 ms attributed GPU at H4 against a 3.25 ms baseline and a 4.4 ms
allocation; ladder at rung 0 throughout. A held frame at t = 17 is md5-identical
across a full part rebuild. Green and cyan measure 0.00 percent at all thirteen
judged timestamps; 0.00 percent clipped and 0.00 percent near-white.
---
ASCENSION/TORNADO r2: the column turns, the ramp keeps its hue, the base dies into the sand
asc_pyre: helical structure that survives the raymarch (twisted anisotropic
noise plus an integer angular-lobe term evaluated on the outer shell, with the
medium dense enough that the near wall carries the radiance); monotone-narrowing
body with the root swell confined to an absolute 30 u; skirt and anvil as
separate terms, the anvil capped below the root swell and sheared downwind;
ramp authored as pre-tonemap radiance against the measured display ceiling so
the core reads #FFF0C8 rather than neutral; density gated by the birth ramp so
the arrival brightens the frame instead of punching a hole in it; density faded
into the sand and around the camera; the base torus gated on the spin peak
alone; the tear throws three ropes off the axis on 120-degree bearings and they
carry their own fire.
asc_spark: camera-facing quads with a radial falloff and a constant screen size,
blended additively so an ember can only add light.
asc_tornado: 128x256x128 fill, march at 2.0 u x 172, emission gain applied once,
fireKey recalibrated at the P4/P5 stations.
---
storm: the sandstorm — an analytic dust medium at post priority 6, 45k GPU grains, and three lifted-sand lights
The medium is a half-resolution scene-depth-aware march (asc_dust.computeShader)
composited by asc_dustmix at priority 6, AFTER the fire's own composite at 5, so
the storm's extinction and inscatter are applied over the column and the tornado
sits IN the storm. Density is a dense ground layer under a wall body with a
noise-ragged top, a lobed haboob face that arrives and passes, a 1/r vortex curl
about the tornado's axis from t=10, and three octaves advected by windAccum.
Extinction is density/visRange and nothing else. Inscatter is mixed between two
ends solved from the dome's own aux.skyMid and aux.skyHorizon on a
Henyey-Greenstein phase against the sun, and lerped toward #FF7A22 on
aux.dustLitByFire in DISPLAY space.
The particulate is one 45,000-grain mesh on asc_grain, re-tiled around the
camera and flown entirely in the vertex stage; count is a threshold on the seed.
Determinism verified: t=17 captured twice across a forced part rebuild is
byte-identical. Green/cyan/magenta measure 0.00 % at all sixteen judged frames.
---
TIDES/SKY: the shared contract, a volumetric squall and a softened horizon
state.module is the lane contract for part 9 - pure functions of part-local t
only (ship, sea, weather, light, palette), so a hot-reload cannot leave one
lane running new code against another lane's old values, and so the wake is
derivable from the ship track rather than accumulated across frames.
sky.module builds the squall: a real-scale density field (9 km across, 350 m to
4600 m) raymarched through preseed.volume and self-shadowed with three taps
toward the sun, carrying a squall line that sweeps past her, a hard-edged shelf
that takes the sun at t=25, a ragged slot that lets one shaft back through for
bar 22, and a volumetric rain veil below the base from t=25. The sun direction
is read live from the scene so the clouds, the shadows and the glitter track
cannot disagree. Height fog lays the warm low haze that softens the sea/sky
seam and hides the ocean clipmap's far edge.
tid_cloud_fill is the fill shader as a folder asset - bindings generated from
bindings.yaml, never hand-written.
p5_tides delegates its sky to the lane, drops the wrong 'bow to -x' comment
(bow is +X), and frames the clouds at the END of update, after the camera.
---
storm: a haboob head with a silhouette, a swarm that reaches the frame, and a fire halo with a radius
The grain shader wrote out.position in WORLD space where the vertex stage's
output is object-local, so every grain was displaced by the entity translation
and drawn six kilometres off frame. Three critics measured the swarm at zero
pixels of high-frequency contribution; it was never on screen.
The medium is now two bodies. The ambient haze e-folds at visRange exactly, so
aerial perspective is a real depth cue instead of an inversion. The head is a
separate, much denser object with a lobed face, a ragged crown that varies
across-wind, self-shadowing rolls and a backlit sun path -- it has a silhouette,
an inside and a lit edge. It falls to zero once it has passed.
The fire's hand is a local halo on a radius rather than a frame-wide mix, and the
tornado clears its own local air, which is what lets the climax keep its range.
The march jitters its start offset per pixel and the composite dithers and
five-taps, both gated on the medium's own coverage.
---
TIDES/SKY: decorrelate the density hash and widen the deck falloff
The value-noise hash scaled all three components by the same constant, which
makes it degenerate along the diagonals and stamps a fixed herringbone through
the whole field. It survived a 6x finer raymarch step and a 4x larger step
budget unchanged, which is what identified it as the field rather than the
march. Three distinct constants remove it.
The deck now thins well before the AABB wall. A near-horizon ray runs edge-on
through the deck for kilometres and integrates ~90 voxels, so per-voxel
variation accumulated into per-column streaking; keeping those long paths in
weak medium is both the fix and what a real deck does as it recedes into haze.
---
ASCENSION LIGHT: salvage r1 spine (clock bus, palette, dust-dome sky, shots, grade)
---
tides/sky: a TIDES-owned volumetric squall, and the three engine facts round 1 missed\n\nThe cloud pass no longer goes through preseed.volume. That module marches\nthrough preseed.emission_raymarch, which builds its ray from unproject(ndc,0)\nto unproject(ndc,1) and tests depth < 1.0 for a surface -- both correct before\nthe engine's projection was reversed and both wrong after it -- into one fixed\n1600x900 target shared with every volume in the demo. tid_cloud_march and\ntid_cloud_composite are this part's own: reversed depth in closed form, so the\nferry occludes cloud and no occluder-range fudge is needed; a target at the\nbackbuffer size; and a step that grows with distance.\n\nMeasured, cloud band, mean |dL/dx| per adjacent pixel: 8.1-20.0 before, 0.15-1.59\nafter. Beat-1 structure energy at the 60px scale: 2.3 before, 20.3 after. Beat-3\nsky local contrast against the hull's: 24.2 vs 2.3 before, 0.16 vs 3.35 after.\nCloud b/r: 0.72-0.88 before, 0.43-0.66 after.\n\nThree things the field had to learn: every fill frequency is bounded by the\nvoxel pitch, because the cell map is a function of x and z only and anything\nfiner aliases into fluting that is constant down a column; the sun's extinction\ntaps are a jittered cone, because four fixed offsets comb-filter the medium\nalong a near-horizontal sun; and the march jitters WITHIN each step, because a\nstart offset bounded by the near step is a fraction of a step out at the deck.\n\nAlso: the scene carries its own ProceduralSky, and SkyConfig is one global\nrecord, so a part that spawns a second one gets a fight rather than a sky --\nwhich is why round 1 had no sun disc, the wrong gradient, and a near-black bar\nunder the horizon. This drives the scene's sky and restores it on exit.
---
ASCENSION LIGHT r2: black point + output dither (asc_tone), sky inverts it, real P1 key, evict foreign post passes
---
ASCENSION LIGHT r2: sunInt back to brief column, exposure 1.95, hot-tint keyed off brightness (neutral 17.4pct to 0.91pct)
---
TIDES LIGHT: drive the scene's sun and ambient, and cut the key with measured cloud transmittance
The part spawned tid_sun and tid_ambient; neither ever reached the renderer.
/runtime/lighting resolves exactly one directional and one ambient, and in this
scene those are the persistent 'sun' and 'ambient' entities. Measured mid-part
with tid_sun at 3.0 and tid_ambient at 2.0, the resolved key was the scene sun
at 0.12 and the fill at 0.14 - the brief's black, colourless sea. The two dead
lights are removed and this lane drives the scene's own, restoring on exit.
The key's occlusion is measured rather than scheduled: tid_key_probe marches
eight rays from the ferry toward the sun through the part's own cloud volume
and reports transmittance back over a readback buffer. Optical depth is
normalised to a 500 m reference path, because a 4-degree beam crossing an 11 km
box saturates on any weather (0.985 at t=8 but 2e-5 by t=25). For the first
twenty-four seconds the key is the medium's answer alone; after that the
authored occlusion is a floor, and the slot's own window re-opens it because the
wedge is carved beyond 2.2 km and the probe stands inside that under the veil.
Also: fixes the bloom override (0.8+0.4*level -> 0.42+0.10*level, threshold 1.0),
drives the ACES exposure ramp, recaptures the reflection probe on every beat
boundary rather than once at build, ramps keyOcclusion's trailing edge so the
key falls to 1.4 over a bar instead of stepping inside one frame, and adds
tid_chroma - Fx.grade has no chromatic_aberration preset, so the brief's 0.0018
had been read and dropped in silence since before this round.
---
ascension(finish): the title in the sand, the credit cards, and the finish slot wired
asc_finish.module is aspect 5. The set line is tessellated from Anton glyph
outlines with font.textMesh and extruded, rotated onto the ground at build time
so the entity transform stays a pure translation and localScale.y is the relief
rising out of the pan on aux.typeReveal. It renders through DESERT's own sand
shader with the whole property set mirrored off asc_sand_field every frame, so
the letters are the pan's material under the same key and separate from it only
by cast shadow and lit side walls. aux.typeGlow lifts the same material's dome
term toward #FFF0C8 rather than adding an emissive channel.
The three credit cards are Text3D, pinned in the camera's own basis on the left
rail, on the schedule the P6 window allows.
p7_ascension names the finish slot so the aspect is built and updated in §8's
order. asc_point, the handoff NDC, its hex and its priority are untouched.
---
ascension(finish): lift the extruded set line onto the pan
font.textMesh extrudes into NEGATIVE z — with depth = 1 the glyph solid
occupies z in [-1, 0] with the front face at 0. Mapping that straight onto
world +Y buried the whole set line under the pan and delivered a riser of
exactly zero. Measured off the built vertices, not assumed. The solid now
occupies y in [0, RELIEF]: span 295.2 u, riser 0.0 -> 0.9, baked yaw 18.417
degrees.
---
tides/light: a key that reaches the ship, a black point, and a print stage
The sun moves from her port quarter (232) to her starboard quarter (140): at
232 no surface a starboard camera can see could take any key at all, which is
the flat, ambient-washed ship three independent reads measured. The fill comes
down from 1.6-2.2 to 1.05-1.55 and its green is lifted so the banned
magenta band closes arithmetically rather than by luck. Exposure is set from
the rendered histogram instead of transcribed. A tides-owned print stage
(chromatic aberration + a lifted print black + a triangular dither) runs last
before the letterbox, and re-attaches itself when a neighbouring part's grade
evicts it. Every tunable in the light contract now lives inside a function body
so a hot-reload can retune it.
Measured over the ten-frame grid: exact black 15-54% -> 0.00%, 1st percentile
0 -> 7.2-9.0, peak 165-184 -> 200-223, banned-hue census 4.3% -> under 1.4%.
---
tides/light: settle the fill and the print floor on the measured values
The fill's green is lifted until 1.5*(g-r) >= (b-r), which closes the banned
magenta band outright instead of narrowing it: a neutral carrying any mix of
this fill and the warm key cannot satisfy (b > r AND r > g). Measured on the
slot hero, the banned-hue census went 10.24% -> 6.67% -> 0.04%.
---
tides/light: delete tid_chroma.shader, replaced by tid_print.shader
The print stage supersedes it: same chromatic aberration, plus the print black
and the dither, and at a priority that puts it last before the letterbox.
---
tides/light: remove tid_chroma.shader, superseded by tid_print.shader
---
tides/light: record the tid_chroma.shader leaves as deleted
---
ferry: the Farjan rebuilt — bulb, stem, plating, transom, funnel casing, boats in davits, markings, procedural hull material, practicals
---
farjan+ascension: ferry hull and glow shaders, tides part, ascension terrain and march
Checkpoint of the work in flight when the TIDES workflow was stopped. The ferry
gains its own hull and glow shaders and p5_tides is wired to them; the ascension
side folds in the terrain, march and deck modules as the lanes left them.
---
farjan+ascension: fold in the remaining lane source
The same round as the previous commit; the live session rewrote these paths
after they were first staged.
---
farjan: the tides sky, light, state and cloud assets
The TIDES lanes as the stopped workflow left them: a volumetric cloud fill and
march with a composite, the sky and light modules that drive them off the shared
state, and the ferry hull and glow shaders.
---
asc_lens: re-record refs so @frame.camera reads as engine frame state, not an asset1a8f0d784dfreshcut: ground-truth occlusion, an antialiased image, and two defects the lit frame never showed
GTAO joins the shared stack, and with it screen-space GI, edge antialiasing and
sharpening. All four sit in base(), so any part opting into the stack gets them
rather than each part deciding again. The mansion additionally takes screen-space
reflections for the polished chequer floor and the mirror; roughnessCutoff keeps
the trace to surfaces smooth enough to show anything, so plaster and fabric never
pay for it.
Screen-space GI is the term image-based lighting could not supply indoors. It is
derived from what the frame actually drew, so a wall occludes it, where the IBL
diffuse landed sky irradiance on every interior surface at full strength.
Antialiasing comes before sharpening in the raise order: sharpening an aliased
edge sharpens the staircase. Twelve systems now, and the frame cost did not move.
Two defects found by asking the engine rather than by looking at a picture, both
invisible in every lit capture taken of this hall:
The stair carpet z-fought on every step. A tread top face sits at y + dy*0.5, and
the red runner was laid at +0.02 with a half-thickness of 0.02, putting its
underside on exactly that plane; the gold band a further 0.01 up overlapped the
red almost entirely. Two coplanar pairs per step, sixteen steps. The red now
clears the tread by ten millimetres and the gold is embedded in the red rather
than stacked on it, so no two faces share a plane.
The volume composite rebound a dead effect every frame. ensure() was guarded by a
module-level flag, spawn() called it and frame() never did — but the module
outlives a part and the effect does not, so after a mode flip the flag still
claimed a registration that had gone and every later bind failed with an invalid
effect. ensure() now verifies against the live post chain instead of trusting the
flag, and frame() re-establishes before binding. The texture and shader creates
are guarded so a re-ensure cannot abort on one already being present; the effect
re-add is the part that has to land.
Known and not addressed: the balustrade rails and a sideboard still z-fight. The
balusters top out clear of the rail underside, so it is not the coplanar cause
the treads had.8a9492c17dfreshcut: a shared render stack, and the rules for using it
render.module is the seam: a part hands over a table naming which of the
builtin rendering systems it wants, and everything raised is temporary and
tracked on the part own context, so one part can be a lit interior and the
next an ocean without either inheriting the other air. Adding a system is one
row in a lookup table.
freshcut takes exposure, aerial perspective, volumetric light, cascade
placement, contact shadows, debanding and film grain.
Three things this cost, all written down where the next part will read them,
because each looked like a tuning number and was not:
Auto exposure over its full range re-brightens an interior that is already lit
to a photographic level and blows it out. The range here is narrow and sits
below unity. It is not there to find the exposure, only to ride the walk from
the hall into daylight. Past about -0.5 stops of compensation it takes the
metals down with it, because a reflection has no light of its own to fall back
on.
Image-based lighting is NOT used in this part. Its specular term and
environment.capture write the same environment and the last one wins, and what
this hall reflects is the room and its own lamps, which a prefiltered sky
cannot reproduce. Nor is specular = 0 a way to keep both: it does not hand the
environment back to the capture, it removes the environment specular outright
and the metals render black. Its diffuse term has no indoor occlusion and lands
sky irradiance on every wall at full strength, which reads as a flat milky
room whatever the sky is doing.
Both of those read the scene ProceduralSky, which was sitting at midnight with
a deep blue zenith because this part drives its look through a volumetric sky
and nothing had ever updated the component. Any system asking the scene what
the sky is was being told midnight. The part now sets it to the hour it is
actually lit for.
Known and not addressed: the hall metals still read darker than they did
before the stack went in.58ecd5fd81tides: the Zero Line ferry on the spectral sea, and three winding fixes
Tides was a hand-rolled Gerstner ocean under a sunset dome, with a chrome ring
and glass monoliths on four custom shaders. It is now the builtin oceans
package -- a spectral FFT sea in cascades with the swell over it, foam struck
from the Jacobian where the wave actually breaks, and a seabed the water is
seen through. The part states a sea state and a depth; the package builds it.
The part owns the light, because that is what the package reads: sky, sun,
ambient and a reflection probe. The hour orients the sun but does not paint the
dome, so the sunset is authored rather than implied by the time of day. The
evening ambient is kept low and only faintly cool -- carried at a tropical
noons strength it computed the red topsides past 1.0, and the blue it added on
top of the clipped red turned a painted hull neon.
The ferry and its buoyancy come from ZeroMind, published out of the Farjan2
world. Her entry was drawn over the forward third of the length, which reads as
a long clipper nose on a ro-pax; the parallel middle body now runs further
forward and the flat of the bottom and the forefoot follow it. The funnel moves
forward by its own base radius, off the after deckhouse, and its body, top, cap
and both diamonds now hang off one station so they cannot drift apart.
Three winding faults, each found by comparing every triangles geometric normal
against its authored one and confirmed on an isolated primitive:
meshbuild wound every box and tube into the solid -- one quad helper emitting
its two triangles in the order the corners arrived, plus the tube caps. The
ferrys hull was unaffected because it emits its own indices.
A negative extent mirrors a box and reverses the winding of every face on that
axis. It arrives by ordinary arithmetic: a stair tread is dz + 0.16, and dz
runs backwards down the flight. Extents are sizes, so both box builders now
take them as magnitudes.
The cylinder builders z axis fell through to the identity while x and y each
applied a single swap, so it carried the opposite handedness and every z
cylinder in the house was inside out.
367,508 triangles now audit clean, counting the whole palace built into fresh
builders. All thirteen parts rebuild.743320c6e0freshcut: the mansion as a PBR palace, glazed and lit
Carries the palace rework that had been sitting uncommitted in the working
tree since 2026-07-25 -- the hollow vertex-coloured house becomes a Palladian
palace on builtin PBR, authored one builder per material class (stone, marble,
oak, gilt, glass, fabric, mirror, glow) with a domed double-height hall, a
gallery on an imperial staircase, colonnaded links and two end pavilions --
together with the fixes below.
The gallery walk was one solid oak box with parquet over its top, so the face
the hall sees from below was raw dark timber: a black band across every stair
shot. All three runs now carry a plaster soffit and a moulded fascia along the
open edge. The slab itself stays oak, because the parquet slats are inset and
a pale slab would show through the floor above.
Glazing no longer blocks the sun. A pane inherits castsShadows, so every window
was a light blocker and the house was lit by its own lamps alone; glass is the
one class that now spawns without it. The panes are also transparent for the
first time -- alpha alone does nothing while a material is opaque, so the class
carries alpha blending and specular transmission, and the sashes read through
to the sky.
The interior daylight was blue enough to read as moonlight and pull the
limestone grey. It is close to neutral now, the hall carries about seventy per
cent more light, a low bounce keeps the chequer floor and the plinths from
falling away to black, and each principal room has a daylight fill so it reads
as a lit room through its archway.
Materials differentiate: marble tightens under a waxed clearcoat, oak gains a
varnish lobe, stone softens, fabric flattens. Gilt stays deliberately broad --
a tighter lobe returns more of the single environment probe, which holds a dim
room, and the torchères go black.
The imperial stair landed forward of the dome: its foot sat at -26.6 against a
hall centre of -27.5, so the ball hung over the treads and the marble compass
inlaid at the centre was buried under the flight. The foot moves back to -29.0
and the run comes out of the half-landing, which clears the centre and puts the
flight on roughly thirty degrees.f04560e69dfreshcut: a hollow mansion, the Amiga ball, and one move out to the great garden
The mansion becomes a house you can be inside. Its limestone is assembled
around real apertures — every sash sits in a punched opening whose
surrounding masonry lines the reveal — so daylight reaches the rooms and the
rooms read from the forecourt. Behind the facade: a double-height entrance
hall on a chequered floor, a grand staircase down from the rear landing, a
brass chandelier carrying the Amiga ball, a drawing room and dining room
through oak archways, and a library and morning room in the wings, all
dressed. The twin front doors are dark oak and swing on cue.
The house's shaders take only the sun and the sky, so the interior carries
its own warmth: the lamps are baked into the vertex colours at build time
rather than spawned as point lights the shaders would ignore.
Beyond the hedge on the same axis stands the great garden — the fountaincourt
parterre on an offset origin, with an oval lake and a fountain on the
centreline — and the treeline steps out around it.
The part is now one continuous move: the camera starts on the landing, walks
down under the ball, out through the opening doors, across the forecourt and
past the mower, then climbs over the freshly carved mark and on into the
garden. The caption re-anchors into the hall, ahead of the camera for its
whole window.
---
fix(preseed): migrate the retired Collider component to the typed shape colliders
@builtin::components.Collider moved to @builtin::components.legacy.Collider, so
every add() against the old identity raised "is not a registered component
type" and aborted the part build at the first call.
freshcut lost the mansion, estate and mower at mowfield spawnVisuals. collapse
lost the tower, crane and ball at the first piece, and its update then threw
every frame on a nil reach. discharge lost its static props and victims.
Box sites take BoxCollider with half-extents, sphere sites SphereCollider with
a radius; friction and restitution carry over unchanged.
freshcut also bakes an environment reflection, from the hall on enter and again
from the forecourt once the camera clears the doors, so the gilt, mirror and
glass read as metal instead of black.d5dbaaa76fcollapse: declare continuous collision per body
The tower's 271 structural pieces say ccd = false and the wrecking ball
says ccd = true, instead of both inheriting whatever the engine default
happens to be. The ball crosses its own diameter every couple of frames
on the way in and has to meet the facade rather than appear on the far
side of it; the debris is thick enough, and moving inside enough dust,
that a swept collision buys the shot nothing and costs it the frame.403a017da1collapse: one blow takes a nine-storey tower
The wrecking ball no longer chews the building down over five strikes. It
hangs, sweeps in on its arc, and lands one heavy blow on the section's single
impact cue — then carries straight on through the tower and out the back wall,
opening the corridor ahead of itself as it goes. The failure runs out and up
from the strike and the whole structure folds into its own footprint.
The building is now nine storeys instead of five, with cornice bands, a fire
escape up the right facade, and a roof deck (stair penthouse, water tank on
legs, vents, mast, signboard).
The part is 25 s instead of 30, so the score loses four bars from the collapse
section and every later section moves back with it; captions and the baked
soundtrack follow. Film is 335 s, score 260 bars.
Performance, whole part, measured back to back against the old part on the
same machine: physics p90 22.6 -> 1.8 ms, frame p90 56.5 -> 45.8 ms, spike
frames 11.1% -> 8.9%, frame p50 36.9 -> 33.8 ms. Structure is static until the
blow rather than kinematic, the release wave is a sorted walk instead of a
per-frame scan of the tower, settled rubble petrifies on a widening gate, and
the facade's glass and window frames fly ballistically instead of as bodies.95bb0e4a70tendril: bake the cave tunnel at 2048, drop repro leftovers
The tunnel carries 3107 m2 of surface, more than the rest of the cave set
combined, and its lightmap was the coarsest of the 79 receivers at roughly
12 cm per effective texel while every prop around it sat at 3-4 cm. It now
bakes at 2048 with 64 samples: 917,767 valid texels, 4x the density, on its
own atlas page. setupPersistentGi splits its pass from the props so the two
carry different resolutions.
Also removes repro_a1 / repro_a2 / repro_b, three component-less entities
left in the scene by an earlier investigation.b311dfcf8ctendril: regenerate cave lightmap UVs and re-bake the set
The cave's 13 ten_cave_* meshes carried lightmap charts laid out in
whatever orientation their planar basis happened to produce, so each
chart's triangles filled about a tenth of the bounding rectangle the
atlas packer had to reserve for it. The tunnel spent a 1024 square
lightmap on 87k usable texels — roughly 27 cm of wall per texel.
Every mesh is re-unwrapped in place (same guid, same positions, same
triangle and vertex counts) and the whole set re-baked against the new
coordinates. The tunnel now claims 229,472 texels of the same lightmap,
2.6x what it held before, and the cave still reads 79/79 covered.
Mean gain across the 13 meshes is 1.83x; the crystal clusters gain the
most at 2.3-2.8x.dbe765bc91tendril: re-bake cave_stag8 lightmap
Cleared and re-baked while checking whether a freshly baked lightmap
reaches the render the same way a loaded one does. Same parameters as the
rest of the set (texelsPerMeter 16, samples 32, intensity 2.5); the entry
differs from the previous one only in its atlas placement.6a0eda4e89tendril: lightmap the tessellated cave tunnel
The tunnel Model carries a Tessellation component, and until the lightmap
UV set became a stream the tessellation pass produces, its runtime output
reached the bake with tiled uv0 only — bakeAll routed it to the probe
field while the other 78 rock receivers took per-texel lightmaps.
Its unwrapped uv1 now survives tessellation, so the bake resolves it as a
lightmap receiver: 1024 square, 87012 valid texels, baked at the same
texelsPerMeter 16 / samples 32 / intensity 2.5 as the rest of the set.
The cave now reads 79/79 static surfaces covered.134921e58ecrawler cave: persistent set entities + ten_cave_* mesh assets (unwrapped lightmap UVs)
---
crawler cave: baked GI container — 78 prop lightmaps + tunnel irradiance probe field
---
p_tendril: build the moving cast over the persistent baked set; setupPersistentGi authoring op; cave spawns static Models from mesh assets
---
setupPersistentGi: read engine.mode directly for the edit-mode gateb29f542ef2cave part: runtime-baked GI — lightmapped rock, probe-lit creature764da2f4b4revert compute-mesh vertex stride to 23 words (92 B) per engine ABI freezec37ae025c4fix: update compute-written vertex strides 23->25 u32 words (engine Vertex grew to 100 B with uv1)eb662e776ascore: swap reese/wob for clean bass — sub swells, rhythmic sub basslines, 808-and-sub bolts, donk answers; rhythms and cue contract unchangedc32d77e85dscore: strip to kick/drums/bass — synth walls and all melodic notes removed, riff becomes cue-only grid, riser band-limited, dark supersaw retired from the mixf2bce24044score: from-scratch rave set — untz/groove/wobble engines, Preseed hoover riff hook, acid lines, gated chops; contract cues pinnede8905c8f3fscore: EDM party cut — untz+wobble engines, sidechained supersaws, malletless mix; ring cues wired through analysis4bc89a0345procedural hedge fence generator (preseed.hedge) + hedge_leaf foliage shader; fountaincourt parterre/bosquet/topiary rebuilt with clipped hedges, spiral topiary, ball-finial piers
---
fountaincourt ground: fc_cobble Voronoi sett walks with travertine curbs, fc_lawn elliptical mow-stripe lawn
---
raise promenade, walks, and their furniture ~10cm to separate coplanar ground surfacesbc874459f1FONTAINE: real-time adaptive SPH stepping, sorted-mirror neighbor passes, MAXP fix, dusk sky with sun disc and stars, teal lake with warm jet bloom, candle rafts, foam thresholds, dusk haze grade6221afd9aafontaine: pre-settled fill, lake plane lowered to bed, darker sky pickup0199229c0cfontaine: real 330k-particle lake on engine fluidSurface + counting-sort SPH at H=0.45ff031b8d90FONTAINE: monumental water show on a 170x66m oval lake — three-tier fountain island, 24-nozzle articulated line array + 16-nozzle island ring (sweeps, crisscross lattices, traveling height waves, burst salvos, 30m geyser), elliptical grand parterre with statues, candelabra, bosquet, colonnade015f81d805p_sph: PATISSERIE -> FONTAINE — gilded two-tier fountain in a dusk palace court. Basin/pedestal/tazza SDFs + GPU drain pump with crown/side nozzles replace the mixing bowl; scalloped rim spills six overflow streams; pre-filled golden pool; champagne/rose tints blend in the basin. New fountaincourt set (checker plaza, balustrade, torcheres, peristyle, topiary); kitchen set and pat_tile/pat_wood shaders removed.42a47863e5feat(demo): play-mode transport controls — remote bar (prev/hold/next/replay, scrub slider, part+time readout, Left/Space/Right/R shortcuts) hosted on a component; director timeline/partIndex/held accessorsf8106d959bfeat(patisserie): full kitchen art pass — pat_checker/pat_tile/pat_wood procedural surfaces, patkitchen set (window wall, shaker cabinets, fridge, stove + lathe kettle, pendants, utensil rail, dense props), marble counter, pitcher set-down, retuned shots/glassffdb69b3bafix(patisserie): stage remaining part module + scene serialization9ec217b2cbAAA polish pass: living material drives, screen-space SPH water, depth-aware volumes, grounded ridges, z-fight-free estate
---
director: start() resolves DemoCamera when no camera is passed; commit canonical scene.json
---
p_mow AAA pass: hot summer day — heat-haze post, marble/limestone/glass mansion, parched lawn, contact AO
---
metadata for the mow estate shader assets
---
p_tendril: bilateral body-plan tendril gait — side-locked anchors, role reach windows, progress-based release
---
refactor(patisserie): DELUGE becomes a pastel-kitchen stand mixer — two colored SPH pours whisked into cream. 32k-particle sim (H 0.062 grid, agitation-scaled tint diffusion, bowl SDF boundary), fluid.module per-pixel color path, glass depth_write fix, Geo.cylinder winding fix, Geo.lathe builder
---
chore: render missing material previews (publish-gate content requirements)2b6824bf7flumen opener: pan-across title shots, music-driven volume halo rising to the oculus for the drop, Text3D lettering209c6b8cc3lumen opener rework WIP: pre-dawn skydome material, luminous glyph shader, rebuilt cathedral partf47e19ae85ascension finale rework: animated sunset skydome, ridged mountain layers, self-shadowed cloud deck, valley mist + rising motes, constellation dot-mesh title and credits