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.
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.