Spaces:
Sleeping
Sleeping
| // Animated dumbbell particles on a Canvas background | |
| (() => { | |
| const canvas = document.getElementById('bg-canvas'); | |
| const ctx = canvas.getContext('2d', { alpha: true }); | |
| function resize() { | |
| const dpr = window.devicePixelRatio || 1; | |
| canvas.width = Math.floor(innerWidth * dpr); | |
| canvas.height = Math.floor(innerHeight * dpr); | |
| ctx.setTransform(dpr, 0, 0, dpr, 0, 0); | |
| } | |
| window.addEventListener('resize', resize); | |
| resize(); | |
| // Create particles shaped like tiny dumbbells | |
| const NUM = Math.min(70, Math.floor((innerWidth * innerHeight) / 22000)); | |
| const particles = Array.from({ length: NUM }, () => spawn()); | |
| function spawn() { | |
| const s = 0.5 + Math.random() * 1.2; // scale | |
| return { | |
| x: Math.random() * innerWidth, | |
| y: Math.random() * innerHeight, | |
| vx: -0.4 + Math.random() * 0.8, | |
| vy: -0.4 + Math.random() * 0.8, | |
| rot: Math.random() * Math.PI * 2, | |
| vr: (-0.004 + Math.random() * 0.008), | |
| s, | |
| alpha: 0.15 + Math.random() * 0.35 | |
| }; | |
| } | |
| function drawDumbbell(x, y, scale, rot, alpha) { | |
| ctx.save(); | |
| ctx.translate(x, y); | |
| ctx.rotate(rot); | |
| ctx.scale(scale, scale); | |
| ctx.globalAlpha = alpha; | |
| // bar | |
| ctx.lineWidth = 2; | |
| ctx.strokeStyle = 'rgba(255,255,255,0.35)'; | |
| ctx.beginPath(); | |
| ctx.moveTo(-16, 0); | |
| ctx.lineTo(16, 0); | |
| ctx.stroke(); | |
| // plates | |
| ctx.fillStyle = 'rgba(255,255,255,0.25)'; | |
| ctx.beginPath(); ctx.arc(-18, 0, 4, 0, Math.PI*2); ctx.fill(); | |
| ctx.beginPath(); ctx.arc(18, 0, 4, 0, Math.PI*2); ctx.fill(); | |
| ctx.restore(); | |
| } | |
| function tick() { | |
| ctx.clearRect(0, 0, innerWidth, innerHeight); | |
| for (const p of particles) { | |
| p.x += p.vx; p.y += p.vy; p.rot += p.vr; | |
| // wrap-around | |
| if (p.x < -30) p.x = innerWidth + 30; | |
| if (p.x > innerWidth + 30) p.x = -30; | |
| if (p.y < -30) p.y = innerHeight + 30; | |
| if (p.y > innerHeight + 30) p.y = -30; | |
| drawDumbbell(p.x, p.y, p.s, p.rot, p.alpha); | |
| } | |
| requestAnimationFrame(tick); | |
| } | |
| requestAnimationFrame(tick); | |
| })(); |