Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

boot: swap spring rainbows for falling water drops + splash ripples

Replaces the procedural turtle-graphics rainbow scene in the default
spring boot animation with a rainy blue-grey sky: 60 drops falling with
slight sway, each splashing into a ripple at a puddle line ~88% down.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

+57 -63
+57 -63
system/netlify/functions/index.mjs
··· 1302 1302 var isNotepat=location.hostname==='notepat.com'||location.hostname==='www.notepat.com'||location.pathname==='/notepat'||location.pathname.startsWith('/notepat?')||location.pathname.startsWith('/notepat/'); 1303 1303 // Notebook: Python/Jupyter notebook with scientific aesthetic 1304 1304 var isNotebook=qs.indexOf('notebook=true')>=0; 1305 - // Boot animation mode: 'spring' (turtle-graphics rainbows, default), 'serious' (clean/refined), or 'aesthetic' (VHS/glitch) 1305 + // Boot animation mode: 'spring' (falling water drops with splash ripples, default), 'serious' (clean/refined), or 'aesthetic' (VHS/glitch) 1306 1306 var bootTheme=params.get('boot')||'spring';var isSerious=bootTheme==='serious';var isSpring=bootTheme==='spring'; 1307 1307 // Density param for scaling (default 1, FF1 uses 8 for 4K) 1308 1308 var densityMatch=qs.match(/density=(\d+)/);var densityParam=densityMatch?parseInt(densityMatch[1]):1; ··· 1371 1371 var NP_KEYS=[];var NP_PARTICLES=[];var NP_LAST_KEY=0;var NP_KEY_INTERVAL=120; 1372 1372 var NP_NOTE_NAMES=['C','D','E','F','G','A','B']; 1373 1373 var NP_KEY_COLS=[[255,107,157],[78,205,196],[255,217,61],[149,225,211],[255,154,162],[170,150,218],[112,214,255],[255,183,77]]; 1374 - // 🌈 Spring boot animation state — procedural turtle-graphics rainbows 1375 - var SPRING_RAINBOWS=[],SPRING_INIT=false; 1374 + // 🌧️ Spring boot animation state — falling water drops with splash ripples 1375 + var SPRING_DROPS=[],SPRING_RIPPLES=[],SPRING_INIT=false; 1376 1376 var SPRING_FONTS_LIGHT=['serif','monospace','YWFTProcessing-Bold, monospace','cursive','Georgia, serif','Courier New, monospace']; 1377 - // ROYGBIV hues (red, orange, yellow, green, blue, indigo, violet) 1378 - var SPRING_RAINBOW_HUES=[0,28,54,120,210,255,290]; 1379 - function springInit(S){SPRING_RAINBOWS=[];var n=7;for(var i=0;i<n;i++){SPRING_RAINBOWS.push({px:Math.random(),py:0.28+Math.random()*0.55,r:(22+Math.random()*34)*S,phase:Math.random()*Math.PI*2,bob:0.6+Math.random()*1.3,tilt:(Math.random()-0.5)*0.28,vx:(0.0009+Math.random()*0.0019)*(Math.random()>0.5?1:-1),twinkle:Math.random()*Math.PI*2,puffHue:40+Math.random()*30});}SPRING_INIT=true;} 1380 - function drawRainbow(ctx,W,H,b,t,S,isLightMode){ 1381 - // Drift horizontally, wrap around edges 1382 - b.px+=b.vx;if(b.px>1.2)b.px=-0.2;if(b.px<-0.2)b.px=1.2; 1383 - var cx=b.px*W,cy=b.py*H+Math.sin(t*0.9+b.phase)*b.bob*2.5*S,r=b.r; 1384 - var tilt=b.tilt+Math.sin(t*0.45+b.phase)*0.07; 1385 - ctx.save();ctx.translate(cx,cy);ctx.rotate(tilt); 1386 - var bandW=Math.max(1.4,r*0.095); 1387 - ctx.lineCap='round'; 1388 - // Soft halo behind the bow 1389 - ctx.beginPath();ctx.arc(0,0,r+bandW*0.3,Math.PI,Math.PI*2); 1390 - ctx.lineWidth=bandW*1.6; 1391 - ctx.strokeStyle=isLightMode?'rgba(255,250,210,0.55)':'rgba(255,240,180,0.22)'; 1392 - ctx.stroke(); 1393 - // ROYGBIV arcs from outermost to innermost (turtle-style concentric strokes) 1394 - for(var bi=0;bi<SPRING_RAINBOW_HUES.length;bi++){ 1395 - var hue=SPRING_RAINBOW_HUES[bi];var bandR=r-bi*bandW;if(bandR<bandW)break; 1396 - ctx.beginPath();ctx.arc(0,0,bandR,Math.PI,Math.PI*2); 1397 - ctx.lineWidth=bandW*0.92; 1398 - ctx.strokeStyle='hsla('+hue+',88%,'+(isLightMode?52:62)+'%,0.85)'; 1399 - ctx.stroke(); 1400 - } 1401 - // Little cloud puffs at each foot 1402 - var puffY=bandW*0.2,puffR=bandW*1.9; 1403 - for(var side=-1;side<=1;side+=2){ 1404 - var fx=side*(r-bandW*3.5); 1405 - ctx.beginPath();ctx.arc(fx,puffY,puffR,0,Math.PI*2); 1406 - ctx.fillStyle=isLightMode?'hsla('+b.puffHue+',60%,92%,0.9)':'hsla('+b.puffHue+',40%,82%,0.55)'; 1407 - ctx.fill(); 1408 - ctx.beginPath();ctx.arc(fx+side*puffR*0.7,puffY-puffR*0.45,puffR*0.75,0,Math.PI*2); 1409 - ctx.fillStyle=isLightMode?'hsla('+b.puffHue+',55%,95%,0.85)':'hsla('+b.puffHue+',35%,78%,0.45)'; 1410 - ctx.fill(); 1411 - ctx.beginPath();ctx.arc(fx-side*puffR*0.55,puffY-puffR*0.25,puffR*0.6,0,Math.PI*2); 1412 - ctx.fillStyle=isLightMode?'hsla('+b.puffHue+',55%,94%,0.75)':'hsla('+b.puffHue+',35%,75%,0.4)'; 1413 - ctx.fill(); 1377 + // Water hues — cyan through royal blue 1378 + var SPRING_DROP_HUES=[188,198,205,212,220,230]; 1379 + function springInit(S){SPRING_DROPS=[];SPRING_RIPPLES=[];var n=60;for(var i=0;i<n;i++){SPRING_DROPS.push({x:Math.random(),y:Math.random()*-1,vy:0.007+Math.random()*0.013,len:(5+Math.random()*10)*S,w:Math.max(0.8,(0.6+Math.random()*0.9)*S),hue:SPRING_DROP_HUES[Math.floor(Math.random()*SPRING_DROP_HUES.length)],bright:60+Math.random()*20,sway:(Math.random()-0.5)*0.0008,phase:Math.random()*Math.PI*2});}SPRING_INIT=true;} 1380 + function drawDrop(ctx,W,H,d,t,S,isLightMode,puddleY){ 1381 + // Fall with slight horizontal sway 1382 + d.x+=d.sway+Math.sin(t*0.7+d.phase)*0.00015; 1383 + d.y+=d.vy; 1384 + if(d.x>1.05)d.x-=1.1;if(d.x<-0.05)d.x+=1.1; 1385 + var cx=d.x*W,cy=d.y*H; 1386 + if(cy>puddleY){ 1387 + // Splash — spawn a ripple and recycle drop to the top 1388 + if(SPRING_RIPPLES.length<50)SPRING_RIPPLES.push({x:cx,y:puddleY+(Math.random()*3-1)*S,r:0,maxR:(6+Math.random()*10)*S,a:0.7+Math.random()*0.2,hue:d.hue,bright:d.bright}); 1389 + d.y=-0.05-Math.random()*0.2;d.x=Math.random(); 1390 + return; 1414 1391 } 1415 - // Twinkle sparkle at the crown 1416 - var twA=0.45+Math.sin(t*3+b.twinkle)*0.45; 1417 - ctx.globalAlpha=Math.max(0,twA); 1418 - ctx.fillStyle=isLightMode?'#fff4b0':'#fffce0'; 1419 - ctx.beginPath();ctx.arc(0,-r+bandW*0.5,Math.max(1,1.5*S),0,Math.PI*2);ctx.fill(); 1420 - // Tiny cross-sparkle rays 1421 - ctx.strokeStyle=ctx.fillStyle;ctx.lineWidth=Math.max(0.5,0.6*S); 1422 - var rays=Math.max(2.5,2.2*S); 1423 - ctx.beginPath();ctx.moveTo(-rays,-r+bandW*0.5);ctx.lineTo(rays,-r+bandW*0.5); 1424 - ctx.moveTo(0,-r+bandW*0.5-rays);ctx.lineTo(0,-r+bandW*0.5+rays);ctx.stroke(); 1425 - ctx.globalAlpha=1; 1426 - ctx.restore();} 1392 + // Streak — transparent tail fading into bright head 1393 + var tailY=cy-d.len; 1394 + var grad=ctx.createLinearGradient(cx,tailY,cx,cy); 1395 + grad.addColorStop(0,'hsla('+d.hue+',70%,'+d.bright+'%,0)'); 1396 + grad.addColorStop(1,'hsla('+d.hue+',85%,'+(d.bright+8)+'%,'+(isLightMode?0.6:0.75)+')'); 1397 + ctx.strokeStyle=grad;ctx.lineWidth=d.w;ctx.lineCap='round'; 1398 + ctx.beginPath();ctx.moveTo(cx,tailY);ctx.lineTo(cx,cy);ctx.stroke(); 1399 + // Droplet head bead 1400 + ctx.beginPath();ctx.arc(cx,cy,d.w*1.1,0,Math.PI*2); 1401 + ctx.fillStyle='hsla('+d.hue+',85%,'+(d.bright+15)+'%,'+(isLightMode?0.75:0.9)+')'; 1402 + ctx.fill(); 1403 + } 1404 + function drawRipple(ctx,r,S,isLightMode){ 1405 + r.r+=(0.6+r.maxR*0.04)*S;r.a*=0.94; 1406 + if(r.r>r.maxR||r.a<0.02)return false; 1407 + ctx.beginPath();ctx.arc(r.x,r.y,r.r,0,Math.PI*2); 1408 + ctx.lineWidth=Math.max(0.6,0.8*S); 1409 + ctx.strokeStyle='hsla('+r.hue+',75%,'+(r.bright+10)+'%,'+(r.a*(isLightMode?0.65:0.85))+')'; 1410 + ctx.stroke(); 1411 + // Inner shimmer ring 1412 + if(r.r>S*2){ctx.beginPath();ctx.arc(r.x,r.y,r.r*0.55,0,Math.PI*2); 1413 + ctx.strokeStyle='hsla('+r.hue+',60%,'+(r.bright+20)+'%,'+(r.a*0.4)+')'; 1414 + ctx.lineWidth=Math.max(0.4,0.5*S);ctx.stroke();} 1415 + return true; 1416 + } 1427 1417 // 📊 Notebook scientific aesthetic boot animation state 1428 1418 var NB_DATA_POINTS=[];var NB_GRID_LINES=[];var NB_WAVEFORMS=[];var NB_LAST_SPAWN=0; 1429 1419 var NB_COLS_DARK=[[0,180,255],[0,255,180],[120,220,255],[80,200,120],[100,255,255]]; ··· 1575 1565 var logFS=densityParam===1&&isDeviceMode?Math.max(14,Math.floor(H/60)):4*S*dS; 1576 1566 x.font=logFS+'px monospace';var logY=(densityParam===1&&isDeviceMode?Math.floor(H/20):16*S*dS)+embedPad;var logSpacing=densityParam===1&&isDeviceMode?Math.floor(logFS*1.5):7*S*dS;for(var li=0;li<lines.length&&li<10;li++){var ln=lines[li],ly=logY+li*logSpacing,la=Math.max(0.3,1-li*0.08),lc=klCols[li%klCols.length];var tw=x.measureText(ln.text).width;var logX=densityParam===1&&isDeviceMode?20:10*S*dS;var textX=densityParam===1&&isDeviceMode?30:(logX+3*S*dS);var pillH=densityParam===1&&isDeviceMode?Math.floor(logFS*1.2):6*S*dS;var pillR=densityParam===1&&isDeviceMode?6:3*S*dS;var pillW=tw+(textX-logX)*2;x.globalAlpha=la*0.15;x.fillStyle='rgb('+lc[0]+','+lc[1]+','+lc[2]+')';x.beginPath();x.roundRect(logX,ly-pillH*0.65,pillW,pillH,pillR);x.fill();x.globalAlpha=la;x.fillStyle='rgb('+lc[0]+','+lc[1]+','+lc[2]+')';x.fillText(ln.text,textX,ly);} 1577 1567 x.globalAlpha=1;requestAnimationFrame(anim);return;} 1578 - // 🌈 Spring mode — yellowish, light, with procedural turtle-graphics rainbows (default) 1568 + // 🌧️ Spring mode — rainy blue-grey sky with falling water drops + splash ripples (default) 1579 1569 if(isSpring){ 1580 1570 if(!SPRING_INIT)springInit(S); 1581 - // Soft sunny gradient bg (cream/butter for light, deep amber for dark) 1571 + // Soft rainy gradient bg (washed blue-grey for light, deep stormy navy for dark) 1582 1572 var sgrad=x.createLinearGradient(0,0,0,H); 1583 - if(isLightMode){sgrad.addColorStop(0,'#fffbe2');sgrad.addColorStop(0.6,'#fff4c2');sgrad.addColorStop(1,'#ffe89a');} 1584 - else{sgrad.addColorStop(0,'#3a2f10');sgrad.addColorStop(0.6,'#2a2410');sgrad.addColorStop(1,'#1f1a08');} 1573 + if(isLightMode){sgrad.addColorStop(0,'#d8e4ef');sgrad.addColorStop(0.5,'#c4d4e4');sgrad.addColorStop(1,'#b0c4d8');} 1574 + else{sgrad.addColorStop(0,'#0e1828');sgrad.addColorStop(0.5,'#132236');sgrad.addColorStop(1,'#0a1420');} 1585 1575 x.fillStyle=sgrad;x.fillRect(0,0,W,H); 1586 - // Wandering pollen specks 1587 - for(var sp=0;sp<22;sp++){var spx=((Math.sin(t*0.3+sp*1.7)+1)*0.5*W+sp*23)%W;var spy=((Math.cos(t*0.2+sp*1.1)+1)*0.5*H+sp*17)%H;var spr=Math.max(0.5,(0.6+Math.sin(t+sp)*0.4)*S);x.globalAlpha=0.35+Math.sin(t*1.4+sp)*0.25;x.fillStyle=isLightMode?'rgba(255,200,80,0.7)':'rgba(255,230,140,0.7)';x.beginPath();x.arc(spx,spy,spr,0,Math.PI*2);x.fill();} 1576 + // Drifting mist specks 1577 + for(var sp=0;sp<22;sp++){var spx=((Math.sin(t*0.25+sp*1.7)+1)*0.5*W+sp*23)%W;var spy=((Math.cos(t*0.18+sp*1.1)+1)*0.5*H+sp*17+f*0.3)%H;var spr=Math.max(0.5,(0.5+Math.sin(t+sp)*0.35)*S);x.globalAlpha=0.22+Math.sin(t*1.2+sp)*0.18;x.fillStyle=isLightMode?'rgba(180,210,230,0.7)':'rgba(160,200,230,0.5)';x.beginPath();x.arc(spx,spy,spr,0,Math.PI*2);x.fill();} 1588 1578 x.globalAlpha=1; 1589 - // Sunbeam streaks from top-right 1590 - for(var br=0;br<5;br++){x.save();x.globalAlpha=0.06+Math.sin(t*0.5+br)*0.03;x.fillStyle=isLightMode?'#fff7c0':'#ffeeaa';x.translate(W*0.85,0);x.rotate(0.6+br*0.08);x.fillRect(-2*S,0,4*S,H*1.4);x.restore();} 1591 - // Draw all rainbows (sorted by y for fake depth — farther ones higher up) 1592 - var sortedBd=SPRING_RAINBOWS.slice().sort(function(a,b){return a.py-b.py;}); 1593 - for(var fi=0;fi<sortedBd.length;fi++){drawRainbow(x,W,H,sortedBd[fi],t,S,isLightMode);} 1579 + // Diagonal rain sheet streaks (translucent) 1580 + for(var br=0;br<5;br++){x.save();x.globalAlpha=0.05+Math.sin(t*0.4+br)*0.02;x.fillStyle=isLightMode?'#e8eff5':'#4a6280';x.translate(W*(0.15+br*0.18),0);x.rotate(0.22+br*0.02);x.fillRect(-3*S,0,6*S,H*1.4);x.restore();} 1581 + // Puddle line near bottom — where drops splash into ripples 1582 + var puddleY=H*0.88; 1583 + x.globalAlpha=isLightMode?0.22:0.18;x.fillStyle=isLightMode?'#9cb8d0':'#1a2c44';x.fillRect(0,puddleY,W,H-puddleY);x.globalAlpha=1; 1584 + // Update + draw all drops (may spawn ripples + recycle themselves) 1585 + for(var fi=0;fi<SPRING_DROPS.length;fi++){drawDrop(x,W,H,SPRING_DROPS[fi],t,S,isLightMode,puddleY);} 1586 + // Update + draw ripples, cull dead ones 1587 + for(var ri=SPRING_RIPPLES.length-1;ri>=0;ri--){if(!drawRipple(x,SPRING_RIPPLES[ri],S,isLightMode))SPRING_RIPPLES.splice(ri,1);} 1594 1588 // Logo top-left (small, soft) 1595 1589 var lS=21*S,lX=5*S,lY=5*S;var logoImg=imgFullLoaded?imgFull:img; 1596 1590 x.imageSmoothingEnabled=imgFullLoaded;x.globalAlpha=0.92;x.drawImage(logoImg,lX,lY,lS,lS);x.globalAlpha=1;