Skip to content

Commit dc2d0b0

Browse files
authored
Create ParticlesBackground.tsx
1 parent b4ea843 commit dc2d0b0

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import React, { useEffect, useRef } from 'react';
2+
3+
const ParticlesBackground: React.FC = () => {
4+
const canvasRef = useRef<HTMLCanvasElement>(null);
5+
6+
useEffect(() => {
7+
const canvas = canvasRef.current;
8+
if (!canvas) return;
9+
const ctx = canvas.getContext('2d');
10+
if (!ctx) return;
11+
12+
let particles: Particle[] = [];
13+
let animationFrameId: number;
14+
let w = (canvas.width = window.innerWidth);
15+
let h = (canvas.height = window.innerHeight);
16+
17+
// Particle Configuration
18+
const particleCount = 60;
19+
const connectionDistance = 150;
20+
21+
class Particle {
22+
x: number;
23+
y: number;
24+
vx: number;
25+
vy: number;
26+
size: number;
27+
28+
constructor() {
29+
this.x = Math.random() * w;
30+
this.y = Math.random() * h;
31+
this.vx = (Math.random() - 0.5) * 0.5; // Slow movement
32+
this.vy = (Math.random() - 0.5) * 0.5;
33+
this.size = Math.random() * 2 + 1;
34+
}
35+
36+
update() {
37+
this.x += this.vx;
38+
this.y += this.vy;
39+
40+
// Bounce off edges
41+
if (this.x < 0 || this.x > w) this.vx *= -1;
42+
if (this.y < 0 || this.y > h) this.vy *= -1;
43+
}
44+
45+
draw() {
46+
if (!ctx) return;
47+
ctx.beginPath();
48+
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
49+
ctx.fillStyle = 'rgba(0, 255, 65, 0.5)'; // Hacker Green
50+
ctx.fill();
51+
}
52+
}
53+
54+
const init = () => {
55+
particles = [];
56+
for (let i = 0; i < particleCount; i++) {
57+
particles.push(new Particle());
58+
}
59+
};
60+
61+
const animate = () => {
62+
if (!ctx) return;
63+
ctx.clearRect(0, 0, w, h);
64+
65+
particles.forEach((p, index) => {
66+
p.update();
67+
p.draw();
68+
69+
// Connect particles
70+
for (let j = index + 1; j < particles.length; j++) {
71+
const p2 = particles[j];
72+
const dx = p.x - p2.x;
73+
const dy = p.y - p2.y;
74+
const dist = Math.sqrt(dx * dx + dy * dy);
75+
76+
if (dist < connectionDistance) {
77+
ctx.beginPath();
78+
ctx.strokeStyle = `rgba(0, 255, 65, ${0.15 - dist / connectionDistance / 5})`; // Fading line
79+
ctx.lineWidth = 1;
80+
ctx.moveTo(p.x, p.y);
81+
ctx.lineTo(p2.x, p2.y);
82+
ctx.stroke();
83+
}
84+
}
85+
});
86+
87+
animationFrameId = requestAnimationFrame(animate);
88+
};
89+
90+
const handleResize = () => {
91+
w = canvas.width = window.innerWidth;
92+
h = canvas.height = window.innerHeight;
93+
init();
94+
};
95+
96+
window.addEventListener('resize', handleResize);
97+
init();
98+
animate();
99+
100+
return () => {
101+
window.removeEventListener('resize', handleResize);
102+
cancelAnimationFrame(animationFrameId);
103+
};
104+
}, []);
105+
106+
return (
107+
<canvas
108+
ref={canvasRef}
109+
className="absolute inset-0 z-0 pointer-events-none opacity-60"
110+
/>
111+
);
112+
};
113+
114+
export default ParticlesBackground;

0 commit comments

Comments
 (0)