Free tool

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

The problem

🧭 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.

The idea

📦 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.

Features

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.

How it works

⚙️ Three steps

  1. Ahead of time, compile an .osm.pbf region into a compact .graph file.
  2. Ship that file — bundle it with the app or put it behind a CDN.
  3. On the device, load that file and run queries locally. You get back the coordinates and the distance.
Try it

⌨️ 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.