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, 12:03:28 PM

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:#fef3c7;overflow:hidden;}
+ .wrap{display:flex;flex-direction:column;height:100%;box-sizing:border-box;padding:.5rem;gap:.4rem;}
+ h1{margin:0;font-size:1rem;text-align:center;color:#92400e;}
+ #board{flex:1;min-height:0;border-radius:1rem;overflow:hidden;background:#fff;box-shadow:0 6px 18px rgba(0,0,0,.18);}
+ canvas{width:100%;height:100%;display:block;touch-action:none;cursor:crosshair;}
+ .colors{display:flex;flex-wrap:wrap;gap:.3rem;justify-content:center;}
+ .sw{width:2rem;height:2rem;border-radius:50%;border:3px solid #fff;box-shadow:0 1px 3px rgba(0,0,0,.35);cursor:pointer;touch-action:manipulation;padding:0;}
+ .sw.on{outline:3px solid #1f2937;outline-offset:1px;}
+ .tools{display:flex;gap:.35rem;justify-content:center;align-items:center;flex-wrap:wrap;}
+ .tool{font:inherit;font-size:.82rem;font-weight:700;border:0;border-radius:9999px;padding:.5rem .85rem;background:#fff;color:#1f2937;box-shadow:0 2px 5px rgba(0,0,0,.2);cursor:pointer;touch-action:manipulation;}
+ .tool.on{background:#1f2937;color:#fff;}
+ .brush{width:2.4rem;height:2.4rem;border-radius:50%;border:0;background:#fff;box-shadow:0 2px 5px rgba(0,0,0,.2);cursor:pointer;touch-action:manipulation;display:flex;align-items:center;justify-content:center;}
+ .brush.on{background:#1f2937;}
+ .dot{border-radius:50%;background:#1f2937;display:block;}
+ .brush.on .dot{background:#fff;}
+</style>
+<div class="wrap">
+ <h1>🎨 Doodle Pad</h1>
+ <div id="board"><canvas id="cv"></canvas></div>
+ <div class="colors" id="colors"></div>
+ <div class="tools">
+ <button class="brush on" data-size="6" type="button"><span class="dot" style="width:7px;height:7px"></span></button>
+ <button class="brush" data-size="16" type="button"><span class="dot" style="width:14px;height:14px"></span></button>
+ <button class="brush" data-size="30" type="button"><span class="dot" style="width:22px;height:22px"></span></button>
+ <button class="tool" id="eraser" type="button">🧽 Eraser</button>
+ <button class="tool" id="undo" type="button">↩️ Undo</button>
+ <button class="tool" id="clear" type="button">🗑️ Clear</button>
+ </div>
+</div>
+<script>
+(function(){
+ var COLORS=['#ef4444','#f97316','#facc15','#22c55e','#06b6d4','#3b82f6','#a855f7','#ec4899','#92400e','#1f2937','#ffffff'];
+ var cv=document.getElementById('cv'), ctx=cv.getContext('2d');
+ var colorsEl=document.getElementById('colors');
+ var color='#ef4444', size=6, erasing=false;
+ var strokes=[], curStroke=null, W=0, H=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)<14&&Math.abs(e.clientY-sy)<14) fn();
+ });
+ }
+ function fit(){
+ var r=cv.getBoundingClientRect();
+ if(r.width<=0||r.height<=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);
+ redraw();
+ }
+ function redraw(){
+ ctx.clearRect(0,0,W,H);
+ ctx.fillStyle='#ffffff'; ctx.fillRect(0,0,W,H);
+ ctx.lineCap='round'; ctx.lineJoin='round';
+ for(var i=0;i<strokes.length;i++) drawStroke(strokes[i]);
+ }
+ function drawStroke(s){
+ if(!s.pts.length) return;
+ ctx.strokeStyle=s.color; ctx.lineWidth=s.size;
+ ctx.lineCap='round'; ctx.lineJoin='round';
+ ctx.beginPath();
+ ctx.moveTo(s.pts[0].x*W,s.pts[0].y*H);
+ for(var i=1;i<s.pts.length;i++) ctx.lineTo(s.pts[i].x*W,s.pts[i].y*H);
+ if(s.pts.length===1) ctx.lineTo(s.pts[0].x*W+0.1,s.pts[0].y*H+0.1);
+ ctx.stroke();
+ }
+ function pt(e){
+ var r=cv.getBoundingClientRect();
+ return { x:(e.clientX-r.left)/r.width, y:(e.clientY-r.top)/r.height };
+ }
+
+ var drawing=false;
+ cv.addEventListener('pointerdown',function(e){
+ drawing=true;
+ try{ cv.setPointerCapture(e.pointerId); }catch(_){}
+ curStroke={ color: erasing?'#ffffff':color, size:size, pts:[pt(e)] };
+ strokes.push(curStroke);
+ drawStroke(curStroke);
+ e.preventDefault();
+ });
+ cv.addEventListener('pointermove',function(e){
+ if(!drawing||!curStroke) return;
+ curStroke.pts.push(pt(e));
+ var n=curStroke.pts.length;
+ ctx.strokeStyle=curStroke.color; ctx.lineWidth=curStroke.size;
+ ctx.lineCap='round'; ctx.lineJoin='round';
+ ctx.beginPath();
+ ctx.moveTo(curStroke.pts[n-2].x*W,curStroke.pts[n-2].y*H);
+ ctx.lineTo(curStroke.pts[n-1].x*W,curStroke.pts[n-1].y*H);
+ ctx.stroke();
+ e.preventDefault();
+ });
+ function endStroke(e){
+ drawing=false; curStroke=null;
+ try{ cv.releasePointerCapture(e.pointerId); }catch(_){}
+ }
+ cv.addEventListener('pointerup',endStroke);
+ cv.addEventListener('pointercancel',endStroke);
+
+ COLORS.forEach(function(c){
+ var b=document.createElement('button');
+ b.type='button'; b.className='sw'; b.style.background=c;
+ if(c==='#ef4444') b.classList.add('on');
+ onTap(b,function(){
+ color=c; erasing=false;
+ document.getElementById('eraser').classList.remove('on');
+ var sws=colorsEl.querySelectorAll('.sw');
+ for(var k=0;k<sws.length;k++) sws[k].classList.toggle('on',sws[k]===b);
+ });
+ colorsEl.appendChild(b);
+ });
+
+ var brushes=document.querySelectorAll('.brush');
+ Array.prototype.forEach.call(brushes,function(b){
+ onTap(b,function(){
+ size=parseInt(b.getAttribute('data-size'),10);
+ Array.prototype.forEach.call(brushes,function(o){ o.classList.toggle('on',o===b); });
+ });
+ });
+ var eraserBtn=document.getElementById('eraser');
+ onTap(eraserBtn,function(){
+ erasing=!erasing;
+ eraserBtn.classList.toggle('on',erasing);
+ });
+ onTap(document.getElementById('undo'),function(){ strokes.pop(); redraw(); });
+ onTap(document.getElementById('clear'),function(){ strokes=[]; redraw(); });
+
+ window.addEventListener('resize',fit);
+ fit();
+ requestAnimationFrame(fit);
+})();
+</script>

v1Current

@liveloop · 5/17/2026, 12:03:28 PM

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:#fef3c7;overflow:hidden;}
+ .wrap{display:flex;flex-direction:column;height:100%;box-sizing:border-box;padding:.5rem;gap:.4rem;}
+ h1{margin:0;font-size:1rem;text-align:center;color:#92400e;}
+ #board{flex:1;min-height:0;border-radius:1rem;overflow:hidden;background:#fff;box-shadow:0 6px 18px rgba(0,0,0,.18);}
+ canvas{width:100%;height:100%;display:block;touch-action:none;cursor:crosshair;}
+ .colors{display:flex;flex-wrap:wrap;gap:.3rem;justify-content:center;}
+ .sw{width:2rem;height:2rem;border-radius:50%;border:3px solid #fff;box-shadow:0 1px 3px rgba(0,0,0,.35);cursor:pointer;touch-action:manipulation;padding:0;}
+ .sw.on{outline:3px solid #1f2937;outline-offset:1px;}
+ .tools{display:flex;gap:.35rem;justify-content:center;align-items:center;flex-wrap:wrap;}
+ .tool{font:inherit;font-size:.82rem;font-weight:700;border:0;border-radius:9999px;padding:.5rem .85rem;background:#fff;color:#1f2937;box-shadow:0 2px 5px rgba(0,0,0,.2);cursor:pointer;touch-action:manipulation;}
+ .tool.on{background:#1f2937;color:#fff;}
+ .brush{width:2.4rem;height:2.4rem;border-radius:50%;border:0;background:#fff;box-shadow:0 2px 5px rgba(0,0,0,.2);cursor:pointer;touch-action:manipulation;display:flex;align-items:center;justify-content:center;}
+ .brush.on{background:#1f2937;}
+ .dot{border-radius:50%;background:#1f2937;display:block;}
+ .brush.on .dot{background:#fff;}
+</style>
+<div class="wrap">
+ <h1>🎨 Doodle Pad</h1>
+ <div id="board"><canvas id="cv"></canvas></div>
+ <div class="colors" id="colors"></div>
+ <div class="tools">
+ <button class="brush on" data-size="6" type="button"><span class="dot" style="width:7px;height:7px"></span></button>
+ <button class="brush" data-size="16" type="button"><span class="dot" style="width:14px;height:14px"></span></button>
+ <button class="brush" data-size="30" type="button"><span class="dot" style="width:22px;height:22px"></span></button>
+ <button class="tool" id="eraser" type="button">🧽 Eraser</button>
+ <button class="tool" id="undo" type="button">↩️ Undo</button>
+ <button class="tool" id="clear" type="button">🗑️ Clear</button>
+ </div>
+</div>
+<script>
+(function(){
+ var COLORS=['#ef4444','#f97316','#facc15','#22c55e','#06b6d4','#3b82f6','#a855f7','#ec4899','#92400e','#1f2937','#ffffff'];
+ var cv=document.getElementById('cv'), ctx=cv.getContext('2d');
+ var colorsEl=document.getElementById('colors');
+ var color='#ef4444', size=6, erasing=false;
+ var strokes=[], curStroke=null, W=0, H=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)<14&&Math.abs(e.clientY-sy)<14) fn();
+ });
+ }
+ function fit(){
+ var r=cv.getBoundingClientRect();
+ if(r.width<=0||r.height<=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);
+ redraw();
+ }
+ function redraw(){
+ ctx.clearRect(0,0,W,H);
+ ctx.fillStyle='#ffffff'; ctx.fillRect(0,0,W,H);
+ ctx.lineCap='round'; ctx.lineJoin='round';
+ for(var i=0;i<strokes.length;i++) drawStroke(strokes[i]);
+ }
+ function drawStroke(s){
+ if(!s.pts.length) return;
+ ctx.strokeStyle=s.color; ctx.lineWidth=s.size;
+ ctx.lineCap='round'; ctx.lineJoin='round';
+ ctx.beginPath();
+ ctx.moveTo(s.pts[0].x*W,s.pts[0].y*H);
+ for(var i=1;i<s.pts.length;i++) ctx.lineTo(s.pts[i].x*W,s.pts[i].y*H);
+ if(s.pts.length===1) ctx.lineTo(s.pts[0].x*W+0.1,s.pts[0].y*H+0.1);
+ ctx.stroke();
+ }
+ function pt(e){
+ var r=cv.getBoundingClientRect();
+ return { x:(e.clientX-r.left)/r.width, y:(e.clientY-r.top)/r.height };
+ }
+
+ var drawing=false;
+ cv.addEventListener('pointerdown',function(e){
+ drawing=true;
+ try{ cv.setPointerCapture(e.pointerId); }catch(_){}
+ curStroke={ color: erasing?'#ffffff':color, size:size, pts:[pt(e)] };
+ strokes.push(curStroke);
+ drawStroke(curStroke);
+ e.preventDefault();
+ });
+ cv.addEventListener('pointermove',function(e){
+ if(!drawing||!curStroke) return;
+ curStroke.pts.push(pt(e));
+ var n=curStroke.pts.length;
+ ctx.strokeStyle=curStroke.color; ctx.lineWidth=curStroke.size;
+ ctx.lineCap='round'; ctx.lineJoin='round';
+ ctx.beginPath();
+ ctx.moveTo(curStroke.pts[n-2].x*W,curStroke.pts[n-2].y*H);
+ ctx.lineTo(curStroke.pts[n-1].x*W,curStroke.pts[n-1].y*H);
+ ctx.stroke();
+ e.preventDefault();
+ });
+ function endStroke(e){
+ drawing=false; curStroke=null;
+ try{ cv.releasePointerCapture(e.pointerId); }catch(_){}
+ }
+ cv.addEventListener('pointerup',endStroke);
+ cv.addEventListener('pointercancel',endStroke);
+
+ COLORS.forEach(function(c){
+ var b=document.createElement('button');
+ b.type='button'; b.className='sw'; b.style.background=c;
+ if(c==='#ef4444') b.classList.add('on');
+ onTap(b,function(){
+ color=c; erasing=false;
+ document.getElementById('eraser').classList.remove('on');
+ var sws=colorsEl.querySelectorAll('.sw');
+ for(var k=0;k<sws.length;k++) sws[k].classList.toggle('on',sws[k]===b);
+ });
+ colorsEl.appendChild(b);
+ });
+
+ var brushes=document.querySelectorAll('.brush');
+ Array.prototype.forEach.call(brushes,function(b){
+ onTap(b,function(){
+ size=parseInt(b.getAttribute('data-size'),10);
+ Array.prototype.forEach.call(brushes,function(o){ o.classList.toggle('on',o===b); });
+ });
+ });
+ var eraserBtn=document.getElementById('eraser');
+ onTap(eraserBtn,function(){
+ erasing=!erasing;
+ eraserBtn.classList.toggle('on',erasing);
+ });
+ onTap(document.getElementById('undo'),function(){ strokes.pop(); redraw(); });
+ onTap(document.getElementById('clear'),function(){ strokes=[]; redraw(); });
+
+ window.addEventListener('resize',fit);
+ fit();
+ requestAnimationFrame(fit);
+})();
+</script>
← Version history