alpha: Math.random()*0.9 + 0.1, twinkle: Math.random()*1.6 + 0.2, vx: (Math.random()-0.5)*0.02, vy: (Math.random()-0.5)*0.02 }; stars.push(s); } // add a few big stars for(let i=0;i<12;i++){ stars.push({x:Math.random()*innerWidth,y:Math.random()*innerHeight,r:Math.random()*3+1,alpha:0.95,twinkle:Math.random()*0.5+0.5,vx:0,vy:0}); } } function drawStar(s,t){ const tw = Math.sin(t * s.twinkle) * 0.4 + 0.6; ctx.beginPath(); ctx.globalAlpha = s.alpha * tw; ctx.fillStyle = `rgba(255,255,255,1)`; ctx.arc(s.x, s.y, s.r * tw, 0, Math.PI*2); ctx.fill(); ctx.closePath(); // cyan halo for some if(Math.random() < 0.018){ ctx.beginPath(); ctx.globalAlpha = 0.08 * tw; ctx.fillStyle = 'rgba(127,232,255,1)'; ctx.arc(s.x, s.y, s.r*6*tw, 0, Math.PI*2); ctx.fill();ctx.closePath(); } } let t0 = 0; function loop(ts){ const t = ts/1000; const dt = t - t0; t0 = t; ctx.clearRect(0,0,innerWidth,innerHeight); // parallax subtle movement const cx = innerWidth/2, cy = innerHeight/2; for(let s of stars){ s.x += s.vx * (0.3 + Math.sin(t*0.2)*0.3); s.y += s.vy * (0.3 + Math.cos(t*0.2)*0.3); if(s.x < -10) s.x = innerWidth + 10; if(s.x > innerWidth + 10) s.x = -10; if(s.y < -10) s.y = innerHeight + 10; if(s.y > innerHeight + 10) s.y = -10; drawStar(s,t); } // slow sweep of aurora line ctx.save(); const grd = ctx.createLinearGradient(0, innerHeight*0.15, innerWidth, innerHeight*0.85); grd.addColorStop(0, 'rgba(120,30,220,0.03)'); grd.addColorStop(0.5, 'rgba(127,232,255,0.02)'); grd.addColorStop(1, 'rgba(139,75,255,0.02)'); ctx.fillStyle = grd; ctx.globalCompositeOperation = 'lighter'; ctx.fillRect(0, innerHeight*0.12, innerWidth, innerHeight*0.76); ctx.restore(); requestAnimationFrame(loop); } // small touch: gently animate the site logo glow intensity (function animateLogo(){ const mark = document.querySelector('.logo-mark'); if(!mark) return; let r = 0; function tick(){ r += 0.02; const s = 1 + Math.sin(r)*0.03; mark.style.transform = `scale(${s})`; requestAnimationFrame(tick); } tick(); })(); // init setup();