import { useEffect, useRef } from 'react' interface Particle { x: number y: number size: number speedX: number speedY: number opacity: number } export default function ParticleBackground() { const canvasRef = useRef(null) useEffect(() => { const canvas = canvasRef.current if (!canvas) return const ctx = canvas.getContext('2d') if (!ctx) return let animationId: number let particles: Particle[] = [] let mouseX = 0 let mouseY = 0 const resize = () => { canvas.width = window.innerWidth canvas.height = window.innerHeight } const createParticles = () => { particles = [] const count = Math.floor((canvas.width * canvas.height) / 15000) for (let i = 0; i < count; i++) { particles.push({ x: Math.random() * canvas.width, y: Math.random() * canvas.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.1 }) } } const drawParticles = () => { ctx.clearRect(0, 0, canvas.width, canvas.height) particles.forEach((particle, i) => { particle.x += particle.speedX particle.y += particle.speedY 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 ctx.beginPath() ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2) ctx.fillStyle = `rgba(102, 126, 234, ${particle.opacity})` ctx.fill() particles.forEach((particle2, j) => { if (i === j) return const dx = particle.x - particle2.x const dy = particle.y - particle2.y const distance = Math.sqrt(dx * dx + dy * dy) if (distance < 150) { ctx.beginPath() ctx.strokeStyle = `rgba(102, 126, 234, ${0.15 * (1 - distance / 150)})` ctx.lineWidth = 0.5 ctx.moveTo(particle.x, particle.y) ctx.lineTo(particle2.x, particle2.y) ctx.stroke() } }) const dx = particle.x - mouseX const dy = particle.y - mouseY const distance = Math.sqrt(dx * dx + dy * dy) if (distance < 200) { const force = (200 - distance) / 200 particle.speedX += (dx / distance) * force * 0.02 particle.speedY += (dy / distance) * force * 0.02 } particle.speedX *= 0.99 particle.speedY *= 0.99 }) animationId = requestAnimationFrame(drawParticles) } const handleMouseMove = (e: MouseEvent) => { mouseX = e.clientX mouseY = e.clientY } resize() createParticles() drawParticles() window.addEventListener('resize', () => { resize() createParticles() }) window.addEventListener('mousemove', handleMouseMove) return () => { cancelAnimationFrame(animationId) window.removeEventListener('resize', resize) window.removeEventListener('mousemove', handleMouseMove) } }, []) return ( ) }