05
Orbit
INDEPENDENT EXPERIMENT · 2026
Live satellite orbits from public TLE
Overview
A web experiment that draws satellites where they are now from public two-line elements (TLEs).
No map tiles or live-position API: orbital elements fetched at build time are propagated in the browser alongside a globe.
Select a point to reveal one orbit and its current altitude, speed and coordinates.
Problem
Satellite data usually arrives as a static result on a map. In reality, objects at different altitudes and periods are continuously moving around the same Earth.
I wanted a compact working object that shows that motion without depending on an external service at every visit or overwhelming the screen with thousands of points.
Constraint
No dependency on a live-position API
Calling an external API while the page runs turns CORS, outages and rate limits into UI failures. Orbital elements are not a position but the material for calculating one, so a single fetch can be propagated again in the browser for any time.
Many points, still legible
Drawing every active satellite becomes a point cloud. I selected public stations, science, weather and GPS groups instead, keeping a density that can be selected while still showing different altitudes and inclinations.
Explain Earth without making it heavy
Photo textures pull focus and add network cost. Simplified coastlines and a latitude-longitude grid leave just enough reference to read what part of Earth a satellite is passing over.
Decision
TLE at build time, propagation at runtime
A collection script writes CelesTrak TLEs to static JSON. The page fetches only that file, uses satellite.js to calculate ECI coordinates at the current time, then converts them to latitude, longitude and altitude. The deployment is static, but the points move at the time you open it.
Draw an orbit for only the selected satellite
Pre-drawing every orbit covers the globe in lines and raises the cost. On selection, one period is sampled from that satellite’s mean motion and only its path is drawn. Without a selection, the moving points remain the whole story.
Auto-rotate, then let the hand explore
The globe starts with a slow rotation to establish the object as 3D. Dragging pauses that rotation and clamps the vertical tilt so Earth cannot flip over. With reduced motion enabled, it starts still.
Interface
Loading orbits…
DRAG TO ROTATE · SELECT A SATELLITE
Engineering
- TLE groupsPublic orbital elements are grouped at build time
- satellite.jsCurrent ECI position and velocity are propagated
- GeodeticConverted to latitude, longitude and altitude for Earth
- Three.jsPoints, coastlines and a selected track render in one scene
Update positions every 120 ms
Propagation does not run on every frame. Every 120 ms, only the point buffer is rewritten. Rendering stays fluid while calculation happens only as often as orbital movement becomes visible.
A bad element cannot stop the whole view
If one TLE pair cannot be parsed or propagated, only that item is skipped. A clear state message appears only when the data files themselves cannot be loaded.
No memory left behind when it disappears
The resize observer, pointer listeners and animation frame are all released when the component unmounts; Three.js geometries, materials and the renderer are disposed too.
Result
The static portfolio now contains an interactive 3D scene driven by real orbital elements without an external runtime API.
Data can be refreshed at the next build, and a visitor can select one satellite to inspect its current position and one complete path.
Orbital elements come from CelesTrak public data and coastlines from Natural Earth 1:110m data. TLE prediction accuracy degrades over time, so the data is refreshed at the next build.