- Create `src/data/themes.js` with theme definitions (background color, parallax layers) and a `getTheme()` resolver that falls back to campaign 1's default look
- Update `PlayScene` to load the active campaign's theme instead of hardcoding colors/texture keys
- Register campaign 2's `_2` background assets in the asset manifest with placeholder fallbacks
- Add updated background art for campaign 2 (`bg_far_2.png`)
- Add per-item sound keys to `SmashItemManager` and `BonusItemManager`, playing a dedicated clip on smash/collection (load-tolerant via `cache.audio.exists`)
- Preload new FX clips: `smash-{tv,chair,cone}` and `bonus-{cash,ctc,guitar}`
- Rebuild level07 terrain/layout with updated items, bonus placements, goal, and camera bounds
- Move level01 item positions to match new layout
- Update smash-items sprite sheet (PNG/PSD)
Introduces a new "bonus item" system alongside the existing smashables:
- **Gameplay**: Floating collectible prizes (CTC box, guitar, cash) that the bus passes through with zero physical response. On first contact, the item pops (scale-up + fade) and spawns a radial burst of tinted firework particles that arc down under gravity, settle on terrain, and fade out. Each collected item scores 100 points on the end-of-level tally.
- **Config**: `BONUS_ITEM` in `config.js` holds all tuning knobs (particle count, speed range, spin, lifetime, per-type tint palette, pop scale/duration). `SCORE.perBonusItem` added.
- **Entity**: New `BonusItemManager` class owns static sensor bodies for each bonus item, detects bus collisions, and orchestrates the pop + firework burst animation. Particles are real Matter bodies exempted from bus/kid collision so they can land on terrain without affecting gameplay.
- **Editor**: "Smashables" section renamed to "Placeables" with a kind toggle (Smashables vs Bonus items). Bonus items are float-only with no gravity option. Preview map, click-to-place, item list, and export all support both kinds. `splitPlaceables()` in `levelBuilder.js` splits the unified editor list into the two level arrays (`items` / `bonusItems`).
- **Levels**: Levels 2–6 updated with bonus item placements (and some additional smashable items).
- **Assets**: New `bonus-items.png` spritesheet (9 frames: 3 bonus items × [item + 2 firework objects]) registered in the asset manifest.
- **Score screen**: `_revealBonus()` method in `LevelScoreScene` displays collected bonus count and points, skipped when zero.
- Add levels 7-10 and move all 10 into campaign01 (campaign02 left empty
as scaffolding)
- Replace the old S-curve auto-layout with a 2-lane circuit: top lane
runs right→left, bottom lane left→right, finish flag in the
bottom-right corner. Comfortable up to ~12 levels per campaign.
- Re-export node/flag sprites as tight 512x512 badges (badge IS the
file) instead of centered-on-960x540 frames; update mapArt.js tables
(BADGE_FILE_FRAC, BADGE_HIT_FRAC, NODE_ART_FRAMES) and asset manifest
accordingly
- Size the finish-flag nudge to stay on-screen when a custom `positions`
layout ends at an edge (flips direction if out of bounds)
- Guard against empty campaigns: skip path/flag rendering when there are
no points, and bail early in _playFirst()
- Shrink node pill font slightly so the longest tag fits under tightly
spaced nodes
- Update README.md and sprites.md to reflect the new sprite convention,
lane geometry, and level count
- Refactor level select scene to handle variable node texture dimensions
instead of assuming all node art is centered on a 960×540 canvas
- Change BADGE_FILE_FRAC and nodeDisplaySize to accept per-state keys,
allowing map_node_current (512×512 badge) to differ from the other
nodes (960×540 frames)
- Update map_finish to use its new 512×512 tight export; reduce its
display scale accordingly
- Rename campaigns: "Sunny Suburbs" → "Evergreen Lake",
"Dusk Junction" → "Underprivileged Community"
- Update asset manifest dimensions and sprites.md documentation
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.
Add four new section types to the level editor:
- dropOff: instant vertical drop with gentle downward tail
- gap: flat lead-in, x-gap, flat landing at same height
- lip: flat run into a steepening (t²) kicker ramp
- dropGap: like gap but landing is well below takeoff
Fix Terrain physics body generation to extrude straight down from
segment endpoints instead of using rotated rectangles. A previous
perpendicular-offset approach caused near-vertical segments (dropOff
cliffs) to balloon physics bodies sideways under adjacent terrain,
making the bus ride above the drawn ground.
Update level03 ("Mind the Gap") to use editor-generated terrain data.
Generalize levelBuilder smoothing to detect gap-shaped sections
(structurally via takeoffPoints/landingPoints) rather than by type
string, so future gap types work automatically.
- Fix terrain preview aspect ratio to match in-game rendering by using
consistent X/Y scaling, preventing slopes from appearing distorted
- Calculate timeLimit automatically based on level length and pace
(TIME_LIMIT_PACE) to ensure consistent difficulty scaling across levels
- Add max-height and vertical scrolling to the level preview panel
- Generate level02 (The Big Jump) from the editor with manual tweak
- Add `timeLimit` configuration to levels 1-4
- Implement countdown timer that starts when throttle is pressed
- Display remaining time in HUD, turning red when under 10s
- Add 'time-up' failure condition and message in LevelFailedScene
- 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: drop GFORCE.ejectThresholdG from 6 to 0.5 - the bouncier
suspension isolates the chassis from shock, so the old threshold was
effectively unreachable and kids were never actually being ejected.
Ejected kids now pop straight up through the roof (ignoring chassis
velocity/tilt) and fly under a lighter gravity (KID.ejectedGravityScale
0.35, applied via KidManager's beforeupdate handler) for a floaty,
Snuggle-Truck-style arc.
- Cut maxLeanAngularVelocity and leanTorqueStep in half for a slower,
more gradual lean that's easier to fine-tune mid-air.
- Parallax: far layer is now screen-fixed, scaled uniformly (no stretch),
and pans exactly once from start to goal by level progress; mid/near
layers are bottom-anchored and tiled at their own uniform scales. Kids
render at depth -1 so the bus always draws over them.
- Level builder: size camera bounds to the level's actual terrain min/max
Y (with padding, 1000px floor) instead of a fixed 1000 height, so long
runs of declines no longer push the bus below the camera's reach.
- Add level 04 "Mega Drop" (5 kids, extended terrain ending in the mega
drop sequence).
- New browser level editor (editor.html + src/editor/): assemble levels
from snap-together section generators (flat/inclines/hills/ditch/jump)
with a live canvas preview, metadata form, and export to ready-to-drop
levelNN.js source; example export registered as level04.js.
- Add parallax background sprites (bg_far/mid/near).
- Bus retune: softer, bouncier suspension (stiffness 0.45->0.35, damping
0.08->0.035, travel 12->30, restitution 0.3->0.45) with wheel rest
point raised 22->34 for a bouncier stance; drive force cut ~60%
(0.011->0.0045) for a much longer runway and lower top speed.
- Gravity 1 -> 0.675 for ~1.5x hang time off jumps; constraintIterations
2 -> 10 so the soft wishbone springs converge within one step.
- Bus: clamp each wheel to the underside of its wishbone anchor line on
every matter afterupdate, fixing wheels punching through to the
mirrored solution and sticking high on the chassis after hard impacts;
add no-op destroy() for the world listener.
- CameraRig: speed-driven horizontal lookahead (bus framed ~10% from the
left edge at rest, out to 1/3 of the screen at speed) via followOffset;
PlayScene scales the g-force grace period to 5.5s for the new gravity
and calls the new update()/destroy() hooks.
- Extend level01's terrain runway by 30x.