datumwell / common.js
windjj's picture
Publish Datumwell EmbodiedTrace project and launch article
3f541b7 verified
Raw History Blame Contribute Delete
2.17 kB
'use strict';
const themeButton = document.querySelector('[data-theme-toggle]');
let theme = 'light';
try { if(localStorage.getItem('datumwell.theme') === 'dark') theme = 'dark'; } catch {}
function applyTheme() {
document.documentElement.dataset.theme=theme;
if(themeButton){themeButton.setAttribute('aria-label',`Switch to ${theme==='light'?'dark':'light'} theme`);themeButton.innerHTML=theme==='light'?'◐':'◑';}
}
applyTheme();
themeButton?.addEventListener('click',()=>{theme=theme==='light'?'dark':'light';applyTheme();try{localStorage.setItem('datumwell.theme',theme);}catch{}});
const background = document.createElement('canvas');
background.className='observation-field';background.setAttribute('aria-hidden','true');
document.body.prepend(background);
const context = background.getContext('2d');
const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)');
let width=0,height=0,points=[],frame,lastTime=0;
function resizeField(){
width=innerWidth;height=innerHeight;
const ratio=Math.min(devicePixelRatio||1,2);background.width=width*ratio;background.height=height*ratio;
context?.setTransform(ratio,0,0,ratio,0,0);
points=Array.from({length:Math.min(200,Math.floor(width*height/4800))},(_,i)=>({x:((i*0.61803398875)%1)*width,y:((i*0.754877666)%1)*height,size:2+i%3,phase:i*1.3}));
drawField(0);
}
function drawField(time){
if(!context)return;
context.clearRect(0,0,width,height);
context.fillStyle=theme==='dark'?'rgba(164,188,174,.11)':'rgba(110,133,119,.14)';
for(const p of points){const drift=reduceMotion.matches?0:Math.sin(time/11000+p.phase)*8;context.fillRect(p.x+drift,p.y+drift*.6,p.size,p.size);}
}
function animateField(time){
if(time-lastTime>65){drawField(time);lastTime=time;}
frame=requestAnimationFrame(animateField);
}
function startField(){cancelAnimationFrame(frame);drawField(0);if(!reduceMotion.matches&&!document.hidden)frame=requestAnimationFrame(animateField);}
resizeField();startField();
addEventListener('resize',resizeField);
reduceMotion.addEventListener('change',startField);
document.addEventListener('visibilitychange',startField);
themeButton?.addEventListener('click',()=>drawField(0));