// === SuperSunday moving bubbles (canvas) — robust autoload === (function(){ function ensureCanvas(){ let layer = document.getElementById('bubble-layer'); if (!layer) { layer = document.createElement('canvas'); layer.id = 'bubble-layer'; document.body.appendChild(layer); } return layer; } const c = ensureCanvas(); const ctx = c.getContext('2d', { alpha: true }); function resize(){ c.width = window.innerWidth; c.height = window.innerHeight; } resize(); window.addEventListener('resize', resize); const COLORS = [ {from:'#1f2a6d', to:'#5b39a8'}, {from:'#1a255d', to:'#3e2a7a'}, {from:'#233278', to:'#7a42c4'}, ]; const BUBBLES = []; const N = Math.min(24, Math.max(12, Math.floor((window.innerWidth*window.innerHeight)/120000))); function rand(a,b){ return a + Math.random()*(b-a); } function makeBubble(){ const r = rand(30, 120); const x = rand(-0.1*c.width, 1.1*c.width); const y = rand(-0.1*c.height, 1.1*c.height); const vy = rand(0.05, 0.2) * (Math.random()<0.5? 1 : -1); const vx = rand(-0.08, 0.08); const col = COLORS[Math.floor(Math.random()*COLORS.length)]; const opacity = rand(0.08, 0.22); return {x,y,r,vx,vy,col,opacity, phase: rand(0, Math.PI*2)}; } for(let i=0;i c.width+200 || b.y < -200 || b.y > c.height+200) { const idx = BUBBLES.indexOf(b); BUBBLES[idx] = makeBubble(); continue; } const g = ctx.createRadialGradient(b.x, b.y, b.r*0.1, b.x, b.y, b.r); g.addColorStop(0, hexA(b.col.to, b.opacity*1.0)); g.addColorStop(1, hexA(b.col.from, 0)); ctx.fillStyle = g; ctx.beginPath(); ctx.arc(b.x, b.y, b.r, 0, Math.PI*2); ctx.fill(); } requestAnimationFrame(tick); } function hexA(hex, a){ const h = hex.replace('#',''); const r = parseInt(h.substring(0,2),16); const g = parseInt(h.substring(2,4),16); const b = parseInt(h.substring(4,6),16); return `rgba(${r},${g},${b},${a})`; } requestAnimationFrame(tick); })();