Hamburger breakoutOne-line
Muse Ember
by MetaReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 20.2 s
- Cost
- $0.0054
- Output tokens
- 10,808
- Spent thinking
- 2,788 tokens
- Speed
- 599.8 tok/s
- Console errors
- 0
- First token after
- 2.1 s
- First visible text after
- 9.3 s
- Prompt tokens
- 375
- Code size
- 22.6 KB
- Finish reason
- stop
- Served by
- Meta
- Model id
meta/muse-ember- Reasoning sent
{"effort":"high"}- Max output
- 943,718 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 · 513 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Hamburger Breakout — Heart Burst</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
html,body{width:100%;min-height:100%}
body{
font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
background:linear-gradient(135deg,#fff1f3 0%,#ffe9c9 48%,#ffd6e0 100%);
color:#432818;
overflow-x:hidden;
padding:14px 12px 20px;
}
.wrap{max-width:960px;margin:0 auto}
header{
display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;
margin-bottom:10px;
}
.logo{display:flex;align-items:center;gap:11px}
.burger-ico{
width:56px;height:56px;border-radius:18px;background:#fff;
box-shadow:0 6px 0 #ffb3c1,0 12px 24px rgba(244,114,143,.35);
display:grid;place-items:center;font-size:34px;line-height:1;
transform:rotate(-3deg);
}
h1{
font-size:clamp(24px,4.5vw,38px);line-height:.9;font-weight:950;letter-spacing:-.03em;
color:#c9184a;text-transform:uppercase;
}
h1 span{display:block;color:#7a4a21;font-size:.52em;letter-spacing:.14em;margin-top:3px}
.tag{
background:#c9184a;color:#fff;font-weight:900;font-size:12px;letter-spacing:.08em;
padding:8px 11px;border-radius:999px;box-shadow:0 4px 0 #590d22;white-space:nowrap;
}
.hud{
display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:10px;
}
.card{
background:#fff;border:2px solid #432818;border-radius:16px;
padding:8px 10px;box-shadow:0 4px 0 #432818;
min-width:0;
}
.card label{font-size:10px;font-weight:900;letter-spacing:.14em;color:#ff5a7a;display:block;line-height:1}
.card strong{font-size:clamp(18px,3vw,24px);font-weight:950;letter-spacing:-.02em;display:block;margin-top:2px;white-space:nowrap}
.card strong.heart{color:#ff2a5f;font-size:18px;letter-spacing:1px}
.stage{
position:relative;background:#fff7e8;border:3px solid #432818;border-radius:24px;
box-shadow:0 8px 0 #432818,0 22px 40px rgba(122,74,33,.22);
overflow:hidden;
}
canvas{display:block;width:100%;height:auto;background:linear-gradient(180deg,#fff3d6 0%,#ffe5ec 58%,#ffc8dd 100%);touch-action:none;cursor:pointer}
#overlay{
position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
background:rgba(255,244,220,.42);backdrop-filter:blur(2px);z-index:5;padding:14px;
}
#overlay.hidden{display:none}
.panel{
background:#fff;border:3px solid #432818;border-radius:22px;box-shadow:0 7px 0 #432818;
max-width:520px;width:100%;text-align:center;padding:20px 18px 16px;
}
.panel .big{font-size:34px;line-height:1}
.panel h2{font-size:clamp(24px,5vw,36px);font-weight:950;letter-spacing:-.03em;color:#c9184a;line-height:.95;margin:6px 0 6px;text-transform:uppercase}
.panel h2 em{font-style:normal;color:#f59e0b}
.panel p{font-size:14px;line-height:1.45;color:#5c3d2e;font-weight:600}
.panel p b{color:#c9184a}
.keys{margin:12px auto 0;display:flex;gap:6px;justify-content:center;flex-wrap:wrap}
.keys span{background:#fff1f3;border:2px solid #432818;border-radius:999px;padding:5px 9px;font-size:11px;font-weight:900}
.btns{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;margin-top:14px}
button{
font-family:inherit;font-weight:950;letter-spacing:.02em;border:2px solid #432818;border-radius:999px;
padding:11px 18px;font-size:15px;cursor:pointer;box-shadow:0 4px 0 #432818;transition:transform .08s,box-shadow .08s;
background:#ff2a5f;color:#fff;
}
button:active{transform:translateY(3px);box-shadow:0 1px 0 #432818}
button.alt{background:#ffb703;color:#432818}
.controls{
display:flex;gap:8px;align-items:center;justify-content:space-between;flex-wrap:wrap;margin-top:10px;
}
.hint{font-size:13px;font-weight:700;color:#6b4230;background:rgba(255,255,255,.75);border:2px solid rgba(67,40,24,.18);padding:9px 11px;border-radius:999px}
.mini{display:flex;gap:7px}
.mini button{padding:9px 14px;font-size:13px;background:#fff;color:#432818}
.mini button.primary{background:#ff2a5f;color:#fff}
.progress{height:12px;background:#fff;border:2px solid #432818;border-radius:999px;overflow:hidden;margin-top:10px;box-shadow:0 3px 0 #432818}
.progress i{display:block;height:100%;width:0%;background:repeating-linear-gradient(45deg,#ff2a5f 0 10px,#ff8fab 10px 20px);transition:width .25s}
@media (max-width:560px){
body{padding:10px 8px 16px}
.hud{grid-template-columns:1fr 1fr}
.burger-ico{width:46px;height:46px;font-size:28px;border-radius:15px}
.tag{display:none}
.panel{padding:16px 12px 13px}
.hint{font-size:12px}
}
</style>
</head>
<body>
<div class="wrap">
<header>
<div class="logo">
<div class="burger-ico">🍔</div>
<h1>Hamburger<br>Breakout <span>★ HEART BURST EDITION ★</span></h1>
</div>
<div class="tag">BREAK A BRICK = HEART EXPLOSION!</div>
</header>
<div class="hud">
<div class="card"><label>SCORE</label><strong id="score">0</strong></div>
<div class="card"><label>HEARTS BURST</label><strong id="hearts">0</strong></div>
<div class="card"><label>LEVEL</label><strong id="level">1</strong></div>
<div class="card"><label>LIVES</label><strong class="heart" id="lives">♥♥♥</strong></div>
</div>
<div class="stage">
<canvas id="game" width="900" height="620"></canvas>
<div id="overlay">
<div class="panel" id="panel">
<div class="big">🍔💥❤️</div>
<h2>Hamburger<br><em>Breakout</em></h2>
<p>Your paddle is a <b>delicious hamburger</b>!<br>Smash every brick and watch it <b>explode into tons of little hearts</b>. Catch golden hearts for extra life.</p>
<div class="keys"><span>🖱️ MOUSE / TOUCH</span><span>← → ARROWS</span><span>SPACE = LAUNCH</span><span>P = PAUSE</span></div>
<div class="btns"><button id="playBtn">▶ PLAY NOW</button></div>
<p style="margin-top:10px;font-size:12px;opacity:.75">Demo is playing behind this card — click anywhere to take control!</p>
</div>
</div>
</div>
<div class="progress"><i id="bar"></i></div>
<div class="controls">
<div class="hint">Move the burger to bounce the tomato ball. Golden ♥ = +1 life!</div>
<div class="mini">
<button id="pauseBtn">⏸ Pause</button>
<button id="restartBtn" class="primary">↺ Restart</button>
</div>
</div>
</div>
<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const W = 900, H = 620;
const $ = id => document.getElementById(id);
const overlay = $('overlay'), panel = $('panel');
let state = 'demo'; // demo | playing | paused | over
let score = 0, heartsBurst = 0, level = 1, lives = 3, totalBricks = 1;
let bricks = [], particles = [], popups = [], powerups = [], trail = [], ambient = [];
let keys = {}, mouseX = null, paddleVX = 0, frame = 0, clearTimer = 0;
let audioCtx = null;
const paddle = { x: W/2-62, y: H-48, w: 124, h: 38, tilt: 0 };
const ball = { x: W/2, y: H-62, r: 11, vx: 0, vy: 0, speed: 5.4, stuck: true };
const brickColors = ['#ff2a5f','#ff7a18','#ffb703','#2ec4b6','#4361ee','#9b5de5','#f15bb5'];
const heartColors = ['#ff2a5f','#ff5a7a','#ff8fab','#ff4d6d','#fb6f92','#ff0a54','#ff758f','#ffb3c1','#ffd166'];
const phrases = ['YUM!','LOVE!','SWEET!','POP!','HEART BURST!','DELICIOUS!','♥ POP!'];
function rr(c,x,y,w,h,r){
r=Math.min(r,w/2,h/2);
c.beginPath();
c.moveTo(x+r,y);c.lineTo(x+w-r,y);c.quadraticCurveTo(x+w,y,x+w,y+r);
c.lineTo(x+w,y+h-r);c.quadraticCurveTo(x+w,y+h,x+w-r,y+h);
c.lineTo(x+r,y+h);c.quadraticCurveTo(x,y+h,x,y+h-r);
c.lineTo(x,y+r);c.quadraticCurveTo(x,y,x+r,y);c.closePath();
}
function heartPath(c,x,y,s,rot){
c.save();c.translate(x,y);c.rotate(rot);c.scale(s,s);
c.beginPath();
c.moveTo(0,4);
c.bezierCurveTo(-7,-3,-10,-1,-10,2.5);
c.bezierCurveTo(-10,6,-5,9,0,13);
c.bezierCurveTo(5,9,10,6,10,2.5);
c.bezierCurveTo(10,-1,7,-3,0,4);
c.closePath();c.restoreNode ? null : null;
c.restore();
}
function drawHeart(c,x,y,s,rot,color,alpha=1){
c.save();c.globalAlpha=alpha;c.translate(x,y);c.rotate(rot);c.scale(s,s);
c.fillStyle=color;
c.beginPath();
c.moveTo(0,4);
c.bezierCurveTo(-7,-3,-10,-1,-10,2.5);
c.bezierCurveTo(-10,6,-5,9,0,13);
c.bezierCurveTo(5,9,10,6,10,2.5);
c.bezierCurveTo(10,-1,7,-3,0,4);
c.closePath();c.fill();
c.fillStyle='rgba(255,255,255,.55)';
c.beginPath();c.ellipse(-3,2,2.4,1.5,-.6,0,7);c.fill();
c.restore();
}
function playTone(f,d=0.07,type='sine',v=0.12){
try{
if(!audioCtx) audioCtx = new (window.AudioContext||window.webkitAudioContext)();
if(audioCtx.state==='suspended') audioCtx.resume();
const o=audioCtx.createOscillator(), g=audioCtx.createGain();
o.type=type;o.frequency.value=f;g.gain.value=v;
g.gain.exponentialRampToValueAtTime(.001,audioCtx.currentTime+d);
o.connect(g);g.connect(audioCtx.destination);o.start();o.stop(audioCtx.currentTime+d);
}catch(e){}
}
function buildBricks(lv){
bricks=[]; powerups=[];
const cols=9, rows=Math.min(4+lv,7);
const left=38, top=78, gap=8;
const bw=(W-left*2-(cols-1)*gap)/cols, bh=26;
for(let r=0;r<rows;r++){
for(let c=0;c<cols;c++){
bricks.push({x:left+c*(bw+gap),y:top+r*(bh+gap),w:bw,h:bh,color:brickColors[r%brickColors.length],alive:true,rr:r,cc:c});
}
}
totalBricks=bricks.length;
updateHUD();
}
function resetBall(stuck=true){
ball.x=paddle.x+paddle.w/2; ball.y=paddle.y-16; ball.vx=0; ball.vy=0;
ball.speed=5.1+level*0.35; ball.stuck=stuck; trail=[];
if(!stuck) launchBall();
}
function launchBall(){
if(!ball.stuck) return;
const a=(-55-Math.random()*20)*Math.PI/180;
ball.vx=Math.cos(a)*ball.speed; ball.vy=Math.sin(a)*ball.speed; ball.stuck=false;
}
function spawnHearts(x,y,n=36,gold=false){
for(let i=0;i<n;i++){
const a=Math.random()*Math.PI*2, sp=1.2+Math.random()*6.2;
const col=gold?'#ffb703':heartColors[Math.floor(Math.random()*heartColors.length)];
particles.push({
x,y,vx:Math.cos(a)*sp,vy:Math.sin(a)*sp-1.4,
s:0.55+Math.random()*1.05,rot:Math.random()*Math.PI*2,vr:(Math.random()-.5)*.28,
life:0,max:55+Math.random()*55,color:col,gold
});
}
// crumbs
for(let i=0;i<10;i++){
particles.push({x,y,vx:(Math.random()-.5)*6,vy:-Math.random()*4,s:.25+Math.random()*.4,rot:0,vr:.2,life:0,max:35,color:'#7a4a21',crumb:true});
}
heartsBurst += n;
}
function popup(x,y,text,color='#c9184a'){
popups.push({x,y,text,color,life:0});
}
function updateHUD(){
$('score').textContent=score;
$('hearts').textContent=heartsBurst;
$('level').textContent=level;
$('lives').textContent='♥'.repeat(Math.max(0,lives))||'—';
const alive=bricks.filter(b=>b.alive).length;
$('bar').style.width=(totalBricks?((totalBricks-alive)/totalBricks*100):0)+'%';
}
function startGame(){
score=0;heartsBurst=0;level=1;lives=3;
buildBricks(level); resetBall(true);
state='playing'; overlay.classList.add('hidden'); updateHUD(); playTone(660,.1,'triangle',.14);
popup(W/2,260,'GO! 🍔','#c9184a');
}
function gameOver(){
state='over';
panel.innerHTML=`<div class="big">💔🍔</div><h2>Game<br><em>Over!</em></h2>
<p>You burst <b>${heartsBurst} hearts</b> and scored <b>${score}</b> points!<br>The burger is a little tired… want another bite?</p>
<div class="btns"><button id="againBtn">↺ PLAY AGAIN</button></div>`;
overlay.classList.remove('hidden');
$('againBtn').onclick=e=>{e.stopPropagation();startGame();};
}
function pauseToggle(){
if(state==='playing'){state='paused';panel.innerHTML=`<div class="big">⏸️🍔</div><h2>Paused</h2><p>Take a breather. The burger is waiting!</p><div class="btns"><button id="resumeBtn">▶ Resume</button><button id="quitBtn" class="alt">Restart</button></div>`;overlay.classList.remove('hidden');$('resumeBtn').onclick=e=>{e.stopPropagation();state='playing';overlay.classList.add('hidden')};$('quitBtn').onclick=e=>{e.stopPropagation();startGame()};}
else if(state==='paused'){state='playing';overlay.classList.add('hidden');}
}
overlay.addEventListener('click',()=>{ if(state==='demo'||state==='over') startGame(); });
$('playBtn').addEventListener('click',e=>{e.stopPropagation();startGame();});
$('pauseBtn').addEventListener('click',()=>{ if(state==='playing'||state==='paused') pauseToggle(); });
$('restartBtn').addEventListener('click',startGame);
function canvasX(clientX){
const r=canvas.getBoundingClientRect();
return (clientX-r.left)/r.width*W;
}
canvas.addEventListener('mousemove',e=>{mouseX=canvasX(e.clientX);});
canvas.addEventListener('click',()=>{ if(state==='demo') startGame(); else if(state==='playing') launchBall(); });
canvas.addEventListener('touchstart',e=>{e.preventDefault(); mouseX=canvasX(e.touches[0].clientX); if(state==='demo') startGame(); else launchBall();},{passive:false});
canvas.addEventListener('touchmove',e=>{e.preventDefault(); mouseX=canvasX(e.touches[0].clientX);},{passive:false});
window.addEventListener('keydown',e=>{
if(['ArrowLeft','ArrowRight','Space'].includes(e.code)) e.preventDefault();
keys[e.code]=true;
if(state==='demo' && (e.code==='Space'||e.code==='Enter')) startGame();
else if(state==='over' && e.code==='Enter') startGame();
else if(state==='playing' && e.code==='Space') launchBall();
if(e.code==='KeyP'||e.code==='Escape'){ if(state==='playing'||state==='paused') pauseToggle(); }
});
window.addEventListener('keyup',e=>keys[e.code]=false);
// ambient background hearts
for(let i=0;i<16;i++) ambient.push({x:Math.random()*W,y:Math.random()*H,s:.5+Math.random()*1.1,vy:.18+Math.random()*.35,rot:Math.random()*6,color:heartColors[i%heartColors.length]});
function drawBurger(){
const {x,y,w,h}=paddle;
ctx.save();
ctx.translate(x+w/2,y+h/2); ctx.rotate(paddle.tilt); ctx.translate(-w/2,-h/2);
ctx.shadowColor='rgba(67,40,24,.35)';ctx.shadowBlur=8;ctx.shadowOffsetY=5;
// bottom bun
ctx.fillStyle='#f4a950'; rr(ctx,5,26,w-10,11,5); ctx.fill();
ctx.fillStyle='#7a4a21'; rr(ctx,3,20,w-6,8,4); ctx.fill();
ctx.fillStyle='#ffd166'; rr(ctx,3,17,w-6,5,3); ctx.fill(); // cheese
ctx.fillStyle='#ff3b30'; rr(ctx,6,13,w-12,6,3); ctx.fill(); // tomato
// lettuce wavy
ctx.fillStyle='#6ac84f'; ctx.beginPath();
ctx.moveTo(0,12);
for(let i=0;i<=10;i++){ ctx.quadraticCurveTo(i*(w/10)+w/20, i%2?18:10, (i+1)*(w/10),12); }
ctx.lineTo(w,15); ctx.lineTo(0,15); ctx.closePath(); ctx.fill();
// top bun dome
ctx.shadowBlur=0;
ctx.fillStyle='#ffb84d';
ctx.beginPath();
ctx.moveTo(2,14); ctx.lineTo(2,9);
ctx.bezierCurveTo(2,1,w*0.28,-2,w/2,-2);
ctx.bezierCurveTo(w*0.72,-2,w-2,1,w-2,9);
ctx.lineTo(w-2,14); ctx.closePath(); ctx.fill();
ctx.strokeStyle='rgba(122,74,33,.55)';ctx.lineWidth=1.5;ctx.stroke();
// sesame
ctx.fillStyle='#fff3d6';
for(let i=0;i<6;i++){ const sx=16+i*(w-32)/5, sy=5+Math.sin(i*1.7)*2; ctx.beginPath(); ctx.ellipse(sx,sy,5,2.4,.5,0,7); ctx.fill(); }
// face on top bun - cute!
ctx.fillStyle='#432818';
ctx.beginPath();ctx.arc(w/2-13,9,2.2,0,7);ctx.arc(w/2+13,9,2.2,0,7);ctx.fill();
ctx.strokeStyle='#432818';ctx.lineWidth=1.8;ctx.beginPath();ctx.arc(w/2,10,7,.2,Math.PI-.2);ctx.stroke();
ctx.restore();
}
function drawBall(){
trail.push({x:ball.x,y:ball.y}); if(trail.length>10) trail.shift();
trail.forEach((t,i)=>{ ctx.globalAlpha=i/10*.35; drawHeart(ctx,t.x,t.y,.55,0,'#ff8fab'); });
ctx.globalAlpha=1;
// tomato ball
const g=ctx.createRadialGradient(ball.x-4,ball.y-4,2,ball.x,ball.y,ball.r);
g.addColorStop(0,'#ff8fab'); g.addColorStop(.4,'#ff2a5f'); g.addColorStop(1,'#c9184a');
ctx.fillStyle=g; ctx.shadowColor='rgba(201,24,74,.4)';ctx.shadowBlur=8;ctx.shadowOffsetY=3;
ctx.beginPath();ctx.arc(ball.x,ball.y,ball.r,0,7);ctx.fill(); ctx.shadowBlur=0;
ctx.fillStyle='#2ec4b6';
ctx.beginPath();ctx.ellipse(ball.x,ball.y-ball.r+1,7,3,0,0,7);ctx.fill();
ctx.fillStyle='rgba(255,255,255,.75)';ctx.beginPath();ctx.ellipse(ball.x-4,ball.y-4,3.5,2,-.6,0,7);ctx.fill();
// cute face
ctx.fillStyle='#fff';ctx.beginPath();ctx.arc(ball.x-3.5,ball.y+1,1.9,0,7);ctx.arc(ball.x+3.5,ball.y+1,1.9,0,7);ctx.fill();
ctx.fillStyle='#432818';ctx.beginPath();ctx.arc(ball.x-3.5,ball.y+1,1,0,7);ctx.arc(ball.x+3.5,ball.y+1,1,0,7);ctx.fill();
}
function drawBricks(){
bricks.forEach(b=>{
if(!b.alive) return;
ctx.save();
ctx.shadowColor='rgba(67,40,24,.25)';ctx.shadowBlur=5;ctx.shadowOffsetY=3;
ctx.fillStyle=b.color; rr(ctx,b.x,b.y,b.w,b.h,8); ctx.fill();
ctx.shadowBlur=0;
ctx.fillStyle='rgba(255,255,255,.38)'; rr(ctx,b.x+4,b.y+3,b.w-8,8,5); ctx.fill();
ctx.strokeStyle='rgba(67,40,24,.45)';ctx.lineWidth=1.6; rr(ctx,b.x,b.y,b.w,b.h,8); ctx.stroke();
drawHeart(ctx,b.x+b.w/2,b.y+b.h/2+1,.62,0,'rgba(255,255,255,.85)',.9);
ctx.restore();
});
}
function update(){
frame++;
// ambient
ambient.forEach(a=>{ a.y-=a.vy; a.x+=Math.sin(frame*.02+a.rot)*.3; if(a.y<-20){a.y=H+20;a.x=Math.random()*W;} });
// paddle control
let target=null;
if(state==='demo'){
if(ball.stuck && frame%90===0) launchBall();
target = ball.x - paddle.w/2;
// add slight imperfection
target += Math.sin(frame*.01)*8;
} else {
if(mouseX!==null) target=mouseX-paddle.w/2;
if(keys.ArrowLeft) target=(target??paddle.x)-11;
if(keys.ArrowRight) target=(target??paddle.x)+11;
}
if(target!==null){
const old=paddle.x;
paddle.x += (target-paddle.x)* (state==='demo'?0.16:0.45);
paddle.x=Math.max(4,Math.min(W-paddle.w-4,paddle.x));
paddleVX=paddle.x-old;
} else paddleVX=0;
paddle.tilt = Math.max(-.12,Math.min(.12,paddleVX*.012));
if(ball.stuck){ ball.x=paddle.x+paddle.w/2; ball.y=paddle.y-14; }
// ball physics
if(!ball.stuck && (state==='playing'||state==='demo')){
ball.x+=ball.vx; ball.y+=ball.vy;
const sp=Math.hypot(ball.vx,ball.vy)||1;
if(sp<ball.speed){ ball.vx*=ball.speed/sp; ball.vy*=ball.speed/sp; }
if(ball.x<ball.r+2){ball.x=ball.r+2;ball.vx=Math.abs(ball.vx);playTone(300,.05,'square',.06);}
if(ball.x>W-ball.r-2){ball.x=W-ball.r-2;ball.vx=-Math.abs(ball.vx);playTone(300,.05,'square',.06);}
if(ball.y<ball.r+2){ball.y=ball.r+2;ball.vy=Math.abs(ball.vy);playTone(300,.05,'square',.06);}
// paddle collision
if(ball.vy>0 && ball.y+ball.r>=paddle.y && ball.y+ball.r<=paddle.y+18 && ball.x>=paddle.x-6 && ball.x<=paddle.x+paddle.w+6){
const rel=Math.max(-1,Math.min(1,(ball.x-(paddle.x+paddle.w/2))/(paddle.w/2)));
const ang=(-90+rel*62)*Math.PI/180;
ball.vx=Math.cos(ang)*ball.speed; ball.vy=Math.sin(ang)*ball.speed;
ball.y=paddle.y-ball.r-1; playTone(520+Math.abs(rel)*200,.07,'triangle',.12);
spawnHearts(ball.x,paddle.y,3);
}
// bricks
for(const b of bricks){
if(!b.alive) continue;
const cx=Math.max(b.x,Math.min(ball.x,b.x+b.w)), cy=Math.max(b.y,Math.min(ball.y,b.y+b.h));
const dx=ball.x-cx, dy=ball.y-cy;
if(dx*dx+dy*dy < ball.r*ball.r){
b.alive=false;
const bcx=b.x+b.w/2, bcy=b.y+b.h/2;
// decide bounce axis
if(Math.abs(ball.x-bcx) > b.w/2-2 && Math.abs(ball.y-bcy) < b.h/2) ball.vx*=-1; else ball.vy*=-1;
const n=38;
spawnHearts(bcx,bcy,n);
score+=50+level*10;
popup(bcx,bcy-12,phrases[Math.floor(Math.random()*phrases.length)],'#c9184a');
playTone(700+Math.random()*400,.09,'sine',.14);
setTimeout(()=>playTone(1000,.08,'sine',.1),40);
if(Math.random()<0.16) powerups.push({x:bcx,y:bcy,vy:2.2,t:0});
updateHUD();
break;
}
}
// bottom
if(ball.y>H+18){
if(state==='demo'){ resetBall(true); spawnHearts(paddle.x+paddle.w/2,paddle.y,10); }
else {
lives--; updateHUD(); playTone(160,.25,'sawtooth',.12);
popup(W/2,H-90,'OUCH!','#7a4a21');
if(lives<=0) gameOver(); else resetBall(true);
}
}
// level clear
if(bricks.length && bricks.every(b=>!b.alive) && clearTimer===0){
clearTimer=55; score+=300; popup(W/2,250,'LEVEL CLEAR! +300','#c9184a'); spawnHearts(W/2,260,60,true); updateHUD();
}
}
if(clearTimer>0){ clearTimer--; if(clearTimer===0){ level++; buildBricks(level); resetBall(true); popup(W/2,240,'LEVEL '+level,'#4361ee'); } }
// powerups
powerups=powerups.filter(p=>{
p.y+=p.vy; p.t++;
if(p.y>paddle.y && p.y<paddle.y+26 && p.x>paddle.x-8 && p.x<paddle.x+paddle.w+8){
lives=Math.min(5,lives+1); score+=250; popup(p.x,p.y-14,'+1 LIFE! ♥','#ffb703'); spawnHearts(p.x,p.y,26,true); playTone(880,.12,'triangle',.15); updateHUD(); return false;
}
return p.y<H+20;
});
// particles
particles=particles.filter(p=>{
p.life++; p.x+=p.vx; p.y+=p.vy; p.vy+= p.gold?0.02:0.07; p.vx*=0.99; p.rot+=p.vr;
return p.life<p.max;
});
popups=popups.filter(p=>{p.life++;p.y-=.9;return p.life<55;});
}
function draw(){
ctx.clearRect(0,0,W,H);
// dotted bg
ctx.fillStyle='rgba(255,255,255,.45)';
for(let x=22;x<W;x+=46) for(let y=22;y<H;y+=46){ ctx.beginPath();ctx.arc(x+((y/46)%2)*14,y,2,0,7);ctx.fill(); }
ambient.forEach(a=>drawHeart(ctx,a.x,a.y,a.s,a.rot*0.1,a.color,.16));
// top score strip inside canvas
ctx.fillStyle='rgba(255,255,255,.75)'; rr(ctx,14,14,W-28,44,14); ctx.fill();
ctx.strokeStyle='rgba(67,40,24,.25)';ctx.lineWidth=2; rr(ctx,14,14,W-28,44,14); ctx.stroke();
ctx.fillStyle='#432818';ctx.font='900 15px system-ui';ctx.textAlign='left';
ctx.fillText('🍔 BURGER PADDLE',28,42);
ctx.textAlign='right';
ctx.fillStyle='#c9184a'; ctx.font='900 20px system-ui';
ctx.fillText('SCORE '+score,W-28,42);
ctx.textAlign='center';ctx.font='900 13px system-ui';ctx.fillStyle='#7a4a21';
const alive=bricks.filter(b=>b.alive).length;
ctx.fillText('BRICKS '+alive+' / '+totalBricks,W/2,42);
drawBricks();
// powerups
powerups.forEach(p=>{ const bob=Math.sin(p.t*.15)*3; drawHeart(ctx,p.x,p.y+bob,1.35,Math.sin(p.t*.08)*.3,'#ffb703'); ctx.strokeStyle='#7a4a21';ctx.lineWidth=1.5; drawHeart(ctx,p.x,p.y+bob,1.35,Math.sin(p.t*.08)*.3,'#ffb703'); });
drawBurger();
drawBall();
particles.forEach(p=>{
const a=1-p.life/p.max;
if(p.crumb){ ctx.save();ctx.globalAlpha=a;ctx.fillStyle=p.color;ctx.translate(p.x,p.y);ctx.rotate(p.rot);ctx.fillRect(-2,-2,4,4);ctx.restore(); }
else drawHeart(ctx,p.x,p.y,p.s,p.rot,p.color,a);
});
popups.forEach(p=>{
ctx.save();ctx.globalAlpha=1-p.life/55;ctx.font='950 22px system-ui';ctx.textAlign='center';
ctx.lineWidth=5;ctx.strokeStyle='#fff';ctx.strokeText(p.text,p.x,p.y);
ctx.fillStyle=p.color;ctx.fillText(p.text,p.x,p.y);ctx.restore();
});
if(ball.stuck && state==='playing'){
ctx.save();ctx.font='900 16px system-ui';ctx.textAlign='center';ctx.fillStyle='#432818';
ctx.fillText('CLICK OR PRESS SPACE TO LAUNCH!',W/2,paddle.y-34);
ctx.restore();
}
if(state==='paused'){ ctx.fillStyle='rgba(255,255,255,.35)';ctx.fillRect(0,0,W,H); }
}
function loop(){ update(); draw(); requestAnimationFrame(loop); }
// init demo
buildBricks(1);
resetBall(true);
updateHUD();
loop();
</script>
</body>
</html>Reasoning trace (2,788 tokens)
Designing a single-file responsive canvas breakout with hamburger paddle, heart particles, AI demo mode, and start overlay.Expanding the design with hamburger paddle rendering, heart particle effects, and responsive canvas layout.Adding game states, HUD, input handling, and overlay UI while keeping the canvas responsive.Detailing canvas drawing routines and collision handling for paddle, ball, bricks, and powerups.