# Revere's Ride: Lantern Run, design notes

The GameLab sequel to RevereBike (`../reverebike/`). The 8-bit game stays where it is; this one reuses its
music and sound, its physics feel (gallop, turbo, heat, health, lean-to-land) and its fifteen stages, and
rebuilds everything else as a 3D game drawn to look like an oil painting.

## Look

- **Backdrops** are panoramas painted on the easel (claude-paint) from one Lua script per stage, 4800 x 1200,
  in a Delft camaieu with a few accent hues per stage. Sources: `source/paint/` (kit.lua is the shared recipe
  kit; pano.py writes the per-stage scripts). They are drawn on a full-screen quad behind the scene with a
  wide "lens" and a yaw that scrolls with the rider, so the painting reads as far away.
- **Models** are lit in value bands with a brush-stroke texture, cool shadows and warm lights, a rim, and
  emissive windows and flames picked out by a region code baked into UV.x in Blender (0 solid, 1 window,
  2 flame, 3 leaf, 4 metal, 5 sway, 6 water, 7 snow). Leaves and sway regions move in the wind.
- **Post**: Kuwahara (radius by quality) then bloom, then a finish pass: grade, linen weave, vignette, gold
  burst edge, radial motion streak, flash and letterbox.

## Models (Blender, `source/blender/`)

- `build_horse.py`: the polyperfect horse rig, scale fixed, takes retargeted through armature space, mane
  cards, tail strands and tack added, Jump/Land/Skid authored. Clips: Idle, Walk, Gallop, Jump, Land, Skid,
  Rear, Fall. Coat colors are per-horse uniforms on region codes (coat, mane, dark, hoof, tack, pad, eye,
  metal, horn), so one GLB serves all six horses, the looks and the unicorn.
- `build_people.py`: two Synty-rig packs recolored into the cast. Thirteen clips authored with an analytic
  two-bone IK: Ride, Crouch, Back, Lantern, Shout, HatTip, Wave, Thrown, Stand, March, Run, Aim, Cheer.
- `build_kit.py`: 87 stage pieces (houses, churches, walls, ramps, boats, ice, locomotive, saucers,
  dinosaurs, candy, the rainbow arch...), 69k triangles in one GLB with kit.json.
- GLBs are packed with gltf-transform and meshopt (`tools/pack-glb.mjs`).

## Play

- Excitebike physics in metres, three lanes (3.2 m apart). Courses are a small script language in
  `src/data.js` read by `src/course.js`.
- New verbs: **Call** (rouse a house, ring a bell, or fire a Lantern Burst when Spirit is full), lane
  changes, hops and tucks.
- Crew: every roused house sends a minuteman to ride with you (two with Sybil).
- Rivals: patrols ahead, chasers behind. Passing on turbo or burst is a takedown.
- Events: volleys, broadsides, flares and asteroids are telegraphed into lanes on the HUD first.
- Set pieces: falling bridges, cannon launches, ice floes, a train race, floats, saucers, vortices,
  long-necked dinosaurs, the rainbow arch.
- Progress: three stars per stage (finish, par, objective), medals, coins, horse XP (10 levels),
  saddler upgrades and looks, six riders with perks and unlocks, thirteen colony lanterns that open
  Rainbow Road, five golden horseshoes for the Golden saddle. Old RevereBike coins and horse XP carry over
  once from the same browser.

## Beat VFX

`tools/beats.py` maps every RevereBike track offline into `assets/audio/beats.json`: tempo and phase, a kick
envelope, and the accents (peak-picked onsets tagged low or high). `src/rhythm.js` reads the playing
`<audio>` element's `currentTime` and walks that list (a 120 BPM house clock stands in when there is no
music). `src/beatfx.js` turns it into effects, scaled by a "heat" that only rises at speed, in turbo or in a
Lantern Burst: hoof sparks and dust shock rings on low hits, ember spits on high hits, a lens punch, shake
and chromatic split on the strongest, speed lines and an exposure punch in the finish pass, bloom and rim
light swelling on the beat, windows and flames breathing, the HUD pulsing via `--beat`, and the gallop
stride locked to the tempo. Settings has a Beat effects switch; reduced motion keeps only the gentle part.

## Mobile

Portrait is playable: the side camera climbs and looks down the lanes with little lead when the screen is
taller than wide. `tools/mobile.mjs` shoots every screen at phone and tablet sizes in both orientations and
flags sideways scroll, off-screen buttons, small touch targets and HUD under the thumb pad.

## Camera

`src/director.js` cuts away from the side camera for big moments: lineup, hoof, front (Lantern Burst),
crane (big air), orbit (takedown, perfect landing), rival two-shot, crash, cannon, flyby and finish. Each cut
slows the clock, letterboxes, and eases back. Settings: Full, Light (start, burst, finish) or Off.

## Testing

`?stage=<id>&auto=1` starts a stage on autopilot (`src/auto.js`), which is also the title screen's attract
mode. `window.__lr` exposes start, step and the save for headless runs (`tools/play.mjs`).
`?unlock=1` opens every stage. `?q=low|medium|high` forces a quality preset.

## Files

- `index.html` boots the import map and the loader (after Prism Light's), `assets.js` is written by
  `tools/make_manifest.py`. Bump `LR_BOOT.build` when files change.
- Music: `../reverebike/audio/bgm/` (shared with the original, not copied).
