Models 44

GPT-5 Nano

by OpenAIReasoningClean
Open in new window

Running live in a sandboxed frame. Click inside it before using the keyboard.

How it went

Total time
26.1 s
Cost
$0.0015
Output tokens
3,819
Spent thinking
192 tokens
Speed
165.3 tok/s
Console errors
0
First token after
3.0 s
First visible text after
4.1 s
Prompt tokens
357
Code size
10.8 KB
Finish reason
stop
Served by
OpenAI
Model id
openai/gpt-5-nano
Reasoning sent
{"effort":"low"}
Max output
128,000 tokens
Generated
Nov 12, 2026

What it was asked

The prompt
“i want a breakout game where the paddle is a hamburger and every brick you break explodes into tons of little hearts”
System prompt, sent with every prompt
You are generating a self-contained web demo. It will be rendered automatically in a sandboxed iframe and compared side by side with the output of other AI models given the exact same task.

Output rules:
- Reply with exactly ONE fenced code block containing the complete file: ```html (or ```svg when the task asks for an SVG). No text before or after the code block.
- Everything must be inline: CSS in <style>, JavaScript in <script>. No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task.
- Do not use localStorage, sessionStorage, cookies, IndexedDB, alert(), confirm(), prompt() or window.open(): they are blocked in the sandbox and will throw.
- The page must look right in a 1280×800 viewport and adapt gracefully down to 375px wide. No horizontal scrollbar.
- Something meaningful must be visible on first paint: a screenshot is taken automatically about 3 seconds after load, without any interaction.
- Everything that makes the demo interesting must be visible within the first seconds: nothing hidden behind a high score, a later level or a long play session.
- Games must start in a self-playing demo mode (a simple AI plays) behind a "Click or press a key to start" message, so the game can be judged in action without playing.
- The iframe only receives keyboard events after the user clicks it: if the demo uses the keyboard, display a clear "Click or press a key to start" message.
- The code must run with zero errors in the console of the latest Chrome.

Code run-1.html · 430 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Hamburger Breakout</title>
<style>
  :root {
    --bg: #11131a;
    --panel: #1e1f2a;
    --hot: #e74c3c;
    --p: #ffd27a;
    --heart: #ff6b88;
  }
  html, body {
    height: 100%;
    margin: 0;
    background: linear-gradient(#0b0f14, #141921 60%, #0b0f14);
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial;
    color: #e8e8e8;
    overflow: hidden;
  }
  .wrap {
    width: 100vw;
    height: 100vh;
    display: grid;
    place-items: center;
    padding: 16px;
    box-sizing: border-box;
  }
  canvas {
    display: block;
    width: min(1100px, 95vw);
    height: auto;
    max-height: 78vh;
    background: radial-gradient(circle at 60% -20%, rgba(255,255,255,0.04), transparent 40%), #0a0f14;
    border-radius: 14px;
    box-shadow: 0 8px 40px rgba(0,0,0,.5);
  }
  .overlay {
    position: absolute;
    top: 0; left: 0;
    width: 100%; height: 100%;
    display: grid;
    place-items: center;
    pointer-events: none;
  }
  .panel {
    background: rgba(20,20,28,.92);
    border: 1px solid rgba(200,200,240,.25);
    border-radius: 12px;
    padding: 18px 22px;
    text-align: center;
    max-width: 420px;
    color: #f3f3f3;
    box-shadow: 0 6px 30px rgba(0,0,0,.4);
    pointer-events: auto;
    user-select: none;
  }
  .panel h1 {
    margin: 0 0 6px;
    font-size: 20px;
  }
  .panel p {
    margin: 6px 0 14px;
    font-size: 13px;
    color: #d9d9d9;
  }
  .startBtn {
    display: inline-block;
    padding: 10px 16px;
    border-radius: 8px;
    border: none;
    background: linear-gradient(#ff8c00, #e44);
    color: white;
    font-weight: bold;
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(0,0,0,.25);
  }
  .startBtn:active {
    transform: translateY(1px);
  }
  @media (max-width: 700px) {
    .panel { width: 92vw; }
  }
</style>
</head>
<body>
<div class="wrap" aria-label="Hamburger Breakout game canvas">
  <canvas id="game" width="1050" height="600"></canvas>
  <div class="overlay" id="overlay" aria-label="Start overlay">
    <div class="panel" id="panel">
      <h1>Hamburger Breakout</h1>
      <p>Control the paddle by AI. Bricks explode into hearts when destroyed. Click or press any key to start.</p>
      <button class="startBtn" id="startBtn" aria-label="Start game">Start</button>
      <p style="margin-top:8px; font-size:12px; color:#cfcfcf;">Tip: The paddle is a hamburger. Hearts are particles from bricks.</p>
    </div>
  </div>
</div>

<script>
(function(){
  const canvas = document.getElementById('game');
  const ctx = canvas.getContext('2d');
  const overlay = document.getElementById('overlay');
  const panel = document.getElementById('panel');
  const startBtn = document.getElementById('startBtn');

  const W = canvas.width;
  const H = canvas.height;

  // Game state
  let running = false; // whether the main loop runs
  let started = false; // user started
  // Scene objects
  const bricks = [];
  const particles = [];
  let paddle;
  let ball;

  // AI controller (simple follower with some lag)
  function aiControl() {
    // If ball is moving, try to align paddle with ball.x with some smoothing
    const targetX = ball.x;
    const dx = targetX - paddle.x;
    paddle.vx = dx * 0.08; // proportional control
  }

  // Init
  function init() {
    bricks.length = 0;
    particles.length = 0;

    // Paddle (hamburger)
    paddle = {
      w: 120,
      h: 22,
      x: W * 0.5,
      y: H - 40,
      vx: 0,
      speed: 8 // not used directly; AI uses smoothing
    };

    // Ball
    ball = {
      x: W * 0.5,
      y: H - 60,
      r: 6,
      vx: 4,
      vy: -6
    };

    // Create brick grid
    const rows = 6;
    const cols = 12;
    const brickW = Math.min(78, (W - 80) / cols);
    const brickH = 22;
    const offsetX = (W - (brickW * cols)) / 2;
    const offsetY = 60;
    for (let r = 0; r < rows; r++) {
      for (let c = 0; c < cols; c++) {
        const brickX = offsetX + c * brickW;
        const brickY = offsetY + r * (brickH + 8);
        bricks.push({
          x: brickX,
          y: brickY,
          w: brickW - 6,
          h: brickH,
          alive: true,
          color: `hsl(${(r * 40) % 360}, 85%, 60%)`
        });
      }
    }

    // Reset ball slightly above paddle
    ball.x = paddle.x;
    ball.y = paddle.y - 10;
    ball.vx = 4;
    ball.vy = -6;
  }

  // Helpers
  function rectsOverlap(a, b) {
    return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;
  }

  function circleRectBounce(ball, rect) {
    // Simple AABB collision resolution for ball and brick/paddle
    // Compute nearest point on rect to ball center
    const cx = Math.max(rect.x, Math.min(ball.x, rect.x + rect.w));
    const cy = Math.max(rect.y, Math.min(ball.y, rect.y + rect.h));
    const dx = ball.x - cx;
    const dy = ball.y - cy;
    const dist = Math.sqrt(dx*dx + dy*dy);
    if (dist < ball.r + 0.1) {
      // reflect ball
      // decide axis by which side closest
      const overlapX = (ball.r + rect.w/2) - Math.abs(ball.x - (rect.x + rect.w/2));
      const overlapY = (ball.r + rect.h/2) - Math.abs(ball.y - (rect.y + rect.h/2));
      if (overlapX < overlapY) {
        ball.vx = -ball.vx;
        // push out
        if (ball.x < rect.x) ball.x = rect.x - ball.r;
        else ball.x = rect.x + rect.w + ball.r;
      } else {
        ball.vy = -ball.vy;
        if (ball.y < rect.y) ball.y = rect.y - ball.r;
        else ball.y = rect.y + rect.h + ball.r;
      }
      return true;
    }
    return false;
  }

  // Explosion into hearts
  function spawnHeartBurst(x, y, count) {
    for (let i = 0; i < count; i++) {
      const angle = Math.random() * Math.PI * 2;
      const speed = 1.5 + Math.random() * 2.5;
      particles.push({
        x, y,
        vx: Math.cos(angle) * speed,
        vy: Math.sin(angle) * speed,
        life: 60 + Math.random() * 40,
        color: '#ff4d6d',
        size: 3 + Math.random() * 3
      });
    }
  }

  // Draw hamburger paddle
  function drawPaddle(p) {
    // Hamburger body
    const x = p.x - p.w/2;
    const y = p.y - p.h/2;
    ctx.save();
    // bun top
    ctx.fillStyle = '#e9a34a';
    ctx.strokeStyle = '#b57a2b';
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.roundRect(x+8, y, p.w-16, p.h, 6);
    ctx.fill();
    ctx.stroke();

    // lettuce (green strip)
    ctx.fillStyle = '#3bb34a';
    ctx.fillRect(x+8, y+4, p.w-16, 4);

    // patty
    ctx.fillStyle = '#4b2d15';
    ctx.fillRect(x+12, y+8, p.w-24, 4);

    // bun bottom
    ctx.fillStyle = '#e07a2a';
    ctx.fillRect(x+8, y+12, p.w-16, 8);

    // sesame seeds
    ctx.fillStyle = '#f6e8a6';
    for (let s = 0; s < 6; s++) {
      const sx = x + 16 + s* (p.w-32) / 5;
      ctx.fillRect(sx, y + 3, 2, 2);
    }
    ctx.restore();
  }

  // Heart drawing for particles
  function drawHeart(px, py, s, color) {
    ctx.save();
    ctx.translate(px, py);
    ctx.scale(s, s);
    ctx.fillStyle = color;
    ctx.beginPath();
    // simple heart path
    ctx.moveTo(0, 0);
    ctx.arc(-6, -2, 6, Math.PI, 0, false);
    ctx.arc(6, -2, 6, Math.PI, 0, false);
    ctx.lineTo(0, 14);
    ctx.closePath();
    ctx.fill();
    ctx.restore();
  }

  // Update and render
  let last = performance.now();
  function loop(now) {
    const dt = Math.min(0.033, (now - last) / 1000);
    last = now;

    // AI and physics only when running
    if (running) {
      aiControl();

      // Move paddle
      paddle.x += paddle.vx * dt * 60;
      // clamp
      const half = paddle.w / 2;
      if (paddle.x - half < 0) paddle.x = half;
      if (paddle.x + half > W) paddle.x = W - half;

      // Move ball
      ball.x += ball.vx;
      ball.y += ball.vy;

      // Wall collisions
      if (ball.x - ball.r < 0) { ball.x = ball.r; ball.vx = -ball.vx; }
      if (ball.x + ball.r > W) { ball.x = W - ball.r; ball.vx = -ball.vx; }
      if (ball.y - ball.r < 0) { ball.y = ball.r; ball.vy = -ball.vy; }

      // Paddle collision
      const paddleRect = { x: paddle.x - paddle.w/2, y: paddle.y - paddle.h/2, w: paddle.w, h: paddle.h };
      circleRectBounce(ball, paddleRect);

      // Brick collisions
      for (let i = bricks.length - 1; i >= 0; i--) {
        const b = bricks[i];
        if (!b.alive) continue;
        const rb = { x: b.x, y: b.y, w: b.w, h: b.h };
        if (circleRectBounce(ball, rb)) {
          b.alive = false;
          spawnHeartBurst(b.x + b.w/2, b.y + b.h/2, 12);
          // minor ball speed tweak
          ball.vx *= 1.02;
          ball.vy *= 1.02;
        }
      }

      // Lose condition (ball out)
      if (ball.y - ball.r > H) {
        // reset to give a second chance
        ball.x = paddle.x;
        ball.y = paddle.y - 10;
        ball.vx = (Math.random() > 0.5 ? 4 : -4);
        ball.vy = -6;
      }
    }

    // Update particles
    for (let i = particles.length - 1; i >= 0; i--) {
      const p = particles[i];
      p.x += p.vx;
      p.y += p.vy;
      p.vy += 0.02; // gravity-ish
      p.life -= 1;
      if (p.life <= 0) particles.splice(i, 1);
    }

    // draw
    ctx.clearRect(0, 0, W, H);

    // bricks
    for (const b of bricks) {
      if (!b.alive) continue;
      ctx.fillStyle = b.color;
      ctx.fillRect(b.x, b.y, b.w, b.h);
      // subtle inner shading
      ctx.fillStyle = 'rgba(0,0,0,.15)';
      ctx.fillRect(b.x+2, b.y+2, b.w-4, b.h-4);
    }

    // paddle
    drawPaddle(paddle);

    // ball
    ctx.fillStyle = '#f5f5f5';
    ctx.beginPath();
    ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2);
    ctx.fill();

    // hearts particles
    for (const p of particles) {
      drawHeart(p.x, p.y, 0.8, p.color);
    }

    // overlay if not started
    if (!started) {
      // Dim overlay
      ctx.fillStyle = 'rgba(0,0,0,0.25)';
      ctx.fillRect(0,0,W,H);
    }

    // End condition: all bricks destroyed
    const anyAlive = bricks.some(br => br.alive);
    if (!anyAlive) {
      // simple win: pause
      running = false;
      ctx.fillStyle = 'rgba(0,0,0,.5)';
      ctx.fillRect(0,0,W,H);
      ctx.fillStyle = '#fff';
      ctx.font = '26px sans-serif';
      ctx.textAlign = 'center';
      ctx.fillText('You cleared all the bricks! 🎉', W/2, H/2);
    }

    requestAnimationFrame(loop);
  }

  // Start flow
  function startGame() {
    if (started) return;
    started = true;
    overlay.style.display = 'none';
    init();
    // small delay before running
    setTimeout(() => { running = true; }, 100);
  }

  // Prepare
  function resize() {
    // keep canvas aspect but our canvas has fixed size; adjust CSS if needed
  }

  // Event hooks
  startBtn.addEventListener('click', startGame);
  // allow keyboard after click
  window.addEventListener('keydown', (e) => {
    if (!started) startGame();
  }, { once: false });

  // Kick off
  init();
  // Show first frame quickly
  requestAnimationFrame(loop);

  // Make sure the overlay sits on top and blocks input until start
  overlay.style.display = 'grid';
})();
</script>
</body>
</html>
Reasoning trace (192 tokens)
**Crafting animated visuals**

I’m thinking about using a requestAnimationFrame loop for smooth animations. Maybe I can use an off-screen pre-drawn hamburger paddle? I plan to create the paddle using rectangles and circles to represent it effectively. It’s important to implement this correctly, ensuring there are no scrollbars. I’ll also need to provide the right CSS to make sure the canvas is centered. Let's get started on this fun project!