import { useEffect, useRef } from 'react' /** * Animated background component that draws an interactive particle effect */ const AnimatedBackground = () => { const canvasRef = useRef(null) useEffect(() => { const canvas = canvasRef.current if (!canvas) return const ctx = canvas.getContext('2d') if (!ctx) return // Set canvas size to match window const setCanvasSize = () => { canvas.width = window.innerWidth canvas.height = window.innerHeight } setCanvasSize() window.addEventListener('resize', setCanvasSize) // Create particles const particles: Particle[] = [] const particleCount = 30 interface Particle { x: number y: number size: number speedX: number speedY: number opacity: number color: string } // Color palette matching theme const colors = [ 'rgba(74, 118, 196, 0.5)', // primary blue 'rgba(155, 125, 255, 0.5)', // purple 'rgba(251, 177, 60, 0.5)', // gold ] // Create initial particles for (let i = 0; i < particleCount; i++) { particles.push({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, size: Math.random() * 3 + 1, speedX: Math.random() * 0.2 - 0.1, speedY: Math.random() * 0.2 - 0.1, opacity: Math.random() * 0.07 + 0.03, color: colors[Math.floor(Math.random() * colors.length)], }) } // Animation loop const animate = () => { // Clear canvas with transparent black to create fade effect ctx.fillStyle = 'rgba(15, 15, 15, 0.1)' ctx.fillRect(0, 0, canvas.width, canvas.height) // Update and draw particles particles.forEach((particle) => { // Update position particle.x += particle.speedX particle.y += particle.speedY // Wrap around edges if (particle.x < 0) particle.x = canvas.width if (particle.x > canvas.width) particle.x = 0 if (particle.y < 0) particle.y = canvas.height if (particle.y > canvas.height) particle.y = 0 // Draw particle ctx.beginPath() ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2) ctx.fillStyle = particle.color.replace('0.5', `${particle.opacity}`) ctx.fill() // Connect particles that are close to each other particles.forEach((otherParticle) => { const dx = particle.x - otherParticle.x const dy = particle.y - otherParticle.y const distance = Math.sqrt(dx * dx + dy * dy) if (distance < 100) { ctx.beginPath() ctx.strokeStyle = particle.color.replace('0.5', `${particle.opacity * 0.5}`) ctx.lineWidth = 0.2 ctx.moveTo(particle.x, particle.y) ctx.lineTo(otherParticle.x, otherParticle.y) ctx.stroke() } }) }) requestAnimationFrame(animate) } // Start animation animate() // Cleanup return () => { window.removeEventListener('resize', setCanvasSize) } }, []) return