import React, { useEffect, useRef } from 'react'; interface Particle { x: number; y: number; vx: number; vy: number; size: number; opacity: number; color: string; } export function ParticleBackground() { const canvasRef = useRef(null); const particlesRef = useRef([]); const animationRef = useRef(); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; const resizeCanvas = () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }; const createParticles = () => { particlesRef.current = []; const particleCount = Math.min(50, Math.floor((canvas.width * canvas.height) / 15000)); for (let i = 0; i < particleCount; i++) { particlesRef.current.push({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, vx: (Math.random() - 0.5) * 0.8, vy: (Math.random() - 0.5) * 0.8, size: Math.random() * 3 + 1, opacity: Math.random() * 0.5 + 0.1, color: Math.random() > 0.5 ? '#3B82F6' : '#14B8A6' }); } }; const animate = () => { ctx.clearRect(0, 0, canvas.width, canvas.height); particlesRef.current.forEach((particle, index) => { // Update position particle.x += particle.vx; particle.y += particle.vy; // Bounce off edges if (particle.x < 0 || particle.x > canvas.width) particle.vx *= -1; if (particle.y < 0 || particle.y > canvas.height) particle.vy *= -1; // Keep particles in bounds particle.x = Math.max(0, Math.min(canvas.width, particle.x)); particle.y = Math.max(0, Math.min(canvas.height, particle.y)); // Draw particle ctx.beginPath(); ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2); ctx.fillStyle = `${particle.color}${Math.floor(particle.opacity * 255).toString(16).padStart(2, '0')}`; ctx.fill(); // Draw connections particlesRef.current.slice(index + 1).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) { const opacity = (1 - distance / 100) * 0.2; ctx.beginPath(); ctx.moveTo(particle.x, particle.y); ctx.lineTo(otherParticle.x, otherParticle.y); ctx.strokeStyle = `#60A5FA${Math.floor(opacity * 255).toString(16).padStart(2, '0')}`; ctx.lineWidth = 1; ctx.stroke(); } }); }); animationRef.current = requestAnimationFrame(animate); }; resizeCanvas(); createParticles(); animate(); const handleResize = () => { resizeCanvas(); createParticles(); }; window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); if (animationRef.current) { cancelAnimationFrame(animationRef.current); } }; }, []); return ( ); }