"use client"; import React, { useEffect, useRef, useState } from 'react'; interface Particle { id: number; x: number; y: number; size: number; speedX: number; speedY: number; opacity: number; color: string; } export const ParticleBackground: React.FC = () => { const canvasRef = useRef(null); const [dimensions, setDimensions] = useState({ width: 0, height: 0 }); const particlesRef = useRef([]); const animationRef = useRef(undefined); const mouseRef = useRef({ x: 0, y: 0 }); useEffect(() => { const handleResize = () => { setDimensions({ width: window.innerWidth, height: window.innerHeight }); }; const handleMouseMove = (e: MouseEvent) => { mouseRef.current = { x: e.clientX, y: e.clientY }; }; handleResize(); window.addEventListener('resize', handleResize); window.addEventListener('mousemove', handleMouseMove); return () => { window.removeEventListener('resize', handleResize); window.removeEventListener('mousemove', handleMouseMove); }; }, []); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; canvas.width = dimensions.width; canvas.height = dimensions.height; // Initialize particles const particleCount = Math.floor((dimensions.width * dimensions.height) / 15000); particlesRef.current = Array.from({ length: particleCount }, (_, i) => ({ id: i, x: Math.random() * dimensions.width, y: Math.random() * dimensions.height, size: Math.random() * 2 + 0.5, speedX: (Math.random() - 0.5) * 0.5, speedY: (Math.random() - 0.5) * 0.5, opacity: Math.random() * 0.5 + 0.2, color: Math.random() > 0.7 ? '#FFAA00' : '#00D4FF' })); const animate = () => { ctx.clearRect(0, 0, dimensions.width, dimensions.height); particlesRef.current.forEach((particle, index) => { // Update position particle.x += particle.speedX; particle.y += particle.speedY; // Mouse interaction - particles move away from cursor const dx = mouseRef.current.x - particle.x; const dy = mouseRef.current.y - particle.y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < 100) { const force = (100 - distance) / 100; particle.x -= (dx / distance) * force * 2; particle.y -= (dy / distance) * force * 2; } // Wrap around screen if (particle.x < 0) particle.x = dimensions.width; if (particle.x > dimensions.width) particle.x = 0; if (particle.y < 0) particle.y = dimensions.height; if (particle.y > dimensions.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(')', `, ${particle.opacity})`).replace('rgb', 'rgba').replace('#', ''); // Convert hex to rgba const hex = particle.color; const r = parseInt(hex.slice(1, 3), 16); const g = parseInt(hex.slice(3, 5), 16); const b = parseInt(hex.slice(5, 7), 16); ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${particle.opacity})`; ctx.fill(); // Draw connections between nearby particles 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 < 120) { ctx.beginPath(); ctx.moveTo(particle.x, particle.y); ctx.lineTo(otherParticle.x, otherParticle.y); ctx.strokeStyle = `rgba(0, 212, 255, ${0.1 * (1 - distance / 120)})`; ctx.lineWidth = 0.5; ctx.stroke(); } }); }); animationRef.current = requestAnimationFrame(animate); }; animate(); return () => { if (animationRef.current) { cancelAnimationFrame(animationRef.current); } }; }, [dimensions]); return ( ); };