@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>