Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Failing after 3m48s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 4s
60 lines
2.1 KiB
TypeScript
60 lines
2.1 KiB
TypeScript
import React, { useMemo, useRef } from 'react';
|
|
import { useFrame } from '@react-three/fiber';
|
|
import { SceneData, SceneEdge } from './Generator';
|
|
import * as THREE from 'three';
|
|
import { Line } from '@react-three/drei';
|
|
|
|
// A single CatmullRomCurve3 cable with particles moving along it
|
|
const Cable: React.FC<{ edge: SceneEdge }> = ({ edge }) => {
|
|
const points = useMemo(() => edge.path.map(p => new THREE.Vector3(p[0], p[1], p[2])), [edge.path]);
|
|
const curve = useMemo(() => new THREE.CatmullRomCurve3(points), [points]);
|
|
|
|
// We extract the line points for rendering the static line
|
|
const linePoints = useMemo(() => curve.getPoints(20), [curve]);
|
|
const linePositions = useMemo(() => linePoints.flatMap(p => [p.x, p.y, p.z]), [linePoints]);
|
|
|
|
const particleRef = useRef<THREE.Mesh>(null!);
|
|
const timeRef = useRef(Math.random()); // Random offset for particles
|
|
|
|
useFrame((state, delta) => {
|
|
if (!particleRef.current) return;
|
|
|
|
// Move particle along the curve. Speed based on edge type.
|
|
const speed = edge.type === 'transmission' ? 0.3 : 0.15;
|
|
timeRef.current = (timeRef.current + delta * speed) % 1;
|
|
|
|
const pos = curve.getPointAt(timeRef.current);
|
|
particleRef.current.position.copy(pos);
|
|
});
|
|
|
|
return (
|
|
<group>
|
|
{/* The actual cable. Underground cables can just be transparent or slightly visible */}
|
|
{edge.type === 'transmission' && (
|
|
<Line
|
|
points={linePoints}
|
|
color="#334155"
|
|
lineWidth={1.5}
|
|
/>
|
|
)}
|
|
{/* The glowing particle */}
|
|
<mesh ref={particleRef}>
|
|
<sphereGeometry args={[edge.type === 'transmission' ? 0.8 : 0.4, 8, 8]} />
|
|
<meshBasicMaterial color="#82ed20" transparent opacity={0.8} />
|
|
</mesh>
|
|
</group>
|
|
);
|
|
};
|
|
|
|
const TransmissionLines: React.FC<{ data: SceneData }> = ({ data }) => {
|
|
return (
|
|
<group>
|
|
{data.edges.map(edge => (
|
|
<Cable key={edge.id} edge={edge} />
|
|
))}
|
|
</group>
|
|
);
|
|
};
|
|
|
|
export default TransmissionLines;
|