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/17/2026, 11:35:54 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:#0b1020;color:#f8fafc;overflow:hidden;}
+ .wrap{display:flex;flex-direction:column;height:100%;box-sizing:border-box;padding:.85rem;gap:.55rem;}
+ .top{display:flex;align-items:baseline;justify-content:space-between;gap:.5rem;}
+ h1{margin:0;font-size:1rem;}
+ #count{font-size:.78rem;color:#94a3b8;font-variant-numeric:tabular-nums;}
+ .stage{flex:1;display:flex;gap:.6rem;min-height:0;}
+ #photo{flex:1;border-radius:1rem;background:#1e293b;background-size:cover;background-position:center;display:flex;flex-direction:column;align-items:center;justify-content:center;overflow:hidden;box-shadow:0 10px 30px rgba(0,0,0,.45);}
+ #emoji{font-size:min(30vw,130px);line-height:1;filter:drop-shadow(0 6px 14px rgba(0,0,0,.35));}
+ #caption{margin-top:.35rem;font-weight:700;font-size:1.05rem;color:#fff;text-shadow:0 2px 10px rgba(0,0,0,.55);}
+ .slider{width:46px;display:flex;align-items:stretch;justify-content:center;padding:.5rem 0;touch-action:none;user-select:none;-webkit-user-select:none;cursor:pointer;}
+ #track{position:relative;width:8px;background:#334155;border-radius:9999px;}
+ #fillbar{position:absolute;left:0;right:0;top:0;background:linear-gradient(#60a5fa,#3b82f6);border-radius:9999px;}
+ #handle{position:absolute;left:50%;top:0;width:34px;height:34px;border-radius:50%;background:#fff;color:#1e293b;box-shadow:0 3px 12px rgba(0,0,0,.55);transform:translate(-50%,-50%);display:flex;align-items:center;justify-content:center;font-size:1rem;}
+ .hint{font-size:.7rem;color:#64748b;text-align:center;}
+ .addrow{display:flex;justify-content:center;}
+ .add{font:inherit;font-size:.82rem;font-weight:600;border:0;border-radius:9999px;padding:.55rem 1.1rem;background:#3b82f6;color:#fff;cursor:pointer;touch-action:manipulation;display:inline-flex;align-items:center;gap:.35rem;}
+ .hidden{display:none;}
+</style>
+<div class="wrap">
+ <div class="top"><h1>📷 Photo Slider</h1><span id="count">1 / 3</span></div>
+ <div class="stage">
+ <div id="photo"><div id="emoji">🌅</div><div id="caption">Sunrise</div></div>
+ <div class="slider" id="slider">
+ <div id="track"><div id="fillbar"></div><div id="handle">⋮</div></div>
+ </div>
+ </div>
+ <div class="hint">Drag the bar down for the next photo, up for the previous</div>
+ <div class="addrow">
+ <label class="add">➕ Add photo<input type="file" accept="image/*" multiple id="pick" class="hidden"></label>
+ </div>
+</div>
+<script>
+(function(){
+ // Remixing? Put image URLs in START_PHOTOS to replace the examples.
+ var START_PHOTOS = [];
+
+ var slides = START_PHOTOS.length
+ ? START_PHOTOS.map(function(u){ return { url:u }; })
+ : [
+ { grad:'linear-gradient(160deg,#fde68a,#fb923c,#ef4444)', emoji:'🌅', label:'Sunrise' },
+ { grad:'linear-gradient(160deg,#a5f3fc,#0ea5e9,#1e3a8a)', emoji:'🌊', label:'Ocean' },
+ { grad:'linear-gradient(160deg,#bbf7d0,#22c55e,#14532d)', emoji:'🌲', label:'Forest' }
+ ];
+ var idx=0;
+ var photo=document.getElementById('photo'),emoji=document.getElementById('emoji'),
+ caption=document.getElementById('caption'),count=document.getElementById('count'),
+ slider=document.getElementById('slider'),track=document.getElementById('track'),
+ handle=document.getElementById('handle'),fillbar=document.getElementById('fillbar'),
+ pick=document.getElementById('pick');
+
+ function render(){
+ var s=slides[idx];
+ if(s.url){
+ photo.style.backgroundImage='url("'+s.url+'")';
+ emoji.style.display='none'; caption.style.display='none';
+ } else {
+ photo.style.backgroundImage=s.grad;
+ emoji.style.display=''; caption.style.display='';
+ emoji.textContent=s.emoji; caption.textContent=s.label;
+ }
+ count.textContent=(idx+1)+' / '+slides.length;
+ var pct=slides.length<2?0:idx/(slides.length-1);
+ handle.style.top=(pct*100)+'%';
+ fillbar.style.height=(pct*100)+'%';
+ }
+ function setIdx(n){
+ n=Math.max(0,Math.min(slides.length-1,n));
+ if(n!==idx) idx=n;
+ render();
+ }
+ function posToIdx(clientY){
+ var r=track.getBoundingClientRect();
+ if(r.height<=0) return idx;
+ var pct=(clientY-r.top)/r.height;
+ pct=Math.max(0,Math.min(1,pct));
+ return Math.round(pct*(slides.length-1));
+ }
+
+ var dragging=false;
+ slider.addEventListener('pointerdown',function(e){
+ dragging=true;
+ try{ slider.setPointerCapture(e.pointerId); }catch(_){}
+ setIdx(posToIdx(e.clientY));
+ e.preventDefault();
+ });
+ slider.addEventListener('pointermove',function(e){
+ if(dragging){ setIdx(posToIdx(e.clientY)); e.preventDefault(); }
+ });
+ function endDrag(e){
+ dragging=false;
+ try{ slider.releasePointerCapture(e.pointerId); }catch(_){}
+ }
+ slider.addEventListener('pointerup',endDrag);
+ slider.addEventListener('pointercancel',endDrag);
+
+ pick.addEventListener('change',function(e){
+ var files=e.target.files; if(!files||!files.length) return;
+ var pending=files.length;
+ function done(){ if(--pending===0) setIdx(slides.length-1); }
+ Array.prototype.forEach.call(files,function(file){
+ var reader=new FileReader();
+ reader.onload=function(){
+ var img=new Image();
+ img.onload=function(){
+ try{
+ var max=900,sc=Math.min(1,max/Math.max(img.width,img.height));
+ var c=document.createElement('canvas');
+ c.width=Math.round(img.width*sc); c.height=Math.round(img.height*sc);
+ c.getContext('2d').drawImage(img,0,0,c.width,c.height);
+ slides.push({ url:c.toDataURL('image/jpeg',0.85) });
+ }catch(err){ slides.push({ url:reader.result }); }
+ done();
+ };
+ img.onerror=function(){ slides.push({ url:reader.result }); done(); };
+ img.src=reader.result;
+ };
+ reader.onerror=done;
+ reader.readAsDataURL(file);
+ });
+ });
+
+ render();
+})();
+</script>

v1Current

@liveloop · 5/17/2026, 11:35:54 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:#0b1020;color:#f8fafc;overflow:hidden;}
+ .wrap{display:flex;flex-direction:column;height:100%;box-sizing:border-box;padding:.85rem;gap:.55rem;}
+ .top{display:flex;align-items:baseline;justify-content:space-between;gap:.5rem;}
+ h1{margin:0;font-size:1rem;}
+ #count{font-size:.78rem;color:#94a3b8;font-variant-numeric:tabular-nums;}
+ .stage{flex:1;display:flex;gap:.6rem;min-height:0;}
+ #photo{flex:1;border-radius:1rem;background:#1e293b;background-size:cover;background-position:center;display:flex;flex-direction:column;align-items:center;justify-content:center;overflow:hidden;box-shadow:0 10px 30px rgba(0,0,0,.45);}
+ #emoji{font-size:min(30vw,130px);line-height:1;filter:drop-shadow(0 6px 14px rgba(0,0,0,.35));}
+ #caption{margin-top:.35rem;font-weight:700;font-size:1.05rem;color:#fff;text-shadow:0 2px 10px rgba(0,0,0,.55);}
+ .slider{width:46px;display:flex;align-items:stretch;justify-content:center;padding:.5rem 0;touch-action:none;user-select:none;-webkit-user-select:none;cursor:pointer;}
+ #track{position:relative;width:8px;background:#334155;border-radius:9999px;}
+ #fillbar{position:absolute;left:0;right:0;top:0;background:linear-gradient(#60a5fa,#3b82f6);border-radius:9999px;}
+ #handle{position:absolute;left:50%;top:0;width:34px;height:34px;border-radius:50%;background:#fff;color:#1e293b;box-shadow:0 3px 12px rgba(0,0,0,.55);transform:translate(-50%,-50%);display:flex;align-items:center;justify-content:center;font-size:1rem;}
+ .hint{font-size:.7rem;color:#64748b;text-align:center;}
+ .addrow{display:flex;justify-content:center;}
+ .add{font:inherit;font-size:.82rem;font-weight:600;border:0;border-radius:9999px;padding:.55rem 1.1rem;background:#3b82f6;color:#fff;cursor:pointer;touch-action:manipulation;display:inline-flex;align-items:center;gap:.35rem;}
+ .hidden{display:none;}
+</style>
+<div class="wrap">
+ <div class="top"><h1>📷 Photo Slider</h1><span id="count">1 / 3</span></div>
+ <div class="stage">
+ <div id="photo"><div id="emoji">🌅</div><div id="caption">Sunrise</div></div>
+ <div class="slider" id="slider">
+ <div id="track"><div id="fillbar"></div><div id="handle">⋮</div></div>
+ </div>
+ </div>
+ <div class="hint">Drag the bar down for the next photo, up for the previous</div>
+ <div class="addrow">
+ <label class="add">➕ Add photo<input type="file" accept="image/*" multiple id="pick" class="hidden"></label>
+ </div>
+</div>
+<script>
+(function(){
+ // Remixing? Put image URLs in START_PHOTOS to replace the examples.
+ var START_PHOTOS = [];
+
+ var slides = START_PHOTOS.length
+ ? START_PHOTOS.map(function(u){ return { url:u }; })
+ : [
+ { grad:'linear-gradient(160deg,#fde68a,#fb923c,#ef4444)', emoji:'🌅', label:'Sunrise' },
+ { grad:'linear-gradient(160deg,#a5f3fc,#0ea5e9,#1e3a8a)', emoji:'🌊', label:'Ocean' },
+ { grad:'linear-gradient(160deg,#bbf7d0,#22c55e,#14532d)', emoji:'🌲', label:'Forest' }
+ ];
+ var idx=0;
+ var photo=document.getElementById('photo'),emoji=document.getElementById('emoji'),
+ caption=document.getElementById('caption'),count=document.getElementById('count'),
+ slider=document.getElementById('slider'),track=document.getElementById('track'),
+ handle=document.getElementById('handle'),fillbar=document.getElementById('fillbar'),
+ pick=document.getElementById('pick');
+
+ function render(){
+ var s=slides[idx];
+ if(s.url){
+ photo.style.backgroundImage='url("'+s.url+'")';
+ emoji.style.display='none'; caption.style.display='none';
+ } else {
+ photo.style.backgroundImage=s.grad;
+ emoji.style.display=''; caption.style.display='';
+ emoji.textContent=s.emoji; caption.textContent=s.label;
+ }
+ count.textContent=(idx+1)+' / '+slides.length;
+ var pct=slides.length<2?0:idx/(slides.length-1);
+ handle.style.top=(pct*100)+'%';
+ fillbar.style.height=(pct*100)+'%';
+ }
+ function setIdx(n){
+ n=Math.max(0,Math.min(slides.length-1,n));
+ if(n!==idx) idx=n;
+ render();
+ }
+ function posToIdx(clientY){
+ var r=track.getBoundingClientRect();
+ if(r.height<=0) return idx;
+ var pct=(clientY-r.top)/r.height;
+ pct=Math.max(0,Math.min(1,pct));
+ return Math.round(pct*(slides.length-1));
+ }
+
+ var dragging=false;
+ slider.addEventListener('pointerdown',function(e){
+ dragging=true;
+ try{ slider.setPointerCapture(e.pointerId); }catch(_){}
+ setIdx(posToIdx(e.clientY));
+ e.preventDefault();
+ });
+ slider.addEventListener('pointermove',function(e){
+ if(dragging){ setIdx(posToIdx(e.clientY)); e.preventDefault(); }
+ });
+ function endDrag(e){
+ dragging=false;
+ try{ slider.releasePointerCapture(e.pointerId); }catch(_){}
+ }
+ slider.addEventListener('pointerup',endDrag);
+ slider.addEventListener('pointercancel',endDrag);
+
+ pick.addEventListener('change',function(e){
+ var files=e.target.files; if(!files||!files.length) return;
+ var pending=files.length;
+ function done(){ if(--pending===0) setIdx(slides.length-1); }
+ Array.prototype.forEach.call(files,function(file){
+ var reader=new FileReader();
+ reader.onload=function(){
+ var img=new Image();
+ img.onload=function(){
+ try{
+ var max=900,sc=Math.min(1,max/Math.max(img.width,img.height));
+ var c=document.createElement('canvas');
+ c.width=Math.round(img.width*sc); c.height=Math.round(img.height*sc);
+ c.getContext('2d').drawImage(img,0,0,c.width,c.height);
+ slides.push({ url:c.toDataURL('image/jpeg',0.85) });
+ }catch(err){ slides.push({ url:reader.result }); }
+ done();
+ };
+ img.onerror=function(){ slides.push({ url:reader.result }); done(); };
+ img.src=reader.result;
+ };
+ reader.onerror=done;
+ reader.readAsDataURL(file);
+ });
+ });
+
+ render();
+})();
+</script>
← Version history