Models 44

GPT-6.1 Terra

by OpenAIReasoningClean
Open in new window

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

How it went

Total time
1 min 40 s
Cost
$0.043
Output tokens
8,583
Spent thinking
1,253 tokens
Speed
90.3 tok/s
Console errors
0
First token after
5.1 s
First visible text after
26.6 s
Prompt tokens
508
Code size
21.9 KB
Finish reason
stop
Served by
OpenAI
Model id
openai/gpt-6.1-terra
Reasoning sent
model default
Max output
128,000 tokens
Generated
Nov 12, 2026

What it was asked

The prompt
Build a polished Breakout (brick breaker) game in a single HTML file using vanilla JavaScript and a <canvas>. Requirements: - A paddle controlled with the mouse and with the left/right arrow keys. - The bounce angle off the paddle depends on where the ball hits it (center = straight up, edges = sharp angle). - One level with at least 6 rows of bricks, mixing normal bricks and tougher bricks that need 2 hits and visibly crack after the first one. - Some bricks visibly carry a power-up icon; when broken they drop it, and catching it with the paddle gives either a wider paddle (10 seconds) or multi-ball (3 balls). - The ball must never pass through bricks or the paddle. - Particles when a brick breaks. - 3 lives, score displayed. Game over and victory screens with a restart option.
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 · 396 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Neon Break</title>
<style>
  :root{color-scheme:dark;--ink:#f4f5ff;--muted:#8c96b5;--line:#28324b;--cyan:#6cf2e4;--purple:#b8a2ff}
  *{box-sizing:border-box}
  body{margin:0;min-height:100vh;background:#0b0e1a;color:var(--ink);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
  body:before{content:"";position:fixed;inset:0;pointer-events:none;background:radial-gradient(ellipse at 45% -25%,#283158 0,transparent 55%),radial-gradient(ellipse at 95% 80%,#151d37 0,transparent 38%)}
  .shell{position:relative;max-width:1160px;margin:auto;padding:25px 28px 30px}
  header{display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #252b40;padding-bottom:20px}
  .brand{display:flex;align-items:center;gap:11px;font-size:14px;font-weight:850;letter-spacing:.14em}
  .brandmark{width:29px;height:29px;display:grid;grid-template-columns:repeat(2,1fr);gap:3px;transform:rotate(-8deg)}
  .brandmark i{border-radius:2px;background:#76eddf}.brandmark i:nth-child(2){background:#b19bff}.brandmark i:nth-child(3){background:#feaa94}.brandmark i:nth-child(4){background:#687de7}
  .top-note{font-size:11px;letter-spacing:.15em;color:#7d89a6;font-weight:750}
  .top-note span{color:var(--cyan);margin-right:8px}
  .intro{display:flex;justify-content:space-between;align-items:end;padding:25px 0 22px}
  .eyebrow{font-size:10px;letter-spacing:.2em;color:#7fe8df;font-weight:800;margin-bottom:7px}
  h1{font-size:30px;letter-spacing:-.045em;line-height:1;margin:0;font-weight:800}
  .intro p{font-size:13px;color:#8e99b4;margin:8px 0 0}
  .level-tag{border:1px solid #333d57;color:#b8c2d9;border-radius:6px;padding:8px 11px;font-size:10px;font-weight:800;letter-spacing:.12em}
  .layout{display:grid;grid-template-columns:minmax(0,1fr) 260px;gap:18px;align-items:start}
  .game-card,.side-card{border:1px solid #2a344d;background:#121827;border-radius:12px;overflow:hidden;box-shadow:0 18px 60px #0003}
  .game-bar{height:65px;display:flex;align-items:center;padding:0 20px;gap:30px}
  .stat-label{display:block;font-size:9px;color:#7f8ba7;font-weight:800;letter-spacing:.15em;margin-bottom:5px}
  .score{font-size:20px;font-weight:800;letter-spacing:.04em;font-variant-numeric:tabular-nums;line-height:1}
  .bar-divider{height:29px;width:1px;background:#2b344b}
  .hearts{display:flex;gap:5px;color:#ff8d9f;font-size:19px;line-height:1}
  .heart.off{color:#354057}
  .bar-right{margin-left:auto;display:flex;align-items:center;gap:8px;color:#9aa7bd;font-size:10px;font-weight:750;letter-spacing:.1em}
  .dot{width:7px;height:7px;border-radius:50%;background:#6cf2e4;box-shadow:0 0 9px #6cf2e4}
  .board-wrap{position:relative;background:#0c1322;line-height:0;overflow:hidden}
  canvas{display:block;width:100%;height:auto;touch-action:none;cursor:crosshair}
  .start-hint{position:absolute;bottom:17px;left:50%;transform:translateX(-50%);white-space:nowrap;line-height:1.2;background:#1a2436eF;border:1px solid #43516b;border-radius:30px;padding:10px 17px;color:#e5edfb;font-size:11px;font-weight:700;letter-spacing:.02em;box-shadow:0 5px 20px #0006;pointer-events:none}
  .start-hint b{color:#75eee0;margin-right:6px}
  .overlay{position:absolute;inset:0;display:none;align-items:center;justify-content:center;line-height:normal;background:#090e19c9;backdrop-filter:blur(5px);text-align:center}
  .overlay.show{display:flex}
  .overlay-inner{padding:28px}
  .overlay .overline{color:#75eee0;font-size:10px;font-weight:800;letter-spacing:.2em}
  .overlay h2{font-size:34px;letter-spacing:-.04em;margin:10px 0}
  .overlay p{color:#a4afc5;font-size:13px;margin:0 0 20px}
  button{font:inherit;cursor:pointer}
  .primary{border:0;border-radius:7px;background:#77eddf;color:#10212a;font-size:12px;font-weight:850;padding:12px 20px}
  .game-foot{min-height:42px;display:flex;align-items:center;justify-content:space-between;padding:0 20px;color:#7886a3;font-size:10px;letter-spacing:.05em}
  .game-foot strong{color:#a6b2c9;font-weight:700}
  aside{display:grid;gap:12px}
  .side-card{padding:19px;box-shadow:none}
  .side-title{font-size:10px;letter-spacing:.16em;font-weight:800;color:#8592ae;margin:0 0 17px}
  .how-row{display:flex;align-items:center;gap:12px;margin:13px 0;color:#cbd4e6;font-size:12px}
  .key-icon{height:32px;min-width:38px;border:1px solid #39465f;background:#1b2436;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#d5e1ee;font-size:14px}
  .side-copy{color:#8592aa;font-size:11px;line-height:1.6;margin:14px 0 0}
  .power-row{display:flex;gap:12px;align-items:center;margin:15px 0}
  .power-icon{width:36px;height:36px;flex:none;border-radius:8px;display:grid;place-items:center;font-size:15px;font-weight:900}
  .power-icon.wide{background:#173d40;color:#79f5df;border:1px solid #2e7770}
  .power-icon.multi{background:#372e50;color:#c4afff;border:1px solid #695493}
  .power-name{font-size:12px;font-weight:750;color:#e7eafa}
  .power-desc{font-size:10px;color:#8996af;margin-top:4px}
  .tip{border-top:1px solid #2b354b;padding-top:13px;color:#8895ae;font-size:11px;line-height:1.6}
  .tip b{color:#d8dfef}
  .progress-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:11px}
  .progress-head .side-title{margin:0}
  .progress-count{font-size:11px;color:#c2cce0;font-weight:700;font-variant-numeric:tabular-nums}
  .track{height:5px;border-radius:10px;background:#2b354b;overflow:hidden}
  .track span{height:100%;width:0;display:block;background:linear-gradient(90deg,#7cefe0,#ad9cff);transition:width .2s}
  .progress-copy{font-size:10px;color:#8190aa;margin:10px 0 0}
  .restart{width:100%;background:transparent;border:1px solid #34415a;color:#b8c4d9;border-radius:7px;padding:11px;font-size:11px;font-weight:750;letter-spacing:.03em}
  .restart:hover{border-color:#7cefe0;color:#7cefe0}
  @media(max-width:750px){
    .shell{padding:18px 16px 28px}
    .layout{grid-template-columns:1fr}
    aside{grid-template-columns:1fr 1fr}
    .side-card.progress-card{grid-column:1/-1}
    .intro{padding:22px 0 18px}
    h1{font-size:26px}
    .game-bar{height:58px;padding:0 14px;gap:18px}
    .game-foot{padding:0 14px}
  }
  @media(max-width:430px){
    .top-note{font-size:9px}
    .intro p{font-size:11px}
    .level-tag{font-size:9px;padding:7px}
    aside{gap:9px}
    .side-card{padding:14px}
    .how-row{gap:7px;font-size:11px}
    .start-hint{font-size:10px;padding:8px 11px;bottom:8px}
    .bar-right{font-size:9px}
  }
</style>
</head>
<body>
<div class="shell">
  <header>
    <div class="brand"><span class="brandmark"><i></i><i></i><i></i><i></i></span> NEON BREAK</div>
    <div class="top-note"><span>●</span> THE ARCADE COLLECTION &nbsp; / &nbsp; 01</div>
  </header>
  <div class="intro">
    <div><div class="eyebrow">A LITTLE ARCADE MOMENT</div><h1>Break the pattern.</h1><p>Clear the wall. Keep the ball alive. You know the drill.</p></div>
    <div class="level-tag">LEVEL 01 &nbsp; / &nbsp; 01</div>
  </div>
  <main class="layout">
    <section class="game-card" aria-label="Breakout game">
      <div class="game-bar">
        <div><span class="stat-label">SCORE</span><div class="score" id="score">000000</div></div>
        <div class="bar-divider"></div>
        <div><span class="stat-label">LIVES</span><div class="hearts" id="lives"><span class="heart">♥</span><span class="heart">♥</span><span class="heart">♥</span></div></div>
        <div class="bar-right"><span class="dot"></span><span id="mode">DEMO MODE</span></div>
      </div>
      <div class="board-wrap">
        <canvas id="game" width="760" height="540" aria-label="Breakout game board"></canvas>
        <div class="start-hint" id="hint"><b>▶</b> Click or press a key to start</div>
        <div class="overlay" id="overlay">
          <div class="overlay-inner">
            <div class="overline" id="overline">GAME OVER</div>
            <h2 id="end-title">Nice run.</h2>
            <p id="end-copy"></p>
            <button class="primary" id="play-again">Play again &nbsp; ↗</button>
          </div>
        </div>
      </div>
      <div class="game-foot"><span><strong>TIP</strong> &nbsp; Hit the paddle edges to change your angle</span><span id="effect">READY TO PLAY</span></div>
    </section>
    <aside>
      <section class="side-card">
        <h2 class="side-title">HOW TO PLAY</h2>
        <div class="how-row"><div class="key-icon">↔</div><span>Move your mouse</span></div>
        <div class="how-row"><div class="key-icon">← &nbsp;→</div><span>Or use arrow keys</span></div>
        <p class="side-copy">Aim with your paddle and clear every brick. Don't let the ball fall!</p>
      </section>
      <section class="side-card">
        <h2 class="side-title">POWER-UPS</h2>
        <div class="power-row"><div class="power-icon wide">↔</div><div><div class="power-name">Wide paddle</div><div class="power-desc">More room for 10 seconds</div></div></div>
        <div class="power-row"><div class="power-icon multi">⁝</div><div><div class="power-name">Multi-ball</div><div class="power-desc">Three balls, more action</div></div></div>
        <div class="tip"><b>Look closely.</b> Catch the icons that drop from marked bricks. Cracked bricks take two hits.</div>
      </section>
      <section class="side-card progress-card">
        <div class="progress-head"><h2 class="side-title">WALL PROGRESS</h2><span class="progress-count" id="progress">0 / 60</span></div>
        <div class="track"><span id="progress-bar"></span></div>
        <p class="progress-copy">Bricks cleared this round</p>
      </section>
      <button class="restart" id="restart">↻ &nbsp; Restart game</button>
    </aside>
  </main>
</div>
<script>
(() => {
  'use strict';
  const canvas = document.getElementById('game');
  const ctx = canvas.getContext('2d');
  const W = canvas.width, H = canvas.height;
  const scoreEl = document.getElementById('score');
  const livesEl = document.getElementById('lives');
  const hint = document.getElementById('hint');
  const overlay = document.getElementById('overlay');
  const modeEl = document.getElementById('mode');
  const effectEl = document.getElementById('effect');
  const progressEl = document.getElementById('progress');
  const progressBar = document.getElementById('progress-bar');
  const colors = ['#ff9c91','#ffb987','#c3a6ff','#a99bf6','#77dce3','#6ae7c2'];
  let bricks=[], balls=[], particles=[], drops=[];
  let paddle, score, lives, cleared, wideTime, state='demo', endTimer=0, keys={};
  let last=0;

  function makeBricks(){
    const list=[];
    const left=31, gap=7, bw=(W-62-gap*9)/10, bh=25;
    const powers = {'0-2':'wide','0-7':'multi','1-5':'multi','2-1':'wide','2-8':'wide','3-4':'multi','4-2':'multi','4-7':'wide','5-5':'wide'};
    for(let r=0;r<6;r++) for(let c=0;c<10;c++){
      const tough = (r===1 && c%3===1) || (r===3 && c%3===0) || (r===5 && c%3===2);
      list.push({x:left+c*(bw+gap),y:62+r*33,w:bw,h:bh,hp:tough?2:1,max:tough?2:1,color:colors[r],power:powers[r+'-'+c]||null,alive:true});
    }
    return list;
  }
  function freshBall(){
    return {x:W/2,y:420,vx:135,vy:-280,r:7,trail:[]};
  }
  function reset(demo){
    bricks=makeBricks(); balls=[freshBall()]; particles=[]; drops=[];
    paddle={x:W/2,w:100,h:11,y:493}; score=0; lives=3; cleared=0; wideTime=0;
    keys={}; state=demo?'demo':'playing'; endTimer=0;
    hint.style.display=demo?'block':'none'; overlay.classList.remove('show');
    modeEl.textContent=demo?'DEMO MODE':'IN PLAY';
    updateUI();
  }
  function updateUI(){
    scoreEl.textContent=String(score).padStart(6,'0');
    livesEl.innerHTML=Array.from({length:3},(_,i)=>'<span class="heart'+(i>=lives?' off':'')+'">♥</span>').join('');
    progressEl.textContent=cleared+' / 60';
    progressBar.style.width=(cleared/60*100)+'%';
    effectEl.textContent=wideTime>0?'WIDE PADDLE · '+Math.ceil(wideTime)+'S':(state==='demo'?'WATCHING DEMO':'GOOD LUCK');
  }
  function start(){reset(false)}
  document.getElementById('restart').addEventListener('click',start);
  document.getElementById('play-again').addEventListener('click',start);
  canvas.addEventListener('pointerdown',e=>{
    if(state==='demo'||state==='over'||state==='won') start();
    movePointer(e);
  });
  function movePointer(e){
    if(state!=='playing') return;
    const rect=canvas.getBoundingClientRect();
    paddle.x=Math.max(paddle.w/2,Math.min(W-paddle.w/2,(e.clientX-rect.left)*W/rect.width));
  }
  canvas.addEventListener('pointermove',movePointer);
  window.addEventListener('keydown',e=>{
    if(['ArrowLeft','ArrowRight',' '].includes(e.key)) e.preventDefault();
    if(state==='demo'||state==='over'||state==='won') start();
    if(e.key==='ArrowLeft') keys.left=true;
    if(e.key==='ArrowRight') keys.right=true;
  });
  window.addEventListener('keyup',e=>{
    if(e.key==='ArrowLeft') keys.left=false;
    if(e.key==='ArrowRight') keys.right=false;
  });
  window.addEventListener('blur',()=>{keys={}});
  function roundRect(x,y,w,h,r,fill,stroke){
    ctx.beginPath();ctx.roundRect(x,y,w,h,r);
    if(fill){ctx.fillStyle=fill;ctx.fill()}
    if(stroke){ctx.strokeStyle=stroke;ctx.stroke()}
  }
  function burst(x,y,color){
    for(let i=0;i<13;i++){
      const a=Math.random()*Math.PI*2, s=35+Math.random()*150;
      particles.push({x,y,vx:Math.cos(a)*s,vy:Math.sin(a)*s,life:.35+Math.random()*.4,max:.75,color,size:2+Math.random()*3});
    }
  }
  function hitBrick(b){
    b.hp--;
    if(b.hp<=0){
      b.alive=false;cleared++;score+=b.max===2?150:100;
      burst(b.x+b.w/2,b.y+b.h/2,b.color);
      if(b.power) drops.push({x:b.x+b.w/2,y:b.y+b.h/2,type:b.power,vy:115});
      if(cleared===60) finish(true);
    } else {score+=25;burst(b.x+b.w/2,b.y+b.h/2,b.color)}
    updateUI();
  }
  function finish(win){
    if(state==='demo'){state='demo-end';endTimer=2;return}
    state=win?'won':'over';
    document.getElementById('overline').textContent=win?'WALL CLEARED':'GAME OVER';
    document.getElementById('end-title').textContent=win?'Beautifully done.':'Nice run.';
    document.getElementById('end-copy').textContent='Final score: '+score.toLocaleString()+(win?' · Every brick, broken.':' · Give it another shot?');
    modeEl.textContent=win?'COMPLETE':'GAME OVER';
    overlay.classList.add('show');
  }
  function applyPower(type){
    if(type==='wide'){wideTime=10;paddle.w=150}
    else if(balls.length){
      const base=balls[0];
      while(balls.length<3){
        const a=balls.length===1?-.48:.48;
        let vx=base.vx*Math.cos(a)-base.vy*Math.sin(a);
        let vy=base.vx*Math.sin(a)+base.vy*Math.cos(a);
        if(Math.abs(vy)<90) vy=vy<0?-120:120;
        balls.push({x:base.x,y:base.y,vx,vy,r:7,trail:[]});
      }
    }
    updateUI();
  }
  function update(dt){
    if(state==='demo-end'){endTimer-=dt;if(endTimer<=0)reset(true);return}
    if(state!=='playing'&&state!=='demo') return;
    if(wideTime>0){wideTime-=dt;if(wideTime<=0){wideTime=0;paddle.w=100}updateUI()}
    if(state==='demo'){
      let target=balls[0];
      for(const b of balls) if(b.vy>0 && (!target || b.y>target.y)) target=b;
      if(target){
        let tx=target.x;
        if(target.vy>0){
          const t=(paddle.y-target.y)/target.vy;
          let projected=target.x+target.vx*Math.max(0,t);
          const span=W-14;
          projected=((projected-7)%(span*2)+span*2)%(span*2);
          tx=7+(projected>span?span*2-projected:projected);
          tx+=Math.sin(performance.now()/1100)*15;
        }
        paddle.x+=Math.max(-430*dt,Math.min(430*dt,tx-paddle.x));
      }
    } else {
      paddle.x+=(keys.right?1:0)*430*dt-(keys.left?1:0)*430*dt;
    }
    paddle.x=Math.max(paddle.w/2,Math.min(W-paddle.w/2,paddle.x));
    for(const ball of balls){
      ball.trail.unshift({x:ball.x,y:ball.y});
      if(ball.trail.length>7)ball.trail.pop();
      const steps=Math.max(1,Math.ceil(Math.hypot(ball.vx,ball.vy)*dt/3));
      const sub=dt/steps;
      for(let s=0;s<steps;s++){
        const ox=ball.x, oy=ball.y;
        ball.x+=ball.vx*sub;ball.y+=ball.vy*sub;
        if(ball.x-ball.r<12){ball.x=12+ball.r;ball.vx=Math.abs(ball.vx)}
        if(ball.x+ball.r>W-12){ball.x=W-12-ball.r;ball.vx=-Math.abs(ball.vx)}
        if(ball.y-ball.r<13){ball.y=13+ball.r;ball.vy=Math.abs(ball.vy)}
        if(ball.vy>0 && oy+ball.r<=paddle.y && ball.y+ball.r>=paddle.y){
          const t=(paddle.y-ball.r-oy)/(ball.y-oy);
          const hitX=ox+(ball.x-ox)*t;
          if(hitX>=paddle.x-paddle.w/2-ball.r && hitX<=paddle.x+paddle.w/2+ball.r){
            const offset=Math.max(-1,Math.min(1,(hitX-paddle.x)/(paddle.w/2)));
            const angle=offset*1.12;
            const speed=Math.min(405,Math.max(310,Math.hypot(ball.vx,ball.vy)+4));
            ball.vx=Math.sin(angle)*speed; ball.vy=-Math.cos(angle)*speed;
            ball.y=paddle.y-ball.r-.1;
            burst(hitX,paddle.y,'#8cf5e9');
          }
        }
        for(const b of bricks){
          if(!b.alive)continue;
          const nx=Math.max(b.x,Math.min(ball.x,b.x+b.w));
          const ny=Math.max(b.y,Math.min(ball.y,b.y+b.h));
          const dx=ball.x-nx,dy=ball.y-ny;
          if(dx*dx+dy*dy>=ball.r*ball.r)continue;
          // The short substeps and positional correction keep the ball outside every solid brick.
          if(oy+ball.r<=b.y+.5 && ball.vy>0){ball.y=b.y-ball.r-.01;ball.vy=-Math.abs(ball.vy)}
          else if(oy-ball.r>=b.y+b.h-.5 && ball.vy<0){ball.y=b.y+b.h+ball.r+.01;ball.vy=Math.abs(ball.vy)}
          else if(ox+ball.r<=b.x+.5 && ball.vx>0){ball.x=b.x-ball.r-.01;ball.vx=-Math.abs(ball.vx)}
          else if(ox-ball.r>=b.x+b.w-.5 && ball.vx<0){ball.x=b.x+b.w+ball.r+.01;ball.vx=Math.abs(ball.vx)}
          else {
            const px=b.w/2+ball.r-Math.abs(ball.x-(b.x+b.w/2));
            const py=b.h/2+ball.r-Math.abs(ball.y-(b.y+b.h/2));
            if(px<py){if(ball.x<b.x+b.w/2){ball.x=b.x-ball.r-.01;ball.vx=-Math.abs(ball.vx)}else{ball.x=b.x+b.w+ball.r+.01;ball.vx=Math.abs(ball.vx)}}
            else{if(ball.y<b.y+b.h/2){ball.y=b.y-ball.r-.01;ball.vy=-Math.abs(ball.vy)}else{ball.y=b.y+b.h+ball.r+.01;ball.vy=Math.abs(ball.vy)}}
          }
          hitBrick(b);break;
        }
        if(state!=='playing'&&state!=='demo')break;
      }
    }
    balls=balls.filter(b=>b.y<H+15);
    if(balls.length===0 && (state==='playing'||state==='demo')){
      lives--;updateUI();
      if(lives<=0)finish(false);
      else {balls=[freshBall()];balls[0].x=paddle.x;balls[0].y=paddle.y-20}
    }
    for(const d of drops){
      d.y+=d.vy*dt;
      if(d.y+10>=paddle.y && d.y-10<=paddle.y+paddle.h && d.x>=paddle.x-paddle.w/2-10 && d.x<=paddle.x+paddle.w/2+10){d.caught=true;applyPower(d.type)}
    }
    drops=drops.filter(d=>!d.caught&&d.y<H+20);
    for(const p of particles){p.x+=p.vx*dt;p.y+=p.vy*dt;p.vy+=110*dt;p.life-=dt}
    particles=particles.filter(p=>p.life>0);
  }
  function draw(){
    ctx.clearRect(0,0,W,H);
    const bg=ctx.createLinearGradient(0,0,0,H);bg.addColorStop(0,'#111b2d');bg.addColorStop(1,'#0b1321');
    ctx.fillStyle=bg;ctx.fillRect(0,0,W,H);
    ctx.strokeStyle='rgba(123,153,192,.045)';ctx.lineWidth=1;
    for(let x=20;x<W;x+=40){ctx.beginPath();ctx.moveTo(x,0);ctx.lineTo(x,H);ctx.stroke()}
    for(let y=20;y<H;y+=40){ctx.beginPath();ctx.moveTo(0,y);ctx.lineTo(W,y);ctx.stroke()}
    ctx.strokeStyle='#28374f';ctx.beginPath();ctx.moveTo(12,0);ctx.lineTo(12,H);ctx.moveTo(W-12,0);ctx.lineTo(W-12,H);ctx.stroke();
    ctx.fillStyle='#60728d';ctx.font='bold 9px system-ui';ctx.letterSpacing='2px';ctx.fillText('TARGET WALL',31,37);
    ctx.textAlign='right';ctx.fillText('01 / 01',W-31,37);ctx.textAlign='left';ctx.letterSpacing='0px';
    for(const b of bricks){
      if(!b.alive)continue;
      ctx.save();ctx.shadowColor=b.color;ctx.shadowBlur=8;
      roundRect(b.x,b.y,b.w,b.h,4,b.color);
      ctx.restore();
      roundRect(b.x+2,b.y+2,b.w-4,7,2,'rgba(255,255,255,.16)');
      if(b.max===2){
        ctx.strokeStyle=b.hp===1?'rgba(43,32,56,.8)':'rgba(30,35,56,.35)';ctx.lineWidth=b.hp===1?1.7:1;
        ctx.beginPath();
        if(b.hp===1){ctx.moveTo(b.x+b.w*.57,b.y+2);ctx.lineTo(b.x+b.w*.48,b.y+10);ctx.lineTo(b.x+b.w*.57,b.y+13);ctx.lineTo(b.x+b.w*.44,b.y+b.h-2);ctx.moveTo(b.x+b.w*.49,b.y+10);ctx.lineTo(b.x+b.w*.38,b.y+8)}
        else {ctx.moveTo(b.x+6,b.y+6);ctx.lineTo(b.x+6,b.y+12);ctx.moveTo(b.x+b.w-6,b.y+6);ctx.lineTo(b.x+b.w-6,b.y+12)}
        ctx.stroke();
      }
      if(b.power){
        ctx.fillStyle='rgba(25,33,54,.72)';ctx.beginPath();ctx.arc(b.x+b.w/2,b.y+b.h/2,8,0,Math.PI*2);ctx.fill();
        ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';ctx.font='bold 11px system-ui';ctx.fillText(b.power==='wide'?'↔':'✣',b.x+b.w/2,b.y+b.h/2+.5);ctx.textAlign='left';ctx.textBaseline='alphabetic';
      }
    }
    for(const d of drops){
      ctx.save();ctx.shadowBlur=14;ctx.shadowColor=d.type==='wide'?'#71f5e0':'#b6a1ff';
      roundRect(d.x-11,d.y-11,22,22,6,d.type==='wide'?'#72e9d7':'#b6a1ff');
      ctx.restore();ctx.fillStyle='#142034';ctx.textAlign='center';ctx.textBaseline='middle';ctx.font='bold 15px system-ui';ctx.fillText(d.type==='wide'?'↔':'✣',d.x,d.y);ctx.textAlign='left';ctx.textBaseline='alphabetic';
    }
    for(const p of particles){ctx.globalAlpha=Math.max(0,p.life/p.max);ctx.fillStyle=p.color;ctx.fillRect(p.x,p.y,p.size,p.size)}
    ctx.globalAlpha=1;
    for(const ball of balls){
      ball.trail.forEach((t,i)=>{ctx.globalAlpha=(1-i/ball.trail.length)*.17;ctx.fillStyle='#b9fff6';ctx.beginPath();ctx.arc(t.x,t.y,ball.r*(1-i/(ball.trail.length+2)),0,Math.PI*2);ctx.fill()});
      ctx.globalAlpha=1;ctx.save();ctx.shadowBlur=20;ctx.shadowColor='#86fff0';ctx.fillStyle='#f2fffd';ctx.beginPath();ctx.arc(ball.x,ball.y,ball.r,0,Math.PI*2);ctx.fill();ctx.restore();
    }
    ctx.save();ctx.shadowBlur=18;ctx.shadowColor='#61e5d8';
    roundRect(paddle.x-paddle.w/2,paddle.y,paddle.w,paddle.h,6,'#7af0e1');ctx.restore();
    roundRect(paddle.x-paddle.w/2+8,paddle.y+2,paddle.w-16,2,1,'rgba(255,255,255,.6)');
    ctx.fillStyle='rgba(104,226,218,.14)';ctx.fillRect(22,H-18,W-44,1);
  }
  function frame(t){
    if(!last)last=t;
    const dt=Math.min((t-last)/1000,.035);last=t;
    update(dt);draw();requestAnimationFrame(frame);
  }
  reset(true);draw();requestAnimationFrame(frame);
})();
</script>
</body>
</html>
Reasoning trace (1,253 tokens)
**Designing a polished game**

I need to create a polished game with solid collision detection to avoid tunneling, using small steps or substeps. The UI should be responsive, featuring a layout at 1280x800 with a dark navy background. The main card should be central, sized 760x620 with a sidebar to the right of 250. I’m thinking about a gameplay area of 760x600 and need to ensure the HUD is positioned well. The overall theme might be "NEON / BREAK" to fit the aesthetic. I’ll want to include starting visuals and some interaction prompts!**Developing game mechanics**

I’m exploring how to incorporate AI into the demos, perhaps for catching power-ups. For the game over and victory screens, I want them to overlay the canvas and allow a restart. The canvas will need to handle mouse coordinates, starting with a prompt for user input like "click or press a key to start." After starting, mouse movement will control the paddle. It’s important to ensure the ball's movement is quick, with robust collision detection to prevent passing through bricks or the paddle. I’ll focus on precise calculations for collisions to enhance gameplay!**Refining collision detection**

I’m working on a robust collision detection system for the bricks, focusing on how to manage circle-rectangle interactions. I'll be determining distances using the previous position so I know when to resolve collisions, especially if the ball gets too close or invades the brick. I need to ensure there's no tunneling. Plus, I want to limit the number of active balls to three, allowing for power-ups that catch and give a temporary boost when activated. The visibility of power-ups will be key too!**Designing game elements**

I'm thinking about setting the HTML overlay with the initial bottom at 14px for displaying the message and gameplay. The board canvas would be 760x570, and I want to include some CSS for the bar. I plan to use inline SVG for power brick icons as chevrons and circles with a specific color palette.

Then, I’ll arrange the bricks in rows with defined spacing, colors, and dimensions, ensuring they fit the grid properly. Also, I want to implement features like collision detection and a simple AI for the paddle, with the ball's initial position and speed clearly defined.**Setting up game controls**

I’m planning to implement controls where the player can click to start or reset the game. The paddle will be controlled using both mouse and arrow keys for smooth movement. I want to position the paddle based on the mouse directly, eliminating any jumping issues.

I need to ensure that the initial screen displays text for instructions. If the player clicks on the canvas, the default pointer should set the paddle properly. Plus, I want to show badge statuses and perhaps some live effects in a sidebar for a better user experience.