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

161 lines
8.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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).