ca-grow-ops-manager/frontend/src/components/facility3d/Beacon.tsx
fullsizemalt 4d900d7bec
Some checks are pending
Deploy to Production / deploy (push) Waiting to run
Test / backend-test (push) Waiting to run
Test / frontend-test (push) Waiting to run
feat: add plant search, beacon highlights, and timeline slider (phases 2+3)
2025-12-18 00:19:21 -08:00

60 lines
2 KiB
TypeScript

import { useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import * as THREE from 'three';
interface BeaconProps {
position: [number, number, number];
color?: string;
height?: number;
}
export function Beacon({ position, color = '#22d3ee', height = 15 }: BeaconProps) {
const meshRef = useRef<THREE.Mesh>(null);
const ringRef = useRef<THREE.Mesh>(null);
// Animate the beacon
useFrame((state) => {
if (meshRef.current) {
// Pulse opacity
const pulse = Math.sin(state.clock.elapsedTime * 3) * 0.3 + 0.5;
(meshRef.current.material as THREE.MeshBasicMaterial).opacity = pulse;
}
if (ringRef.current) {
// Expand and fade ring
const t = (state.clock.elapsedTime % 2) / 2;
ringRef.current.scale.set(1 + t * 3, 1, 1 + t * 3);
(ringRef.current.material as THREE.MeshBasicMaterial).opacity = 0.6 * (1 - t);
}
});
return (
<group position={position}>
{/* Vertical Light Beam */}
<mesh ref={meshRef} position={[0, height / 2, 0]}>
<cylinderGeometry args={[0.15, 0.4, height, 16, 1, true]} />
<meshBasicMaterial
color={color}
transparent
opacity={0.5}
side={THREE.DoubleSide}
depthWrite={false}
/>
</mesh>
{/* Ground Ring */}
<mesh ref={ringRef} rotation={[-Math.PI / 2, 0, 0]} position={[0, 0.05, 0]}>
<ringGeometry args={[0.3, 0.5, 32]} />
<meshBasicMaterial
color={color}
transparent
opacity={0.6}
side={THREE.DoubleSide}
depthWrite={false}
/>
</mesh>
{/* Core Glow */}
<pointLight color={color} intensity={2} distance={5} />
</group>
);
}