1- import { useMemo } from 'react' ;
21import { OrbitControls } from '@react-three/drei' ;
32import { Canvas } from '@react-three/fiber' ;
43import { useShallow } from 'zustand/react/shallow' ;
54
6- import { type Vehicle , VEHICLE_LABELS } from '@/domain/vehicle' ;
75import { PRESETS , type SpacecraftConfig } from '@/schemas/spacecraft' ;
86import type { StateVectorInput } from '@/schemas/stateVector' ;
97import { useConfig , type VehicleStateSlot } from '@/stores/configuration' ;
10- import { configToSpacecraftProps , Spacecraft , TINTS } from '@/viewport3d/spacecraft' ;
118
12- import {
13- FARFIELD_LABEL_FONT_SIZE ,
14- FARFIELD_LABEL_OFFSET_Y ,
15- FARFIELD_SPACECRAFT_SCALE ,
16- } from './constants' ;
17- import { eciKmToScenePosition } from './coordinates' ;
189import Earth from './Earth' ;
10+ import { computeCameraPos , computeEraRad , computeSunScenePos , FALLBACK_LIGHT_POS } from './scene' ;
11+ import VehicleMesh from './VehicleMesh' ;
1912
2013const FALLBACK_CONFIG : SpacecraftConfig = {
2114 preset : 'Servicer 500kg' ,
@@ -26,33 +19,6 @@ function loadedVector(slot: VehicleStateSlot): StateVectorInput | null {
2619 return slot . status === 'loaded' ? slot . vector : null ;
2720}
2821
29- function VehicleMesh ( {
30- vehicle,
31- config,
32- vector,
33- } : {
34- vehicle : Vehicle ;
35- config : SpacecraftConfig ;
36- vector : StateVectorInput ;
37- } ) {
38- const props = useMemo ( ( ) => configToSpacecraftProps ( config , vehicle ) , [ config , vehicle ] ) ;
39- const position = useMemo (
40- ( ) => eciKmToScenePosition ( vector . position_eci_km ) ,
41- [ vector . position_eci_km ] ,
42- ) ;
43- return (
44- < Spacecraft
45- { ...props }
46- position = { position }
47- scale = { FARFIELD_SPACECRAFT_SCALE }
48- label = { VEHICLE_LABELS [ vehicle ] }
49- labelColor = { TINTS [ vehicle ] . accent }
50- labelFontSize = { FARFIELD_LABEL_FONT_SIZE }
51- labelOffsetY = { FARFIELD_LABEL_OFFSET_Y }
52- />
53- ) ;
54- }
55-
5622export default function FarFieldViewport ( ) {
5723 const { chiefConfig, deputyConfig, chiefState, deputyState } = useConfig (
5824 useShallow ( ( s ) => ( {
@@ -66,13 +32,19 @@ export default function FarFieldViewport() {
6632 const chiefVector = loadedVector ( chiefState ) ;
6733 const deputyVector = loadedVector ( deputyState ) ;
6834
35+ const epoch = chiefVector ?. epoch ?? deputyVector ?. epoch ?? null ;
36+ const eraRad = epoch === null ? 0 : computeEraRad ( epoch ) ;
37+ const sunScenePos = epoch === null ? FALLBACK_LIGHT_POS : computeSunScenePos ( epoch ) ;
38+ // OrbitControls owns the camera after first render; remount to re-apply.
39+ const cameraPos = computeCameraPos ( chiefVector , deputyVector ) ;
40+
6941 return (
7042 < div className = "h-full w-full" >
71- < Canvas camera = { { position : [ 0 , 0 , 6 ] , fov : 50 , near : 0.1 , far : 100 } } dpr = { [ 1 , 2 ] } >
43+ < Canvas camera = { { position : cameraPos , fov : 50 , near : 0.1 , far : 100 } } dpr = { [ 1 , 2 ] } >
7244 < ambientLight intensity = { 0.35 } />
7345 < hemisphereLight args = { [ '#8aa0c0' , '#1a1f2c' , 0.4 ] } />
74- < directionalLight position = { [ 10 , 5 , 10 ] } intensity = { 1.0 } />
75- < Earth />
46+ < directionalLight position = { sunScenePos } intensity = { 1.0 } />
47+ < Earth rotationY = { eraRad } />
7648 { chiefVector && < VehicleMesh vehicle = "chief" config = { chiefConfig } vector = { chiefVector } /> }
7749 { deputyVector && (
7850 < VehicleMesh vehicle = "deputy" config = { deputyConfig } vector = { deputyVector } />
0 commit comments