Skip to content

Repository files navigation

gtfs-rt-simulator

Standalone transit vehicle simulator. Given a GTFS static feed (zip or extracted directory), it simulates vehicles following their scheduled routes and serves a GTFS-RT VehiclePositions feed over HTTP.

Designed as the sibling of DM (transit-detour-manager): the simulator produces the real-time vehicle layer, while DM continues to emit TripUpdates / TripModifications / Alerts. The detours.json format and the vendored proto/gtfs-realtime.proto are shared and round-trip compatible with DM.

Scope

  • Output is VehiclePositions only — no TripUpdates / Alerts / TripModifications.
  • Vehicles follow prescribed routing only: the GTFS shape, or the stitched detour shape when a detour is active. No off-route deviation.
  • Deterministic when a --seed is provided: the same seed and clock produce identical trajectories.

Quick start

npm install
npm run dev -- serve test/fixtures/gtfs-minimal --time 2026-07-15T12:00:00

Or build and run the compiled CLI:

npm run build
npm start -- serve path/to/gtfs.zip --port 4100

Open http://localhost:4100/health to confirm it is running.

CLI

gtfs-rt-simulator serve <gtfs.zip|dir> [options]
Option Description
<gtfs.zip|dir> Path to a GTFS static feed, either a zip file or an extracted directory.
--time <iso> As-of start time (ISO 8601). The simulation clock starts there and advances with wall time. Defaults to wall-clock now. Validated against the feed's calendar range; errors if outside it, warns if no service runs that day.
--port <number> HTTP port (default 4100).
--seed <number> Deterministic RNG seed.
--config <path> Path to a JSON config file (see below).
--detours <file> Path to a DM-compatible detours.json file (re-read when the file changes).

Config file

{
  "port": 4100,
  "tickIntervalMs": 1000,
  "seed": 42,
  "speedNoise": { "enabled": true, "std": 0.1, "clamp": [0.7, 1.3] },
  "dwellMs": 15000,
  "delay": { "probability": 0.2, "minS": 30, "maxS": 120 }
}
  • speedNoise — per-vehicle speed variation (normal distribution clamped to clamp).
  • dwellMs — base dwell time at each stop.
  • delay — random extra dwell on stop arrivals: probability 0..1, uniform seconds within [minS, maxS]. All randomness flows through the seeded RNG.

HTTP API

Method Path Description
GET /gtfs-rt GTFS-RT VehiclePositions feed (application/x-protobuf). Cached ~15s.
GET /gtfs-rt.json Same feed as JSON, for debugging.
GET /health Vehicle count, uptime, and config summary.
GET /api/vehicles All simulated vehicles.
GET /api/vehicles/:id A single vehicle (404 if unknown).
POST /api/vehicles/:id/hold Body { "seconds": 60 } — hold at the next stop.
POST /api/vehicles/:id/release Release an active hold.
POST /api/vehicles/:id/breakdown Body { "seconds": 60 } — freeze the vehicle in place.
POST /api/vehicles/:id/speed Body { "factor": 0.8 } — rescale the vehicle's segment speeds.
POST /api/vehicles/:id/teleport Body { "lat": .., "lon": .. } or { "distanceAlongShape": .. } — reposition on the current shape.
GET/PUT /api/config Read / update runtime tunables (dwellMs, speedNoise, delay, seed).

No authentication — this is a local tool.

detours.json

A DM-compatible array of detour objects. Only fields used by the simulation are required; extra DM fields round-trip unchanged.

[
  {
    "id": "detour-1",
    "routeId": "route-1",
    "directionId": 0,
    "startStopId": "stop-b",
    "endStopId": "stop-d",
    "replacementStops": [{ "stopId": "stop-c", "stopName": "Stop C", "lat": 41.882, "lon": -87.63, "travelTimeFromPrevious": 300 }],
    "detourShape": [[41.881, -87.63], [41.883, -87.63]],
    "startTime": "2026-07-15T00:00:00",
    "endTime": "2026-07-15T23:59:59",
    "description": "Road work on Main St",
    "createdAt": "2026-07-01T00:00:00"
  }
]

A vehicle switches to the stitched detour shape when it is still before the startStopId diverge point; if the detour is cleared or expires before the vehicle reaches that point, it reverts to the original shape.

Development

npm run dev          # tsx watch
npm run build        # tsc
npm start            # node dist/cli.js
npm test             # vitest (watch)
npm run test:run     # vitest once
npm run test:coverage
npm run lint         # eslint
npm run lint:fix
npm run format       # prettier
npm run format:check

Tests run fully offline against the committed fixture in test/fixtures/gtfs-minimal (Vitest, test/unit). Verify = build + test:run + lint all green.

Architecture

  • src/gtfs/ — GTFS static loading (zip or dir) into SQLite (better-sqlite3).
  • src/sim/ — simulation engine, seeded RNG (mulberry32), vehicle types. No HTTP, no fs.
  • src/detours/DetourSpec type plus file and in-memory providers.
  • src/feed/ — protobuf encode/decode and the VehiclePositions feed emitter.
  • src/api/ — express: feed endpoints plus the JSON control API.
  • src/cli.ts — commander entry point.

Dependency direction: cli → api → {feed, sim} → {gtfs, detours}. The simulation engine never imports the API or feed modules.

License

MIT

About

GTFS-rt Vehicle Positions feed simulator -- takes static GTFS and simulates vehicle movements

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages