Public transport map across Great Britain and Ireland
- Python 86.1%
- HTML 10.9%
- JavaScript 1.5%
- Shell 0.5%
- Dockerfile 0.4%
- Other 0.6%
The two panels on the left were 272px of a screen whose subject is underneath them. The stack goes to 216px and the key to 150px, which is the first panel here to be narrower than the stack it sits in: nothing in it is prose -- eight mode names, a bar each and one row of ticks -- so the width it needs is the width of the widest of those and not the width of the panel above. The header is the same height at the new width rather than taller, because the title column now takes the whole row and the buttons take the next one. The 110px floor `base.css` puts on that column is what a 272px panel wanted: there the row held the title and three of the four buttons and wrapped the fourth alone, which is a ragged two rows where this is a tidy one plus one. The placeholder loses "Filter by", which the input's own label still says and which did not fit. Six ticks reading 3 to 1000+ are 107px of text and want a bar of 270 to stand clear of each other -- wider than the key needs for anything else in it, and on a 150px panel "300" and "1000+" print on top of each other. So `thinTicks` drops every second one, then every third, until what is left stands clear: 3, 100 and 1000+ on the desktop panel, all six on a phone, where the key is the width of the screen. Both ends are kept whatever the step, because they are the range, and that is the one thing a bar with no numbers under it cannot say. Measured rather than counted, because how many fit is the reader's font size as much as the panel's width. Thinning from the left was the first try and it packs the labels at the low end and leaves a hole before the last, which reads as a fault rather than as a scale. A `ResizeObserver` is what runs it again: the key folds away at some widths, a fold has no width to measure against, and the call sites for the fold, the window and a phone turning would be three and would go on being three. |
||
|---|---|---|
| .github/workflows | ||
| .vscode | ||
| deploy | ||
| docs | ||
| scripts | ||
| tests | ||
| wayfare | ||
| web | ||
| .dockerignore | ||
| .env.example | ||
| .envrc | ||
| .gitignore | ||
| .hadolint.yaml | ||
| .taplo.toml | ||
| biome.jsonc | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| flake.lock | ||
| flake.nix | ||
| pyproject.toml | ||
| README.md | ||
Wayfare
Wayfare builds an aggregate dataset of public transport routes across Great Britain and Ireland. It produces a PMTiles archive, a tiled hierarchical map file, behind an interactive map where hovering a road lists the services on it.
Quick start
Wales is 41 MB zipped and exercises every stage, which makes it a better first run than the national bundle. WAYFARE_REGION and WAYFARE_OSM_URL must describe the same area.
$ cat > .env <<'EOF'
WAYFARE_REGION=wales
WAYFARE_OSM_URL=https://download.geofabrik.de/europe/united-kingdom/wales-latest.osm.pbf
EOF
$ direnv allow # or: nix develop
$ docker compose up -d valhalla # builds its graph before it answers anything
$ wayfare acquire --region wales # resolves its own extract URL from --region
$ wayfare patterns
$ wayfare match # the long one
$ wayfare aggregate
$ wayfare publish
$ wayfare status
$ wayfare serve # viewer on http://localhost:8099
On a server
$ docker compose up -d valhalla # first start builds the graph
$ docker compose run --rm pipeline # every stage, acquire through publish
$ docker compose up -d web # viewer and renderer on :8099
pipeline runs wayfare all, which is safe to interrupt and re-run, since every stage skips work already done. It runs the same stages in the same order as deploy/refresh.sh, which is for incremental updates on a schedule.
Data sources and licences
| Source | Covers | Licence |
|---|---|---|
| DfT Bus Open Data Service (BODS) GTFS | Great Britain | Open Government Licence (OGL) v3.0 |
| NaPTAN stop register | Great Britain | OGL v3.0 |
| National Transport Authority (NTA) GTFS, published as Transport for Ireland | Republic of Ireland | Creative Commons Attribution (CC BY) 4.0 |
| Translink TransXChange timetables and MapInfo route geometry, via OpenDataNI | Northern Ireland | OGL v3.0 |
| Geofabrik OpenStreetMap extracts | all three | Open Database License (ODbL) |
Further reading
docs/pipeline.md— the nine stages, storage, clustering, tiles.docs/data.md— the feeds, their traps, mode filtering, coverage gaps, attribution.docs/deploy.md— the scheduled refresh, and the publish gate that guards it.
