89 lines
2 KiB
TypeScript
89 lines
2 KiB
TypeScript
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();
|