Replace the flat level-grid level select screen with a campaign-based
map view. Levels are grouped into themed campaigns (e.g. "Sunny Suburbs",
"Dusk Junction") each with its own background art and node positions
rendered along a Catmull-Rom spline ribbon.
Key changes:
- Introduce CAMPAIGNS array in src/data/levels/index.js with helpers for
campaign/level lookup.
- Add src/data/levels/positioning.js for auto-layout S-curve generation
and Catmull-Rom spline sampling.
- Rewrite LevelSelectScene.js to render per-campaign maps with animated
node entrance, idle pulse on the current level, hover states,
tool-tips for locked levels, and ← → / P keyboard navigation.
- Remove the now-unused LevelCompleteScene; scores now record progress
and return directly to the map via LevelScoreScene.
- Add map assets (campaign backgrounds, node/flag/tag sprites) and
manifest entries with a documented 960x540 centered-canvas convention.
- Add src/util/mapArt.js for shared map geometry constants and scaling.
- IntroScene: use bg_main.png poster art as full background, layer
logo.png with a breathing tween aligned to the baked wordmark via
fitted similarity transform constants, and add a double-stroke
"Press any key" prompt (replaced auto-advance with input-only trigger).
- MainMenuScene: replace text title with bg_menu.png background and
centered logo.png overlay; add semi-transparent background pill to
instructions text for readability over the treeline.
- LevelSelectScene: add bg_menu.png background and background pill to
back button text for contrast.
- assetManifest: register bg_main, logo, and bg_menu textures.
- New assets: bg_menu.png, ctc.png, paid.png, bg_main.png, logo.png.
Introduce LevelScoreScene to display a choreographed score breakdown (base score, per-kid results, time bonus) using a frozen snapshot of the win condition.
Replace generic icon_kid in the HUD with individual kid portraits that update based on each kid's specific status (aboard vs. ejected).
Extract _formatTime to a shared utility used by both PlayScene and LevelScoreScene.
Add audio assets for the scoring sequence.
- Add checkered finish line entity with rippling flag pole (purely visual)
- Add three kid fall voice clips with random playback on kid ejection
- Add load tolerance for optional voice assets matching voiceLine.js pattern
- Preload kid fall sounds in PreloadScene and wire into KidManager
- Implement EngineSound system that pitches engine-heavy.mp3 based on rear
wheel angular velocity, with rate smoothing to avoid stair-stepping
- Add continuous menu music across Intro → MainMenu → LevelSelect scenes
- Add per-level voice-over support (level01: "Get the Money!")
- Redesign level01 with hand-crafted terrain sections (Flat, Incline,
Jump, Roller, Descent, Bumps, Flat, Descent, Bumps, Flat)
- Editor: per-section width and vertical scale (vScale) controls
- Editor: smooth entry blending between sections using angle-based
interpolation (avoids slope overshoot from naive height blending)
- Editor: new size-panel UI with range/number inputs and smooth checkbox
- Fix KidManager re-boarding: ejected kids must be settled before
re-boarding to prevent mid-air teleportation
- Load audio assets in PreloadScene; handle missing voice files gracefully
Ejection used to be g-force-triggered, but the suspension isolates the
chassis from shocks so the old threshold was effectively unreachable -
kids were never actually being ejected. Instead the bus now carries an
invisible three-sided box (floor + left/right walls, deliberately no
ceiling) pinned to the chassis with rigid constraints. The fixtures are
standalone bodies in a dedicated kid collision category, not compounded
into the chassis, because Matter only consults the root body's filter
on compounds, so only standalone bodies can be made to collide with kids
while the chassis part stays exempt.
KidManager now checks each kid's rotation-corrected chassis-local
position every physics tick and flips state in both directions: crossing
above the open top marks the kid ejected (light custom gravity,
kid_ejected texture), and drifting back down through it re-marks the kid
aboard. A per-tick hard clamp keeps kids from tunneling through the
floor/walls on a fast hit. Seat constraints and the settle timer are
gone - containment is purely physical collision. GForceMonitor is
demoted to a debug-only readout for landing diagnosis.
Kid art is now 5-frame spritesheets (one distinct kid per seat), with
the frame picked by seat index in Kid.js, and render order is fixed with
explicit depths (kids 1, bus chassis/wheels 2).