Hamburger breakoutOne-line
GPT-5 Nano
by OpenAIReasoningClean
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!