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 (
{ if (String(path.id).startsWith("orbit-")) { return 0.7; } if (String(path.id).startsWith("trail-")) { return 1.55; } if (String(path.id).startsWith("capture-")) { return 1.0; } return 1.15; }} pathDashLength={(path) => { if (String(path.id).startsWith("orbit-")) { return 0; } if (String(path.id).startsWith("trail-")) { return 0; } if (String(path.id).startsWith("capture-")) { return 0.1; } return 0.22; }} pathDashGap={(path) => { if (String(path.id).startsWith("downlink-")) { return 0.14; } if (String(path.id).startsWith("capture-")) { return 0.2; } return 0; }} pathDashAnimateTime={0} htmlElementsData={markerNodes} htmlLat="lat" htmlLng="lng" htmlAltitude="altitude" htmlElement={(marker) => { const element = document.createElement("div"); if (marker.type === "satellite") { element.className = "globe-marker satellite"; } else if (marker.type === "region") { element.className = "globe-marker region"; } else { element.className = "globe-marker station"; } element.style.setProperty("--marker-color", marker.color); element.style.setProperty("--marker-size", `${marker.size}rem`); element.setAttribute("title", marker.label); element.innerHTML = ``; return element; }} />

Orbital Flow Console

Live tracking across satellites and ground stations.

Active satellites {snapshot?.satellites?.length ?? 0}
Ground links {snapshot?.transfers?.filter((item) => item.kind === "downlink").length ?? 0}
); } function satelliteColor(action) { if (action === "capture") { return "#ffb86b"; } if (action === "downlink") { return "#7cf7c9"; } if (action === "maintain") { return "#9caaff"; } return "#95a2bb"; } function regionColor(cloudCover) { const cloud = Number(cloudCover); if (cloud <= 0.3) { return "#88ffd1"; } if (cloud <= 0.6) { return "#ffc778"; } return "#ff8f8f"; } function App() { const { snapshot, loading, playing, taskName, error, setPlaying, resetDemo, stepDemo } = useDemoData(); const weatherSummary = !snapshot?.weather_conditions ? [] : Object.entries(snapshot.weather_conditions).map(([region, cloudCover]) => ({ region, cloudCover, })); return (

OpenEnv Showcase

Satellite mission tracking

{TASKS.map((task) => ( ))}
{loading ?
Loading orbital telemetry…
: }

Mission Controls

Playback

{error ?

{error}

: null}
} label="Step" value={`${Math.min(snapshot?.step_count ?? 0, snapshot?.max_steps ?? 0)}/${snapshot?.max_steps ?? 0}`} /> } label="Total reward" value={(snapshot?.total_reward ?? 0).toFixed(1)} /> } label="Last reward" value={(snapshot?.last_reward ?? 0).toFixed(1)} /> } label="Tasks done" value={String(snapshot?.metrics?.tasks_completed ?? 0)} /> } label="Downlink units" value={(snapshot?.metrics?.downlink_units ?? 0).toFixed(1)} />

Fleet Status

Satellites

{(snapshot?.satellites ?? []).map((satellite) => (
Sat {satellite.id} {satellite.last_action}
{satellite.battery.toFixed(0)}%
{satellite.storage.toFixed(0)}%
{satellite.altitude_km.toFixed(0)} km altitude {satellite.longitude.toFixed(1)}° lon
))}

Network

Ground stations & transfers

{(snapshot?.ground_stations ?? []).map((station) => (
{station.name} {station.latitude.toFixed(1)}°, {station.longitude.toFixed(1)}°
{station.capacity.toFixed(1)} Gbps
))} {(snapshot?.transfers ?? []).map((transfer) => (
{transfer.kind === "downlink" ? "Downlink beam" : "Capture sweep"} Sat {transfer.satellite_id} · {transfer.amount.toFixed(1)} units {transfer.kind === "downlink" && transfer.ground_station_id !== undefined ? ` · GS ${transfer.ground_station_id}` : ""} {transfer.kind === "capture" && transfer.region ? ` · ${transfer.region}` : ""}
{transfer.throughput.toFixed(1)} MB/s
))}

Conditions

Weather & queue

{weatherSummary.map((item) => (
{item.region} {Math.round(Number(item.cloudCover) * 100)}% cloud cover
))}
{(snapshot?.pending_tasks ?? []).slice(0, 5).map((task) => (
{task.id} {task.type.replaceAll("_", " ")} {task.type === "image_capture" && task.region ? ` · ${task.region}` : ""} {task.type === "data_downlink" && task.station !== undefined ? ` · GS ${task.station}` : ""}
))}
); } function MetricCard({ icon, label, value }) { return (
{icon}
{label} {value}
); } export default App;