All projects

Sydney Rail Simulator

Drive the T1 North Shore line in your browser

Sydney Rail Simulator

A browser-based simulator of the Sydney Trains T1 North Shore line, Central to Hornsby via the Harbour Bridge (25 km, 20 stations). Everything on screen comes from open data: the track is from OpenStreetMap, the timetable is the real sydneytrains GTFS feed, and passenger demand is Opal patronage. You can drive a scheduled service from the cab, watch the whole morning peak run itself, or take over as the signaller.

The Harbour Bridge and the North Shore line in free camera

Best on desktop Chrome with WebGL2. Start at the menu for scenarios (The 07:39 Hornsby to Central, Recover a delayed peak), free drive, saves and settings.

A deterministic, headless sim core

The simulation is plain TypeScript with no DOM or renderer imports (enforced by lint), so it runs identically in the browser, in tests and in a headless fast-forward. A five-hour morning peak runs in about 3 seconds under Node.

  • Fixed 0.1 s timestep with O(1) work per train per step: each train's route is a 1-D path with precomputed prefix sums for elevation, curve resistance and tunnels.
  • Train dynamics: a longitudinal model with Davis resistance, gradient and curve (Röckl) resistance, traction limited by tractive effort, power and adhesion, and load-weighed, jerk-limited braking. It is unit-tested against published Waratah acceleration and braking figures.
  • Determinism: seeded PRNG sub-streams, id-ordered iteration, and every player or signaller action is a tick-stamped command. A save file is just the command log, and loading replays it and checks a per-minute state hash.

Signalling and interlocking

The signalling layout is generated from the track graph, not hand-drawn. Signals come from OSM, then from the published track-diagram km list where OSM has gaps. Routes run from signal to signal, and conflicts are derived from shared track sections and point positions.

  • Track circuits, 2- and 3-aspect automatic signals, and controlled signals with route setting.
  • Sectional route locking and release. Overlaps are proved clear rather than locked (locking them deadlocked the Gordon and Hornsby turnbacks).
  • Trainstops: passing a signal at danger (a SPAD) triggers the emergency brake.
  • Automatic route setting works in timetable order with platform reservation. The signaller panel can override it signal by signal.
  • Tests check that no conflicting route can ever be set and that a following train always sees the correct aspect.

Passengers

Aggregate queues per station and destination are fed by Poisson arrivals from an Opal-derived origin–destination matrix. Boarding depends on which destinations a train serves, and dwell time comes out of the busiest door, with crowding slowing it down. Loads are calibrated against published train-load data with one global scale factor.

Data pipeline

TypeScript scripts (run with tsx) share zod schemas with the sim:

  1. Track: Overpass (OSM) → track graph with points, curvature and gradient. Elevation comes from the NSW 5 m DEM, and tunnels and bridges are interpolated between portals. Chainage is calibrated to the published station km (median error 19 m against the km posts in signal names).
  2. Timetable: the GTFS feed, streamed from the zip, limited to the services that use the segment's tracks (including T9 through-running), with empty trains and turnbacks linked into train runs.
  3. Demand: Opal station entries and exits, time-of-day bands and a 2020 origin–destination seed.
  4. World: OSM buildings, roads, land use and trees, plus a wide DEM terrain.

The processed data is committed, and a byte-identical rebuild is tested.

3D and assets

The renderer uses Three.js with a floating origin, interpolation between sim steps, instancing for sleepers, trees and crowds, and day/night lighting. Every 3D asset is built by headless Blender scripts (vertex-colour palettes with a baked AO, exported as Draco GLB) and checked in a render-and-critique loop. Audio is WebAudio synthesis tuned to measurements of openly licensed Sydney recordings, and the announcements are speech synthesis.

Attribution

  • Track geometry, stations, buildings and signals © OpenStreetMap contributors, licensed under the Open Database Licence (ODbL) 1.0.
  • Timetable (GTFS), Opal patronage and train-load data: contains data from Transport for NSW Open Data, licensed under CC BY 4.0.
  • Elevation: NSW 5 m DEM © Spatial Services (NSW Department of Customer Service), CC BY 4.0.
  • Audio excerpts are CC0, CC BY and CC BY-SA recordings, credited individually on the in-app credits screen.

This is an independent fan project. It is not affiliated with Sydney Trains or Transport for NSW, and it uses no official logos or branding.

Status
Live
Stack
TypeScript, Three.js, Vite
Tags
simulation, 3d, data, transport
Updated