Run details
- Model
- opencode/ling-3.1-flash-free
- Route
- opencode CLI
- Reasoning
- provider default
- Limits
- 60 min · 32,768 output tokens
- Date
- 2 Oct 2026
- Time
- 5 min 25 s
- Size
- 25 kB
- Tokens
- 8,449 in, 32,932 out
- List price
- $0.008 ($0.075 in / $0.225 out per M)
- Paid
- Not billed per run (CLI plan)
Exact prompt
Make a Breakout game I can play right now with the keyboard or the mouse. Give it several levels, a score and some juice. It must be one complete, self-contained HTML file: inline all CSS and JavaScript, and make no network requests of any kind (no CDNs, web fonts or remote images). Save it as index.html in the current directory, then stop. Do not ask questions.
Source
25 kB 637 lines Raw
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>NEON BREAKER</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
html,body { height:100%; background:#05060f; overflow:hidden; }
body { display:flex; flex-direction:column; align-items:center; justify-content:center;
font-family:ui-monospace,Menlo,Consolas,monospace; }
canvas {
display:block;
width:min(96vw, calc(92vh * 4 / 3));
aspect-ratio:4/3;
background:#070a18;
border-radius:10px;
box-shadow:0 0 40px rgba(80,120,255,.25), 0 0 120px rgba(80,120,255,.12);
touch-action:none;
}
#foot { color:#4a5578; font-size:12px; letter-spacing:1px; margin-top:10px; user-select:none; }
</style>
</head>
<body>
<canvas id="game"></canvas>
<div id="foot">MOVE: MOUSE or ← → / A D · LAUNCH: SPACE / CLICK · P PAUSE · M MUTE</div>
<script>
'use strict';
(() => {
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const W = 800, H = 600, TAU = Math.PI * 2;
const clamp = (v,a,b) => v<a?a:v>b?b:v;
const rand = (a,b) => a + Math.random()*(b-a);
function fit(){ const d=Math.min(window.devicePixelRatio||1,2);
canvas.width=W*d; canvas.height=H*d; ctx.setTransform(d,0,0,d,0,0); }
window.addEventListener('resize', fit); fit();
function rr(x,y,w,h,r){
ctx.beginPath();
if(ctx.roundRect){ ctx.roundRect(x,y,w,h,r); return; }
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();
}
/* ---------------- audio (all synthesized, no files) ---------------- */
let actx=null, muted=false;
function ac(){ if(!actx){ try{ actx=new (window.AudioContext||window.webkitAudioContext)(); }catch(e){} }
if(actx && actx.state==='suspended') actx.resume(); return actx; }
function tone(f,d,type,v,slide){
if(muted) return; const a=ac(); if(!a) return;
const t=a.currentTime, o=a.createOscillator(), g=a.createGain();
o.type=type||'square'; o.frequency.setValueAtTime(f,t);
if(slide) o.frequency.exponentialRampToValueAtTime(Math.max(30,slide), t+d);
g.gain.setValueAtTime(v||.12,t); g.gain.exponentialRampToValueAtTime(.0001, t+d);
o.connect(g); g.connect(a.destination); o.start(t); o.stop(t+d+.03);
}
function sfx(n){ switch(n){
case 'paddle': tone(200,.08,'square',.10,320); break;
case 'brick': tone(480+Math.random()*120,.06,'square',.09,700); break;
case 'hard': tone(170,.07,'sawtooth',.11,110); break;
case 'wall': tone(150,.04,'triangle',.06); break;
case 'bomb': tone(140,.4,'sawtooth',.20,35); tone(70,.3,'square',.14,30); break;
case 'power': tone(520,.1,'square',.11,760); setTimeout(()=>tone(760,.12,'square',.11,1080),70); break;
case 'life': tone(660,.1,'sine',.12,990); setTimeout(()=>tone(990,.15,'sine',.12,1320),90); break;
case 'lose': tone(280,.45,'sawtooth',.15,60); break;
case 'launch': tone(300,.09,'square',.10,520); break;
case 'click': tone(600,.05,'square',.07); break;
case 'level': [523,659,784,1047].forEach((f,i)=>setTimeout(()=>tone(f,.14,'square',.11), i*90)); break;
case 'over': [400,300,220,140].forEach((f,i)=>setTimeout(()=>tone(f,.2,'sawtooth',.12), i*140)); break;
case 'win': [523,659,784,1047,1319].forEach((f,i)=>setTimeout(()=>tone(f,.18,'square',.11), i*110)); break;
}}
/* ---------------- levels ---------------- */
const COLORS={a:'#ff5d73',b:'#ffa94d',c:'#ffe066',d:'#69db7c',e:'#4dabf7',f:'#9775fa',g:'#f783ac',X:'#c3cad6',B:'#ff8787'};
const LEVELS=[
["aaaaaaaaaaaa","bbbbbbbbbbbb","cccccccccccc","dddddddddddd","eeeeeeeeeeee"],
["XXXXXXXXXXXX","a.a.a.a.a.a.",".b.b.b.b.b.b","a.a.a.a.a.a.",".b.b.b.b.b.b","XXXXXXXXXXXX"],
[".....BB.....","....aXXa....","...abccba...","..abccdccb..","...abccba...","....aXXa....",".....BB....."],
["..a......a..","...a....a...","..aaaaaaaa..",".aa.aaaa.aa.","aaaaaaaaaaaa","a.aaaaaaaa.a","a.a......a.a","....aa.aa..."],
["b.B.b.B.b.B.","XXXXXXXXXXXX","c.x.c.x.c.x.",".x.c.x.c.x.c","XXXXXXXXXXXX","d.B.d.B.d.B.","eeeeeeeeeeee"]
];
const BCOLS=12, GAP=6, BW=(W-80-(BCOLS-1)*GAP)/BCOLS, BH=26, BTOP=92;
/* ---------------- state ---------------- */
const G={ mode:'menu', score:0, best:0, lives:3, level:0, combo:0, broken:0,
shake:0, freeze:0, levelT:0, clearT:0, flash:0, time:0, paused:false, lastBonus:0 };
try{ G.best=+localStorage.getItem('neonbreaker_best')||0; }catch(e){}
function saveBest(){ try{ localStorage.setItem('neonbreaker_best', G.best); }catch(e){} }
const paddle={ x:W/2, w:110, base:110, h:14, y:H-48, squash:0, expandT:0 };
let balls=[], bricks=[], parts=[], texts=[], powers=[], booms=[], stars=[];
let slowT=0;
for(let i=0;i<90;i++) stars.push({x:rand(0,W), y:rand(0,H), z:rand(.2,1), s:rand(.5,1.8)});
function targetSpeed(){ return Math.min(330 + G.level*28 + G.broken*2.2, 600) * (slowT>0 ? .62 : 1); }
function shake(a){ G.shake=Math.max(G.shake,a); }
function buildLevel(idx){
bricks=[]; const map=LEVELS[idx];
map.forEach((row,r)=>{
for(let c=0;c<row.length;c++){
const ch=row[c]; if(ch==='.') continue;
const hard=ch==='X', bomb=ch==='B';
bricks.push({ x:40+c*(BW+GAP), y:BTOP+r*(BH+GAP), w:BW, h:BH,
hp:hard?2:1, maxHp:hard?2:1, type:bomb?'B':(hard?'X':'N'),
color:COLORS[ch]||'#fff', flash:0, born:r*.06+c*.02, alive:true });
}
});
}
function startGame(){ G.score=0; G.lives=3; G.level=0; startLevel(); G.mode='serve'; }
function startLevel(){
G.combo=0; G.broken=0; G.levelT=0;
buildLevel(G.level);
balls=[]; powers=[]; booms=[]; parts=[]; texts=[];
slowT=0; paddle.expandT=0; paddle.w=paddle.base;
resetServe();
}
function resetServe(){
paddle.x=W/2;
balls=[{ x:paddle.x, y:paddle.y-10, vx:0, vy:0, r:7, trail:[] }];
}
function launch(){
if(G.mode!=='serve') return;
G.mode='play';
const sp=targetSpeed(), a=rand(-.35,.35);
balls[0].vx=Math.sin(a)*sp; balls[0].vy=-Math.cos(a)*sp;
sfx('launch');
}
function enterClear(){
if(G.mode!=='play') return;
G.mode='clear'; G.clearT=2.4; balls=[];
G.lastBonus=250*(G.level+1); G.score+=G.lastBonus;
if(G.score>G.best){ G.best=G.score; saveBest(); }
sfx('level');
for(let i=0;i<6;i++) burst(rand(120,W-120), rand(120,320), Object.values(COLORS)[i%7], 18, 300);
}
function nextLevel(){
if(G.level>=LEVELS.length-1){ G.mode='win'; sfx('win'); saveBest(); return; }
G.level++; startLevel(); G.mode='serve';
}
function gameOver(){ G.mode='over'; sfx('over'); saveBest(); }
/* ---------------- gameplay ---------------- */
function burst(x,y,color,n,spd){
for(let i=0;i<n;i++){
const a=rand(0,TAU), s=rand(spd*.3,spd);
parts.push({ x,y, vx:Math.cos(a)*s, vy:Math.sin(a)*s, life:rand(.35,.8), max:.8, color, size:rand(2,4.5) });
}
}
function addText(x,y,str,color){ texts.push({ x,y, str, color:color||'#fff', life:1 }); }
function hitBrick(br){
br.flash=1;
if(br.type==='X' && br.hp>1){
br.hp--; G.score+=30;
burst(br.x+br.w/2, br.y+br.h/2, '#c3cad6', 5, 120); sfx('hard');
return;
}
destroyBrick(br);
}
function destroyBrick(br){
if(!br.alive) return;
br.alive=false; G.broken++; G.combo++;
const mult=1+Math.floor(G.combo/5);
const base=br.type==='B'?75:(br.maxHp>1?120:50);
const pts=base*mult;
G.score+=pts;
if(G.score>G.best){ G.best=G.score; saveBest(); }
addText(br.x+br.w/2, br.y+br.h/2, '+'+pts, mult>1?'#ffd43b':'#ffffff');
burst(br.x+br.w/2, br.y+br.h/2, br.color, br.type==='B'?26:12, br.type==='B'?260:180);
shake(br.type==='B'?9:2.2);
if(br.type==='B'){
booms.push({ x:br.x+br.w/2, y:br.y+br.h/2, r:100, t:0, delay:.14, done:false });
sfx('bomb'); G.freeze=.05;
} else sfx('brick');
if(Math.random()<.14) spawnPower(br.x+br.w/2, br.y+br.h/2);
if(bricks.every(b=>!b.alive)) enterClear();
}
const PTYPES=[{k:'E',c:'#69db7c',w:3},{k:'M',c:'#4dabf7',w:3},{k:'S',c:'#ffd43b',w:2.4},{k:'L',c:'#ff5d73',w:.8}];
function spawnPower(x,y){
const tot=PTYPES.reduce((a,p)=>a+p.w,0); let r=Math.random()*tot;
for(const p of PTYPES){ if((r-=p.w)<=0){ powers.push({ x,y, vy:150, k:p.k, c:p.c, t:0 }); return; } }
}
function applyPower(p){
sfx(p.k==='L'?'life':'power');
addText(p.x, paddle.y-22, {E:'EXPAND!',M:'MULTIBALL!',S:'SLOW-MO!',L:'+1 LIFE!'}[p.k], p.c);
burst(p.x, p.y, p.c, 14, 200);
if(p.k==='E') paddle.expandT=12;
else if(p.k==='M'){
const src=balls.slice();
for(const b of src){
if(balls.length>=8) break;
const sp=Math.hypot(b.vx,b.vy)||targetSpeed(), a=Math.atan2(b.vy,b.vx)||(-Math.PI/2);
for(const da of [-.45,.45]){
if(balls.length>=8) break;
balls.push({ x:b.x, y:b.y, vx:Math.cos(a+da)*sp, vy:Math.sin(a+da)*sp, r:7, trail:[] });
}
}
}
else if(p.k==='S') slowT=9;
else if(p.k==='L') G.lives=Math.min(G.lives+1, 6);
}
function updatePaddle(dt){
let dir=0;
if(keys['arrowleft']||keys['a']) dir-=1;
if(keys['arrowright']||keys['d']) dir+=1;
if(dir!==0) paddle.x+=dir*560*dt;
paddle.x=clamp(paddle.x, paddle.w/2+6, W-paddle.w/2-6);
}
function updateBalls(dt){
const sp=targetSpeed();
for(let i=balls.length-1;i>=0;i--){
const b=balls[i];
const cur=Math.hypot(b.vx,b.vy)||1; b.vx=b.vx/cur*sp; b.vy=b.vy/cur*sp;
const steps=Math.max(1, Math.ceil(sp*dt/5)), sdt=dt/steps;
for(let s=0;s<steps;s++){
b.x+=b.vx*sdt; b.y+=b.vy*sdt;
if(b.x<b.r+4){ b.x=b.r+4; b.vx=Math.abs(b.vx); sfx('wall'); }
if(b.x>W-b.r-4){ b.x=W-b.r-4; b.vx=-Math.abs(b.vx); sfx('wall'); }
if(b.y<b.r+44){ b.y=b.r+44; b.vy=Math.abs(b.vy); sfx('wall'); }
if(b.vy>0 && b.y+b.r>=paddle.y && b.y-b.r<=paddle.y+paddle.h &&
b.x>=paddle.x-paddle.w/2-b.r && b.x<=paddle.x+paddle.w/2+b.r){
const rel=clamp((b.x-paddle.x)/(paddle.w/2), -1, 1);
const ang=rel*1.15, nsp=Math.hypot(b.vx,b.vy);
b.vx=Math.sin(ang)*nsp; b.vy=-Math.abs(Math.cos(ang)*nsp);
b.y=paddle.y-b.r-.5;
if(G.combo>=5) addText(paddle.x, paddle.y-26, 'COMBO x'+(1+Math.floor(G.combo/5))+'!', '#ffd43b');
G.combo=0; paddle.squash=1;
burst(b.x, paddle.y, '#8ec5ff', 6, 140); sfx('paddle');
}
for(const br of bricks){
if(!br.alive) continue;
const nx=clamp(b.x,br.x,br.x+br.w), ny=clamp(b.y,br.y,br.y+br.h);
const dx=b.x-nx, dy=b.y-ny;
if(dx*dx+dy*dy<=b.r*b.r){
hitBrick(br);
if(Math.abs(dx)>Math.abs(dy)){ b.vx=dx>0?Math.abs(b.vx):-Math.abs(b.vx); b.x=nx+Math.sign(dx)*(b.r+.1); }
else{
if(dx===0&&dy===0) b.vy=-b.vy;
else { b.vy=dy>0?Math.abs(b.vy):-Math.abs(b.vy); b.y=ny+Math.sign(dy)*(b.r+.1); }
}
break;
}
}
}
b.trail.push({x:b.x,y:b.y}); if(b.trail.length>10) b.trail.shift();
if(b.y>H+30) balls.splice(i,1);
}
if(balls.length===0 && G.mode==='play'){
G.lives--; G.combo=0; G.flash=1; shake(10); sfx('lose');
if(G.lives<=0) gameOver(); else { G.mode='serve'; resetServe(); }
}
}
function updatePowers(dt){
for(let i=powers.length-1;i>=0;i--){
const p=powers[i]; p.t+=dt; p.y+=p.vy*dt; p.x+=Math.sin(p.t*4)*18*dt;
if(p.y>H+20){ powers.splice(i,1); continue; }
if(p.y+10>=paddle.y && p.y-10<=paddle.y+paddle.h && Math.abs(p.x-paddle.x)<=paddle.w/2+10){
applyPower(p); powers.splice(i,1);
}
}
}
function updateBooms(dt){
for(const ex of booms){
ex.t+=dt;
if(!ex.done && ex.t>=ex.delay){
ex.done=true;
for(const br of bricks){
if(!br.alive) continue;
const cx=br.x+br.w/2, cy=br.y+br.h/2;
if((cx-ex.x)*(cx-ex.x)+(cy-ex.y)*(cy-ex.y)<=ex.r*ex.r){
if(br.type==='B'){
br.alive=false; G.broken++; G.combo++; G.score+=75;
booms.push({ x:cx, y:cy, r:100, t:0, delay:.16, done:false });
burst(cx,cy,'#ff8787',20,240); addText(cx,cy,'+75','#fff');
}
else if(br.type==='X' && br.hp>1){ br.hp--; br.flash=1; burst(cx,cy,'#c3cad6',6,140); }
else destroyBrick(br);
}
}
burst(ex.x, ex.y, '#ffd43b', 30, 340); burst(ex.x, ex.y, '#ff8787', 20, 260);
shake(13); G.freeze=Math.max(G.freeze,.04);
if(bricks.every(b=>!b.alive)) enterClear();
}
}
booms=booms.filter(e=>e.t<e.delay+.45);
}
function updateParts(dt){
for(let i=parts.length-1;i>=0;i--){
const p=parts[i]; p.life-=dt;
if(p.life<=0){ parts.splice(i,1); continue; }
p.x+=p.vx*dt; p.y+=p.vy*dt; p.vy+=500*dt; p.vx*=(1-2*dt);
}
}
function updateTexts(dt){
for(let i=texts.length-1;i>=0;i--){
const t=texts[i]; t.life-=dt*.8; t.y-=40*dt;
if(t.life<=0) texts.splice(i,1);
}
}
function update(dt){
G.time+=dt;
for(const s of stars){ s.y+=s.z*14*dt; if(s.y>H){ s.y-=H; s.x=rand(0,W); } }
updateParts(dt); updateTexts(dt);
if(G.freeze>0){ G.freeze-=dt; return; }
if(G.mode==='play' || G.mode==='serve'){
G.levelT+=dt;
updatePaddle(dt);
if(G.mode==='serve'){
const b=balls[0]; b.x=paddle.x; b.y=paddle.y-b.r-3; b.trail.length=0;
} else {
slowT=Math.max(0, slowT-dt);
if(paddle.expandT>0) paddle.expandT-=dt;
const tw=paddle.expandT>0 ? paddle.base*1.55 : paddle.base;
paddle.w+=(tw-paddle.w)*Math.min(1,dt*10);
if(paddle.expandT<=0) paddle.w=paddle.base;
updateBalls(dt); updatePowers(dt); updateBooms(dt);
}
for(const br of bricks) if(br.flash>0) br.flash-=dt*4;
} else if(G.mode==='clear'){
G.clearT-=dt; updateBooms(dt); updatePowers(dt);
if(G.clearT<=0) nextLevel();
}
G.shake=Math.max(0, G.shake-dt*36);
G.flash=Math.max(0, G.flash-dt*2.4);
paddle.squash=Math.max(0, paddle.squash-dt*5);
}
/* ---------------- render ---------------- */
function drawBricks(){
for(const br of bricks){
if(!br.alive) continue;
const ap=clamp((G.levelT-br.born)/.3, 0, 1);
if(ap<=0) continue;
ctx.save();
ctx.globalAlpha=ap;
const cx=br.x+br.w/2, cy=br.y+br.h/2;
ctx.translate(cx,cy); ctx.scale(1+(1-ap)*.6, 1+(1-ap)*.6); ctx.translate(-cx,-cy);
ctx.shadowColor=br.color; ctx.shadowBlur=10+br.flash*18;
ctx.fillStyle=br.color; rr(br.x,br.y,br.w,br.h,5); ctx.fill();
ctx.shadowBlur=0;
ctx.fillStyle='rgba(255,255,255,.28)'; rr(br.x+2,br.y+2,br.w-4,br.h*.38,4); ctx.fill();
if(br.type==='B'){
ctx.fillStyle='#2b0a12';
ctx.beginPath(); ctx.arc(cx,cy+2,7,0,TAU); ctx.fill();
ctx.strokeStyle='#2b0a12'; ctx.lineWidth=2;
ctx.beginPath(); ctx.moveTo(cx+4,cy-4); ctx.quadraticCurveTo(cx+9,cy-12,cx+13,cy-9); ctx.stroke();
ctx.fillStyle='#ffe066';
ctx.beginPath(); ctx.arc(cx+13,cy-9,2.5+Math.sin(G.time*20)*1,0,TAU); ctx.fill();
}
if(br.type==='X' && br.hp<br.maxHp){
ctx.strokeStyle='rgba(40,40,60,.7)'; ctx.lineWidth=1.5;
ctx.beginPath();
ctx.moveTo(br.x+br.w*.2,br.y+2); ctx.lineTo(br.x+br.w*.45,br.y+br.h*.6); ctx.lineTo(br.x+br.w*.3,br.y+br.h-2);
ctx.moveTo(br.x+br.w*.75,br.y+3); ctx.lineTo(br.x+br.w*.6,br.y+br.h*.55);
ctx.stroke();
}
if(br.flash>0){ ctx.fillStyle='rgba(255,255,255,'+(br.flash*.7)+')'; rr(br.x,br.y,br.w,br.h,5); ctx.fill(); }
ctx.restore();
}
}
function drawPaddle(){
const p=paddle, sq=p.squash;
const w=p.w*(1+sq*.35), h=p.h*(1-sq*.35);
const x=p.x-w/2, y=p.y+(p.h-h)/2;
ctx.save();
ctx.shadowColor='#4dabf7'; ctx.shadowBlur=16;
const g=ctx.createLinearGradient(x,y,x,y+h);
g.addColorStop(0,'#9fd0ff'); g.addColorStop(.5,'#4dabf7'); g.addColorStop(1,'#1c6dd9');
ctx.fillStyle=g; rr(x,y,w,h,h/2); ctx.fill();
ctx.shadowBlur=0;
ctx.fillStyle='rgba(255,255,255,.5)'; rr(x+6,y+2,w-12,h*.3,h*.15); ctx.fill();
ctx.restore();
}
function drawBalls(){
for(const b of balls){
for(let i=0;i<b.trail.length;i++){
const t=b.trail[i], a=(i+1)/b.trail.length;
ctx.globalAlpha=a*.25; ctx.fillStyle='#8ec5ff';
ctx.beginPath(); ctx.arc(t.x,t.y,b.r*a,0,TAU); ctx.fill();
}
ctx.globalAlpha=1;
ctx.save();
ctx.shadowColor='#aee2ff'; ctx.shadowBlur=18;
const g=ctx.createRadialGradient(b.x-2,b.y-2,1,b.x,b.y,b.r);
g.addColorStop(0,'#ffffff'); g.addColorStop(1,'#74c0fc');
ctx.fillStyle=g;
ctx.beginPath(); ctx.arc(b.x,b.y,b.r,0,TAU); ctx.fill();
ctx.restore();
}
}
function drawPowers(){
for(const p of powers){
ctx.save();
ctx.shadowColor=p.c; ctx.shadowBlur=14;
ctx.fillStyle=p.c; rr(p.x-16,p.y-10,32,20,10); ctx.fill();
ctx.shadowBlur=0;
ctx.fillStyle='rgba(0,0,0,.55)';
ctx.font='bold 13px ui-monospace,monospace';
ctx.textAlign='center'; ctx.textBaseline='middle';
ctx.fillText(p.k, p.x, p.y+1);
ctx.restore();
}
}
function drawBooms(){
for(const ex of booms){
const k=clamp(ex.t/(ex.delay+.4), 0, 1);
ctx.save();
ctx.globalAlpha=(1-k)*.9;
ctx.strokeStyle='#ffd43b'; ctx.lineWidth=4*(1-k)+1;
ctx.beginPath(); ctx.arc(ex.x,ex.y,ex.r*k,0,TAU); ctx.stroke();
ctx.strokeStyle='#ff8787'; ctx.lineWidth=2;
ctx.beginPath(); ctx.arc(ex.x,ex.y,ex.r*k*.7,0,TAU); ctx.stroke();
ctx.restore();
}
}
function drawParts(){
ctx.save();
ctx.globalCompositeOperation='lighter';
for(const p of parts){
ctx.globalAlpha=clamp(p.life/p.max,0,1);
ctx.fillStyle=p.color;
ctx.fillRect(p.x-p.size/2, p.y-p.size/2, p.size, p.size);
}
ctx.restore();
}
function drawTexts(){
ctx.save();
ctx.textAlign='center'; ctx.textBaseline='middle';
for(const t of texts){
ctx.globalAlpha=clamp(t.life,0,1);
ctx.font='bold 16px ui-monospace,monospace';
ctx.fillStyle=t.color; ctx.shadowColor=t.color; ctx.shadowBlur=8;
ctx.fillText(t.str, t.x, t.y);
}
ctx.restore();
}
function badge(x,y,label,k,c){
ctx.fillStyle='rgba(255,255,255,.08)'; rr(x,y-8,58,16,8); ctx.fill();
ctx.fillStyle=c; rr(x,y-8,58*clamp(k,0,1),16,8); ctx.fill();
ctx.fillStyle='#0b1030'; ctx.font='bold 10px ui-monospace,monospace';
ctx.textAlign='center'; ctx.textBaseline='middle';
ctx.fillText(label, x+29, y);
}
function drawHUD(){
ctx.save();
ctx.fillStyle='rgba(255,255,255,.06)'; ctx.fillRect(0,0,W,40);
ctx.strokeStyle='rgba(140,170,255,.25)';
ctx.beginPath(); ctx.moveTo(0,40.5); ctx.lineTo(W,40.5); ctx.stroke();
ctx.textBaseline='middle'; ctx.font='bold 18px ui-monospace,monospace';
ctx.textAlign='left'; ctx.fillStyle='#8ec5ff';
ctx.fillText('SCORE '+String(G.score).padStart(6,'0'), 16, 21);
ctx.textAlign='center'; ctx.fillStyle='#9d6bff';
ctx.fillText('LEVEL '+(G.level+1)+' / '+LEVELS.length, W/2, 21);
ctx.textAlign='right'; ctx.fillStyle='#ff8787';
ctx.fillText('BEST '+G.best, W-16, 21);
for(let i=0;i<G.lives;i++){
ctx.fillStyle='#ff5d73'; ctx.shadowColor='#ff5d73'; ctx.shadowBlur=8;
ctx.beginPath(); ctx.arc(W-24-i*20, 50, 5, 0, TAU); ctx.fill();
}
ctx.shadowBlur=0;
let bx=16;
if(paddle.expandT>0){ badge(bx,60,'WIDE',paddle.expandT/12,'#69db7c'); bx+=70; }
if(slowT>0){ badge(bx,60,'SLOW',slowT/9,'#ffd43b'); bx+=70; }
if(G.combo>=5){
ctx.fillStyle='#ffd43b'; ctx.font='bold 14px ui-monospace,monospace'; ctx.textAlign='left';
ctx.fillText('COMBO x'+(1+Math.floor(G.combo/5)), bx, 60);
}
if(muted){ ctx.fillStyle='#666'; ctx.font='12px ui-monospace,monospace'; ctx.textAlign='right'; ctx.fillText('MUTED', W-16, 60); }
ctx.restore();
}
function drawCenter(big, small, color){
ctx.save();
ctx.fillStyle='rgba(5,6,15,.72)'; ctx.fillRect(0,0,W,H);
ctx.textAlign='center'; ctx.textBaseline='middle';
ctx.font='bold 44px ui-monospace,monospace';
ctx.fillStyle=color; ctx.shadowColor=color; ctx.shadowBlur=24;
ctx.fillText(big, W/2, H*.42);
ctx.shadowBlur=0;
ctx.font='18px ui-monospace,monospace'; ctx.fillStyle='#cdd7ff';
ctx.fillText(small, W/2, H*.42+48);
ctx.restore();
}
function drawServe(){
ctx.save();
ctx.textAlign='center'; ctx.textBaseline='middle';
ctx.globalAlpha=.6+.4*Math.sin(G.time*5);
ctx.font='bold 20px ui-monospace,monospace'; ctx.fillStyle='#fff';
ctx.fillText(G.levelT<2 ? 'LEVEL '+(G.level+1) : 'SPACE / CLICK TO LAUNCH', W/2, H*.62);
ctx.restore();
}
function drawMenu(){
ctx.save();
ctx.fillStyle='rgba(5,6,15,.68)'; ctx.fillRect(0,0,W,H);
ctx.textAlign='center'; ctx.textBaseline='middle';
ctx.font='bold 56px ui-monospace,monospace';
const g=ctx.createLinearGradient(W/2-220,0,W/2+220,0);
g.addColorStop(0,'#ff5d73'); g.addColorStop(.5,'#ffd43b'); g.addColorStop(1,'#4dabf7');
ctx.fillStyle=g; ctx.shadowColor='#4dabf7'; ctx.shadowBlur=30;
ctx.fillText('NEON BREAKER', W/2, H*.28);
ctx.shadowBlur=0;
ctx.font='16px ui-monospace,monospace'; ctx.fillStyle='#cdd7ff';
ctx.fillText('SMASH BRICKS · CHAIN COMBOS · CATCH POWER-UPS', W/2, H*.28+52);
ctx.fillStyle='#8ec5ff';
ctx.fillText('MOVE · MOUSE or ← → / A D', W/2, H*.46);
ctx.fillText('LAUNCH · SPACE or CLICK', W/2, H*.46+30);
ctx.fillText('P PAUSE · M MUTE', W/2, H*.46+60);
ctx.globalAlpha=.6+.4*Math.sin(G.time*5);
ctx.font='bold 22px ui-monospace,monospace'; ctx.fillStyle='#69db7c';
ctx.fillText('PRESS SPACE OR CLICK TO START', W/2, H*.68);
ctx.globalAlpha=1;
if(G.best>0){ ctx.font='15px ui-monospace,monospace'; ctx.fillStyle='#ffd43b'; ctx.fillText('BEST '+G.best, W/2, H*.68+40); }
ctx.restore();
}
function drawOver(){
ctx.save();
ctx.fillStyle='rgba(20,5,10,.78)'; ctx.fillRect(0,0,W,H);
ctx.textAlign='center'; ctx.textBaseline='middle';
ctx.font='bold 52px ui-monospace,monospace';
ctx.fillStyle='#ff5d73'; ctx.shadowColor='#ff5d73'; ctx.shadowBlur=26;
ctx.fillText('GAME OVER', W/2, H*.34);
ctx.shadowBlur=0;
ctx.font='22px ui-monospace,monospace'; ctx.fillStyle='#fff';
ctx.fillText('SCORE '+G.score, W/2, H*.34+62);
ctx.font='16px ui-monospace,monospace'; ctx.fillStyle='#ffd43b';
ctx.fillText(G.score>=G.best ? 'NEW BEST!' : 'BEST '+G.best, W/2, H*.34+94);
ctx.globalAlpha=.6+.4*Math.sin(G.time*5);
ctx.font='bold 20px ui-monospace,monospace'; ctx.fillStyle='#8ec5ff';
ctx.fillText('SPACE / CLICK TO PLAY AGAIN', W/2, H*.34+142);
ctx.restore();
}
function drawWin(){
ctx.save();
ctx.fillStyle='rgba(5,15,10,.78)'; ctx.fillRect(0,0,W,H);
ctx.textAlign='center'; ctx.textBaseline='middle';
ctx.font='bold 52px ui-monospace,monospace';
ctx.fillStyle='#69db7c'; ctx.shadowColor='#69db7c'; ctx.shadowBlur=26;
ctx.fillText('YOU WIN!', W/2, H*.34);
ctx.shadowBlur=0;
ctx.font='22px ui-monospace,monospace'; ctx.fillStyle='#fff';
ctx.fillText('FINAL SCORE '+G.score, W/2, H*.34+62);
ctx.font='16px ui-monospace,monospace'; ctx.fillStyle='#ffd43b';
ctx.fillText(G.score>=G.best ? 'NEW BEST!' : 'BEST '+G.best, W/2, H*.34+94);
ctx.globalAlpha=.6+.4*Math.sin(G.time*5);
ctx.font='bold 20px ui-monospace,monospace'; ctx.fillStyle='#8ec5ff';
ctx.fillText('SPACE / CLICK FOR MENU', W/2, H*.34+142);
ctx.restore();
}
function render(){
const g=ctx.createLinearGradient(0,0,0,H);
g.addColorStop(0,'#0b1030'); g.addColorStop(.6,'#070a18'); g.addColorStop(1,'#05060f');
ctx.fillStyle=g; ctx.fillRect(0,0,W,H);
ctx.save();
for(const s of stars){ ctx.globalAlpha=.25+.5*s.z; ctx.fillStyle='#9db4ff'; ctx.fillRect(s.x,s.y,s.s,s.s); }
ctx.restore();
ctx.save();
if(G.shake>0) ctx.translate(rand(-G.shake,G.shake)*.5, rand(-G.shake,G.shake)*.5);
drawBricks(); drawPowers(); drawPaddle(); drawBalls(); drawBooms(); drawParts(); drawTexts();
ctx.restore();
drawHUD();
if(G.mode==='menu') drawMenu();
else if(G.mode==='clear') drawCenter('LEVEL '+(G.level+1)+' CLEAR!', 'BONUS +'+G.lastBonus, '#69db7c');
else if(G.mode==='over') drawOver();
else if(G.mode==='win') drawWin();
else if(G.paused) drawCenter('PAUSED', 'PRESS P TO RESUME', '#8ec5ff');
else if(G.mode==='serve') drawServe();
if(G.flash>0){ ctx.fillStyle='rgba(255,60,80,'+(G.flash*.28)+')'; ctx.fillRect(0,0,W,H); }
const v=ctx.createRadialGradient(W/2,H/2,H*.45,W/2,H/2,H*.95);
v.addColorStop(0,'rgba(0,0,0,0)'); v.addColorStop(1,'rgba(0,0,0,.45)');
ctx.fillStyle=v; ctx.fillRect(0,0,W,H);
}
/* ---------------- input ---------------- */
const keys={};
function primaryAction(){
if(G.mode==='menu'){ sfx('click'); startGame(); }
else if(G.mode==='serve') launch();
else if(G.mode==='clear') nextLevel();
else if(G.mode==='over'){ sfx('click'); startGame(); }
else if(G.mode==='win'){ G.mode='menu'; }
}
window.addEventListener('keydown', e=>{
const k=e.key.toLowerCase();
if(k===' '||k==='arrowleft'||k==='arrowright'||k==='arrowup'||k==='arrowdown') e.preventDefault();
keys[k]=true;
ac();
if(k===' ') primaryAction();
else if(k==='p'||k==='escape'){ if(G.mode==='play'||G.mode==='serve') G.paused=!G.paused; }
else if(k==='m') muted=!muted;
else if((k==='arrowleft'||k==='arrowright'||k==='a'||k==='d') && G.mode==='serve') launch();
});
window.addEventListener('keyup', e=>{ keys[e.key.toLowerCase()]=false; });
window.addEventListener('blur', ()=>{ if(G.mode==='play'||G.mode==='serve') G.paused=true; });
function canvasX(e){
const r=canvas.getBoundingClientRect();
const cx=(e.touches && e.touches[0]) ? e.touches[0].clientX : e.clientX;
return (cx-r.left)/r.width*W;
}
canvas.addEventListener('mousemove', e=>{
if(G.paused) return;
paddle.x=clamp(canvasX(e), paddle.w/2+6, W-paddle.w/2-6);
});
canvas.addEventListener('mousedown', ()=>{ ac(); primaryAction(); });
canvas.addEventListener('touchstart', e=>{
e.preventDefault(); ac();
paddle.x=clamp(canvasX(e), paddle.w/2+6, W-paddle.w/2-6);
primaryAction();
}, {passive:false});
canvas.addEventListener('touchmove', e=>{
e.preventDefault();
paddle.x=clamp(canvasX(e), paddle.w/2+6, W-paddle.w/2-6);
}, {passive:false});
/* ---------------- loop ---------------- */
let last=performance.now();
function loop(t){
requestAnimationFrame(loop);
let dt=(t-last)/1000; last=t;
if(dt>1/20) dt=1/20;
if(!G.paused) update(dt);
render();
canvas.style.cursor=(G.mode==='play'||G.mode==='serve')&&!G.paused ? 'none' : 'default';
}
requestAnimationFrame(loop);
})();
</script>
</body>
</html>Compare with
Ling 3.1 Flash: other attempts
- Ling 3.1 Flash, Watch: Queued · #6 of 15 paid · not before 23 Oct
- Ling 3.1 Flash, Landing: No file after 2 runs, used all 32,768 output tokens

- About · 147 words