Models 44

Muse Ember

Open in new window

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

How it went

Total time
18.7 s
Cost
$0.0041
Output tokens
8,074
Spent thinking
657 tokens
Speed
518.7 tok/s
Console errors
0
First token after
3.2 s
First visible text after
4.2 s
Prompt tokens
375
Code size
20.4 KB
Finish reason
stop
Served by
Meta
Model id
meta/muse-ember
Reasoning sent
{"effort":"low"}
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 · 391 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 Explosion</title>
<style>
  *{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
  html,body{height:100%}
  body{
    font-family:ui-rounded, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    background: radial-gradient(1200px 700px at 20% -10%, #ffe4ec 0%, transparent 55%),
                radial-gradient(1000px 600px at 110% 10%, #fff3c4 0%, transparent 50%),
                linear-gradient(180deg,#fff8e7 0%,#ffeef3 55%,#ffe0e8 100%);
    color:#3d1f2a; overflow:hidden; display:flex; flex-direction:column; align-items:center;
    min-height:100vh;
  }
  /* ambient floating hearts bg */
  .bg-heart{position:fixed;pointer-events:none;opacity:.14;animation:floatUp linear infinite;z-index:0;line-height:1}
  @keyframes floatUp{from{transform:translateY(110vh) rotate(0deg)}to{transform:translateY(-10vh) rotate(340deg)}}
  .wrap{position:relative;z-index:1;width:min(920px,100vw);height:100vh;height:100dvh;display:flex;flex-direction:column;padding:10px 12px 8px;gap:8px}
  header{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}
  .logo{display:flex;align-items:center;gap:10px}
  .logo-emoji{font-size:42px;line-height:1;filter:drop-shadow(0 4px 0 rgba(0,0,0,.08));animation:wobble 2.4s ease-in-out infinite}
  @keyframes wobble{0%,100%{transform:rotate(-4deg) scale(1)}50%{transform:rotate(5deg) scale(1.06)}}
  h1{font-size:clamp(22px,4.5vw,34px);font-weight:900;letter-spacing:-.5px;line-height:.95}
  h1 span{color:#ff3b6e}
  .sub{font-size:12px;font-weight:700;opacity:.65;margin-top:3px;letter-spacing:.4px}
  .stats{display:flex;gap:8px;flex-wrap:wrap}
  .card{background:#fff;border:2.5px solid #3d1f2a;border-radius:16px;padding:6px 12px;min-width:92px;box-shadow:3px 3px 0 #3d1f2a;text-align:center}
  .card b{display:block;font-size:20px;line-height:1}
  .card label{font-size:10px;font-weight:900;letter-spacing:1.2px;opacity:.6}
  .card.pink{background:#ffd6e1}.card.yellow{background:#fff1a8}.card.white{background:#fff}
  .lives{font-size:16px;letter-spacing:1px}
  .stage{position:relative;flex:1;min-height:0;display:flex;align-items:center;justify-content:center}
  .frame{position:relative;width:100%;max-width:860px;background:#2b1332;border:3.5px solid #3d1f2a;border-radius:22px;box-shadow:8px 8px 0 #3d1f2a, 0 20px 50px rgba(255,59,110,.25);overflow:hidden}
  canvas{display:block;width:100%;height:auto;aspect-ratio:800/580;touch-action:none;cursor:none;background:linear-gradient(180deg,#3a1a4d 0%,#5b245e 52%,#8a2f5b 100%)}
  @media(max-width:640px){canvas{cursor:default}}
  /* overlay */
  #overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;background:linear-gradient(180deg,rgba(43,19,50,.55),rgba(43,19,50,.78));backdrop-filter:blur(2px);z-index:5;padding:20px;transition:opacity .35s;color:#fff;cursor:pointer}
  #overlay.hide{opacity:0;pointer-events:none}
  .big-burger{font-size:76px;line-height:1;animation:bounce 1s ease-in-out infinite;filter:drop-shadow(0 8px 0 rgba(0,0,0,.25))}
  @keyframes bounce{0%,100%{transform:translateY(0) rotate(-3deg)}50%{transform:translateY(-12px) rotate(3deg)}}
  #overlay h2{font-size:clamp(26px,6vw,44px);font-weight:900;line-height:.95;margin:10px 0 6px;text-shadow:3px 3px 0 #ff3b6e}
  #overlay p{font-size:15px;font-weight:700;opacity:.92;max-width:520px;line-height:1.4}
  .pill{display:inline-flex;gap:6px;align-items:center;background:#ffdf3d;color:#3d1f2a;border:2.5px solid #3d1f2a;border-radius:999px;padding:10px 18px;font-weight:900;font-size:15px;box-shadow:3px 3px 0 #3d1f2a;margin-top:16px;animation:pulse 1.2s infinite}
  @keyframes pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.05)}}
  .mini-row{display:flex;gap:8px;margin-top:14px;flex-wrap:wrap;justify-content:center}
  .mini{background:rgba(255,255,255,.95);color:#3d1f2a;border-radius:999px;padding:6px 11px;font-size:12px;font-weight:800;border:2px solid #3d1f2a}
  /* bottom bar */
  footer{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap}
  .hint{font-size:12px;font-weight:800;opacity:.7}
  .btns{display:flex;gap:8px}
  button{font-family:inherit;font-weight:900;font-size:13px;border:2.5px solid #3d1f2a;border-radius:999px;padding:8px 14px;background:#fff;box-shadow:3px 3px 0 #3d1f2a;cursor:pointer;transition:transform .08s, box-shadow .08s}
  button:active{transform:translate(2px,2px);box-shadow:1px 1px 0 #3d1f2a}
  button.primary{background:#ff3b6e;color:#fff}
  button.yellow{background:#ffdf3d}
  #toast{position:absolute;left:50%;top:14px;transform:translateX(-50%) translateY(-8px);background:#fff;border:2.5px solid #3d1f2a;border-radius:999px;padding:7px 14px;font-weight:900;font-size:13px;box-shadow:3px 3px 0 #3d1f2a;opacity:0;pointer-events:none;transition:.25s;z-index:6;white-space:nowrap}
  #toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
</style>
</head>
<body>
<div id="bg"></div>
<div class="wrap">
  <header>
    <div class="logo">
      <div class="logo-emoji">🍔</div>
      <div>
        <h1>HAMBURGER<br><span>HEART BREAKOUT</span></h1>
        <div class="sub">EVERY BRICK BURSTS INTO HEARTS 💖</div>
      </div>
    </div>
    <div class="stats">
      <div class="card pink"><label>SCORE</label><b id="score">0</b></div>
      <div class="card yellow"><label>💖 HEARTS</label><b id="hearts">0</b></div>
      <div class="card white"><label>LIVES</label><b class="lives" id="lives">🍔🍔🍔</b></div>
      <div class="card white"><label>LEVEL</label><b id="level">1</b></div>
    </div>
  </header>

  <div class="stage">
    <div class="frame" id="frame">
      <canvas id="game" width="800" height="580"></canvas>
      <div id="toast">+100 ❤️</div>
      <div id="overlay">
        <div class="big-burger">🍔💥💖</div>
        <h2>CLICK TO PLAY!</h2>
        <p>The paddle is a <b style="color:#ffdf3d">hamburger</b>. Smash the bricks —<br>each one explodes into <b style="color:#ff9ec0">TONS of little hearts!</b></p>
        <div class="pill">👆 CLICK or PRESS ANY KEY TO START</div>
        <div class="mini-row">
          <span class="mini">🖱️ Mouse / Touch to move</span>
          <span class="mini">⌨️ ← → or A / D</span>
          <span class="mini">⏸️ Space = Pause</span>
          <span class="mini">🤖 Demo AI is playing now</span>
        </div>
      </div>
    </div>
  </div>

  <footer>
    <div class="hint">💡 Tip: Hit the ball with the edges of the burger for a sharper angle!</div>
    <div class="btns">
      <button id="pauseBtn">⏸ Pause</button>
      <button id="resetBtn" class="yellow">↺ Restart</button>
      <button id="startBtn" class="primary">▶ Start Game</button>
    </div>
  </footer>
</div>

<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const W = 800, H = 580;
const $ = id => document.getElementById(id);
const scoreEl=$('score'), heartsEl=$('hearts'), livesEl=$('lives'), levelEl=$('level'), overlay=$('overlay'), toast=$('toast');

let demo = true, paused=false, started=false;
let score=0, heartCount=0, lives=3, level=1;
let keys={}, mouseX=W/2, shake=0, flash=0, combo=0, comboTimer=0;

const paddle = {x:W/2, y:H-42, w:124, h:46, vx:0, tx:W/2};
const ball = {x:W/2, y:H-90, r:9, vx:4.2, vy:-5.2, trail:[]};
let bricks=[], particles=[], floaters=[], ambient=[];

const rowColors = [
  {c:'#ff3b6e', d:'#d61e52'}, {c:'#ff8a3d', d:'#e06a1f'}, {c:'#ffd93d', d:'#e0b91f'},
  {c:'#6be15e', d:'#3fb33a'}, {c:'#3ec6ff', d:'#1a9ed6'}, {c:'#b78cff', d:'#8a5fe6'}
];
const heartColors = ['#ff3b6e','#ff6b9d','#ff8fae','#ffb3c6','#ffdf3d','#ffffff','#ff5c7a','#ff2e63'];

function makeBricks(lv){
  bricks=[];
  const rows = Math.min(5+lv, 8);
  const cols = 10;
  const gap=6, top=58, bw=(W-40-(cols-1)*gap)/cols, bh=22;
  for(let r=0;r<rows;r++){
    for(let c=0;c<cols;c++){
      // checker holes for variety on higher levels
      if(lv>1 && (r===rows-1 && (c===2||c===7))) continue;
      bricks.push({x:20+c*(bw+gap), y:top+r*(bh+gap), w:bw, h:bh, hp: (lv>2 && r===0 && c%3===0)?2:1, col:rowColors[r%rowColors.length], dead:false, pop:0});
    }
  }
}
function resetBall(){
  ball.x=paddle.x; ball.y=paddle.y-34; const a=-Math.PI/2 + (Math.random()-.5)*.6; const s=6.2+level*.3;
  ball.vx=Math.cos(a)*s; ball.vy=Math.sin(a)*s; ball.trail=[];
}
function resetGame(){
  score=0; heartCount=0; lives=3; level=1; combo=0;
  makeBricks(1); resetBall(); particles=[]; floaters=[]; updateHUD();
}
function updateHUD(){
  scoreEl.textContent=score; heartsEl.textContent=heartCount; levelEl.textContent=level;
  livesEl.textContent = '🍔'.repeat(Math.max(0,lives)) || '—';
  if(lives===0) livesEl.textContent='💔';
}
function showToast(txt){ toast.textContent=txt; toast.classList.add('show'); clearTimeout(showToast.t); showToast.t=setTimeout(()=>toast.classList.remove('show'),1100); }

/* ---------- HEARTS ---------- */
function drawHeart(x,y,s,rot,color,alpha){
  ctx.save(); ctx.translate(x,y); ctx.rotate(rot); ctx.globalAlpha=alpha;
  ctx.fillStyle=color; ctx.beginPath();
  const u=s/16;
  ctx.moveTo(0, 6*u);
  ctx.bezierCurveTo(-10*u,-2*u, -6*u,-9*u, 0,-4.5*u);
  ctx.bezierCurveTo( 6*u,-9*u, 10*u,-2*u, 0, 6*u);
  ctx.fill();
  // highlight
  ctx.fillStyle='rgba(255,255,255,.55)'; ctx.beginPath(); ctx.ellipse(-3.2*u,-3.5*u,2.2*u,1.3*u,-.6,0,Math.PI*2); ctx.fill();
  ctx.restore();
}
function explodeHearts(x,y,count,power=1){
  for(let i=0;i<count;i++){
    const a=Math.random()*Math.PI*2, sp=(1.5+Math.random()*5.5)*power;
    particles.push({
      x:x+(Math.random()-.5)*30, y:y+(Math.random()-.5)*14,
      vx:Math.cos(a)*sp, vy:Math.sin(a)*sp - 2.2,
      s:5+Math.random()*13, rot:(Math.random()-.5)*1.4, vr:(Math.random()-.5)*.22,
      life:1, decay:.008+Math.random()*.012, color:heartColors[Math.floor(Math.random()*heartColors.length)],
      grav: .06+Math.random()*.05
    });
  }
}
function breakBrick(b){
  b.dead=true; combo++; comboTimer=90;
  const pts = 50 + combo*10;
  score+=pts; heartCount+= 26;
  explodeHearts(b.x+b.w/2, b.y+b.h/2, 28, 1);
  explodeHearts(b.x+b.w/2, b.y+b.h/2, 12, .7);
  floaters.push({x:b.x+b.w/2,y:b.y,txt:'+'+pts+' 💖',life:1});
  shake=Math.min(7,shake+2.5); flash=.25;
  if(combo>=3) showToast('🔥 COMBO x'+combo+'  +'+pts+' ❤️');
  updateHUD();
  if(bricks.every(x=>x.dead)){
    level++; score+=250; makeBricks(level);
    explodeHearts(W/2,140,70,1.4);
    showToast('🎉 LEVEL '+level+'! +250 bonus');
    updateHUD();
  }
}

/* ---------- HAMBURGER PADDLE ---------- */
function drawBurger(x,y,w,h){
  const bob = Math.sin(Date.now()/180)*1.2;
  y+=bob;
  ctx.save(); ctx.translate(x,y);
  ctx.shadowColor='rgba(0,0,0,.35)'; ctx.shadowBlur=10; ctx.shadowOffsetY=5;
  // bottom bun
  ctx.fillStyle='#e8a04c'; rr(-w/2,-h/2+22,w,16,8); ctx.fill();
  ctx.fillStyle='#c97d2a'; rr(-w/2,-h/2+22,w,5,3); ctx.fill();
  // patty
  ctx.fillStyle='#6b3a1f'; rr(-w/2+3,-h/2+16,w-6,10,5); ctx.fill();
  ctx.fillStyle='#8a4f2a'; rr(-w/2+3,-h/2+16,w-6,4,2); ctx.fill();
  // cheese drips
  ctx.fillStyle='#ffcc00';
  rr(-w/2+2,-h/2+10,w-4,7,3); ctx.fill();
  ctx.beginPath(); ctx.moveTo(-w/2+14,-h/2+16); ctx.lineTo(-w/2+22,-h/2+24); ctx.lineTo(-w/2+30,-h/2+16); ctx.fill();
  ctx.beginPath(); ctx.moveTo(w/2-30,-h/2+16); ctx.lineTo(w/2-22,-h/2+25); ctx.lineTo(w/2-14,-h/2+16); ctx.fill();
  // tomato
  ctx.fillStyle='#ff4d4d'; rr(-w/2+5,-h/2+6,w-10,6,3); ctx.fill();
  ctx.fillStyle='#ff8a8a'; rr(-w/2+8,-h/2+7,w-16,2,1); ctx.fill();
  // lettuce wavy
  ctx.fillStyle='#4ecb5a'; ctx.beginPath();
  const ly=-h/2+7;
  ctx.moveTo(-w/2+1,ly);
  for(let i=0;i<6;i++){ ctx.quadraticCurveTo(-w/2+ (i+.5)*(w/6), ly-5, -w/2+(i+1)*(w/6), ly); }
  ctx.lineTo(w/2-1,ly+4); ctx.lineTo(-w/2+1,ly+4); ctx.closePath(); ctx.fill();
  // top bun
  ctx.shadowBlur=0; ctx.shadowOffsetY=0;
  const g=ctx.createLinearGradient(0,-h/2-4,0,ly+2); g.addColorStop(0,'#ffc46b'); g.addColorStop(1,'#e8973a');
  ctx.fillStyle=g; ctx.beginPath();
  ctx.moveTo(-w/2, ly+1);
  ctx.bezierCurveTo(-w/2,-h/2-8, -w/4,-h/2-10, 0,-h/2-10);
  ctx.bezierCurveTo(w/4,-h/2-10, w/2,-h/2-8, w/2,ly+1);
  ctx.closePath(); ctx.fill();
  // sesame
  ctx.fillStyle='#fff3d6';
  [[-28,-14],[-10,-18],[12,-16],[30,-12],[0,-11],[-20,-9],[20,-8]].forEach(p=>{ ctx.beginPath(); ctx.ellipse(p[0],p[1],4,2.2,.5,0,Math.PI*2); ctx.fill(); });
  // cute face
  ctx.fillStyle='#3d1f2a';
  ctx.beginPath(); ctx.arc(-14,-2,2.2,0,Math.PI*2); ctx.fill();
  ctx.beginPath(); ctx.arc(14,-2,2.2,0,Math.PI*2); ctx.fill();
  ctx.strokeStyle='#3d1f2a'; ctx.lineWidth=1.8; ctx.beginPath(); ctx.arc(0,0,5, .15*Math.PI, .85*Math.PI); ctx.stroke();
  ctx.fillStyle='rgba(255,120,150,.55)'; ctx.beginPath(); ctx.ellipse(-22,2,5,3,0,0,Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.ellipse(22,2,5,3,0,0,Math.PI*2); ctx.fill();
  ctx.restore();
}
function rr(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(); }

/* ---------- GAME LOOP ---------- */
function update(){
  // paddle
  if(demo){
    const target = ball.vy>0 ? ball.x : W/2 + Math.sin(Date.now()/600)*90;
    paddle.tx += (target - paddle.tx)*.14;
    if(Math.abs(ball.x-paddle.x)<6 && ball.vy>0) paddle.tx=ball.x;
  } else {
    if(keys['ArrowLeft']||keys['a']) paddle.tx-=10;
    if(keys['ArrowRight']||keys['d']) paddle.tx+=10;
    paddle.tx = mouseX;
  }
  paddle.tx = Math.max(paddle.w/2, Math.min(W-paddle.w/2, paddle.tx));
  paddle.vx = paddle.tx - paddle.x;
  paddle.x += paddle.vx*.38;
  paddle.x = Math.max(paddle.w/2, Math.min(W-paddle.w/2, paddle.x));

  if(!paused){
    ball.trail.push({x:ball.x,y:ball.y}); if(ball.trail.length>10) ball.trail.shift();
    ball.x+=ball.vx; ball.y+=ball.vy;
    if(ball.x<ball.r+4){ball.x=ball.r+4; ball.vx*=-1;}
    if(ball.x>W-ball.r-4){ball.x=W-ball.r-4; ball.vx*=-1;}
    if(ball.y<ball.r+4){ball.y=ball.r+4; ball.vy*=-1;}

    // paddle collision
    if(ball.vy>0 && Math.abs(ball.x-paddle.x)<paddle.w/2+ball.r && Math.abs(ball.y-(paddle.y-6))<16){
      const rel=(ball.x-paddle.x)/(paddle.w/2);
      const ang=-Math.PI/2 + rel*.95;
      const sp=Math.min(11, Math.hypot(ball.vx,ball.vy)+.15);
      ball.vx=Math.cos(ang)*sp; ball.vy=Math.sin(ang)*sp;
      ball.y=paddle.y-22; combo=0;
      explodeHearts(ball.x,ball.y,6,.5);
    }
    // bricks
    for(const b of bricks){
      if(b.dead) 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){
        const overlapL = (ball.x+ball.r)-b.x, overlapR=(b.x+b.w)-(ball.x-ball.r);
        const overlapT = (ball.y+ball.r)-b.y, overlapB=(b.y+b.h)-(ball.y-ball.r);
        const min=Math.min(overlapL,overlapR,overlapT,overlapB);
        if(min===overlapT||min===overlapB) ball.vy*=-1; else ball.vx*=-1;
        if(b.hp>1){ b.hp--; b.pop=1; explodeHearts(ball.x,ball.y,10,.6); score+=10; updateHUD(); }
        else breakBrick(b);
        break;
      }
    }
    if(ball.y>H+20){
      lives--; combo=0; updateHUD();
      if(lives<=0){ showToast('💔 GAME OVER — Restarting!'); setTimeout(()=>{resetGame(); resetBall();},900); }
      else { showToast('💔 Ouch! '+lives+' burger'+(lives>1?'s':'')+' left'); resetBall(); }
      ball.y=H-90;
    }
    if(comboTimer>0){comboTimer--; if(comboTimer===0) combo=0;}
  }
  // particles
  for(let i=particles.length-1;i>=0;i--){
    const p=particles[i]; p.x+=p.vx; p.y+=p.vy; p.vy+=p.grav; p.vx*=.985; p.rot+=p.vr; p.life-=p.decay;
    if(p.life<=0) particles.splice(i,1);
  }
  for(let i=floaters.length-1;i>=0;i--){ const f=floaters[i]; f.y-=1.1; f.life-=.018; if(f.life<=0) floaters.splice(i,1); }
  for(const b of bricks) if(b.pop>0) b.pop-=.08;
  if(shake>0) shake*=.85; if(flash>0) flash-=.02;
  // ambient hearts
  if(Math.random()<.12) ambient.push({x:Math.random()*W,y:H+20,s:6+Math.random()*10,vy:-(.6+Math.random()*1.2),vx:(Math.random()-.5)*.4,rot:Math.random()*6,vr:(Math.random()-.5)*.03,c:heartColors[Math.floor(Math.random()*heartColors.length)]});
  for(let i=ambient.length-1;i>=0;i--){ const a=ambient[i]; a.x+=a.vx; a.y+=a.vy; a.rot+=a.vr; if(a.y<-30) ambient.splice(i,1); }
}

function draw(){
  ctx.save();
  if(shake>.4) ctx.translate((Math.random()-.5)*shake,(Math.random()-.5)*shake);
  // bg deco
  ctx.fillStyle='rgba(255,255,255,.05)';
  for(let i=0;i<5;i++){ ctx.beginPath(); ctx.arc(100+i*160, 500-((i*37)%120), 50,0,Math.PI*2); ctx.fill(); }
  ctx.fillStyle='rgba(255,223,61,.08)'; ctx.font='28px serif'; ctx.fillText('🍔', 30, 320); ctx.fillText('🍔', 740, 180);
  for(const a of ambient) drawHeart(a.x,a.y,a.s,a.rot,a.c,.35);

  // bricks
  for(const b of bricks){
    if(b.dead) continue;
    const s=1+Math.max(0,b.pop)*.08;
    ctx.save(); ctx.translate(b.x+b.w/2,b.y+b.h/2); ctx.scale(s,s); ctx.translate(-b.w/2,-b.h/2);
    ctx.shadowColor='rgba(0,0,0,.3)'; ctx.shadowBlur=5; ctx.shadowOffsetY=3;
    ctx.fillStyle=b.col.c; rr(0,0,b.w,b.h,7); ctx.fill();
    ctx.shadowBlur=0; ctx.fillStyle='rgba(255,255,255,.35)'; rr(3,3,b.w-6,7,4); ctx.fill();
    ctx.fillStyle='rgba(0,0,0,.12)'; rr(3,b.h-7,b.w-6,4,2); ctx.fill();
    ctx.font='11px serif'; ctx.textAlign='center'; ctx.fillText(b.hp>1?'💖':'❤️', b.w/2, b.h/2+4);
    ctx.restore();
  }
  // ball trail
  ball.trail.forEach((t,i)=>{ ctx.globalAlpha=i/ball.trail.length*.35; drawHeart(t.x,t.y,10+i*.6,0,'#ff8fae',i/ball.trail.length*.4); });
  ctx.globalAlpha=1;
  // ball as mini heart orb
  ctx.save(); ctx.shadowColor='#ff3b6e'; ctx.shadowBlur=16;
  const bg=ctx.createRadialGradient(ball.x-3,ball.y-3,1,ball.x,ball.y,ball.r+4); bg.addColorStop(0,'#fff'); bg.addColorStop(.4,'#ff6b9d'); bg.addColorStop(1,'#ff2e63');
  ctx.fillStyle=bg; ctx.beginPath(); ctx.arc(ball.x,ball.y,ball.r,0,Math.PI*2); ctx.fill(); ctx.restore();
  drawHeart(ball.x,ball.y-1,13,Math.sin(Date.now()/200)*.15,'#ffffff',.95);

  // paddle
  drawBurger(paddle.x,paddle.y,paddle.w,paddle.h);

  // particles on top
  for(const p of particles) drawHeart(p.x,p.y,p.s,p.rot,p.color,Math.max(0,p.life));
  // floaters
  ctx.font='900 16px ui-rounded, system-ui'; ctx.textAlign='center';
  for(const f of floaters){ ctx.globalAlpha=Math.max(0,f.life); ctx.fillStyle='#fff'; ctx.strokeStyle='#3d1f2a'; ctx.lineWidth=3; ctx.strokeText(f.txt,f.x,f.y); ctx.fillText(f.txt,f.x,f.y); }
  ctx.globalAlpha=1;
  if(flash>0){ ctx.fillStyle=`rgba(255,150,180,${flash})`; ctx.fillRect(0,0,W,H); }
  // demo label
  if(demo){ ctx.fillStyle='rgba(255,255,255,.9)'; ctx.font='800 11px system-ui'; ctx.textAlign='left'; ctx.fillText('🤖 DEMO MODE — click to play',12,H-10); }
  if(paused && !demo){ ctx.fillStyle='rgba(0,0,0,.45)'; ctx.fillRect(0,0,W,H); ctx.fillStyle='#fff'; ctx.font='900 34px system-ui'; ctx.textAlign='center'; ctx.fillText('⏸ PAUSED',W/2,H/2); }
  ctx.restore();
}
function loop(){ update(); draw(); requestAnimationFrame(loop); }

/* ---------- INPUT ---------- */
function startGame(){
  if(started && !demo) return;
  demo=false; started=true; overlay.classList.add('hide');
  resetGame(); resetBall(); showToast('🍔 GO! Smash for HEARTS 💖');
}
overlay.addEventListener('click',startGame);
document.addEventListener('keydown',e=>{
  keys[e.key]=true;
  if(!started) startGame();
  if(e.key===' '){ e.preventDefault(); if(started){paused=!paused; $('pauseBtn').textContent=paused?'▶ Resume':'⏸ Pause';} }
});
document.addEventListener('keyup',e=>keys[e.key]=false);
function toGameX(clientX){ const r=canvas.getBoundingClientRect(); return (clientX-r.left)/r.width*W; }
canvas.addEventListener('mousemove',e=>{ mouseX=toGameX(e.clientX); if(!started) startGame(); });
canvas.addEventListener('touchmove',e=>{ mouseX=toGameX(e.touches[0].clientX); if(!started) startGame(); e.preventDefault(); },{passive:false});
canvas.addEventListener('touchstart',e=>{ mouseX=toGameX(e.touches[0].clientX); if(!started) startGame(); },{passive:true});
$('startBtn').addEventListener('click',startGame);
$('pauseBtn').addEventListener('click',()=>{ if(!started) return startGame(); paused=!paused; $('pauseBtn').textContent=paused?'▶ Resume':'⏸ Pause'; });
$('resetBtn').addEventListener('click',()=>{ if(!started) startGame(); resetGame(); resetBall(); paused=false; $('pauseBtn').textContent='⏸ Pause'; showToast('↺ Restarted!'); });

/* ambient bg hearts */
const bg=document.getElementById('bg');
for(let i=0;i<14;i++){ const d=document.createElement('div'); d.className='bg-heart'; d.textContent=['💖','❤️','💕','🍔'][i%4]; d.style.left=Math.random()*100+'vw'; d.style.fontSize=(14+Math.random()*22)+'px'; d.style.animationDuration=(9+Math.random()*14)+'s'; d.style.animationDelay=(-Math.random()*14)+'s'; bg.appendChild(d); }

makeBricks(1); updateHUD(); loop();
</script>
</body>
</html>
Reasoning trace (657 tokens)
Implementing a single-file canvas breakout with hamburger paddle, heart particles on brick break, demo autopilot, and responsive UI.