oneshotlm
Compare all models on this prompt →

Space Invaders · grok-build-0.1

Build a playable Space Invaders game on a canvas: a player cannon that moves and shoots, a descending grid of aliens that advance and fire back, destructible bunkers, score, and lives. Procedural graphics only, no external assets.

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

Build a playable Space Invaders game on a canvas: a player cannon that moves and shoots, a descending grid of aliens that advance and fire back, destructible bunkers, score, and lives. Procedural graphics only, no external assets.

assistant
thinking
The task is to build a playable Space Invaders game in a single self-contained index.html file. It must include CSS in a <style> tag, JS in a <script> tag, no external resources, fully sandboxed.
First, the user wants a playable Space Invaders game in a single index.html file with procedural graphics only, no external assets. It needs to be self-contained with CSS in <style> and JS in <script>.

I need to build this and end with index.html present in /tmp/ws.

I have a write tool to create the file.

I need to write the entire HTML file content.

Plan the code:

- HTML structure: <!DOCTYPE html>, <html>, <head> with <style>, <body> with <canvas id="gameCanvas">, <div> for score and lives, maybe button.

- CSS for 100% width/height canvas, dark bg, green text.

- JS: script tag with all code.

Game logic in JS:

Use requestAnimationFrame for loop.

Handle keyboard events for movement and shooting.

Define entities.

For aliens: let's say 5 rows, 11 columns, but to keep simple, maybe 4 rows x 8 cols for performance, but classic is 11 wide.

Canvas width 800, height 600.

Player at bottom y=550, x=375 center.

Aliens start y=50, x from 50 to 750 step 60 or so.

For bunkers: 3 bunk 4 bunkers at bottom.

Each bunker: width 100px, height 50px, made of 4x4 blocks say 5x3 blocks.

Define a function to draw bunker with damage map.

Damage: array of arrays bool.

On hit, set to false.

For simplicity, use a list of 2d points or rects for each block.

Let's code it mentally.

I need to output the full code in the end.

Confidence: this is complex, but I know how to do it, so high confidence \confidence{70}

I need to write the code using the tool.
bash {"command":"ls -la /tmp/ws"}
toolResult

total 0 drwxr-sr-x. 2 node node 6 Aug 1 20:48 . drwxrwsrwx. 3 root node 16 Aug 1 20:48 ..

assistant
thinking
The task is to build a playable Space Invaders game on a canvas in a single self-contained index.html file. Everything inline: CSS in <style>, JS in <script>. No external resources, CDNs, or network r...First, I need to create an index.html file with the game. Since it's self-contained, all in one file.

I need to use the write tool to write the content to /tmp/ws/index.html.

But the user says "I need to end with index.html present there." So probably write it and confirm.

 The current directory is /tmp/ws, so I should write index.html there.

Plan the code.

Basic structure:

<!DOCTYPE html>
<html>
<head>
<title>Space Invaders</title>
<style>
body { background: black; margin: 0; }
canvas { display: block; margin: auto; background #000; }
#ui { position: absolute; top: 0; left: 0; color: white; }
</style>
</head>
<body>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<div id="ui">Score: 0 Lives: 3 </div>
<script>
// JS code here
</script>
</body>
</html>

Width 800 height 600 for classic.

Now, JS:

const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const ui = document.getElementById('ui');

 // Constants
const WIDTH = 800;
const HEIGHT = 600;
const PLAYER_WIDTH = 50;
const PLAYER_HEIGHT = 20;
const PLAYER_Y = HEIGHT - 50;
const ALIEN_ROWS = 5;
const ALIEN_COLS = 11;
const ALIEN_WIDTH = 40;
const ALIEN_HEIGHT = 30;
const ALIEN_SPACING_X = 50;
const ALIEN_SPACING_Y = 40;
const BULLET_WIDTH = 4;
const BULLET_HEIGHT = 10;
const BUNKER_ROWS = 4;
const BUNKER_COLS = 6;
const B UNKER_CELL_SIZE = 8;
const BUNKER_WIDTH = BUNKER_COLS * BUNKER_CELL_SIZE;
const BUNKER_HEIGHT = BUNKER_ROWS * BUNKER_CELL_SIZE;
const BUNKER_SPACING = 50;
const BUNKER_Y = HEIGHT - 100;
 // 4 bunkers: positions x = 50, 150, 450, 550 or something.

 // Game variables
let playerX = WIDTH / 2 - PLAYER_WIDTH / 2;
let score = 0;
let lives = 3;
let aliens = [];
let bullets = [];
let enemy Bullets = [];
let alienDx = 1;
let alienDy = 0;
let alienSpeed = 50; // pixels per move
let lastAlienMove = 0;
let alienInterval = 500;
let playerBullets = [];
let enemyBullets = [];
let keys = {};
let gameRunning = true;
let startScreen = true;
let bunkerGrids = [];

// Initialize bunkers
function initBunkers() {
  for(let i=0; i<4; i++) {
    let bx = 50 + i*200;
    let grid = createBunkerGrid();
    bunkerGr ids.push({x: bx, y: BUNKER_Y, grid: grid});
  }
}

function createBunkerGrid() {
  return [
    [1,1,1,1,1,1],
    [1,1,1,1,1,1],
    [1,1 1,1,1,1],
    [1,1,1,1,1,1]
  ]; // simple all filled, or patterned
  // better pattern
  return [
    [0,0,1,1,1,1],
    [0,1,1,1, 1,1],
    [1,1,1,1,1,1],
    [1,1,1,0,0,0]
  ];
}

// Init aliens
function initAliens() {
  aliens = [];
  for(let r=0; r<ALIEN_ROWS; r++) {
 for(let c=0; c<ALIEN_COLS; c++) {
    let x = ALIEN_START_X + c * ALIEN_SPACING_X;
    let y = ALIEN_START_Y + r * ALIEN_SPACING_Y;
    aliens.push({x, y, alive: true, row: 4-r, type: r});
  }
  }
}

const ALIEN_START_X = 50;
const ALIEN_START_Y = 50;

 // Add event listeners
document.addEventListener('keydown', e => {
  keys[e.key] = true;
  if(e.key === ' ' && !e.repeat && startScreen) {
    startScreen = false;
    initGame();
  }
  if(e.key === ' ' && !startScreen && playerBullets.length <2) {
    firePlayerBullet();
  }
});

document.addEventListener('keyup', e => {
  keys[e.key] = false;
});

 // Game loop
function gameLoop() {
  if(!gameRunning) return;
  update();
  draw();
  requestAnimationFrame(gameLoop);
}

function update() {
  if(startScreen) return;
  // Player movement
  if(keys['ArrowLeft'] || keys['a']) playerX -= 5 if(playerX >0);
  if(keys['ArrowRight'] || keys['d']) playerX +=5 if(playerX <WIDTH -PLAYER_WIDTH);
  // Shoot
  // Already in keydown but to cooldown
  // Better use cooldown
  // Let's add cooldown var
  // I need to add let shootCooldown =0;
  // In update: if(shootCooldown >0) shootCooldown--;
  // if(keys[' '] && shootCooldown <=0) {
  // firePlayerBullet();
  // shootCooldown = 10;
  // }
  // Yes, move fire to update.

  // Move aliens if(Date.now() - lastAlienMove > alienInterval) {
  moveAliens();
  lastAlienMove = Date.now();
  }
  // Move bullets
  moveBullets();
  // Check collisions
  checkCollisions();
  // Check win
  if(aliens.every(a=> !a.alive)) {
    nextWave();
  }
  // Check lose
  if(lives <=0) gameOver();
  // Check alien reach player
  checkAlienPlayerCollision();
}

function draw() {
  ctx.fillStyle = '#000';
  ctx.fillRect(0,0,WIDTH,HEIGHT);
  // Draw stars? Optional
  // Draw bunkers
  bunkerGrids.forEach(b => drawBunker(b));
  // Draw aliens
  aliens.forEach(a => if(a.alive) drawAlien(a.x, a.y, a.row));
  // Draw player
  drawPlayer(playerX, PLAYER_Y);
 // Draw bullets
  bullets.forEach(b => drawBullet(b.x, b.y));
  enemyBullets.forEach(b => drawBullet(b.x, b.y, 'red'));
  // Draw UI
  ui.innerHTML = `Score: ${score} Lives: ${lives}`;
  if(startScreen) {
 ctx.fillStyle = '#fff';
  ctx.font = '30px Arial';
  ctx.fillText('SPACE INVADERS', WIDTH/2 -200, HEIGHT/2 -50);
  ctx.font = '20px Arial';
  ctx.fillText('Use arrow keys to move, space to shoot', WIDTH/ 2 -300, HEIGHT/2);
  ctx.fillText('Press space to start', WIDTH/2 -100, HEIGHT/2 +50);
  }
  if(!gameRunning) {
 ctx.fillStyle = '#fff';
  ctx.font = '30px Arial';
  ctx.fillText('GAME OVER', WIDTH /2 -100, HEIGHT/2);
  }
}

 // Implement functions one by one.

This is getting long, I need to write the full code.

Since the task is to build it, I will use the tool to write a complete code.

I need to craft a complete index.html.

Let me try to write a minimal version first, then expand.

To save time, I recall there are standard codes for this.

But since no external, I have to write it.

Let's try to assemble a working code.

Let's write it.

First, the HTML part.

Then in script:

let canvas = document.getElementById(' gameCanvas');

let ctx = canvas.getContext('2d');

canvas.width = 800;

canvas.height = 600;

let player = {x: 375, y: 550, width: 50, height: 20};

let score = 0;

let lives = 3;

let aliens = [];

let bullets = [];

let enemyBullets = [];

let alienDirection = 1;

let alienSpeed = 1;

let alienMoveInterval = 1000;

let lastAlienMoveTime = 0;

let keys = {};

let gameState = 'start';

let shootCooldown = 0;

let bunkerGr ids = [];

let level = 1;

 // Init bunkers

function initBunkers() {

  bunkerGrids = [];

  for(let i =0; i<4; i++) {

    let x = 50 + i * 150;

    let grid = [

      [1,1, 1,1,1,1],

      [1,1,1,1,1,1],

      [1,1,1,1,1,1],

      [1,1,1,1,1,1]

    ]; // simple

    bunkerGrids.push({x: x , y: 400, grid: grid});

  }

}

 // Init aliens

function initAliens() {

  aliens = [];

  let startX = 50;

  let startY = 50;

  for(let r =0; r<5; r++) {

    for(let c=0; c<11; c++) {

      aliens.push({

        x: startX + c * 60,

        y: startY + r * 40,

        width: 40,

        height: 30,

        alive: true,

        row: r

      });

    }

  }

}

function fire PlayerBullet() {

  bullets.push({x: player.x + player.width /2 -2, y: player.y, width:4, height:10, dy: -10});

}

function moveBullets() {

  for(let i = bullets.length -1; i>=0; i--) {

    let b = bullets[i];

    b.y += b.dy;

    if(b.y <0) bullets.splice(i,1);

  }

  for(let i = enemyBullets.length -1; i>=0; i--) {

    let b = enemyBullets[i];

    b.
write /tmp/ws/index.html (16094 bytes)
toolResult

Successfully wrote 16094 bytes to /tmp/ws/index.html

assistant
thinking
The file is written. I need to verify it exists and test it somehow. Since it's a self-contained HTML, I can check the file and perhaps use a simple way to validate syntax.
bash {"command":"ls -la /tmp/ws/index.html && wc -c /tmp/ws/index.html"}
toolResult

-rw-r--r--. 1 node node 16108 Aug 1 20:50 /tmp/ws/index.html 16108 /tmp/ws/index.html

assistant
thinking
The file has been created successfully. It's a single self-contained index.html with the full Space Invaders game implemented using canvas, pure procedural graphics (no external assets), inline CSS an...
bash {"command":"head -n 30 /tmp/ws/index.html && echo \"...\" && tail -n 10 /tmp/ws/index.html"}
toolResult

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>SPACE INVADERS</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { background: #000; color: #0f0; font-family: 'Courier New', Courier, monospace; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; overflow: hidden; } h1 { font-size: 28px; letter-spacing: 8px; margin-bottom: 8px; text-shadow: 0 0 10px #0f0; } canvas { border: 3px solid #0a0; background: #000; box-shadow: 0 0 20px rgba(0, 255, 0, 0.3); image-rendering: crisp-edges; ... // Kick off lastAlienMove = Date.now(); lastEnemyFire = Date.now(); gameLoop(); } window.onload = startGame; </script> </body> </html>

assistant
thinking
The file is created successfully. It's a complete, self-contained Space Invaders game in a single index.html file.
bash {"command":"echo \"File present:\" && ls -lh /tmp/ws/index.html && echo \"\" && echo \"No external refs check:\" && grep -oE 'src=|href=|htt
toolResult

File present: -rw-r--r--. 1 node node 16K Aug 1 20:50 /tmp/ws/index.html No external refs check:

assistant
thinking
The file is complete and self-contained. It meets all requirements:

The single-file self-contained Space Invaders game has been created at `/tmp/ws/index.html`. **Features implemented:** - 640×720 canvas with retro green-on-black aesthetic - Player cannon: keyboard move (←/→ or A/D) + Space to fire (limited to 2 bullets) - 5×11 alien grid with classic shapes and row-based point values (10/20/30) - Aliens move horizontally, drop on edge hits, increase speed as they die, and eventually fire back - Player and bunker-damaging enemy bullets - 4 destructible bunkers with pixel-cell destruction (no holes pre-cut) - Score, lives (3), and level/wave counter - Progressive difficulty: faster aliens, higher fire rate per wave - Procedural graphics only: all drawn with `fillRect` (aliens, player, bullets, bunkers, stars) - States: start screen, gameplay, wave complete, game over + restart (Space or R) - Fully offline — no external files, CDNs, images, or network requests Open `index.html` directly in any browser to play.

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

modelgrok-build-0.1
vendorxAI · Grok
harnesspi-agent
generated2026-08-01

EVALUATION

3/5 working

Space Invaders starts on keyboard input with player ship, bunkers, aliens, and bullets; mouse input has no effect.

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 motion0.0%
on click0.0%
on drag0.0%
on wheel0.0%
on enter + space4.2%
on arrow keys3.3%
on w/a/s/d3.6%
frame spread18.6 / 255
console errors0
js errors none

METRICS

runtime132.4s
tokens in5.8k
tokens out20k
cached25k
cost / run$0.0515