Liveloop

An interactive timeline for social media. Every post is a tiny app you can play, save, and remix.

Product

  • Feed
  • Create
  • Claude Code plugin
  • Blog

Legal

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • DMCA

Project

  • Templates
© 2026 Liveloop. All rights reserved.
LiveloopVersion history

v1Current

@mae_arcade · 6/10/2026, 8:17:41 AM

Initial version — all lines are new.

+<style>
+ html,body{height:100%;margin:0;overflow:hidden;background:#FFF1E0;}
+ *{box-sizing:border-box;}
+ #wrap{position:relative;height:100%;width:100%;display:flex;flex-direction:column;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:radial-gradient(110% 80% at 50% 0%,#FFF8EC 0%,#FFE9CE 70%,#FFDDB6 100%);-webkit-tap-highlight-color:transparent;touch-action:none;user-select:none;-webkit-user-select:none;}
+ #head{padding:1.05rem 1.2rem .3rem;z-index:2;pointer-events:none;}
+ #head h1{margin:0;font-family:"Instrument Serif",Georgia,"Times New Roman",serif;font-weight:400;font-size:2.2rem;line-height:1;color:#4a3a55;}
+ #head p{margin:.2rem 0 0;font-size:.78rem;color:#a08d77;font-weight:500;}
+ #hud{position:absolute;left:1.2rem;top:4.6rem;z-index:3;display:none;gap:8px;pointer-events:none;}
+ .pill{background:rgba(255,255,255,.85);border:1px solid rgba(120,90,50,.2);border-radius:999px;font-size:.72rem;font-weight:800;color:#4a3a55;padding:.32rem .7rem;}
+ #setup{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;padding:0 1.4rem 1.6rem;}
+ #slots{display:flex;gap:10px;width:100%;max-width:330px;}
+ .slot{flex:1;aspect-ratio:3/4;border:2px dashed rgba(124,92,255,.45);border-radius:14px;background:rgba(255,255,255,.55) center/cover no-repeat;cursor:pointer;position:relative;color:#8a76b8;font-weight:800;font-size:.8rem;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:4px;}
+ .slot.full{border-style:solid;border-color:rgba(124,92,255,.7);color:transparent;}
+ .slot b{font-size:1.3rem;}
+ #setupNote{font-size:.7rem;color:#a08d77;font-weight:600;text-align:center;}
+ #start{border:0;border-radius:999px;background:linear-gradient(135deg,#7C5CFF,#FF5A1F);color:#fff;font-weight:800;font-size:1rem;padding:.9rem 1.9rem;cursor:pointer;box-shadow:0 10px 26px rgba(124,92,255,.35);opacity:.45;}
+ #start.ready{opacity:1;}
+ #start:active{transform:scale(.96);}
+ #board{flex:1;position:relative;min-height:0;margin:.4rem .9rem .9rem;border-radius:18px;overflow:hidden;display:none;box-shadow:0 14px 34px rgba(90,60,30,.3);}
+ #cv{display:block;width:100%;height:100%;touch-action:none;}
+ #overlay{position:absolute;inset:0;z-index:4;display:none;flex-direction:column;align-items:center;justify-content:center;background:rgba(60,45,75,.5);backdrop-filter:blur(4px);text-align:center;padding:1.4rem;}
+ #overlay h2{margin:0;font-family:"Instrument Serif",Georgia,serif;font-weight:400;font-style:italic;font-size:2rem;color:#fff;}
+ #overlay p{margin:.4rem 0 1rem;font-size:.85rem;color:rgba(255,255,255,.85);font-weight:600;}
+ #overlay button{border:0;border-radius:999px;background:#fff;color:#4a3a55;font-weight:800;font-size:.95rem;padding:.8rem 1.7rem;cursor:pointer;}
+ #end{position:absolute;inset:0;z-index:5;display:none;flex-direction:column;align-items:center;justify-content:center;background:rgba(60,45,75,.6);backdrop-filter:blur(6px);padding:1.2rem;text-align:center;}
+ #trio{display:flex;gap:8px;margin-bottom:.9rem;}
+ #trio img{width:84px;height:112px;object-fit:cover;border-radius:10px;border:3px solid #fff;box-shadow:0 8px 20px rgba(0,0,0,.3);}
+ #trio img:nth-child(1){transform:rotate(-4deg);}
+ #trio img:nth-child(3){transform:rotate(4deg);}
+ #endTime{font-family:"Instrument Serif",Georgia,serif;font-style:italic;font-size:2.4rem;color:#fff;line-height:1;}
+ #endBest{font-size:.74rem;font-weight:700;color:rgba(255,255,255,.85);margin:.45rem 0 1rem;}
+ #end .row{display:flex;gap:10px;}
+ #end button{border:0;border-radius:999px;font-weight:800;font-size:.85rem;padding:.75rem 1.3rem;cursor:pointer;}
+ #againBtn{background:#fff;color:#4a3a55;}
+ #cardBtn{background:linear-gradient(135deg,#7C5CFF,#FF5A1F);color:#fff;}
+ #shareView{position:absolute;inset:0;z-index:6;display:none;flex-direction:column;align-items:center;justify-content:center;background:rgba(40,30,55,.72);backdrop-filter:blur(6px);padding:1.2rem;}
+ #shareImg{max-width:82%;max-height:68%;border-radius:12px;box-shadow:0 18px 44px rgba(0,0,0,.45);}
+ #shareView p{color:#FFE9CE;font-size:.78rem;font-weight:700;margin:.8rem 0 .5rem;}
+ #shareBack{border:0;border-radius:999px;background:rgba(255,255,255,.95);color:#4a3a55;font-weight:800;font-size:.85rem;padding:.65rem 1.4rem;cursor:pointer;}
+ #file{display:none;}
+</style>
+<div id="wrap">
+ <div id="head"><h1>Pop Reveal</h1><p>Hide 3 photos behind balloons. Pop to reveal. Race the clock.</p></div>
+ <div id="hud"><span class="pill" id="lvlPill">level 1</span><span class="pill" id="timePill">0.0s</span></div>
+ <div id="setup">
+ <div id="slots">
+ <button class="slot" data-i="0"><b>1</b>easy</button>
+ <button class="slot" data-i="1"><b>2</b>tricky</button>
+ <button class="slot" data-i="2"><b>3</b>wild</button>
+ </div>
+ <div id="setupNote">one photo per level — they never leave your phone.<br>send it to a friend with THEIR photos &#128521;</div>
+ <button id="start">pop! &#127880;</button>
+ </div>
+ <div id="board">
+ <canvas id="cv"></canvas>
+ <div id="overlay"><h2 id="ovTitle"></h2><p id="ovSub"></p><button id="ovBtn">go</button></div>
+ </div>
+ <div id="end">
+ <div id="trio"></div>
+ <div id="endTime"></div>
+ <div id="endBest"></div>
+ <div class="row">
+ <button id="againBtn">play again</button>
+ <button id="cardBtn">brag card &#127881;</button>
+ </div>
+ </div>
+ <div id="shareView">
+ <img id="shareImg" alt="score card">
+ <p>press &amp; hold to save — then challenge a friend</p>
+ <button id="shareBack">back</button>
+ </div>
+ <input id="file" type="file" accept="image/*">
+</div>
+<script>
+(function(){
+ var LL=window.liveloop||null;
+ 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 popSnd(r){
+ if(muted) return; var c=actx(); if(!c) return;
+ var t=c.currentTime;
+ var n=Math.floor(c.sampleRate*0.04), b=c.createBuffer(1,n,c.sampleRate), d=b.getChannelData(0);
+ for(var i=0;i<n;i++){ d[i]=(Math.random()*2-1)*Math.pow(1-i/n,2); }
+ var s=c.createBufferSource(); s.buffer=b;
+ var g=c.createGain(); g.gain.value=0.14; s.connect(g); g.connect(c.destination); s.start(t);
+ var o=c.createOscillator(), g2=c.createGain();
+ o.type='sine'; var f=520+(46-r)*14+Math.random()*60;
+ o.frequency.setValueAtTime(f,t); o.frequency.exponentialRampToValueAtTime(f*1.6,t+0.06);
+ g2.gain.setValueAtTime(0.0001,t); g2.gain.exponentialRampToValueAtTime(0.12,t+0.008);
+ g2.gain.exponentialRampToValueAtTime(0.0001,t+0.14);
+ o.connect(g2); g2.connect(c.destination); o.start(t); o.stop(t+0.16);
+ }
+ function fanfare(){
+ if(muted) return; var c=actx(); if(!c) return;
+ var t=c.currentTime, fr=[523.25,659.25,783.99,1046.5];
+ for(var i=0;i<fr.length;i++){ (function(i){
+ var o=c.createOscillator(), g=c.createGain();
+ o.type='triangle'; o.frequency.setValueAtTime(fr[i],t+i*0.09);
+ g.gain.setValueAtTime(0.0001,t+i*0.09); g.gain.exponentialRampToValueAtTime(0.12,t+i*0.09+0.012);
+ g.gain.exponentialRampToValueAtTime(0.0001,t+i*0.09+0.5);
+ o.connect(g); g.connect(c.destination); o.start(t+i*0.09); o.stop(t+i*0.09+0.55);
+ })(i); }
+ }
+
+ var setupEl=document.getElementById('setup');
+ var slots=[].slice.call(document.querySelectorAll('.slot'));
+ var startBtn=document.getElementById('start');
+ var fileIn=document.getElementById('file');
+ var boardEl=document.getElementById('board');
+ var cv=document.getElementById('cv'), ctx=cv.getContext('2d');
+ var hud=document.getElementById('hud'), lvlPill=document.getElementById('lvlPill'), timePill=document.getElementById('timePill');
+ var overlay=document.getElementById('overlay'), ovTitle=document.getElementById('ovTitle'), ovSub=document.getElementById('ovSub'), ovBtn=document.getElementById('ovBtn');
+ var endEl=document.getElementById('end'), trio=document.getElementById('trio'), endTime=document.getElementById('endTime'), endBest=document.getElementById('endBest');
+ var againBtn=document.getElementById('againBtn'), cardBtn=document.getElementById('cardBtn');
+ var shareView=document.getElementById('shareView'), shareImg=document.getElementById('shareImg'), shareBack=document.getElementById('shareBack');
+
+ var photos=[null,null,null]; // canvases
+ var pickIdx=0;
+ var LEVELS=[
+ {cols:5,rows:7,drift:0, tough:0, name:'easy'},
+ {cols:6,rows:8,drift:0.6,tough:0, name:'tricky'},
+ {cols:7,rows:9,drift:1.0,tough:0.18, name:'wild'}
+ ];
+ var COLS=['#FF5A1F','#7C5CFF','#E14C8F','#F6A93B','#6B4EFE','#FF7A55','#9B7BFF'];
+ var phase='setup', level=0, balloons=[], parts=[], left=0;
+ var elapsed=0, lastT=0, paused=false, raf=0;
+ var best=0;
+ try{
+ if(LL && LL.storage && LL.storage.get){
+ LL.storage.get().then(function(s){ if(s && s.bestMs) best=s.bestMs|0; }).catch(function(){});
+ }
+ }catch(e){}
+
+ slots.forEach(function(s){
+ s.addEventListener('click',function(){ pickIdx=+s.getAttribute('data-i'); fileIn.click(); });
+ });
+ fileIn.addEventListener('change',function(){
+ if(!(fileIn.files && fileIn.files[0])) return;
+ var rd=new FileReader();
+ rd.onload=function(){
+ var im=new Image();
+ im.onload=function(){
+ var MAX=900, sc=Math.min(1,MAX/Math.max(im.width,im.height));
+ var c2=document.createElement('canvas');
+ c2.width=Math.round(im.width*sc); c2.height=Math.round(im.height*sc);
+ c2.getContext('2d').drawImage(im,0,0,c2.width,c2.height);
+ photos[pickIdx]=c2;
+ var el=slots[pickIdx];
+ el.classList.add('full');
+ el.style.backgroundImage='url('+c2.toDataURL('image/jpeg',0.6)+')';
+ if(photos.some(function(p){ return p; })) startBtn.classList.add('ready');
+ };
+ im.src=rd.result;
+ };
+ rd.readAsDataURL(fileIn.files[0]);
+ fileIn.value='';
+ });
+
+ function photoFor(i){
+ if(photos[i]) return photos[i];
+ var have=photos.filter(function(p){ return p; });
+ return have[i%have.length];
+ }
+
+ function size(){
+ var r=boardEl.getBoundingClientRect();
+ var dpr=Math.min(window.devicePixelRatio||1,2);
+ cv.width=Math.round(r.width*dpr); cv.height=Math.round(r.height*dpr);
+ ctx.setTransform(dpr,0,0,dpr,0,0);
+ return {w:r.width,h:r.height};
+ }
+
+ function buildLevel(){
+ var L=LEVELS[level], dim=size();
+ balloons=[]; parts=[]; left=L.cols*L.rows;
+ var cw=dim.w/L.cols, ch=dim.h/L.rows;
+ var r=Math.max(cw,ch)*0.62;
+ for(var y=0;y<L.rows;y++){ for(var x=0;x<L.cols;x++){
+ balloons.push({
+ cx:(x+0.5)*cw, cy:(y+0.5)*ch, r:r,
+ col:COLS[(x*3+y*5+level)%COLS.length],
+ ph:Math.random()*7, sp:0.0012+Math.random()*0.0012,
+ amp:2+L.drift*7, hp:(Math.random()<L.tough?2:1), popped:false
+ });
+ }}
+ lvlPill.textContent='level '+(level+1)+' · '+L.name;
+ }
+
+ function drawBalloon(b,now){
+ var dx=Math.sin(now*b.sp+b.ph)*b.amp, dy=Math.cos(now*b.sp*0.8+b.ph*2)*b.amp*0.7;
+ var x=b.cx+dx, y=b.cy+dy, r=b.hp===2?b.r:b.r*(b.hp===1&&b.wasTough?0.84:1);
+ b._x=x; b._y=y; b._r=r;
+ var g=ctx.createRadialGradient(x-r*0.35,y-r*0.4,r*0.1,x,y,r);
+ g.addColorStop(0,'#ffffff');
+ g.addColorStop(0.25,b.col);
+ g.addColorStop(1,shade(b.col,-38));
+ ctx.fillStyle=g;
+ ctx.beginPath(); ctx.ellipse(x,y,r*0.92,r,0,0,Math.PI*2); ctx.fill();
+ // knot
+ ctx.fillStyle=shade(b.col,-50);
+ ctx.beginPath(); ctx.moveTo(x,y+r*0.98); ctx.lineTo(x-4,y+r*1.12); ctx.lineTo(x+4,y+r*1.12); ctx.closePath(); ctx.fill();
+ if(b.hp===2){
+ ctx.strokeStyle='rgba(255,255,255,.85)'; ctx.lineWidth=2;
+ ctx.beginPath(); ctx.ellipse(x,y,r*0.6,r*0.66,0,0,Math.PI*2); ctx.stroke();
+ }
+ }
+ function shade(hexc,amt){
+ var v=parseInt(hexc.slice(1),16);
+ var r=Math.max(0,Math.min(255,(v>>16)+amt)), g=Math.max(0,Math.min(255,((v>>8)&255)+amt)), b2=Math.max(0,Math.min(255,(v&255)+amt));
+ return 'rgb('+r+','+g+','+b2+')';
+ }
+
+ function drawPhoto(dim){
+ var ph=photoFor(level);
+ var sc=Math.max(dim.w/ph.width,dim.h/ph.height);
+ var w=ph.width*sc, h=ph.height*sc;
+ ctx.drawImage(ph,(dim.w-w)/2,(dim.h-h)/2,w,h);
+ }
+
+ function tick(now){
+ raf=requestAnimationFrame(tick);
+ if(paused||phase!=='play'&&phase!=='reveal') return;
+ var dt=Math.min(100,now-lastT); lastT=now;
+ if(phase==='play') elapsed+=dt;
+ var dim={w:cv.width/(Math.min(window.devicePixelRatio||1,2)),h:cv.height/(Math.min(window.devicePixelRatio||1,2))};
+ drawPhoto(dim);
+ if(phase==='play'){
+ ctx.fillStyle='rgba(60,45,75,.18)'; ctx.fillRect(0,0,dim.w,dim.h);
+ for(var i=0;i<balloons.length;i++){ if(!balloons[i].popped) drawBalloon(balloons[i],now); }
+ }
+ // pop particles
+ for(var j=parts.length-1;j>=0;j--){
+ var p=parts[j];
+ p.x+=p.vx*dt/16; p.y+=p.vy*dt/16; p.vy+=0.05*dt/16; p.life-=dt;
+ if(p.life<=0){ parts.splice(j,1); continue; }
+ ctx.globalAlpha=Math.max(0,p.life/420);
+ ctx.fillStyle=p.col;
+ ctx.fillRect(p.x-2.4,p.y-2.4,4.8,4.8);
+ ctx.globalAlpha=1;
+ }
+ timePill.textContent=(elapsed/1000).toFixed(1)+'s';
+ }
+
+ function burst(x,y,col){
+ for(var i=0;i<10;i++){
+ var a=Math.random()*Math.PI*2, v=1.5+Math.random()*2.5;
+ parts.push({x:x,y:y,vx:Math.cos(a)*v,vy:Math.sin(a)*v-1,col:i%3?col:'#ffffff',life:320+Math.random()*120});
+ }
+ }
+
+ cv.addEventListener('pointerdown',function(e){
+ if(phase!=='play') return;
+ e.preventDefault();
+ var rect=cv.getBoundingClientRect();
+ var x=e.clientX-rect.left, y=e.clientY-rect.top;
+ var bestB=null, bd=1e9;
+ for(var i=0;i<balloons.length;i++){
+ var b=balloons[i]; if(b.popped) continue;
+ var d=Math.hypot((b._x||b.cx)-x,(b._y||b.cy)-y);
+ if(d<(b._r||b.r)*1.18 && d<bd){ bd=d; bestB=b; }
+ }
+ if(!bestB) return;
+ if(bestB.hp>1){ bestB.hp=1; bestB.wasTough=true; popSnd(bestB.r*1.4); burst(bestB._x,bestB._y,'#ffffff'); return; }
+ bestB.popped=true; left--;
+ popSnd(bestB.r); burst(bestB._x,bestB._y,bestB.col);
+ if(left<=0) levelClear();
+ });
+
+ function levelClear(){
+ phase='reveal'; fanfare();
+ setTimeout(function(){
+ if(level<2){
+ level++;
+ showOverlay('level '+(level+1),LEVELS[level].name+' — '+(LEVELS[level].cols*LEVELS[level].rows)+' balloons','pop it');
+ } else finish();
+ },1400);
+ }
+ function showOverlay(t,s,b){
+ phase='between';
+ ovTitle.textContent=t; ovSub.textContent=s; ovBtn.textContent=b;
+ overlay.style.display='flex';
+ }
+ ovBtn.addEventListener('click',function(){
+ overlay.style.display='none';
+ buildLevel(); phase='play'; lastT=performance.now();
+ });
+
+ function fmt(ms){ return (ms/1000).toFixed(1)+'s'; }
+ function finish(){
+ phase='end';
+ boardEl.style.display='none'; hud.style.display='none';
+ trio.innerHTML='';
+ for(var i=0;i<3;i++){
+ var im=document.createElement('img');
+ im.src=photoFor(i).toDataURL('image/jpeg',0.7);
+ trio.appendChild(im);
+ }
+ endTime.textContent=fmt(elapsed);
+ var isBest = !best || elapsed<best;
+ if(isBest){ best=Math.round(elapsed);
+ try{ if(LL && LL.storage && LL.storage.set) LL.storage.set({bestMs:best}); }catch(e){}
+ endBest.textContent='new best! 🏆';
+ } else endBest.textContent='best: '+fmt(best);
+ endEl.style.display='flex';
+ }
+
+ startBtn.addEventListener('click',function(){
+ if(!photos.some(function(p){ return p; })) return;
+ setupEl.style.display='none';
+ boardEl.style.display='block'; hud.style.display='flex';
+ level=0; elapsed=0;
+ buildLevel(); phase='play'; lastT=performance.now();
+ });
+ againBtn.addEventListener('click',function(){
+ endEl.style.display='none';
+ boardEl.style.display='block'; hud.style.display='flex';
+ level=0; elapsed=0;
+ buildLevel(); phase='play'; lastT=performance.now();
+ });
+
+ cardBtn.addEventListener('click',function(){
+ var W=720,H=1000,out=document.createElement('canvas');
+ out.width=W; out.height=H;
+ var oc=out.getContext('2d');
+ var bg=oc.createLinearGradient(0,0,0,H);
+ bg.addColorStop(0,'#FFF8EC'); bg.addColorStop(1,'#FFDDB6');
+ oc.fillStyle=bg; oc.fillRect(0,0,W,H);
+ oc.fillStyle='#4a3a55'; oc.textAlign='center';
+ oc.font='64px Georgia,"Times New Roman",serif';
+ oc.fillText('Pop Reveal',W/2,110);
+ var pw=190,phh=253,gap=22,x0=(W-3*pw-2*gap)/2;
+ for(var i=0;i<3;i++){ (function(i){
+ var ph=photoFor(i);
+ var x=x0+i*(pw+gap), y=170;
+ oc.save(); oc.translate(x+pw/2,y+phh/2); oc.rotate((i-1)*0.06);
+ oc.shadowColor='rgba(80,50,20,.3)'; oc.shadowBlur=18; oc.shadowOffsetY=8;
+ oc.fillStyle='#fff'; oc.fillRect(-pw/2-8,-phh/2-8,pw+16,phh+16);
+ oc.shadowColor='transparent';
+ var sc=Math.max(pw/ph.width,phh/ph.height);
+ oc.save(); oc.beginPath(); oc.rect(-pw/2,-phh/2,pw,phh); oc.clip();
+ oc.drawImage(ph,-ph.width*sc/2,-ph.height*sc/2,ph.width*sc,ph.height*sc);
+ oc.restore(); oc.restore();
+ })(i); }
+ oc.fillStyle='#4a3a55';
+ oc.font='italic 110px Georgia,serif';
+ oc.fillText(fmt(elapsed),W/2,610);
+ oc.font='600 24px system-ui,sans-serif'; oc.fillStyle='#a08d77';
+ oc.fillText('146 balloons · 3 photos · beat my time',W/2,665);
+ oc.font='600 20px system-ui,sans-serif'; oc.fillStyle='#b9a88c';
+ var d=new Date();
+ oc.fillText(d.toLocaleDateString(undefined,{month:'short',day:'numeric',year:'numeric'}),W/2,940);
+ shareImg.src=out.toDataURL('image/jpeg',0.9);
+ shareView.style.display='flex';
+ });
+ shareBack.addEventListener('click',function(){ shareView.style.display='none'; });
+
+ if(LL && LL.onPause){ try{ LL.onPause(function(p){ paused=p; if(!p) lastT=performance.now(); }); }catch(e){} }
+ document.addEventListener('visibilitychange',function(){ paused=document.hidden; if(!paused) lastT=performance.now(); });
+ window.addEventListener('resize',function(){ if(phase==='play'){ buildLevel(); } });
+ raf=requestAnimationFrame(tick);
+})();
+</script>

v1Current

@mae_arcade · 6/10/2026, 8:17:41 AM

Initial version — all lines are new.

+<style>
+ html,body{height:100%;margin:0;overflow:hidden;background:#FFF1E0;}
+ *{box-sizing:border-box;}
+ #wrap{position:relative;height:100%;width:100%;display:flex;flex-direction:column;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:radial-gradient(110% 80% at 50% 0%,#FFF8EC 0%,#FFE9CE 70%,#FFDDB6 100%);-webkit-tap-highlight-color:transparent;touch-action:none;user-select:none;-webkit-user-select:none;}
+ #head{padding:1.05rem 1.2rem .3rem;z-index:2;pointer-events:none;}
+ #head h1{margin:0;font-family:"Instrument Serif",Georgia,"Times New Roman",serif;font-weight:400;font-size:2.2rem;line-height:1;color:#4a3a55;}
+ #head p{margin:.2rem 0 0;font-size:.78rem;color:#a08d77;font-weight:500;}
+ #hud{position:absolute;left:1.2rem;top:4.6rem;z-index:3;display:none;gap:8px;pointer-events:none;}
+ .pill{background:rgba(255,255,255,.85);border:1px solid rgba(120,90,50,.2);border-radius:999px;font-size:.72rem;font-weight:800;color:#4a3a55;padding:.32rem .7rem;}
+ #setup{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;padding:0 1.4rem 1.6rem;}
+ #slots{display:flex;gap:10px;width:100%;max-width:330px;}
+ .slot{flex:1;aspect-ratio:3/4;border:2px dashed rgba(124,92,255,.45);border-radius:14px;background:rgba(255,255,255,.55) center/cover no-repeat;cursor:pointer;position:relative;color:#8a76b8;font-weight:800;font-size:.8rem;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:4px;}
+ .slot.full{border-style:solid;border-color:rgba(124,92,255,.7);color:transparent;}
+ .slot b{font-size:1.3rem;}
+ #setupNote{font-size:.7rem;color:#a08d77;font-weight:600;text-align:center;}
+ #start{border:0;border-radius:999px;background:linear-gradient(135deg,#7C5CFF,#FF5A1F);color:#fff;font-weight:800;font-size:1rem;padding:.9rem 1.9rem;cursor:pointer;box-shadow:0 10px 26px rgba(124,92,255,.35);opacity:.45;}
+ #start.ready{opacity:1;}
+ #start:active{transform:scale(.96);}
+ #board{flex:1;position:relative;min-height:0;margin:.4rem .9rem .9rem;border-radius:18px;overflow:hidden;display:none;box-shadow:0 14px 34px rgba(90,60,30,.3);}
+ #cv{display:block;width:100%;height:100%;touch-action:none;}
+ #overlay{position:absolute;inset:0;z-index:4;display:none;flex-direction:column;align-items:center;justify-content:center;background:rgba(60,45,75,.5);backdrop-filter:blur(4px);text-align:center;padding:1.4rem;}
+ #overlay h2{margin:0;font-family:"Instrument Serif",Georgia,serif;font-weight:400;font-style:italic;font-size:2rem;color:#fff;}
+ #overlay p{margin:.4rem 0 1rem;font-size:.85rem;color:rgba(255,255,255,.85);font-weight:600;}
+ #overlay button{border:0;border-radius:999px;background:#fff;color:#4a3a55;font-weight:800;font-size:.95rem;padding:.8rem 1.7rem;cursor:pointer;}
+ #end{position:absolute;inset:0;z-index:5;display:none;flex-direction:column;align-items:center;justify-content:center;background:rgba(60,45,75,.6);backdrop-filter:blur(6px);padding:1.2rem;text-align:center;}
+ #trio{display:flex;gap:8px;margin-bottom:.9rem;}
+ #trio img{width:84px;height:112px;object-fit:cover;border-radius:10px;border:3px solid #fff;box-shadow:0 8px 20px rgba(0,0,0,.3);}
+ #trio img:nth-child(1){transform:rotate(-4deg);}
+ #trio img:nth-child(3){transform:rotate(4deg);}
+ #endTime{font-family:"Instrument Serif",Georgia,serif;font-style:italic;font-size:2.4rem;color:#fff;line-height:1;}
+ #endBest{font-size:.74rem;font-weight:700;color:rgba(255,255,255,.85);margin:.45rem 0 1rem;}
+ #end .row{display:flex;gap:10px;}
+ #end button{border:0;border-radius:999px;font-weight:800;font-size:.85rem;padding:.75rem 1.3rem;cursor:pointer;}
+ #againBtn{background:#fff;color:#4a3a55;}
+ #cardBtn{background:linear-gradient(135deg,#7C5CFF,#FF5A1F);color:#fff;}
+ #shareView{position:absolute;inset:0;z-index:6;display:none;flex-direction:column;align-items:center;justify-content:center;background:rgba(40,30,55,.72);backdrop-filter:blur(6px);padding:1.2rem;}
+ #shareImg{max-width:82%;max-height:68%;border-radius:12px;box-shadow:0 18px 44px rgba(0,0,0,.45);}
+ #shareView p{color:#FFE9CE;font-size:.78rem;font-weight:700;margin:.8rem 0 .5rem;}
+ #shareBack{border:0;border-radius:999px;background:rgba(255,255,255,.95);color:#4a3a55;font-weight:800;font-size:.85rem;padding:.65rem 1.4rem;cursor:pointer;}
+ #file{display:none;}
+</style>
+<div id="wrap">
+ <div id="head"><h1>Pop Reveal</h1><p>Hide 3 photos behind balloons. Pop to reveal. Race the clock.</p></div>
+ <div id="hud"><span class="pill" id="lvlPill">level 1</span><span class="pill" id="timePill">0.0s</span></div>
+ <div id="setup">
+ <div id="slots">
+ <button class="slot" data-i="0"><b>1</b>easy</button>
+ <button class="slot" data-i="1"><b>2</b>tricky</button>
+ <button class="slot" data-i="2"><b>3</b>wild</button>
+ </div>
+ <div id="setupNote">one photo per level — they never leave your phone.<br>send it to a friend with THEIR photos &#128521;</div>
+ <button id="start">pop! &#127880;</button>
+ </div>
+ <div id="board">
+ <canvas id="cv"></canvas>
+ <div id="overlay"><h2 id="ovTitle"></h2><p id="ovSub"></p><button id="ovBtn">go</button></div>
+ </div>
+ <div id="end">
+ <div id="trio"></div>
+ <div id="endTime"></div>
+ <div id="endBest"></div>
+ <div class="row">
+ <button id="againBtn">play again</button>
+ <button id="cardBtn">brag card &#127881;</button>
+ </div>
+ </div>
+ <div id="shareView">
+ <img id="shareImg" alt="score card">
+ <p>press &amp; hold to save — then challenge a friend</p>
+ <button id="shareBack">back</button>
+ </div>
+ <input id="file" type="file" accept="image/*">
+</div>
+<script>
+(function(){
+ var LL=window.liveloop||null;
+ 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 popSnd(r){
+ if(muted) return; var c=actx(); if(!c) return;
+ var t=c.currentTime;
+ var n=Math.floor(c.sampleRate*0.04), b=c.createBuffer(1,n,c.sampleRate), d=b.getChannelData(0);
+ for(var i=0;i<n;i++){ d[i]=(Math.random()*2-1)*Math.pow(1-i/n,2); }
+ var s=c.createBufferSource(); s.buffer=b;
+ var g=c.createGain(); g.gain.value=0.14; s.connect(g); g.connect(c.destination); s.start(t);
+ var o=c.createOscillator(), g2=c.createGain();
+ o.type='sine'; var f=520+(46-r)*14+Math.random()*60;
+ o.frequency.setValueAtTime(f,t); o.frequency.exponentialRampToValueAtTime(f*1.6,t+0.06);
+ g2.gain.setValueAtTime(0.0001,t); g2.gain.exponentialRampToValueAtTime(0.12,t+0.008);
+ g2.gain.exponentialRampToValueAtTime(0.0001,t+0.14);
+ o.connect(g2); g2.connect(c.destination); o.start(t); o.stop(t+0.16);
+ }
+ function fanfare(){
+ if(muted) return; var c=actx(); if(!c) return;
+ var t=c.currentTime, fr=[523.25,659.25,783.99,1046.5];
+ for(var i=0;i<fr.length;i++){ (function(i){
+ var o=c.createOscillator(), g=c.createGain();
+ o.type='triangle'; o.frequency.setValueAtTime(fr[i],t+i*0.09);
+ g.gain.setValueAtTime(0.0001,t+i*0.09); g.gain.exponentialRampToValueAtTime(0.12,t+i*0.09+0.012);
+ g.gain.exponentialRampToValueAtTime(0.0001,t+i*0.09+0.5);
+ o.connect(g); g.connect(c.destination); o.start(t+i*0.09); o.stop(t+i*0.09+0.55);
+ })(i); }
+ }
+
+ var setupEl=document.getElementById('setup');
+ var slots=[].slice.call(document.querySelectorAll('.slot'));
+ var startBtn=document.getElementById('start');
+ var fileIn=document.getElementById('file');
+ var boardEl=document.getElementById('board');
+ var cv=document.getElementById('cv'), ctx=cv.getContext('2d');
+ var hud=document.getElementById('hud'), lvlPill=document.getElementById('lvlPill'), timePill=document.getElementById('timePill');
+ var overlay=document.getElementById('overlay'), ovTitle=document.getElementById('ovTitle'), ovSub=document.getElementById('ovSub'), ovBtn=document.getElementById('ovBtn');
+ var endEl=document.getElementById('end'), trio=document.getElementById('trio'), endTime=document.getElementById('endTime'), endBest=document.getElementById('endBest');
+ var againBtn=document.getElementById('againBtn'), cardBtn=document.getElementById('cardBtn');
+ var shareView=document.getElementById('shareView'), shareImg=document.getElementById('shareImg'), shareBack=document.getElementById('shareBack');
+
+ var photos=[null,null,null]; // canvases
+ var pickIdx=0;
+ var LEVELS=[
+ {cols:5,rows:7,drift:0, tough:0, name:'easy'},
+ {cols:6,rows:8,drift:0.6,tough:0, name:'tricky'},
+ {cols:7,rows:9,drift:1.0,tough:0.18, name:'wild'}
+ ];
+ var COLS=['#FF5A1F','#7C5CFF','#E14C8F','#F6A93B','#6B4EFE','#FF7A55','#9B7BFF'];
+ var phase='setup', level=0, balloons=[], parts=[], left=0;
+ var elapsed=0, lastT=0, paused=false, raf=0;
+ var best=0;
+ try{
+ if(LL && LL.storage && LL.storage.get){
+ LL.storage.get().then(function(s){ if(s && s.bestMs) best=s.bestMs|0; }).catch(function(){});
+ }
+ }catch(e){}
+
+ slots.forEach(function(s){
+ s.addEventListener('click',function(){ pickIdx=+s.getAttribute('data-i'); fileIn.click(); });
+ });
+ fileIn.addEventListener('change',function(){
+ if(!(fileIn.files && fileIn.files[0])) return;
+ var rd=new FileReader();
+ rd.onload=function(){
+ var im=new Image();
+ im.onload=function(){
+ var MAX=900, sc=Math.min(1,MAX/Math.max(im.width,im.height));
+ var c2=document.createElement('canvas');
+ c2.width=Math.round(im.width*sc); c2.height=Math.round(im.height*sc);
+ c2.getContext('2d').drawImage(im,0,0,c2.width,c2.height);
+ photos[pickIdx]=c2;
+ var el=slots[pickIdx];
+ el.classList.add('full');
+ el.style.backgroundImage='url('+c2.toDataURL('image/jpeg',0.6)+')';
+ if(photos.some(function(p){ return p; })) startBtn.classList.add('ready');
+ };
+ im.src=rd.result;
+ };
+ rd.readAsDataURL(fileIn.files[0]);
+ fileIn.value='';
+ });
+
+ function photoFor(i){
+ if(photos[i]) return photos[i];
+ var have=photos.filter(function(p){ return p; });
+ return have[i%have.length];
+ }
+
+ function size(){
+ var r=boardEl.getBoundingClientRect();
+ var dpr=Math.min(window.devicePixelRatio||1,2);
+ cv.width=Math.round(r.width*dpr); cv.height=Math.round(r.height*dpr);
+ ctx.setTransform(dpr,0,0,dpr,0,0);
+ return {w:r.width,h:r.height};
+ }
+
+ function buildLevel(){
+ var L=LEVELS[level], dim=size();
+ balloons=[]; parts=[]; left=L.cols*L.rows;
+ var cw=dim.w/L.cols, ch=dim.h/L.rows;
+ var r=Math.max(cw,ch)*0.62;
+ for(var y=0;y<L.rows;y++){ for(var x=0;x<L.cols;x++){
+ balloons.push({
+ cx:(x+0.5)*cw, cy:(y+0.5)*ch, r:r,
+ col:COLS[(x*3+y*5+level)%COLS.length],
+ ph:Math.random()*7, sp:0.0012+Math.random()*0.0012,
+ amp:2+L.drift*7, hp:(Math.random()<L.tough?2:1), popped:false
+ });
+ }}
+ lvlPill.textContent='level '+(level+1)+' · '+L.name;
+ }
+
+ function drawBalloon(b,now){
+ var dx=Math.sin(now*b.sp+b.ph)*b.amp, dy=Math.cos(now*b.sp*0.8+b.ph*2)*b.amp*0.7;
+ var x=b.cx+dx, y=b.cy+dy, r=b.hp===2?b.r:b.r*(b.hp===1&&b.wasTough?0.84:1);
+ b._x=x; b._y=y; b._r=r;
+ var g=ctx.createRadialGradient(x-r*0.35,y-r*0.4,r*0.1,x,y,r);
+ g.addColorStop(0,'#ffffff');
+ g.addColorStop(0.25,b.col);
+ g.addColorStop(1,shade(b.col,-38));
+ ctx.fillStyle=g;
+ ctx.beginPath(); ctx.ellipse(x,y,r*0.92,r,0,0,Math.PI*2); ctx.fill();
+ // knot
+ ctx.fillStyle=shade(b.col,-50);
+ ctx.beginPath(); ctx.moveTo(x,y+r*0.98); ctx.lineTo(x-4,y+r*1.12); ctx.lineTo(x+4,y+r*1.12); ctx.closePath(); ctx.fill();
+ if(b.hp===2){
+ ctx.strokeStyle='rgba(255,255,255,.85)'; ctx.lineWidth=2;
+ ctx.beginPath(); ctx.ellipse(x,y,r*0.6,r*0.66,0,0,Math.PI*2); ctx.stroke();
+ }
+ }
+ function shade(hexc,amt){
+ var v=parseInt(hexc.slice(1),16);
+ var r=Math.max(0,Math.min(255,(v>>16)+amt)), g=Math.max(0,Math.min(255,((v>>8)&255)+amt)), b2=Math.max(0,Math.min(255,(v&255)+amt));
+ return 'rgb('+r+','+g+','+b2+')';
+ }
+
+ function drawPhoto(dim){
+ var ph=photoFor(level);
+ var sc=Math.max(dim.w/ph.width,dim.h/ph.height);
+ var w=ph.width*sc, h=ph.height*sc;
+ ctx.drawImage(ph,(dim.w-w)/2,(dim.h-h)/2,w,h);
+ }
+
+ function tick(now){
+ raf=requestAnimationFrame(tick);
+ if(paused||phase!=='play'&&phase!=='reveal') return;
+ var dt=Math.min(100,now-lastT); lastT=now;
+ if(phase==='play') elapsed+=dt;
+ var dim={w:cv.width/(Math.min(window.devicePixelRatio||1,2)),h:cv.height/(Math.min(window.devicePixelRatio||1,2))};
+ drawPhoto(dim);
+ if(phase==='play'){
+ ctx.fillStyle='rgba(60,45,75,.18)'; ctx.fillRect(0,0,dim.w,dim.h);
+ for(var i=0;i<balloons.length;i++){ if(!balloons[i].popped) drawBalloon(balloons[i],now); }
+ }
+ // pop particles
+ for(var j=parts.length-1;j>=0;j--){
+ var p=parts[j];
+ p.x+=p.vx*dt/16; p.y+=p.vy*dt/16; p.vy+=0.05*dt/16; p.life-=dt;
+ if(p.life<=0){ parts.splice(j,1); continue; }
+ ctx.globalAlpha=Math.max(0,p.life/420);
+ ctx.fillStyle=p.col;
+ ctx.fillRect(p.x-2.4,p.y-2.4,4.8,4.8);
+ ctx.globalAlpha=1;
+ }
+ timePill.textContent=(elapsed/1000).toFixed(1)+'s';
+ }
+
+ function burst(x,y,col){
+ for(var i=0;i<10;i++){
+ var a=Math.random()*Math.PI*2, v=1.5+Math.random()*2.5;
+ parts.push({x:x,y:y,vx:Math.cos(a)*v,vy:Math.sin(a)*v-1,col:i%3?col:'#ffffff',life:320+Math.random()*120});
+ }
+ }
+
+ cv.addEventListener('pointerdown',function(e){
+ if(phase!=='play') return;
+ e.preventDefault();
+ var rect=cv.getBoundingClientRect();
+ var x=e.clientX-rect.left, y=e.clientY-rect.top;
+ var bestB=null, bd=1e9;
+ for(var i=0;i<balloons.length;i++){
+ var b=balloons[i]; if(b.popped) continue;
+ var d=Math.hypot((b._x||b.cx)-x,(b._y||b.cy)-y);
+ if(d<(b._r||b.r)*1.18 && d<bd){ bd=d; bestB=b; }
+ }
+ if(!bestB) return;
+ if(bestB.hp>1){ bestB.hp=1; bestB.wasTough=true; popSnd(bestB.r*1.4); burst(bestB._x,bestB._y,'#ffffff'); return; }
+ bestB.popped=true; left--;
+ popSnd(bestB.r); burst(bestB._x,bestB._y,bestB.col);
+ if(left<=0) levelClear();
+ });
+
+ function levelClear(){
+ phase='reveal'; fanfare();
+ setTimeout(function(){
+ if(level<2){
+ level++;
+ showOverlay('level '+(level+1),LEVELS[level].name+' — '+(LEVELS[level].cols*LEVELS[level].rows)+' balloons','pop it');
+ } else finish();
+ },1400);
+ }
+ function showOverlay(t,s,b){
+ phase='between';
+ ovTitle.textContent=t; ovSub.textContent=s; ovBtn.textContent=b;
+ overlay.style.display='flex';
+ }
+ ovBtn.addEventListener('click',function(){
+ overlay.style.display='none';
+ buildLevel(); phase='play'; lastT=performance.now();
+ });
+
+ function fmt(ms){ return (ms/1000).toFixed(1)+'s'; }
+ function finish(){
+ phase='end';
+ boardEl.style.display='none'; hud.style.display='none';
+ trio.innerHTML='';
+ for(var i=0;i<3;i++){
+ var im=document.createElement('img');
+ im.src=photoFor(i).toDataURL('image/jpeg',0.7);
+ trio.appendChild(im);
+ }
+ endTime.textContent=fmt(elapsed);
+ var isBest = !best || elapsed<best;
+ if(isBest){ best=Math.round(elapsed);
+ try{ if(LL && LL.storage && LL.storage.set) LL.storage.set({bestMs:best}); }catch(e){}
+ endBest.textContent='new best! 🏆';
+ } else endBest.textContent='best: '+fmt(best);
+ endEl.style.display='flex';
+ }
+
+ startBtn.addEventListener('click',function(){
+ if(!photos.some(function(p){ return p; })) return;
+ setupEl.style.display='none';
+ boardEl.style.display='block'; hud.style.display='flex';
+ level=0; elapsed=0;
+ buildLevel(); phase='play'; lastT=performance.now();
+ });
+ againBtn.addEventListener('click',function(){
+ endEl.style.display='none';
+ boardEl.style.display='block'; hud.style.display='flex';
+ level=0; elapsed=0;
+ buildLevel(); phase='play'; lastT=performance.now();
+ });
+
+ cardBtn.addEventListener('click',function(){
+ var W=720,H=1000,out=document.createElement('canvas');
+ out.width=W; out.height=H;
+ var oc=out.getContext('2d');
+ var bg=oc.createLinearGradient(0,0,0,H);
+ bg.addColorStop(0,'#FFF8EC'); bg.addColorStop(1,'#FFDDB6');
+ oc.fillStyle=bg; oc.fillRect(0,0,W,H);
+ oc.fillStyle='#4a3a55'; oc.textAlign='center';
+ oc.font='64px Georgia,"Times New Roman",serif';
+ oc.fillText('Pop Reveal',W/2,110);
+ var pw=190,phh=253,gap=22,x0=(W-3*pw-2*gap)/2;
+ for(var i=0;i<3;i++){ (function(i){
+ var ph=photoFor(i);
+ var x=x0+i*(pw+gap), y=170;
+ oc.save(); oc.translate(x+pw/2,y+phh/2); oc.rotate((i-1)*0.06);
+ oc.shadowColor='rgba(80,50,20,.3)'; oc.shadowBlur=18; oc.shadowOffsetY=8;
+ oc.fillStyle='#fff'; oc.fillRect(-pw/2-8,-phh/2-8,pw+16,phh+16);
+ oc.shadowColor='transparent';
+ var sc=Math.max(pw/ph.width,phh/ph.height);
+ oc.save(); oc.beginPath(); oc.rect(-pw/2,-phh/2,pw,phh); oc.clip();
+ oc.drawImage(ph,-ph.width*sc/2,-ph.height*sc/2,ph.width*sc,ph.height*sc);
+ oc.restore(); oc.restore();
+ })(i); }
+ oc.fillStyle='#4a3a55';
+ oc.font='italic 110px Georgia,serif';
+ oc.fillText(fmt(elapsed),W/2,610);
+ oc.font='600 24px system-ui,sans-serif'; oc.fillStyle='#a08d77';
+ oc.fillText('146 balloons · 3 photos · beat my time',W/2,665);
+ oc.font='600 20px system-ui,sans-serif'; oc.fillStyle='#b9a88c';
+ var d=new Date();
+ oc.fillText(d.toLocaleDateString(undefined,{month:'short',day:'numeric',year:'numeric'}),W/2,940);
+ shareImg.src=out.toDataURL('image/jpeg',0.9);
+ shareView.style.display='flex';
+ });
+ shareBack.addEventListener('click',function(){ shareView.style.display='none'; });
+
+ if(LL && LL.onPause){ try{ LL.onPause(function(p){ paused=p; if(!p) lastT=performance.now(); }); }catch(e){} }
+ document.addEventListener('visibilitychange',function(){ paused=document.hidden; if(!paused) lastT=performance.now(); });
+ window.addEventListener('resize',function(){ if(phase==='play'){ buildLevel(); } });
+ raf=requestAnimationFrame(tick);
+})();
+</script>
← Version history