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>
52 lines
3.0 KiB
Markdown
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.
|