@liveloop · 6/9/2026, 7:20:23 PM
Initial version — all lines are new.
+<style>+ html,body{height:100%;margin:0;overflow:hidden;background:#F4EEE3;}+ *{box-sizing:border-box;}+ #wrap{position:relative;height:100%;width:100%;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;-webkit-tap-highlight-color:transparent;touch-action:none;user-select:none;-webkit-user-select:none;cursor:pointer;}+ canvas{display:block;width:100%;height:100%;position:absolute;inset:0;}+ #hud{position:absolute;top:0;left:0;z-index:2;display:flex;justify-content:flex-start;gap:1.8rem;align-items:flex-start;padding:1.1rem 1.25rem;pointer-events:none;}+ #hud .lab{font-size:.56rem;letter-spacing:.16em;text-transform:uppercase;color:#8F857B;font-weight:700;margin-bottom:.1rem;}+ #score{font-family:"Instrument Serif",Georgia,serif;font-size:2.6rem;line-height:.9;color:#16110D;}+ #best{font-size:.92rem;font-weight:800;color:#6B4EFE;text-align:left;}+ #ov{position:absolute;inset:0;z-index:3;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.35rem;text-align:center;padding:1.6rem;background:rgba(248,243,234,.72);backdrop-filter:blur(3px);}+ #ov h1{margin:0;font-family:"Instrument Serif",Georgia,serif;font-weight:400;font-size:3rem;line-height:1;color:#16110D;}+ #ov .sub{margin:.15rem 0 0;font-size:.95rem;color:#5C544C;}+ #ov .big{margin:.2rem 0 0;font-size:1.05rem;font-weight:800;color:#6B4EFE;}+ #ov .pulse{margin-top:.7rem;font-size:.85rem;font-weight:700;color:#FF5A1F;animation:p 1.3s ease-in-out infinite;}+ @keyframes p{0%,100%{opacity:.4}50%{opacity:1}}+ .hide{display:none!important;}+</style>+<div id="wrap">+ <canvas id="orbs"></canvas>+ <canvas id="cv"></canvas>+ <div id="hud">+ <div><div class="lab">Stacked</div><div id="score">0</div></div>+ <div><div class="lab">Best</div><div id="best">0</div></div>+ </div>+ <div id="ov">+ <h1 id="ovt">Stack</h1>+ <p class="sub" id="ovs">Tap to drop each block.<br>Line it up — the overhang slices off.</p>+ <p class="big" id="ovb"></p>+ <p class="pulse">Tap to play</p>+ </div>+</div>+<script>+(function(){+ var LL=window.liveloop||null;+ // --- sound: short tap SFX gated on the feed-wide mute; declareMedia so the+ // platform draws the sound control (carries across loops); SDK auto-unlocks. ---+ var muted = LL ? LL.muted : true;+ if(LL && LL.onMute){ try{ LL.onMute(function(m){ muted=m; }); }catch(e){} }+ if(LL && LL.declareMedia){ try{ LL.declareMedia({sound:true}); }catch(e){} }+ var _ac=null;+ function actx(){ if(!_ac){ try{ _ac=new (window.AudioContext||window.webkitAudioContext)(); }catch(e){ _ac=null; } } return _ac; }+ function tone(freq,dur,type,vol,delay){+ if(muted) return; var c=actx(); if(!c) return;+ var t=c.currentTime+(delay||0), o=c.createOscillator(), g=c.createGain();+ o.type=type||'sine'; o.frequency.setValueAtTime(freq,t);+ g.gain.setValueAtTime(0.0001,t); g.gain.exponentialRampToValueAtTime(vol||0.16,t+0.012);+ g.gain.exponentialRampToValueAtTime(0.0001,t+dur);+ o.connect(g); g.connect(c.destination); o.start(t); o.stop(t+dur+0.03);+ }+ function thunk(){ var f=261.63*Math.pow(2, Math.min(score,20)/12); tone(f,0.18,'triangle',0.17); tone(f*0.5,0.12,'sine',0.08); }+ function fall(){ tone(330,0.22,'sine',0.14); tone(247,0.3,'sine',0.12,0.12); tone(185,0.45,'sine',0.10,0.26); }+ var wrap=document.getElementById('wrap');+ var orbC=document.getElementById('orbs'), oc=orbC.getContext('2d');+ var cv=document.getElementById('cv'), ctx=cv.getContext('2d');+ var scoreEl=document.getElementById('score'), bestEl=document.getElementById('best');+ var ov=document.getElementById('ov'), ovt=document.getElementById('ovt'), ovs=document.getElementById('ovs'), ovb=document.getElementById('ovb');+ var W=0,H=0,dpr=1,T=0,raf=0,paused=false;+ var BH=30; // block height in px (before scaling)+ var state='start', score=0, best=0;+ var blocks=[], active=null, dir=1, speed=2.2, camY=0, camTarget=0, slices=[];+ var COLS=[['#6B4EFE','#9B7BFF'],['#FF5A1F','#FF8A4C'],['#E14C8F','#F37AAE'],['#3C9A6A','#5FC68C'],['#F6A93B','#FBC56E'],['#7C5CFF','#A98CFF']];++ function size(){+ var r=wrap.getBoundingClientRect();+ W=Math.max(180,r.width); H=Math.max(260,r.height);+ dpr=Math.min(window.devicePixelRatio||1,2.5);+ [orbC,cv].forEach(function(c){ c.width=Math.round(W*dpr); c.height=Math.round(H*dpr); });+ oc.setTransform(dpr,0,0,dpr,0,0); ctx.setTransform(dpr,0,0,dpr,0,0);+ BH=Math.max(24,Math.min(40,H*0.05));+ drawOrbs();+ }+ function blob(x,y,r,col){ var g=oc.createRadialGradient(x,y,0,x,y,r); g.addColorStop(0,col); g.addColorStop(1,'rgba(244,238,227,0)'); oc.fillStyle=g; oc.beginPath(); oc.arc(x,y,r,0,Math.PI*2); oc.fill(); }+ function drawOrbs(){+ oc.clearRect(0,0,W,H);+ var bg=oc.createLinearGradient(0,0,0,H); bg.addColorStop(0,'#F8F3EA'); bg.addColorStop(1,'#F1E7D7');+ oc.fillStyle=bg; oc.fillRect(0,0,W,H);+ blob(W*0.85,H*0.14,W*0.5,'rgba(232,226,255,0.85)');+ blob(W*0.12,H*0.22,W*0.46,'rgba(255,227,210,0.8)');+ blob(W*0.5,H*0.95,W*0.6,'rgba(255,212,226,0.45)');+ }++ function reset(){+ score=0; scoreEl.textContent='0'; camY=0; camTarget=0; slices=[];+ var bw=W*0.5, bx=(W-bw)/2;+ blocks=[{x:bx,w:bw,c:0}]; // base level 0 (y from bottom)+ spawn();+ }+ function topBlock(){ return blocks[blocks.length-1]; }+ function spawn(){+ var t=topBlock();+ var fromLeft=Math.random()<0.5;+ active={ x: fromLeft? 0 : Math.max(0,W-t.w), w:t.w, c:blocks.length };+ dir=fromLeft?1:-1;+ speed=2.0+blocks.length*0.08;+ // scroll the tower so the active row stays in view as it grows+ camTarget=Math.max(0,(blocks.length+1)*BH - H*0.42);+ }+ function levelY(i){ // screen y of the TOP of block at level i+ return H - 40 - i*BH + camY;+ }++ function drop(){+ if(state!=='play') return;+ var t=topBlock();+ var left=Math.max(active.x,t.x), right=Math.min(active.x+active.w,t.x+t.w);+ var ov2=right-left;+ if(ov2<=2){ // missed entirely+ gameOver(); return;+ }+ // overhang slice falls away+ if(active.x<t.x){ slices.push({x:active.x,w:t.x-active.x,y:levelY(blocks.length),vy:0,vx:-1.2,c:active.c}); }+ if(active.x+active.w>t.x+t.w){ var ox=t.x+t.w; slices.push({x:ox,w:(active.x+active.w)-ox,y:levelY(blocks.length),vy:0,vx:1.2,c:active.c}); }+ blocks.push({x:left,w:ov2,c:active.c});+ score++; scoreEl.textContent=score; thunk();+ if(score>best){ best=score; bestEl.textContent=best; persist(); if(LL&&LL.confetti){try{LL.confetti();}catch(e){}} }+ spawn();+ }+ function persist(){ if(LL&&LL.storage){ try{ LL.storage.set({best:best}); }catch(e){} } }++ function gameOver(){+ state='over'; fall();+ ovt.textContent='Nice tower'; ovs.innerHTML='You stacked it up.';+ ovb.textContent='Stacked '+score+(best>0?' · best '+best:'');+ ov.classList.remove('hide');+ }+ function start(){+ ov.classList.add('hide'); state='play'; reset(); T=performance.now();+ }++ 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 drawBlock(x,y,w,c){+ var col=COLS[c%COLS.length];+ var g=ctx.createLinearGradient(x,y,x,y+BH-3); g.addColorStop(0,col[1]); g.addColorStop(1,col[0]);+ ctx.save(); ctx.shadowColor='rgba(60,32,217,.16)'; ctx.shadowBlur=10; ctx.shadowOffsetY=4;+ roundRect(x,y,w,BH-3,7); ctx.fillStyle=g; ctx.fill(); ctx.restore();+ ctx.fillStyle='rgba(255,255,255,.22)'; roundRect(x+3,y+2,Math.max(0,w-6),5,3); ctx.fill();+ }++ function frame(now){+ raf=requestAnimationFrame(frame);+ if(paused) return;+ var dt=Math.min(2.4,(now-T)/16.67); T=now;+ camY+=(camTarget-camY)*0.12*dt;+ ctx.clearRect(0,0,W,H);+ // settled blocks+ for(var i=0;i<blocks.length;i++){ drawBlock(blocks[i].x, levelY(i), blocks[i].w, blocks[i].c); }+ // falling slices+ for(var s=slices.length-1;s>=0;s--){ var sl=slices[s]; sl.vy+=0.5*dt; sl.y+=sl.vy*dt; sl.x+=sl.vx*dt; if(sl.y>H+60){ slices.splice(s,1); continue; } ctx.globalAlpha=0.85; drawBlock(sl.x,sl.y,sl.w,sl.c); ctx.globalAlpha=1; }+ // active block — slides wall to wall, bouncing at the edges+ if(state==='play' && active){+ active.x+=dir*speed*dt;+ if(active.x<=0){ active.x=0; dir=1; }+ else if(active.x>=W-active.w){ active.x=W-active.w; dir=-1; }+ drawBlock(active.x, levelY(blocks.length), active.w, active.c);+ }+ }++ function tap(){ if(state==='start'||state==='over') start(); else drop(); }+ wrap.addEventListener('pointerdown',function(e){ e.preventDefault(); tap(); });++ if(LL&&LL.onPause){ try{ LL.onPause(function(p){ paused=p; if(!p) T=performance.now(); }); }catch(e){} }+ document.addEventListener('visibilitychange',function(){ paused=document.hidden; if(!paused) T=performance.now(); });+ window.addEventListener('resize',size);++ size();+ if(LL&&LL.storage){ try{ LL.storage.get().then(function(s){ if(s&&typeof s.best==='number'){ best=s.best; bestEl.textContent=best; } }).catch(function(){}); }catch(e){} }+ // idle preview tower behind the start overlay+ reset(); state='start';+ T=performance.now(); raf=requestAnimationFrame(frame);+})();+</script>