a living map of the Indian Railways timetable. every train, drawn in light.
Live: deploy pending · Stack: Vite + TypeScript + raw WebGL2, zero runtime dependencies
India does not publish live GPS for its trains. It publishes something almost as good, and arguably more poetic: the timetable. This site plays the published schedule against the clock — every glowing point is a scheduled train placed by interpolation, exactly where it should be right now if the day went to plan.
It is not GPS. It is the timetable, dreaming.
The rail network on screen is not a basemap. It is the union of every train's station-to-station path — the railways draw the country themselves. Night falls across the map where the sun actually is (analytic terminator), and trains burn brighter after dark.
- 9,298 trains simulated from 183,499 timetable rows, each running only on the days it actually runs (real weekday masks, not "assume daily")
- 9,409 geocoded stations; 15,273 unique rail segments, 12,453 of them routed along real OSM track geometry (Dijkstra over a 612k-node rail graph)
- ~2,000–2,900 trains moving at any given moment, depending on hour and weekday
- simulation cost: ~0.3 ms per frame; rendering is one instanced draw call
- data payload: ~2.5 MB over the wire
pipeline/build-data.mjs raw datameet dumps -> compact binaries (run: npm run data)
public/data/trains.bin per-train stop chains, minutes since IST midnight, u16s
public/data/network.bin unique station-pair segments (the veins)
public/data/stations.json station index; array position = stationIdx everywhere
pipeline/extract-rail.mjs osm pbf -> rail graph -> Dijkstra per station pair ->
public/data/paths.bin simplified real-track polylines (80% of segments)
src/sim.ts the engine: binary-search the active segment per train,
walk real track polylines arc-length-parametrized,
handle multi-day journeys (a Kanyakumari–Dibrugarh run
spans 4 calendar days), dwell at stations, allocation-free
src/gl.ts five passes: veins (additive), coast, station dots,
day/night terminator, instanced comet sprites
src/camera.ts hand-rolled mercator camera: drag, wheel, pinch, inertia
The timetable data includes run-through stations (arrival == departure), so a long-haul train has ~200 waypoints, which is why trains follow believable track curves without any OSM routing.
- Schedules are pulled from India's National Train Enquiry System and are current as of the build (Vande Bharats included). The pull is unofficial; treat exact times as indicative.
- Each train runs only on the days its schedule says it does. Station coordinates come from OpenStreetMap; ~200 obscure halts we couldn't place are skipped, with time continuity preserved.
- Without the live layer, delays do not exist here — this is the intention, not the outcome. For the outcome, ask any passenger at Mughal Sarai (now DDU).
npm install
npm run data # rebuild binaries from pipeline/raw (raw dumps not committed)
npm run dev # http://localhost:5199
npm run build # production bundle
npm run shot # screenshot via playwright (my eyes during development)Deep links: ?t=12951 follows a train · ?at=21:30 time-travels · ?chrome=0
hides UI for captures. Keyboard: / search · space pause · esc close.
Timetable and station data collected by the DataMeet
community (datameet/railways, CC0).
India land boundary from datameet/maps. Track geometry (public/data/paths.bin)
is a derived database of OpenStreetMap
data, © OpenStreetMap contributors, ODbL. Code is MIT (see LICENSE).
The raw source dumps in pipeline/raw/ are not committed (1.7 GB of OSM pbf
plus the datameet JSONs); the compiled binaries in public/data/ are, so a
fresh clone runs with npm install && npm run dev. Built by shwetank.
