Self-hosted and offline-first, rather than a cloud maps SDK. Japan has good LTE
coverage, so this is not the argument it would be in a sparse country — it rests
on tunnels, of which Japan has a great many, plus mountain roads and urban
canyon. Independently: a map that round-trips to a cloud API in order to pan is
the wrong shape for a car whatever the coverage, and holding the data locally is
what makes map matching against recorded sessions possible at all.
| Piece | Choice | Role |
|---|---|---|
| Basemap tiles | Protomaps **PMTiles**, Japan extract | Single file, static-served; no tile server process |
| Renderer | **MapLibre GL** | Basemap, own position, trace, route line |
| Routing | **Valhalla** | Route and turn-by-turn, from OSM tiles built offline |
Valhalla over GraphHopper for three reasons: it is C++ with memory-mapped tiles
rather than a JVM holding a resident graph, which suits an 8 GB Jetson; it
targets embedded and automotive use explicitly; and it ships **Meili** map
matching.
That last point is why this is not a detour from the roadmap. Meili's
`trace_attributes` snaps a recorded GNSS trace onto OSM and returns road
attribution along it — speed limit, road class, geometry. That is *ground truth
for validating reverse-engineered CAN signals* in Phase 2, and it pays off
before any navigation UI exists.
A moving map — position, heading and trace, no routing — is most of the value in
a car and needs only the renderer and a GNSS fix. Routing is the expensive 20%
and comes last.
### Guidance on the bus, route requests over HTTP
Guidance is state, so it belongs on the bus: `yukart/nav/guidance` carries the
next manoeuvre, retained, and a display connecting mid-drive renders immediately.
Route *requests* are request/response and fit MQTT badly. Displays call the
Valhalla HTTP API through `telemetry-gw` instead of inventing a request/reply
topic pair. Recorded as decision 9.
### Map data is not source
Basemap and routing tiles are large binary artifacts rebuilt from upstream OSM.
They are never committed. `tool-mapmint` holds the scripts that fetch and build
them, plus a report of each build's provenance; `svc-nav` consumes the output. The
artifacts themselves live outside git and never touch the workstation-side repo.
They reach the car by `rsync`**over the LAN only, never over LTE** — the IoT SIM
is not a sensible transport for a multi-gigabyte tile set. Gate the sync on a
reachable LAN target rather than on an SSID, so the check validates the thing it
actually needs, and treat NetworkManager's metered flag as a second guard.
Cadence is quarterly or on annoyance; road geometry does not move fast enough to
justify anything more.
Swap atomically. Build beside the live copy, symlink-swap, restart Valhalla —
never overwrite tiles in place while the server is reading them. The basemap is
one file, so write-then-`mv` covers it with no restart.
This also settles the tile *form*: the **directory** wins over the `.tar`, twice
over — once for RAM on an 8 GB board, and once because rsync deltas a tree of
changed files efficiently where a single multi-gigabyte tar forces a full-file
checksum at both ends.
### Japan specifics
| Concern | Consequence |
|---|---|
| **Left-hand traffic** | `valhalla_build_admins` builds the admin database that determines driving side. It is a separate step *before* the tile build, and the database is used only at build time, not by the running server. Skip it and Valhalla routes and narrates as though Japan drove on the right. |
| **Data volume** | The whole-Japan PBF is **2.3 GB** — Japan is among the more densely mapped countries in OSM. Routing tiles and basemap scale with it. Geofabrik publishes per-region extracts (Kantō, Chūbu, Hokkaidō, …); start with the region actually driven, not the whole country. |
| **CJK labels** | MapLibre cannot ship Japanese glyph sets as SDF ranges — far too large. Set `localIdeographFontFamily` so the browser renders CJK from on-device fonts. Protomaps tiles also carry `name:en`, so romanised labels are an option. |
| **Addressing** | Japanese addresses are block-based, not street-based. Valhalla does not geocode at all, so destination search is a separate problem — do not assume a western geocoder transfers. |
### Known risk
Valhalla's arm64 container story is unsettled upstream. Confirming that Valhalla
builds and runs on the Jetson is the **first** task in this workstream, before