# Lane G — Colour zones, paint puddles, MEGA/MINI **Owns:** `src/paint/puddles.ts`, `src/paint/buffs.ts` (extend — you inherit Lane B's file), `src/course/zones.ts`, `demos/lane-g.html`, `src/demo/lane-g.ts`. **Never touches:** contracts, world, game, main, package.json, `src/blob/`, `src/machine/` (USE machine parts via import — just don't edit them), other lane dirs. No new deps. ## Why this lane exists (live-play finding, 2026-07-18) A naive racer currently finishes the course with **0% paint** — ballistic cannons miss fast movers and nothing on the ground paints you. The core mechanic is skippable. Fix: paint must be guaranteed by ROUTE, not by aim, and colours must come in ZONES so buffs actually activate (20% threshold is unreachable when three colours dilute each other — also observed live). ## Deliverables 1. `src/paint/puddles.ts` — `PaintPuddle`: a flat coloured strip on the track (mesh + config `{position, size, color}`). While the blob's ground contact is inside the strip, stamp its UNDERSIDE via `skin.splatAtPoint` at the contact point on a cadence (~6 stamps/s, small radius) — rolling through paint coats your belly. Registered via an `installPuddles(world, blob, skin, configs)` entry point (integration calls it). Emit `paint:splatted {color, target:'blob'}` per stamp (audio hooks it). 2. `src/paint/buffs.ts` — extend the coverage→modifier mapping (GDD §6): - **purple MEGA**: `size` 1.0→1.45 + extra `massMul` (heavy). Strength scales 20%→70% like the others. - **pink MINI**: `size` 1.0→0.62, LESS mass (lighter than clean at high %). - purple and pink fight: net size uses (purple − pink) strength. - Existing red/green/blue unchanged. Keep the pure-function style + UPDATE `src/paint/coverage-math.test.ts` for the new mappings. 3. `src/course/zones.ts` — `installZones(world, blob, skin)`: builds the colour zones ON the existing greybox (import nothing from game.ts; use absolute course coordinates — the course spans z 30 → -70, see src/course/greybox.ts): - **RED zone** (ramp approach, z≈20..8): red puddle strip + the existing red cannon position gets a second red cannon (crossfire). BURN speed helps the climb. - **GREEN zone** (shelves + slope, z≈8..-24): green puddles on both shelves; GRIP helps the slope and gravity-flip future. - **BLUE zone** (milk river, z≈-24..-37): blue puddle lines the riverbanks; waterproof = your paint survives the water. - **PURPLE/PINK fork** (machine district, z≈-37..-58): LEFT lane (x<0): purple puddle → MEGA → heavy enough to trip the pressure plate → boot yeet (the course TEACHES paint=weight). RIGHT lane (x>3): pink puddle → MINI → a **low tunnel** (build it: a slab roof over the track at y≈0.9, only a MINI blob fits under) that shortcuts toward the finish. Normal-size blobs bonk and must take another lane. - Cannons: relocate/add so each zone's cannons fire ITS colour (configs returned so integration can place them; or place them yourself in installZones — your call, document it). 4. Demo `demos/lane-g.html` + `src/demo/lane-g.ts`: a test ball rolling through each zone in sequence with live coverage/modifier logging; prove: puddles coat reliably, purple grows + trips a test plate, pink shrinks + fits the tunnel while a clean ball bonks. ## Acceptance - `npm run build` + updated coverage-math tests pass. - A straight-line hold-forward run through the zones ends with ≥40% total coverage and at least one active buff (puddles guarantee it — verify in demo). - Purple demo ball trips a `massThreshold: baseMass*1.25` plate; clean ball doesn't. - Pink demo ball (≥35% pink) passes under the tunnel; clean ball cannot. - No edits outside owned paths. ## Contracts Emit `paint:splatted` per puddle stamp. Existing events unchanged. `blob.modifiers.size` is already honored by the controller (collider + visual scale) — do not touch the blob.