Run details
- Model
- opencode/nemotron-3.5-lightning-free
- Route
- opencode CLI
- Reasoning
- provider default
- Limits
- 60 min · 262,144 output tokens
- Date
- 2 Oct 2026
- Time
- 4 min 7 s
- Size
- 6.8 kB
- Tokens
- 24,797 in, 9,984 out
- List price
- $0.004 ($0.07 in / $0.2 out per M)
- Paid
- Not billed per run (CLI plan)
Exact prompt
Make a Breakout game I can play right now with the keyboard or the mouse. Give it several levels, a score and some juice. It must be one complete, self-contained HTML file: inline all CSS and JavaScript, and make no network requests of any kind (no CDNs, web fonts or remote images). Save it as index.html in the current directory, then stop. Do not ask questions.
Source
6.8 kB 239 lines Raw
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Breakout</title>
<style>
body { margin:0; overflow:hidden; background:#111; }
canvas { display:block; }
</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
(()=> {
const cnv = document.getElementById('c');
const ctx = cnv.getContext('2d');
let w, h, PADDLEWidth = 100, PADDLEHeight = 15, paddleX = 0;
let ballX = 0, ballY = 0, ballVX = 4, ballVY = -4, radius = 10;
let score = 0, lives = 3, level = 1, bricks = [];
let particles = [], powerUps = [];
let gameOver = false, playing = false;
function resize() {
w = cnv.width = innerWidth;
h = cnv.height = innerHeight;
}
resize();
window.addEventListener('resize', resize);
function initBricks() {
bricks = [];
const brickRowCount = 5 + level * 2;
const brickColumnCount = Math.max(4, Math.floor(w / 60));
const brickWidth = (w - 20) / brickColumnCount - 4;
const brickHeight = 20;
for (let c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (let r = 0; r < brickRowCount; r++) {
const status = 1;
bricks[c][r] = { x: c * (brickWidth + 4) + 20, y: r * (brickHeight + 4) + 30, status };
}
}
}
function drawBall() {
ctx.beginPath();
ctx.arc(ballX, ballY, radius, 0, Math.PI * 2);
ctx.fillStyle = '#fff';
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, h - 30, PADDLEWidth, PADDLEHeight);
ctx.fillStyle = '#0ff';
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for (let c = 0; c < bricks.length; c++) {
for (let r = 0; r < bricks[c].length; r++) {
if (bricks[c][r].status === 1) {
const b = bricks[c][r];
ctx.beginPath();
ctx.rect(b.x, b.y, (w - 20) / bricks[c].length - 4, 20);
ctx.fillStyle = '#f55';
ctx.fill();
ctx.closePath();
}
}
}
}
function drawScore() {
ctx.font = '16px Arial';
ctx.fillStyle = '#fff';
ctx.fillText(`Score: ${score}`, 8, 20);
ctx.fillText(`Level: ${level}`, w - 100, 20);
}
function drawLives() {
ctx.font = '16px Arial';
ctx.fillStyle = '#fff';
ctx.fillText('Lives: ' + lives, w - 150, 20);
}
function drawParticles(x, y, color) {
const count = 8;
for (let i = 0; i < count; i++) {
particles.push({
x: x, y: y,
vx: (Math.random() - 0.5) * 6,
vy: (Math.random() - 0.5) * 6,
color: color || '#fff',
life: 30
});
}
}
function drawParticlesLoop() {
ctx.fillStyle = '#fff';
particles.forEach(p => {
p.x += p.vx; p.y += p.vy; p.vy *= 0.95; p.vx *= 0.95; p.life--;
ctx.globalAlpha = p.life / 30;
ctx.fillRect(p.x - 2, p.y - 2, 4, 4);
});
ctx.globalAlpha = 1;
requestAnimationFrame(drawParticlesLoop);
}
drawParticlesLoop();
function movePaddle(dx) {
paddleX = Math.max(0, Math.min(w - PADDLEWidth, paddleX + dx));
}
function spawnPowerUp(x, y) {
powerUps.push({ x, y, vy: 2, width: 30, height: 10, type: Math.random() > 0.5 ? 'extra' : 'wider' });
}
function drawPowerUps() {
powerUps.forEach(p => {
p.y += p.vy;
ctx.fillStyle = p.type === 'extra' ? '#0f0' : '#ff0';
ctx.fillRect(p.x, p.y, p.width, p.height);
});
}
function collisionBallPaddle() {
if (ballY + radius > h - 30 && ballY - radius < h - 30 + PADDLEHeight &&
ballX > paddleX && ballX < paddleX + PADDLEWidth) {
ballVY = -Math.abs(ballVY);
ballY = h - 30 - radius;
const hitPos = (ballX - paddleX) / PADDLEWidth - 0.5;
ballVX = hitPos * 5;
drawParticles(paddleX + PADDLEWidth / 2, h - 30, '#0ff');
}
}
function collisionBallBricks() {
for (let c = 0; c < bricks.length; c++) {
for (let r = 0; r < bricks[c].length; r++) {
if (bricks[c][r].status === 1) {
const b = bricks[c][r];
if (ballX + radius > b.x && ballX - radius < b.x + (w - 20) / bricks[c].length - 4 &&
ballY + radius > b.y && ballY - radius < b.y + 20) {
ballVY = -ballVY;
bricks[c][r].status = 0;
score += 10 * level;
drawParticles(b.x + (w - 20) / bricks[c].length / 2, b.y + 10, '#f55');
if (Math.random() < 0.2) spawnPowerUp(b.x, b.y);
}
}
}
}
}
function collisionPowerUpPaddle() {
powerUps.forEach((p, i) => {
if (ballY + radius > p.y && ballY - radius < p.y + p.height &&
ballX > p.x && ballX < p.x + p.width) {
if (p.type === 'extra') lives++; else PADDLEWidth = Math.min(200, PADDLEWidth + 20);
powerUps.splice(i, 1);
ballY -= 10;
}
});
}
function update() {
if (!playing || gameOver) return;
ballX += ballVX; ballY += ballVY;
// wall bounce
if (ballX + radius > w || ballX - radius < 0) ballVX = -ballVX;
if (ballY - radius < 0) ballVY = Math.abs(ballVY);
// bottom miss
if (ballY - radius > h) {
lives--;
if (lives <= 0) { gameOver = true; alert('Game Over! Final Score: ' + score); }
else { resetBall(); }
}
collisionBallPaddle();
collisionBallBricks();
collisionPowerUpPaddle();
// level complete
const allBroken = bricks.every(row => row.every(b => b.status === 0));
if (allBroken) {
level++; score += 100;
initBricks();
ballVX = 4 * (level % 2 === 0 ? 1 : -1);
ballVY = -4;
}
// draw
ctx.clearRect(0, 0, w, h);
drawBricks();
drawBall();
drawPaddle();
drawScore();
drawLives();
drawPowerUps();
requestAnimationFrame(update);
}
function resetBall() {
ballX = w / 2; ballY = h / 2;
ballVX = 4; ballVY = -4;
}
// Input
document.addEventListener('keydown', e => {
if (e.key === 'ArrowLeft') movePaddle(-6);
if (e.key === 'ArrowRight') movePaddle(6);
if (e.key === ' ' && !playing) { playing = true; resetBall(); update(); }
});
document.addEventListener('keyup', e => {
if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') movePaddle(0);
});
document.addEventListener('mousemove', e => {
if (playing) paddleX = e.clientX - PADDLEWidth / 2;
});
// start menu
ctx.fillStyle = '#fff';
ctx.font = '30px Arial';
ctx.textAlign = 'center';
ctx.fillText('Breakout', w / 2, h / 2 - 20);
ctx.font = '20px Arial';
ctx.fillText('Arrow keys or Move mouse to play', w / 2, h / 2 + 20);
initBricks();
})();
</script>
</body>
</html>

