import { useEffect, useRef } from "react"; interface Particle { x: number; y: number; vx: number; vy: number; size: number; opacity: number; } export function ParticlesBackground() { const canvasRef = useRef(null); const particlesRef = useRef([]); const animationFrameRef = useRef(); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext("2d"); if (!ctx) return; // Set canvas size const resizeCanvas = () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }; resizeCanvas(); window.addEventListener("resize", resizeCanvas); // Initialize particles const particleCount = Math.min(150, Math.floor((canvas.width * canvas.height) / 12000)); particlesRef.current = Array.from({ length: particleCount }, () => ({ 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.5, opacity: Math.random() * 0.6 + 0.3, })); // Animation loop const animate = () => { ctx.clearRect(0, 0, canvas.width, canvas.height); // Update and draw particles particlesRef.current.forEach((particle) => { // Update position particle.x += particle.vx; particle.y += particle.vy; // 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 = `rgba(16, 185, 129, ${particle.opacity})`; // gekon-green ctx.fill(); }); // Draw connections particlesRef.current.forEach((p1, i) => { particlesRef.current.slice(i + 1).forEach((p2) => { const dx = p1.x - p2.x; const dy = p1.y - p2.y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { ctx.beginPath(); ctx.moveTo(p1.x, p1.y); ctx.lineTo(p2.x, p2.y); const opacity = (1 - distance / 150) * 0.2; ctx.strokeStyle = `rgba(6, 182, 212, ${opacity})`; // gekon-cyan ctx.lineWidth = 0.5; ctx.stroke(); } }); }); animationFrameRef.current = requestAnimationFrame(animate); }; animate(); return () => { window.removeEventListener("resize", resizeCanvas); if (animationFrameRef.current) { cancelAnimationFrame(animationFrameRef.current); } }; }, []); return ( ); }