RoughRoute — waypoints in, a real road route out
An offline mini-router built on OpenStreetMap data. Give it ordered waypoints and it returns a polyline that follows real roads — with no network calls at runtime, in single-digit milliseconds.
Free and open source · Rust · MIT License
🧭 A straight line is not a road
Anything that simulates movement — a mock-GPS playback tool, a demo, a map animation — needs a path that looks like it was driven, not a straight line through buildings. Full routing engines solve that, but they are heavy, and most of them expect a server on the other end of a network call.
📦 Small enough to embed
RoughRoute does one thing: waypoints in, a plausible road-following line out. The map is compiled ahead of time into a compact map file that ships with your app, so at runtime there is no server, no API key, and nothing to rate-limit you.
What it does
📴 No network at runtime
Queries run against a pre-built map file on the device. Works on a plane, in a tunnel, or in CI with the network switched off.
🧩 One core, three shells
The same Rust core compiles to WebAssembly for the browser, a native Android library via UniFFI, and a command-line binary.
⚡ Single-digit millisecond queries
A* over a compressed road network. Fast enough to route on every frame of a playback, not just once at the start.
🗜 Map files measured in megabytes
Degree-2 collapse and delta-compressed geometry keep a usable region small enough to bundle or serve from a CDN.
🚗 Driving and walking
One map file carries both profiles through access bitmasks, so you do not build and ship the region twice.
🔁 Same input, same bytes
Routing is deterministic: the same waypoints and the same map file always produce the same line. Good news for tests that compare output.
⚙️ Three steps
- Ahead of time, compile an .osm.pbf region into a compact .graph file.
- Ship that file — bundle it with the app or put it behind a CDN.
- On the device, load that file and run queries locally. You get back the coordinates and the distance.
⌨️ From the command line
roughroute build region.osm.pbf -o region.graph
roughroute route region.graph \
--profile car \
--via 40.7128,-74.0060 \
--via 40.7580,-73.9855 \
--format geojson
Or from the browser, via WebAssembly:
const router = new WasmRouter(graphBytes);
const { coords, distance } = router.route(waypoints, "car");
⚖️ What it deliberately does not do
RoughRoute trades accuracy for size and speed. It ignores one-way streets, turn restrictions and speed-based costing, and if it cannot find a path it returns a straight segment rather than refusing. That is the right trade for playback, demos and offline fallbacks — and the wrong one for turn-by-turn navigation, where you want a full routing engine.
Licensed under MIT. Map data comes from OpenStreetMap contributors, licensed under ODbL.