Rungs 2-4 embodied as hospital-white placeholder bodies (warden / gunship /
auditor), the gunship's ghost-mirrored sector + parity tether, the auditor's
0:00 stasis bleach, compliance placards, and the v9 onEvents migration.
The inversion is measured, not asserted: fed a worst-case integer-stepped
position that the sim moves on 6 of 120 frames, the warden renders 120 distinct
positions with zero stalled frames. The auditor renders 1 position and 119
stalled frames, deliberately — it moves only between frames (codex 5).
- correction.ts: tick-lerp + damped follow for wardens/gunships, instant
relocation + blink for auditors, instanced ghost mirror (cap 512), tether,
bleach + 00:00:00:00 timecode, and the frozen-entity set
- entities.ts: compliance placard + total idle/mixer/haze freeze (idle clock
delta measured at exactly 0.000000 over 30 sealed frames)
- beltitems.ts: cargo pinned MID-TILE inside a lock; the freeze path is
cheaper than the normal path (0.392 vs 0.465 ms at 2,000 items)
- index.ts: onEvents buffered and drained at the top of render(); repaired,
the firewall can, and relicFound all retired as snapshot heuristics
- notice.ts: the fax-side notice halo, with a one-frame retry because main.ts
runs the renderer BEFORE the UI and the panel may not be laid out yet
- correction.test.ts: 9 tests, mutation-checked. Pins the cross-lane rect
convention against LANE-SIM's own frozenEnt formula over 4,896 cases.
Perf at a deliberate worst case (500 entities, 2,000 items, the entire base
both mirrored AND frozen): whole frame 2.30 ms median against a 16.6 ms
budget; this round's net cost ~0.2 ms. Prod bundle clean of all scaffold.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
scene.environment was null for seven rounds. diffuse = albedo * (1 - metalness),
so a metal is nothing but reflected surroundings — and 13 of the 27 shipped GLB
materials are metallicFactor >= 0.8 (16 at >= 0.5, 21 with no MR texture). Round
6's GLB_EMISSIVE_FLOOR = 0.42 was cosmetics over a lighting hole.
- env.ts (new): procedural 128x64 half-float equirect through PMREMGenerator.
Zero bytes shipped, no asset fetch. Dark industrial room per codex 8; key/fill
blob directions passed in from index.ts's real lights, never duplicated.
- GLB materials take envMap explicitly (three overrides material.envMapIntensity
with scene.environmentIntensity on the scene-fallback path), so the assets can
be dosed at 2.6 while six rounds of hand-tuned world art keep 0.5.
- emissive floor 0.42 -> 0.18: re-tuned, not retired. Still the "never a hole"
guarantee and still what carries a machine through a brownout.
- registry.init no longer awaits probeAll: renderer.init 284ms -> 28ms, ready at
339ms -> 88ms. Placement juice suppressed on asset-version bumps so the factory
doesn't re-place itself a second into every boot; a def change still pops.
- era.ts: eraIndex now breaks a contested unlock FIRST-tech-wins, matching
LANE-UI's indexTech. It was LAST-tech-wins despite round 4's NOTES claiming
otherwise; the tests found it.
- registry.test.ts (new): 31 tests, this lane's first. 481 -> 512 repo tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- registry: texel-following emissive floor + one-impossible-element accent beacon on every
hot-swapped GLB (generic, no hardcoded list) — restores the two-material rule on baked assets
- wildlife: parity-mite beetles with green checkmark eye, size-driven state tell (hunt/repair/
sated), derived 'repaired' tidy sparkle + firewall-can 'filed paperwork' cue
- relics/juice: golden excavation geyser on unfound->found transition
- devscene: parity-mite fixtures across all three states for verification
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The review verdict was "the game about place has no place". The root cause was
not a missing feature: a raw ShaderMaterial gets none of the renderer's output
includes, so THREE.Color's sRGB->linear conversion was never undone and the
crust rendered ~6x too dark. Measured: authored #0c0a15 (RGB 12,10,21) came out
RGB(1,1,2). One #include <colorspace_fragment> and it measures (10,8,18). Every
raw shader in this lane has been that dark since round 1.
Round 5 orders 1-8:
- ground.ts: fbm terrain mottle + neutral rim + the colorspace fix.
- seams.ts: 8 seam regions from data/seams.json. Era skins the crust with a
wide falloff; the ore glints as sparse twinkling flecks (first pass drew
continuous veins and they read as green worms competing with the belts).
Fleck fade is short on purpose: SIM extracts on any footprint/rect overlap,
so a glint dying inside the boundary would under-report where mining works.
- relics.ts: unfound = a breathing static patch, found = fossil on a plinth.
Measured +39 contrast vs floor at wandering zoom, -18 at overview zoom —
findable by looking, invisible from above.
- wildlife.ts: dust-pile glitter heaps + gnat swarms, harassed machines stutter.
Two draw calls for the whole ecosystem.
- juice.ts: placement scale-pop + puff, demolition burst, shipment flash,
all derived from snapshot deltas since render() never sees events.
- breakroom.ts: the GLYTCH cabinet, own raycast, opens match.html.
- ghost.ts: inspect highlight + cooler aura (closes round 4's placed-and-
selected gap).
Also fixes juice never appearing: clock.getDelta() returns the real gap and a
backgrounded tab hands back SECONDS (measured 63.7s), so particles were born
and killed inside one update and the integrator flung them to infinity.
render() now clamps dt to 0.05.
Default framing lifts world origin clear of the build bar. 500 entities +
2,000 items + 50 piles + 198 gnats + the floor: 4.4ms/frame, 8 draw calls.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Round 4 orders 1-5:
- ghost keys demolition off setGhost's `mode` arg; the '__remove' sentinel is
ignored and REMOVE_DEF is gone from this lane.
- locked-build ghost: padlock-amber (not occupied-red — "not yet" and "not
here" are different sentences) + a padlock tinted by the gating era. Needed
a new ERA_TELL palette: ERA_SKIN.tint is a multiplier tuned to leave DATA's
chassis alone, so it can't carry a signal (stream is #ffffff).
- aura.ts: cooling coverage as a dashed RECTANGLE. coolRadius is chebyshev, so
the cooled region is the footprint grown by r per side; a circle would look
better and lie about the corners.
- lab placeholder: bench + the "bottled artifact triptych" (§2); consumes
MachineDef.accent when present, derivation stays the fallback.
Also:
- buffer fill reads bandwidth.capacity (v4) instead of re-summing bufferCap —
a second copy of the sim's arithmetic is what the scram latch warned about.
- lock rule matched to LANE-UI's reading: absent research means nothing has
completed, so gated machines padlock. Mine said the opposite; theirs is the
literal contract text, and the build bar and ghost disagreeing on the same
screen is worse than either answer.
- showroom fitted to BOTH axes. Round 3's depth-only fit collapsed the item
grid to one 206-tile row once the machine hall grew and ate the depth.
Verified against DATA's real v4 data and UI's migrated flow: 6x6 aura on
asic-cooler, reel/broadcast era tells, lab accent #ffc24a from data, 29
machines + 60 items in the showroom, 500 entities + 2,000 items at 3.6ms.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Confirms the units conversion (bufferCap 240 = 8.0s of cover at a 30/s
deficit) and reports scram survival: first scram t434, restart t934,
~718-tick duty cycle, ZERO brownout ticks across 20k, melt rate unchanged.
For the orchestrator:
- heat semantics need a one-line ruling. heatPerTick is GROSS in my model
(net = heatPerTick - coolPerTick). DATA's committed 0.0025 against the
0.004 default nets negative -- the decoder could never scram. Their
in-flight 0.0033/0.001 works, so we agree by luck of timing.
- the codex's literal bloom loop is not expressible with per-grade recipes
- asic-cooler does nothing without a spatial heat mechanic
- my sim code landed inside 45003db [ui] REMOVE mode: the shared tree has
one git index and an add-everything commit in another session swept it.
Not a UI ownership violation. Suggest a no-`git add -A` rule.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Round 2 orders 1-6:
- topology.ts: belt neighbour analysis -> straight/cornerA/cornerB/merge,
one InstancedMesh per (def x shape), flow field baked per shape. Corners
sweep a quarter-arc; merges get inlet arrows.
- cargo follows the corner arc: `t` is progress along the tile, so walking
items straight through the centre made them cut corners and pop in at the
wrong edge. They now enter at the feeding edge (verified 0.089-0.248 off
the centreline where straight pins to 0.000).
- heat.ts + entities.ts: dull-red body ramp, rising shimmer column, throttle
(idle AND GLB clips slow together), scram (dead-dark + amber, frozen) and
a restart path that restores what scram zeroed.
- buffer tanks show fill from their share of bandwidth.stored / bufferCap.
- AnimationMixer plays clip 0 looped; rigged GLBs clone via SkeletonUtils so
instances don't share a skeleton.
- exact cargo interpolation via BeltItem.id, order-matching kept as fallback.
- multi-mesh belt GLBs merge with groups (2 materials, 1 draw call) instead
of rendering only the first mesh.
MachineDef.color is wired to the BODY, not the accent, against the letter of
the orders: all 21 values DATA authored are industrial chassis neutrals per
codex/§8, and wiring them to the emissive makes every machine glow muddy and
kills the two-material rule. Flagged in NOTES for the orchestrator to settle.
500 entities + 2,000 items still at 3.6ms/frame (4.6x headroom), 5 draw calls.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces the render stub with the full M1 surface:
- camera: ortho iso rig, wheel zoom, middle/right-drag + WASD pan, resize
- ground: shader tile grid w/ world-edge dissolve + screen-space vignette
- registry: procedural placeholders (two-material rule) + MODELBEAST GLB
hot-swap, probed on init and every 10s in dev. GLBs auto-normalise to
the machine footprint, so any export scale lands correctly.
- belts: InstancedMesh per belt def, chevron scroll injected into a
MeshStandardMaterial so belts keep lighting/fog/brownout
- cargo: InstancedMesh per item type, interpolated across ticks via alpha
- ghost + pickTile with footprint occupancy (cyan valid / red blocked)
- feedback: jam klaxon blink, brownout dims the scene via tone-mapping
exposure so emissives dim too
Machine accents are derived from data (recipes -> outputs -> ItemDef.color),
with a legibility floor: near-black products like MDAT ORE would otherwise
render the extractor's CRT head as a black panel and its ore as invisible.
Verified in the dev build: 500 entities + 2,000 belt items at 3.2ms/frame
(5 instanced draw calls); a GLB dropped in mid-session swaps without reload.
Dev scaffold is DEV-gated and tree-shaken from the prod bundle.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>