@liveloop · 5/18/2026, 10:15:39 AM
Initial version — all lines are new.
+<style>+ html,body{height:100%;margin:0;background:#06060f;overflow:hidden;}+ *{box-sizing:border-box;}+ #wrap{position:relative;height:100%;width:100%;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;}+ canvas{display:block;width:100%;height:100%;touch-action:none;}+ #hud{position:absolute;top:0;left:0;right:0;display:flex;justify-content:space-between;align-items:flex-start;padding:.7rem .95rem;color:#dbeafe;font-size:.86rem;font-weight:800;letter-spacing:.04em;pointer-events:none;text-shadow:0 0 10px rgba(0,0,0,.95);}+ #hud .lab{font-size:.56rem;opacity:.55;letter-spacing:.14em;margin-bottom:.05rem;}+ #hud .r{text-align:right;}+ #lives{color:#f472b6;font-size:1rem;letter-spacing:.1em;}+ #ov{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;text-align:center;padding:1.6rem;background:rgba(6,6,15,.85);color:#e9d5ff;cursor:pointer;-webkit-tap-highlight-color:transparent;touch-action:none;user-select:none;-webkit-user-select:none;}+ #ov h1{margin:0;font-size:2.15rem;font-weight:900;letter-spacing:.02em;background:linear-gradient(90deg,#22d3ee,#c084fc,#f472b6);-webkit-background-clip:text;background-clip:text;color:transparent;}+ #ov .sub{margin:.1rem 0 0;font-size:.92rem;color:#a5b4fc;}+ #ov .big{margin:.1rem 0 0;font-size:1.05rem;font-weight:800;color:#e9d5ff;}+ #ov .pulse{margin-top:.5rem;font-size:.84rem;color:#67e8f9;animation:nbpulse 1.3s ease-in-out infinite;}+ @keyframes nbpulse{0%,100%{opacity:.35}50%{opacity:1}}+</style>+<div id="wrap">+ <canvas id="cv"></canvas>+ <div id="hud">+ <div><div class="lab">SCORE</div><div id="score">0</div></div>+ <div class="r"><div class="lab">BEST</div><div id="best">0</div></div>+ <div class="r"><div class="lab">BALLS</div><div id="lives">|||</div></div>+ </div>+ <div id="ov">+ <h1 id="ovtitle">GLOW BREAKER</h1>+ <p class="sub" id="ovsub">Break every block. Don't drop the ball.</p>+ <p class="big" id="ovbig"></p>+ <p class="pulse">Tap to play</p>+ </div>+</div>+<script>+(function(){+ var LL=window.liveloop||null;+ var cv=document.getElementById('cv'), ctx=cv.getContext('2d');+ var ov=document.getElementById('ov'), ovsub=document.getElementById('ovsub'),+ ovbig=document.getElementById('ovbig'), ovtitle=document.getElementById('ovtitle');+ var scoreEl=document.getElementById('score'), bestEl=document.getElementById('best'),+ livesEl=document.getElementById('lives');+ var COLORS=['#f472b6','#fb923c','#facc15','#a3e635','#22d3ee'];+ var W=0,H=0,dpr=1;+ var state='start', score=0, best=0, lives=3, level=1;+ var paddle=null, ball=null, bricks=[], parts=[];+ var dockUntil=0, flashText='', flashUntil=0;+ var lastT=0, raf=0, running=false, keyL=false, keyR=false;++ function setCanvas(){+ var r=cv.getBoundingClientRect();+ W=Math.max(140,r.width); H=Math.max(180,r.height);+ dpr=Math.min(window.devicePixelRatio||1,2.5);+ cv.width=Math.round(W*dpr); cv.height=Math.round(H*dpr);+ ctx.setTransform(dpr,0,0,dpr,0,0);+ }+ function aliveCount(){+ var n=0; for(var i=0;i<bricks.length;i++) if(bricks[i].alive) n++;+ return n;+ }+ function buildBricks(){+ bricks=[];+ var cols=6, rows=Math.min(3+level,7);+ var mx=W*0.045, top=H*0.115, gap=W*0.014;+ var bw=(W-2*mx-(cols-1)*gap)/cols, bh=H*0.03;+ for(var r=0;r<rows;r++){+ for(var c=0;c<cols;c++){+ bricks.push({x:mx+c*(bw+gap),y:top+r*(bh+gap),w:bw,h:bh,+ color:COLORS[r%COLORS.length],alive:true});+ }+ }+ }+ function dockBall(){+ var sp=H*0.0118*(1+(level-1)*0.11);+ ball={x:paddle.x,y:paddle.y-H*0.035,r:Math.max(5,W*0.019),vx:0,vy:0,sp:sp,docked:true};+ dockUntil=performance.now()+700;+ }+ function launch(){+ var a=(-Math.PI/2)+(Math.random()*0.5-0.25);+ ball.vx=Math.cos(a)*ball.sp; ball.vy=Math.sin(a)*ball.sp; ball.docked=false;+ }+ function newGame(){+ score=0; lives=3; level=1; parts=[];+ paddle={w:W*0.23,h:Math.max(9,H*0.016),x:W/2,y:H*0.9};+ buildBricks(); dockBall(); state='playing'; syncHud();+ }+ function flash(t){ flashText=t; flashUntil=performance.now()+1100; }+ function syncHud(){+ scoreEl.textContent=score; bestEl.textContent=best;+ var s=''; for(var i=0;i<lives;i++) s+='|';+ livesEl.textContent=s||'-';+ }+ function pop(b){+ var cx=b.x+b.w/2, cy=b.y+b.h/2, i;+ for(i=0;i<8;i++){+ var a=Math.random()*6.283;+ parts.push({x:cx,y:cy,vx:Math.cos(a)*(1+Math.random()*2.4),+ vy:Math.sin(a)*(1+Math.random()*2.4),life:14+Math.random()*12,color:b.color});+ }+ }+ function normSpeed(){+ var m=Math.sqrt(ball.vx*ball.vx+ball.vy*ball.vy);+ if(m>0){ ball.vx=ball.vx/m*ball.sp; ball.vy=ball.vy/m*ball.sp; }+ var minv=ball.sp*0.34;+ if(Math.abs(ball.vy)<minv){+ ball.vy=(ball.vy<0?-1:1)*minv;+ normSpeedXOnly();+ }+ }+ function normSpeedXOnly(){+ var rem=ball.sp*ball.sp-ball.vy*ball.vy;+ if(rem<0) rem=0;+ ball.vx=(ball.vx<0?-1:1)*Math.sqrt(rem);+ }+ function gameOver(){+ state='over';+ if(score>best){ best=score; saveBest(); }+ syncHud();+ ovtitle.textContent='GAME OVER';+ ovsub.textContent='You reached level '+level;+ ovbig.textContent='Score '+score+' · Best '+best;+ ov.style.display='flex';+ }+ function substep(dt){+ ball.x+=ball.vx*dt; ball.y+=ball.vy*dt;+ var r=ball.r;+ if(ball.x-r<0){ ball.x=r; ball.vx=Math.abs(ball.vx); }+ else if(ball.x+r>W){ ball.x=W-r; ball.vx=-Math.abs(ball.vx); }+ if(ball.y-r<0){ ball.y=r; ball.vy=Math.abs(ball.vy); }+ var px=paddle.x-paddle.w/2;+ if(ball.vy>0 && ball.y+r>=paddle.y && ball.y-r<=paddle.y+paddle.h &&+ ball.x>=px-r && ball.x<=px+paddle.w+r){+ ball.y=paddle.y-r;+ var rel=(ball.x-paddle.x)/(paddle.w/2);+ if(rel>1)rel=1; if(rel<-1)rel=-1;+ ball.vx=ball.sp*0.8*rel;+ ball.vy=-Math.sqrt(Math.max(ball.sp*ball.sp-ball.vx*ball.vx,ball.sp*ball.sp*0.16));+ }+ for(var k=0;k<bricks.length;k++){+ var b=bricks[k]; if(!b.alive) continue;+ var nx=Math.max(b.x,Math.min(ball.x,b.x+b.w));+ var ny=Math.max(b.y,Math.min(ball.y,b.y+b.h));+ var ddx=ball.x-nx, ddy=ball.y-ny;+ if(ddx*ddx+ddy*ddy<=r*r){+ b.alive=false; score+=10*level; pop(b);+ ball.sp*=1.014; if(ball.sp>H*0.032) ball.sp=H*0.032;+ var rcx=(ball.x-(b.x+b.w/2))/(b.w/2);+ var rcy=(ball.y-(b.y+b.h/2))/(b.h/2);+ if(Math.abs(rcx)>=Math.abs(rcy)) ball.vx=(rcx>0?1:-1)*Math.abs(ball.vx);+ else ball.vy=(rcy>0?1:-1)*Math.abs(ball.vy);+ normSpeed(); syncHud();+ break;+ }+ }+ if(ball.y-r>H){+ lives--; syncHud();+ if(lives<=0) gameOver(); else dockBall();+ return;+ }+ if(aliveCount()===0){+ level++; buildBricks(); dockBall(); flash('LEVEL '+level);+ }+ }+ function step(dt){+ if(keyL) paddle.x-=W*0.026*dt;+ if(keyR) paddle.x+=W*0.026*dt;+ var hw=paddle.w/2;+ if(paddle.x<hw) paddle.x=hw;+ if(paddle.x>W-hw) paddle.x=W-hw;+ if(ball.docked){+ ball.x=paddle.x; ball.y=paddle.y-H*0.035;+ if(performance.now()>=dockUntil) launch();+ } else {+ var steps=Math.ceil(dt), i;+ for(i=0;i<steps && state==='playing';i++) substep(dt/steps);+ }+ for(var j=parts.length-1;j>=0;j--){+ var p=parts[j];+ p.x+=p.vx*dt; p.y+=p.vy*dt; p.vy+=0.07*dt; p.life-=dt;+ if(p.life<=0) parts.splice(j,1);+ }+ }+ function rr(x,y,w,h,rad){+ var r=Math.min(rad,w/2,h/2);+ 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 render(){+ var g=ctx.createLinearGradient(0,0,0,H);+ g.addColorStop(0,'#100c26'); g.addColorStop(1,'#06060f');+ ctx.fillStyle=g; ctx.fillRect(0,0,W,H);+ var i;+ for(i=0;i<bricks.length;i++){+ var b=bricks[i]; if(!b.alive) continue;+ ctx.shadowColor=b.color; ctx.shadowBlur=10;+ ctx.fillStyle=b.color; rr(b.x,b.y,b.w,b.h,b.h*0.32); ctx.fill();+ ctx.shadowBlur=0;+ ctx.fillStyle='rgba(255,255,255,0.28)';+ rr(b.x+b.w*0.12,b.y+b.h*0.2,b.w*0.76,b.h*0.22,b.h*0.12); ctx.fill();+ }+ for(i=0;i<parts.length;i++){+ var p=parts[i];+ ctx.globalAlpha=Math.max(0,Math.min(1,p.life/16));+ ctx.fillStyle=p.color;+ ctx.fillRect(p.x-2,p.y-2,4,4);+ }+ ctx.globalAlpha=1;+ if(paddle){+ var pg=ctx.createLinearGradient(paddle.x-paddle.w/2,0,paddle.x+paddle.w/2,0);+ pg.addColorStop(0,'#22d3ee'); pg.addColorStop(1,'#c084fc');+ ctx.shadowColor='#22d3ee'; ctx.shadowBlur=14;+ ctx.fillStyle=pg;+ rr(paddle.x-paddle.w/2,paddle.y,paddle.w,paddle.h,paddle.h/2); ctx.fill();+ ctx.shadowBlur=0;+ }+ if(ball){+ ctx.shadowColor='#67e8f9'; ctx.shadowBlur=16;+ ctx.fillStyle='#f0fdff';+ ctx.beginPath(); ctx.arc(ball.x,ball.y,ball.r,0,6.2832); ctx.fill();+ ctx.shadowBlur=0;+ }+ if(performance.now()<flashUntil){+ ctx.globalAlpha=Math.max(0,Math.min(1,(flashUntil-performance.now())/700));+ ctx.fillStyle='#e9d5ff';+ ctx.font='900 '+Math.round(H*0.06)+'px system-ui';+ ctx.textAlign='center'; ctx.textBaseline='middle';+ ctx.shadowColor='#c084fc'; ctx.shadowBlur=18;+ ctx.fillText(flashText,W/2,H*0.42);+ ctx.shadowBlur=0; ctx.globalAlpha=1;+ }+ }+ function frame(now){+ if(!running) return;+ var dt=(now-lastT)/16.667; lastT=now;+ if(dt<0.2)dt=0.2; if(dt>2.6)dt=2.6;+ if(state==='playing' && paddle) step(dt);+ render();+ raf=requestAnimationFrame(frame);+ }+ function startLoop(){+ if(running) return;+ running=true; lastT=performance.now(); raf=requestAnimationFrame(frame);+ }+ function stopLoop(){+ running=false; if(raf) cancelAnimationFrame(raf); raf=0;+ }+ function saveBest(){+ if(LL && LL.storage && LL.storage.set){ try{ LL.storage.set({best:best}); }catch(e){} }+ }+ function loadBest(){+ if(LL && LL.storage && LL.storage.get){+ LL.storage.get().then(function(s){+ if(s && typeof s.best==='number' && s.best>best){ best=s.best; syncHud(); }+ },function(){});+ }+ }+ function moveTo(clientX){+ if(!paddle) return;+ var r=cv.getBoundingClientRect(), x=clientX-r.left, hw=paddle.w/2;+ if(x<hw)x=hw; if(x>W-hw)x=W-hw;+ paddle.x=x;+ }+ cv.addEventListener('pointerdown',function(e){ moveTo(e.clientX); });+ cv.addEventListener('pointermove',function(e){ moveTo(e.clientX); });+ window.addEventListener('keydown',function(e){+ if(e.key==='ArrowLeft')keyL=true; else if(e.key==='ArrowRight')keyR=true;+ });+ window.addEventListener('keyup',function(e){+ if(e.key==='ArrowLeft')keyL=false; else if(e.key==='ArrowRight')keyR=false;+ });+ ov.addEventListener('pointerdown',function(e){+ e.preventDefault();+ ov.style.display='none';+ newGame();+ });+ function onResize(){+ var oW=W,oH=H;+ setCanvas();+ if(oW>0 && oH>0 && (oW!==W||oH!==H) && paddle){+ var sx=W/oW, sy=H/oH;+ paddle.x*=sx; paddle.w*=sx; paddle.h*=sy; paddle.y*=sy;+ ball.x*=sx; ball.y*=sy; ball.r*=sx; ball.vx*=sx; ball.vy*=sy; ball.sp*=sx;+ for(var k=0;k<bricks.length;k++){+ var b=bricks[k]; b.x*=sx; b.y*=sy; b.w*=sx; b.h*=sy;+ }+ for(k=0;k<parts.length;k++){ parts[k].x*=sx; parts[k].y*=sy; }+ }+ }+ window.addEventListener('resize',onResize);+ if(LL && LL.onResize) LL.onResize(onResize);+ if(LL && LL.onVisibility) LL.onVisibility(function(v){ if(v) startLoop(); else stopLoop(); });+ document.addEventListener('visibilitychange',function(){+ if(document.hidden) stopLoop(); else startLoop();+ });++ setCanvas(); syncHud(); loadBest(); startLoop();+})();+</script>