import React, { useEffect, useRef } from "react"; import { TRUNK_TOP_CSS } from "./Tree"; interface Leaf { x: number; y: number; size: number; speed: number; drift: number; rotation: number; rotationSpeed: number; opacity: number; sway: number; swaySpeed: number; phase: number; } export default function FallingLeaves({ treeRef }: { treeRef: React.RefObject }) { const canvasRef = useRef(null); useEffect(() => { const canvas = canvasRef.current!; const ctx = canvas.getContext("2d")!; let animId: number; const leaves: Leaf[] = []; const MAX_LEAVES = 50; function resize() { const parent = canvas.parentElement; const rect = parent?.getBoundingClientRect(); canvas.width = Math.max(1, Math.round(rect?.width || window.innerWidth)); canvas.height = Math.max(1, Math.round(rect?.height || window.innerHeight)); } resize(); window.addEventListener("resize", resize); function spawnLeaf(): Leaf { const treeRect = treeRef.current?.getBoundingClientRect(); const canvasRect = canvas.getBoundingClientRect(); const spawnY = treeRect ? treeRect.top - canvasRect.top + TRUNK_TOP_CSS : canvas.height * 0.4; const spawnX = treeRect ? treeRect.left - canvasRect.left + Math.random() * treeRect.width * 0.8 + treeRect.width * 0.1 : Math.random() * canvas.width * 0.6 + canvas.width * 0.2; return { x: spawnX, y: spawnY, size: Math.random() * 4 + 2, speed: Math.random() * 0.3 + 0.15, drift: Math.random() * 0.5 - 0.25, rotation: Math.random() * Math.PI * 2, rotationSpeed: (Math.random() - 0.5) * 0.02, opacity: Math.random() * 0.25 + 0.08, sway: Math.random() * 30 + 15, swaySpeed: Math.random() * 0.008 + 0.003, phase: Math.random() * Math.PI * 2, }; } let spawnTimer = 0; function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); spawnTimer++; if (spawnTimer > 30 && leaves.length < MAX_LEAVES) { leaves.push(spawnLeaf()); spawnTimer = 0; } for (let i = leaves.length - 1; i >= 0; i--) { const l = leaves[i]; l.y += l.speed; l.x += l.drift + Math.sin(l.phase) * l.swaySpeed * l.sway * 0.05; l.phase += l.swaySpeed; l.rotation += l.rotationSpeed; ctx.save(); ctx.translate(l.x, l.y); ctx.rotate(l.rotation); ctx.globalAlpha = l.opacity; ctx.fillStyle = "#fdb068"; const s = Math.round(l.size); ctx.fillRect(-s / 2, -s / 2, s, s); ctx.restore(); if (l.y > canvas.height + 10) { leaves.splice(i, 1); } } animId = requestAnimationFrame(draw); } draw(); return () => { cancelAnimationFrame(animId); window.removeEventListener("resize", resize); }; }, []); return ; }