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
- 14.0 s
- Cost
- $0.0040
- Output tokens
- 7,960
- Spent thinking
- 937 tokens
- Speed
- 717.6 tok/s
- Console errors
- 0
- First token after
- 2.9 s
- First visible text after
- 4.3 s
- Prompt tokens
- 375
- Code size
- 19.9 KB
- Finish reason
- stop
- Served by
- Meta
- Model id
meta/muse-ember- Reasoning sent
{"effort":"medium"}- 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 · 413 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Hamburger Breakout — Heart Explosion!</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{
font-family:ui-rounded, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background:#fff0f3;
background-image:radial-gradient(circle at 15% 15%, #ffe4ec 0 90px, transparent 91px),
radial-gradient(circle at 85% 90%, #fff3cd 0 110px, transparent 111px),
radial-gradient(circle at 90% 12%, #ffe4ec 0 60px, transparent 61px);
color:#3d1f26; overflow-x:hidden; min-height:100vh;
}
.wrap{max-width:1000px;margin:0 auto;padding:14px 14px 18px}
.top{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:12px}
.brand{display:flex;align-items:center;gap:12px}
.logo{width:58px;height:58px;background:#fff;border:3px solid #ff8fab;border-radius:16px;display:grid;place-items:center;font-size:34px;box-shadow:0 6px 0 #ffb3c6;transform:rotate(-3deg)}
h1{font-size:clamp(24px,4vw,38px);line-height:1;letter-spacing:-1px}
h1 span{color:#ff4d6d}
.sub{font-size:13px;font-weight:700;opacity:.75;margin-top:4px;letter-spacing:.3px}
.badge{background:#ff4d6d;color:#fff;font-weight:900;font-size:12px;letter-spacing:.8px;padding:8px 11px;border-radius:999px;box-shadow:0 4px 0 #c9184a;transform:rotate(2deg)}
.hud{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:10px}
.card{background:#fff;border:2px solid #ffe0e8;border-radius:16px;padding:10px 12px;box-shadow:0 4px 0 #ffd6e0}
.label{font-size:10px;letter-spacing:1.2px;font-weight:900;opacity:.55;text-transform:uppercase}
.value{font-size:22px;font-weight:900;line-height:1.1;margin-top:2px}
.value small{font-size:12px;opacity:.6;font-weight:800}
.lives{color:#ff4d6d;letter-spacing:2px}
.stage{position:relative;background:#fff8ec;border:3px solid #3d1f26;border-radius:22px;overflow:hidden;box-shadow:0 10px 0 #ffb3c6, 0 20px 40px rgba(255,77,109,.18)}
canvas{display:block;width:100%;height:auto;touch-action:none;cursor:none;background:linear-gradient(180deg,#fffaf0 0%,#fff1f5 55%,#ffe8ee 100%)}
.overlay{
position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
background:rgba(255,248,240,.55);backdrop-filter:blur(2px);z-index:5;transition:.3s;
}
.overlay.hide{opacity:0;pointer-events:none}
.panel{background:#fff;border:3px solid #3d1f26;border-radius:20px;padding:18px 20px;text-align:center;max-width:520px;width:calc(100% - 28px);box-shadow:0 8px 0 #ff8fab}
.panel .big{font-size:28px;line-height:1.05;font-weight:900}
.panel p{font-size:14px;font-weight:700;opacity:.75;line-height:1.45;margin:8px 0 12px}
.pill{display:inline-block;background:#fff0f3;border:2px dashed #ff8fab;color:#c9184a;font-weight:900;font-size:12px;padding:6px 10px;border-radius:999px;margin:2px}
.btns{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;margin-top:12px}
button{border:3px solid #3d1f26;background:#ff4d6d;color:#fff;font-weight:900;padding:10px 16px;border-radius:999px;cursor:pointer;box-shadow:0 4px 0 #3d1f26;font-size:14px}
button:active{transform:translateY(3px);box-shadow:0 1px 0 #3d1f26}
button.alt{background:#fff;color:#3d1f26}
.controls{display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap;margin-top:12px}
.hint{font-size:13px;font-weight:800;opacity:.8}
.hint b{background:#fff;border:2px solid #ffe0e8;padding:2px 7px;border-radius:8px}
.rightBtns{display:flex;gap:8px;flex-wrap:wrap}
.mini{padding:7px 12px;font-size:12px;box-shadow:0 3px 0 #3d1f26}
.mini.white{background:#fff;color:#3d1f26}
.toast{position:absolute;left:50%;top:14px;transform:translateX(-50%);background:#3d1f26;color:#fff;padding:8px 14px;border-radius:999px;font-weight:900;font-size:13px;z-index:6;white-space:nowrap;box-shadow:0 6px 16px rgba(0,0,0,.18)}
.hidden{display:none!important}
@media(max-width:640px){
.hud{grid-template-columns:repeat(2,1fr)}
.badge{display:none}
.panel .big{font-size:24px}
.wrap{padding:10px 10px 14px}
}
</style>
</head>
<body>
<div class="wrap">
<div class="top">
<div class="brand">
<div class="logo">🍔</div>
<div>
<h1>HAMBURGER <span>BREAKOUT</span></h1>
<div class="sub">Every brick explodes into TONS of little hearts 💖</div>
</div>
</div>
<div class="badge">❤️ HEART BURST EDITION</div>
</div>
<div class="hud">
<div class="card"><div class="label">Score</div><div class="value" id="score">0</div></div>
<div class="card"><div class="label">Bricks Broken</div><div class="value" id="broken">0 <small>/ 50</small></div></div>
<div class="card"><div class="label">Hearts Exploded</div><div class="value" id="hearts">0 <small>💗</small></div></div>
<div class="card"><div class="label">Level · Lives</div><div class="value"><span id="level">1</span> <small>·</small> <span class="lives" id="lives">♥♥♥</span></div></div>
</div>
<div class="stage" id="stage">
<canvas id="game" width="920" height="620"></canvas>
<div class="toast hidden" id="toast">+100 ❤️</div>
<div class="overlay" id="overlay">
<div class="panel">
<div style="font-size:42px;line-height:1">🍔 💥 ❤️</div>
<div class="big">Click or press a key<br>to start!</div>
<p>Demo is playing behind this card. The hamburger paddle is bouncing the tomato ball — watch the bricks explode into hearts!</p>
<div><span class="pill">🖱️ Move mouse</span><span class="pill">◀ ▶ / A D</span><span class="pill">👆 Touch drag</span></div>
<div class="btns">
<button id="playBtn">▶ PLAY NOW</button>
<button id="demoBtn" class="alt">Watch Demo</button>
</div>
</div>
</div>
</div>
<div class="controls">
<div class="hint">Move: <b>Mouse</b> <b>← →</b> <b>Touch</b> · Bounce the tomato, smash bricks, spread love!</div>
<div class="rightBtns">
<button class="mini white" id="pauseBtn">⏸ Pause</button>
<button class="mini white" id="soundBtn">🔊 Sound: On</button>
<button class="mini" id="restartBtn">↺ Restart</button>
</div>
</div>
</div>
<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const W = canvas.width, H = canvas.height;
const $ = id => document.getElementById(id);
let demo = true, paused = false, soundOn = true;
let score=0, broken=0, heartsTotal=0, level=1, lives=3;
let keys={}, mouseX = W/2, touchX=null;
let shake=0, frame=0;
const paddle = {x:W/2, y:H-38, w:128, h:50, target:W/2};
const ball = {x:W/2, y:H-120, vx:4.2, vy:-4.2, r:13, trail:[]};
let bricks=[], particles=[], floaters=[], ambient=[];
const brickColors = [
{f:'#ff8fab', s:'#fb3a6e', heart:'#fff'},
{f:'#ffb703', s:'#fb8500', heart:'#fff'},
{f:'#8ecae6', s:'#219ebc', heart:'#fff'},
{f:'#95d5b2', s:'#2a9d8f', heart:'#fff'},
{f:'#c77dff', s:'#9d4edd', heart:'#fff'},
{f:'#ff9770', s:'#f15bb5', heart:'#fff'},
];
function buildBricks(){
bricks=[];
const cols=10, rows=Math.min(4+level,6);
const pad=8, top=62, left=28;
const bw=(W-left*2 - pad*(cols-1))/cols;
const bh=30;
for(let r=0;r<rows;r++){
for(let c=0;c<cols;c++){
const col=brickColors[(r+c)%brickColors.length];
bricks.push({x:left+c*(bw+pad), y:top+r*(bh+7), w:bw, h:bh, hp: (level>2 && (r+c)%7===0)?2:1, col, alive:true, wob:Math.random()*Math.PI*2});
}
}
}
function resetBall(dir=1){
ball.x=paddle.x; ball.y=paddle.y-30;
const a = (-Math.PI/2)+(Math.random()-.5)*.6;
const sp=4.6+level*.25;
ball.vx=Math.cos(a)*sp*dir; ball.vy=Math.sin(a)*sp;
}
function resetGame(){
score=0; broken=0; heartsTotal=0; level=1; lives=3;
paddle.x=W/2; paddle.target=W/2;
buildBricks(); resetBall(1); particles=[]; floaters=[];
updateHUD();
}
function updateHUD(){
$('score').textContent=score.toLocaleString();
$('broken').innerHTML=broken+' <small>/ '+bricks.length+'</small>';
$('hearts').innerHTML=heartsTotal.toLocaleString()+' <small>💗</small>';
$('level').textContent=level;
$('lives').textContent='♥'.repeat(Math.max(0,lives)) + '♡'.repeat(Math.max(0,3-lives));
}
function popSound(f=600,d=.08){
if(!soundOn) return;
try{
if(!window._ac) window._ac=new (window.AudioContext||window.webkitAudioContext)();
const o=window._ac.createOscillator(), g=window._ac.createGain();
o.type='square'; o.frequency.value=f; g.gain.value=.06;
o.connect(g); g.connect(window._ac.destination); o.start();
g.gain.exponentialRampToValueAtTime(.001, window._ac.currentTime+d);
o.stop(window._ac.currentTime+d);
}catch(e){}
}
function heartPath(x,y,s,rot){
ctx.save(); ctx.translate(x,y); ctx.rotate(rot); ctx.scale(s,s);
ctx.beginPath();
ctx.moveTo(0,0.35);
ctx.bezierCurveTo(-0.9,-0.35,-0.35,-0.95,0,-0.45);
ctx.bezierCurveTo(0.35,-0.95,0.9,-0.35,0,0.35);
ctx.closePath(); ctx.restore();
}
function drawHeart(x,y,s,rot,color,alpha){
ctx.save(); ctx.globalAlpha=alpha; ctx.fillStyle=color;
ctx.translate(x,y); ctx.rotate(rot); ctx.scale(s,s);
ctx.beginPath();
ctx.moveTo(0,0.35);
ctx.bezierCurveTo(-0.9,-0.35,-0.35,-0.95,0,-0.45);
ctx.bezierCurveTo(0.35,-0.95,0.9,-0.35,0,0.35);
ctx.fill(); ctx.restore();
}
function explodeHearts(x,y,count,baseColor){
const colors=['#ff4d6d','#ff8fab','#ff7096','#fb3a6e','#ffccd5','#ff85a2','#e5989b','#ffb4a2', baseColor||'#ff4d6d'];
for(let i=0;i<count;i++){
const a=Math.random()*Math.PI*2;
const sp=1.2+Math.random()*6.5;
particles.push({
x,y, vx:Math.cos(a)*sp, vy:Math.sin(a)*sp -1.5,
s:4+Math.random()*13, rot:(Math.random()-.5)*1.4, vr:(Math.random()-.5)*.25,
color:colors[Math.floor(Math.random()*colors.length)],
life:0, max:70+Math.random()*90, grav:.08+Math.random()*.06
});
}
heartsTotal+=count;
// big ones
for(let i=0;i<6;i++){
particles.push({x:x+(Math.random()-.5)*30,y:y+(Math.random()-.5)*16,vx:(Math.random()-.5)*3,vy:-2-Math.random()*3,s:14+Math.random()*12,rot:(Math.random()-.5)*.6,vr:.05,color:'#ff4d6d',life:0,max:110,grav:-.02});
}
floaters.push({x,y:y-18,txt:'+100 ❤️',life:0});
}
function showToast(t){
const el=$('toast'); el.textContent=t; el.classList.remove('hidden');
clearTimeout(el._t); el._t=setTimeout(()=>el.classList.add('hidden'),700);
}
// ambient hearts
for(let i=0;i<22;i++) ambient.push({x:Math.random()*W,y:Math.random()*H,s:5+Math.random()*9,vy:.2+Math.random()*.5,sway:Math.random()*6,rot:Math.random()*6});
function drawHamburger(x,y,w){
const h=52;
ctx.save(); ctx.translate(x,y);
// shadow
ctx.fillStyle='rgba(0,0,0,.12)'; ctx.beginPath(); ctx.ellipse(0,24,w*.48,8,0,0,Math.PI*2); ctx.fill();
// bottom bun
ctx.fillStyle='#f4a261'; roundRect(-w/2,8,w,16,8); ctx.fill();
ctx.fillStyle='#e76f51'; roundRect(-w/2+3,10,w-6,5,3); ctx.fill();
// patty
ctx.fillStyle='#6f4518'; roundRect(-w/2+2,2,w-4,11,6); ctx.fill();
// cheese drips
ctx.fillStyle='#ffb703';
ctx.beginPath(); ctx.moveTo(-w/2+4,-2); ctx.lineTo(w/2-4,-2); ctx.lineTo(w/2-10,6); ctx.lineTo(w/2-22,2); ctx.lineTo(w/2-34,8); ctx.lineTo(-w/2+20,5); ctx.lineTo(-w/2+10,8); ctx.lineTo(-w/2+4,2); ctx.fill();
// tomato
ctx.fillStyle='#ef233c'; roundRect(-w/2+8,-7,w-16,7,4); ctx.fill();
ctx.fillStyle='#ffccd5'; ctx.globalAlpha=.5; roundRect(-w/2+14,-5,w-28,2,2); ctx.fill(); ctx.globalAlpha=1;
// lettuce
ctx.fillStyle='#70e000';
ctx.beginPath(); ctx.moveTo(-w/2-3,-10);
for(let i=0;i<=8;i++){ ctx.lineTo(-w/2-3 + i*(w+6)/8, -10 + ((i%2)?3:-1)); }
ctx.lineTo(-w/2-3,-7); ctx.fill();
// top bun
ctx.fillStyle='#f4a261';
ctx.beginPath(); ctx.ellipse(0,-14,w/2,15,0,Math.PI,0); ctx.fill();
ctx.fillStyle='#e9c46a'; ctx.beginPath(); ctx.ellipse(0,-16,w/2-4,11,0,Math.PI,0); ctx.fill();
// sesame
ctx.fillStyle='#fff3b0';
[[-28,-24],[-8,-28],[16,-26],[34,-21],[2,-19],[-18,-18]].forEach(p=>{ ctx.beginPath(); ctx.ellipse(p[0],p[1],4,2,-.5,0,Math.PI*2); ctx.fill(); });
// face on burger
ctx.fillStyle='#3d1f26';
ctx.beginPath(); ctx.arc(-10,-17,2.2,0,Math.PI*2); ctx.arc(10,-17,2.2,0,Math.PI*2); ctx.fill();
ctx.strokeStyle='#3d1f26'; ctx.lineWidth=1.8; ctx.beginPath(); ctx.arc(0,-16,6,0.2,Math.PI-.2); ctx.stroke();
ctx.restore();
}
function roundRect(x,y,w,h,r){ ctx.beginPath(); ctx.moveTo(x+r,y); ctx.arcTo(x+w,y,x+w,y+h,r); ctx.arcTo(x+w,y+h,x,y+h,r); ctx.arcTo(x,y+h,x,y,r); ctx.arcTo(x,y,x+w,y,r); ctx.closePath(); }
function drawBall(){
ball.trail.push({x:ball.x,y:ball.y}); if(ball.trail.length>10) ball.trail.shift();
ball.trail.forEach((p,i)=>{ ctx.globalAlpha=i/ball.trail.length*.25; ctx.fillStyle='#ff4d6d'; ctx.beginPath(); ctx.arc(p.x,p.y,ball.r*.6,0,Math.PI*2); ctx.fill(); });
ctx.globalAlpha=1;
ctx.save(); ctx.translate(ball.x,ball.y); ctx.rotate(frame*.08);
ctx.fillStyle='#ef233c'; ctx.beginPath(); ctx.arc(0,0,ball.r,0,Math.PI*2); ctx.fill();
ctx.fillStyle='#ff8fab'; ctx.beginPath(); ctx.ellipse(-4,-5,5,3,-.6,0,Math.PI*2); ctx.fill();
ctx.fillStyle='#2a9d8f'; ctx.beginPath(); ctx.moveTo(0,-ball.r); ctx.lineTo(-8,-ball.r-5); ctx.lineTo(0,-ball.r-2); ctx.lineTo(8,-ball.r-5); ctx.fill();
ctx.restore();
}
function draw(){
ctx.clearRect(0,0,W,H);
// background dots & ambient hearts
ctx.fillStyle='rgba(255,77,109,.06)';
for(let x=20;x<W;x+=44) for(let y=20;y<H;y+=44){ ctx.beginPath(); ctx.arc(x,y,2,0,Math.PI*2); ctx.fill(); }
ambient.forEach(a=>{
drawHeart(a.x+Math.sin(frame*.01+a.sway)*10, a.y, a.s, a.rot, 'rgba(255,120,150,.28)', .5);
});
// bricks
bricks.forEach(b=>{
if(!b.alive) return;
const wob = Math.sin(frame*.08+b.wob)*.6;
ctx.save(); ctx.translate(b.x+b.w/2,b.y+b.h/2); ctx.rotate(wob*.02);
ctx.fillStyle='rgba(0,0,0,.08)'; roundRect(-b.w/2+3,-b.h/2+5,b.w,b.h,9); ctx.fill();
ctx.fillStyle=b.col.f; roundRect(-b.w/2,-b.h/2,b.w,b.h,9); ctx.fill();
ctx.fillStyle=b.col.s; ctx.globalAlpha=.25; roundRect(-b.w/2,-b.h/2,b.w,9,9); ctx.fill(); ctx.globalAlpha=1;
ctx.strokeStyle=b.col.s; ctx.lineWidth=2; roundRect(-b.w/2,-b.h/2,b.w,b.h,9); ctx.stroke();
drawHeart(0,1,9,0,'rgba(255,255,255,.95)',.95);
if(b.hp>1) { ctx.fillStyle='#fff'; ctx.font='900 10px sans-serif'; ctx.textAlign='center'; ctx.fillText('×2', b.w/2-12, -b.h/2+12); }
ctx.restore();
});
// particles hearts
particles.forEach(p=> drawHeart(p.x,p.y,p.s,p.rot,p.color, Math.max(0,1-p.life/p.max)));
// floaters
floaters.forEach(f=>{ ctx.globalAlpha=Math.max(0,1-f.life/45); ctx.fillStyle='#c9184a'; ctx.font='900 18px sans-serif'; ctx.textAlign='center'; ctx.fillText(f.txt,f.x,f.y-f.life*.8); ctx.globalAlpha=1; });
drawBall();
drawHamburger(paddle.x,paddle.y,paddle.w);
if(shake>0){ ctx.fillStyle=`rgba(255,77,109,${shake*.02})`; ctx.fillRect(0,0,W,H); }
}
function update(){
if(paused) return;
frame++;
ambient.forEach(a=>{ a.y+=a.vy; a.x+=Math.sin(frame*.02+a.sway)*.3; if(a.y>H+20){a.y=-20;a.x=Math.random()*W;} });
// paddle control
if(demo){
// AI follow ball with imperfection
const jitter = Math.sin(frame*.02)*14;
paddle.target = ball.x + jitter*.3;
const diff = paddle.target - paddle.x;
paddle.x += Math.max(-7,Math.min(7,diff));
} else {
if(keys.left) paddle.x-=9;
if(keys.right) paddle.x+=9;
if(touchX!==null) paddle.x += (touchX-paddle.x)*.35;
else if(!keys.left && !keys.right) paddle.x += (mouseX-paddle.x)*.35;
}
paddle.x=Math.max(paddle.w/2,Math.min(W-paddle.w/2,paddle.x));
// ball
ball.x+=ball.vx; ball.y+=ball.vy;
if(ball.x<ball.r){ball.x=ball.r; ball.vx*=-1; popSound(300,.05)}
if(ball.x>W-ball.r){ball.x=W-ball.r; ball.vx*=-1; popSound(300,.05)}
if(ball.y<ball.r+8){ball.y=ball.r+8; ball.vy*=-1; popSound(300,.05)}
// paddle collision
if(ball.vy>0 && ball.y+ball.r>=paddle.y-14 && ball.y+ball.r<=paddle.y+14 && Math.abs(ball.x-paddle.x)<=paddle.w/2+ball.r){
const rel=(ball.x-paddle.x)/(paddle.w/2);
const ang=-Math.PI/2 + rel*.95;
const sp=Math.sqrt(ball.vx*ball.vx+ball.vy*ball.vy);
ball.vx=Math.cos(ang)*sp; ball.vy=Math.sin(ang)*sp;
ball.y=paddle.y-22; popSound(500,.07);
explodeHearts(ball.x,ball.y,3,'#ff8fab');
}
// bricks
for(let b of bricks){
if(!b.alive) continue;
if(ball.x+ball.r>b.x && ball.x-ball.r<b.x+b.w && ball.y+ball.r>b.y && ball.y-ball.r<b.y+b.h){
b.hp--;
// bounce
const overlapLeft=Math.abs(ball.x-ball.r-(b.x+b.w)), overlapRight=Math.abs(ball.x+ball.r-b.x), overlapTop=Math.abs(ball.y-ball.r-(b.y+b.h)), overlapBottom=Math.abs(ball.y+ball.r-b.y);
const min=Math.min(overlapLeft,overlapRight,overlapTop,overlapBottom);
if(min===overlapLeft||min===overlapRight) ball.vx*=-1; else ball.vy*=-1;
if(b.hp<=0){
b.alive=false; broken++; score+=100;
explodeHearts(b.x+b.w/2,b.y+b.h/2,34,b.col.s); // TONS
shake=4; popSound(800,.12); setTimeout(()=>popSound(1000,.08),40);
showToast('💥 HEART BURST! +100');
updateHUD();
if(bricks.every(x=>!x.alive)){ level++; score+=500; showToast('🎉 LEVEL CLEAR! +500'); buildBricks(); resetBall(1); updateHUD(); }
} else {
explodeHearts(ball.x,ball.y,12,'#fff'); popSound(600,.06);
}
break;
}
}
// lose ball
if(ball.y>H+20){
lives--; updateHUD(); shake=6; popSound(180,.2);
explodeHearts(paddle.x,paddle.y,20,'#ff4d6d');
if(lives<=0){ showToast('💔 Game Over — Restarting!'); setTimeout(()=>resetGame(),900); }
else resetBall(Math.random()>.5?1:-1);
}
particles.forEach(p=>{ p.life++; p.x+=p.vx; p.y+=p.vy; p.vy+=p.grav; p.vx*=.985; p.rot+=p.vr; if(p.y>H-10 && p.vy>0){p.vy*=-.35; p.y=H-10;} });
particles=particles.filter(p=>p.life<p.max);
floaters.forEach(f=>f.life++); floaters=floaters.filter(f=>f.life<50);
if(shake>0) shake-=.4;
}
function loop(){ update(); draw(); requestAnimationFrame(loop); }
function startPlay(){
if(!demo) return;
demo=false; $('overlay').classList.add('hide');
showToast('▶ You\'re playing! Good luck! 🍔');
popSound(700,.1);
}
function toDemo(){
demo=true; $('overlay').classList.remove('hide'); showToast('🤖 Demo mode');
}
canvas.addEventListener('mousemove',e=>{
const r=canvas.getBoundingClientRect(); mouseX=(e.clientX-r.left)/r.width*W; touchX=null;
});
canvas.addEventListener('touchmove',e=>{ e.preventDefault(); const r=canvas.getBoundingClientRect(); touchX=(e.touches[0].clientX-r.left)/r.width*W; },{passive:false});
canvas.addEventListener('touchstart',e=>{ const r=canvas.getBoundingClientRect(); touchX=(e.touches[0].clientX-r.left)/r.width*W; startPlay(); },{passive:true});
canvas.addEventListener('click',()=>startPlay());
$('overlay').addEventListener('click',e=>{ if(e.target.id==='overlay') startPlay(); });
$('playBtn').onclick=startPlay;
$('demoBtn').onclick=()=>{ $('overlay').classList.add('hide'); demo=true; setTimeout(()=>$('overlay').classList.remove('hide'),1200); };
$('restartBtn').onclick=()=>{ resetGame(); startPlay(); };
$('pauseBtn').onclick=()=>{ paused=!paused; $('pauseBtn').textContent=paused?'▶ Resume':'⏸ Pause'; };
$('soundBtn').onclick=()=>{ soundOn=!soundOn; $('soundBtn').textContent=soundOn?'🔊 Sound: On':'🔇 Sound: Off'; };
window.addEventListener('keydown',e=>{
if(['ArrowLeft','ArrowRight',' '].includes(e.key)) e.preventDefault();
if(demo) startPlay();
if(e.key==='ArrowLeft'||e.key==='a'||e.key==='A') keys.left=true;
if(e.key==='ArrowRight'||e.key==='d'||e.key==='D') keys.right=true;
if(e.key===' ') { paused=!paused; $('pauseBtn').textContent=paused?'▶ Resume':'⏸ Pause'; }
});
window.addEventListener('keyup',e=>{
if(e.key==='ArrowLeft'||e.key==='a'||e.key==='A') keys.left=false;
if(e.key==='ArrowRight'||e.key==='d'||e.key==='D') keys.right=false;
});
resetGame();
loop();
// auto burst one brick at start so screenshot shows hearts
setTimeout(()=>{ if(bricks[12]){ bricks[12].alive=false; broken++; score+=100; explodeHearts(bricks[12].x+bricks[12].w/2,bricks[12].y+15,46); updateHUD(); } },700);
setTimeout(()=>{ if(bricks[23]){ bricks[23].alive=false; broken++; score+=100; explodeHearts(bricks[23].x+bricks[23].w/2,bricks[23].y+15,40); updateHUD(); } },1600);
</script>
</body>
</html>Reasoning trace (937 tokens)
Implementing canvas breakout with hamburger paddle, heart particle explosions, responsive layout, and AI demo mode triggered by user input.Extending the canvas implementation with heart particles, responsive layout, and AI demo paddle logic.