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