BLOBBO/lanes/LANE-C-machine.md
type-two 969f602dd4 Foundation: vite+ts+three+rapier scaffold, frozen contracts, lane docs A-E
Fixed-step world runtime, event bus wire protocol between lanes, integration
seam (game.ts) with placeholder ball. Lanes A/B/C own disjoint dirs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 19:55:43 +10:00

52 lines
3.0 KiB
Markdown

# Lane C — Machine (Rube Goldberg toolkit)
**Owns:** `src/machine/`, `demos/lane-c.html`, `src/demo/lane-c.ts`.
**Never touches:** `src/contracts.ts`, `src/world.ts`, `src/game.ts`, `src/main.ts`,
`package.json`, other lanes' dirs. No new deps — three + rapier only.
## Mission
Player-triggered contraptions with mandatory telegraphs (GDD §5.4). Contraptions
are data-placeable parts that chain via signals — the course is a machine.
## Deliverables (`src/machine/`)
1. `telegraph.ts` — helper: given a mesh + duration (default 0.5s), play an
unmissable windup (flash + shake/scale pulse + optional emissive) then resolve.
EVERY contraption that applies force or dumps paint MUST telegraph first.
This is a design pillar, not decoration.
2. `parts.ts` — each part takes a config `{id, position, ..., onSignal?, emits?}`,
registers physics + visuals, listens/emits on `world.events`:
- **PressurePlate** `{massThreshold}` — depresses under weight; uses blob
effective mass (`body.mass()`); emits its `emits` signal on trip.
- **SeeSaw** — plank on Rapier revolute joint; purely physical (heavy blob
dominates it).
- **SpringBoot** `{impulse, direction}` — on signal: telegraph → kick
anything in its strike volume.
- **BucketDump** `{color, radius}` — on signal: telegraph (teeter!) → tips;
emits `paint:request-splat {point, color, radius}` for everything under it
(paint lane renders the splat; you also spawn a brief visual slosh mesh).
- **ConveyorBelt** `{velocity}` — surface that adds velocity to bodies on it.
- **BubbleArch** `{fraction}` — sensor volume; on blob overlap emits
`paint:request-cleanse {fraction}` + bubble particle burst.
- **Fan** `{force, direction}` — constant force volume (pushes light blobs
hard, heavy blobs barely — mass does the work).
3. `surfaces.ts``SurfaceMaterial` registry per contracts (`normal`, `ice`,
`oil`, `honey`, `mud`, `water`): friction/restitution + tags; helper
`applySurface(collider, name)` + a way for the blob controller to query the
surface under a body (`surfaceAt(point)`).
4. Chain demo `demos/lane-c.html` + `src/demo/lane-c.ts`: heavy test ball (your
own stub — do NOT import Lane A) rolls onto **PressurePlate → SpringBoot →
ball lands on SeeSaw → tips into BucketDump trigger → bucket teeters and
dumps** (log the paint event), plus a ConveyorBelt and a BubbleArch on the
side, and an ice + honey patch to feel surfaces. Debug key T re-runs the ball.
## Acceptance
- `npm run build` passes; the full chain runs end-to-end on one ball with a
visible telegraph before every kick/dump.
- PressurePlate does NOT trip below its mass threshold (test with a light ball).
- Surfaces measurably change rolling behavior.
- No edits outside owned paths.
## Contracts (frozen — read `src/contracts.ts` first)
Emit: `machine:signal {id}`, `paint:request-splat`, `paint:request-cleanse`.
Nothing in this lane imports from `src/paint/` or `src/blob/` — events only.