Muse Ember
by MetaReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 7.9 s
- Cost
- $0.0025
- Output tokens
- 4,871
- Spent thinking
- 257 tokens
- Speed
- 759 tok/s
- Console errors
- 0
- First token after
- 1.5 s
- First visible text after
- 1.5 s
- Prompt tokens
- 526
- Code size
- 12.7 KB
- Finish reason
- stop
- Served by
- Meta
- Model id
meta/muse-ember- Reasoning sent
{"effort":"minimal"}- Max output
- 943,718 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 · 186 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Neon Breakout</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%;background:#050816;font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;color:#fff;overflow:hidden}
body{display:flex;align-items:center;justify-content:center;background:radial-gradient(900px 600px at 70% 20%,#1a1f4d 0%,#050816 60%)}
#wrap{width:min(96vw,860px);height:min(96vh,720px);display:flex;flex-direction:column;gap:10px}
header{display:flex;justify-content:space-between;align-items:center;padding:6px 10px;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);border-radius:14px;backdrop-filter:blur(8px)}
h1{font-size:20px;letter-spacing:2px;background:linear-gradient(90deg,#22d3ee,#a78bfa,#f472b6);-webkit-background-clip:text;background-clip:text;color:transparent}
.stats{display:flex;gap:14px;font-weight:700;font-size:14px}
.stats span{opacity:.95}
#hud2{display:flex;gap:8px;flex-wrap:wrap}
.pill{font-size:12px;padding:5px 10px;border-radius:999px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.14);font-weight:700}
.pill b{color:#fde68a}
#stage{position:relative;flex:1;border-radius:16px;overflow:hidden;border:1px solid rgba(255,255,255,.16);box-shadow:0 20px 60px rgba(0,0,0,.7),0 0 40px rgba(99,102,241,.25);background:#070b22}
canvas{width:100%;height:100%;display:block;touch-action:none}
#overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;background:rgba(5,8,22,.45);backdrop-filter:blur(3px);text-align:center;padding:20px;z-index:5;cursor:pointer}
#overlay.hidden{display:none}
#overlay h2{font-size:clamp(28px,5vw,44px);letter-spacing:3px}
#overlay p{max-width:560px;line-height:1.5;opacity:.92;font-size:15px}
.btn{pointer-events:auto;background:linear-gradient(90deg,#06b6d4,#8b5cf6,#ec4899);border:none;color:#fff;font-weight:800;letter-spacing:1px;padding:13px 28px;border-radius:999px;font-size:15px;cursor:pointer;box-shadow:0 10px 25px rgba(139,92,246,.5)}
.btn:hover{transform:translateY(-1px)}
.keys{font-size:12px;opacity:.8}
#toast{position:absolute;top:12px;left:50%;transform:translateX(-50%);background:rgba(0,0,0,.65);padding:8px 16px;border-radius:999px;font-weight:800;letter-spacing:1px;display:none;z-index:4;border:1px solid rgba(255,255,255,.2)}
@media(max-width:560px){h1{font-size:16px}.stats{font-size:12px;gap:8px}}
</style>
</head>
<body>
<div id="wrap">
<header>
<h1>🧱 NEON BREAKOUT</h1>
<div class="stats"><span>SCORE <b id="score" style="color:#fde68a">0</b></span><span>LIVES <b id="lives" style="color:#fda4af">❤❤❤</b></span><span>LEVEL <b>1</b></span></div>
</header>
<div id="hud2">
<div class="pill">🏆 <b id="best">0</b> BEST</div>
<div class="pill">⬅️ ➡️ / MOUSE move paddle</div>
<div class="pill">✨ Catch <b>W</b> = Wide • <b>×3</b> = Multi-ball</div>
<div class="pill" id="widePill" style="display:none">WIDE <b id="wideT">10</b>s</div>
</div>
<div id="stage">
<canvas id="c" width="800" height="560"></canvas>
<div id="toast">WIDE PADDLE!</div>
<div id="overlay">
<div style="font-size:54px">🧱✨</div>
<h2>NEON<br>BREAKOUT</h2>
<p>Break all bricks! <b style="color:#fca5a5">Cracked bricks need 2 hits</b>. Catch falling power-ups: <b>W</b> widens your paddle for 10s, <b>×3</b> splits into 3 balls. Demo is playing — take control anytime!</p>
<button class="btn" id="startBtn">▶ PLAY</button>
<div class="keys">Click or press a key to start • Mouse / ← → to move • Space to launch</div>
</div>
</div>
</div>
<script>
const canvas=document.getElementById('c'),ctx=canvas.getContext('2d');
const W=canvas.width,H=canvas.height;
let score=0,best=0,lives=3,state='demo',wideUntil=0,ai=true,keys={},launched=true;
let paddle={x:W/2-60,y:H-28,w:120,h:14,tx:W/2};
let balls=[],particles=[],powerups=[];
const COLORS=[['#ef4444','#f97316'],['#f97316','#facc15'],['#22c55e','#84cc16'],['#06b6d4','#22d3ee'],['#3b82f6','#6366f1'],['#a855f7','#ec4899'],['#ec4899','#f43f5e']];
let bricks=[];
function buildBricks(){
bricks=[];const cols=10,rows=7,bw=72,bh=20,gap=6,ox=(W-(cols*bw+(cols-1)*gap))/2,oy=58;
const toughPattern=[[],[4,5],[2,7],[1,4,5,8],[3,6],[2,4,5,7],[0,9]];
const powerPattern={};
powerPattern[0]=3;powerPattern[1]=7;powerPattern[2]=1;powerPattern[3]=8;powerPattern[4]=0;powerPattern[5]=5;powerPattern[6]=4;
for(let r=0;r<rows;r++)for(let c=0;c<cols;c++){
const isTough=toughPattern[r].includes(c);
const hasPower=(powerPattern[r]===c);
bricks.push({x:ox+c*(bw+gap),y:oy+r*(bh+gap),w:bw,h:bh,hp:isTough?2:1,maxHp:isTough?2:1,row:r,col:c,power:hasPower?((r%2===0)?'wide':'multi'):null,alive:true,flash:0});
}
}
function makeBall(x,y,ang){
const s=5.2;return{x:x||paddle.x+paddle.w/2,y:y||paddle.y-12,vx:Math.cos(ang)*s,vy:Math.sin(ang)*s,r:8};
}
function resetBall(){balls=[makeBall(paddle.x+paddle.w/2,paddle.y-12,-Math.PI/2+(Math.random()*.4-.2))];}
function resetLevel(){buildBricks();particles=[];powerups=[];wideUntil=0;paddle.w=120;resetBall();}
function burst(x,y,color,n=14){for(let i=0;i<n;i++){const a=Math.random()*6.28,s=1+Math.random()*3.5;particles.push({x,y,vx:Math.cos(a)*s,vy:Math.sin(a)*s,life:30+Math.random()*20,c:color,r:2+Math.random()*3});}}
function toast(t){const e=document.getElementById('toast');e.textContent=t;e.style.display='block';setTimeout(()=>e.style.display='none',1400);}
function startGame(){if(state!=='demo'&&state!=='over'&&state!=='win')return; if(state==='over'||state==='win'){score=0;lives=3;} state='playing';ai=false;document.getElementById('overlay').classList.add('hidden');resetLevel();}
document.getElementById('startBtn').addEventListener('click',e=>{e.stopPropagation();startGame();});
document.getElementById('overlay').addEventListener('click',startGame);
addEventListener('keydown',e=>{keys[e.key]=true;if(state==='demo')startGame(); if(e.key===' '&&state==='playing')e.preventDefault();});
addEventListener('keyup',e=>keys[e.key]=false);
canvas.addEventListener('mousemove',e=>{const r=canvas.getBoundingClientRect();paddle.tx=(e.clientX-r.left)*W/r.width;ai=false;if(state==='demo')startGame();});
canvas.addEventListener('touchmove',e=>{e.preventDefault();const r=canvas.getBoundingClientRect();paddle.tx=(e.touches[0].clientX-r.left)*W/r.width;ai=false;},{passive:false});
function showEnd(win){
state=win?'win':'over';best=Math.max(best,score);document.getElementById('best').textContent=best;
const o=document.getElementById('overlay');o.classList.remove('hidden');
o.innerHTML=`<div style="font-size:54px">${win?'🏆':'💥'}</div><h2>${win?'VICTORY!':'GAME OVER'}</h2><p>Score <b style="color:#fde68a">${score}</b> • Best ${best}<br>${win?'You smashed every brick — amazing!':'Out of lives. Try again, champion!'}</p><button class="btn" onclick="startGame()">↻ PLAY AGAIN</button><div class="keys">Click or press a key to start</div>`;
o.querySelector('.btn').addEventListener('click',e=>{e.stopPropagation();startGame();});
}
function paddleBounce(b){
const rel=Math.max(-1,Math.min(1,(b.x-(paddle.x+paddle.w/2))/(paddle.w/2)));
const ang=-Math.PI/2+rel*1.05; const sp=Math.hypot(b.vx,b.vy)||5.2; const ns=Math.min(7.5,sp+0.03);
b.vx=Math.cos(ang)*ns; b.vy=Math.sin(ang)*ns; b.y=paddle.y-b.r-1;
}
function step(){
// paddle
if(ai||state==='demo'){
let target=balls[0]?balls[0].x+ (balls[0].vx*0.35):W/2;
paddle.x+=(target-paddle.x-paddle.w/2)*0.12;
} else {
if(keys['ArrowLeft'])paddle.tx-=9; if(keys['ArrowRight'])paddle.tx+=9;
paddle.x+=(paddle.tx-paddle.x-paddle.w/2)*0.35;
}
paddle.x=Math.max(0,Math.min(W-paddle.w,paddle.x));
const now=performance.now();
if(now<wideUntil){paddle.w=180;document.getElementById('widePill').style.display='block';document.getElementById('wideT').textContent=Math.ceil((wideUntil-now)/1000);}
else {paddle.w=120;document.getElementById('widePill').style.display='none';}
// balls substeps
for(let b of balls){
for(let s=0;s<3;s++){
b.x+=b.vx/3;b.y+=b.vy/3;
if(b.x<b.r){b.x=b.r;b.vx*=-1;} if(b.x>W-b.r){b.x=W-b.r;b.vx*=-1;} if(b.y<b.r){b.y=b.r;b.vy*=-1;}
// paddle
if(b.vy>0&&b.y+b.r>=paddle.y&&b.y-b.r<=paddle.y+paddle.h&&b.x>=paddle.x-b.r&&b.x<=paddle.x+paddle.w+b.r){paddleBounce(b);burst(b.x,paddle.y,'#22d3ee',5);}
// bricks
for(let br of bricks){
if(!br.alive)continue;
if(b.x+b.r>br.x&&b.x-b.r<br.x+br.w&&b.y+b.r>br.y&&b.y-b.r<br.y+br.h){
// determine side
const overlapL=b.x+b.r-br.x, overlapR=br.x+br.w-(b.x-b.r), overlapT=b.y+b.r-br.y, overlapB=br.y+br.h-(b.y-b.r);
const minX=Math.min(overlapL,overlapR),minY=Math.min(overlapT,overlapB);
if(minX<minY){b.vx*=-1;b.x+=overlapL<overlapR?-1:1;}else{b.vy*=-1;b.y+=overlapT<overlapB?-1:1;}
br.hp--;br.flash=8;
if(br.hp<=0){
br.alive=false;score+=br.maxHp===2?150:100;
burst(br.x+br.w/2,br.y+br.h/2,COLORS[br.row][0],18);
if(br.power)powerups.push({x:br.x+br.w/2,y:br.y+br.h/2,vy:2.2,type:br.power,r:14});
}else{score+=50;burst(b.x,b.y,'#fde68a',8);toast('CRACKED! One more hit!');}
break;
}
}
}
}
balls=balls.filter(b=>b.y<H+20);
if(balls.length===0&&state==='playing'){
lives--;updateHUD();
if(lives<=0){showEnd(false);}
else{resetBall();toast('💔 Lost a ball! '+lives+' lives left');}
}
if(state==='playing'&&bricks.every(b=>!b.alive)){score+=500;showEnd(true);}
// powerups
powerups=powerups.filter(p=>{
p.y+=p.vy;
if(p.y+p.r>=paddle.y&&p.y-p.r<=paddle.y+paddle.h&&p.x>=paddle.x&&p.x<=paddle.x+paddle.w){
if(p.type==='wide'){wideUntil=performance.now()+10000;toast('✨ WIDE PADDLE 10s!');}
else{toast('✨ MULTI-BALL ×3!');const base=balls[0]||makeBall();const ns=base?[{vx:base.vx,vy:base.vy},{vx:base.vx*0.6-2,vy:base.vy},{vx:base.vx*0.6+2,vy:base.vy}]:[];balls=ns.map(v=>({x:paddle.x+paddle.w/2,y:paddle.y-12,vx:v.vx,vy:Math.abs(v.vy)<2?-4:v.vy,r:8}));}
score+=25;return false;
}
return p.y<H+20;
});
particles=particles.filter(p=>{p.x+=p.vx;p.y+=p.vy;p.vy+=0.06;p.life--;return p.life>0;});
bricks.forEach(b=>b.flash=Math.max(0,b.flash-1));
}
function draw(){
ctx.clearRect(0,0,W,H);
// bg stars
ctx.fillStyle='#070b22';ctx.fillRect(0,0,W,H);
ctx.fillStyle='rgba(255,255,255,.35)';for(let i=0;i<40;i++){ctx.fillRect((i*97)%W,(i*61)%H,2,2);}
// bricks
for(let b of bricks){if(!b.alive)continue;const [c1,c2]=COLORS[b.row];const g=ctx.createLinearGradient(b.x,b.y,b.x,b.y+b.h);g.addColorStop(0,b.flash?'#fff':c1);g.addColorStop(1,c2);ctx.fillStyle=g;round(b.x,b.y,b.w,b.h,6);ctx.fill();
if(b.maxHp===2&&b.hp===1){ctx.strokeStyle='rgba(0,0,0,.7)';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(b.x+10,b.y+4);ctx.lineTo(b.x+30,b.y+10);ctx.lineTo(b.x+22,b.y+16);ctx.moveTo(b.x+45,b.y+3);ctx.lineTo(b.x+40,b.y+12);ctx.lineTo(b.x+58,b.y+16);ctx.stroke();}
if(b.power){ctx.fillStyle='rgba(255,255,255,.95)';ctx.beginPath();ctx.arc(b.x+b.w/2,b.y+b.h/2,9,0,7);ctx.fill();ctx.fillStyle='#111';ctx.font='bold 10px Arial';ctx.textAlign='center';ctx.fillText(b.power==='wide'?'W':'×3',b.x+b.w/2,b.y+b.h/2+3.5);}
ctx.strokeStyle='rgba(255,255,255,.25)';ctx.stroke();
}
// powerups
for(let p of powerups){ctx.fillStyle=p.type==='wide'?'#22d3ee':'#f472b6';ctx.beginPath();ctx.arc(p.x,p.y,p.r,0,7);ctx.fill();ctx.fillStyle='#fff';ctx.font='bold 12px Arial';ctx.textAlign='center';ctx.fillText(p.type==='wide'?'W':'×3',p.x,p.y+4);ctx.strokeStyle='#fff';ctx.stroke();}
// paddle
const pg=ctx.createLinearGradient(paddle.x,0,paddle.x+paddle.w,0);pg.addColorStop(0,'#06b6d4');pg.addColorStop(1,'#8b5cf6');ctx.fillStyle=pg;round(paddle.x,paddle.y,paddle.w,paddle.h,8);ctx.fill();ctx.fillStyle='rgba(255,255,255,.85)';round(paddle.x+6,paddle.y+3,paddle.w-12,4,4);ctx.fill();
// balls
for(let b of balls){const bg=ctx.createRadialGradient(b.x-2,b.y-2,2,b.x,b.y,b.r);bg.addColorStop(0,'#fff');bg.addColorStop(1,'#f472b6');ctx.fillStyle=bg;ctx.beginPath();ctx.arc(b.x,b.y,b.r,0,7);ctx.fill();}
// particles
for(let p of particles){ctx.globalAlpha=Math.max(0,p.life/30);ctx.fillStyle=p.c;ctx.beginPath();ctx.arc(p.x,p.y,p.r,0,7);ctx.fill();}ctx.globalAlpha=1;
if(state==='demo'){ctx.fillStyle='rgba(0,0,0,.25)';ctx.fillRect(0,0,W,H);}
}
function round(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 updateHUD(){document.getElementById('score').textContent=score;document.getElementById('lives').textContent='❤'.repeat(Math.max(0,lives))||'—';}
function loop(){step();draw();updateHUD();requestAnimationFrame(loop);}
resetLevel();loop();
</script>
</body>
</html>