A 2D side-scrolling platformer built with Phaser 4, React 19, TypeScript, and Vite. Play as a wizard crossing a procedurally generated world through four seasons — collect starlights to push back the darkness, dodge or defeat murklings, and clear Spring through Winter to win.
AI / contributor reference: See AGENTS.md for architecture, game logic, world generation, assets, and conventions. Start there instead of reading the full codebase.
npm install
npm run devOpen http://localhost:8080. The game loads Story → Instructions → Game (MainMenu is registered but skipped on cold start).
| Command | Description |
|---|---|
npm install |
Install dependencies |
npm run dev |
Development server with hot reload |
npm run build |
Production build in dist/ |
Each season starts with the sky at 50% darkness. Darkness rises passively over time (~90 seconds to reach 100% if you collect nothing). Collect starlights to reduce darkness; reach 0% to clear the season. Beat all four seasons — Spring, Summer, Fall, Winter — to win. If darkness hits 100%, you lose.
- Murklings patrol platforms; touching one adds darkness and knocks you back.
- Striker murklings (Summer onward) stop and shoot purple bolts at range.
- Fireballs (Space) destroy murklings but lock movement briefly during the attack animation.
- Clearing Spring–Fall shows a season-complete interstitial, regenerates the world, and advances to the next season.
- Esc opens pause with Resume and New Game (regenerates the map and restarts gameplay).
| Input | Action |
|---|---|
| Left / Right | Move |
| Shift + Left / Right | Run (faster move + higher jump) |
| Up | Jump |
| Space | Throw fireball |
| Esc | Pause / resume |
| Technology | Version |
|---|---|
| Phaser | 4 |
| React | 19 |
| Vite | 6 |
| TypeScript | 5.7 |
Viewport: 1280 × 960. World width: 6480px (135 tile columns × 48px).
src/
main.tsx, App.tsx, PhaserGame.tsx # React shell + Phaser bridge
game/
main.ts # Phaser config, scene list
debug.ts # Dev flags (physics grid, start season)
scenes/ # Preloader, Story, Instructions, Game, …
world/ # Procedural map, platforms, spawn pickers
config/ # Season, starlight, murkling, combat tuning
stats/ # Lifetime stats (localStorage)
public/assets/
background/ # Seasonal parallax layers
platform/ # Tiles + seasonal trees
wizard/, murkling/, starlight/ # Character and collectible art
Key gameplay lives in src/game/scenes/Game.ts. Per-season difficulty and backgrounds are in src/game/config/seasonConfig.ts.
IDE: Run and Debug → Debug in Chrome (starts Vite and attaches the debugger; breakpoints work in src/).
URL flags (see src/game/debug.ts):
| Param | Effect |
|---|---|
?physicsDebug=1 |
Arcade body outlines |
?worldGrid=1 |
World-map grid overlay |
In-game hotkeys (dev builds, Game scene): P toggles physics debug, G toggles world grid.
DEFAULT_START_SEASON in debug.ts is currently 2 (Summer) for testing; set to 1 for a normal Spring start.
Static assets load from public/assets/ in Phaser's Preloader. After npm run build, they are copied to dist/.
PhaserGame.tsx creates the Phaser game and exposes it via React ref. Scenes emit EventBus.emit('current-scene-ready', this) when ready so React can track the active scene. See src/game/EventBus.ts and AGENTS.md for details.
Run npm run build, then upload the entire dist/ folder to a static web host.
Built on the Phaser React TypeScript template. Game design and implementation: The Starwarden project.