Lanes A (engine), B (player), C (worldgen), D (machines/quest), E (audio/fx/ui) as landed, each with HANDOFF.md + update docs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
6.4 KiB
Lane C — World Builder · Progress Update
For Fable's review. Lane C = the level-design lane: author the entire DJ-booth
diorama in voxels via buildBooth(world).
Status: ✅ complete and verified. Typecheck clean, demo renders with no console errors, build deterministic and fully validated. Ready for Lane D to mount machines.
1. What shipped
| file | role |
|---|---|
src/worldgen/tools.ts |
voxel toolkit: box, hollowBox, cylinderY, sphere, line3, spline (Catmull-Rom), mulberry32 PRNG, bounds-guarded setVox, duck-typed fillBox fast path |
src/worldgen/anchors.ts |
single source of truth for every LAYOUT-derived position (deck furniture, mixer face, patch-bay grid, under-table) — so no coordinate is written twice |
src/worldgen/questPositions.ts |
QUEST_POS — the Lane C→D contract: exact voxels for stylus/rca/crossfader/fuse/power |
src/worldgen/buildBooth.ts |
the build: buildShell, buildDeckA/B, buildMixer, buildCableCanyon, buildPatchBay, buildUnderTable, set-dressing; exports SPAWN |
src/worldgen/index.ts |
public barrel for integrators |
src/demo/worldgenDemo.ts + demo-worldgen.html |
standalone InstancedMesh visualizer, zone teleports, live validation panel |
src/worldgen/HANDOFF.md |
API surface + integration notes |
2. What the booth contains (DESIGN §4, all present + eyeballed)
- Shell: warm plywood console,
ply_edgelaminate caps, front lip, hinge plates, tabletop with vent shafts behind each deck + a front-left crate hatch & stair. - Deck A / Deck B: steel-grey plinths, rubber feet, brushed-alu top border, a recessed empty platter well with chrome spindle stub, start/stop + 33/45 button recesses, pitch-fader canyon with green centre-detent, tonearm base pedestal + empty headshell socket, Technics strobe lamp. Deck B adds dust drifts + a half-open glass dust cover.
- Mixer Massif: matte-black body, speaker-mesh climb vents, 4 channel strips (silver/black knob-stem grids + empty fader alleys), the crossfader tram with the dust-jam plug, two VU-meter towers (green→amber→red), power-switch recess, fuse chimney.
- Cable Canyon: 5 splined RCA/power cables draping to the patch bay, gold plug heads, a power strip, and the quest cable ending short with a loose gold plug on the floor.
- Patch Bay: proud alu panel, 2×6 gold socket grid, the conspicuously empty quest socket (red blink), two sockets that are real doorways into copper-busbar rooms.
- PCB Depths: green board floors, copper trace paths, capacitor pillars, solder stalagmites, sparse LEDs, the fuse box (blown fuse), the parts bin (fresh-fuse + the blue-spotlit stylus block), and the record crate of blue/black vinyl slabs on edge.
3. Verification (headless + in-demo + cross-lane, all green)
✓ build < 500ms (14ms mock / 30.7ms real VoxelWorld)
✓ deterministic — two runs byte-identical (seed 1210)
✓ 0 out-of-bounds writes
✓ deck A + deck B platter wells empty (left for Lane D's platter)
✓ spawn stands on solid steel with headroom, facing the mixer
✓ 8/8 quest anchor points reachable (adjacent air)
✓ fuse & stylus anchors land on the intended block (not a neighbour)
✓ record crate populated (regression-guarded)
~4.5M non-air voxels · 24.6% fill · 29/30 non-air block types used
Screenshotted the spawn deck, whole booth, PCB Depths, and the record crate — all read clearly as the intended DJ-booth diorama.
Adversarial review pass. I ran a 5-dimension multi-agent review (12 agents, each finding independently verified). It CONFIRMED 5 defects my first-pass validation missed — all now fixed and re-verified:
- [HIGH] the record crate placed zero records (footprint had collapsed to ~2 voxels) → re-anchored, now a full row of blue/black vinyl on edge.
- [MED]
QUEST_POS.fuse.boxsat on the frame, one voxel off the fuse → now exact. - [MED] VU-tower LEDs were sealed inside a closed casing → front face opened.
- [LOW] added the PCB "resistor beams" the brief lists.
- [LOW] the demo's "Record Crate" teleport aimed into the left wall → re-aimed. (Two other raw findings were false positives — one described already-fixed code; a doc-comment nit I tightened anyway.) I added regression guards for the crate and anchors.
Cross-lane smoke test. Since all five lanes have now landed, I ran buildBooth
against Lane A's real VoxelWorld (not my mock): the fillBox fast path engages
(Lane A's signature + inclusive semantics match my assumption exactly), 30.7 ms build,
and every acceptance check still passes. Lane C drops into the engine with zero friction.
4. Contract friction (needs an integrator/Fable call)
- Mixer height: the brief says "tabletop →
topY+40", butconstants.ts+ DESIGN both define the mixer face plate top surface astopY = 67. I built to 67 (with a raised rear ridge + VU towers for the "tallest mesa" look). Flag if a 107-tall mixer was actually intended — it's a one-liner. fillBoxsignature:tools.box()callsworld.fillBox(x0,y0,z0,x1,y1,z1,id)(inclusive) if Lane A provides it, else loopssetBlock.buildBoothlogs which path ran. Lane A should match that signature (or we reconcile at integration; the loop is always correct).
5. Handoff to Lane D (machines)
Lane D reads QUEST_POS + the exported anchors — no re-hardcoding coordinates. Every
moving part has a socket waiting: platter wells, tonearm pedestal + headshell anchor,
empty fader/crossfader slots, button/switch recesses. Anchor semantics are documented in
src/worldgen/HANDOFF.md.
6. Suggested next steps for Fable
- Greenlight (or correct) the mixer-height interpretation in §4.1.
- Confirm the
fillBoxsignature with Lane A so the fast path engages at integration. - Lane D can start now against
QUEST_POS+ anchors; nothing blocks it. - (Optional polish later) chunkier cable cross-sections, a lower/hinged glass dust cover, and more copper-trace detail in the PCB rooms.
7. Repo note
Work is in the shared working tree (/Users/jing/TURNCRAFT), not yet pushed. The fresh
remote ssh://git@100.71.119.27:222/monster/TURNCRAFT.git is empty and there's no local
git repo yet — I did not git init/push, since seeding a shared repo from one of five
parallel lanes is an orchestration decision (whole scaffold + all lanes) better made by
the integrator. Say the word and I'll initialize + push Lane C on a branch.