hypeorcode
Network offOpen alone (new tab)

Run details

Model
nvidia/nemotron-3.5-super-vl:free
Route
OpenRouter API, one user message
Reasoning
provider default, 12,956 reasoning tokens
Limits
60 min · 131,072 output tokens
Date
21 Oct 2026
Time
1 min 43 s
Size
14 kB
Tokens
94 in, 18,258 out
List price
$0.009 ($0.15 in / $0.5 out per M)
Paid
$0 (free route)

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). Reply with the file in a single ```html code block.

Source

14 kB 540 lines Raw

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Juicy Breakout</title>
<style>
  * { box-sizing: border-box; }
  body {
    margin: 0;
    background: #050508;
    color: #fff;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    overflow: hidden;
    touch-action: none;
  }
  canvas {
    display: block;
    background: #000;
    box-shadow: 0 0 40px rgba(0,0,0,0.8);
    max-width: 95vw;
    max-height: 90vh;
    cursor: none;
  }
  #hud {
    position: absolute;
    top: 10px;
    left: 0;
    right: 0;
    display: flex;
    justify-content: space-between;
    padding: 0 20px;
    font-size: 18px;
    font-weight: bold;
    text-transform: uppercase;
    letter-spacing: 2px;
    pointer-events: none;
    z-index: 5;
    text-shadow: 0 0 8px rgba(0,0,0,0.8);
  }
  .overlay {
    position: absolute;
    inset: 0;
    background: rgba(5, 5, 8, 0.9);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    z-index: 50;
    text-align: center;
    padding: 20px;
  }
  .hidden { display: none !important; }
  h1 { margin: 0 0 10px; font-size: 48px; text-shadow: 0 0 20px #ff0055; }
  p { margin-bottom: 25px; opacity: 0.9; line-height: 1.5; }
  button {
    background: #ff0055;
    border: none;
    color: #fff;
    padding: 12px 32px;
    font-size: 18px;
    font-weight: bold;
    border-radius: 6px;
    cursor: pointer;
    box-shadow: 0 0 20px rgba(255,0,85,0.5);
    transition: transform 0.1s;
  }
  button:active { transform: scale(0.95); }
  button:hover { background: #ff3377; }
</style>
</head>
<body>

<div id="hud">
  <span>SCORE: <span id="score">0</span></span>
  <span>LEVEL: <span id="level">1</span></span>
  <span>LIVES: <span id="lives">3</span></span>
</div>

<canvas id="game" width="800" height="600"></canvas>

<div id="overlay-menu" class="overlay">
  <h1>JUICY BREAKOUT</h1>
  <p>Arrows / A-D : Move &nbsp;•&nbsp; Space / Click : Launch<br>Mouse also controls paddle</p>
  <button onclick="startGame()">Start Game</button>
</div>

<div id="overlay-level" class="overlay hidden">
  <h1>Level Cleared!</h1>
  <button onclick="nextLevel()">Next Level</button>
</div>

<div id="overlay-gameover" class="overlay hidden">
  <h1 id="go-title">Game Over</h1>
  <button onclick="restartGame()">Try Again</button>
</div>

<script>
/* ========== GAME CODE ========== */
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');

const scoreEl = document.getElementById('score');
const levelEl = document.getElementById('level');
const livesEl = document.getElementById('lives');
const overlayMenu = document.getElementById('overlay-menu');
const overlayLevel = document.getElementById('overlay-level');
const overlayGameOver = document.getElementById('overlay-gameover');
const goTitle = document.getElementById('go-title');

// --- Config ---
const PADDLE_W = 100;
const PADDLE_H = 14;
const BALL_R = 7;
const BRICK_PAD = 6;

// --- State ---
let state = 'MENU'; // MENU | PLAYING | LEVEL_COMPLETE | GAME_OVER
let score = 0;
let lives = 3;
let levelIndex = 0;
let shake = 0;

let audioCtx = null;
const keys = {};
let mouseX = canvas.width / 2;

const paddle = { x: 350, y: canvas.height - 40, w: PADDLE_W, h: PADDLE_H };
const ball = { x: 0, y: 0, r: BALL_R, vx: 0, vy: 0, speed: 4, launched: false };
const bricks = [];
const particles = [];

// --- Levels ---
const LEVELS = [
  {
    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,1,1,1,1,1,1],
      [1,1,1,1,1,1,1,1,1,1]
    ],
    colors: ['#ff4444', '#ff8800', '#ffdd00', '#00ff88']
  },
  {
    grid: [
      [1,1,1,1,1,1,1,1,1,1],
      [1,0,0,0,0,0,0,0,0,1],
      [1,0,1,1,1,1,1,1,0,1],
      [1,0,0,0,0,0,0,0,0,1],
      [1,1,1,1,1,1,1,1,1,1]
    ],
    colors: ['#ff4444', '#ff8800', '#ffdd00', '#00ff88', '#4444ff']
  },
  {
    grid: [
      [0,0,0,0,1,1,0,0,0,0],
      [0,0,0,1,1,1,1,0,0,0],
      [0,0,1,1,1,1,1,1,0,0],
      [0,1,1,1,1,1,1,1,1,0],
      [1,1,1,1,1,1,1,1,1,1]
    ],
    colors: ['#ff4444', '#ff8800', '#ffdd00', '#00ff88', '#4444ff']
  },
  {
    grid: [
      [1,0,1,0,1,0,1,0,1,0],
      [0,1,0,1,0,1,0,1,0,1],
      [1,0,1,0,1,0,1,0,1,0],
      [0,1,0,1,0,1,0,1,0,1],
      [1,0,1,0,1,0,1,0,1,0]
    ],
    colors: ['#ff4444', '#ff8800', '#ffdd00', '#00ff88', '#4444ff']
  },
  {
    grid: [
      [1,1,1,1,1,1,1,1,1,1],
      [1,1,1,1,1,1,1,1,1,1],
      [1,0,0,1,1,1,1,0,0,1],
      [1,1,1,1,1,1,1,1,1,1],
      [1,1,1,1,1,1,1,1,1,1]
    ],
    colors: ['#ff4444', '#ff8800', '#ffdd00', '#00ff88', '#4444ff']
  }
];

// --- Audio ---
function initAudio() {
  if (!audioCtx) {
    const Ctx = window.AudioContext || window.webkitAudioContext;
    if (Ctx) audioCtx = new Ctx();
  }
}
function playTone(freq, type = 'square', duration = 0.1, vol = 0.1) {
  if (!audioCtx) return;
  const t = audioCtx.currentTime;
  const o = audioCtx.createOscillator();
  const g = audioCtx.createGain();
  o.type = type;
  o.frequency.setValueAtTime(freq, t);
  g.gain.setValueAtTime(vol, t);
  g.gain.exponentialRampToValueAtTime(0.001, t + duration);
  o.connect(g);
  g.connect(audioCtx.destination);
  o.start(t);
  o.stop(t + duration);
}

// --- Helpers ---
function clamp(v, min, max) { return Math.max(min, Math.min(max, v)); }
function getMouseX(e) {
  const rect = canvas.getBoundingClientRect();
  const scaleX = canvas.width / rect.width;
  return (e.clientX - rect.left) * scaleX;
}
function updateHUD() {
  scoreEl.textContent = score;
  levelEl.textContent = levelIndex + 1;
  livesEl.textContent = lives;
}

// --- Level loading ---
function loadLevel(idx) {
  bricks.length = 0;
  const lvl = LEVELS[idx % LEVELS.length];
  const rows = lvl.grid.length;
  const cols = lvl.grid[0].length;
  const bw = 60, bh = 20;
  const totalW = cols * bw + (cols - 1) * BRICK_PAD;
  const startX = (canvas.width - totalW) / 2;
  const startY = 50;
  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      if (lvl.grid[r][c]) {
        bricks.push({
          x: startX + c * (bw + BRICK_PAD),
          y: startY + r * (bh + BRICK_PAD),
          w: bw,
          h: bh,
          color: lvl.colors[r % lvl.colors.length],
          alive: true
        });
      }
    }
  }
  resetBall();
}

function resetBall() {
  ball.x = paddle.x + paddle.w / 2;
  ball.y = paddle.y - ball.r - 2;
  ball.vx = 0;
  ball.vy = 0;
  ball.launched = false;
}

function launchBall() {
  if (ball.launched) return;
  const baseSpeed = 4 + levelIndex * 0.4;
  const dir = Math.random() < 0.5 ? -1 : 1;
  ball.vx = dir * 3;
  ball.vy = -baseSpeed;
  ball.launched = true;
}

function spawnParticles(x, y, color, count) {
  for (let i = 0; i < count; i++) {
    particles.push({
      x, y,
      vx: (Math.random() - 0.5) * 12,
      vy: (Math.random() - 0.5) * 12,
      life: 1.0,
      color,
      size: Math.random() * 4 + 2
    });
  }
}

// --- Input ---
window.addEventListener('keydown', e => {
  keys[e.key] = true;
  if (['ArrowLeft','ArrowRight',' '].includes(e.key)) e.preventDefault();
  if (e.key === ' ' && state === 'PLAYING' && !ball.launched) launchBall();
  if ((e.key === ' ' || e.key === 'Enter') && state === 'MENU') startGame();
  if ((e.key === ' ' || e.key === 'Enter') && state === 'LEVEL_COMPLETE') nextLevel();
  if ((e.key === ' ' || e.key === 'Enter') && state === 'GAME_OVER') restartGame();
});
window.addEventListener('keyup', e => { keys[e.key] = false; });

window.addEventListener('mousemove', e => { mouseX = getMouseX(e); });
window.addEventListener('mousedown', e => {
  if (state === 'MENU') { startGame(); return; }
  if (state === 'LEVEL_COMPLETE') { nextLevel(); return; }
  if (state === 'GAME_OVER') { restartGame(); return; }
  if (state === 'PLAYING' && !ball.launched) launchBall();
});

// --- Game logic ---
function update() {
  initAudio();

  if (state === 'PLAYING') {
    // Paddle
    let ax = 0;
    if (keys['ArrowLeft'] || keys['a'] || keys['A']) ax = -8;
    if (keys['ArrowRight'] || keys['d'] || keys['D']) ax = 8;

    if (ax !== 0) {
      paddle.x += ax;
    } else {
      paddle.x = mouseX - paddle.w / 2;
    }
    paddle.x = clamp(paddle.x, 0, canvas.width - paddle.w);

    if (!ball.launched) {
      ball.x = paddle.x + paddle.w / 2;
      ball.y = paddle.y - ball.r - 2;
    } else {
      ball.x += ball.vx;
      ball.y += ball.vy;

      // Ball trail juice
      if (Math.random() < 0.6) {
        particles.push({
          x: ball.x, y: ball.y,
          vx: -ball.vx * 0.15, vy: -ball.vy * 0.15,
          life: 0.35, color: '#fff', size: Math.random() * 2 + 1
        });
      }

      // Walls
      if (ball.x - ball.r < 0) { ball.x = ball.r; ball.vx *= -1; playTone(80, 'square', 0.04, 0.05); shake = 4; }
      if (ball.x + ball.r > canvas.width) { ball.x = canvas.width - ball.r; ball.vx *= -1; playTone(80, 'square', 0.04, 0.05); shake = 4; }
      if (ball.y - ball.r < 0) { ball.y = ball.r; ball.vy *= -1; playTone(110, 'square', 0.04, 0.05); shake = 4; }

      // Paddle collision
      if (ball.vy > 0 &&
          ball.x >= paddle.x && ball.x <= paddle.x + paddle.w &&
          ball.y + ball.r >= paddle.y && ball.y - ball.r <= paddle.y + paddle.h) {
        const hitFactor = (ball.x - (paddle.x + paddle.w / 2)) / (paddle.w / 2);
        ball.vx = hitFactor * 7;
        ball.vy = -Math.abs(ball.vy);
        const spd = Math.hypot(ball.vx, ball.vy) * 1.03;
        const ang = Math.atan2(ball.vy, ball.vx);
        ball.vx = Math.cos(ang) * spd;
        ball.vy = Math.sin(ang) * spd;
        playTone(180, 'sine', 0.1, 0.1);
        shake = 6;
      }

      // Bricks
      for (let b of bricks) {
        if (!b.alive) continue;
        const cx = clamp(ball.x, b.x, b.x + b.w);
        const cy = clamp(ball.y, b.y, b.y + b.h);
        const dx = ball.x - cx;
        const dy = ball.y - cy;
        if (dx * dx + dy * dy < ball.r * ball.r) {
          b.alive = false;
          score += 10;
          updateHUD();
          spawnParticles(b.x + b.w / 2, b.y + b.h / 2, b.color, 10);
          playTone(300 + Math.random() * 400, 'square', 0.08, 0.1);
          shake = 10;

          const overlapX = ball.r - Math.abs(dx);
          const overlapY = ball.r - Math.abs(dy);
          if (overlapX < overlapY) {
            ball.vx *= -1;
            ball.x += dx > 0 ? overlapX : -overlapX;
          } else {
            ball.vy *= -1;
            ball.y += dy > 0 ? overlapY : -overlapY;
          }
          break; // one brick per frame
        }
      }

      // Death
      if (ball.y - ball.r > canvas.height) {
        lives--;
        updateHUD();
        playTone(60, 'sawtooth', 0.4, 0.1);
        shake = 25;
        if (lives <= 0) {
          state = 'GAME_OVER';
          goTitle.textContent = 'GAME OVER';
          overlayGameOver.classList.remove('hidden');
        } else {
          resetBall();
        }
      }
    }

    // Level clear
    if (bricks.every(b => !b.alive)) {
      state = 'LEVEL_COMPLETE';
      overlayLevel.classList.remove('hidden');
      playTone(500, 'square', 0.1, 0.1);
      setTimeout(() => playTone(620, 'square', 0.1, 0.1), 120);
      setTimeout(() => playTone(800, 'square', 0.25, 0.1), 240);
    }
  }

  // Particles
  for (let i = particles.length - 1; i >= 0; i--) {
    const p = particles[i];
    p.x += p.vx;
    p.y += p.vy;
    p.vx *= 0.94;
    p.vy *= 0.94;
    p.life -= 0.05;
    if (p.life <= 0) particles.splice(i, 1);
  }

  if (shake > 0) shake *= 0.92;
  else shake = 0;
}

// --- Draw ---
function draw() {
  const sx = shake > 0 ? (Math.random() - 0.5) * shake : 0;
  const sy = shake > 0 ? (Math.random() - 0.5) * shake : 0;

  ctx.save();
  ctx.translate(sx, sy);

  // background
  ctx.fillStyle = '#050508';
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  // faint grid
  ctx.strokeStyle = '#111';
  ctx.lineWidth = 1;
  for (let x = 0; x < canvas.width; x += 40) {
    ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, canvas.height); ctx.stroke();
  }
  for (let y = 0; y < canvas.height; y += 40) {
    ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(canvas.width, y); ctx.stroke();
  }

  // bricks
  for (const b of bricks) {
    if (!b.alive) continue;
    const g = ctx.createLinearGradient(b.x, b.y, b.x, b.y + b.h);
    g.addColorStop(0, b.color);
    g.addColorStop(1, '#000');
    ctx.fillStyle = g;
    ctx.fillRect(b.x, b.y, b.w, b.h);
    ctx.strokeStyle = 'rgba(255,255,255,0.4)';
    ctx.lineWidth = 2;
    ctx.strokeRect(b.x + 1.5, b.y + 1.5, b.w - 3, b.h - 3);
  }

  // paddle
  const pg = ctx.createLinearGradient(paddle.x, paddle.y, paddle.x, paddle.y + paddle.h);
  pg.addColorStop(0, '#ffffff');
  pg.addColorStop(1, '#aaaaaa');
  ctx.fillStyle = pg;
  ctx.fillRect(paddle.x, paddle.y, paddle.w, paddle.h);
  ctx.strokeStyle = '#fff';
  ctx.lineWidth = 2;
  ctx.strokeRect(paddle.x, paddle.y, paddle.w, paddle.h);

  // ball
  const glow = 10;
  const ballGrad = ctx.createRadialGradient(ball.x, ball.y, 0, ball.x, ball.y, ball.r + glow);
  ballGrad.addColorStop(0, '#fff');
  ballGrad.addColorStop(1, 'rgba(255,255,255,0)');
  ctx.fillStyle = ballGrad;
  ctx.beginPath();
  ctx.arc(ball.x, ball.y, ball.r + glow, 0, Math.PI * 2);
  ctx.fill();
  ctx.fillStyle = '#fff';
  ctx.beginPath();
  ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2);
  ctx.fill();

  // particles
  for (const p of particles) {
    ctx.globalAlpha = p.life;
    ctx.fillStyle = p.color;
    ctx.fillRect(p.x - p.size / 2, p.y - p.size / 2, p.size, p.size);
    ctx.globalAlpha = 1;
  }

  ctx.restore();
}

// --- Loop ---
function loop() {
  update();
  draw();
  requestAnimationFrame(loop);
}

// --- Public functions for buttons ---
function startGame() {
  initAudio();
  state = 'PLAYING';
  score = 0;
  lives = 3;
  levelIndex = 0;
  scoreEl.textContent = '0';
  livesEl.textContent = '3';
  levelEl.textContent = '1';
  overlayMenu.classList.add('hidden');
  overlayLevel.classList.add('hidden');
  overlayGameOver.classList.add('hidden');
  loadLevel(0);
}

function nextLevel() {
  overlayLevel.classList.add('hidden');
  levelIndex++;
  if (levelIndex >= LEVELS.length) {
    state = 'GAME_OVER';
    goTitle.textContent = 'YOU WIN!';
    overlayGameOver.classList.remove('hidden');
  } else {
    state = 'PLAYING';
    levelEl.textContent = levelIndex + 1;
    loadLevel(levelIndex);
  }
}

function restartGame() {
  overlayGameOver.classList.add('hidden');
  startGame();
}

// Start
loop();
</script>
</body>
</html>

Compare with

Nemotron 3.5 Super VL: other attempts