codeSentry / codesentry-frontend /src /components /ParticleBackground.jsx
YashashviAlva's picture
Initial commit for HF Spaces deploy
7b4f5dd
/* ═══════════════════════════════════════════════════════════════
ParticleBackground β€” Animated cyberpunk network visualization
Canvas-based particle system with connecting lines
═══════════════════════════════════════════════════════════════ */
import { useEffect, useRef } from 'react';
const PARTICLE_COUNT = 50;
const CONNECTION_DISTANCE = 140;
const PARTICLE_SPEED = 0.25;
export default function ParticleBackground() {
const canvasRef = useRef(null);
const animRef = useRef(null);
const particlesRef = useRef([]);
useEffect(() => {
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
let width = window.innerWidth;
let height = window.innerHeight;
canvas.width = width;
canvas.height = height;
// Initialize particles
particlesRef.current = Array.from({ length: PARTICLE_COUNT }, () => ({
x: Math.random() * width,
y: Math.random() * height,
vx: (Math.random() - 0.5) * PARTICLE_SPEED,
vy: (Math.random() - 0.5) * PARTICLE_SPEED,
radius: Math.random() * 1.5 + 0.5,
opacity: Math.random() * 0.3 + 0.1,
}));
function animate() {
ctx.clearRect(0, 0, width, height);
const particles = particlesRef.current;
// Update & draw particles
particles.forEach((p) => {
p.x += p.vx;
p.y += p.vy;
// Wrap around edges
if (p.x < 0) p.x = width;
if (p.x > width) p.x = 0;
if (p.y < 0) p.y = height;
if (p.y > height) p.y = 0;
// Draw particle
ctx.beginPath();
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
ctx.fillStyle = `rgba(0, 240, 255, ${p.opacity})`;
ctx.fill();
});
// Draw connections
for (let i = 0; i < particles.length; i++) {
for (let j = i + 1; j < particles.length; j++) {
const dx = particles[i].x - particles[j].x;
const dy = particles[i].y - particles[j].y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < CONNECTION_DISTANCE) {
const opacity = (1 - dist / CONNECTION_DISTANCE) * 0.15;
ctx.beginPath();
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(particles[j].x, particles[j].y);
ctx.strokeStyle = `rgba(0, 240, 255, ${opacity})`;
ctx.lineWidth = 0.5;
ctx.stroke();
}
}
}
animRef.current = requestAnimationFrame(animate);
}
animate();
const handleResize = () => {
width = window.innerWidth;
height = window.innerHeight;
canvas.width = width;
canvas.height = height;
};
window.addEventListener('resize', handleResize);
return () => {
cancelAnimationFrame(animRef.current);
window.removeEventListener('resize', handleResize);
};
}, []);
return (
<canvas
ref={canvasRef}
style={{
position: 'fixed',
top: 0,
left: 0,
width: '100%',
height: '100%',
zIndex: -1,
pointerEvents: 'none',
}}
/>
);
}