Spaces:
Sleeping
Sleeping
| "use client"; | |
| import { useEffect, useRef } from "react"; | |
| interface NeuralNode { | |
| x: number; | |
| y: number; | |
| vx: number; | |
| vy: number; | |
| radius: number; | |
| } | |
| export function NeuralBackground() { | |
| const canvasRef = useRef<HTMLCanvasElement>(null); | |
| const nodesRef = useRef<NeuralNode[]>([]); | |
| const animRef = useRef<number>(0); | |
| useEffect(() => { | |
| const canvas = canvasRef.current; | |
| if (!canvas) return; | |
| const ctx = canvas.getContext("2d"); | |
| if (!ctx) return; | |
| const resize = () => { | |
| canvas.width = window.innerWidth; | |
| canvas.height = window.innerHeight; | |
| }; | |
| resize(); | |
| window.addEventListener("resize", resize); | |
| // Initialize nodes | |
| const nodeCount = 60; | |
| nodesRef.current = Array.from({ length: nodeCount }, () => ({ | |
| x: Math.random() * canvas.width, | |
| y: Math.random() * canvas.height, | |
| vx: (Math.random() - 0.5) * 0.4, | |
| vy: (Math.random() - 0.5) * 0.4, | |
| radius: Math.random() * 2 + 1, | |
| })); | |
| const draw = () => { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| const nodes = nodesRef.current; | |
| // Update positions | |
| for (const node of nodes) { | |
| node.x += node.vx; | |
| node.y += node.vy; | |
| if (node.x < 0 || node.x > canvas.width) node.vx *= -1; | |
| if (node.y < 0 || node.y > canvas.height) node.vy *= -1; | |
| } | |
| // Draw connections | |
| const maxDist = 150; | |
| for (let i = 0; i < nodes.length; i++) { | |
| for (let j = i + 1; j < nodes.length; j++) { | |
| const dx = nodes[i].x - nodes[j].x; | |
| const dy = nodes[i].y - nodes[j].y; | |
| const dist = Math.sqrt(dx * dx + dy * dy); | |
| if (dist < maxDist) { | |
| const alpha = (1 - dist / maxDist) * 0.15; | |
| ctx.strokeStyle = `rgba(161, 161, 170, ${alpha})`; | |
| ctx.lineWidth = 0.5; | |
| ctx.beginPath(); | |
| ctx.moveTo(nodes[i].x, nodes[i].y); | |
| ctx.lineTo(nodes[j].x, nodes[j].y); | |
| ctx.stroke(); | |
| } | |
| } | |
| } | |
| // Draw nodes | |
| for (const node of nodes) { | |
| ctx.fillStyle = "rgba(161, 161, 170, 0.4)"; | |
| ctx.beginPath(); | |
| ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2); | |
| ctx.fill(); | |
| } | |
| animRef.current = requestAnimationFrame(draw); | |
| }; | |
| draw(); | |
| return () => { | |
| window.removeEventListener("resize", resize); | |
| cancelAnimationFrame(animRef.current); | |
| }; | |
| }, []); | |
| return ( | |
| <canvas | |
| ref={canvasRef} | |
| className="fixed inset-0 pointer-events-none z-0" | |
| style={{ opacity: 0.6 }} | |
| /> | |
| ); | |
| } | |