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

@nova_builds · 6/20/2026, 2:12:21 AM

Initial version — all lines are new.

+<style>
+ html,body{height:100%;margin:0;overflow:hidden;background:#05060f;}
+ *{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:crosshair;}
+ canvas{display:block;width:100%;height:100%;position:absolute;inset:0;}
+ #head{position:absolute;top:0;left:0;right:0;z-index:2;padding:1.15rem 1.25rem;pointer-events:none;}
+ #head h1{margin:0;font-family:"Instrument Serif",Georgia,"Times New Roman",serif;font-weight:400;font-size:2.35rem;line-height:1;color:#EDEBFF;}
+ #head p{margin:.2rem 0 0;font-size:.8rem;color:#8a8fc0;font-weight:500;}
+ #clear{position:absolute;bottom:1.1rem;right:1.1rem;z-index:3;pointer-events:auto;border:1px solid rgba(180,190,255,.22);background:rgba(255,255,255,.06);color:#cdd2ff;border-radius:999px;font-size:.72rem;font-weight:700;padding:.4rem .85rem;cursor:pointer;backdrop-filter:blur(6px);}
+ #clear:active{transform:scale(.95);}
+ #hint{position:absolute;left:50%;top:52%;transform:translate(-50%,-50%);z-index:2;pointer-events:none;font-family:"Instrument Serif",Georgia,serif;font-size:1.2rem;color:#8a8fc0;opacity:.85;transition:opacity .6s;text-align:center;}
+</style>
+<div id="wrap">
+ <canvas id="cv"></canvas>
+ <div id="head">
+ <div><h1>Star Field</h1><p>Drag star to star. Draw the sky.</p></div>
+ </div>
+ <button id="clear">clear</button>
+ <div id="hint">drag between stars</div>
+</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; }
+ // a soft bell when a constellation line connects two stars
+ function chime(freq){
+ if(muted) return; var c=actx(); if(!c) return;
+ var t=c.currentTime, o=c.createOscillator(), g=c.createGain();
+ o.type='sine'; o.frequency.setValueAtTime(freq,t);
+ var o2=c.createOscillator(), g2=c.createGain();
+ o2.type='sine'; o2.frequency.setValueAtTime(freq*2.005,t); // shimmer
+ g.gain.setValueAtTime(0.0001,t); g.gain.exponentialRampToValueAtTime(0.06,t+0.02);
+ g.gain.exponentialRampToValueAtTime(0.0001,t+1.4);
+ g2.gain.setValueAtTime(0.0001,t); g2.gain.exponentialRampToValueAtTime(0.02,t+0.02);
+ g2.gain.exponentialRampToValueAtTime(0.0001,t+1.0);
+ o.connect(g); g.connect(c.destination); o2.connect(g2); g2.connect(c.destination);
+ o.start(t); o.stop(t+1.45); o2.start(t); o2.stop(t+1.05);
+ }
+ function whoosh(){ // faint meteor pass
+ if(muted) return; var c=actx(); if(!c) return;
+ var t=c.currentTime, n=Math.floor(c.sampleRate*0.5), 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 f=c.createBiquadFilter(); f.type='bandpass'; f.frequency.setValueAtTime(900,t); f.frequency.exponentialRampToValueAtTime(2600,t+0.45); f.Q.value=0.7;
+ var g=c.createGain(); g.gain.setValueAtTime(0.0001,t); g.gain.exponentialRampToValueAtTime(0.05,t+0.08); g.gain.exponentialRampToValueAtTime(0.0001,t+0.5);
+ s.connect(f); f.connect(g); g.connect(c.destination); s.start(t);
+ }
+
+ var SCALE=[523.25,587.33,659.25,783.99,880.0,1046.5,1174.7,1318.5];
+
+ var wrap=document.getElementById('wrap');
+ var cv=document.getElementById('cv'), ctx=cv.getContext('2d');
+ var hint=document.getElementById('hint');
+ var W=0,H=0,dpr=1,T0=0,paused=false;
+ var stars=[], links=[], pulses=[], meteors=[], dust=[];
+ var lastStar=null, nextMeteor=0;
+
+ function size(){
+ var r=wrap.getBoundingClientRect();
+ W=Math.max(180,r.width); H=Math.max(240,r.height);
+ dpr=Math.min(window.devicePixelRatio||1,2.5);
+ cv.width=Math.round(W*dpr); cv.height=Math.round(H*dpr);
+ ctx.setTransform(dpr,0,0,dpr,0,0);
+ makeStars();
+ }
+ function makeStars(){
+ stars=[]; dust=[];
+ var n=Math.round(W*H/8500);
+ for(var i=0;i<n;i++){
+ stars.push({ x:Math.random()*W, y:Math.random()*H,
+ r:0.6+Math.random()*1.7, base:0.35+Math.random()*0.5,
+ tw:Math.random()*7, sp:0.6+Math.random()*1.4, lit:0 });
+ }
+ // faint background dust (non-interactive specks)
+ for(var k=0;k<n*1.5;k++){ dust.push({x:Math.random()*W,y:Math.random()*H,r:Math.random()*0.8,a:0.05+Math.random()*0.12}); }
+ }
+
+ function nearestStar(x,y,maxD){
+ var best=null,bd=maxD*maxD;
+ for(var i=0;i<stars.length;i++){
+ var s=stars[i], dx=s.x-x, dy=s.y-y, d=dx*dx+dy*dy;
+ if(d<bd){ bd=d; best=s; }
+ }
+ return best;
+ }
+
+ function connect(a,b){
+ if(!a||!b||a===b) return;
+ // avoid duplicate links
+ for(var i=0;i<links.length;i++){ var l=links[i]; if((l.a===a&&l.b===b)||(l.a===b&&l.b===a)) return; }
+ links.push({a:a,b:b,t:performance.now()});
+ a.lit=1; b.lit=1;
+ pulses.push({a:a,b:b,t:performance.now()});
+ var d=Math.hypot(a.x-b.x,a.y-b.y);
+ chime(SCALE[Math.max(0,Math.min(SCALE.length-1, Math.round((1-Math.min(1,d/(Math.max(W,H)*0.5)))*(SCALE.length-1)) ))]);
+ if(hint.style.opacity!=='0') hint.style.opacity='0';
+ }
+
+ function spawnMeteor(){
+ var edge=Math.random()<0.5;
+ var x0=edge?Math.random()*W:-30, y0=edge?-30:Math.random()*H*0.5;
+ var ang=Math.PI*(0.18+Math.random()*0.16);
+ meteors.push({x:x0,y:y0,vx:Math.cos(ang)*(7+Math.random()*4),vy:Math.sin(ang)*(7+Math.random()*4),life:0,max:60+Math.random()*30,trail:[]});
+ whoosh();
+ }
+
+ function tick(now){
+ requestAnimationFrame(tick);
+ if(paused) return;
+ var dt=Math.min(2.4,(now-T0)/16.67); T0=now;
+
+ // sky gradient
+ var g=ctx.createLinearGradient(0,0,0,H);
+ g.addColorStop(0,'#070818'); g.addColorStop(0.55,'#0a0a1c'); g.addColorStop(1,'#100a22');
+ ctx.fillStyle=g; ctx.fillRect(0,0,W,H);
+ // soft nebula glow
+ var ng=ctx.createRadialGradient(W*0.7,H*0.28,0,W*0.7,H*0.28,Math.max(W,H)*0.6);
+ ng.addColorStop(0,'rgba(120,92,255,0.10)'); ng.addColorStop(1,'rgba(120,92,255,0)');
+ ctx.fillStyle=ng; ctx.fillRect(0,0,W,H);
+
+ // dust
+ for(var i=0;i<dust.length;i++){ var p=dust[i]; ctx.fillStyle='rgba(200,205,255,'+p.a+')'; ctx.fillRect(p.x,p.y,p.r,p.r); }
+
+ // constellation lines
+ for(var i=0;i<links.length;i++){
+ var l=links[i];
+ ctx.strokeStyle='rgba(170,180,255,0.28)'; ctx.lineWidth=1;
+ ctx.beginPath(); ctx.moveTo(l.a.x,l.a.y); ctx.lineTo(l.b.x,l.b.y); ctx.stroke();
+ }
+ // travelling pulses along fresh lines
+ for(var j=pulses.length-1;j>=0;j--){
+ var pu=pulses[j], age=(now-pu.t)/650;
+ if(age>=1){ pulses.splice(j,1); continue; }
+ var px=pu.a.x+(pu.b.x-pu.a.x)*age, py=pu.a.y+(pu.b.y-pu.a.y)*age;
+ var pg=ctx.createRadialGradient(px,py,0,px,py,7);
+ pg.addColorStop(0,'rgba(255,255,255,0.9)'); pg.addColorStop(1,'rgba(180,190,255,0)');
+ ctx.fillStyle=pg; ctx.beginPath(); ctx.arc(px,py,7,0,Math.PI*2); ctx.fill();
+ }
+
+ // stars
+ for(var i=0;i<stars.length;i++){
+ var s=stars[i];
+ var tw=0.5+0.5*Math.sin(now*0.001*s.sp+s.tw);
+ var a=s.base*(0.6+0.4*tw)+s.lit*0.5;
+ if(s.lit>0) s.lit=Math.max(0,s.lit-0.004*dt);
+ var rr=s.r*(1+s.lit*1.4);
+ if(s.lit>0.02 || s.r>1.4){
+ var sg=ctx.createRadialGradient(s.x,s.y,0,s.x,s.y,rr*4);
+ sg.addColorStop(0,'rgba(255,255,255,'+Math.min(1,a)+')');
+ sg.addColorStop(0.4,'rgba(200,210,255,'+(a*0.35)+')');
+ sg.addColorStop(1,'rgba(200,210,255,0)');
+ ctx.fillStyle=sg; ctx.beginPath(); ctx.arc(s.x,s.y,rr*4,0,Math.PI*2); ctx.fill();
+ }
+ ctx.fillStyle='rgba(255,255,255,'+Math.min(1,a)+')';
+ ctx.beginPath(); ctx.arc(s.x,s.y,rr,0,Math.PI*2); ctx.fill();
+ }
+
+ // the in-progress line from the last anchored star to the finger
+ if(lastStar && drag){
+ ctx.strokeStyle='rgba(170,180,255,0.4)'; ctx.lineWidth=1; ctx.setLineDash([4,4]);
+ ctx.beginPath(); ctx.moveTo(lastStar.x,lastStar.y); ctx.lineTo(fx,fy); ctx.stroke(); ctx.setLineDash([]);
+ }
+
+ // meteors
+ if(now>nextMeteor){ nextMeteor=now+6000+Math.random()*7000; spawnMeteor(); }
+ for(var m=meteors.length-1;m>=0;m--){
+ var me=meteors[m]; me.x+=me.vx*dt; me.y+=me.vy*dt; me.life+=dt;
+ me.trail.push({x:me.x,y:me.y}); if(me.trail.length>14) me.trail.shift();
+ for(var k=0;k<me.trail.length;k++){ var tp=me.trail[k], al=(k/me.trail.length)*0.8*(1-me.life/me.max);
+ ctx.fillStyle='rgba(255,250,230,'+Math.max(0,al)+')'; ctx.beginPath(); ctx.arc(tp.x,tp.y,1.6*(k/me.trail.length)+0.3,0,Math.PI*2); ctx.fill(); }
+ if(me.life>me.max||me.x>W+40||me.y>H+40) meteors.splice(m,1);
+ }
+ }
+
+ var drag=false, fx=0, fy=0;
+ function at(e){ var r=cv.getBoundingClientRect(), t=e.touches?e.touches[0]:e; return {x:t.clientX-r.left,y:t.clientY-r.top}; }
+ wrap.addEventListener('pointerdown',function(e){
+ e.preventDefault(); var p=at(e); fx=p.x; fy=p.y; drag=true;
+ lastStar=nearestStar(p.x,p.y,40) || null;
+ if(lastStar){ lastStar.lit=1; }
+ });
+ wrap.addEventListener('pointermove',function(e){
+ if(!drag) return; e.preventDefault(); var p=at(e); fx=p.x; fy=p.y;
+ var hit=nearestStar(p.x,p.y,26);
+ if(hit && hit!==lastStar){ if(lastStar) connect(lastStar,hit); lastStar=hit; }
+ });
+ function release(){ drag=false; lastStar=null; }
+ wrap.addEventListener('pointerup',release);
+ wrap.addEventListener('pointercancel',release);
+ wrap.addEventListener('pointerleave',release);
+
+ document.getElementById('clear').addEventListener('pointerdown',function(e){
+ e.stopPropagation(); links=[]; pulses=[]; for(var i=0;i<stars.length;i++) stars[i].lit=0;
+ hint.style.opacity='.85';
+ });
+
+ if(LL && LL.onPause){ try{ LL.onPause(function(p){ paused=p; if(!p) T0=performance.now(); }); }catch(e){} }
+ document.addEventListener('visibilitychange',function(){ paused=document.hidden; if(!paused) T0=performance.now(); });
+ window.addEventListener('resize',function(){ size(); });
+ size();
+ T0=performance.now(); nextMeteor=performance.now()+3000; requestAnimationFrame(tick);
+})();
+</script>

v1Current

@nova_builds · 6/20/2026, 2:12:21 AM

Initial version — all lines are new.

+<style>
+ html,body{height:100%;margin:0;overflow:hidden;background:#05060f;}
+ *{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:crosshair;}
+ canvas{display:block;width:100%;height:100%;position:absolute;inset:0;}
+ #head{position:absolute;top:0;left:0;right:0;z-index:2;padding:1.15rem 1.25rem;pointer-events:none;}
+ #head h1{margin:0;font-family:"Instrument Serif",Georgia,"Times New Roman",serif;font-weight:400;font-size:2.35rem;line-height:1;color:#EDEBFF;}
+ #head p{margin:.2rem 0 0;font-size:.8rem;color:#8a8fc0;font-weight:500;}
+ #clear{position:absolute;bottom:1.1rem;right:1.1rem;z-index:3;pointer-events:auto;border:1px solid rgba(180,190,255,.22);background:rgba(255,255,255,.06);color:#cdd2ff;border-radius:999px;font-size:.72rem;font-weight:700;padding:.4rem .85rem;cursor:pointer;backdrop-filter:blur(6px);}
+ #clear:active{transform:scale(.95);}
+ #hint{position:absolute;left:50%;top:52%;transform:translate(-50%,-50%);z-index:2;pointer-events:none;font-family:"Instrument Serif",Georgia,serif;font-size:1.2rem;color:#8a8fc0;opacity:.85;transition:opacity .6s;text-align:center;}
+</style>
+<div id="wrap">
+ <canvas id="cv"></canvas>
+ <div id="head">
+ <div><h1>Star Field</h1><p>Drag star to star. Draw the sky.</p></div>
+ </div>
+ <button id="clear">clear</button>
+ <div id="hint">drag between stars</div>
+</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; }
+ // a soft bell when a constellation line connects two stars
+ function chime(freq){
+ if(muted) return; var c=actx(); if(!c) return;
+ var t=c.currentTime, o=c.createOscillator(), g=c.createGain();
+ o.type='sine'; o.frequency.setValueAtTime(freq,t);
+ var o2=c.createOscillator(), g2=c.createGain();
+ o2.type='sine'; o2.frequency.setValueAtTime(freq*2.005,t); // shimmer
+ g.gain.setValueAtTime(0.0001,t); g.gain.exponentialRampToValueAtTime(0.06,t+0.02);
+ g.gain.exponentialRampToValueAtTime(0.0001,t+1.4);
+ g2.gain.setValueAtTime(0.0001,t); g2.gain.exponentialRampToValueAtTime(0.02,t+0.02);
+ g2.gain.exponentialRampToValueAtTime(0.0001,t+1.0);
+ o.connect(g); g.connect(c.destination); o2.connect(g2); g2.connect(c.destination);
+ o.start(t); o.stop(t+1.45); o2.start(t); o2.stop(t+1.05);
+ }
+ function whoosh(){ // faint meteor pass
+ if(muted) return; var c=actx(); if(!c) return;
+ var t=c.currentTime, n=Math.floor(c.sampleRate*0.5), 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 f=c.createBiquadFilter(); f.type='bandpass'; f.frequency.setValueAtTime(900,t); f.frequency.exponentialRampToValueAtTime(2600,t+0.45); f.Q.value=0.7;
+ var g=c.createGain(); g.gain.setValueAtTime(0.0001,t); g.gain.exponentialRampToValueAtTime(0.05,t+0.08); g.gain.exponentialRampToValueAtTime(0.0001,t+0.5);
+ s.connect(f); f.connect(g); g.connect(c.destination); s.start(t);
+ }
+
+ var SCALE=[523.25,587.33,659.25,783.99,880.0,1046.5,1174.7,1318.5];
+
+ var wrap=document.getElementById('wrap');
+ var cv=document.getElementById('cv'), ctx=cv.getContext('2d');
+ var hint=document.getElementById('hint');
+ var W=0,H=0,dpr=1,T0=0,paused=false;
+ var stars=[], links=[], pulses=[], meteors=[], dust=[];
+ var lastStar=null, nextMeteor=0;
+
+ function size(){
+ var r=wrap.getBoundingClientRect();
+ W=Math.max(180,r.width); H=Math.max(240,r.height);
+ dpr=Math.min(window.devicePixelRatio||1,2.5);
+ cv.width=Math.round(W*dpr); cv.height=Math.round(H*dpr);
+ ctx.setTransform(dpr,0,0,dpr,0,0);
+ makeStars();
+ }
+ function makeStars(){
+ stars=[]; dust=[];
+ var n=Math.round(W*H/8500);
+ for(var i=0;i<n;i++){
+ stars.push({ x:Math.random()*W, y:Math.random()*H,
+ r:0.6+Math.random()*1.7, base:0.35+Math.random()*0.5,
+ tw:Math.random()*7, sp:0.6+Math.random()*1.4, lit:0 });
+ }
+ // faint background dust (non-interactive specks)
+ for(var k=0;k<n*1.5;k++){ dust.push({x:Math.random()*W,y:Math.random()*H,r:Math.random()*0.8,a:0.05+Math.random()*0.12}); }
+ }
+
+ function nearestStar(x,y,maxD){
+ var best=null,bd=maxD*maxD;
+ for(var i=0;i<stars.length;i++){
+ var s=stars[i], dx=s.x-x, dy=s.y-y, d=dx*dx+dy*dy;
+ if(d<bd){ bd=d; best=s; }
+ }
+ return best;
+ }
+
+ function connect(a,b){
+ if(!a||!b||a===b) return;
+ // avoid duplicate links
+ for(var i=0;i<links.length;i++){ var l=links[i]; if((l.a===a&&l.b===b)||(l.a===b&&l.b===a)) return; }
+ links.push({a:a,b:b,t:performance.now()});
+ a.lit=1; b.lit=1;
+ pulses.push({a:a,b:b,t:performance.now()});
+ var d=Math.hypot(a.x-b.x,a.y-b.y);
+ chime(SCALE[Math.max(0,Math.min(SCALE.length-1, Math.round((1-Math.min(1,d/(Math.max(W,H)*0.5)))*(SCALE.length-1)) ))]);
+ if(hint.style.opacity!=='0') hint.style.opacity='0';
+ }
+
+ function spawnMeteor(){
+ var edge=Math.random()<0.5;
+ var x0=edge?Math.random()*W:-30, y0=edge?-30:Math.random()*H*0.5;
+ var ang=Math.PI*(0.18+Math.random()*0.16);
+ meteors.push({x:x0,y:y0,vx:Math.cos(ang)*(7+Math.random()*4),vy:Math.sin(ang)*(7+Math.random()*4),life:0,max:60+Math.random()*30,trail:[]});
+ whoosh();
+ }
+
+ function tick(now){
+ requestAnimationFrame(tick);
+ if(paused) return;
+ var dt=Math.min(2.4,(now-T0)/16.67); T0=now;
+
+ // sky gradient
+ var g=ctx.createLinearGradient(0,0,0,H);
+ g.addColorStop(0,'#070818'); g.addColorStop(0.55,'#0a0a1c'); g.addColorStop(1,'#100a22');
+ ctx.fillStyle=g; ctx.fillRect(0,0,W,H);
+ // soft nebula glow
+ var ng=ctx.createRadialGradient(W*0.7,H*0.28,0,W*0.7,H*0.28,Math.max(W,H)*0.6);
+ ng.addColorStop(0,'rgba(120,92,255,0.10)'); ng.addColorStop(1,'rgba(120,92,255,0)');
+ ctx.fillStyle=ng; ctx.fillRect(0,0,W,H);
+
+ // dust
+ for(var i=0;i<dust.length;i++){ var p=dust[i]; ctx.fillStyle='rgba(200,205,255,'+p.a+')'; ctx.fillRect(p.x,p.y,p.r,p.r); }
+
+ // constellation lines
+ for(var i=0;i<links.length;i++){
+ var l=links[i];
+ ctx.strokeStyle='rgba(170,180,255,0.28)'; ctx.lineWidth=1;
+ ctx.beginPath(); ctx.moveTo(l.a.x,l.a.y); ctx.lineTo(l.b.x,l.b.y); ctx.stroke();
+ }
+ // travelling pulses along fresh lines
+ for(var j=pulses.length-1;j>=0;j--){
+ var pu=pulses[j], age=(now-pu.t)/650;
+ if(age>=1){ pulses.splice(j,1); continue; }
+ var px=pu.a.x+(pu.b.x-pu.a.x)*age, py=pu.a.y+(pu.b.y-pu.a.y)*age;
+ var pg=ctx.createRadialGradient(px,py,0,px,py,7);
+ pg.addColorStop(0,'rgba(255,255,255,0.9)'); pg.addColorStop(1,'rgba(180,190,255,0)');
+ ctx.fillStyle=pg; ctx.beginPath(); ctx.arc(px,py,7,0,Math.PI*2); ctx.fill();
+ }
+
+ // stars
+ for(var i=0;i<stars.length;i++){
+ var s=stars[i];
+ var tw=0.5+0.5*Math.sin(now*0.001*s.sp+s.tw);
+ var a=s.base*(0.6+0.4*tw)+s.lit*0.5;
+ if(s.lit>0) s.lit=Math.max(0,s.lit-0.004*dt);
+ var rr=s.r*(1+s.lit*1.4);
+ if(s.lit>0.02 || s.r>1.4){
+ var sg=ctx.createRadialGradient(s.x,s.y,0,s.x,s.y,rr*4);
+ sg.addColorStop(0,'rgba(255,255,255,'+Math.min(1,a)+')');
+ sg.addColorStop(0.4,'rgba(200,210,255,'+(a*0.35)+')');
+ sg.addColorStop(1,'rgba(200,210,255,0)');
+ ctx.fillStyle=sg; ctx.beginPath(); ctx.arc(s.x,s.y,rr*4,0,Math.PI*2); ctx.fill();
+ }
+ ctx.fillStyle='rgba(255,255,255,'+Math.min(1,a)+')';
+ ctx.beginPath(); ctx.arc(s.x,s.y,rr,0,Math.PI*2); ctx.fill();
+ }
+
+ // the in-progress line from the last anchored star to the finger
+ if(lastStar && drag){
+ ctx.strokeStyle='rgba(170,180,255,0.4)'; ctx.lineWidth=1; ctx.setLineDash([4,4]);
+ ctx.beginPath(); ctx.moveTo(lastStar.x,lastStar.y); ctx.lineTo(fx,fy); ctx.stroke(); ctx.setLineDash([]);
+ }
+
+ // meteors
+ if(now>nextMeteor){ nextMeteor=now+6000+Math.random()*7000; spawnMeteor(); }
+ for(var m=meteors.length-1;m>=0;m--){
+ var me=meteors[m]; me.x+=me.vx*dt; me.y+=me.vy*dt; me.life+=dt;
+ me.trail.push({x:me.x,y:me.y}); if(me.trail.length>14) me.trail.shift();
+ for(var k=0;k<me.trail.length;k++){ var tp=me.trail[k], al=(k/me.trail.length)*0.8*(1-me.life/me.max);
+ ctx.fillStyle='rgba(255,250,230,'+Math.max(0,al)+')'; ctx.beginPath(); ctx.arc(tp.x,tp.y,1.6*(k/me.trail.length)+0.3,0,Math.PI*2); ctx.fill(); }
+ if(me.life>me.max||me.x>W+40||me.y>H+40) meteors.splice(m,1);
+ }
+ }
+
+ var drag=false, fx=0, fy=0;
+ function at(e){ var r=cv.getBoundingClientRect(), t=e.touches?e.touches[0]:e; return {x:t.clientX-r.left,y:t.clientY-r.top}; }
+ wrap.addEventListener('pointerdown',function(e){
+ e.preventDefault(); var p=at(e); fx=p.x; fy=p.y; drag=true;
+ lastStar=nearestStar(p.x,p.y,40) || null;
+ if(lastStar){ lastStar.lit=1; }
+ });
+ wrap.addEventListener('pointermove',function(e){
+ if(!drag) return; e.preventDefault(); var p=at(e); fx=p.x; fy=p.y;
+ var hit=nearestStar(p.x,p.y,26);
+ if(hit && hit!==lastStar){ if(lastStar) connect(lastStar,hit); lastStar=hit; }
+ });
+ function release(){ drag=false; lastStar=null; }
+ wrap.addEventListener('pointerup',release);
+ wrap.addEventListener('pointercancel',release);
+ wrap.addEventListener('pointerleave',release);
+
+ document.getElementById('clear').addEventListener('pointerdown',function(e){
+ e.stopPropagation(); links=[]; pulses=[]; for(var i=0;i<stars.length;i++) stars[i].lit=0;
+ hint.style.opacity='.85';
+ });
+
+ if(LL && LL.onPause){ try{ LL.onPause(function(p){ paused=p; if(!p) T0=performance.now(); }); }catch(e){} }
+ document.addEventListener('visibilitychange',function(){ paused=document.hidden; if(!paused) T0=performance.now(); });
+ window.addEventListener('resize',function(){ size(); });
+ size();
+ T0=performance.now(); nextMeteor=performance.now()+3000; requestAnimationFrame(tick);
+})();
+</script>
← Version history