"use client"; import { useEffect, useRef } from "react"; const MAX_PARTICLES = 48; type Particle = { x: number; y: number; vy: number; vx: number; size: number; alpha: number; }; type Props = { active: boolean; className?: string; }; export function HeroRiftParticles({ active, className }: Props) { const canvasRef = useRef(null); useEffect(() => { if (!active) return; const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext("2d"); if (!ctx) return; let raf = 0; let particles: Particle[] = []; const resize = () => { const parent = canvas.parentElement; if (!parent) return; const dpr = Math.min(window.devicePixelRatio ?? 1, 2); const w = parent.clientWidth; const h = parent.clientHeight; canvas.width = w * dpr; canvas.height = h * dpr; canvas.style.width = `${w}px`; canvas.style.height = `${h}px`; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); const count = Math.min(MAX_PARTICLES, Math.floor((w * h) / 12000)); particles = Array.from({ length: count }, () => ({ x: w * (0.35 + Math.random() * 0.3), y: h * (0.45 + Math.random() * 0.35), vy: -0.15 - Math.random() * 0.35, vx: (Math.random() - 0.5) * 0.2, size: 0.6 + Math.random() * 1.4, alpha: 0.15 + Math.random() * 0.35, })); }; const tick = () => { const w = canvas.clientWidth; const h = canvas.clientHeight; ctx.clearRect(0, 0, w, h); for (const p of particles) { p.x += p.vx; p.y += p.vy; if (p.y < h * 0.25) { p.y = h * (0.55 + Math.random() * 0.3); p.x = w * (0.35 + Math.random() * 0.3); } ctx.beginPath(); ctx.fillStyle = `rgba(255, 191, 80, ${p.alpha})`; ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2); ctx.fill(); } raf = requestAnimationFrame(tick); }; resize(); window.addEventListener("resize", resize); raf = requestAnimationFrame(tick); return () => { cancelAnimationFrame(raf); window.removeEventListener("resize", resize); }; }, [active]); if (!active) return null; return ( ); }