oneshotlm
Compare all models on this prompt →

Tetris · mercury-2

Build a playable Tetris on a canvas with all seven tetrominoes, rotation, line clears, increasing speed, a next-piece preview, and score.

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

Build a playable Tetris on a canvas with all seven tetrominoes, rotation, line clears, increasing speed, a next-piece preview, and score.

assistant
write index.html (6228 bytes)
toolResult

Successfully wrote 6228 bytes to index.html

assistant
read {"path":"index.html","limit":2000}
toolResult

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Tetris</title> <style> body { background:#111; color:#fff; font-family:Arial,Helvetica,sans-serif; display:flex; justify-content:center; align-items:center; height:100vh; margin:0; } #game { position:relative; } canvas { background:#222; display:block; } #info { position:absolute; top:0; right:-150px; width:140px; } #info h2 { margin:0 0 5px; font-size:1.2em; } #info div { margin-bottom:10px; } </style> </head> <body> <div id="game"> <canvas id="board" width="300" height="600"></canvas> <div id="info"> <h2>Next</h2> <canvas id="next" width="120" height="120"></canvas> <h2>Score</h2> <div id="score">0</div> <h2>Level</h2> <div id="level">1</div> </div> </div> <script> (() => { const canvas = document.getElementById('board'); const ctx = canvas.getContext('2d'); const nextCanvas = document.getElementById('next'); const nextCtx = nextCanvas.getContext('2d'); const COLS = 10, ROWS = 20, BLOCK_SIZE = 30; const colors = [null,'cyan','blue','orange','yellow','green','purple','red']; const shapes = [ // I [[0,0,0,0], [1,1,1,1], [0,0,0,0], [0,0,0,0]], // J [[2,0,0], [2,2,2], [0,0,0]], // L [[0,0,3], [3,3,3], [0,0,0]], // O [[4,4], [4,4]], // S [[0,5,5], [5,5,0], [0,0,0]], // T [[0,6,0], [6,6,6], [0,0,0]], // Z [[7,7,0], [0,7,7], [0,0,0]] ]; let board = Array.from({length: ROWS}, () => Array(COLS).fill(0)); let current, next, posX, posY, score=0, level=1, linesCleared=0, dropInterval=1000, lastDrop=0, gameOver=false; function drawCell(x,y,color){ ctx.fillStyle = color; ctx.fillRect(x*BLOCK_SIZE, y*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); ctx.strokeStyle = '#111'; ctx.strokeRect(x*BLOCK_SIZE, y*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); } function drawBoard(){ ctx.clearRect(0,0,canvas.width,canvas.height); for(let y=0;y<ROWS;y++){ for(let x=0;x<COLS;x++){ const val = board[y][x]; if(val) drawCell(x,y,colors[val]); } } // draw current piece for(let y=0;y<current.length;y++){ for(let x=0;x<current[y].length;x++){ const val = current[y][x]; if(val) drawCell(posX+x, posY+y, colors[val]); } } } function drawNext(){ nextCtx.clearRect(0,0,nextCanvas.width,nextCanvas.height); const shape = next; const offsetX = Math.floor((nextCanvas.width/ BLOCK_SIZE - shape[0].length)/2); const offsetY = Math.floor((nextCanvas.height/ BLOCK_SIZE - shape.length)/2); for(let y=0;y<shape.length;y++){ for(let x=0;x<shape[y].length;x++){ const val = shape[y][x]; if(val){ nextCtx.fillStyle = colors[val]; nextCtx.fillRect((offsetX+x)*BLOCK_SIZE, (offsetY+y)*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); nextCtx.strokeStyle = '#111'; nextCtx.strokeRect((offsetX+x)*BLOCK_SIZE, (offsetY+y)*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); } } } } function rotate(mat){ const N = mat.length; const res = Array.from({length:N},()=>Array(N).fill(0)); for(let y=0;y<N;y++){ for(let x=0;x<N;x++){ res[x][N-1-y] = mat[y][x]; } } // trim empty rows/cols while(res[0].every(v=>v===0)) res.shift(); while(res[res.length-1].every(v=>v===0)) res.pop(); // left trim while(res.every(row=>row[0]===0)) res.forEach(row=>row.shift()); while(res.every(row=>row[row.length-1]===0)) res.forEach(row=>row.pop()); return res; } function collision(shape,offX,offY){ for(let y=0;y<shape.length;y++){ for(let x=0;x<shape[y].length;x++){ if(shape[y][x]){ const newX = offX + x; const newY = offY + y; if(newX<0||newX>=COLS||newY>=ROWS) return true; if(newY>=0 && board[newY][newX]) return true; } } } return false; } function merge(){ for(let y=0;y<current.length;y++){ for(let x=0;x<current[y].length;x++){ const val = current[y][x]; if(val && posY+y>=0){ board[posY+y][posX+x] = val; } } } } function clearLines(){ let rows = 0; for(let y=ROWS-1;y>=0;y--){ if(board[y].every(v=>v!==0)){ board.splice(y,1); board.unshift(Array(COLS).fill(0)); rows++; y++; // recheck same index after splice } } if(rows){ const points = [0,40,100,300,1200]; score += points[rows] * level; linesCleared += rows; level = Math.floor(linesCleared/10)+1; dropInterval = 1000 - (level-1)*100; document.getElementById('score').textContent = score; document.getElementById('level').textContent = level; } } function spawn(){ current = next; posX = Math.floor(COLS/2 - current[0].length/2); posY = -current.length; next = shapes[Math.floor(Math.random()*shapes.length)]; drawNext(); if(collision(current,posX,posY)){ gameOver = true; alert('Game Over! Score: '+score); } } function move(dx){ if(!collision(current,posX+dx,posY)) posX+=dx; } function softDrop(){ if(!collision(current,posX,posY+1)) posY++; else { merge(); clearLines(); spawn(); } } function hardDrop(){ while(!collision(current,posX,posY+1)) posY++; merge(); clearLines(); spawn(); } function rotateCurrent(){ const rotated = rotate(current); if(!collision(rotated,posX,posY)) current = rotated; } function loop(timestamp){ if(gameOver) return; if(timestamp - lastDrop > dropInterval){ softDrop(); lastDrop = timestamp; } drawBoard(); requestAnimationFrame(loop); } document.addEventListener('keydown',e=>{ if(gameOver) return; switch(e.key){ case 'ArrowLeft': move(-1); break; case 'ArrowRight': move(1); break; case 'ArrowDown': softDrop(); break; case 'ArrowUp': rotateCurrent(); break; case ' ': hardDrop(); break; } }); // init next = shapes[Math.floor(Math.random()*shapes.length)]; spawn(); requestAnimationFrame(loop); })(); </script> </body> </html>

assistant

The **index.html** file has been created in the current directory. It contains a complete, self‑contained Tetris game that runs entirely in the browser with no external resources: * All seven tetrominoes (I, J, L, O, S, T, Z) * Rotation, line clearing, and gravity that speeds up as you level * Next‑piece preview, score, and level display * Keyboard controls: ←/→ move, ↓ soft‑drop, ↑ rotate, space hard‑drop Open `index.html` in a browser to play. Enjoy!

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

modelmercury-2
vendorInception
harnesspi-agent
generated2026-08-01

EVALUATION

3/5 partial

Tetris renders with pieces falling, next preview, score/level, and pieces respond to arrows/wasd but score never increases and no lines cleared.

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.4%
on click0.8%
on drag1.4%
on wheel0.4%
on enter + space1.9%
on arrow keys0.9%
on w/a/s/d0.6%
frame spread15.4 / 255
console errors0
js errors none

METRICS

runtime6.8s
tokens in11k
tokens out2.7k
cached2.4k
cost / run$0.0043