Spaces:
Running
Running
| import React, { useEffect, useRef } from 'react'; | |
| const QuantumParticles = () => { | |
| const canvasRef = useRef(null); | |
| useEffect(() => { | |
| const canvas = canvasRef.current; | |
| if (!canvas) return; | |
| const ctx = canvas.getContext('2d'); | |
| const particles = []; | |
| const particleCount = 50; | |
| // Set canvas size | |
| const resizeCanvas = () => { | |
| canvas.width = window.innerWidth; | |
| canvas.height = window.innerHeight; | |
| }; | |
| resizeCanvas(); | |
| window.addEventListener('resize', resizeCanvas); | |
| // Particle class | |
| class Particle { | |
| constructor() { | |
| this.x = Math.random() * canvas.width; | |
| this.y = Math.random() * canvas.height; | |
| this.vx = (Math.random() - 0.5) * 0.5; | |
| this.vy = (Math.random() - 0.5) * 0.5; | |
| this.radius = Math.random() * 2 + 1; | |
| this.opacity = Math.random() * 0.5 + 0.2; | |
| this.hue = Math.random() * 60 + 200; // Blue to purple range | |
| } | |
| update() { | |
| this.x += this.vx; | |
| this.y += this.vy; | |
| // Wrap around edges | |
| if (this.x < 0) this.x = canvas.width; | |
| if (this.x > canvas.width) this.x = 0; | |
| if (this.y < 0) this.y = canvas.height; | |
| if (this.y > canvas.height) this.y = 0; | |
| // Quantum-like behavior - occasional teleportation | |
| if (Math.random() < 0.001) { | |
| this.x = Math.random() * canvas.width; | |
| this.y = Math.random() * canvas.height; | |
| } | |
| } | |
| draw() { | |
| ctx.beginPath(); | |
| ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2); | |
| ctx.fillStyle = `hsla(${this.hue}, 70%, 60%, ${this.opacity})`; | |
| ctx.fill(); | |
| // Add glow effect | |
| ctx.shadowBlur = 10; | |
| ctx.shadowColor = `hsla(${this.hue}, 70%, 60%, 0.8)`; | |
| ctx.fill(); | |
| ctx.shadowBlur = 0; | |
| } | |
| } | |
| // Initialize particles | |
| for (let i = 0; i < particleCount; i++) { | |
| particles.push(new Particle()); | |
| } | |
| // Animation loop | |
| const animate = () => { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| particles.forEach(particle => { | |
| particle.update(); | |
| particle.draw(); | |
| }); | |
| // Draw connections between nearby particles | |
| particles.forEach((particle, i) => { | |
| particles.slice(i + 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) { | |
| ctx.beginPath(); | |
| ctx.moveTo(particle.x, particle.y); | |
| ctx.lineTo(otherParticle.x, otherParticle.y); | |
| ctx.strokeStyle = `hsla(220, 70%, 60%, ${0.1 * (1 - distance / 100)})`; | |
| ctx.lineWidth = 0.5; | |
| ctx.stroke(); | |
| } | |
| }); | |
| }); | |
| requestAnimationFrame(animate); | |
| }; | |
| animate(); | |
| return () => { | |
| window.removeEventListener('resize', resizeCanvas); | |
| }; | |
| }, []); | |
| return ( | |
| <canvas | |
| ref={canvasRef} | |
| className="absolute inset-0 pointer-events-none" | |
| style={{ zIndex: 1 }} | |
| /> | |
| ); | |
| }; | |
| export default QuantumParticles; | |