TURNCRAFT/docs/briefs/LANE_C_WORLDGEN.md
jing 5a39e3a947 TURNCRAFT: contracts, docs, and all five lane deliverables (pre-integration)
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>
2026-07-13 20:50:56 +10:00

8.6 KiB
Raw Permalink Blame History

LANE C — World Builder (the Booth)

Read first: docs/DESIGN.md (especially §3§4), docs/CONTRACTS.md, everything in src/core/. You own: src/worldgen/**, src/demo/worldgenDemo.ts, demo-worldgen.html. You may not touch anything else.

Mission

Author the entire diorama in voxels: buildBooth(world: IVoxelWorld): void writes every static block of the DJ booth — plywood shell, tabletop, two turntable plinths, the mixer massif, cable canyon, patch-bay wall, and the PCB Depths under the table. This is the level-design lane: you are building a place, and the inspiration photo (plywood console, silver 1200s, black 4-channel mixer, blue records, wall patch bay, visible hinges) is your mood board. Deterministic output: same world every run (seedable PRNG, fixed seed).

What you do NOT build: the platter, record disc, tonearm, fader caps/sleds, and buttons — those are moving machines (Lane D). You build the sockets they sit in: the platter well (a recessed circular pit around each spindle), the tonearm base mount, empty fader slots, button recesses. Use LAYOUT from constants for every position Lane D also needs.

Provides

  • buildBooth(world: IVoxelWorld): void — main entry, composed of exported sub-builders so they're individually testable: buildShell, buildDeck(A|B), buildMixer, buildCableCanyon, buildPatchBay, buildUnderTable.
  • SPAWN: Vec3 — export the player spawn (on Deck A's plinth top, near the platter well, facing the mixer).

Consumes

IVoxelWorld interface only. Prefer fillBox when available (Lane A adds it; code against the interface plus an optional duck-typed (world as any).fillBox?.(…) ?? loop fallback so your demo's simple mock still works).

Tasks & structure specs

Work top-down; keep each builder a pure function of (world, LAYOUT, prng). A tiny toolkit first (src/worldgen/tools.ts): box, hollowBox, cylinderY (disc/annulus fill), line3 (thick voxel line), spline (Catmull-Rom sampled → spheres stamped along it, for cables), mulberry32 PRNG.

C1. Shell & tabletop

  • Plywood floor at world bottom, walls (rimThickness) up to Y_BOOTH_WALL_TOP, back wall at backWallZ. ply_edge striping on every exposed wall top/cut edge (that laminate look). Two chrome screw+ brushed_alu hinge plates on the back wall like the photo.
  • Tabletop slab at Y_TABLETOP spanning inside the rim, with: a rectangular vent slot behind each deck (the way down to PCB Depths), and a 6×6 open hatch near the front-left with a plywood step-stair down into the crate.

C2. Decks A & B (steel-grey mesas)

  • Plinth: filled steel_grey box from tabletop to Y_PLINTH_TOP over the LAYOUT footprint, 2-voxel rubber feet at corners, a brushed_alu top face border. Rounded-ish corners (chamfer 23 voxels).
  • Platter well: recessed circular pit centered on the spindle, radius PLATTER.radius + 2, depth 6 below plinth top — leave it EMPTY (Lane D's rotating platter fills it). Chrome 1-voxel spindle stub at center bottom.
  • Deck-top furniture (all voxel, non-moving): start/stop button recess (4×4×1 pit, front-left), two small round 33/45 button recesses beside it, pitch fader canyon — an 18-long, 3-wide, 4-deep slot on the right side with led_green center-detent dot at its midpoint, tonearm base mount — a 10×10 brushed_alu raised pedestal at back-right with a 3-voxel chrome post stub, and a strobe_dot + led_red strobe lamp pillar at front-left corner (the classic Technics pop-up light).
  • Deck B only: drifts of dust blocks banked on top and around; its glass dust cover half-open — a glass slab canopy over the rear half at y ≈ Y_PLINTH_TOP+18, hinged at the back wall side, forming the crystal cave (2-voxel-thick, walkable on top).

C3. Mixer Massif

  • matte_black body over LAYOUT.mixer footprint, tabletop → topY+40 (i.e. face plate at y=67... use LAYOUT.mixer.topY); speaker_mesh side-vent ladders (climbable = 1-voxel ledges every 2), brushed_alu face plate border.
  • Face plate furniture: 4 channel strips, each with a 3×3 grid of knob stems (1-voxel knob_black stubs — caps are Lane D machines) and a fader alley: 14×3 slot, 5 deep. Front edge: the crossfader tram — a 40-long, 4-wide, 6-deep slot running leftright; fill its center with a plug of 12 dust blocks (the quest jam). Back edge: two VU towers — 12-tall columns, alternating led_green×8 / led_amber×3 / led_red×1, plus a matte_black casing open on the front face.
  • Rear face: master power switch recess (Lane D machine) and a fuse-door slot leading down a chimney into the PCB Depths fuse room.

C4. Cable Canyon (z 140200)

  • 46 cables, each a 2×2 cable_black tube along a drooping Catmull-Rom spline from gear rear panels (RCA heights on deck/mixer backs) over the canyon floor to the patch-bay wall; two of them sheathed cable_red / cable_white near the ends with rca_gold plug heads (3×3×4).
  • One cable is THE quest cable: it ends 8 voxels short of the patch bay, its gold plug resting on the canyon floor, aligned with an empty socket.
  • Canyon floor: tabletop plywood with dust drifts, a few vinyl slab off-cuts leaning on walls (walkable ramps), power-strip block (matte_black box with led_amber pilot light) feeding cables.

C5. Patch Bay (back wall)

  • Over LAYOUT.patchBay: a brushed_alu panel proud of the wall by 2, with a 2×6 grid of round rca_gold sockets (3-voxel-diameter rings, 2 deep); most plugged with cable-colored plugs, one conspicuously EMPTY with an led_red blink block above it (the quest socket — Lane D puts the interactive socket machine here; you build the hole).
  • Two sockets are real doorways: 3-deep tunnels opening into a small room inside the wall with copper busbars and a led_blue glow — a secret.

C6. PCB Depths & the crate (under-table, y 040)

  • Under each deck and the mixer: rooms with pcb_green floors, copper trace paths inlaid (1-wide runs connecting solder-blob clusters), solder stalagmites, capacitor pillars (cylinders: matte_black body, brushed_alu top with cross-scored cap), resistor beams bridging gaps. LED sprinkles (led_green/amber, sparse, per DESIGN's "dim until repaired" — just place them; Lane E handles dimming).
  • Fuse room under the mixer: fuse box on the wall — a brushed_alu frame holding one blackened fuse (use rubber block flanked by chrome caps to read as "blown"), and a parts bin nearby: an open plywood tray holding a fresh fuse (glass block with chrome caps), plus the stylus block (single chrome block on a felt pad, spotlit by one led_blue) — the two quest pickups. Coordinate: place pickups exactly at positions exported as QUEST_POS (export a const with stylus/fuse/plug/socket world coords so Lane D reads positions from you at integration — put it in src/worldgen/questPositions.ts, derived from LAYOUT, no magic numbers elsewhere).
  • Record crate (front-left, under the hatch): plywood cavern holding 810 giant vinyl slabs (2-thick discs on edge, alternating vinyl_black / vinyl_blue with label_cream centers), gaps walkable, one leaning slab as a ramp back up.

C7. Set dressing pass

  • The booth should feel used: dust in corners, one screw block half-out, scattered label_cream sticker blocks on the shell, cable stubs. Restrained — this is a tidy booth, per the photo.

Demo (demo-worldgen.html)

Build the full booth into a simple array-backed mock world, render with a naive InstancedMesh-per-block-id visualizer (flat colors from blocks.ts tints — fine at this scale), OrbitControls, per-zone teleport buttons, and a stats line: total non-air voxels, per-id counts, build time (< 500 ms). Validation asserts (console.error on fail): platter wells empty, spawn stands on solid, quest positions non-air-adjacent-reachable (has an adjacent air voxel), world edges sealed (no non-air outside bounds… i.e. no writes OOB).

Acceptance

  • buildBooth writes only through IVoxelWorld, deterministic across runs
  • Every zone from DESIGN §4 exists and is visually recognizable in the demo
  • All LAYOUT-adjacent geometry derives from constants.ts (grep-proof: no duplicated literal for spindle/mixer coords)
  • Platter wells, fader slots, button recesses left empty for Lane D
  • questPositions.ts exports all quest coords; validation asserts pass
  • Build < 500 ms; npm run typecheck clean; HANDOFF.md written

Out of scope

Anything that moves (Lane D), real meshing (Lane A), lighting/audio (E), player (B).