Mission Controls
Playback
{error}
: null}Fleet Status
Satellites
Network
Ground stations & transfers
Conditions
import { useEffect, useRef, useState } from "react"; import Globe from "react-globe.gl"; import { motion } from "framer-motion"; import { Activity, Gauge, Orbit, Radio, RefreshCcw, Satellite, Signal, } from "lucide-react"; const TASKS = ["easy", "medium", "hard"]; const STEP_INTERVAL_MS = 2200; const explicitApiBase = import.meta.env.VITE_API_BASE?.replace(/\/$/, ""); const isLocalPreview = typeof window !== "undefined" && ["localhost", "127.0.0.1"].includes(window.location.hostname) && window.location.port === "4173"; const API_BASE = explicitApiBase || (isLocalPreview ? "http://127.0.0.1:8000" : ""); const EARTH_TEXTURE = "https://unpkg.com/three-globe/example/img/earth-blue-marble.jpg"; const EARTH_BUMP = "https://unpkg.com/three-globe/example/img/earth-topology.png"; const STARFIELD = "https://unpkg.com/three-globe/example/img/night-sky.png"; function apiUrl(path) { return `${API_BASE}${path}`; } function useDemoData() { const [snapshot, setSnapshot] = useState(null); const [loading, setLoading] = useState(true); const [playing, setPlaying] = useState(true); const [taskName, setTaskName] = useState("medium"); const [error, setError] = useState(""); const steppingRef = useRef(false); async function loadSnapshot() { try { const response = await fetch(apiUrl("/api/ui/demo")); if (!response.ok) { throw new Error(`Snapshot request failed with ${response.status}`); } const data = await response.json(); setSnapshot(data); setTaskName(data.task_name ?? "medium"); setError(""); } catch (err) { setError(err instanceof Error ? err.message : "Unable to load UI snapshot"); } finally { setLoading(false); } } async function resetDemo(nextTask) { setLoading(true); try { const response = await fetch(apiUrl(`/api/ui/demo/reset?task_name=${encodeURIComponent(nextTask)}`), { method: "POST", }); if (!response.ok) { throw new Error(`Reset failed with ${response.status}`); } const data = await response.json(); setSnapshot(data); setTaskName(data.task_name ?? nextTask); setError(""); } catch (err) { setError(err instanceof Error ? err.message : "Unable to reset demo"); } finally { setLoading(false); } } async function stepDemo() { if (steppingRef.current || loading) { return; } if (snapshot?.done || (snapshot?.step_count ?? 0) >= (snapshot?.max_steps ?? Number.POSITIVE_INFINITY)) { setPlaying(false); return; } steppingRef.current = true; try { const response = await fetch(apiUrl("/api/ui/demo/step"), { method: "POST" }); if (!response.ok) { throw new Error(`Step failed with ${response.status}`); } const data = await response.json(); setSnapshot(data); if (data.done || (data.step_count ?? 0) >= (data.max_steps ?? Number.POSITIVE_INFINITY)) { setPlaying(false); } setError(""); } catch (err) { setPlaying(false); setError(err instanceof Error ? err.message : "Unable to advance demo"); } finally { steppingRef.current = false; } } useEffect(() => { loadSnapshot(); }, []); useEffect(() => { if (!playing || loading || snapshot?.done || (snapshot?.step_count ?? 0) >= (snapshot?.max_steps ?? Number.POSITIVE_INFINITY)) { return undefined; } const timer = window.setInterval(() => { stepDemo(); }, STEP_INTERVAL_MS); return () => window.clearInterval(timer); }, [playing, loading, snapshot]); return { snapshot, loading, playing, taskName, error, setPlaying, resetDemo, stepDemo, }; } function GlobeView({ snapshot }) { const globeRef = useRef(null); const [view, setView] = useState({ lat: 14, lng: 12, altitude: 2.35 }); const pathStoreRef = useRef([]); const [pathData, setPathData] = useState([]); useEffect(() => { if (!globeRef.current) { return; } const controls = globeRef.current.controls(); controls.autoRotate = false; controls.enablePan = false; controls.enableZoom = false; controls.minDistance = 220; controls.maxDistance = 320; controls.minPolarAngle = Math.PI * 0.42; controls.maxPolarAngle = Math.PI * 0.58; const handleChange = () => { const pov = globeRef.current?.pointOfView(); if (!pov) { return; } const clamped = { lat: Math.max(4, Math.min(24, pov.lat)), lng: pov.lng, altitude: 2.35, }; if ( Math.abs(clamped.lat - pov.lat) > 0.01 || Math.abs(clamped.altitude - pov.altitude) > 0.01 ) { globeRef.current.pointOfView(clamped, 0); } }; controls.addEventListener("change", handleChange); return () => { controls.removeEventListener("change", handleChange); }; }, []); useEffect(() => { if (!globeRef.current) { return; } globeRef.current.pointOfView(view, 0); }, [view]); useEffect(() => { const satellites = snapshot?.satellites ?? []; const stepCount = snapshot?.step_count ?? 0; if (!satellites.length) { pathStoreRef.current = []; setPathData([]); return; } if (stepCount === 0) { const nextPaths = []; for (const satellite of satellites) { const altitude = 0.11 + Math.min(satellite.altitude_km / 8000, 0.1); const orbitPoints = (satellite.route ?? []).map((node) => ({ lat: node.latitude, lng: node.longitude, alt: altitude, })); if (orbitPoints.length > 1) { nextPaths.push({ id: `orbit-${satellite.id}`, color: satelliteColor(satellite.last_action), points: orbitPoints, }); } nextPaths.push({ id: `trail-${satellite.id}`, color: satelliteColor(satellite.last_action), points: [ { lat: satellite.latitude, lng: satellite.longitude, alt: altitude, }, ], }); } pathStoreRef.current = nextPaths; } else { const pathMap = new Map(pathStoreRef.current.map((path) => [path.id, path])); for (const satellite of satellites) { const orbitId = `orbit-${satellite.id}`; const trailId = `trail-${satellite.id}`; const color = satelliteColor(satellite.last_action); const altitude = 0.11 + Math.min(satellite.altitude_km / 8000, 0.1); const nextPoint = { lat: satellite.latitude, lng: satellite.longitude, alt: altitude, }; const orbitPath = pathMap.get(orbitId); if (orbitPath) { orbitPath.color = color; } const trailPath = pathMap.get(trailId); if (!trailPath) { pathMap.set(trailId, { id: trailId, color, points: [nextPoint], }); continue; } trailPath.color = color; const lastPoint = trailPath.points[trailPath.points.length - 1]; const hasSamePoint = lastPoint && Math.abs(lastPoint.lat - nextPoint.lat) < 0.0001 && Math.abs(lastPoint.lng - nextPoint.lng) < 0.0001; if (!hasSamePoint) { trailPath.points.push(nextPoint); if (trailPath.points.length > 160) { trailPath.points.shift(); } } } pathStoreRef.current = [...pathMap.values()]; } const pathMap = new Map(pathStoreRef.current.map((path) => [path.id, path])); const activeTransferPaths = new Set(); for (const transfer of snapshot?.transfers ?? []) { if (transfer.kind !== "downlink" && transfer.kind !== "capture") { continue; } const pathId = `${transfer.kind}-${transfer.satellite_id}`; activeTransferPaths.add(pathId); const points = [ { lat: transfer.from.latitude, lng: transfer.from.longitude, alt: transfer.kind === "downlink" ? 0.13 : 0.15, }, { lat: transfer.to.latitude, lng: transfer.to.longitude, alt: transfer.kind === "downlink" ? 0.015 : 0.012, }, ]; const existingPath = pathMap.get(pathId); if (existingPath) { existingPath.points.splice(0, existingPath.points.length, ...points); existingPath.visible = true; existingPath.color = transfer.kind === "downlink" ? "#7cf7c9" : "#ffb86b"; } else { pathMap.set(pathId, { id: pathId, color: transfer.kind === "downlink" ? "#7cf7c9" : "#ffb86b", points, visible: true, }); } } for (const path of pathMap.values()) { if ( (String(path.id).startsWith("downlink-") || String(path.id).startsWith("capture-")) && !activeTransferPaths.has(path.id) ) { path.visible = false; } } pathStoreRef.current = [...pathMap.values()]; setPathData(pathStoreRef.current.filter((path) => path.visible !== false)); }, [snapshot]); const satellites = (snapshot?.satellites ?? []).map((satellite) => ({ ...satellite, lat: satellite.latitude, lng: satellite.longitude, altitude: 0.1 + Math.min(satellite.altitude_km / 8000, 0.1), type: "satellite", color: satelliteColor(satellite.last_action), size: 0.45, label: `Sat ${satellite.id} · ${satellite.last_action}`, })); const groundStations = (snapshot?.ground_stations ?? []).map((station) => ({ ...station, lat: station.latitude, lng: station.longitude, altitude: 0.01, type: "station", color: "#8cffef", size: 0.34, label: `${station.name} · ${station.capacity.toFixed(1)} Gbps`, })); const captureRegions = (snapshot?.capture_regions ?? []).map((region) => ({ ...region, lat: region.latitude, lng: region.longitude, altitude: 0.009, type: "region", color: regionColor(region.cloud_cover), size: 0.28, label: `${region.name} · Cloud ${Math.round(Number(region.cloud_cover) * 100)}%`, })); const markerNodes = [...groundStations, ...captureRegions, ...satellites]; return (
Orbital Flow Console
OpenEnv Showcase
Mission Controls
{error}
: null}Fleet Status
Network
Conditions