TURNCRAFT/docs/CONTRACTS.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

105 lines
6.4 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 — Lane Contracts
**Every lane reads this file and [DESIGN.md](./DESIGN.md) before writing code.**
This document exists so five agents can build simultaneously without touching
each other's files or breaking each other's assumptions.
## 1. The Law
1. **`src/core/` is read-only for all lanes.** It defines the shared types,
block registry, constants, and event bus. If you believe a contract file
has a bug or a missing field, STOP and report it in your summary instead of
editing it — the integrator resolves contract changes.
2. **Own your directory, never write outside it.** Ownership map in §3.
3. **Cross-lane imports: `src/core/` types only.** Never import a concrete
class from another lane's directory. Depend on `IVoxelWorld`, `IMachine`,
`IPlayerView`, `KinematicCollider`, `bus` — not on implementations. In your
standalone demo, mock what you need (§6).
4. **Communicate via the event bus** (`src/core/events.ts`) for anything
fire-and-forget; via the core interfaces for anything synchronous.
5. **No new runtime dependencies.** `three` only. Dev deps: `vite`,
`typescript`, `@types/three`. Textures are painted procedurally on canvas;
audio is synthesized with WebAudio. No binary assets, no CDN loads.
6. **TypeScript strict mode must pass**: `npm run typecheck` clean at handoff.
7. Coordinate system: Three.js right-handed, **Y-up**, 1 voxel = 1 world unit.
Voxel (x,y,z) occupies world space [x,x+1)×[y,y+1)×[z,z+1). World bounds
and all gear placement come from `src/core/constants.ts` (`LAYOUT`) —
never hardcode a magic position.
## 2. Contract Files (already written — read them)
| file | contents |
|---|---|
| `src/core/constants.ts` | world size, chunk size, elevations, `LAYOUT` gear placement, player physics numbers, platter RPMs, quest node list |
| `src/core/blocks.ts` | the full block registry: ids 030, solidity, transparency, emissive, tint colors, texture `pattern` names, sounds |
| `src/core/types.ts` | `IVoxelWorld`, `KinematicCollider`, `IMachine`, `RayHit`, `IPlayerView`, `Vec3` |
| `src/core/events.ts` | the typed global `bus` and every event name/payload |
## 3. Ownership Map
| lane | owns (create/edit freely) | delivers |
|---|---|---|
| **A — Voxel Engine** | `src/engine/**`, `src/demo/engineDemo.ts`, `demo-engine.html` | `VoxelWorld` (implements `IVoxelWorld`), chunk mesher, texture atlas, renderer/scene/lighting setup, chunk-remesh-on-dirty |
| **B — Player & Physics** | `src/player/**`, `src/demo/playerDemo.ts`, `demo-player.html` | `PlayerController` (implements `IPlayerView`): input, AABB-vs-voxel collision, kinematic platform riding, fly mode |
| **C — World Builder** | `src/worldgen/**`, `src/demo/worldgenDemo.ts`, `demo-worldgen.html` | `buildBooth(world: IVoxelWorld): void` — writes the entire diorama |
| **D — Machines & Interaction** | `src/machines/**`, `src/interact/**`, `src/demo/machinesDemo.ts`, `demo-machines.html` | platter/tonearm/fader/button machines (implement `IMachine`), raycaster, break/place, hotbar model, quest state machine |
| **E — Audio, FX & UI** | `src/audio/**`, `src/fx/**`, `src/ui/**`, `src/demo/audioDemo.ts`, `demo-audio.html` | synthesized stem mix, positional audio, beat events, LED pulse/VU systems, particles, HUD/hotbar UI, win screen |
| **integration** (after lanes land) | `src/main.ts` | final wiring per `docs/INTEGRATION.md` |
Shared read-only: `src/core/**`, `index.html`, configs, `docs/**`.
## 4. Key Cross-Lane Behaviors (who does what)
- **Dirty chunks**: `VoxelWorld.setBlock` (Lane A) marks the containing chunk
(and neighbors when the block borders them) dirty; the engine remeshes dirty
chunks, budgeted per frame. Nobody else touches meshing.
- **Riding platforms**: Lane D machines expose `KinematicCollider`s with
`velocityAt`. Lane B, when the player's ground contact is a kinematic
collider, adds that surface velocity to the player each tick and reports it
via `IPlayerView.groundedOn`. Cylinder colliders rotate about +Y only.
- **Break/place**: Lane D raycasts (voxel DDA for blocks + analytic tests for
machine colliders), calls `world.setBlock`, emits `block:break`/`block:place`.
Lane A reacts by remeshing; Lane E reacts with sound/particles.
- **Quest**: Lane D owns quest state and emits `signal:repair` / `game:win`.
Lane E owns everything audible/visible that reacts to those events.
- **Emissive blocks**: Lane A renders `emissive > 0` blocks with an emissive
material channel. Lane E may pulse a global uniform (via a small exported
hook Lane A provides: `setEmissiveBoost(v: number)` on the renderer) — Lane
A must expose that one function; Lane E must not reach into A's materials.
## 5. Fixed Timestep
The game loop runs physics/machines at `FIXED_DT` (1/60) with up to
`MAX_SUBSTEPS` catch-up steps, render decoupled. Every lane's `update(dt)`
must be stable if called with dt = FIXED_DT repeatedly. No lane creates its
own `requestAnimationFrame` loop except inside its own demo.
## 6. Demo Harness Rules (how you verify alone)
Each lane ships a standalone Vite page (`demo-<lane>.html` at repo root +
`src/demo/<lane>Demo.ts`) that runs with **zero code from other lanes**.
Mock the interfaces you consume — e.g. Lane B's demo includes a ~30-line
`MockWorld implements IVoxelWorld` (flat floor + some steps) and one mock
spinning-cylinder `KinematicCollider`; Lane C's demo may include a naive
brute-force mesher (one box per voxel face is fine at demo scale, or
`InstancedMesh`) purely to eyeball the build. Keep mocks inside your demo
file(s), clearly marked `// DEMO MOCK — not for integration`.
`npm run dev` then open `http://localhost:5173/demo-<lane>.html`.
## 7. Definition of Done (every lane)
- [ ] `npm run typecheck` passes with your code included
- [ ] Your demo page runs, and its README-style header comment says exactly
what to look at / press to verify each acceptance criterion
- [ ] No writes outside your owned paths; no imports of other lanes' concrete code
- [ ] No console errors in a 2-minute demo session
- [ ] A `HANDOFF.md` in your owned directory: what's done, what's stubbed,
any contract friction you hit, and your public API surface in 10 lines
## 8. Style
Match the existing core files: plain TypeScript, no classes-for-the-sake-of-it,
comments only where a constraint isn't obvious from code. Keep per-frame
allocations near zero in hot paths (meshing, physics): reuse arrays/vectors.