Skip to content

About

3D globe of the world’s air traffic with a cargo-only filter, altitude and ground filters, callsign search, region fly-to, live operator and country rankings, and a flight card with the route drawn on the globe.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Flightline

A live 3D globe of the world's air traffic. Around 10,000 aircraft, updated from the OpenSky Network, glide across a dot-matrix Earth with real day and night. Filter to cargo operators, slice by altitude, search a callsign, and click any aircraft for its details and route.

Live demo →

Built with Three.js r186, TypeScript and Vite. No framework and no backend: it runs entirely in the browser, with an optional proxy for production.

What it does

  • Live traffic: every aircraft OpenSky can see, refreshed about every 75 seconds. Between updates, each one keeps flying along its great circle at its reported speed and heading.
  • Cargo view: freight operators (FedEx, UPS, DHL, Cargolux, Atlas and others) are highlighted in amber, with a one-click "Cargo only" filter.
  • Filters: an altitude range, aircraft on the ground, and callsign search with suggestions.
  • Flight details: altitude, speed, heading, climb rate and registration. A route lookup draws the great circle from origin to destination, solid behind the aircraft and dashed ahead.
  • Live summaries: counts, busiest operators and countries of registration, all following the filters.
  • Fly-to: regions, plus a Follow this aircraft camera.
  • Shareable links: …/flightline/#UPS231 opens straight to that flight.
  • Phones: the panel becomes a bottom sheet.

How it works

GPU dead reckoning. All aircraft are one InstancedBufferGeometry draw call. Each instance stores its last position fix, heading, speed and fix time. The vertex shader moves it to "now" every frame along its great circle, using P(d) = cos d · P₀ + sin d · T₀, and orients it to its new heading. The CPU never updates a position between API calls. Instance times are stored relative to a base epoch, so they fit in 32-bit floats. (src/globe/flights.ts)

Picking without raycasting. Clicks and hovers run the same dead reckoning on the CPU, project the visible aircraft to the screen, and take the nearest within a few pixels, skipping any behind the globe. A unit test checks that the shader's vector maths matches the CPU formula. (tests/geo.test.ts)

A respectful API client. The feed controller (src/data/feed.ts):

  • polls every 75 s, slowing down as OpenSky reports fewer credits left;
  • honours 429 and X-Rate-Limit-Retry-After-Seconds;
  • backs off exponentially on errors, from 30 s up to 10 min;
  • times out hung requests;
  • pauses entirely while the tab is hidden.

Never an empty globe. If live data can't be reached, the app falls back, in order, to:

  1. a recorded snapshot, if you made one locally with npm run snapshot, replayed as if it were captured just now;
  2. simulated traffic on real routes between hub airports.

The status pill always says which one you're looking at, and why.

The Earth. Land comes from Natural Earth (via world-atlas). It is painted once into an equirectangular mask, with rings that cross the antimeridian unwrapped first, and then sampled on an equal-area dot grid. Borders are a LineSegments mesh. The ocean, dots and atmosphere shaders all share one sun direction, computed from the date. The land dots shrink as you zoom in, and the view is offset so the globe centres in the space the panel leaves free. (src/globe/earth.ts)

Data and limits

Source Used for Notes
OpenSky Network REST API Live positions Anonymous use: 400 credits a day per visitor, and a global query costs 4.
adsbdb Origin and destination for a callsign A crowd-maintained schedule, so it can be wrong for a given day. Labelled as the scheduled route.
Natural Earth via world-atlas Land and borders Public domain

OpenSky's terms. OpenSky licenses its data for non-profit research and education, and asks for written permission before its API is used in a live product or service. Its terms also forbid redistributing the data, which is why recorded snapshots are git-ignored and never committed here. If you publish a fork, ask OpenSky first, or build the demo mode, which uses simulated traffic only: set VITE_LIVE=off, or the LIVE repository variable to off.

Citation: The OpenSky Network, https://opensky-network.org. M. Schäfer, M. Strohmeier, V. Lenders, I. Martinovic and M. Wilhelm, "Bringing up OpenSky: A large-scale ADS-B sensor network for research", IPSN 2014.

The "cargo" label comes from a hand-made list of freight operators by callsign prefix (src/data/airlines.ts). Passenger airlines' belly cargo isn't counted.

Going to production: the proxy

Out of the box, each visitor calls OpenSky directly with their own allowance. Serving one shared, cached feed to the public counts as operational use, so get OpenSky's permission first. proxy/ holds a small Cloudflare Worker that adds CORS headers, caches each update for 30 s so every visitor shares one feed, and can use an OpenSky API client for a larger allowance. Set its address as the FLIGHTS_URL repository variable and GitHub Actions builds it in. See proxy/README.md.

Running it

npm install
npm run dev        # http://localhost:5173
npm test           # unit tests (Node's built-in test runner)
npm run build      # type-checks, then builds to dist/
npm run snapshot   # records live data into public/data/snapshot.json (local only, git-ignored)

Deploying: in the repository, go to Settings → Pages and set Source to GitHub Actions. Every push to main then tests, builds and deploys through .github/workflows/deploy.yml.

Project structure

index.html              page and panel markup
src/
  main.ts               scene, camera, fly-to, panel, filters, search, selection, loop
  geo.ts                great circles, dead reckoning, bearings, the sun's position
  globe/earth.ts        ocean, dot-matrix land, borders, atmosphere, day and night
  globe/flights.ts      instanced aircraft, dead-reckoned in the vertex shader; picking
  globe/route.ts        the selected flight's route
  data/opensky.ts       OpenSky client and state-vector parser
  data/feed.ts          polling, rate limits, backoff, fallbacks
  data/simulated.ts     fallback traffic between real hubs
  data/airlines.ts      callsign prefix → operator, cargo flag
  data/routes.ts        adsbdb route lookup
  ui/format.ts          feet, knots, headings, "40 s ago"
  style.css
tests/                  unit tests
scripts/snapshot.mjs    records a snapshot
proxy/                  optional Cloudflare Worker

Licence

MIT. See LICENSE. The flight data belongs to its providers and is used under their terms.

About

3D globe of the world’s air traffic with a cargo-only filter, altitude and ground filters, callsign search, region fly-to, live operator and country rankings, and a flight card with the route drawn on the globe.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages