Driven by the live fresh-eyes finding: a naive racer finishes with 0% paint — the core mechanic is currently skippable. G makes paint route-guaranteed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
48 lines
2.7 KiB
Markdown
48 lines
2.7 KiB
Markdown
# Lane H — Ghost replay + title screen
|
|
|
|
**Owns:** `src/ghost/`, `src/ui/`, `demos/lane-h.html`, `src/demo/lane-h.ts`.
|
|
**Never touches:** contracts, world, game, main, package.json, other lanes' dirs.
|
|
No new deps.
|
|
|
|
## Mission
|
|
Two pieces that turn a tech slice into a GAME you return to:
|
|
a ghost of your best run to race against, and a title card that explains the
|
|
game in five seconds (and unlocks audio).
|
|
|
|
## Deliverables
|
|
1. `src/ghost/recorder.ts` — `GhostRecorder`: on `race:started`, record the
|
|
blob root's position + uniform scale at 15Hz into a flat Float32Array-backed
|
|
buffer (cap ~5 min). On `race:finished`, if this run is the new best, save
|
|
quantized (int16 centimeters is plenty) + the time to localStorage
|
|
`blobbo:ghost` (base64). Keep total under ~200KB.
|
|
2. `src/ghost/player.ts` — `GhostPlayer`: if a saved ghost exists, on
|
|
`race:started` spawn a translucent ghost blob (simple sphere + eyes is fine,
|
|
opacity ~0.35, no physics — kinematic visual only) and replay it in race
|
|
time with linear interpolation between samples. Despawn on finish/respawn.
|
|
The ghost must be OBVIOUSLY not-you (ghostly white/desaturated, slight bob).
|
|
3. `src/ghost/install.ts` — `installGhost(world, blob)` wiring both to events.
|
|
4. `src/ui/title.ts` — `installTitle(world)`: full-screen overlay on boot:
|
|
- big BLOBBO wordmark (styled CSS bubble text is fine — thick white letters,
|
|
rainbow paint-drip accents, Comic-adjacent but tasteful),
|
|
- one-line pitch: "Race. Get painted. Paint is power.",
|
|
- controls card: WASD/stick · Space/A jump · R/Start restart,
|
|
- a fat **PLAY** button. On click/keypress/gamepad-button: fade out,
|
|
emit **`ui:play`** on world.events (audio unlocks on this), start allowed.
|
|
- While Rapier/world is still booting, show the same overlay with a wobbling
|
|
"loading…" blob dot instead of PLAY (installTitle can be handed a promise).
|
|
- Show saved best time + "👻 ghost ready" if `blobbo:ghost` exists.
|
|
5. Demo `demos/lane-h.html` + `src/demo/lane-h.ts`: fake a 20s scripted "run"
|
|
(a ball on a circle), record it, finish, then restart and race the ghost.
|
|
Title screen in front. Debug key G wipes the saved ghost.
|
|
|
|
## Acceptance
|
|
- `npm run build` passes; demo shows title → play → run 1 records → run 2 shows
|
|
interpolated ghost racing the circle; localStorage survives reload; wipe works.
|
|
- `ui:play` emitted exactly once per page life; overlay never reappears mid-game.
|
|
- Ghost replay drift vs recorded path < one blob radius at all sample points
|
|
(it's the SAME deterministic path in the demo — verify numerically).
|
|
- No edits outside owned paths.
|
|
|
|
## Events
|
|
Consume `race:started`, `race:finished {time,best}`. Emit `ui:play` only.
|