Drop or click to upload your GTFS .zip file (max 250 MB). The app reads it entirely in your browser — nothing is sent to any server. After loading, a file manifest shows which GTFS files were detected.
Key files: stops.txt, routes.txt, trips.txt, stop_times.txt, calendar.txt, and optionally calendar_dates.txt.
Browse your feed — routes, agencies, calendar services and stops — in sortable, searchable tables. The Routes tab shows a Variants count per route: click it to see each distinct journey variant (grouped by stop sequence, so trips sharing a stop pattern are one variant even if the feed gives them different shape IDs) with its trip count. The Variability button opens the run-time variability explorer: pick a date, route and variant and it plots every one of that variant's trips by total run time against departure time, with a rolling median line and an inter-quartile band, plus headline stats (median, spread, range, hours of operation, trip count). Variants that don't run on the chosen date are greyed out. It's the quickest way to see whether a variant's run time is stable or peak-sensitive before you build anything.
Choose a single analysis date that has active services. Run times come only from the trips operating that day — using one date keeps the sample clean, since pooling several days would blend different service patterns. Also set the time band granularity (15/30/60 min) and run time rounding precision.
Click stops on the map to build a run sequence. After each selection, the stops reachable directly from the last selected stop are shown in green, sized and shaded by popularity — the number of direct trips running to them. The exact count, the routes serving a stop and its ID appear in a card when you hover. Selected and reachable stops always stay visible — they never collapse into a cluster. Use Copy IDs / Copy names to lift the sequence to your clipboard. Create up to 20 named patterns; search top-left or paste stop IDs directly. At low zoom, other nearby stops collapse into slate square clusters — zoom in to break them apart. A map key (bottom-left) starts collapsed — click its header to expand it; it explains every symbol.
Reachable — many direct trips
Reachable — some direct trips
Reachable — few direct trips
Run times are shown per time band per stop pair, keyed on departures from each leg's own upstream stop (so congestion shows up leg by leg). For each band the app buckets trip durations to your rounding precision and takes the mode; if no value genuinely repeats it falls back to a trimmed mean (≥6 trips) or a median (fewer). Hover any measured cell to see which method and how many trips produced it. Empty bands are filled by linear interpolation between the two nearest measured bands (amber). Where a leg has very few, widely varying measured trips, interpolated cells are hatched and flagged as unreliable — check the variability chart. Where one leg is served by more than one route or journey variant (e.g. a direct run vs an estate loop), Edit routes & variants opens a map-based picker: switch legs with the tabs, then click a route on the map or in the popularity-ranked side list to choose it (the most-used option is recommended), optionally splitting a leg by time of day. If the source timetable has built-in dwell time at any of your pattern's stops (a vehicle waiting, i.e. departure later than arrival), an amber notice lists those stops — run times are measured stop-to-stop, so that waiting isn't included in any leg. Every cell is editable, including No data, No service and outside-operating-hours (—) cells; manual values flow straight to the Timetable.
Interpolation example: if 06:00 measures 10 min and 12:00 measures 16 min with the bands between empty, the old method gave a flat 12.1 min all morning then jumped to 13.9 at noon. Linear interpolation instead ramps smoothly — about 11 min at 07:00, 13 min at 09:00, 15 min at 11:00 — straight-lined between the two measured anchors.
Select a pattern and anchor stop. Type a departure time in the anchor column — just four digits works (0830 → 08:30; 2515 → 25:15 for after-midnight). Every other stop time is computed from your run times, identically whichever stop you anchor on. The Run time column shows each trip's total length, first stop to last. Override any cell by typing in it; if a trip runs backwards it's flagged red. Where a leg has no run time at all — nothing measured, interpolated, or nearby to borrow — it defaults to 0 seconds so the draft stays complete, but those stop times and the affected trip total are highlighted red so you can see they're unfounded. Fill the leg in on Results to clear the flag. Add trips with +, reorder by drag, and export to CSV (zero-filled values are marked there too).
A few things worth knowing before you rely on the output:
- Service-day clock, 04:00–28:00. Time bands span a 24-hour service day from 04:00 to 28:00 (i.e. 04:00 the next morning). After-midnight trips should be entered on this 24+ clock —
2700 for a 3 a.m. trip, not 0300. A trip placed before 04:00 or after 28:00 falls outside every band, so its legs borrow a representative run time rather than a time-of-day-specific one.
- Needs a connection for the map. The tool runs fully in your browser and never uploads your data, but the Pattern Builder and route-picker maps fetch tiles (and, on first load, fonts and the mapping library) from the web. Offline, the maps degrade to lines on a blank background.
- One time per stop. The timetable models a single time at each stop, so built-in dwell at a stop isn't shown as a separate arrival/departure. It's detected and flagged on the Results page instead, but isn't added into the run times.
- Dwell flag isn't variant-filtered. The dwell notice looks at every active trip passing through a stop in pattern order, not only the route/variant you selected for the adjacent legs.
- One date at a time. Analysis is intentionally limited to a single service date to keep the sample clean; the tool doesn't pool multiple days.
- Main-thread parsing. Very large feeds are parsed in chunks on the main thread (with progress shown). Feeds beyond roughly 80 MB still work but can be slow — trimming the feed first helps.