adn / frontend /src /components /FluidField.tsx
dimensionalpulsar's picture
Upload 38 files
9a16769 verified
Raw History Blame Contribute Delete
1.89 kB
import { useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import * as THREE from 'three';
import { useStore } from '../store';
// Visual representation of the fluid field (Navier-Stokes snapshot from backend)
export default function FluidField() {
const { fluidField } = useStore();
const groupRef = useRef<THREE.Group>(null);
useFrame(({ clock }) => {
if (!groupRef.current) return;
groupRef.current.children.forEach((child, i) => {
const mesh = child as THREE.Mesh;
// Subtle pulsing animation on field cells
mesh.position.y = mesh.userData.baseY + Math.sin(clock.elapsedTime * 2 + i) * 0.05;
});
});
if (!fluidField || fluidField.length === 0) return null;
const N = Math.sqrt(fluidField.length);
const spacing = 1.2;
const offset = (N * spacing) / 2;
return (
<group ref={groupRef} position={[30, 0, 0]}>
{fluidField.map((elevation, idx) => {
const col = idx % N;
const row = Math.floor(idx / N);
const x = col * spacing - offset;
const z = row * spacing - offset;
const y = elevation;
const intensity = Math.abs(elevation);
return (
<mesh
key={idx}
position={[x, y, z]}
userData={{ baseY: y }}
>
<boxGeometry args={[0.9, Math.max(0.05, intensity * 2), 0.9]} />
<meshStandardMaterial
color={new THREE.Color().setHSL(
0.55 - intensity * 0.15,
0.8,
0.3 + intensity * 0.3
)}
transparent
opacity={0.75}
wireframe={false}
/>
</mesh>
);
})}
{/* Label */}
<mesh position={[0, 5, 0]}>
<planeGeometry args={[12, 1.5]} />
<meshBasicMaterial color="#0a2040" />
</mesh>
</group>
);
}