hypeorcode
Network offOpen alone (new tab)

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)

Raw files: output · meta.json

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>

Compare with

Nemotron 3.5 Lightning: other attempts