TURNCRAFT/docs/INTEGRATION_NOTES.md
jing 49cab1f69b Concept-art pass: terraced records, spindle towers, warm lit room
- Records are stepped groove amphitheaters (3 vinyl tiers + 4-tier spindle
  tower, stacked rotating cylinder colliders) - you climb a spinning
  staircase. Tonearm clearances raised to match.
- Player physics: cylinder contacts resolve by minimum penetration (fixes a
  latent radial-slingshot bug), collider lips auto-step like voxel ledges,
  rim-standing radius grace.
- Well seam ring raised (was a 7-deep inescapable trench, now a 1-step
  Technics seam).
- Plywood ceiling with amber lamp panels + warm point lights; brighter warm
  lighting rig; colorful mixer knob caps; rim-crumble debris.
- window.TURNCRAFT_CINE camera override for screenshots/trailers.

Verified live: rim->plateau spiral climb at 33rpm, tower climb 83->87,
seam escape, quest/win chain, 121 fps.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 21:48:00 +10:00

113 lines
6.6 KiB
Markdown
Raw 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.

# TURNCRAFT — Integration Notes (what the integrator changed and why)
Integration performed per [INTEGRATION.md](./INTEGRATION.md) after all five
lanes landed. Every cross-lane glue decision is listed here.
## Contract changes (core is integrator-owned)
1. **`Y_RECORD_TOP`: 85 → 81** (`src/core/constants.ts`). At 85 the vinyl
surface was a 5-voxel cliff above the plinth (jump height ≈ 1.3 — the
record was unreachable), and Lane D's platter stack floated on the plinth
top, ignoring the 6-deep well Lane C carved. Now the record sits 1 proud of
the plinth (auto-steppable, like a real 1200) and the platter body fills
the well. Everything downstream (tonearm heights, audio panner positions,
FX rim sparkle, D's quest defaults) derives from the constant and moved
automatically. Added `PLATTER.wellDepth = 6` alongside.
2. Lane B's requested `velocityAt` out-param overload was NOT taken: Lane D
already returns a reused per-collider scratch array (no allocation), which
satisfies the hot-path concern with no contract change.
## Cross-lane glue (in `src/main.ts`)
- **QuestPositions adapter**: Lane C's nested `QUEST_POS` is mapped to Lane
D's flat `QuestPositions`; the crossfader slot span is derived from C's
`MIXER` anchors (centerX ± halfLen, faceTopYdepth+1 … faceTopY1, z 1…+2)
so D's slide gate covers exactly the tram volume C carved.
- **`machines.attachPlayer(player)`** called after the player is built
(Lane D's added step "6.5") — enables walk-push faders and walk-press plates.
- **Hotbar**: D's `Hotbar` structurally satisfies E's `HotbarModel`; passed
directly as `getHotbar`, with `hotbar.onChange(() => hud.refreshHotbar())`.
- **Input wiring**: LMB hold = mine, RMB = place, E = use, 19/wheel = hotbar,
all gated on pointer lock (matching Lane B's own key gating). Start splash
click → `audio.init()` + pointer lock; resume click → re-lock only.
- **Fixed-step loop**: machines → player → interaction → fx at `FIXED_DT`,
with `MAX_SUBSTEPS` catch-up and an accumulator clamp so a backgrounded tab
doesn't spiral; `audio.updateListener` + `chunks.update()` + render per frame.
- Debug handle `window.TURNCRAFT` (world/player/machines/quest/hotbar/audio/
fx/hud/chunks/interaction) — used by the smoke tests, harmless in play.
## Lane-file adjustments (documented per CONTRACTS "integrator resolves")
- `src/machines/platter.ts` — platter body now spans the well floor to 1
below the vinyl (visuals) and its collider spans well floor → `Y_RECORD_TOP`
so the spinning body also pushes the player out of the well's 2-voxel gap
ring (which is now a real, intentional fall-in hazard).
- `src/fx/layout.ts` — VU overlay sprites aligned to Lane C's physical LED
towers (x = mixer minX+18 / maxX18, 12 segments, in front of the open
casing face) per Lane E's friction note #5.
- `src/interact/interaction.ts` — per-material break times (soft 0.12 s,
glass 0.25 s, default 0.4 s). The crossfader jam is ~240 dust blocks; at a
flat 0.4 s it was a 96-second chore.
- `docs/DESIGN.md` — elevation table updated for the Y_RECORD_TOP change.
## Deviations accepted as-is
- **45 speed available pre-win** (D's reading; DESIGN's "45 unlocked at win"
treated as flavor). `Platter.unlocked45` exists if we ever gate it.
- **`fader_cross` does not drive audio** (E maps pitch + channel digits only);
crossfader is quest/physical-only in v1.
- **Both deck pitch faders drive the one global mix pitch** (E has a single
transport; fine until per-deck stems exist).
- **Tonearm pedestal (C's voxels) vs D's arm pivot** are ~11 voxels apart —
cosmetic misalignment, queued for polish, gameplay unaffected.
## Verified at integration (live browser, real code paths)
- Boot: booth builds + meshes in ~670 ms dev / 46 modules build in 0.5 s;
fillBox fast path ENABLED; **120 fps**; zero console errors all session.
- Ride: standing on the record at 33 → clean circle, r drift 20.00→20.02 over
4 s, y = 81 exactly, spin-up ramp visible; at 45 near the rim → 10.7 v/s
(= ω×r), jump lands back on the moving disc.
- Mining: real DDA aim → dust breaks into hotbar; crossfader stays gated
while dust remains.
- Quest chain: stems stack 0→5 per `signal:repair`, power switch arms exactly
after the 4th repair, real button press → `game:win` once, both platters
auto-start, HUD banner + tracker 5/5, AudioContext running.
- The platter-well gap ring behaves as a trench (collider pushes, no clipping).
## Concept-art pass (post-integration, from John's Gemini mockup)
- **Terraced records**: the flat disc became a stepped "groove amphitheater" —
3 vinyl tiers rising 1 voxel each to the label plateau, then a 4-tier
stepped spindle tower with an amber lamp (all in `TIERS`, `platter.ts`).
Each tier is its own stacked kinematic cylinder; you walk/spiral up a
SPINNING staircase. Tonearm raised (`HEAD_Y` +2.6) and `R_INNER` pulled to
16 so the needle clears the terraces and never hits the tower.
- **Player physics upgrades this required** (`PlayerController.ts`):
cylinder contacts now resolve by minimum penetration (up vs radial), which
fixes a latent slingshot bug (feet dipping below a disc's top while deep
inside its footprint used to teleport the player radially to the rim);
1-voxel collider lips auto-step like voxel ledges; cylinder tops have a
half-foot radius grace so you can stand on rims.
- **Well seam**: the platter well's outer ring was a 7-deep inescapable
trench; floor raised to 1 below the plinth top (worldgen) — now a Technics
seam you step out of.
- **Room feel**: plywood ceiling with six recessed amber lamp panels
(worldgen) + matching warm PointLights (main.ts), warmer/brighter
hemi/ambient/fog (renderer.ts).
- **Mixer color pop**: knob caps get a deterministic palette scatter (red/
white/gold/LED) in `buildMixer`. **Rim crumble**: vinyl chips/dust/screws
scattered around the well mouths in `buildDeck`.
- Dev nicety: `window.TURNCRAFT_CINE = { pos, look }` detaches the camera
for screenshots/trailers; `window.TURNCRAFT` exposes camera/render too.
- Verified: walk-in from the rim spirals up to the label plateau at 33 rpm
(fighting the spin is intentional physics — stop the deck for an easy
climb); tower fully climbable (83→87 by walking); seam escape 1-step;
121 fps with ceiling + lights; quest/win chain re-verified end-to-end.
## Not yet done (deploy phase)
Run `/ship-check` before exposing anything publicly; deploy per deploy-map
conventions (static `dist/` — 156 KB gzipped). Cloudflare/host wiring is a
separate step, to be done with the token holder present.