"use client"; import { useEffect, useRef } from "react"; interface Orb { x: number; y: number; size: number; speedX: number; speedY: number; opacity: number; } interface AnimatedBackgroundProps { variant?: "dark" | "light" | "red"; orbCount?: number; className?: string; } export default function AnimatedBackground({ variant = "dark", orbCount = 5, className = "", }: AnimatedBackgroundProps) { const canvasRef = useRef(null); const orbsRef = useRef([]); const animationRef = useRef(undefined); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext("2d"); if (!ctx) return; const resizeCanvas = () => { const parent = canvas.parentElement; if (parent) { canvas.width = parent.offsetWidth; canvas.height = parent.offsetHeight; } }; resizeCanvas(); window.addEventListener("resize", resizeCanvas); // Initialize orbs orbsRef.current = Array.from({ length: orbCount }, () => ({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, size: Math.random() * 200 + 100, speedX: (Math.random() - 0.5) * 0.5, speedY: (Math.random() - 0.5) * 0.5, opacity: Math.random() * 0.3 + 0.1, })); const getOrbColor = (opacity: number) => { switch (variant) { case "dark": return `rgba(220, 38, 38, ${opacity})`; case "light": return `rgba(220, 38, 38, ${opacity * 0.5})`; case "red": return `rgba(255, 255, 255, ${opacity * 0.3})`; default: return `rgba(220, 38, 38, ${opacity})`; } }; const animate = () => { ctx.clearRect(0, 0, canvas.width, canvas.height); orbsRef.current.forEach((orb) => { // Update position orb.x += orb.speedX; orb.y += orb.speedY; // Bounce off edges if (orb.x < -orb.size) orb.x = canvas.width + orb.size; if (orb.x > canvas.width + orb.size) orb.x = -orb.size; if (orb.y < -orb.size) orb.y = canvas.height + orb.size; if (orb.y > canvas.height + orb.size) orb.y = -orb.size; // Draw orb with gradient const gradient = ctx.createRadialGradient( orb.x, orb.y, 0, orb.x, orb.y, orb.size ); gradient.addColorStop(0, getOrbColor(orb.opacity)); gradient.addColorStop(1, getOrbColor(0)); ctx.beginPath(); ctx.arc(orb.x, orb.y, orb.size, 0, Math.PI * 2); ctx.fillStyle = gradient; ctx.fill(); }); animationRef.current = requestAnimationFrame(animate); }; animate(); return () => { window.removeEventListener("resize", resizeCanvas); if (animationRef.current) { cancelAnimationFrame(animationRef.current); } }; }, [variant, orbCount]); return ( ); }