Polaris
A world intelligence website: wildfires, storms, earthquakes, aircraft and satellites on a live 3D Earth, each with its source and the time it was observed.
- Status
- Live
Deployed on Vercel; stored history in PostGIS is the next phase
- Role
- Owner and developer: product scope, data pipeline, the globe engine and the site.
- Built with
- Next.js 16, React 19, TypeScript, CesiumJS, satellite.js (SGP4), zod, Tailwind CSS, Vitest, Playwright, axe-core



The problem
Earth-observation data is public but scattered across agency feeds with different formats, limits and update rates. Polaris puts it on one globe and labels every object with where it came from and how old it is, so a visitor can trust what they are looking at.
How it works
- Server routes collect from NASA EONET, USGS, OpenSky, CelesTrak, NASA GIBS and Open-Meteo. Every response is validated with zod and normalised into one domain model.
- Collectors fetch only when someone asks and the cache is due, never run two requests at once, keep serving the last good copy on failure, and back off for exactly as long as a provider's Retry-After says.
- CesiumJS renders NASA Blue Marble with real VIIRS city lights on the night side. Rendering stays out of React: aircraft are billboards in collections and satellites a point collection propagated once a second with SGP4.
- The scene renders on demand, so an idle globe costs almost nothing, and a 7-day timeline replays recorded observations.
Decisions that mattered
- The browser never talks to rate-limited providers
- The server holds every credential and enforces each provider's limits; browsers only load NASA imagery tiles directly.
- On-demand, single-flight collection
- An idle site spends no provider quota, which matters with anonymous OpenSky's 400 credits a day.
- Estimates are labelled as estimates
- Satellite positions are SGP4 estimates from published elements, not tracking, and the detail panel says so.
- Privacy by construction
- No accounts, cookies or analytics. Aircraft appear only by broadcast identifiers; owners are never looked up.
Problems I had to solve
Thousands of aircraft without React re-rendering
About 10,000 aircraft and every tracked satellite are drawn as Cesium primitives that React drives through method calls on a GlobeEngine, instead of components that re-render each update.
Living inside provider limits
Anonymous OpenSky allows roughly one global snapshot every 15 minutes, and CelesTrak asks not to be polled faster than every 2 hours. Each feed has its own refresh policy and freshness threshold, and the Sources page shows the live state of every one.
What is verified, and what isn't
| Part | State |
|---|---|
| 41 unit tests passing for normalisers, the collector, geo maths and SGP4 (run 25 Oct 2026) | Verified |
| Live on Vercel at polaris-seven-ashen.vercel.app | Verified |
| Playwright end-to-end and axe accessibility specs | Built, not yet verified |
| Stored history in PostgreSQL + PostGIS on an Oracle VM | Blocked |
Taken from the project's own status documents.
Still unfinished
- PostgreSQL + PostGIS on the Oracle VM for stored history
- Docker Compose and an HTTPS reverse proxy for the server phase
- Authenticated OpenSky access for a faster aircraft refresh

