Inspiration
On February 10, 2009, a satellite that had been dead for over a decade, Russia's Cosmos 2251, slammed into a working Iridium 33 communications satellite about 790 km above Siberia. A dead machine killed a living one, and the crash created thousands of new fragments that are still circling Earth today.
Halloween is about the dead that won't stay buried. Earth's orbit is exactly that: a graveyard where nothing is ever really laid to rest. The LancerHacks theme was space, so I took it three ways: outer space, Halloween ghosts, and the fact that we are literally running out of space in orbit.
What it does
Ghost Orbit is an interactive 3D globe that shows real space debris as ghosts, at their real positions, moving in real time.
- 1,300+ tracked ghosts from three real disasters: the 2009 Cosmos–Iridium collision, the 2007 Fengyun-1C anti-satellite missile test, and intact "zombie" satellites like Vanguard 1 (1958) and Telstar 1, which was killed by a nuclear test.
- Ghost Radar: filter between intact dead satellites and collision shrapnel, with a breakdown by disaster.
- The Haunted Zone: an altitude histogram showing where debris is most crowded (around 700–800 km), next to sourced ESA figures on the total debris population.
- Near-Miss Detector: predicts the 5 closest approaches between debris objects in the next hour, with miss distance, time, and relative speed. Click one and the camera flies there and links the two ghosts in red.
- Haunted transmissions: click any ghost to hear its story. Claude writes a first-person ghost story using only verified historical facts about that object, and ElevenLabs voices it through a custom "haunted radio" audio filter.
How we built it
- Frontend: React + TypeScript (TanStack Start), Tailwind, built with Lovable.
- 3D globe: globe.gl / Three.js, with custom ghost sprites and a camera path that curves around Earth instead of cutting through it.
- Orbital data: real Two-Line Element (TLE) sets from CelesTrak, fetched server-side and cached for 2 hours, with a bundled snapshot as a fallback so the demo never breaks.
- Orbital physics: SGP4 propagation with satellite.js, converting ECI coordinates to latitude, longitude, and altitude every few seconds.
- Near-miss analysis: runs in a Web Worker so the UI never freezes. It propagates every object in 60-second steps over the next hour (61 samples) and tracks each pair's minimum separation:
$$d_{\min}(a,b) = \min_{t} \lVert \mathbf{r}_a(t) - \mathbf{r}_b(t) \rVert$$
Comparing every pair would cost about $n^2/2 \approx 850{,}000$ checks per step. Instead, I sort by altitude and only compare objects within 10 km of each other in height (a sweep-line prune), which cuts that down massively. Relative speed is: $$\lVert \mathbf{v}_a - \mathbf{v}_b \rVert$$
- AI stories: a server function sends each object's verified facts to Claude (Anthropic API), with explicit "never invent or contradict" rules, so the horror is fictional but the history is real.
- Voice: ElevenLabs
eleven_multilingual_v2with tuned settings (low stability 0.22 for a trembling voice, style 0.8, speed 0.85). - Audio processing: a custom Web Audio API graph: a highpass and lowpass filter to mimic a radio channel, an LFO tremolo, and a feedback delay for a deep-space echo.
- Testing: Vitest unit tests for near-miss math, audio, voice config, and story handling.
Challenges we ran into
- Making ghosts clickable: at first they were tiny dots moving at orbital speed and almost impossible to click. I swapped them for glowing ghost sprites with bigger click targets, and added pause-on-hover plus a pause-spin button.
- Browser autoplay blocking: browsers block audio that isn't started by the user, so the ghost's voice sometimes never played. I routed playback through the Web Audio API and added a one-tap play button for when the browser delays it.
- The voice drowning in its own effects: the haunted-radio filter and background drone buried the narrator. I decoded the voice directly through Web Audio and rebalanced the effect levels so it sounds eerie but is still clear.
- Keeping the browser responsive: checking hundreds of thousands of pairs over 61 time steps froze the page, so the near-miss scan runs in a Web Worker with altitude pruning.
- SGP4 changes its satellite records as it runs: sharing them between the live globe and the scanner caused bugs, so the scanner works on its own copies.
- AI making up history: early stories invented details, so I locked each ghost to a verified fact sheet with explicit "forbidden" claims.
- Audio errors that failed silently: ElevenLabs error responses were being played as if they were audio. I added error handling, a visible retry, and cleanup so audio doesn't break after several clicks.
- Camera flights: the camera flew straight through Earth on its way to a near miss, so I rewrote the path to orbit around the planet.
- Scoping solo against a 7 PM deadline: I chose the idea within minutes, then planned backward from the deadline with a code freeze before recording.
Accomplishments that we're proud of
- I built this solo at my first hackathon, from idea to deployed app in about 4 hours.
- It uses real orbital mechanics (SGP4) on real CelesTrak data instead of fake animations.
- The near-miss detector gives an actual prediction, not just a picture.
- The full pipeline works end to end: real data, a fact-locked Claude story, an ElevenLabs voice, then a custom haunted-radio filter.
- The interface explains itself in plain English (the Haunted Zone and each disaster are described right on screen), so anyone can understand it in seconds.
What we learned
- How satellites are actually tracked: TLE data, SGP4 propagation, and ECI vs. geodetic coordinates.
- How serious the debris problem is: ESA estimates 36,500+ objects larger than 10 cm and about 130 million larger than 1 mm, and collisions happen at closing speeds over 10 km/s.
- Browser audio is harder than it looks: autoplay policies, AudioContext limits, and mixing effects without burying the voice.
- How to keep an LLM factual: give it only verified facts and explicitly list what it must not claim.
- How to build fast with AI tools (Lovable for building, Claude for planning and debugging) while still understanding and checking the code myself.
- Scoping: a polished small project beats an ambitious broken one.
What's next for Ghost Orbit
- Track all of CelesTrak's catalog (around 30,000 objects) with a spatial grid index for faster near-miss detection.
- Show live satellites at risk, such as the ISS and Starlink, next to the ghosts that threaten them.
- Visualize Kessler syndrome: a "what if" mode that simulates how one collision cascades.
- A classroom mode for teaching students about orbital sustainability.
Built With
- anthropic
- bun
- celestrak
- claude
- elevenlabs
- globe.gl
- lovable
- react
- satellite.js
- sgp4
- tailwindcss
- tanstack-start
- three.js
- typescript
- vite
- vitest
- web-audio-api
- web-workers
- zod
Log in or sign up for Devpost to join the conversation.