What you'll build

A short arcade dodger game. The kind of thing you'd bookmark for a 5-minute coffee break, not a 50-hour campaign. By the end you'll have:

The whole thing fits in about 250 lines of TypeScript across 3 scenes (Boot, Main, GameOver). Every line of code is generated by Claude using a real prompt you can copy.

What you need before you start

How to use this guide

Read sequentially. Don't skip ahead. The 4 hours are 4 hour-long blocks; you can pause between any of them. Each block has a single prompt and a clear deliverable. By Hour 4 you have a shipped game URL.

HOUR 01 ~60 min

Project scaffold and Phaser hello world

Open a terminal in a fresh folder. Run:

$ npm create vite@latest dodger -- --template vanilla-ts
$ cd dodger
$ npm install phaser
$ npm run dev

Vite gives you instant hot reload. Open http://localhost:5173. You'll see Vite's default page. We'll replace its content next.

Now use Pixeldex's pixel-perfect camera prompt as a reference for Phaser+TS structure, then send this scaffold prompt to Claude:

$ Build me a Phaser 3.70+ TypeScript scaffold for an arcade dodger game.

// shape
- Three scenes: BootScene, MainScene, GameOverScene.
- Game config: 320x480 logical resolution, scale Phaser.Scale.FIT, autoCenter.
- BootScene generates colored rect Texture2Ds at runtime for: player (green 24x16), obstacle (red 20x20), coin (yellow 14x14). Use this.textures.generate or this.add.graphics + generateTexture. No external assets.
- MainScene draws a starfield background (30 tiny white pixels at random positions, rendered via this.add.graphics).

// behavior
- BootScene immediately starts MainScene after generating textures.
- MainScene shows the player at the bottom-center, no movement yet.
- GameOverScene shows a "GAME OVER" text + "Press SPACE to restart" + final score (passed via scene data).

// constraints
- TypeScript strict mode. No any, no //@ts-ignore.
- One file per scene (boot.ts, main.ts, gameover.ts) plus main.ts entry that creates the game.
- Use a single shared CONSTANTS object (export const) for: WIDTH, HEIGHT, PLAYER_Y.

// return format
- Four files in separate code blocks: boot.ts, main.ts (scene), gameover.ts, index.ts (entry).
- A snippet showing what to put in index.html.
- No prose before or after.

Save each file in src/. Update index.html to match. Reload — you should see a black starfield with a green rectangle (the player) at the bottom.

End of Hour 1: a Phaser game running with three scenes wired up.

HOUR 02 ~60 min

Player movement and falling obstacles

Send this prompt:

$ Extend MainScene to add player movement and falling obstacles.

// player
- Create the player sprite at (CONSTANTS.WIDTH / 2, CONSTANTS.PLAYER_Y).
- Arrow keys move it left/right at 220 px/s. Clamp to screen bounds.
- Read input via this.input.keyboard.createCursorKeys().

// obstacles
- A Phaser group of obstacles at this.obstacles.
- Spawn one obstacle every 700ms via a Phaser timer event.
- Spawn position: random x in [10, WIDTH-10], y = -20.
- Each obstacle moves down at 160 px/s. Destroy it when y > HEIGHT + 20.

// collision
- this.physics.overlap(player, obstacles, () => this.scene.start('GameOverScene', { score: this.score }))
- For now, this.score = 0; we'll increment in the next step.

// constraints
- Use Phaser arcade physics. Add this.physics.world.setBounds.
- All numbers (spawn rate, fall speed, etc.) as named constants at the top of MainScene.

// return format
- One updated main.ts file in a code block.
- No prose before or after.

Reload. Use the arrows to dodge the falling red rectangles. When one hits you, you flip to the GameOver scene.

End of Hour 2: the core gameplay loop is alive.

HOUR 03 ~60 min

Coins, score HUD, and difficulty ramp

$ Extend MainScene with coins, a score HUD, and a difficulty ramp.

// coins
- A separate group this.coins.
- Spawn one coin every 1100ms (use a separate timer from obstacles).
- Coins fall at 120 px/s.
- this.physics.overlap(player, coins, (p, c) => { c.destroy(); this.score += 10; })

// score HUD
- A Phaser text object at (8, 8) showing "Score: 0".
- Updates every frame from this.score.
- Use Phaser's built-in font (no need to load).
- Style: 14px monospace, white.

// difficulty
- Every 10 seconds, increase obstacle fall speed by 20px/s and decrease spawn delay by 50ms (clamp delay to 200ms minimum).
- Use a this.time.addEvent loop with delay 10000 and loop true.

// game over
- When transitioning to GameOverScene, pass { score: this.score } as scene data.
- GameOverScene displays the final score below "GAME OVER".

// return format
- Updated main.ts and gameover.ts in two code blocks.
- No prose before or after.

Reload. Now you collect coins, score climbs, the game gets harder over time. The GameOver screen shows your final score.

End of Hour 3: a real game with difficulty curve.

HOUR 04 ~60 min

Sound, polish, and ship to itch.io

Sound: grab two free CC0 SFX from sfxr.me (more options on the audio toolkit page) — one "pickup/coin" and one "explosion/hit." Save in public/sounds/ as coin.wav and hit.wav.

Send this prompt:

$ Add sound, screen flash, and a build step.

// audio
- BootScene preloads /sounds/coin.wav and /sounds/hit.wav via this.load.audio.
- MainScene plays this.sound.play('coin') on coin pickup, 'hit' on collision.
- Add a small pitch jitter (+- 0.05) on coin so identical SFX don't sound mechanical.

// screen flash on hit
- On collision, before transitioning to GameOver, run this.cameras.main.flash(200, 255, 100, 100) and delay scene transition by 300ms.

// vite build for itch.io
- Add a build script step. The output should go to dist/ and use relative paths (./assets/...) so itch.io can serve it as a zipped folder.
- In vite.config.ts: base: './'.

// return format
- Updated boot.ts, main.ts, vite.config.ts in code blocks.
- No prose before or after.

Run npm run build. You get a dist/ folder. Test it locally: cd dist && python3 -m http.server 8000, open localhost:8000 — game should run.

Upload to itch.io:

  1. Zip the entire dist/ folder.
  2. itch.io → Upload new project. Name it "Dodger" (or whatever). Kind: HTML. Pricing: free.
  3. Upload the zip. Check This file will be played in browser. Set viewport: 320x480 (or 640x960 for embedded display).
  4. Save and view. Game should run in browser.

Share the URL.

DONE. You shipped a Phaser web game in an evening.

What to do next

Why this works

Three reasons this 4-hour walkthrough actually finishes:

  1. The web is forgiving. No build target hell, no platform store approval, no App Store review. Zip + upload + done.
  2. Phaser hides the boilerplate. No window/canvas setup, no game loop you write by hand. Scene + sprites + arcade physics is enough.
  3. Scope is locked. One enemy type. One pickup. One difficulty curve. No menus, no levels, no save system. Three or four hours is exactly enough for this scope.

License + sharing

This walkthrough is CC0. The Claude prompts are CC0. The output Claude returns is yours. If you ship a game with this guide, link to pixeldex.app in your itch description so the next solo dev can find it.