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:
- A player ship that moves left/right with arrow keys
- Obstacles that fall from the top at increasing speed
- Coins that fall and award points when collected
- A score HUD that updates as you play
- A "you died" screen with a one-key restart
- Sound effects for pickup and collision
- The game embedded as a playable web build on itch.io
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
- Node.js 18+ installed (free, nodejs.org)
- A code editor (VS Code is fine, free)
- A free Claude account
- A free itch.io account
- Roughly 4 hours, can be one evening
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.
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.
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.
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.
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:
- Zip the entire
dist/folder. - itch.io → Upload new project. Name it "Dodger" (or whatever). Kind: HTML. Pricing: free.
- Upload the zip. Check This file will be played in browser. Set viewport: 320x480 (or 640x960 for embedded display).
- Save and view. Game should run in browser.
Share the URL.
What to do next
- Add a high-score system. Use the JSON save prompt approach but in localStorage instead of PlayerPrefs.
- Better art. Replace the colored rectangles with real sprites. Use the sprite spec builder to plan multi-directional ship art.
- More obstacle types. A homing seeker, a faster zig-zagger, etc. Each is one new sprite + one new behavior method.
- Mobile controls. Add this.input.on('pointermove') for touch dragging the player. Phaser handles the mobile event mapping for you.
- Submit to a game jam. Phaser games are jam favorites because they run anywhere.
Why this works
Three reasons this 4-hour walkthrough actually finishes:
- The web is forgiving. No build target hell, no platform store approval, no App Store review. Zip + upload + done.
- Phaser hides the boilerplate. No window/canvas setup, no game loop you write by hand. Scene + sprites + arcade physics is enough.
- 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.
For more Phaser content on Pixeldex (the no-install walkthrough, the pixel-perfect camera prompt, the kids edition), see the Phaser engine track.
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.dev in your itch description so the next solo dev can find it.