Muse Ember
by MetaReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 10.1 s
- Cost
- $0.0024
- Output tokens
- 4,666
- Spent thinking
- 159 tokens
- Speed
- 563.2 tok/s
- Console errors
- 0
- First token after
- 1.8 s
- First visible text after
- 1.8 s
- Prompt tokens
- 510
- Code size
- 13.2 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 Snake game in a single HTML file using vanilla JavaScript and a <canvas>. Requirements: - A grid of at least 20×20 cells, centered on the page. - Arrow keys and WASD control the snake. Quick successive key presses must both be honored, but the snake can never reverse onto itself. - Eating food adds 10 points and grows the snake by one cell; new food never spawns on the snake. - Game over when the snake hits a wall or itself, with an overlay showing the score; Space or Enter restarts, P pauses. - Visual polish: smooth movement, a snake with a distinct head and eyes facing its direction, and a small particle burst when eating. - Display the current score and the best score of the session.
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 · 252 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Neon Snake</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
html,body{width:100%;height:100%;overflow:hidden}
body{
font-family:ui-rounded,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;
background:radial-gradient(1000px 700px at 70% -10%,#1e3a5f 0%,transparent 55%),
radial-gradient(800px 600px at 10% 110%,#123524 0%,transparent 55%),
#070d16;
color:#eaf2ff;display:flex;flex-direction:column;align-items:center;justify-content:center;
min-height:100vh;padding:14px;
}
.wrap{display:flex;flex-direction:column;align-items:center;gap:12px;width:min(96vw,640px)}
header{width:100%;display:flex;align-items:flex-end;justify-content:space-between;gap:12px}
h1{font-size:clamp(24px,4vw,38px);letter-spacing:.5px;line-height:1}
h1 span{color:#4ade80}
.sub{font-size:12px;opacity:.65;margin-top:5px;letter-spacing:.12em;text-transform:uppercase}
.scores{display:flex;gap:10px}
.card{background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.12);backdrop-filter:blur(8px);
border-radius:16px;padding:8px 16px;text-align:center;min-width:92px;box-shadow:0 10px 30px rgba(0,0,0,.35)}
.card small{font-size:10px;letter-spacing:.18em;opacity:.65;text-transform:uppercase}
.card b{display:block;font-size:26px;line-height:1.1;color:#fff}
.card.hot b{color:#facc15}
.boardWrap{position:relative;width:100%;aspect-ratio:1/1;max-height:min(72vh,600px)}
canvas{width:100%;height:100%;display:block;border-radius:22px;border:1px solid rgba(255,255,255,.14);
box-shadow:0 25px 60px rgba(0,0,0,.55),0 0 0 6px rgba(255,255,255,.04),0 0 50px rgba(74,222,128,.12);background:#0b1626}
.overlay{position:absolute;inset:0;border-radius:22px;display:flex;flex-direction:column;align-items:center;justify-content:center;
text-align:center;padding:20px;background:rgba(5,10,20,.62);backdrop-filter:blur(3px);transition:opacity .25s}
.overlay.hide{opacity:0;pointer-events:none}
.pill{background:#4ade80;color:#052e16;font-weight:800;font-size:11px;letter-spacing:.16em;padding:6px 12px;border-radius:999px}
.overlay h2{font-size:clamp(32px,6vw,52px);margin:12px 0 6px;line-height:1}
.overlay p{opacity:.85;font-size:15px;line-height:1.5;max-width:420px}
.overlay .final{font-size:18px;margin-top:10px}
.overlay .final b{color:#facc15;font-size:28px}
.btn{margin-top:16px;background:#fff;color:#0b1626;border:none;padding:12px 22px;border-radius:999px;font-weight:800;cursor:pointer;font-size:15px;box-shadow:0 10px 25px rgba(0,0,0,.35)}
.btn:hover{transform:translateY(-1px)}
.keys{display:flex;flex-wrap:wrap;gap:8px;justify-content:center}
.kbd{background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.14);border-bottom-width:3px;border-radius:9px;padding:6px 10px;font-size:12px;opacity:.9}
.kbd b{color:#fff}
.note{font-size:12px;opacity:.55;text-align:center}
@media(max-width:520px){ .card{min-width:78px;padding:6px 10px} .card b{font-size:20px} h1{font-size:24px} }
</style>
</head>
<body>
<div class="wrap">
<header>
<div><h1>🐍 Neon <span>Snake</span></h1><div class="sub">Smooth • Quick Turns • Particle Pop</div></div>
<div class="scores">
<div class="card"><small>Score</small><b id="score">0</b></div>
<div class="card hot"><small>Best</small><b id="best">0</b></div>
</div>
</header>
<div class="boardWrap">
<canvas id="game" width="640" height="640" aria-label="Snake game"></canvas>
<div class="overlay" id="overlay">
<div class="pill" id="pill">● DEMO PLAYING</div>
<h2 id="title">Click or press a key<br>to start</h2>
<p id="desc">Watch the AI play — take over anytime with <b>Arrow Keys</b> or <b>WASD</b>. Eat the glowing apple for +10 points.</p>
<div class="final" id="final" style="display:none">Score <b id="finalScore">0</b></div>
<button class="btn" id="startBtn">▶ Play Snake</button>
</div>
</div>
<div class="keys">
<span class="kbd"><b>↑ ↓ ← →</b> / <b>WASD</b> Move</span>
<span class="kbd"><b>P</b> Pause</span>
<span class="kbd"><b>Space / Enter</b> Restart</span>
<span class="kbd">🍎 +10 & grow</span>
</div>
<div class="note">Quick successive turns are queued — the snake can never reverse onto itself.</div>
</div>
<script>
const COLS=24, ROWS=24;
const canvas=document.getElementById('game'),ctx=canvas.getContext('2d');
const scoreEl=document.getElementById('score'),bestEl=document.getElementById('best');
const overlay=document.getElementById('overlay'),title=document.getElementById('title'),desc=document.getElementById('desc'),
pill=document.getElementById('pill'),finalEl=document.getElementById('final'),finalScore=document.getElementById('finalScore'),startBtn=document.getElementById('startBtn');
let cell=canvas.width/COLS;
let snake,prevSnake,dir,queue,pendingGrow,food,particles,score,best=0,state='demo',tickMs=135,lastTick=0,tickProgress=0,foodPulse=0,flash=0;
const DIRS={up:{x:0,y:-1},down:{x:0,y:1},left:{x:-1,y:0},right:{x:1,y:0}};
function reset(){
snake=[{x:12,y:12},{x:11,y:12},{x:10,y:12},{x:9,y:12}];
prevSnake=JSON.parse(JSON.stringify(snake));
dir={x:1,y:0}; queue=[]; pendingGrow=0; particles=[]; score=0; tickMs=135;
scoreEl.textContent=0; spawnFood(); lastTick=performance.now();
}
function spawnFood(){
while(true){
const f={x:Math.floor(Math.random()*COLS),y:Math.floor(Math.random()*ROWS)};
if(!snake.some(s=>s.x===f.x&&s.y===f.y)){ food=f; break; }
}
}
function wouldHit(nx,ny){
if(nx<0||ny<0||nx>=COLS||ny>=ROWS) return true;
const body = pendingGrow>0 ? snake : snake.slice(0,-1);
return body.some(s=>s.x===nx&&s.y===ny);
}
function aiDir(){
// BFS to food
const start=snake[0], target=food, key=(x,y)=>x+','+y;
const q=[start], seen=new Map([[key(start.x,start.y),null]]);
while(q.length){
const cur=q.shift();
if(cur.x===target.x&&cur.y===target.y) break;
for(const d of Object.values(DIRS)){
const nx=cur.x+d.x, ny=cur.y+d.y;
if(wouldHit(nx,ny)&&!(nx===target.x&&ny===target.y)) continue;
if(nx<0||ny<0||nx>=COLS||ny>=ROWS) continue;
if(seen.has(key(nx,ny))) continue;
seen.set(key(nx,ny),cur); q.push({x:nx,y:ny});
}
}
if(seen.has(key(target.x,target.y))){
let cur=target;
while(seen.get(key(cur.x,cur.y)) && !(JSON.stringify(seen.get(key(cur.x,cur.y)))===JSON.stringify(start))){
cur=seen.get(key(cur.x,cur.y));
}
const first=seen.get(key(cur.x,cur.y))||cur;
// walk back to first step
let c=target; const path=[];
while(c){ path.unshift(c); c=seen.get(key(c.x,c.y)); if(!c) break; }
if(path.length>1){
const step=path[1]; const dx=step.x-start.x, dy=step.y-start.y;
const cand=Object.values(DIRS).find(d=>d.x===dx&&d.y===dy);
if(cand && !(cand.x===-dir.x&&cand.y===-dir.y)) return cand;
}
}
// fallback: any safe move, prefer straight
const opts=Object.values(DIRS).filter(d=>!(d.x===-dir.x&&d.y===-dir.y)&&!wouldHit(start.x+d.x,start.y+d.y));
return opts[0]||dir;
}
function enqueue(d){
const last=queue.length?queue[queue.length-1]:dir;
if(d.x===-last.x&&d.y===-last.y) return;
if(d.x===last.x&&d.y===last.y) return;
if(queue.length<3) queue.push(d);
}
function burst(x,y){
for(let i=0;i<22;i++){
const a=Math.random()*Math.PI*2, sp=1+Math.random()*3.2;
particles.push({x:(x+.5)*cell,y:(y+.5)*cell,vx:Math.cos(a)*sp,vy:Math.sin(a)*sp,life:1, r:2+Math.random()*4, c:Math.random()<.5?'#fde68a':'#fb7185'});
}
}
function step(){
prevSnake=JSON.parse(JSON.stringify(snake));
if(state==='demo') dir=aiDir();
else if(queue.length) dir=queue.shift();
const head={x:snake[0].x+dir.x,y:snake[0].y+dir.y};
if(wouldHit(head.x,head.y)){ gameOver(); return; }
snake.unshift(head);
if(head.x===food.x&&head.y===food.y){
score+=10; scoreEl.textContent=score; if(score>best){best=score;bestEl.textContent=best;}
pendingGrow+=1; burst(food.x,food.y); flash=1; spawnFood(); tickMs=Math.max(75,135-score*0.35);
}
if(pendingGrow>0) pendingGrow--; else snake.pop();
}
function gameOver(){
state='over'; finalScore.textContent=score;
pill.textContent='GAME OVER'; title.innerHTML='💥 Game Over!'; desc.innerHTML='You hit a wall or yourself.<br>Press <b>Space</b> or <b>Enter</b> to restart.';
finalEl.style.display='block'; startBtn.textContent='↻ Play Again'; overlay.classList.remove('hide');
}
function startGame(){
reset(); state='playing'; overlay.classList.add('hide');
}
function togglePause(){
if(state==='playing'){ state='paused'; pill.textContent='PAUSED'; title.textContent='⏸ Paused'; desc.textContent='Press P to resume, or Space / Enter to restart.'; finalEl.style.display='none'; startBtn.textContent='▶ Resume'; overlay.classList.remove('hide'); }
else if(state==='paused'){ state='playing'; overlay.classList.add('hide'); lastTick=performance.now(); }
}
window.addEventListener('keydown',e=>{
const k=e.key.toLowerCase();
if(['arrowup','arrowdown','arrowleft','arrowright',' '].includes(k)) e.preventDefault();
if(state!=='playing' && state!=='paused' && state!=='demo'){ if(k===' '||k==='enter'){ startGame(); return; } }
if(k==='p'){ if(state==='playing'||state==='paused') togglePause(); return; }
if(state==='demo') startGame();
if(state==='paused') return;
if(k==='arrowup'||k==='w') enqueue(DIRS.up);
else if(k==='arrowdown'||k==='s') enqueue(DIRS.down);
else if(k==='arrowleft'||k==='a') enqueue(DIRS.left);
else if(k==='arrowright'||k==='d') enqueue(DIRS.right);
else if((k===' '||k==='enter') && state==='playing'){ /* nothing */ }
});
startBtn.addEventListener('click',()=>{ if(state==='paused') togglePause(); else startGame(); });
overlay.addEventListener('click',e=>{ if(e.target!==startBtn && state==='demo') startGame(); });
function roundRect(x,y,w,h,r){ ctx.beginPath(); ctx.moveTo(x+r,y); ctx.arcTo(x+w,y,x+w,y+h,r); ctx.arcTo(x+w,y+h,x,y+h,r); ctx.arcTo(x,y+h,x,y,r); ctx.arcTo(x,y,x+w,y,r); ctx.closePath(); }
function draw(now){
// timing
if(state==='playing'||state==='demo'){
tickProgress=Math.min(1,(now-lastTick)/tickMs);
if(now-lastTick>=tickMs){ step(); lastTick=now; tickProgress=0; }
}
foodPulse+=0.06; flash*=0.92;
// board
const g=ctx.createLinearGradient(0,0,canvas.width,canvas.height); g.addColorStop(0,'#0f2138'); g.addColorStop(1,'#0a1424');
ctx.fillStyle=g; ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle='rgba(255,255,255,0.035)';
for(let y=0;y<ROWS;y++) for(let x=0;x<COLS;x++) if((x+y)%2===0) ctx.fillRect(x*cell,y*cell,cell,cell);
// grid dots
ctx.fillStyle='rgba(255,255,255,0.05)';
for(let y=0;y<ROWS;y++) for(let x=0;x<COLS;x++){ ctx.beginPath(); ctx.arc(x*cell+cell/2,y*cell+cell/2,1.2,0,7); ctx.fill(); }
if(flash>0.02){ ctx.fillStyle=`rgba(253,224,71,${flash*0.14})`; ctx.fillRect(0,0,canvas.width,canvas.height); }
// food glow
const fx=(food.x+.5)*cell, fy=(food.y+.5)*cell, pulse=1+Math.sin(foodPulse)*0.12;
const fg=ctx.createRadialGradient(fx,fy,2,fx,fy,cell*1.4); fg.addColorStop(0,'rgba(251,113,133,.55)'); fg.addColorStop(1,'rgba(251,113,133,0)');
ctx.fillStyle=fg; ctx.beginPath(); ctx.arc(fx,fy,cell*1.4,0,7); ctx.fill();
ctx.save(); ctx.translate(fx,fy); ctx.scale(pulse,pulse);
ctx.fillStyle='#fb7185'; ctx.beginPath(); ctx.arc(0,2,cell*0.34,0,7); ctx.fill();
ctx.fillStyle='#ffe4e6'; ctx.beginPath(); ctx.arc(-cell*0.11,-cell*0.06,cell*0.09,0,7); ctx.fill();
ctx.strokeStyle='#16a34a'; ctx.lineWidth=3; ctx.beginPath(); ctx.moveTo(0,-cell*0.3); ctx.quadraticCurveTo(cell*0.1,-cell*0.55,cell*0.28,-cell*0.5); ctx.stroke();
ctx.fillStyle='#4ade80'; ctx.beginPath(); ctx.ellipse(cell*0.28,-cell*0.5,cell*0.16,cell*0.08,-0.5,0,7); ctx.fill();
ctx.restore();
// snake interpolated
const interp = (state==='over'||state==='paused') ? 0 : tickProgress;
for(let i=snake.length-1;i>=0;i--){
const cur=snake[i], prev=prevSnake[Math.min(i,prevSnake.length-1)]||cur;
const x=(prev.x+(cur.x-prev.x)*interp+.5)*cell, y=(prev.y+(cur.y-prev.y)*interp+.5)*cell;
const t=i/Math.max(1,snake.length-1), r=cell*(0.46 - t*0.2);
if(i===0){
ctx.save(); ctx.shadowColor='rgba(74,222,128,.7)'; ctx.shadowBlur=18; ctx.fillStyle='#4ade80'; ctx.beginPath(); ctx.arc(x,y,r,0,7); ctx.fill(); ctx.restore();
// eyes facing dir
const perp={x:-dir.y,y:dir.x}, fwd=dir;
for(const s of [-1,1]){
const ex=x+fwd.x*r*0.35+perp.x*s*r*0.42, ey=y+fwd.y*r*0.35+perp.y*s*r*0.42;
ctx.fillStyle='#fff'; ctx.beginPath(); ctx.arc(ex,ey,r*0.34,0,7); ctx.fill();
ctx.fillStyle='#0b1626'; ctx.beginPath(); ctx.arc(ex+fwd.x*r*0.13,ey+fwd.y*r*0.13,r*0.18,0,7); ctx.fill();
}
ctx.fillStyle='#166534'; ctx.beginPath(); ctx.arc(x+fwd.x*r*0.55,y+fwd.y*r*0.55,r*0.16,0,7); ctx.fill();
}else{
ctx.fillStyle=t<0.3?'#22c55e':'#16a34a'; ctx.beginPath(); ctx.arc(x,y,r,0,7); ctx.fill();
ctx.fillStyle='rgba(255,255,255,.18)'; ctx.beginPath(); ctx.arc(x-r*0.25,y-r*0.25,r*0.35,0,7); ctx.fill();
}
}
// particles
particles=particles.filter(p=>p.life>0);
for(const p of particles){ p.x+=p.vx; p.y+=p.vy; p.vy+=0.08; p.life-=0.03; ctx.globalAlpha=Math.max(0,p.life); ctx.fillStyle=p.c; ctx.beginPath(); ctx.arc(p.x,p.y,p.r*p.life+0.5,0,7); ctx.fill(); }
ctx.globalAlpha=1;
requestAnimationFrame(draw);
}
reset(); requestAnimationFrame(draw);
</script>
</body>
</html>