Go to file
Brian Fertig 6229f9529b Refactor level select into campaign map with auto-layout
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.
2026-08-21 12:41:49 -06:00
assets Refactor level select into campaign map with auto-layout 2026-08-21 12:41:49 -06:00
src Refactor level select into campaign map with auto-layout 2026-08-21 12:41:49 -06:00
vendor Initial Commit 2026-08-18 20:23:33 -06:00
README.md Refactor level select into campaign map with auto-layout 2026-08-21 12:41:49 -06:00
editor.html feat(editor): improve level preview and auto-calculate time limits 2026-08-20 12:38:21 -06:00
index.html Initial Commit 2026-08-18 20:23:33 -06:00
sprites.md Refactor level select into campaign map with auto-layout 2026-08-21 12:41:49 -06:00
start_web.sh Initial Commit 2026-08-18 20:23:33 -06:00

README.md

Monsterplex

A Trials-style physics driving game starring a school bus, crossed with Snuggle Truck: land badly enough and the g-force throws your passengers off. Built with Phaser 4, plain ES6 modules, and no package manager.

Running it

Browsers block ES module imports over file://, so serve the folder with any static file server. No install needed - this ships with Python 3:

python3 -m http.server 8000

Then open http://localhost:8000/.

Controls

  • Arrow Up / W - throttle
  • Arrow Down / S - brake / reverse
  • Arrow Left/Right / A/D - lean the bus left/right

Land smoothly or the g-force throws a kid off the bus. Lose all of them and the level fails.

Project layout

index.html            entry point, import map -> vendor/phaser.esm.js
vendor/phaser.esm.js   vendored local copy of Phaser 4 (see below)
src/main.js            Phaser.Game config + scene list
src/config.js          every tunable constant (physics, g-force threshold, camera, ...)
src/scenes/            Boot -> Preload -> Intro -> MainMenu -> LevelSelect (map) -> Play -> LevelScore -> LevelSelect / LevelFailed
src/entities/          Bus, Kid, Terrain
src/systems/           GForceMonitor, KidManager, InputController, CameraRig
src/data/levels/       the 3 hand-authored levels
src/util/              asset manifest, placeholder-texture generator, localStorage progress, small UI helper
assets/                where real art goes (see manifest below) - currently empty

Adding real art

No art assets exist yet - src/util/assetManifest.js lists every image the game expects, and PreloadScene falls back to a synthesized colored placeholder (via src/util/placeholderTextures.js) for anything missing. Drop a real PNG at the exact path below and it's picked up automatically - no code changes needed.

key path size notes
bus_chassis assets/sprites/bus_chassis.png 170x64 scaled to this size regardless of source resolution
bus_wheel assets/sprites/bus_wheel.png 52x52 used for both wheels
kid_idle assets/sprites/kid_idle.png 28x28 passenger while aboard
kid_ejected assets/sprites/kid_ejected.png 28x28 passenger after being thrown off
bg_far assets/backgrounds/bg_far.png 256x540 tiled, slowest parallax layer
bg_mid assets/backgrounds/bg_mid.png 256x540 tiled, mid parallax layer
bg_near assets/backgrounds/bg_near.png 256x540 tiled, fastest parallax layer
icon_kid assets/ui/icon_kid.png 24x24 HUD "kids aboard" icon
favicon assets/favicon.png 32x32 browser tab icon

Tuning the feel

Everything worth tweaking lives in src/config.js, notably:

  • GFORCE.ejectThresholdG - how hard a landing has to be before a kid is thrown off. Not physically derived - tune by playtesting.
  • GFORCE.gracePeriodMs / ejectCooldownMs - ignore-window after level start/restart, and minimum time between two ejections so one bad landing doesn't empty the whole bus at once.
  • BUS.* - suspension stiffness/damping, wheel friction, throttle/lean torque and their clamps.

Set DEBUG = true in config.js to show a live g-force readout and Matter's physics debug overlay in PlayScene.

Phaser 4 loading

Phaser is vendored locally at vendor/phaser.esm.js (downloaded once from jsDelivr's CDN build) and wired up via an import map in index.html, so every source file just does import Phaser from 'phaser' like a normal npm project would - the only place that knows about the vendored file is that one import map line. This keeps the project working fully offline with no runtime dependency on a third-party CDN staying up.

To upgrade Phaser later: download a newer phaser.esm.js build over vendor/phaser.esm.js and re-verify Bus.js against the Matter physics Factory API in the new file (grep for class Factory under the Matter section).