oneshotlm
Compare all models on this prompt →

Asteroids · gemini-3.1-flash-lite

Build a playable Asteroids game on a canvas: a thrust-and-rotate vector ship that shoots and wraps around the screen edges, splitting asteroids into smaller pieces, with score and lives. Procedural vector graphics only, no external assets.

⛨ sandboxed Open in new tab ↗
transcript · 4 messages
user

Build a playable Asteroids game on a canvas: a thrust-and-rotate vector ship that shoots and wraps around the screen edges, splitting asteroids into smaller pieces, with score and lives. Procedural vector graphics only, no external assets.

assistant
thinking
**Developing Core Mechanics**

I'm currently focused on implementing the fundamental elements for our Asteroids game. The ship's movement, including thrust and rotation, is taking shape, and I'm also starting to integrate the shooting mechanism. Next, I'll be tackling screen wrapping and the initial asteroid behavior.

**Implementing Core Game Logic**

I'm now shifting my focus to integrating the score and lives systems. The core game loop is well-defined with `requestAnimationFrame`, and I'm refining the entity structures for ship, bullets, and asteroids. Collision detection using circular approximations and vector math is a key area I'm actively working on.

write index.html (5392 bytes)
toolResult

Successfully wrote 5392 bytes to index.html

assistant

This single-file solution implements the Asteroids game using HTML5 Canvas and procedural vector drawing. It includes: * **Vector Physics:** Thrust movement, rotation, and momentum for the ship. * **Game Loop:** The game runs in a `requestAnimationFrame` loop. * **Procedural Asteroids:** Asteroids are generated as random polygons that wrap around the screen. * **Collision Detection:** Circular math resolves ship-asteroid and bullet-asteroid interactions. * **Mechanics:** Shooting triggers asteroid splitting, and the ship has lives and persistent score tracking. You can open `index.html` in any modern web browser to play. **Controls:** * **Arrow Keys:** Rotate and Thrust. * **Spacebar:** Shoot. ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Asteroids Vector Game</title> <style> body { margin: 0; background: #000; color: #fff; overflow: hidden; font-family: monospace; } canvas { display: block; } #ui { position: absolute; top: 10px; left: 10px; pointer-events: none; } </style> </head> <body> <div id="ui"> Score: <span id="score">0</span><br> Lives: <span id="lives">3</span> </div> <canvas id="game"></canvas> <script> const canvas = document.getElementById('game'); const ctx = canvas.getContext('2d'); const scoreEl = document.getElementById('score'); const livesEl = document.getElementById('lives'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; let score = 0, lives = 3, gameOver = false; const keys = {}; window.addEventListener('keydown', e => keys[e.code] = true); window.addEventListener('keyup', e => keys[e.code] = false); const ship = { x: canvas.width / 2, y: canvas.height / 2, dx: 0, dy: 0, angle: -Math.PI / 2, bullets: [], lastShot: 0 }; let asteroids = []; function createAsteroid(x, y, radius, level = 3) { const vertices = []; const offset = 8; for (let i = 0; i < 8; i++) { vertices.push({ x: (radius + Math.random() * offset - offset / 2) * Math.cos(i / 8 * 2 * Math.PI), y: (radius + Math.random() * offset - offset / 2) * Math.sin(i / 8 * 2 * Math.PI) }); } return { x, y, dx: (Math.random() - 0.5) * 2, dy: (Math.random() - 0.5) * 2, radius, vertices, level }; } for(let i=0; i<5; i++) asteroids.push(createAsteroid(Math.random()*canvas.width, Math.random()*canvas.height, 40)); function drawVector(x, y, vertices, angle = 0) { ctx.beginPath(); ctx.strokeStyle = '#fff'; ctx.lineWidth = 2; for (let i = 0; i < vertices.length; i++) { const px = x + vertices[i].x * Math.cos(angle) - vertices[i].y * Math.sin(angle); const py = y + vertices[i].x * Math.sin(angle) + vertices[i].y * Math.cos(angle); if (i === 0) ctx.moveTo(px, py); else ctx.lineTo(px, py); } ctx.closePath(); ctx.stroke(); } function update() { if (gameOver) return; if (keys['ArrowLeft']) ship.angle -= 0.1; if (keys['ArrowRight']) ship.angle += 0.1; if (keys['ArrowUp']) { ship.dx += Math.cos(ship.angle) * 0.2; ship.dy += Math.sin(ship.angle) * 0.2; } if (keys['Space'] && Date.now() - ship.lastShot > 250) { ship.bullets.push({ x: ship.x + Math.cos(ship.angle)*20, y: ship.y + Math.sin(ship.angle)*20, dx: Math.cos(ship.angle)*7, dy: Math.sin(ship.angle)*7, life: 60 }); ship.lastShot = Date.now(); } ship.x = (ship.x + ship.dx + canvas.width) % canvas.width; ship.y = (ship.y + ship.dy + canvas.height) % canvas.height; ship.dx *= 0.99; ship.dy *= 0.99; ship.bullets.forEach((b, i) => { b.x += b.dx; b.y += b.dy; b.life--; if(b.life <= 0) ship.bullets.splice(i, 1); }); asteroids.forEach((a, i) => { a.x = (a.x + a.dx + canvas.width) % canvas.width; a.y = (a.y + a.dy + canvas.height) % canvas.height; ship.bullets.forEach((b, bi) => { if (Math.hypot(a.x - b.x, a.y - b.y) < a.radius) { if (a.level > 1) { asteroids.push(createAsteroid(a.x, a.y, a.radius / 2, a.level - 1)); asteroids.push(createAsteroid(a.x, a.y, a.radius / 2, a.level - 1)); } asteroids.splice(i, 1); ship.bullets.splice(bi, 1); score += 100; scoreEl.innerText = score; } }); if (Math.hypot(a.x - ship.x, a.y - ship.y) < a.radius) { lives--; livesEl.innerText = lives; if (lives <= 0) gameOver = true; ship.x = canvas.width/2; ship.y = canvas.height/2; ship.dx = 0; ship.dy = 0; } }); if (asteroids.length === 0) for(let i=0; i<6; i++) asteroids.push(createAsteroid(Math.random()*canvas.width, Math.random()*canvas.height, 40)); ctx.fillStyle = '#000'; ctx.fillRect(0, 0, canvas.width, canvas.height); drawVector(ship.x, ship.y, [{x:20, y:0}, {x:-10, y:10}, {x:-5, y:0}, {x:-10, y:-10}], ship.angle); ship.bullets.forEach(b => { ctx.fillStyle='#fff'; ctx.fillRect(b.x, b.y, 2, 2); }); asteroids.forEach(a => drawVector(a.x, a.y, a.vertices)); requestAnimationFrame(update); } update(); </script> </body> </html> ```

TAKE IT TO CODE

A single self-contained HTML file — copy it and open in any browser, or reuse the prompt with your own pi-agent run.

RUN

modelgemini-3.1-flash-lite
vendorGoogle
harnesspi-agent
generated2026-07-22

EVALUATION

2/5 partial

Ship and asteroids render and drift, but ship never rotates/thrusts/shoots in response to any input; controls appear non-functional.

Vision grade · anthropic/claude-sonnet-5

MEASUREMENTS

Raw readings from the capture, not a verdict — the grade above is the only judgement. Percentages are how much of the screen changed; the measure under-reports sparse motion on a dark background.

idle motion2.6%
on click2.8%
on drag2.7%
on wheel0.0%
on enter + space0.0%
on arrow keys0.0%
on w/a/s/d0.0%
frame spread6.8 / 255
console errors0
js errors none

METRICS

runtime17.4s
tokens in4.6k
tokens out4.0k
cached0
cost / run$0.0072