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
- 30.3 s
- Cost
- $0.0018
- Output tokens
- 4,473
- Spent thinking
- 0 tokens
- Speed
- 152.1 tok/s
- Console errors
- 0
- First token after
- 903 ms
- First visible text after
- 903 ms
- Prompt tokens
- 357
- Code size
- 13.5 KB
- Finish reason
- stop
- Served by
- OpenAI
- Model id
openai/gpt-5-nano- Reasoning sent
{"effort":"minimal"}- 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 · 491 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Hamburger Breakout — Hearts Explosion</title>
<style>
:root{
--bg:#101018;
--panel:#1e1a24;
--hamburger:#d35400;
--bun:#f2a043;
--lettuce:#2ecc71;
--tomato:#e74c3c;
--cheese:#f1c40f;
--heart:#ff5a7a;
--brick:#e74c3c;
--brick2:#c0392b;
--shadow: rgba(0,0,0,.35);
}
html,body{height:100%;margin:0;padding:0;background: radial-gradient(circle at 20% 0%, #1a1020 0%, #0b0b14 40%, #0b0b14 100%), #0b0b14; font-family: Inter, system-ui, -apple-system, Segoe UI, Roboto, Arial; color:#fff; overflow:hidden;}
.wrap{display:flex;align-items:center;justify-content:center;height:100vh;}\n
canvas{display:block;background: linear-gradient(#0b0b14, #0a0a12); box-shadow:0 10px 40px var(--shadow); border-radius:14px; width: min(1100px, 92vw); height:auto;}
/* Overlay message */
.overlay{
position: absolute; top:0; left:0; right:0; bottom:0;
display:flex; align-items:center; justify-content:center;
pointer-events:none;
}
.panel{
background: rgba(0,0,0,.55);
border:1px solid rgba(255,255,255,.15);
padding: 22px 28px;
border-radius:12px;
text-align:center;
max-width: 90vw;
backdrop-filter: blur(3px);
}
h1{margin:0 0 8px;font-size:22px;letter-spacing:.4px}
p{margin:0 0 8px;opacity:.9}
.startBtn{
display:inline-block;margin-top:6px;padding:10px 14px;
background:#fff0; color:#fff; border:1px solid #fff; border-radius:999px;
padding-left:18px;padding-right:18px; cursor:pointer;
transition: all .2s ease;
}
.startBtn:hover{background:#fff; color:#111}
/* HUD */
.hud{ position:absolute; left:12px; top:12px; display:flex; gap:12px; align-items:center; font-family:monospace; font-size:14px; }
.hud .chip{ background:rgba(0,0,0,.4); border:1px solid rgba(255,255,255,.15); padding:6px 10px; border-radius:999px; }
.heartIcon{ color: #ff6b9a; filter: drop-shadow(0 0 2px rgba(255,90,122,.8)); }
@media (max-width: 720px){
.panel{font-size:14px; padding:18px}
}
</style>
</head>
<body>
<div class="wrap">
<canvas id="gameCanvas" width="1120" height="640" tabindex="0"></canvas>
<div class="overlay" id="overlay">
<div class="panel" aria-label="Start screen">
<h1>Hamburger Breakout</h1>
<p>Controls: Move with mouse or touch. The hamburger is the paddle. Break bricks to reveal exploding hearts!</p>
<p>Click or press any key to start</p>
<button class="startBtn" id="startBtn" aria-label="Start game">Click or press a key to start</button>
</div>
</div>
<div class="hud" aria-label="Score and lives">
<div class="chip" id="scoreBox">Score: 0</div>
<div class="chip" id="levelBox">Level: 1</div>
<div class="chip" id="livesBox">Lives: 3</div>
</div>
</div>
<script>
(() => {
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const overlay = document.getElementById('overlay');
const startBtn = document.getElementById('startBtn');
const scoreBox = document.getElementById('scoreBox');
const levelBox = document.getElementById('levelBox');
const livesBox = document.getElementById('livesBox');
// Game state
let w = canvas.width, h = canvas.height;
let running = false; // auto-play mode true after start
let started = false;
let keys = {};
let score = 0;
let level = 1;
let lives = 3;
// Paddle shaped as a hamburger
const paddle = {
width: 110,
height: 28,
x: (w - 110) / 2,
y: h - 60,
speed: 8,
// components for drawing the hamburger
draw(p){
// bun top
p.fillRect(p.x, p.y, p.width, 10, '#f2a043');
}
};
// We'll implement drawing with helper
function drawHamburger(x,y,wid,h) {
// bun top
ctx.fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--bun') || '#f2a043';
ctx.strokeStyle = 'rgba(0,0,0,.2)';
// Bun top
ctx.beginPath();
ctx.moveTo(x, y);
ctx.quadraticCurveTo(x + wid*0.5, y - h*0.5, x + wid, y);
ctx.lineTo(x + wid, y + 10);
ctx.quadraticCurveTo(x + wid*0.5, y + h*0.6, x, y + 10);
ctx.closePath();
ctx.fill();
// Filling
ctx.fillStyle = '#e74c3c';
ctx.fillRect(x, y + 10, wid, h * 0.55);
// Lettuce
ctx.fillStyle = '#2ecc71';
ctx.fillRect(x, y + 20, wid, h * 0.25);
// Cheese
ctx.fillStyle = '#f1c40f';
ctx.fillRect(x, y + h * 0.5, wid, 6);
// Bun bottom
ctx.fillStyle = '#d35400';
ctx.beginPath();
ctx.moveTo(x, y + h);
ctx.quadraticCurveTo(x + wid*0.5, y + h + h*0.25, x + wid, y + h);
ctx.lineTo(x + wid, y + h + 6);
ctx.quadraticCurveTo(x + wid*0.5, y + h - h*0.15, x, y + h + 6);
ctx.closePath();
ctx.fill();
}
// We'll implement bricks
const bricks = [];
const brickRows = 6;
const brickCols = 10;
const brickW = (w - 80) / brickCols;
const brickH = 22;
const heartPieces = []; // particles after brick break
function initBricks() {
bricks.length = 0;
const offsetX = 40;
const offsetY = 60;
for(let r=0;r<brickRows;r++){
for(let c=0;c<brickCols;c++){
const hp = {
x: offsetX + c*brickW,
y: offsetY + r*(brickH+6),
w: brickW - 6,
h: brickH,
alive: true,
color: r%2===0 ? '#e74c3c' : '#c0392b'
};
bricks.push(hp);
}
}
}
// Ball
const ball = {
x: w/2,
y: h/2,
r: 8,
vx: 4,
vy: -4,
speed: 6
};
// Hearts particles
function spawnHearts(x,y,dirX,dirY){
const n = 12 + Math.floor(Math.random()*10);
for(let i=0;i<n;i++){
heartPieces.push({
x: x,
y: y,
vx: dirX*(0.5 + Math.random()*2),
vy: dirY*(0.5 + Math.random()*2) - Math.random()*2,
life: 60 + Math.floor(Math.random()*60),
r: 3 + Math.random()*3,
color: '#ff5a7a'
});
}
}
// 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;
}
// Basic circle-rect collision for ball with bricks
function circleRectCollision(bx,by,br,rx,ry,rw,rh){
// Find closest point to circle within the rectangle
const closestX = clamp(bx, rx, rx+rw);
const closestY = clamp(by, ry, ry+rh);
const dx = bx - closestX;
const dy = by - closestY;
return (dx*dx + dy*dy) < (br*br);
}
function clamp(v, a, b){ return Math.max(a, Math.min(b, v)); }
// Input
function resetPaddle(){
paddle.x = (w - 110) / 2;
}
// AI auto play: simple follower of ball with lag
function aiMove(){
// keep paddle near ball x
const targetX = ball.x - 55;
const dx = targetX - paddleX();
const step = 6;
if(Math.abs(dx) > step){
if(dx>0) paddle.v = Math.min(6, dx);
else paddle.v = Math.max(-6, dx);
} else {
paddle.v = 0;
}
}
function paddleX(){ return clamp(paddle.x,0,w-110); }
function updatePaddle(){
// in demo, AI controls movement
const targetX = ball.x - 55;
const dx = targetX - paddle.x;
const maxStep = 6;
if(Math.abs(dx) > maxStep){
paddle.x += dx>0 ? maxStep : -maxStep;
} else {
paddle.x += dx;
}
// bounds
if(paddle.x < 0) paddle.x = 0;
if(paddle.x + 110 > w) paddle.x = w - 110;
}
function drawPaddle(){
// draw hamburger using simple shapes layered
const x = paddle.x;
const y = paddle.y;
// bun top
ctx.fillStyle = '#f2a043';
ctx.beginPath();
ctx.moveTo(x, y);
ctx.quadraticCurveTo(x + 55, y - 14, x + 110, y);
ctx.lineTo(x + 110, y + 12);
ctx.quadraticCurveTo(x + 55, y + 20, x, y + 12);
ctx.closePath();
ctx.fill();
// Lettuce layer
ctx.fillStyle = '#2ecc71';
ctx.fillRect(x, y + 12, 110, 6);
// Patty
ctx.fillStyle = '#7f4a2b';
ctx.fillRect(x + 0, y + 18, 110, 6);
// Bun bottom
ctx.fillStyle = '#d35400';
ctx.beginPath();
ctx.moveTo(x, y + 24);
ctx.quadraticCurveTo(x + 55, y + 38, x + 110, y + 24);
ctx.lineTo(x + 110, y + 38);
ctx.quadraticCurveTo(x + 55, y + 50, x, y + 38);
ctx.closePath();
ctx.fill();
}
// Init
function init(){
w = canvas.width; h = canvas.height;
resetPaddle();
initBricks();
spawnAllHeartsReady();
ball.x = w/2; ball.y = h/2; ball.vx = 4; ball.vy = -4;
}
function spawnAllHeartsReady(){
// nothing pre-spawn; hearts spawn on brick break
}
// Start / restart
function startGame(){
overlay.style.display = 'none';
started = true;
running = true;
}
// Rendering loop
let lastT = 0;
function loop(ts){
if(!lastT) lastT = ts;
const dt = Math.min(50, ts - lastT);
lastT = ts;
update(dt);
render();
requestAnimationFrame(loop);
}
function update(dt){
// AI moves paddle
updatePaddle();
// Move ball
ball.x += ball.vx;
ball.y += ball.vy;
// Wall collisions
if(ball.x - ball.r < 0){ ball.x = ball.r; ball.vx *= -1; }
if(ball.x + ball.r > w){ ball.x = w - ball.r; ball.vx *= -1; }
if(ball.y - ball.r < 0){ ball.y = ball.r; ball.vy *= -1; }
if(ball.y - ball.r > h){
// life lost
lives--;
if(lives <= 0){
// restart
score = 0; level = 1; lives = 3;
init();
} else {
// reset ball
ball.x = w/2; ball.y = h/2; ball.vx = 4 * (Math.random() < 0.5 ? 1 : -1);
ball.vy = -4;
}
}
// Paddle collision (simple AABB)
const paddleRect = {x: paddle.x, y: paddle.y, w: 110, h: 20};
if(ball.y + ball.r >= paddleRect.y && ball.y - ball.r <= paddleRect.y + paddleRect.h &&
ball.x >= paddleRect.x && ball.x <= paddleRect.x + paddleRect.w){
ball.y = paddleRect.y - ball.r;
// reflect with some angle based on where hit
const relative = (ball.x - (paddleRect.x + paddleRect.w/2)) / (paddleRect.w/2);
const maxBounce = 1.1;
ball.vy = -Math.abs(ball.vy);
ball.vx = relative * maxBounce * 5;
}
// Bricks collisions
for(let i=0;i<bricks.length;i++){
const b = bricks[i];
if(!b.alive) continue;
if(circleRectCollision(ball.x, ball.y, ball.r, b.x, b.y, b.w, b.h)){
// Basic response: reflect y
ball.vy = -ball.vy;
b.alive = false;
// spawn hearts
spawnHearts(b.x + b.w/2, b.y + b.h/2, (Math.random()<0.5?-1:1), -1 - Math.random()*1.5);
score += 10;
// level complete check
if(bricks.every(br => !br.alive)){
level++;
levelBox.textContent = 'Level: ' + level;
// reset bricks and ball
initBricks();
ball.x = w/2; ball.y = h/2;
ball.vx = 4 * (Math.random()<0.5?1:-1);
ball.vy = -4;
}
break;
}
}
// Hearts particles update
for(let p of heartPieces){
p.x += p.vx;
p.y += p.vy;
p.vy += 0.15;
p.life--;
}
// remove dead
for(let i = heartPieces.length -1; i>=0; i--){
if(heartPieces[i].life <= 0) heartPieces.splice(i,1);
}
// Update HUD
scoreBox.textContent = 'Score: ' + score;
livesBox.textContent = 'Lives: ' + lives;
}
function render(){
// Clear
ctx.clearRect(0,0,w,h);
// Bricks
for(let b of bricks){
if(!b.alive) continue;
ctx.fillStyle = b.color;
ctx.fillRect(b.x, b.y, b.w, b.h);
// subtle border
ctx.strokeStyle = 'rgba(0,0,0,.25)';
ctx.lineWidth = 1;
ctx.strokeRect(b.x, b.y, b.w, b.h);
}
// Hearts pieces
for(let p of heartPieces){
// heart shape drawn as simple rotated square hearts
ctx.save();
ctx.translate(p.x, p.y);
ctx.rotate(Math.atan2(p.vy, p.vx));
ctx.fillStyle = p.color;
// heart path simplified
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.bezierCurveTo(-p.r, -p.r, -p.r*2, -p.r, -p.r, 0);
ctx.bezierCurveTo(-p.r, p.r, 0, p.r*1.5, 0, p.r*0.8);
ctx.bezierCurveTo(0, p.r*1.5, p.r, p.r, p.r, 0);
ctx.bezierCurveTo(p.r, -p.r, 0, -p.r, 0, 0);
ctx.closePath();
ctx.fill();
ctx.restore();
// fallbacks if heart path not visible, draw simple circle
}
// Paddle
drawPaddle();
// Ball
ctx.fillStyle = '#fff';
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI*2);
ctx.fill();
// Overlay show if not started
if(!started){
// Keep overlay visible
}
}
// Input handling
function onPointerMove(e){
// Move paddle with pointer for non-AI initial
if(!started) return;
const rect = canvas.getBoundingClientRect();
const px = (e.clientX ?? 0) - rect.left;
paddle.x = px - 55;
if(paddle.x < 0) paddle.x = 0;
if(paddle.x + 110 > w) paddle.x = w - 110;
}
function onKey(e){
if(!started){
startGame();
}
}
// Start and click to hide overlay
startBtn.addEventListener('click', startGame);
canvas.addEventListener('mousemove', onPointerMove);
window.addEventListener('keydown', onKey);
// Resize support
function fit(){
// maintain aspect
const ratio = 1120/640;
const pw = window.innerWidth;
const ph = window.innerHeight;
// We rely on canvas intrinsic size; nothing heavy
}
window.addEventListener('resize', fit);
// Initialize and start
init();
// self-playing demo: we auto-run; show initial overlay until user interaction
requestAnimationFrame(loop);
// Expose minimal event to start on keydown if focused
// Ensure iframe click will capture keyboard after user click by focusing canvas
canvas.addEventListener('click', ()=>{ if(!started){ canvas.focus(); } });
// Focusable for keyboard events
canvas.focus();
})();
</script>
</body>
</html>