interface Snowflake { x: number; y: number; size: number; opacity: number; speedY: number; speedX: number; } function createSnowfall() { const canvas = document.createElement("canvas"); const ctx = canvas.getContext("2d")!; document.body.style.margin = "0"; document.body.style.overflow = "hidden"; canvas.style.position = "fixed"; canvas.style.top = "0"; canvas.style.left = "0"; canvas.style.zIndex = "-1"; document.body.appendChild(canvas); const resizeCanvas = () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }; resizeCanvas(); window.addEventListener("resize", resizeCanvas); const NUM_SNOWFLAKES = 320; const snowflakes: Snowflake[] = []; let windStrength = 0; for (let i = 0; i < NUM_SNOWFLAKES; i++) { snowflakes.push(createSnowflake()); } function createSnowflake(): Snowflake { const size = Math.random() * 3 + 1; return { x: Math.random() * canvas.width, y: Math.random() * canvas.height, size, opacity: Math.random() * 0.2 + 0.2, speedY: Math.random() * size * 0.6 + 0.4, speedX: Math.random() * 0.5 - 0.25, }; } function updateWind() { windStrength += (Math.random() - 0.5) * 0.01; windStrength = Math.max(-0.5, Math.min(0.5, windStrength)); } function updateSnowflakes() { ctx.clearRect(0, 0, canvas.width, canvas.height); updateWind(); for (const flake of snowflakes) { flake.x += flake.speedX + windStrength; flake.y += flake.speedY; if (flake.y > canvas.height) { flake.y = -flake.size; flake.x = Math.random() * canvas.width; flake.speedY = Math.random() * flake.size * 0.5 + 0.5; flake.speedX = Math.random() * 0.5 - 0.25; } if (flake.x < -flake.size) { flake.x = canvas.width + flake.size; } else if (flake.x > canvas.width + flake.size) { flake.x = -flake.size; } ctx.beginPath(); ctx.arc(flake.x, flake.y, flake.size, 0, Math.PI * 2); ctx.fillStyle = `rgba(255, 255, 255, ${flake.opacity})`; ctx.fill(); } requestAnimationFrame(updateSnowflakes); } updateSnowflakes(); } createSnowfall();