Run details
- Model
- claude-sonnet-5-5
- Route
- Claude Code CLI
- Reasoning
- provider default
- Date
- 2 Oct 2026
- Time
- 53 s
- Size
- 13 kB
- Tokens
- 4 in, 8,273 out
- List price
- $0.083 ($2 in / $10 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
13 kB 312 lines Raw
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Breakout</title>
<style>
html,body{margin:0;height:100%;background:#07070f;color:#cfe;font-family:ui-monospace,Menlo,Consolas,monospace;overflow:hidden}
body{display:flex;align-items:center;justify-content:center}
canvas{background:#0b0b1a;max-width:100vw;max-height:100vh;box-shadow:0 0 40px #0ff3;border-radius:6px;cursor:none;touch-action:none}
</style>
</head>
<body>
<canvas id="c" width="800" height="600"></canvas>
<script>
(()=>{
const cv=document.getElementById('c'),ctx=cv.getContext('2d');
const W=800,H=600;
const PH=14,BR=7;
const COLS=10,BW=68,BH=24,BGAP=6,BX0=(W-(COLS*(BW+BGAP)-BGAP))/2,BY0=70;
const hues=[0,25,50,120,180,220,280,320];
// ---- audio (synthesized, no network) ----
let ac=null;
function beep(f,d,type='square',vol=.06,slide=0){
try{
ac=ac||new (window.AudioContext||window.webkitAudioContext)();
const o=ac.createOscillator(),g=ac.createGain();
o.type=type;o.frequency.value=f;
if(slide)o.frequency.exponentialRampToValueAtTime(Math.max(30,f+slide),ac.currentTime+d);
g.gain.value=vol;g.gain.exponentialRampToValueAtTime(.0001,ac.currentTime+d);
o.connect(g);g.connect(ac.destination);o.start();o.stop(ac.currentTime+d);
}catch(e){}
}
// ---- levels: strings, '.' empty, digit = hits (1-3), '#' = unbreakable ----
const LEVELS=[
["..........","1111111111","1111111111","1111111111","1111111111"],
["1.1.1.1.1.",".1.1.1.1.1","1.1.1.1.1.","2222222222","..........","1111111111"],
["....11....","...1221...","..123321..",".12333321.","..123321..","...1221...","....11...."],
["#.......#.","2222222222","1.1.1.1.1.",".2.2.2.2.2","3333333333","#........#"],
["3333333333","2#2222222#","1.1.##.1.1","2#2222222#","3333333333","1111111111"],
["#2#2#2#2#2","2#3#3#3#3#","#3#1#1#1#3","3#1#.#.#1#","1#1#1#1#1#","3333333333"]
];
let state='title',level=0,score=0,lives=3,best=+(localStorage.getItem('bo_best')||0);
let bricks=[],balls=[],parts=[],pops=[],powers=[],trail=[];
let paddle={x:W/2,w:100,tw:100},shake=0,flash=0,combo=0,stateT=0,bannerT=0,sticky=0,slow=0;
let keys={},mouseX=null,usingMouse=false,stars=[];
for(let i=0;i<70;i++)stars.push({x:Math.random()*W,y:Math.random()*H,z:Math.random()*.8+.2});
function buildLevel(n){
bricks=[];
const L=LEVELS[n%LEVELS.length],loop=Math.floor(n/LEVELS.length);
L.forEach((row,r)=>{
[...row].forEach((ch,c)=>{
if(ch==='.')return;
const u=ch==='#';
let hp=u?99:Math.min(3,+ch+(loop>0&&!u&&Math.random()<.3?1:0));
bricks.push({x:BX0+c*(BW+BGAP),y:BY0+r*(BH+BGAP),hp,max:hp,u,hue:hues[(r+c)%hues.length],hit:0});
});
});
}
function speed(){return 5.2+level*.45+Math.min(combo,10)*.05}
function resetBall(){
balls=[{x:paddle.x,y:H-50-BR,vx:0,vy:0,stuck:true}];trail=[];combo=0;
}
function startLevel(n){
level=n;buildLevel(n);powers=[];paddle.tw=paddle.w=100;sticky=0;slow=0;resetBall();
bannerT=120;
}
function newGame(){score=0;lives=3;startLevel(0);state='play';beep(440,.2,'triangle',.08,400)}
function burst(x,y,hue,n=14,sp=4){
for(let i=0;i<n;i++){
const a=Math.random()*6.283,s=Math.random()*sp+1;
parts.push({x,y,vx:Math.cos(a)*s,vy:Math.sin(a)*s,life:1,hue,sz:Math.random()*3+1.5});
}
}
function pop(x,y,t,hue=50){pops.push({x,y,t,life:1,hue})}
function launch(){
const b=balls.find(b=>b.stuck);if(!b)return;
const a=-Math.PI/2+(Math.random()-.5)*.5,s=speed();
b.vx=Math.cos(a)*s;b.vy=Math.sin(a)*s;b.stuck=false;beep(520,.08,'square',.05,300);
}
function action(){
if(state==='title'||state==='over'||state==='win')newGame();
else if(state==='play')launch();
else if(state==='pause')state='play';
}
addEventListener('keydown',e=>{
if(['ArrowLeft','ArrowRight',' ','ArrowUp','ArrowDown'].includes(e.key))e.preventDefault();
keys[e.key.toLowerCase()]=true;usingMouse=false;
if(e.key===' '||e.key==='Enter')action();
if(e.key==='p'||e.key==='Escape'){if(state==='play')state='pause';else if(state==='pause')state='play'}
});
addEventListener('keyup',e=>keys[e.key.toLowerCase()]=false);
function mpos(e){const r=cv.getBoundingClientRect();mouseX=(e.clientX-r.left)*W/r.width;usingMouse=true}
cv.addEventListener('mousemove',mpos);
cv.addEventListener('mousedown',e=>{mpos(e);action()});
cv.addEventListener('touchstart',e=>{mpos(e.touches[0]);action();e.preventDefault()},{passive:false});
cv.addEventListener('touchmove',e=>{mpos(e.touches[0]);e.preventDefault()},{passive:false});
addEventListener('blur',()=>{if(state==='play')state='pause'});
function dropPower(x,y){
if(Math.random()>.16)return;
const types=['W','S','M','L','T'];// wide, sticky, multi, life, slow
powers.push({x,y,t:types[Math.floor(Math.random()*types.length)]});
}
function applyPower(t){
beep(700,.25,'triangle',.07,500);flash=.25;
if(t==='W'){paddle.tw=160;pop(paddle.x,H-50,'WIDE!',180)}
if(t==='S'){sticky=1;pop(paddle.x,H-50,'STICKY!',120)}
if(t==='L'){lives=Math.min(6,lives+1);pop(paddle.x,H-50,'+1 LIFE',0)}
if(t==='T'){slow=600;pop(paddle.x,H-50,'SLOW',200)}
if(t==='M'){
const src=balls.filter(b=>!b.stuck)[0];
if(src){for(const d of[-.5,.5]){const a=Math.atan2(src.vy,src.vx)+d,s=Math.hypot(src.vx,src.vy);
balls.push({x:src.x,y:src.y,vx:Math.cos(a)*s,vy:Math.sin(a)*s,stuck:false})}}
pop(paddle.x,H-50,'MULTI!',300);
}
}
const pcol={W:200,S:120,M:300,L:0,T:190};
function hitBrick(b,br){
if(br.u){beep(180,.07,'square',.05);br.hit=6;shake=Math.max(shake,2);return}
br.hp--;br.hit=6;combo++;
const pts=10*(1+Math.min(combo,10)*.2)|0;
if(br.hp<=0){
score+=pts*br.max;
burst(br.x+BW/2,br.y+BH/2,br.hue,18,5);
pop(br.x+BW/2,br.y+BH/2,'+'+pts*br.max,br.hue);
beep(300+Math.min(combo,12)*50,.12,'square',.06,200);
shake=Math.max(shake,4);
dropPower(br.x+BW/2,br.y+BH/2);
bricks.splice(bricks.indexOf(br),1);
}else{score+=pts;burst(br.x+BW/2,br.y+BH/2,br.hue,6,3);beep(260,.07,'square',.05)}
if(score>best){best=score;localStorage.setItem('bo_best',best)}
}
function update(){
stateT++;
// paddle
if(state==='play'){
const sp=10;
if(keys['arrowleft']||keys['a']){paddle.x-=sp;}
if(keys['arrowright']||keys['d']){paddle.x+=sp;}
if(usingMouse&&mouseX!==null)paddle.x+=(mouseX-paddle.x)*.5;
paddle.w+=(paddle.tw-paddle.w)*.15;
paddle.x=Math.max(paddle.w/2,Math.min(W-paddle.w/2,paddle.x));
if(slow>0)slow--;
const py=H-40;
for(const b of balls){
if(b.stuck){b.x=paddle.x;b.y=py-PH/2-BR;continue}
const k=slow>0?.65:1;
// sub-steps to avoid tunneling
const steps=3;
for(let s=0;s<steps;s++){
b.x+=b.vx*k/steps;b.y+=b.vy*k/steps;
if(b.x<BR){b.x=BR;b.vx=Math.abs(b.vx);beep(200,.04,'sine',.05)}
if(b.x>W-BR){b.x=W-BR;b.vx=-Math.abs(b.vx);beep(200,.04,'sine',.05)}
if(b.y<BR){b.y=BR;b.vy=Math.abs(b.vy);beep(200,.04,'sine',.05)}
// paddle
if(b.vy>0&&b.y+BR>=py-PH/2&&b.y-BR<=py+PH/2&&b.x>=paddle.x-paddle.w/2-BR&&b.x<=paddle.x+paddle.w/2+BR){
const rel=(b.x-paddle.x)/(paddle.w/2),a=-Math.PI/2+rel*1.1,sp2=speed();
b.vx=Math.cos(a)*sp2;b.vy=Math.sin(a)*sp2;b.y=py-PH/2-BR;
combo=0;shake=3;burst(b.x,b.y+BR,200,6,2);beep(330,.06,'triangle',.08);
if(sticky){b.stuck=true;b.vx=b.vy=0;sticky=0}
}
// bricks
for(const br of bricks){
if(b.x+BR>br.x&&b.x-BR<br.x+BW&&b.y+BR>br.y&&b.y-BR<br.y+BH){
const ox=Math.min(b.x+BR-br.x,br.x+BW-(b.x-BR)),oy=Math.min(b.y+BR-br.y,br.y+BH-(b.y-BR));
if(ox<oy){b.vx=(b.x<br.x+BW/2?-1:1)*Math.abs(b.vx);b.x+=b.vx>0?ox:-ox}
else{b.vy=(b.y<br.y+BH/2?-1:1)*Math.abs(b.vy);b.y+=b.vy>0?oy:-oy}
hitBrick(b,br);break;
}
}
}
trail.push({x:b.x,y:b.y,l:1});
}
balls=balls.filter(b=>b.y<H+20);
if(!balls.length){
lives--;shake=14;flash=.4;beep(120,.5,'sawtooth',.08,-80);
burst(paddle.x,H-40,0,30,6);
if(lives<=0){state='over';stateT=0}else resetBall();
}
// powerups
for(const p of powers){p.y+=2.2;
if(p.y>H-40-PH&&p.y<H-30&&Math.abs(p.x-paddle.x)<paddle.w/2+10){p.dead=1;applyPower(p.t)}
else if(p.y>H+10)p.dead=1}
powers=powers.filter(p=>!p.dead);
// clear
if(!bricks.some(b=>!b.u)){
score+=500;beep(600,.5,'triangle',.08,600);flash=.5;
for(let i=0;i<6;i++)burst(Math.random()*W,Math.random()*300+50,hues[i],25,6);
state='clear';stateT=0;
}
}
if(state==='clear'&&stateT>110){
if(level+1>=LEVELS.length*2){state='win'}
else{startLevel(level+1);state='play'}
}
// fx
for(const p of parts){p.x+=p.vx;p.y+=p.vy;p.vy+=.12;p.vx*=.98;p.life-=.025}
parts=parts.filter(p=>p.life>0);
for(const p of pops){p.y-=.8;p.life-=.02}
pops=pops.filter(p=>p.life>0);
for(const t of trail)t.l-=.12;
trail=trail.filter(t=>t.l>0);
for(const b of bricks)if(b.hit>0)b.hit--;
for(const s of stars){s.y+=s.z*.4;if(s.y>H){s.y=0;s.x=Math.random()*W}}
shake*=.85;flash*=.9;if(bannerT>0)bannerT--;
}
function txt(s,x,y,size,col='#fff',align='center',glow=null){
ctx.font=`bold ${size}px ui-monospace,Menlo,Consolas,monospace`;
ctx.textAlign=align;
if(glow){ctx.shadowColor=glow;ctx.shadowBlur=14}
ctx.fillStyle=col;ctx.fillText(s,x,y);ctx.shadowBlur=0;
}
function draw(){
ctx.save();
ctx.clearRect(0,0,W,H);
const g=ctx.createLinearGradient(0,0,0,H);g.addColorStop(0,'#10102a');g.addColorStop(1,'#07070f');
ctx.fillStyle=g;ctx.fillRect(0,0,W,H);
for(const s of stars){ctx.fillStyle=`rgba(180,220,255,${s.z*.6})`;ctx.fillRect(s.x,s.y,s.z*2,s.z*2)}
if(shake>.3)ctx.translate((Math.random()-.5)*shake,(Math.random()-.5)*shake);
// bricks
for(const b of bricks){
const l=b.u?55:40+ (b.hp/b.max)*20+b.hit*4;
ctx.fillStyle=b.u?`hsl(220,10%,${l}%)`:`hsl(${b.hue},85%,${l}%)`;
ctx.shadowColor=b.u?'#889':`hsl(${b.hue},90%,55%)`;ctx.shadowBlur=b.hit?18:6;
ctx.beginPath();ctx.roundRect(b.x,b.y,BW,BH,4);ctx.fill();ctx.shadowBlur=0;
ctx.fillStyle='rgba(255,255,255,.22)';ctx.fillRect(b.x+3,b.y+2,BW-6,4);
if(!b.u&&b.max>1){ctx.fillStyle='rgba(0,0,0,.35)';for(let i=0;i<b.hp;i++)ctx.fillRect(b.x+8+i*9,b.y+BH-8,6,4)}
}
// powerups
for(const p of powers){
ctx.fillStyle=`hsl(${pcol[p.t]},90%,55%)`;ctx.shadowColor=ctx.fillStyle;ctx.shadowBlur=12;
ctx.beginPath();ctx.roundRect(p.x-12,p.y-10,24,20,6);ctx.fill();ctx.shadowBlur=0;
txt(p.t,p.x,p.y+5,14,'#000');
}
// paddle
const py=H-40;
ctx.fillStyle='#4df';ctx.shadowColor='#0ff';ctx.shadowBlur=16;
ctx.beginPath();ctx.roundRect(paddle.x-paddle.w/2,py-PH/2,paddle.w,PH,7);ctx.fill();ctx.shadowBlur=0;
if(sticky){ctx.fillStyle='#6f6';ctx.fillRect(paddle.x-paddle.w/2+6,py-PH/2-3,paddle.w-12,3)}
// trail & balls
for(const t of trail){ctx.fillStyle=`rgba(255,255,255,${t.l*.3})`;ctx.beginPath();ctx.arc(t.x,t.y,BR*t.l,0,6.283);ctx.fill()}
for(const b of balls){
ctx.fillStyle='#fff';ctx.shadowColor=slow>0?'#6cf':'#fff';ctx.shadowBlur=18;
ctx.beginPath();ctx.arc(b.x,b.y,BR,0,6.283);ctx.fill();ctx.shadowBlur=0;
}
// particles
for(const p of parts){ctx.globalAlpha=Math.max(0,p.life);ctx.fillStyle=`hsl(${p.hue},90%,60%)`;ctx.fillRect(p.x,p.y,p.sz,p.sz)}
ctx.globalAlpha=1;
for(const p of pops){ctx.globalAlpha=Math.max(0,p.life);txt(p.t,p.x,p.y,16,`hsl(${p.hue},90%,70%)`);}
ctx.globalAlpha=1;
ctx.restore();
if(flash>.02){ctx.fillStyle=`rgba(255,255,255,${flash*.35})`;ctx.fillRect(0,0,W,H)}
// HUD
txt('SCORE '+score,16,30,20,'#fff','left','#0ff');
txt('LEVEL '+(level+1),W/2,30,20,'#ff8','center','#fa0');
txt('♥'.repeat(lives),W-16,30,20,'#f46','right','#f04');
txt('BEST '+best,16,52,12,'#789','left');
if(combo>2&&state==='play')txt('COMBO x'+combo,W-16,52,14,'#fc4','right');
if(slow>0)txt('SLOW',W/2,52,12,'#6cf');
if(bannerT>0&&state==='play'){
ctx.globalAlpha=Math.min(1,bannerT/40);
txt('LEVEL '+(level+1),W/2,H/2+40,48,'#fff','center','#0ff');ctx.globalAlpha=1;
}
if(state==='play'&&balls.some(b=>b.stuck))txt('SPACE / CLICK to launch',W/2,H-90,16,'#9ab');
const overlay=(a,b,c)=>{
ctx.fillStyle='rgba(5,5,15,.75)';ctx.fillRect(0,0,W,H);
txt(a,W/2,H/2-30,56,'#fff','center','#0ff');
if(b)txt(b,W/2,H/2+15,22,'#fc4');
if(c)txt(c,W/2,H/2+55,16,'#9ab');
};
if(state==='title'){
overlay('BREAKOUT','Clear all the bricks. Don\'t drop the ball.','Move: mouse or ←/→ (A/D) · Launch: click or SPACE · Pause: P');
txt('Press SPACE or click to start',W/2,H/2+100,18,'#fff','center','#0ff');
txt('Power-ups: W wide · S sticky · M multiball · T slow · L life',W/2,H/2+135,13,'#789');
}
if(state==='pause')overlay('PAUSED','','Press P or click to resume');
if(state==='over')overlay('GAME OVER','Score '+score+(score>=best?' — NEW BEST!':''),'Press SPACE or click to play again');
if(state==='win')overlay('YOU WIN!','Final score '+score,'Press SPACE or click to play again');
if(state==='clear'){
txt('LEVEL CLEAR! +500',W/2,H/2,44,'#fff','center','#f0f');
}
}
let last=0,acc=0;
function frame(t){
acc+=Math.min(50,t-last);last=t;
while(acc>=1000/60){if(state!=='pause')update();acc-=1000/60}
draw();requestAnimationFrame(frame);
}
paddle.x=W/2;buildLevel(0);resetBall();
requestAnimationFrame(t=>{last=t;frame(t)});
})();
</script>
</body>
</html>

