/** * CelestialBody component - renders a planet or probe with textures */ import { useRef, useMemo } from 'react'; import { Mesh, DoubleSide } from 'three'; import { useFrame } from '@react-three/fiber'; import { useTexture, Html } from '@react-three/drei'; import type { CelestialBody as CelestialBodyType } from '../types'; import { scalePosition } from '../utils/scaleDistance'; interface CelestialBodyProps { body: CelestialBodyType; } // Saturn Rings component - multiple rings for band effect function SaturnRings() { return ( {/* Inner bright ring */} {/* Middle darker band */} {/* Outer bright ring */} {/* Cassini Division (gap) */} {/* A Ring (outer) */} ); } // Planet component with texture function Planet({ body, size, emissive, emissiveIntensity }: { body: CelestialBodyType; size: number; emissive: string; emissiveIntensity: number; }) { const meshRef = useRef(null); const position = body.positions[0]; // Apply non-linear distance scaling for better visualization const scaledPos = useMemo(() => { // Special handling for Moon - display it relative to Earth with visible offset if (body.name === 'Moon') { const moonScaled = scalePosition(position.x, position.y, position.z); // Add a visual offset to make Moon visible next to Earth (2 units away) // Moon orbits Earth at ~0.00257 AU, we'll give it a 2-unit offset from Earth's scaled position const angle = Math.atan2(position.y, position.x); const offset = 2.0; // Visual offset in scaled units return { x: moonScaled.x + Math.cos(angle) * offset, y: moonScaled.y + Math.sin(angle) * offset, z: moonScaled.z, }; } return scalePosition(position.x, position.y, position.z); }, [position.x, position.y, position.z, body.name]); // Texture mapping for planets const texturePath = useMemo(() => { const textureMap: Record = { Sun: '/textures/2k_sun.jpg', Mercury: '/textures/2k_mercury.jpg', Venus: '/textures/2k_venus_surface.jpg', Earth: '/textures/2k_earth_daymap.jpg', Moon: '/textures/2k_moon.jpg', Mars: '/textures/2k_mars.jpg', Jupiter: '/textures/2k_jupiter.jpg', Saturn: '/textures/2k_saturn.jpg', Uranus: '/textures/2k_uranus.jpg', Neptune: '/textures/2k_neptune.jpg', }; return textureMap[body.name] || null; }, [body.name]); // Load texture - this must be at the top level, not in try-catch const texture = texturePath ? useTexture(texturePath) : null; // Slow rotation for visual effect useFrame((_, delta) => { if (meshRef.current) { meshRef.current.rotation.y += delta * 0.1; } }); // Calculate ACTUAL distance from Sun for display (not scaled) const distance = Math.sqrt(position.x ** 2 + position.y ** 2 + position.z ** 2); return ( {texture ? ( ) : ( )} {/* Saturn Rings */} {body.name === 'Saturn' && } {/* Sun glow effect */} {body.type === 'star' && ( <> )} {/* Name label */} {body.name_zh || body.name}
{distance.toFixed(2)} AU
); } export function CelestialBody({ body }: CelestialBodyProps) { // Get the current position (use the first position for now) const position = body.positions[0]; if (!position) return null; // Skip probes - they will use 3D models if (body.type === 'probe') { return null; } // Determine size based on body type const appearance = useMemo(() => { if (body.type === 'star') { return { size: 0.4, // Slightly larger sun for better visibility emissive: '#FDB813', emissiveIntensity: 1.5, }; } // Planet sizes - balanced for visibility with smaller probes const planetSizes: Record = { Mercury: 0.35, // Slightly larger for visibility Venus: 0.55, // Slightly larger for visibility Earth: 0.6, // Slightly larger for visibility Moon: 0.25, // Smaller than Earth Mars: 0.45, // Slightly larger for visibility Jupiter: 1.4, // Larger gas giant Saturn: 1.2, // Larger gas giant Uranus: 0.8, // Medium outer planet Neptune: 0.8, // Medium outer planet }; return { size: planetSizes[body.name] || 0.5, emissive: '#000000', emissiveIntensity: 0, }; }, [body.name, body.type]); return ( ); }