@haru_calm · 6/9/2026, 8:17:48 PM
Initial version — all lines are new.
+<style>+ html,body{height:100%;margin:0;overflow:hidden;background:#E9DEC6;}+ *{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;display:flex;justify-content:space-between;align-items:flex-start;}+ #head h1{margin:0;font-family:"Instrument Serif",Georgia,"Times New Roman",serif;font-weight:400;font-size:2.35rem;line-height:1;color:#5a4a2f;}+ #head p{margin:.2rem 0 0;font-size:.8rem;color:#9b8a68;font-weight:500;}+ #smooth{position:absolute;bottom:1.1rem;right:1.1rem;z-index:3;pointer-events:auto;border:1px solid rgba(120,100,60,.25);background:rgba(255,255,255,.4);color:#6a5836;border-radius:999px;font-size:.72rem;font-weight:700;padding:.4rem .8rem;cursor:pointer;backdrop-filter:blur(4px);}+ #smooth: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.25rem;color:#a8966f;opacity:.85;transition:opacity .6s;text-align:center;}+</style>+<div id="wrap">+ <canvas id="cv"></canvas>+ <div id="head">+ <div><h1>Sand Garden</h1><p>Drag to rake the sand. Breathe out.</p></div>+ </div>+ <button id="smooth">smooth</button>+ <div id="hint">rake anywhere</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 "shhh" — short filtered noise, like a rake brushing sand+ function grain(){+ if(muted) return; var c=actx(); if(!c) return;+ var dur=0.13, n=Math.floor(c.sampleRate*dur), buf=c.createBuffer(1,n,c.sampleRate), d=buf.getChannelData(0);+ for(var i=0;i<n;i++){ d[i]=(Math.random()*2-1)*Math.pow(1-i/n,1.6); }+ var src=c.createBufferSource(); src.buffer=buf;+ var bp=c.createBiquadFilter(); bp.type='bandpass'; bp.frequency.value=1500+Math.random()*900; bp.Q.value=0.8;+ var g=c.createGain(); g.gain.value=0.11;+ src.connect(bp); bp.connect(g); g.connect(c.destination); src.start();+ }++ 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;+ var TINES=5, GAP=8, last=null, soundT=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);+ GAP=Math.max(6, Math.min(11, W*0.022));+ sand();+ }+ function sand(){+ var g=ctx.createLinearGradient(0,0,0,H);+ g.addColorStop(0,'#F1E8D2'); g.addColorStop(1,'#E3D5B6');+ ctx.fillStyle=g; ctx.fillRect(0,0,W,H);+ // faint grain speckle+ ctx.globalAlpha=0.05;+ for(var i=0;i<W*H/900;i++){ ctx.fillStyle=Math.random()<0.5?'#c9b88f':'#fff7e6'; ctx.fillRect(Math.random()*W,Math.random()*H,1,1); }+ ctx.globalAlpha=1;+ // soft inner frame (the tray edge)+ ctx.strokeStyle='rgba(150,125,80,.22)'; ctx.lineWidth=2;+ ctx.strokeRect(7,7,W-14,H-14);+ }++ function rakeSeg(ax,ay,bx,by){+ var dx=bx-ax, dy=by-ay, len=Math.hypot(dx,dy)||1;+ var px=-dy/len, py=dx/len; // perpendicular+ for(var k=0;k<TINES;k++){+ var off=(k-(TINES-1)/2)*GAP;+ var x1=ax+px*off, y1=ay+py*off, x2=bx+px*off, y2=by+py*off;+ // shadow groove+ ctx.strokeStyle='rgba(120,98,58,0.5)'; ctx.lineWidth=2.4; ctx.lineCap='round';+ ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke();+ // highlight ridge just beside it+ ctx.strokeStyle='rgba(255,248,228,0.55)'; ctx.lineWidth=1.3;+ ctx.beginPath(); ctx.moveTo(x1+px*1.6,y1+py*1.6); ctx.lineTo(x2+px*1.6,y2+py*1.6); ctx.stroke();+ }+ }++ 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}; }+ function move(e){+ e.preventDefault(); var p=at(e);+ if(last){ rakeSeg(last.x,last.y,p.x,p.y);+ var now=performance.now(); if(now-soundT>85){ soundT=now; grain(); }+ }+ last=p;+ if(hint.style.opacity!=='0') hint.style.opacity='0';+ }+ wrap.addEventListener('pointerdown',function(e){ last=at(e); });+ wrap.addEventListener('pointermove',function(e){ if(e.buttons||e.pressure>0||(e.touches&&e.touches.length)) move(e); });+ wrap.addEventListener('pointerup',function(){ last=null; });+ wrap.addEventListener('pointerleave',function(){ last=null; });+ document.getElementById('smooth').addEventListener('pointerdown',function(e){ e.stopPropagation(); sand(); hint.style.opacity='.85'; });++ window.addEventListener('resize',size);+ size();+ // a few starter ripples so it reads as a garden+ (function(){+ var cy=H*0.6;+ for(var r=40;r<Math.min(W,H)*0.5;r+=GAP){+ var pts=24, prev=null;+ for(var a=0;a<=pts;a++){ var ang=(a/pts)*Math.PI*2; var x=W*0.5+Math.cos(ang)*r, y=cy+Math.sin(ang)*r*0.62;+ if(prev){ ctx.strokeStyle='rgba(120,98,58,0.32)'; ctx.lineWidth=2; ctx.beginPath(); ctx.moveTo(prev.x,prev.y); ctx.lineTo(x,y); ctx.stroke();+ ctx.strokeStyle='rgba(255,248,228,0.4)'; ctx.lineWidth=1; ctx.beginPath(); ctx.moveTo(prev.x,prev.y-1.6); ctx.lineTo(x,y-1.6); ctx.stroke(); }+ prev={x:x,y:y};+ }+ }+ })();+ hint.style.opacity='.85';+})();+</script>