Build a pixel-perfect Space Invaders arcade game in a single self-contained HTML file with inline CSS and JS. Replicate the original 1978 Taito arcade cabinet experience with full fidelity to the original rules, sprite designs, and mechanics.
- 800×600px canvas (or scaled 2× from original 224×256 logical resolution)
- Black background, phosphor-green or white pixel aesthetic
- Scanline overlay effect (subtle CSS or canvas lines) to simulate CRT monitor
- Fixed aspect ratio — letterbox if viewport is smaller
- Use monospace pixel font (Press Start 2P from Google Fonts) for all UI text
Row 1 — Top (2 invaders wide, squid-like): Frame A: 00100 01110 11111 10101 01010 Frame B: 00100 01110 11111 01010 10001
Row 2–3 — Middle (crab-like): Frame A: 01010 11111 11111 10001 01010 Frame B: 00100 11111 11111 01110 10001
Row 4–5 — Bottom (octopus-like): Frame A: 01110 11111 11011 01110 10001 Frame B: 01110 11111 11011 10101 01010
Color per row:
- Top row: white/cyan
- Middle rows: white/green
- Bottom rows: white/magenta
00100 01110 11111 11111 Use color: #00FF41 (matrix green) or classic white
0011110 1111111 1101011 0111110 Draw as a flying saucer shape, color: red
Pixel grid ~22×16, classic bunker shape with notch at bottom center:
- Start solid, erode pixel-by-pixel when hit by bullets (both player and invader)
- Store as a 2D boolean pixel array; collision detection per pixel
- Player: single vertical line 1×6px, white
- Invaders: 3 pixel "squiggle" or "cross" shape, 2×6px, white or yellow
- Score (left), Hi-Score (center), lives (right) — top bar
- Game area below
- Bottom bar: row of small player ship icons = remaining lives
- 55 invaders total: 5 columns × 11 rows
- Row 1: 1 type (top)
- Rows 2–3: middle type
- Rows 4–5: bottom type
- Invaders start ~top 40% of screen
- 4 bunkers at ~70% height
- Player starts bottom 10%, centered, can move left/right only
- Invaders move as a grid block: step right → drop 8px → step left → drop 8px → repeat
- Step size: 2px per tick horizontally
- Speed increases as invaders are eliminated:
- 55 invaders: ~0.5 steps/sec
- 1 invader: ~fast as possible (~15 steps/sec)
- Use formula: speed = baseSpeed + (55 - remaining) * accelerationFactor
- Each invader animates between Frame A and Frame B on each horizontal step
- The "march sound" is 4 alternating bass tones (Web Audio API, see AUDIO)
- Appears randomly every 25–30 seconds (or when player fires 23rd bullet)
- Travels horizontally across top at fixed speed
- Awards 50–300 points (seemingly random, actually deterministic in original: based on shot count)
- Plays a looping high-pitched sound while visible
- Press SPACE to fire
- Max 1 bullet on screen at a time (must wait for previous to hit or go off-screen)
- Bullet travels upward at fast fixed speed
- Can destroy invaders, UFO, and damage bunkers
- A random invader from the bottom row of each column fires
- Max 3 invader bullets on screen simultaneously
- Bullets travel downward at moderate speed
- Bullets collide with player, bunkers, and player bullets (cancel each other out in original)
- Invader bullet hits player → player explodes (brief animation), lose 1 life, respawn centered
- Player bullet hits invader → invader explodes (2-frame burst animation), add score, remove from grid
- Player bullet hits UFO → UFO explodes, show score popup, award points
- Any bullet hits bunker pixel → erase that pixel region (~3×3px area)
- Invaders reaching bunker row → erase bunker pixels they overlap
- Invader reaches player row → GAME OVER immediately
- Bottom row invaders: 10 pts
- Middle rows: 20 pts
- Top row: 30 pts
- UFO: 50, 100, 150, or 300 pts (cycle based on total shots fired)
- Free life awarded at 1,000 points (original: 1500, configurable)
- Hi-Score persists in localStorage
- Start with 3 lives
- On death: brief explosion animation, short pause, respawn
- After 0 lives: show GAME OVER screen with score, hi-score, press ENTER to restart
- Invaders reaching the bottom = instant GAME OVER
- On clearing all invaders: brief flash, new wave starts
- Each new wave: invaders start one row lower than previous starting position
- Speed resets but with a slight base increase per level
- Bunkers do NOT regenerate between waves
Implement all sounds procedurally:
- March — 4 cycling tones: 160Hz, 130Hz, 100Hz, 80Hz — play one per invader step, 80ms duration, sawtooth wave
- Player shoot — short chirp: 800Hz → 200Hz sweep, 100ms, square wave
- Invader explode — noise burst: white noise, 300ms, amplitude decay
- Player explode — low rumble + noise, 800ms, multiple oscillators
- UFO loop — 40Hz + 80Hz alternating, continuous while UFO visible
- UFO hit — ascending sweep 200→1200Hz, 500ms
- Level clear — short ascending arpeggio
- Extra life — classic two-tone chime
All sounds: create AudioContext on first user interaction to comply with browser autoplay policy.
- ← → Arrow keys or A/D: move player
- SPACE: shoot
- P: pause/resume (show PAUSE overlay)
- Enter: start game / confirm on game over
- Support touch: left/right zones on screen + tap-to-shoot for mobile
- Top: "SCORE< 1 >" left, "HI-SCORE" center, "SCORE< 2 >" right (even in single player)
- Below top bar: actual score values
- Bottom: "CREDIT 00" right side, lives icons left side
- All text in Press Start 2P font, green (#00FF41) or white
- Attract mode: if not started, show "PLAY SPACE INVADERS", march invaders demo, show score table
- "1 MYSTERY = ? MYSTERY SHIP"
- "1 = 30 POINTS"
- "1 = 20 POINTS"
- "1 = 10 POINTS"
Structure your JS with clear separation:
Gameclass: main loop, state machine (ATTRACT, PLAYING, PAUSED, DEAD, GAME_OVER)InvaderGridclass: manages 55 invaders, movement, shooting logicPlayerclass: position, movement, shooting, livesBulletclass: position, velocity, owner (player/invader)Bunkerclass: pixel array, erosionUFOclass: spawning, movement, scoringRendererclass: all canvas drawing, sprite definitions as pixel arraysAudioEngineclass: Web Audio API, all sound generationInputHandlerclass: keyboard + touch eventsGameLoop: requestAnimationFrame with fixed timestep (60fps target)
- Single HTML file, zero external dependencies except Google Font (Press Start 2P)
- Vanilla JS only — no frameworks, no canvas libraries
- Must run in Chrome, Firefox, Safari latest
- Pixel-perfect rendering: disable image smoothing on canvas
- Use
ctx.imageSmoothingEnabled = false - All sprites drawn programmatically from pixel arrays (no image files)
- localStorage for hi-score persistence
- Fully playable, complete game — not a demo or partial implementation
- Player ship "warp in" animation at game start and after death
- Invader explosion lingers for 2-3 frames before disappearing
- Score popup (+30, +UFO score) floats up briefly where target was hit
- Screen flashes white for 1 frame on player death
- "GAME OVER" text animates in, red color
- Subtle scanline effect over entire canvas (CSS or drawn as semi-transparent horizontal lines)