Asteroids · grok-build-0.1
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.
transcript · 10 messages
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.
thinking
The task is to build a playable Asteroids game on a canvas in a single self-contained file named index.html. It must include CSS in a <style> tag, JS in a <script> tag, all inline. No external resourc...The task is to build a playable Asteroids game in a single self-contained index.html file with inline CSS and JS, using only procedural vector graphics on a canvas.
I need to implement:
- Canvas for rendering
- Ship: triangle that can rotate and thrust
- Bullets: projectiles
- Asteroids: polygonal 8-12 sides, random sizes/shapes, moving randomly, wrapping around edges
- Collision detection
- Splitting on hit
- Score and lives
- Game loop with RAF
- Input: arrows for rotate/thrust, space for shoot
Since it's single file, all in one HTML.
I recall classic JS 100 lines Asteroids code exists, I need to write it.
Let me outline code:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Asteroids</title>
<style>
body { margin:0; background:black; }
canvas { display:block; }
# // no UI needed, draw on canvas
</style>
</head>
<body>
<canvas id="c" width="800" height="600"></canvas>
<script>
// JS here
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const WIDTH = 800 // fixed
const HEIGHT = 600
// game vars
let ship = {
x: WIDTH/2, y: HEIGHT/2,
angle: 0,
vx:0, vy:0,
thrusting: false
}
let asteroids = []
let bullets = []
let particles = []
let score = 0
let lives = 3
let gameRunning = true
let keys = {}
const ROT_SPEED = 0.1
const THRUST = 0.1
const BULLET_SPEED = 5
const ASTEROID_SIZES = [3,2,1] // large med small
// init
function init() {
resetGame()
loop()
}
function resetGame() {
ship.x = WIDTH/2
ship.y = HEIGHT/2
ship.angle = 0
ship.vx = 0
ship.vy = 0
ship.thrusting = false
asteroids = []
bullets = []
particles = []
score = 0
lives = 3
spawnAsteroids(5)
gameRunning = true
}
function spawnAsteroids(n) {
for(let i=0; i<n; i++) {
let size = 3 // start with large
let a = createAsteroid(WIDTH * Math.random(), HEIGHT * Math.random(), size)
asteroids.push(a)
}
}
function createAsteroid(x, y, size) {
let radius = size * 25
let verts = 5 + size * 2 // more sides for smaller? or fixed 8
let points = []
for(let i=0; i<verts; i++) {
let ang = i * Math.PI*2 / verts + Math.random()*0.5
let r = radius + Math.random()*radius*0.3 - radius*0.15
points.push({x: Math.cos(ang)*r, y: Math.sin(ang)*r})
}
return {
x, y,
vx: (Math.random()-0.5)*0.5,
vy: (Math.random()-0.5)*0.5,
angle: Math.random()*Math.PI*2,
rotSpeed: (Math.random()-0.5)*0 // slow rot
, points, radius: radius, size
}
}
Better generate points properly.
Standard way:
function generateAsteroidPoints(size) {
const points = []
const numPoints = 8 + Math.floor(Math.random()*4)
const radius = size * 20
for(let i=0; i < numPoints; i++) {
const angle = i * (Math.PI * 2 / numPoints) + (Math.random() - 0.5) * 0.5
const radiusVariation = radius * (0.75 + Math.random() * 0.5)
points.push({
x: Math.cos(angle) * radiusVariation,
y: Math.sin(angle) * radiusVariation
})
}
return points
}
Then in create:
return {
x: Math.random()*WIDTH,
y: Math.random()*HEIGHT,
vx: (Math.random()-0.5)*1,
vy: (Math.random()-0. 5)*1,
angle: Math.random()*Math.PI*2,
rotSpeed: (Math.random()-0.5)*0.02,
points: generateAsteroidPoints(size),
size: size,
radius: size*25
}
Yes.
Then in update:
function update() {
if(!gameRunning) return // but for gameover
// input
if(keys['ArrowLeft'] || keys['a']) ship.angle -= ROT_SPEED
if(keys['ArrowRight'] || keys['d']) ship.angle += ROT_SPEED
if(keys['ArrowUp'] || keys['w']) {
ship.thrusting = true
ship.v x += Math.cos(ship.angle) * THRUST
ship.vy += Math.sin(ship.angle) * THRUST
} else ship.thrusting = false
// physics
ship.x += ship.vx
ship.y += ship.vy
// wrap ship
wrap(ship)
for(let i= 0; i<bullets.length; i++) {
let b = bullets[i]
b.x += b.vx
b.y += b.vy
wrap(b)
b.life --
if(b.life <0) bullets.splice(i,1)
}
for(let i=0; i<asteroids.{"command":"ls -la /tmp/ws"}total 0 drwxr-sr-x. 2 node node 6 Aug 1 19:43 . drwxrwsrwx. 3 root node 16 Aug 1 19:43 ..
thinking
The task is to build a playable Asteroids game in a single self-contained index.html file. It must include CSS in a <style> tag, JS in a <script> tag, all inline, no external resources, no CDNs, no ne...First, the user wants a playable Asteroids game in a single index.html file with inline CSS and JS, no external assets or CDNs. I need to build it step by step in my reasoning, then output the full HTML. Key elements: - Canvas for rendering. - Ship: vector graphics, rotatable, thrust (use arrows or WASD for controls). - Bullets: shoot with spacebar. - Asteroids: random polygons, split on hit. - Wrap around edges. - Score, lives. - Game loop with requestAnimationFrame. - Procedural: generate asteroids procedurally. I need to write the code myself, as I have no tools for execution, but I can reason it out. The system says "You use tools via function calls", but in available tools, there's "write" which is for writing files, but since it's a single file, I need to construct the HTML.
/tmp/ws/index.html (18892 bytes)Successfully wrote 18892 bytes to /tmp/ws/index.html
thinking
The file is written. Let me verify it exists and check its size.
{"command":"ls -la /tmp/ws/index.html && wc -c /tmp/ws/index.html"}-rw-r--r--. 1 node node 18900 Aug 1 19:44 /tmp/ws/index.html 18900 /tmp/ws/index.html
thinking
The file is complete and self-contained. Let me verify it works by checking for any syntax issues quickly.
{"command":"cd /tmp/ws && head -n 50 index.html && echo \"...\" && tail -n 20 index.html"}<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>ASTEROIDS</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { background: #000; color: #0f0; font-family: 'Courier New', monospace; display: flex; justify-content: center; align-items: center; min-height: 100vh; overflow: hidden; } #container { position: relative; border: 2px solid #0f0; box-shadow: 0 0 20px #0f0; } canvas { display: block; background: #000; image-rendering: pixelated; } #overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; display: flex; flex-direction: column; justify-content: space-between; padding: 15px; font-size: 18px; text-shadow: 0 0 5px #0f0; } .topbar { display: flex; justify-content: space-between; align-items: flex-start; } .score { font-size: 22px; } .lives { font-size: 18px; } .center { position: absolute; ... // Boot straight into the loop requestAnimationFrame(gameLoop); // Allow immediate space press to start setTimeout(() => { if (gameState === 'title') { // already ready } }, 100); // Easter egg: click title to start too document.getElementById('title').addEventListener('click', () => { if (gameState === 'title') startGame(); }); } init(); </script> </body> </html>
thinking
The file is written and complete. It's a fully self-contained single-file Asteroids game with:
**index.html** is complete and ready. Open it directly in any browser — fully self-contained, zero external resources. **Controls:** - ← / → or A / D — rotate - ↑ or W — thrust - Space — shoot (click canvas also works) - P — pause (during play) **Features:** - Classic thrust-and-rotate vector ship with screen wrapping - Procedural jagged asteroid polygons that rotate and split (large → medium → small) - Bullets wrap and have limited simultaneous count + fire rate - Score + 3 lives system - Particle effects (thrust flame + impact/explosion debris) - Retro phosphor-green vector aesthetic + subtle scanlines - Progressive waves with increasing asteroid count - Safe respawn positioning + brief invulnerability - Game over screen with final score + instant replay All graphics are generated with canvas primitives only. No images, fonts, or network calls.
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
EVALUATION
Vector Asteroids starts on space press, ship and asteroids render, arrows/wasd move asteroids field, click/drag/wheel don't affect menu as expected.
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.