wave: score:
lives:

move mouse to aim · auto-fire · survive


How to play

Move your mouse over the canvas to pilot your ship. It follows your cursor smoothly. Bullets fire automatically every few frames. Destroy asteroids and enemy drones before they reach you. Each wave spawns more and faster enemies. You have three lives — collisions cost one. Reach zero and it's over.

On touch devices, tap and drag across the canvas to move the ship.

Design notes

The aesthetic mirrors the rest of the site: Geist Mono, dark background, muted whites. Particles, asteroids, and explosions are rendered entirely on a single 2D canvas with no external libraries. The ship is a minimal triangle — one vertex always points toward the nearest threat.

Technical overview

systemimplementation
RenderingHTML Canvas 2D, requestAnimationFrame loop
Ship controlmouse / touch position → lerp to target each frame
Shootingauto-fire: bullet spawns at ship nose every N frames
Asteroidspolygon with random vertex jitter, slow rotation
Enemieshoming drones added from wave 3 onward
Collisioncircle–circle distance check for all entities
Difficultywave number scales spawn count and speed multiplier
Particlesexplosion sparks with velocity, gravity, fade-out

Source highlights

// ship smoothly follows mouse via lerp
ship.x += (mouse.x - ship.x) * 0.12;
ship.y += (mouse.y - ship.y) * 0.12;

// auto-fire: every FIRE_INTERVAL frames
if (frameCount % fireInterval === 0) spawnBullet();

// asteroid polygon generation
for (let i = 0; i < sides; i++) {
  const angle = (i / sides) * Math.PI * 2;
  const r = radius * (0.75 + Math.random() * 0.5);
  verts.push({ x: Math.cos(angle) * r, y: Math.sin(angle) * r });
}

[go back to /cool stuff]