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

@liveloop · 5/18/2026, 8:14:56 AM

Initial version — all lines are new.

+<style>
+ html,body{height:100%;margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:linear-gradient(160deg,#1e1b4b,#0f172a);color:#f1f5f9;overflow:hidden;}
+ .wrap{display:flex;flex-direction:column;height:100%;box-sizing:border-box;padding:1.2rem;gap:.85rem;align-items:center;justify-content:center;}
+ h1{margin:0;font-size:1.35rem;text-align:center;}
+ .hint{margin:0;font-size:.78rem;color:#94a3b8;text-align:center;min-height:1.1em;}
+ #card{position:relative;width:min(86vw,330px);aspect-ratio:5/3;border-radius:1rem;overflow:hidden;box-shadow:0 14px 36px rgba(0,0,0,.55);}
+ #prize{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.35rem;text-align:center;padding:1rem;box-sizing:border-box;}
+ #prize .big{font-size:1.45rem;font-weight:800;}
+ #prize .code{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:1.5rem;font-weight:800;letter-spacing:.14em;background:rgba(0,0,0,.28);padding:.3rem .75rem;border-radius:.5rem;}
+ #prize .note{font-size:.68rem;opacity:.8;max-width:26ch;}
+ #scratch{position:absolute;inset:0;width:100%;height:100%;touch-action:none;cursor:grab;}
+ button{font:inherit;font-weight:700;border:0;border-radius:9999px;padding:.6rem 1.5rem;background:#fbbf24;color:#0b1020;cursor:pointer;touch-action:manipulation;}
+</style>
+<div class="wrap">
+ <h1>🎟️ Scratch & Win</h1>
+ <div id="card">
+ <div id="prize"></div>
+ <canvas id="scratch"></canvas>
+ </div>
+ <p class="hint" id="hint">Scratch the silver area with your finger.</p>
+ <button id="again" type="button" style="display:none">New card</button>
+</div>
+<script>
+(function(){
+ // Remixing this into a real promo? Set your odds + prize text here.
+ var WIN_RATE = 0.5;
+ var PRIZE = {
+ label: 'You won a coupon!',
+ note: 'Demo code — remix this card and set your own real one.'
+ };
+
+ var prize=document.getElementById('prize'), cv=document.getElementById('scratch'),
+ ctx=cv.getContext('2d'), hint=document.getElementById('hint'),
+ again=document.getElementById('again');
+ var W=0,H=0,won=false,revealed=false,scratching=false,lastX=0,lastY=0;
+
+ function onTap(el,fn){
+ var sx=0,sy=0,armed=false;
+ el.addEventListener('pointerdown',function(e){ armed=true;sx=e.clientX;sy=e.clientY; });
+ el.addEventListener('pointercancel',function(){ armed=false; });
+ el.addEventListener('pointerup',function(e){
+ if(!armed) return; armed=false;
+ if(Math.abs(e.clientX-sx)<16&&Math.abs(e.clientY-sy)<16) fn();
+ });
+ }
+ function mk(cls,txt){ var e=document.createElement('div'); e.className=cls; e.textContent=txt; return e; }
+ function genCode(){
+ var A='ABCDEFGHJKLMNPQRSTUVWXYZ23456789', s='';
+ for(var i=0;i<4;i++) s+=A.charAt(Math.floor(Math.random()*A.length));
+ return 'LL-'+s;
+ }
+ function setPrize(){
+ won = Math.random() < WIN_RATE;
+ prize.innerHTML='';
+ if(won){
+ prize.style.background='linear-gradient(160deg,#16a34a,#065f46)';
+ prize.appendChild(mk('big','🎉 '+PRIZE.label));
+ prize.appendChild(mk('code',genCode()));
+ prize.appendChild(mk('note',PRIZE.note));
+ } else {
+ prize.style.background='linear-gradient(160deg,#475569,#1e293b)';
+ prize.appendChild(mk('big','😬 Not this time'));
+ prize.appendChild(mk('note','Tap “New card” for another go.'));
+ }
+ }
+ function coverFoil(){
+ ctx.globalCompositeOperation='source-over';
+ var g=ctx.createLinearGradient(0,0,W,H);
+ g.addColorStop(0,'#cbd5e1'); g.addColorStop(0.5,'#94a3b8'); g.addColorStop(1,'#e2e8f0');
+ ctx.fillStyle=g; ctx.fillRect(0,0,W,H);
+ ctx.fillStyle='rgba(15,23,42,.5)';
+ ctx.textAlign='center'; ctx.textBaseline='middle';
+ ctx.font='800 '+Math.round(H*0.15)+'px system-ui';
+ ctx.fillText('SCRATCH HERE',W/2,H*0.42);
+ ctx.font='600 '+Math.round(H*0.16)+'px system-ui';
+ ctx.fillText('👆',W/2,H*0.7);
+ }
+ function fit(){
+ var r=cv.getBoundingClientRect(); if(r.width<=0) return;
+ var dpr=Math.min(window.devicePixelRatio||1,2);
+ W=r.width; H=r.height;
+ cv.width=Math.round(W*dpr); cv.height=Math.round(H*dpr);
+ ctx.setTransform(dpr,0,0,dpr,0,0);
+ if(!revealed) coverFoil();
+ }
+ function newCard(){
+ revealed=false; scratching=false;
+ again.style.display='none';
+ hint.textContent='Scratch the silver area with your finger.';
+ cv.style.display='block';
+ setPrize(); coverFoil();
+ }
+ function eraseTo(x,y){
+ ctx.globalCompositeOperation='destination-out';
+ ctx.lineCap='round'; ctx.lineJoin='round';
+ ctx.lineWidth=Math.max(24,W*0.11);
+ ctx.beginPath(); ctx.moveTo(lastX,lastY); ctx.lineTo(x,y); ctx.stroke();
+ ctx.beginPath(); ctx.arc(x,y,ctx.lineWidth/2,0,Math.PI*2); ctx.fill();
+ lastX=x; lastY=y;
+ }
+ function scratchedPct(){
+ try{
+ var d=ctx.getImageData(0,0,cv.width,cv.height).data, clear=0, n=0;
+ for(var i=3;i<d.length;i+=40){ n++; if(d[i]<40) clear++; }
+ return n? clear/n : 0;
+ }catch(e){ return 0; }
+ }
+ function revealAll(){
+ revealed=true;
+ ctx.globalCompositeOperation='destination-out';
+ ctx.fillRect(0,0,W,H);
+ cv.style.display='none';
+ hint.textContent = won ? 'Lucky you — use the code above!' : 'No prize this time.';
+ again.style.display='inline-block';
+ }
+ function ptr(e){
+ var r=cv.getBoundingClientRect();
+ return { x:(e.clientX-r.left)/r.width*W, y:(e.clientY-r.top)/r.height*H };
+ }
+ cv.addEventListener('pointerdown',function(e){
+ if(revealed) return;
+ scratching=true;
+ try{ cv.setPointerCapture(e.pointerId); }catch(_){}
+ var p=ptr(e); lastX=p.x; lastY=p.y; eraseTo(p.x,p.y);
+ e.preventDefault();
+ });
+ cv.addEventListener('pointermove',function(e){
+ if(!scratching||revealed) return;
+ var p=ptr(e); eraseTo(p.x,p.y);
+ e.preventDefault();
+ });
+ function endScratch(){
+ if(!scratching) return;
+ scratching=false;
+ if(!revealed && scratchedPct()>0.55) revealAll();
+ }
+ cv.addEventListener('pointerup',endScratch);
+ cv.addEventListener('pointercancel',endScratch);
+
+ onTap(again,newCard);
+ window.addEventListener('resize',fit);
+ setPrize();
+ fit();
+ requestAnimationFrame(fit);
+})();
+</script>

v1Current

@liveloop · 5/18/2026, 8:14:56 AM

Initial version — all lines are new.

+<style>
+ html,body{height:100%;margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:linear-gradient(160deg,#1e1b4b,#0f172a);color:#f1f5f9;overflow:hidden;}
+ .wrap{display:flex;flex-direction:column;height:100%;box-sizing:border-box;padding:1.2rem;gap:.85rem;align-items:center;justify-content:center;}
+ h1{margin:0;font-size:1.35rem;text-align:center;}
+ .hint{margin:0;font-size:.78rem;color:#94a3b8;text-align:center;min-height:1.1em;}
+ #card{position:relative;width:min(86vw,330px);aspect-ratio:5/3;border-radius:1rem;overflow:hidden;box-shadow:0 14px 36px rgba(0,0,0,.55);}
+ #prize{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.35rem;text-align:center;padding:1rem;box-sizing:border-box;}
+ #prize .big{font-size:1.45rem;font-weight:800;}
+ #prize .code{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:1.5rem;font-weight:800;letter-spacing:.14em;background:rgba(0,0,0,.28);padding:.3rem .75rem;border-radius:.5rem;}
+ #prize .note{font-size:.68rem;opacity:.8;max-width:26ch;}
+ #scratch{position:absolute;inset:0;width:100%;height:100%;touch-action:none;cursor:grab;}
+ button{font:inherit;font-weight:700;border:0;border-radius:9999px;padding:.6rem 1.5rem;background:#fbbf24;color:#0b1020;cursor:pointer;touch-action:manipulation;}
+</style>
+<div class="wrap">
+ <h1>🎟️ Scratch & Win</h1>
+ <div id="card">
+ <div id="prize"></div>
+ <canvas id="scratch"></canvas>
+ </div>
+ <p class="hint" id="hint">Scratch the silver area with your finger.</p>
+ <button id="again" type="button" style="display:none">New card</button>
+</div>
+<script>
+(function(){
+ // Remixing this into a real promo? Set your odds + prize text here.
+ var WIN_RATE = 0.5;
+ var PRIZE = {
+ label: 'You won a coupon!',
+ note: 'Demo code — remix this card and set your own real one.'
+ };
+
+ var prize=document.getElementById('prize'), cv=document.getElementById('scratch'),
+ ctx=cv.getContext('2d'), hint=document.getElementById('hint'),
+ again=document.getElementById('again');
+ var W=0,H=0,won=false,revealed=false,scratching=false,lastX=0,lastY=0;
+
+ function onTap(el,fn){
+ var sx=0,sy=0,armed=false;
+ el.addEventListener('pointerdown',function(e){ armed=true;sx=e.clientX;sy=e.clientY; });
+ el.addEventListener('pointercancel',function(){ armed=false; });
+ el.addEventListener('pointerup',function(e){
+ if(!armed) return; armed=false;
+ if(Math.abs(e.clientX-sx)<16&&Math.abs(e.clientY-sy)<16) fn();
+ });
+ }
+ function mk(cls,txt){ var e=document.createElement('div'); e.className=cls; e.textContent=txt; return e; }
+ function genCode(){
+ var A='ABCDEFGHJKLMNPQRSTUVWXYZ23456789', s='';
+ for(var i=0;i<4;i++) s+=A.charAt(Math.floor(Math.random()*A.length));
+ return 'LL-'+s;
+ }
+ function setPrize(){
+ won = Math.random() < WIN_RATE;
+ prize.innerHTML='';
+ if(won){
+ prize.style.background='linear-gradient(160deg,#16a34a,#065f46)';
+ prize.appendChild(mk('big','🎉 '+PRIZE.label));
+ prize.appendChild(mk('code',genCode()));
+ prize.appendChild(mk('note',PRIZE.note));
+ } else {
+ prize.style.background='linear-gradient(160deg,#475569,#1e293b)';
+ prize.appendChild(mk('big','😬 Not this time'));
+ prize.appendChild(mk('note','Tap “New card” for another go.'));
+ }
+ }
+ function coverFoil(){
+ ctx.globalCompositeOperation='source-over';
+ var g=ctx.createLinearGradient(0,0,W,H);
+ g.addColorStop(0,'#cbd5e1'); g.addColorStop(0.5,'#94a3b8'); g.addColorStop(1,'#e2e8f0');
+ ctx.fillStyle=g; ctx.fillRect(0,0,W,H);
+ ctx.fillStyle='rgba(15,23,42,.5)';
+ ctx.textAlign='center'; ctx.textBaseline='middle';
+ ctx.font='800 '+Math.round(H*0.15)+'px system-ui';
+ ctx.fillText('SCRATCH HERE',W/2,H*0.42);
+ ctx.font='600 '+Math.round(H*0.16)+'px system-ui';
+ ctx.fillText('👆',W/2,H*0.7);
+ }
+ function fit(){
+ var r=cv.getBoundingClientRect(); if(r.width<=0) return;
+ var dpr=Math.min(window.devicePixelRatio||1,2);
+ W=r.width; H=r.height;
+ cv.width=Math.round(W*dpr); cv.height=Math.round(H*dpr);
+ ctx.setTransform(dpr,0,0,dpr,0,0);
+ if(!revealed) coverFoil();
+ }
+ function newCard(){
+ revealed=false; scratching=false;
+ again.style.display='none';
+ hint.textContent='Scratch the silver area with your finger.';
+ cv.style.display='block';
+ setPrize(); coverFoil();
+ }
+ function eraseTo(x,y){
+ ctx.globalCompositeOperation='destination-out';
+ ctx.lineCap='round'; ctx.lineJoin='round';
+ ctx.lineWidth=Math.max(24,W*0.11);
+ ctx.beginPath(); ctx.moveTo(lastX,lastY); ctx.lineTo(x,y); ctx.stroke();
+ ctx.beginPath(); ctx.arc(x,y,ctx.lineWidth/2,0,Math.PI*2); ctx.fill();
+ lastX=x; lastY=y;
+ }
+ function scratchedPct(){
+ try{
+ var d=ctx.getImageData(0,0,cv.width,cv.height).data, clear=0, n=0;
+ for(var i=3;i<d.length;i+=40){ n++; if(d[i]<40) clear++; }
+ return n? clear/n : 0;
+ }catch(e){ return 0; }
+ }
+ function revealAll(){
+ revealed=true;
+ ctx.globalCompositeOperation='destination-out';
+ ctx.fillRect(0,0,W,H);
+ cv.style.display='none';
+ hint.textContent = won ? 'Lucky you — use the code above!' : 'No prize this time.';
+ again.style.display='inline-block';
+ }
+ function ptr(e){
+ var r=cv.getBoundingClientRect();
+ return { x:(e.clientX-r.left)/r.width*W, y:(e.clientY-r.top)/r.height*H };
+ }
+ cv.addEventListener('pointerdown',function(e){
+ if(revealed) return;
+ scratching=true;
+ try{ cv.setPointerCapture(e.pointerId); }catch(_){}
+ var p=ptr(e); lastX=p.x; lastY=p.y; eraseTo(p.x,p.y);
+ e.preventDefault();
+ });
+ cv.addEventListener('pointermove',function(e){
+ if(!scratching||revealed) return;
+ var p=ptr(e); eraseTo(p.x,p.y);
+ e.preventDefault();
+ });
+ function endScratch(){
+ if(!scratching) return;
+ scratching=false;
+ if(!revealed && scratchedPct()>0.55) revealAll();
+ }
+ cv.addEventListener('pointerup',endScratch);
+ cv.addEventListener('pointercancel',endScratch);
+
+ onTap(again,newCard);
+ window.addEventListener('resize',fit);
+ setPrize();
+ fit();
+ requestAnimationFrame(fit);
+})();
+</script>
← Version history