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
39.2 s
Cost
$0.011
Output tokens
21,679
Spent thinking
9,307 tokens
Speed
575.6 tok/s
Console errors
0
First token after
1.5 s
First visible text after
24.1 s
Prompt tokens
375
Code size
35.8 KB
Finish reason
stop
Served by
Meta
Model id
meta/muse-ember
Reasoning sent
model default
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 · 875 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hamburger Breakout — Heart Burst Edition</title>
<style>
  *{box-sizing:border-box}
  html,body{margin:0;padding:0}
  body{
    font-family: ui-rounded, "Segoe UI", system-ui, -apple-system, Arial, sans-serif;
    background:
      radial-gradient(circle at 15% 20%, rgba(255,77,109,.14) 0 120px, transparent 121px),
      radial-gradient(circle at 85% 15%, rgba(255,197,61,.22) 0 140px, transparent 141px),
      linear-gradient(180deg,#FFF8E7 0%, #FFE5EC 55%, #FFF0D6 100%);
    color:#161616;
    min-height:100vh;
    overflow-x:hidden;
  }
  .wrap{max-width:1240px;margin:0 auto;padding:16px 16px 22px}
  header{display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap;margin-bottom:16px}
  .logo h1{margin:0;font-size:clamp(28px,4.2vw,44px);line-height:.95;font-weight:900;letter-spacing:.5px;text-shadow:3px 3px 0 #FFD166}
  .logo h1 span{color:#FF2E4D}
  .logo p{margin:6px 0 0;font-weight:800;letter-spacing:3px;font-size:12px;color:#7a3b12}
  .logo p b{background:#161616;color:#FFD166;padding:3px 8px;border-radius:999px;letter-spacing:2px}
  .stats{display:flex;gap:10px;flex-wrap:wrap}
  .stat{background:#fff;border:3px solid #161616;border-radius:14px;box-shadow:4px 4px 0 #161616;padding:8px 14px;min-width:98px;text-align:center}
  .stat label{display:block;font-size:10px;font-weight:900;letter-spacing:2px;color:#888}
  .stat strong{display:block;font-size:23px;line-height:1.1;font-weight:900}
  .stat .lives{color:#FF2E4D;font-size:20px;letter-spacing:2px}
  main{display:grid;grid-template-columns:1fr 284px;gap:18px;align-items:start}
  @media(max-width:920px){main{grid-template-columns:1fr}}
  .game-shell{position:relative;background:#fff;border:4px solid #161616;border-radius:22px;box-shadow:8px 8px 0 #161616;overflow:hidden}
  canvas{width:100%;display:block;aspect-ratio:820/560;background:linear-gradient(180deg,#FFF8E7,#FFE5EC);touch-action:none;cursor:crosshair}
  .badge{position:absolute;top:12px;left:12px;display:flex;align-items:center;gap:7px;background:#161616;color:#fff;font-weight:900;font-size:11px;letter-spacing:1.6px;padding:7px 11px;border-radius:999px;border:2px solid #fff;box-shadow:3px 3px 0 rgba(0,0,0,.25);z-index:5}
  .dot{width:9px;height:9px;background:#FF2E4D;border-radius:50%;animation:pulse 1s infinite}
  @keyframes pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.5)}}
  .badge.manual .dot{background:#2ED573}
  #overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(255,248,231,.28);z-index:6;cursor:pointer;padding:16px}
  #overlay.hidden{display:none}
  .card{background:#fff;border:3px solid #161616;border-radius:18px;box-shadow:6px 6px 0 #161616;padding:18px 22px;max-width:470px;width:92%;text-align:center}
  .card h2{margin:0 0 6px;font-size:26px;font-weight:900}
  .card h2 span{color:#FF2E4D}
  .card p{margin:0 0 12px;font-weight:700;color:#555;line-height:1.4}
  .card .big{font-size:13px;letter-spacing:2px;font-weight:900;background:#FFD166;display:inline-block;padding:7px 12px;border:2px solid #161616;border-radius:999px;box-shadow:3px 3px 0 #161616}
  .card small{display:block;margin-top:10px;font-weight:800;color:#999;letter-spacing:1px}
  .controls{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}
  button{font:inherit;font-weight:900;letter-spacing:.5px;background:#FFD166;color:#161616;border:3px solid #161616;border-radius:12px;padding:10px 16px;box-shadow:4px 4px 0 #161616;cursor:pointer;transition:transform .06s, box-shadow .06s}
  button:active{transform:translate(3px,3px);box-shadow:1px 1px 0 #161616}
  button.red{background:#FF2E4D;color:#fff}
  button.white{background:#fff}
  button.pink{background:#FF8FAB}
  .hint{margin-top:10px;font-weight:800;color:#8a6a4a;font-size:13px;text-align:center}
  .hint kbd{background:#161616;color:#fff;padding:2px 7px;border-radius:6px;font-size:11px}
  aside{display:flex;flex-direction:column;gap:14px}
  .panel{background:#fff;border:3px solid #161616;border-radius:16px;box-shadow:5px 5px 0 #161616;padding:16px}
  .panel h3{margin:0 0 10px;font-size:15px;letter-spacing:1.5px;font-weight:900}
  .panel p{margin:0 0 10px;line-height:1.5;color:#444;font-weight:600;font-size:14px}
  .panel ul{margin:0;padding-left:18px;line-height:1.7;font-weight:700;color:#333;font-size:14px}
  .heart-num{font-size:38px;font-weight:900;color:#FF2E4D;line-height:1;text-align:center}
  .heart-num small{display:block;font-size:11px;letter-spacing:2px;color:#888;margin-top:4px}
  .bar{height:16px;background:#FFE5EC;border:3px solid #161616;border-radius:999px;overflow:hidden;margin-top:10px}
  .bar i{display:block;height:100%;width:0%;background:linear-gradient(90deg,#FF2E4D,#FF8FAB,#FFD166);transition:width .2s}
  .bar-label{display:flex;justify-content:space-between;font-size:11px;font-weight:900;letter-spacing:1px;color:#888;margin-top:6px}
  .pow{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:2px dashed #FFE5EC;font-weight:800;font-size:14px}
  .pow:last-child{border-bottom:none}
  .pow .ic{width:34px;height:34px;flex:0 0 34px;display:grid;place-items:center;border:2px solid #161616;border-radius:50%;font-weight:900;color:#fff}
  .toast{background:#FFF3CD;border:2px dashed #FFB703;border-radius:10px;padding:9px 10px;font-weight:900;font-size:13px;text-align:center;color:#7a4a00}
  footer{text-align:center;margin-top:16px;font-weight:800;color:#a07a5a;font-size:13px;letter-spacing:.5px}
  @media(max-width:420px){
    .wrap{padding:10px}
    .stat{min-width:78px;padding:6px 10px}
    .stat strong{font-size:19px}
    .card{padding:14px}
    .card h2{font-size:21px}
  }
</style>
</head>
<body>
<div class="wrap">
  <header>
    <div class="logo">
      <h1>HAMBURGER<br><span>BREAKOUT</span> ♥</h1>
      <p><b>HEART-BURST</b> EDITION</p>
    </div>
    <div class="stats">
      <div class="stat"><label>SCORE</label><strong id="score">0</strong></div>
      <div class="stat"><label>LEVEL</label><strong id="level">1</strong></div>
      <div class="stat"><label>LIVES</label><strong class="lives" id="lives">♥♥♥</strong></div>
      <div class="stat"><label>BEST</label><strong id="best">0</strong></div>
    </div>
  </header>

  <main>
    <section>
      <div class="game-shell">
        <canvas id="game" width="820" height="560"></canvas>
        <div class="badge" id="badge"><span class="dot"></span><span id="badgeText">AUTO DEMO</span></div>
        <div id="overlay">
          <div class="card">
            <h2 id="ovTitle">DEMO MODE <span>♥</span></h2>
            <p id="ovSub">The hamburger is auto-playing! Every brick you break explodes into tons of little hearts.</p>
            <span class="big" id="ovBtn">▶ CLICK OR PRESS A KEY TO START</span>
            <small>MOUSE / TOUCH / ← → TO MOVE &nbsp;•&nbsp; SPACE TO LAUNCH</small>
          </div>
        </div>
      </div>

      <div class="controls">
        <button class="red" id="btnPause">⏸ PAUSE</button>
        <button id="btnLaunch">🚀 LAUNCH BALL</button>
        <button class="white" id="btnRestart">↺ RESTART</button>
        <button class="pink" id="btnSound">🔊 SOUND ON</button>
      </div>
      <div class="hint"><kbd>←</kbd> <kbd>→</kbd> or mouse to move the burger &nbsp; <kbd>SPACE</kbd> launch &nbsp; <kbd>P</kbd> pause &nbsp; Catch <span style="color:#FF2E4D">golden hearts</span> for power-ups!</div>
    </section>

    <aside>
      <div class="panel">
        <h3>💖 HEART BURST METER</h3>
        <div class="heart-num"><span id="heartsCount">0</span><small>LITTLE HEARTS EXPLODED</small></div>
        <div class="bar"><i id="progFill"></i></div>
        <div class="bar-label"><span>BRICKS BROKEN</span><span id="progText">0%</span></div>
      </div>

      <div class="panel">
        <h3>🍔 HOW TO PLAY</h3>
        <ul>
          <li>Move the <b>hamburger paddle</b> to bounce the cherry ball.</li>
          <li>Break every brick to clear the level.</li>
          <li>Each brick <b style="color:#FF2E4D">explodes into 30+ hearts</b> — chain breaks for combo points!</li>
          <li>Don't let the ball fall. You have 3 lives.</li>
        </ul>
      </div>

      <div class="panel">
        <h3>✨ GOLDEN HEART POWER-UPS</h3>
        <div class="pow"><span class="ic" style="background:#FF9F1A">W</span> BIG BURGER — wider paddle</div>
        <div class="pow"><span class="ic" style="background:#4D96FF">S</span> SLOW KETCHUP — slower ball</div>
        <div class="pow"><span class="ic" style="background:#FF2E4D">♥</span> EXTRA LIFE — one more heart</div>
        <div class="pow"><span class="ic" style="background:#9B5DE5">★</span> BONUS — instant +250 pts</div>
      </div>

      <div class="panel">
        <h3>📣 LAST POWER-UP</h3>
        <div class="toast" id="toast">Catch a golden heart to power up!</div>
      </div>
    </aside>
  </main>
  <footer>Every brick = a burst of love. Made with canvas, hearts &amp; 100% beef. ♥</footer>
</div>

<script>
(() => {
  const canvas = document.getElementById('game');
  const ctx = canvas.getContext('2d');
  const W = 820, H = 560;
  let dpr = 1;

  const scoreEl = document.getElementById('score');
  const levelEl = document.getElementById('level');
  const livesEl = document.getElementById('lives');
  const bestEl = document.getElementById('best');
  const heartsEl = document.getElementById('heartsCount');
  const progFill = document.getElementById('progFill');
  const progText = document.getElementById('progText');
  const overlay = document.getElementById('overlay');
  const ovTitle = document.getElementById('ovTitle');
  const ovSub = document.getElementById('ovSub');
  const ovBtn = document.getElementById('ovBtn');
  const badge = document.getElementById('badge');
  const badgeText = document.getElementById('badgeText');
  const toast = document.getElementById('toast');

  function resize(){
    dpr = Math.min(window.devicePixelRatio || 1, 2);
    canvas.width = W * dpr;
    canvas.height = H * dpr;
  }
  resize();
  window.addEventListener('resize', resize);

  // ---------- Audio ----------
  let audioCtx = null, muted = false;
  function ensureAudio(){
    if(!audioCtx){ try{ audioCtx = new (window.AudioContext||window.webkitAudioContext)(); }catch(e){} }
    if(audioCtx && audioCtx.state === 'suspended') audioCtx.resume();
  }
  function blip(f, dur=0.09, type='triangle', vol=0.07){
    if(muted || !audioCtx) return;
    try{
      const o = audioCtx.createOscillator(), g = audioCtx.createGain();
      o.type = type; o.frequency.value = f;
      g.gain.setValueAtTime(vol, audioCtx.currentTime);
      g.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + dur);
      o.connect(g); g.connect(audioCtx.destination);
      o.start(); o.stop(audioCtx.currentTime + dur);
    }catch(e){}
  }

  // ---------- Helpers ----------
  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();
  }
  const HEART_COLORS = ['#FF2E4D','#FF4D6D','#FF6B9D','#FF8FAB','#FFB3C1','#FFD166','#FF3B30'];
  function drawHeart(x,y,size,color,alpha,rot){
    ctx.save();
    ctx.translate(x,y); ctx.rotate(rot||0);
    ctx.globalAlpha = alpha;
    ctx.fillStyle = color;
    ctx.beginPath();
    ctx.moveTo(0, size*0.45);
    ctx.bezierCurveTo(-size*0.95, -size*0.25, -size*0.5, -size*0.95, 0, -size*0.35);
    ctx.bezierCurveTo( size*0.5, -size*0.95,  size*0.95, -size*0.25, 0, size*0.45);
    ctx.closePath(); ctx.fill();
    ctx.restore();
  }
  const rand = (a,b)=>a+Math.random()*(b-a);
  const clamp = (v,a,b)=>Math.max(a,Math.min(b,v));
  const pick = arr => arr[Math.floor(Math.random()*arr.length)];

  // ---------- Game State ----------
  let demo = true;
  let paused = false;
  let state = 'serve'; // serve | playing | over | levelclear
  let score = 0, best = 0, lives = 3, level = 1;
  let combo = 1, comboTimer = 0;
  let heartsBurst = 0;
  let shake = 0, time = 0;
  let stuckTimer = 1, overTimer = 0, levelTimer = 0;
  let speedBonus = 0;
  let wideTimer = 0, slowTimer = 0;
  let overlayMode = 'demo';

  const paddle = { x: W/2-56, y: H-42, w: 112, h: 40, baseW: 112, squash: 0 };
  const ball = { x: W/2, y: paddle.y-12, vx:0, vy:0, r: 10, stuck:true };
  let bricks = [], particles = [], floaters = [], powerups = [];
  let totalBricks = 0;
  let mouseTargetX = W/2, lastInput = 'mouse', useMouse = false;
  const keys = {};
  let trailTimer = 0;

  const ROW_COLORS = ['#FF4D6D','#FF8A3D','#FFC53D','#6BCB77','#4D96FF','#B983FF','#FF2E8A'];

  function buildLevel(lvl){
    bricks = [];
    const cols = 10;
    const rows = lvl === 1 ? 5 : Math.min(5 + Math.floor((lvl-1)/2), 6);
    const gap = 6, marginX = 30, marginY = 64;
    const bw = (W - marginX*2 - gap*(cols-1)) / cols;
    const bh = 22;
    for(let r=0;r<rows;r++){
      for(let c=0;c<cols;c++){
        let include = true;
        if(lvl % 3 === 2){
          // diamond-ish
          if(r===0 && (c<1||c>8)) include = false;
          if(r===rows-1 && (c<1||c>8)) include = false;
          if(c===0 && r>0 && r<rows-1 && (r+c)%2===0) include = false;
        } else if(lvl % 3 === 0 && lvl > 2){
          if(c % 3 === 2 && r % 2 === 1) include = false;
        }
        if(!include) continue;
        const hp = (lvl>=3 && r===0) ? 2 : (lvl>=4 && Math.random()<0.18 ? 2 : 1);
        bricks.push({
          x: marginX + c*(bw+gap),
          y: marginY + r*(bh+gap),
          w: bw, h: bh,
          color: ROW_COLORS[r % ROW_COLORS.length],
          hp, maxHp: hp, alive:true
        });
      }
    }
    totalBricks = bricks.length;
  }

  function currentSpeed(){
    let s = 345 + (level-1)*28;
    s = Math.min(s, 545) + speedBonus;
    if(slowTimer > 0) s *= 0.62;
    return s;
  }
  function normalizeBall(){
    const m = Math.hypot(ball.vx, ball.vy) || 1;
    const s = currentSpeed();
    ball.vx = ball.vx/m*s; ball.vy = ball.vy/m*s;
  }
  function resetBallToPaddle(){
    ball.x = paddle.x + paddle.w/2;
    ball.y = paddle.y - ball.r - 2;
    ball.vx = 0; ball.vy = 0; ball.stuck = true; state = 'serve';
  }
  function launch(){
    if(!ball.stuck) return;
    const ang = rand(-0.38, 0.38);
    const s = currentSpeed();
    ball.vx = Math.sin(ang)*s;
    ball.vy = -Math.cos(ang)*s;
    ball.stuck = false; state = 'playing';
    blip(520, .12, 'square', .06);
  }
  function resetGame(){
    score = 0; lives = 3; level = 1; combo = 1; comboTimer = 0;
    heartsBurst = 0; speedBonus = 0; wideTimer = 0; slowTimer = 0;
    paddle.w = paddle.baseW; paddle.x = W/2 - paddle.w/2;
    particles = []; floaters = []; powerups = [];
    buildLevel(1);
    resetBallToPaddle();
    stuckTimer = demo ? 0.9 : 999;
    updateHUD();
  }
  function nextLevel(){
    level++;
    buildLevel(level);
    speedBonus = 0;
    resetBallToPaddle();
    stuckTimer = demo ? 0.8 : 999;
    addFloater(W/2, 250, 'LEVEL ' + level + '!', '#FF2E4D', 30);
    updateHUD();
  }

  // ---------- Particles ----------
  function explode(x,y,baseColor,count=30,power=1){
    for(let i=0;i<count;i++){
      const a = Math.random()*Math.PI*2;
      const sp = rand(35, 260)*power;
      particles.push({
        type:'heart', x, y,
        vx: Math.cos(a)*sp, vy: Math.sin(a)*sp - 55,
        size: rand(4,13), rot: rand(-.6,.6), vr: rand(-3,3),
        color: Math.random()<0.35 ? baseColor : pick(HEART_COLORS),
        life:0, max: rand(0.95, 2.1), sway: rand(0, Math.PI*2)
      });
    }
    for(let i=0;i<8;i++){
      const a = Math.random()*Math.PI*2, sp = rand(60,200)*power;
      particles.push({type:'dot', x,y, vx:Math.cos(a)*sp, vy:Math.sin(a)*sp, size:rand(2,4), rot:0, vr:0, color:'#FFD166', life:0, max:rand(.4,.8), sway:0});
    }
    heartsBurst += count;
    if(particles.length > 650) particles.splice(0, particles.length-650);
  }
  function addFloater(x,y,text,color='#161616',size=18){
    floaters.push({x,y,text,color,size,life:0,max:1.15});
  }

  // ---------- Powerups ----------
  function maybeSpawnPowerup(x,y){
    if(Math.random() > 0.20) return;
    let type;
    const r = Math.random();
    if(r < 0.42) type='wide';
    else if(r < 0.74) type='slow';
    else if(r < 0.86 && lives < 5) type='life';
    else type='points';
    powerups.push({x,y,vy:135,type,rot:0,sway:rand(0,6)});
  }
  function applyPowerup(p){
    ensureAudio();
    if(p.type==='wide'){
      paddle.w = 160; wideTimer = 12;
      toast.textContent = '🍔 BIG BURGER! Wider paddle for 12s';
      addFloater(paddle.x+paddle.w/2, paddle.y-18, 'WIDE!', '#FF9F1A', 20);
      blip(700,.1,'square',.07); setTimeout(()=>blip(900,.12,'square',.07),90);
    } else if(p.type==='slow'){
      slowTimer = 8; normalizeBall();
      toast.textContent = '🍅 SLOW KETCHUP! Ball slowed for 8s';
      addFloater(paddle.x+paddle.w/2, paddle.y-18, 'SLOW!', '#4D96FF', 20);
      blip(440,.12,'sine',.08);
    } else if(p.type==='life'){
      lives = Math.min(5, lives+1);
      toast.textContent = '♥ EXTRA LIFE! +1 heart';
      addFloater(paddle.x+paddle.w/2, paddle.y-18, '+1 ♥', '#FF2E4D', 22);
      blip(880,.12,'triangle',.08); setTimeout(()=>blip(1100,.14,'triangle',.08),90);
    } else {
      score += 250;
      toast.textContent = '★ BONUS! +250 points';
      addFloater(paddle.x+paddle.w/2, paddle.y-18, '+250', '#9B5DE5', 20);
      blip(990,.1,'square',.06);
    }
    explode(p.x, p.y, '#FFD166', 16, 0.7);
    updateHUD();
  }

  // ---------- HUD / Overlay ----------
  function updateHUD(){
    scoreEl.textContent = score;
    levelEl.textContent = level;
    livesEl.textContent = '♥'.repeat(Math.max(0,lives)) + '♡'.repeat(Math.max(0, 3-lives));
    if(score > best){ best = score; }
    bestEl.textContent = best;
    heartsEl.textContent = heartsBurst;
    const alive = bricks.filter(b=>b.alive).length;
    const pct = totalBricks ? Math.round((totalBricks-alive)/totalBricks*100) : 0;
    progFill.style.width = pct + '%';
    progText.textContent = pct + '%';
  }
  function showOverlay(mode, title, sub, btn){
    overlayMode = mode;
    ovTitle.innerHTML = title;
    ovSub.textContent = sub;
    ovBtn.textContent = btn;
    overlay.classList.remove('hidden');
  }
  function hideOverlay(){ overlay.classList.add('hidden'); overlayMode='hidden'; }
  function setDemoUI(){
    badge.classList.toggle('manual', !demo);
    badgeText.textContent = demo ? 'AUTO DEMO' : 'YOU ARE PLAYING';
  }
  function startManual(){
    if(!demo && overlayMode==='hidden') return;
    ensureAudio();
    demo = false; paused = false;
    setDemoUI(); hideOverlay();
    resetGame();
    addFloater(W/2, 300, 'GO! BREAK THOSE BRICKS ♥', '#FF2E4D', 22);
  }

  // ---------- Input ----------
  function canvasX(e){
    const r = canvas.getBoundingClientRect();
    return (e.clientX - r.left) * (W / r.width);
  }
  canvas.addEventListener('pointermove', e=>{
    mouseTargetX = canvasX(e); lastInput='mouse'; useMouse=true;
  });
  canvas.addEventListener('pointerdown', e=>{
    ensureAudio();
    mouseTargetX = canvasX(e); lastInput='mouse'; useMouse=true;
    if(demo){ startManual(); return; }
    if(overlayMode==='demo'){ startManual(); return; }
    if(overlayMode==='over'){ startManual(); return; }
    if(overlayMode==='pause'){ paused=false; hideOverlay(); return; }
    if(ball.stuck) launch();
  });
  window.addEventListener('keydown', e=>{
    const k = e.key.toLowerCase();
    if(['arrowleft','arrowright',' '].includes(k) || e.key===' ') e.preventDefault();
    keys[k]=true; keys[e.key]=true;
    if(e.key==='ArrowLeft'||e.key==='ArrowRight'||k==='a'||k==='d') lastInput='keys';
    if(demo){ startManual(); return; }
    if(overlayMode==='over'){ startManual(); return; }
    if(overlayMode==='pause' && (k==='p'||e.key===' ')){ paused=false; hideOverlay(); return; }
    if(e.key===' '){ if(ball.stuck) launch(); }
    if(k==='p'){ togglePause(); }
    if(e.key==='Enter' && overlayMode!=='hidden'){ startManual(); }
  });
  window.addEventListener('keyup', e=>{ keys[e.key.toLowerCase()]=false; keys[e.key]=false; });
  overlay.addEventListener('click', ()=>{
    ensureAudio();
    if(overlayMode==='demo'||overlayMode==='over') startManual();
    else if(overlayMode==='pause'){ paused=false; hideOverlay(); }
  });
  function togglePause(){
    if(demo) return;
    paused = !paused;
    document.getElementById('btnPause').textContent = paused ? '▶ RESUME' : '⏸ PAUSE';
    if(paused) showOverlay('pause','PAUSED ⏸','Take a breath. The burger is waiting.','▶ CLICK TO RESUME');
    else hideOverlay();
  }
  document.getElementById('btnPause').addEventListener('click', ()=>{ ensureAudio(); togglePause(); });
  document.getElementById('btnLaunch').addEventListener('click', ()=>{
    ensureAudio();
    if(demo){ startManual(); return; }
    if(ball.stuck) launch();
  });
  document.getElementById('btnRestart').addEventListener('click', ()=>{
    ensureAudio();
    if(demo){ startManual(); return; }
    paused=false; document.getElementById('btnPause').textContent='⏸ PAUSE';
    hideOverlay(); resetGame();
  });
  document.getElementById('btnSound').addEventListener('click', function(){
    muted = !muted;
    this.textContent = muted ? '🔇 SOUND OFF' : '🔊 SOUND ON';
    if(!muted) ensureAudio();
  });

  // ---------- Update ----------
  function update(dt){
    time += dt;
    // timers
    if(comboTimer>0){ comboTimer-=dt; if(comboTimer<=0) combo=1; }
    if(wideTimer>0){ wideTimer-=dt; if(wideTimer<=0) paddle.w=paddle.baseW; }
    if(slowTimer>0){ slowTimer-=dt; if(slowTimer<=0) normalizeBall(); }
    shake = Math.max(0, shake - dt*14);
    paddle.squash = Math.max(0, paddle.squash - dt*6);

    // paddle control
    const center = paddle.x + paddle.w/2;
    if(demo){
      let target;
      if(ball.stuck) target = W/2 + Math.sin(time*0.9)*85;
      else if(ball.vy > 0) target = ball.x + ball.vx*0.16;
      else target = ball.x*0.65 + W*0.17;
      target += Math.sin(time*2.2)*5;
      const maxStep = 540*dt;
      const delta = clamp(target-center, -maxStep, maxStep);
      paddle.x += delta;
    } else {
      let moved = false;
      const spd = 560;
      if(keys['arrowleft']||keys['a']){ paddle.x -= spd*dt; moved=true; }
      if(keys['arrowright']||keys['d']){ paddle.x += spd*dt; moved=true; }
      if(moved){ mouseTargetX = paddle.x + paddle.w/2; }
      else if(useMouse){
        const desired = clamp(mouseTargetX - paddle.w/2, 6, W-paddle.w-6);
        paddle.x += (desired - paddle.x) * Math.min(1, dt*20);
      }
    }
    paddle.x = clamp(paddle.x, 6, W-paddle.w-6);

    // serve / state timers
    if(ball.stuck){
      ball.x = paddle.x + paddle.w/2;
      ball.y = paddle.y - ball.r - 2;
      if(demo){ stuckTimer-=dt; if(stuckTimer<=0) launch(); }
    }
    if(state==='over'){
      overTimer-=dt;
      if(overTimer<=0){
        if(demo){ resetGame(); }
        else showOverlay('over', 'GAME OVER <span>♥</span>', 'Final score: ' + score + '  •  Hearts burst: ' + heartsBurst + '. The burger believes in you!', '↺ CLICK TO PLAY AGAIN');
      }
    }
    if(state==='levelclear'){
      levelTimer-=dt;
      if(levelTimer<=0) nextLevel();
    }

    // ball physics
    if(!ball.stuck && state==='playing'){
      const prevX = ball.x, prevY = ball.y;
      ball.x += ball.vx*dt;
      ball.y += ball.vy*dt;

      // trail hearts
      trailTimer -= dt;
      if(trailTimer<=0){
        trailTimer = 0.07;
        particles.push({type:'heart', x:ball.x+rand(-4,4), y:ball.y+rand(-4,4), vx:rand(-12,12), vy:rand(8,28), size:rand(3,6), rot:rand(-.4,.4), vr:rand(-1,1), color:pick(HEART_COLORS), life:0, max:.55, sway:rand(0,6)});
      }

      // walls
      if(ball.x < ball.r){ ball.x=ball.r; ball.vx=Math.abs(ball.vx); blip(220,.05,'square',.04); }
      if(ball.x > W-ball.r){ ball.x=W-ball.r; ball.vx=-Math.abs(ball.vx); blip(220,.05,'square',.04); }
      if(ball.y < ball.r){ ball.y=ball.r; ball.vy=Math.abs(ball.vy); blip(220,.05,'square',.04); }

      // paddle
      if(ball.vy>0 &&
         ball.y+ball.r >= paddle.y &&
         ball.y < paddle.y+paddle.h+6 &&
         ball.x >= paddle.x-ball.r && ball.x <= paddle.x+paddle.w+ball.r){
        const rel = clamp((ball.x - (paddle.x+paddle.w/2)) / (paddle.w/2), -1, 1);
        const ang = rel * (Math.PI/3.1);
        const s = currentSpeed();
        ball.vx = Math.sin(ang)*s;
        ball.vy = -Math.cos(ang)*s;
        ball.y = paddle.y - ball.r;
        paddle.squash = 1;
        blip(320,.08,'square',.06);
        explode(ball.x, paddle.y, '#FFD166', 5, 0.35);
      }

      // bricks
      for(const 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) continue;
        // determine side from previous position
        const fromTop = prevY + ball.r <= b.y + 4;
        const fromBottom = prevY - ball.r >= b.y + b.h - 4;
        const fromLeft = prevX + ball.r <= b.x + 4;
        const fromRight = prevX - ball.r >= b.x + b.w - 4;
        if(fromTop||fromBottom) ball.vy = -ball.vy;
        else if(fromLeft||fromRight) ball.vx = -ball.vx;
        else ball.vy = -ball.vy;

        b.hp--;
        speedBonus = Math.min(55, speedBonus+2.2);
        normalizeBall();

        if(b.hp > 0){
          explode(b.x+b.w/2, b.y+b.h/2, b.color, 10, 0.5);
          addFloater(b.x+b.w/2, b.y, 'CRACK!', '#161616', 13);
          blip(300,.07,'square',.06);
        } else {
          b.alive = false;
          // combo & score
          if(comboTimer>0) combo++; else combo=1;
          comboTimer = 2;
          const pts = 50 * combo;
          score += pts;
          explode(b.x+b.w/2, b.y+b.h/2, b.color, 30, 1);
          addFloater(b.x+b.w/2, b.y+b.h/2, '+'+pts, '#FF2E4D', combo>=3?20:16);
          if(combo>=3) addFloater(W/2, 130, 'COMBO x'+combo+' ♥', '#FF2E4D', 24);
          shake = Math.min(7, 3 + combo*0.4);
          blip(rand(520,900), .13, 'triangle', .09);
          maybeSpawnPowerup(b.x+b.w/2, b.y+b.h/2);
        }
        updateHUD();
        break;
      }

      // lose
      if(ball.y - ball.r > H+10){
        lives--;
        explode(ball.x, H-30, '#999999', 22, 0.8);
        addFloater(W/2, H-120, 'OUCH! -1 ♥', '#161616', 24);
        blip(140,.3,'sawtooth',.08);
        shake = 8;
        updateHUD();
        if(lives<=0){ state='over'; overTimer=2.0; ball.stuck=true; }
        else { resetBallToPaddle(); stuckTimer = demo?0.9:999; }
      }

      // level clear
      if(state==='playing' && bricks.every(b=>!b.alive)){
        state='levelclear'; levelTimer=1.6;
        score += 500*level;
        explode(W/2, 200, '#FF2E4D', 70, 1.4);
        explode(W/2-120, 260, '#FFD166', 40, 1.1);
        explode(W/2+120, 260, '#FF8FAB', 40, 1.1);
        addFloater(W/2, 300, 'LEVEL CLEAR! +'+(500*level), '#FF2E4D', 28);
        blip(660,.12,'square',.07); setTimeout(()=>blip(880,.12,'square',.07),110); setTimeout(()=>blip(1100,.18,'square',.07),220);
        updateHUD();
      }
    }

    // powerups
    for(let i=powerups.length-1;i>=0;i--){
      const p = powerups[i];
      p.y += p.vy*dt; p.x += Math.sin(time*3+p.sway)*28*dt; p.rot += dt*2;
      if(p.y > paddle.y && p.y < paddle.y+paddle.h+14 && p.x > paddle.x-10 && p.x < paddle.x+paddle.w+10){
        applyPowerup(p); powerups.splice(i,1); continue;
      }
      if(p.y > H+20) powerups.splice(i,1);
    }

    // particles
    for(let i=particles.length-1;i>=0;i--){
      const p = particles[i];
      p.life += dt;
      if(p.life>=p.max){ particles.splice(i,1); continue; }
      p.vy -= 26*dt; // float up
      p.vx *= (1 - 1.4*dt); p.vy *= (1 - 0.6*dt);
      p.x += p.vx*dt + Math.sin(p.life*6 + p.sway)*22*dt;
      p.y += p.vy*dt;
      p.rot += p.vr*dt;
    }
    // floaters
    for(let i=floaters.length-1;i>=0;i--){
      const f = floaters[i];
      f.life += dt; f.y -= 42*dt;
      if(f.life>=f.max) floaters.splice(i,1);
    }
    updateHUD();
  }

  // ---------- Draw ----------
  function drawHamburger(){
    const x = paddle.x, y = paddle.y, w = paddle.w, h = paddle.h;
    const squashScale = 1 - paddle.squash*0.18;
    ctx.save();
    ctx.translate(x+w/2, y+h/2);
    ctx.scale(1 + paddle.squash*0.08, squashScale);
    ctx.translate(-(x+w/2), -(y+h/2));

    // shadow
    ctx.fillStyle='rgba(0,0,0,.16)';
    ctx.beginPath(); ctx.ellipse(x+w/2, y+h+7, w*0.46, 6, 0, 0, Math.PI*2); ctx.fill();

    ctx.lineWidth=2; ctx.strokeStyle='#C47A12';
    // bottom bun
    rr(x+5, y+h-12, w-10, 12, 6); ctx.fillStyle='#F4B860'; ctx.fill(); ctx.stroke();
    // patty
    rr(x+2, y+h-21, w-4, 10, 5); ctx.fillStyle='#7B3F1D'; ctx.fill(); ctx.strokeStyle='#5A2A0E'; ctx.stroke();
    // cheese with drips
    ctx.beginPath();
    ctx.moveTo(x+5, y+h-27); ctx.lineTo(x+w-5, y+h-27); ctx.lineTo(x+w-5, y+h-21);
    ctx.lineTo(x+w*0.78, y+h-21); ctx.lineTo(x+w*0.72, y+h-16); ctx.lineTo(x+w*0.62, y+h-21);
    ctx.lineTo(x+w*0.38, y+h-21); ctx.lineTo(x+w*0.32, y+h-15); ctx.lineTo(x+w*0.22, y+h-21);
    ctx.lineTo(x+5, y+h-21); ctx.closePath();
    ctx.fillStyle='#FFD166'; ctx.fill(); ctx.strokeStyle='#E8A317'; ctx.stroke();
    // tomato
    rr(x+6, y+h-32, w-12, 6, 3); ctx.fillStyle='#FF5964'; ctx.fill(); ctx.strokeStyle='#D92B36'; ctx.stroke();
    // lettuce wavy
    ctx.beginPath();
    ctx.moveTo(x+4, y+h-31);
    for(let i=0;i<=6;i++){
      const lx = x+4 + (w-8)*i/6;
      ctx.quadraticCurveTo(lx+ (w-8)/12, y+h-38, lx + (w-8)/6, y+h-31);
    }
    ctx.lineTo(x+w-4, y+h-27); ctx.lineTo(x+4, y+h-27); ctx.closePath();
    ctx.fillStyle='#6BCB77'; ctx.fill(); ctx.strokeStyle='#3A9A4A'; ctx.stroke();

    // top bun dome
    ctx.beginPath();
    ctx.moveTo(x+3, y+17);
    ctx.bezierCurveTo(x+3, y-4, x+w*0.3, y-6, x+w/2, y-6);
    ctx.bezierCurveTo(x+w*0.7, y-6, x+w-3, y-4, x+w-3, y+17);
    ctx.closePath();
    ctx.fillStyle='#FFD07A'; ctx.fill(); ctx.strokeStyle='#D99A2B'; ctx.lineWidth=2.2; ctx.stroke();

    // sesame seeds
    ctx.fillStyle='#FFF3D6';
    const seeds=[[0.22,0.18,-.4],[0.78,0.16,.5],[0.14,0.42,.2],[0.84,0.44,-.3],[0.62,0.08,.1]];
    for(const [sx,sy,rot] of seeds){
      ctx.save(); ctx.translate(x+w*sx, y+16*sy); ctx.rotate(rot);
      ctx.beginPath(); ctx.ellipse(0,0,4.5,2.4,0,0,Math.PI*2); ctx.fill(); ctx.restore();
    }
    // kawaii face
    ctx.fillStyle='#161616';
    ctx.beginPath(); ctx.arc(x+w*0.42, y+9, 2.6, 0, Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(x+w*0.58, y+9, 2.6, 0, Math.PI*2); ctx.fill();
    ctx.strokeStyle='#161616'; ctx.lineWidth=1.8;
    ctx.beginPath(); ctx.arc(x+w/2, y+10, 5, 0.15*Math.PI, 0.85*Math.PI); ctx.stroke();
    ctx.fillStyle='rgba(255,77,109,.5)';
    ctx.beginPath(); ctx.arc(x+w*0.36, y+13, 3.5, 0, Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(x+w*0.64, y+13, 3.5, 0, Math.PI*2); ctx.fill();

    ctx.restore();
  }

  function drawBall(){
    const x=ball.x, y=ball.y, r=ball.r;
    // shadow
    ctx.fillStyle='rgba(0,0,0,.12)';
    ctx.beginPath(); ctx.ellipse(x, y+r+3, r*0.8, 3, 0, 0, Math.PI*2); ctx.fill();
    // cherry tomato body
    const g = ctx.createRadialGradient(x-3,y-3,2,x,y,r+2);
    g.addColorStop(0,'#FF8A8A'); g.addColorStop(0.55,'#FF2E4D'); g.addColorStop(1,'#C9183A');
    ctx.fillStyle=g; ctx.beginPath(); ctx.arc(x,y,r,0,Math.PI*2); ctx.fill();
    ctx.strokeStyle='#8F0F2A'; ctx.lineWidth=1.6; ctx.stroke();
    // stem
    ctx.strokeStyle='#2E7D32'; ctx.lineWidth=2.4; ctx.lineCap='round';
    ctx.beginPath(); ctx.moveTo(x,y-r+2); ctx.quadraticCurveTo(x+3,y-r-5,x+7,y-r-4); ctx.stroke();
    ctx.fillStyle='#6BCB77';
    ctx.beginPath(); ctx.ellipse(x+8,y-r-3,5,2.4,-.5,0,Math.PI*2); ctx.fill();
    // shine
    ctx.fillStyle='rgba(255,255,255,.75)';
    ctx.beginPath(); ctx.ellipse(x-3.5,y-3.5,3.2,2, -0.6,0,Math.PI*2); ctx.fill();
    // cute face on ball too
    ctx.fillStyle='#161616';
    ctx.beginPath(); ctx.arc(x-2.6,y+0.5,1.1,0,Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(x+2.6,y+0.5,1.1,0,Math.PI*2); ctx.fill();
  }

  function draw(){
    ctx.setTransform(dpr,0,0,dpr,0,0);
    ctx.clearRect(0,0,W,H);
    ctx.save();
    if(shake>0) ctx.translate(rand(-shake,shake), rand(-shake,shake));

    // background
    const bg = ctx.createLinearGradient(0,0,0,H);
    bg.addColorStop(0,'#FFF8E7'); bg.addColorStop(0.55,'#FFE5EC'); bg.addColorStop(1,'#FFD6E0');
    ctx.fillStyle=bg; ctx.fillRect(-10,-10,W+20,H+20);
    // polka dots
    ctx.fillStyle='rgba(255,77,109,.07)';
    for(let y=28;y<H;y+=52) for(let x=((y/52)%2? 24:52); x<W; x+=64){ ctx.beginPath(); ctx.arc(x,y,9,0,Math.PI*2); ctx.fill(); }
    // decorative hearts floating in bg
    for(let i=0;i<6;i++){
      const bx = 70 + i*135, by = 36 + Math.sin(time*0.8+i)*5;
      drawHeart(bx,by,9,'#FF8FAB',0.28, Math.sin(time+i)*0.15);
    }
    // table line
    ctx.fillStyle='#FFD166'; ctx.fillRect(0,H-22,W,22);
    ctx.fillStyle='rgba(0,0,0,.08)'; ctx.fillRect(0,H-22,W,3);

    // bricks
    for(const b of bricks){
      if(!b.alive) continue;
      ctx.save();
      rr(b.x,b.y,b.w,b.h,6);
      ctx.fillStyle=b.color; ctx.fill();
      ctx.lineWidth=2; ctx.strokeStyle='rgba(0,0,0,.75)'; ctx.stroke();
      // highlight
      ctx.fillStyle='rgba(255,255,255,.35)'; rr(b.x+3,b.y+3,b.w-6,7,4); ctx.fill();
      // heart emblem
      drawHeart(b.x+b.w/2, b.y+b.h/2+1, 6.5, '#FFFFFF', b.hp>1?0.95:0.45, 0);
      if(b.hp>1){
        ctx.strokeStyle='rgba(0,0,0,.55)'; ctx.lineWidth=1.4;
        ctx.beginPath(); ctx.moveTo(b.x+8,b.y+4); ctx.lineTo(b.x+16,b.y+16); ctx.moveTo(b.x+b.w-10,b.y+5); ctx.lineTo(b.x+b.w-18,b.y+17); ctx.stroke();
      }
      ctx.restore();
    }

    // powerups
    for(const p of powerups){
      const col = p.type==='wide'?'#FF9F1A':p.type==='slow'?'#4D96FF':p.type==='life'?'#FF2E4D':'#9B5DE5';
      const label = p.type==='wide'?'W':p.type==='slow'?'S':p.type==='life'?'♥':'★';
      ctx.save();
      ctx.translate(p.x,p.y);
      ctx.shadowColor='rgba(0,0,0,.25)'; ctx.shadowBlur=6; ctx.shadowOffsetY=3;
      drawHeart(0,0,15,col,1,p.rot*0.25);
      ctx.shadowBlur=0;
      ctx.fillStyle='#fff'; ctx.font='900 13px Arial'; ctx.textAlign='center'; ctx.textBaseline='middle';
      ctx.fillText(label,0,0);
      ctx.restore();
    }

    // particles (hearts)
    for(const p of particles){
      const a = 1 - p.life/p.max;
      if(p.type==='heart'){
        const s = p.size * (0.7 + 0.3*a);
        drawHeart(p.x,p.y,s,p.color, a, p.rot);
      } else {
        ctx.globalAlpha=a; ctx.fillStyle=p.color;
        ctx.beginPath(); ctx.arc(p.x,p.y,p.size,0,Math.PI*2); ctx.fill(); ctx.globalAlpha=1;
      }
    }

    drawHamburger();
    drawBall();

    // wide / slow indicators
    if(wideTimer>0 || slowTimer>0){
      ctx.font='900 11px Arial'; ctx.textAlign='left';
      let tx=10, ty=H-34;
      if(wideTimer>0){ ctx.fillStyle='#B85C00'; ctx.fillText('WIDE '+Math.ceil(wideTimer)+'s',tx,ty); ty-=14; }
      if(slowTimer>0){ ctx.fillStyle='#2456A6'; ctx.fillText('SLOW '+Math.ceil(slowTimer)+'s',tx,ty); }
    }
    if(combo>1 && comboTimer>0){
      ctx.font='900 16px Arial'; ctx.textAlign='right';
      ctx.fillStyle='#FF2E4D'; ctx.strokeStyle='#fff'; ctx.lineWidth=4;
      const txt='COMBO x'+combo+' ♥';
      ctx.strokeText(txt,W-12,26); ctx.fillText(txt,W-12,26);
    }

    // floaters
    for(const f of floaters){
      const a = 1 - f.life/f.max;
      ctx.globalAlpha=a;
      ctx.font='900 '+f.size+'px Arial'; ctx.textAlign='center';
      ctx.lineWidth=5; ctx.strokeStyle='#fff'; ctx.strokeText(f.text,f.x,f.y);
      ctx.fillStyle=f.color; ctx.fillText(f.text,f.x,f.y);
      ctx.globalAlpha=1;
    }

    // stuck hint
    if(ball.stuck && state==='serve'){
      ctx.font='800 13px Arial'; ctx.textAlign='center';
      ctx.fillStyle='rgba(22,22,22,.55)';
      ctx.fillText(demo ? 'launching…' : 'click or press SPACE to launch', W/2, paddle.y-42);
    }
    if(paused){
      ctx.fillStyle='rgba(255,248,231,.55)'; ctx.fillRect(0,0,W,H);
    }
    ctx.restore();
  }

  // ---------- Main Loop ----------
  let last = performance.now();
  function loop(now){
    const dt = Math.min(0.033, (now-last)/1000 || 0.016);
    last = now;
    if(!paused) update(dt);
    draw();
    requestAnimationFrame(loop);
  }

  resetGame();
  setDemoUI();
  showOverlay('demo','DEMO MODE <span>♥</span>','The hamburger is auto-playing! Every brick you break explodes into tons of little hearts.','▶ CLICK OR PRESS A KEY TO START');
  requestAnimationFrame(loop);
})();
</script>
</body>
</html>
Reasoning trace (9,307 tokens)
Designing a single-file responsive canvas breakout with hamburger paddle and heart particle effects, plus click-to-start AI demo mode.Adding cherry ball sprite, heart particles, screen shake, and AI demo with manual input switching.Extending the canvas implementation with responsive layout, level patterns, paddle rendering, particle effects, powerups, and audio handling.Detailing the HTML layout, canvas sizing, game state, collision logic, and hamburger paddle rendering.Adding cherry tomato ball rendering, heart particles, screen shake, audio, and input handling.Adding overlay click handling, responsive layout tweaks, and paddle-ball collision logic with previous-position checks.Implementing brick collision response with damage, single-hit guard, particle explosions, and powerup timers.Adding overlay state handling, demo badge, side panel UI, audio, combo scoring, and particle limits.Extending UI styling with chunky borders, shadows, and controls plus adding detailed canvas drawing helpers and touch handling.Implementing level generation, powerups, particles, state timers, and input handling for the game loop.