{"id":50343579,"url":"https://abelvm.github.io/omt-router/","last_synced_at":"2026-06-15T09:01:25.530Z","repository":{"id":355293108,"uuid":"1227165435","full_name":"AbelVM/omt-router","owner":"AbelVM","description":"Client-side routing library for OpenMapTiles vector tiles. Computes optimal routes for pedestrian, car, and bicycle travel entirely client-side — no routing backend or third-party service required.","archived":false,"fork":false,"pushed_at":"2026-06-02T09:50:57.000Z","size":45415,"stargazers_count":12,"open_issues_count":2,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-02T11:24:39.560Z","etag":null,"topics":["astar","bicycle","car","dijkstra","mapbox","maplibre","navigation","openmaptiles","pedestrian","performance","routing","sssp","walking"],"latest_commit_sha":null,"homepage":"https://abelvm.github.io/omt-router/example/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AbelVM.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-02T09:51:39.000Z","updated_at":"2026-06-02T09:50:59.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/AbelVM/omt-router","commit_stats":null,"previous_names":["abelvm/omt-router"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/AbelVM/omt-router","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbelVM%2Fomt-router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbelVM%2Fomt-router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbelVM%2Fomt-router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbelVM%2Fomt-router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AbelVM","download_url":"https://codeload.github.com/AbelVM/omt-router/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbelVM%2Fomt-router/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34355156,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["astar","bicycle","car","dijkstra","mapbox","maplibre","navigation","openmaptiles","pedestrian","performance","routing","sssp","walking"],"created_at":"2026-05-29T19:00:20.340Z","updated_at":"2026-06-15T09:01:25.518Z","avatar_url":"https://github.com/AbelVM.png","language":"JavaScript","funding_links":[],"categories":["Navigation \u0026 Directions"],"sub_categories":["Sprite Generation"],"readme":"# OMT Router\n\n[![npm](https://img.shields.io/npm/v/omt-router)](https://www.npmjs.com/package/omt-router) [![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0.en.html)\n\nClient-side routing library for OpenMapTiles vector tiles. Computes optimal routes and isolines for `car`, `pedestrian`, and `bicycle` travel entirely in the browser — no external routing backend required.\n\nThis repository is provider-agnostic for OpenMapTiles-compatible vector tiles, so the same tiles used for your basemap can be used for routing (reduces network and operational overhead).\n\n[Live demo](https://abelvm.github.io/omt-router/example/)\n\n---\n\n## Table of contents\n\n- [Overview](#overview)\n- [Key features](#key-features)\n- [Available routing engines](#available-routing-engines)\n- [Engine selector](#engine-selector)\n- [Quick start](#quick-start)\n- [MapLibre integration](#maplibre-integration)\n- [API reference](#api-reference)\n- [Architecture](#architecture)\n- [Transport modes \u0026 road classes](#transport-modes--road-classes)\n- [Development](#development)\n- [Caveats](#caveats)\n- [License](#license)\n\n---\n\n## Overview\n\n`omt-router` builds a routing graph from OpenMapTiles-formatted vector tiles in Web Workers, then runs routing algorithms in the browser. It is designed for: high performance, deterministic tile stitching across tile boundaries, and flexible engine selection to trade runtime vs reliability.\n\nThe library supports route finding, isoline (reachability) polygons, worker pools, tile caching, and a lightweight MapLibre control for quick integration into web maps.\n\n## Key features\n\n- Zero backend — client-side graph construction and routing; no third-party routing API required.\n- Routing and isolines (isoPHAST) for `car`, `pedestrian`, and `bicycle` modes.\n- Multi-engine routing: `bidirectional-astar`, `adaptive-barrier`, `delta-stepping`, `ultra-dijkstra`.\n- Automatic runtime engine selector (benchmark-trained) with conservative fallbacks.\n- Endpoint snapping with configurable quality guard (`maxAcceptableSnapDistanceM`).\n- Seamless tile stitching using Liang–Barsky clipping to ensure bit-identical boundary nodes across tiles.\n- Worker pool (`PowerPool`) + tile parse cache (`PowerCache`) for parallel parsing and reuse.\n\nFor details on the training and benchmark pipeline, see [benchmark/README.md](benchmark/README.md).\n\n---\n\n## Available routing engines\n\nThe library exposes several engines. Use `engineId` to force a specific engine, or `auto` to use the runtime selector.\n\n| Engine ID             | Algorithm                                                                                                                    | Parallel ready | Best fit                                                   |\n| --------------------- | ---------------------------------------------------------------------------------------------------------------------------- | :------------: | ---------------------------------------------------------- |\n| `bidirectional-astar` | [Bidirectional A\\* with geographic heuristic](https://en.wikipedia.org/wiki/Bidirectional_search)                            |                | Stable performance on sparse or long routes                |\n| `adaptive-barrier`    | [Adaptive Barrier SSSP](https://doi.org/10.48550/arXiv.2504.17033)                                                           |       ✓        | Dense, medium/large graphs; benefits from parallel runtime |\n| `delta-stepping`      | [Delta-Stepping SSSP](https://en.wikipedia.org/wiki/Parallel_single-source_shortest_path_algorithm#Delta_stepping_algorithm) |       ✓        | Large frontiers and bursty relax phases                    |\n| `ultra-dijkstra`      | [Optimized Dijkstra (4-ary heap)](https://doi.org/10.48550/arXiv.1505.05033)                                                 |                | Reliable baseline and fallback                             |\n\nNotes:\n\n- `queryRoute()` and `route()` accept `options.engineId` to force a specific engine.\n- When an engine returns invalid/no-path, the router can fall back to `bidirectional-astar` for correctness.\n\n---\n\n## Engine selector\n\nAn ML-based selector chooses the engine per request to minimize runtime while keeping correctness risk low. The compact runtime artifact is `src/tuning/model.js` and inference lives in `src/tuning/tuning.js`.\n\n- Validation: selects the optimal engine in ~91% of validation cases; selects a “good-enough” engine ~92% of the time (average runtime within ~6–7% of optimal).\n- Trained on 16,646 samples; supports `sabOn` (SharedArrayBuffer/worker-enabled) and `sabOff` profiles.\n- Conservative defaults: `ultra-dijkstra` is used as a low-risk fallback; thresholds can be tuned for canary rollouts.\n\nAt runtime the selector evaluates features such as beeline distance, `E` (edge count), `N` (node count), density/branching indicators, and available runtime capabilities (SharedArrayBuffer, Worker availability, cross-origin isolation).\n\n---\n\n## Quick start\n\nInstall:\n\n```bash\nnpm install omt-router\n```\n\nBasic `route()` example:\n\n```javascript\nimport { route } from 'omt-router';\n\nconst metadata = await fetch('https://tiles.openfreemap.org/planet').then((r) =\u003e r.json());\nconst urlTemplate = metadata.tiles[0];\n\nconst result = await route(\n  [-3.7038, 40.4168], // origin  [lng, lat]\n  [-3.6937, 40.4101], // destination\n  'car', // 'car' | 'pedestrian' | 'bicycle'\n  urlTemplate,\n  { costField: 'travelTime' } // 'distance' | 'travelTime' | 'optimal'\n);\n\nconsole.log(result.found); // true\nconsole.log(result.coordinates); // [[lng, lat], ...]\nconsole.log(result.cost); // total route cost for the selected costField\n```\n\nMapTiler or other providers also work:\n\n```javascript\nconst urlTemplate = 'https://api.maptiler.com/tiles/v3-openmaptiles/{z}/{x}/{y}.pbf?key=YOUR_KEY';\n```\n\nReturned `RouteResult` highlights:\n\n| Field          | Type                 | Description                                                        |\n| -------------- | -------------------- | ------------------------------------------------------------------ |\n| `found`        | `boolean`            | Whether a path was found                                           |\n| `path`         | `number[]`           | Sequence of internal node IDs                                      |\n| `coordinates`  | `[number, number][]` | `[lng, lat]` pairs ready for GeoJSON                               |\n| `cost`         | `number`             | Total route cost (`distance` in metres or `travelTime` in seconds) |\n| `costField`    | `string`             | Cost field used (`distance` / `travelTime` / `optimal`)            |\n| `partialGraph` | `boolean`            | `true` when computed against a graph with missing tiles            |\n\n---\n\n## MapLibre integration\n\n`omt-router` provides a `MapLibreRoutingControl` for easy integration with MapLibre GL JS.\n\nExample usage:\n\n```javascript\nimport {\n  MapLibreRoutingControl,\n  route,\n  getEngineWorkerStatus,\n  onEngineWorkerStatusChange,\n  cancelRunningEngine,\n} from 'omt-router';\n\nconst control = new MapLibreRoutingControl({\n  routeFunction: route,\n  getEngineWorkerStatus,\n  onEngineWorkerStatusChange,\n  cancelRunningEngine,\n  tileJsonUrl: 'https://tiles.openfreemap.org/planet',\n  maplibre: maplibregl,\n});\nmap.addControl(control, 'top-left');\n```\n\nConstructor options (selected):\n\n| Option                       | Type       | Default                                                | Description                                                                     |\n| ---------------------------- | ---------- | ------------------------------------------------------ | ------------------------------------------------------------------------------- |\n| `maplibre`                   | `object`   | —                                                      | Required MapLibre GL object (`maplibregl`).                                     |\n| `tileJsonUrl`                | `string`   | —                                                      | Metadata endpoint returning `{ tiles: [urlTemplate] }`.                         |\n| `urlTemplate`                | `string`   | —                                                      | Optional `{z}/{x}/{y}.pbf` template; if present, no metadata fetch is required. |\n| `routeFunction`              | `function` | `route`                                                | Custom route implementation returning the routing result.                       |\n| `getEngineWorkerStatus`      | `function` | —                                                      | Optional callback that returns engine worker status.                            |\n| `onEngineWorkerStatusChange` | `function` | —                                                      | Subscription callback for engine status changes.                                |\n| `cancelRunningEngine`        | `function` | —                                                      | Cancel callback used when a route request times out or control is removed.      |\n| `defaultMode`                | `string`   | `car`                                                  | Initial transport mode: `car`, `pedestrian`, or `bicycle`.                      |\n| `defaultCostField`           | `string`   | `distance`                                             | Optimization target: `distance`, `travelTime`, or `optimal`.                    |\n| `theme`                      | `string`   | `light`                                                | UI theme: `auto`, `light`, or `dark`.                                           |\n| `panelClassName`             | `string`   | ``                                                     | Additional CSS class(es) for the control panel.                                 |\n| `routeTimeoutMs`             | `number`   | `20000`                                                | Route request timeout (ms).                                                     |\n| `routeOptions`               | `object`   | `{ maxAutoRadius: 8, maxAcceptableSnapDistanceM: 60 }` | Forwarded to route engine.                                                      |\n| `showGraph`                  | `boolean`  | `false`                                                | Whether to render the internal graph overlay.                                   |\n| `features`                   | `string`   | `both`                                                 | Which features to show: `routing`, `isolines`, or `both`.                       |\n| `isolineMaxCost`             | `number`   | `1000` / `900`                                         | Default isoline max cost (meters for `distance`, seconds for `travelTime`).     |\n\nAll unspecified text in `locale_override` is merged from the selected built-in locale. See the examples in the repository for localization overrides.\n\n### Instance API (selected)\n\n- `setOrigin(lngLat)` — set origin and trigger route update.\n- `setDest(lngLat)` — set destination and trigger route update.\n- `setUrlTemplate(urlTemplate)` — update tile URL template and refresh route.\n- `setTileJsonUrl(url)` — update tile metadata URL, fetch template, refresh route.\n- `dispose()` / `shutdown()` — free worker pools and caches.\n\n### Isolines\n\n- Integrated isoline (isoPHAST) UI computes reachability polygons for a selected point.\n- `features === 'both'` renders tabs for routing and isolines; switching clears the alternate feature's layers/sources.\n- Isolines are output to `isolineSourceId` as a GeoJSON `FeatureCollection`; each feature includes `properties.color` used for styling.\n- Default isoline behaviour: direction `from`, `isolineMaxCost` defaults to `1000` m for `distance`, `900` s for `travelTime`.\n\n---\n\n## API reference\n\nThis section summarizes the most important public functions and options. For full details, consult the source in `src/`.\n\n### `route(start, end, mode, urlTemplate, options?)`\n\nHigh-level convenience function. Fetches tiles, builds the graph, and returns the route result.\n\nKey `options` (selected):\n\n- `zoom` (number) — default `14`.\n- `schema` (`'zxy'` | `'tms'`) — default `'zxy'`.\n- `maxAutoRadius` (number) — default `8`.\n- `engineId` (string) — `'auto'` (default) or explicit engine id.\n- `costField` (string) — `'distance'` (default), `'travelTime'`, or `'optimal'`.\n- `penalties` (object) — `{ intersectionPenaltySec, turnPenaltySec, turnAngleThresholdDeg }`.\n- `maxAcceptableSnapDistanceM` (number) — default `60`.\n- `includeGraph` (boolean) — include prepared graph for debugging.\n\nReturned result includes runtime metadata: `engine`, optional `fallback`, `startSnapDistanceM`, `endSnapDistanceM`, `partialGraph`, `hasMissingTiles`, `missingTileErrors`, and `reason` on failure.\n\n### `buildTileURL(urlTemplate, tile, options?)`\n\nFormats a `{z}/{x}/{y}` tile URL and supports `tileProxyTemplate` and `tileUrlTransform` hooks.\n\nExample:\n\n```javascript\nconst tileUrl = buildTileURL(\n  'https://example.com/{z}/{x}/{y}.pbf',\n  { z: 14, x: 4827, y: 6372 },\n  {\n    tileProxyTemplate: '/api/tile?url={url}',\n  }\n);\n```\n\n### `buildGraphForTiles(tiles, mode, options?)`\n\nBuild a prepared routing graph from an explicit tile list without running `route()`. Useful for preloads and reusing graphs across requests.\n\nExample:\n\n```javascript\nconst tiles = [\n  { z: 14, x: 4827, y: 6372 },\n  { z: 14, x: 4828, y: 6372 },\n];\nconst graph = await buildGraphForTiles(tiles, 'car', { urlTemplate });\n```\n\n### `routeBatch(requests, urlTemplate, options?)`\n\nRun many `route()` requests in parallel while sharing tile cache and worker pools.\n\n### `computeRoute(startCoords, endCoords, graph, options?)`\n\nRun routing on a pre-built graph (when you manage tile loading yourself). Supports `costField`, `penalties`, `snapDistancesM`, `maxAcceptableSnapDistanceM`, and `engineId` hints.\n\n### `buildCH(graph, costField?)`\n\nConvert merged graph into compact typed arrays and CSR adjacency for engine execution; costs are scaled for fast inner-loop arithmetic.\n\n### `queryRoute(startId, endId, prepared, options?)`\n\nRun the routing algorithm on a `buildCH`-prepared graph. Supports `engineId: 'auto'` and explicit engine IDs, `useCache`, `allowFallback`, and parallel/serial policies.\n\n### `nearestNode(coords, graph, maxDistM?)`\n\nReturn the nearest graph node id within `maxDistM` (default 500 m).\n\n---\n\n## Architecture\n\nHigh-level flow:\n\n```text\nroute()\n  │\n  ├─ tilesManager  →  corridor tiles (+ adaptive radius retries)\n  │\n  ├─ graphBuilder\n  │    ├─ PowerPool workers  →  fetch + parse transportation layer\n  │    ├─ PowerCache         →  per-tile parse cache\n  │    └─ mergeSegments      →  graph nodes/edges with distance + travelTime\n  │\n  └─ chRouter\n      ├─ buildCH            →  typed arrays + forward/reverse CSR\n      ├─ nearestNode        →  endpoint snapping via KDBush\n      └─ queryRoute         →  auto engine select, worker run, validate, fallback\n```\n\nKey implementation notes:\n\n- Tile corridor enumeration uses [Bresenham rasterisation](https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm) to select slippy-map tiles around the origin→destination corridor and supports adaptive radius retry loops for robustness.\n- Tile parsing is parallelised using [PowerPool](https://abelvm.github.io/performance-helpers/#/powerpool) workers and cached in [PowerCache](https://abelvm.github.io/performance-helpers/#/lru-cache-with-ttl-and-memoizer) to avoid repeated decoding.\n- Road segments are clipped to tile boundaries using [Liang–Barsky clipping](https://en.wikipedia.org/wiki/Liang%E2%80%93Barsky_algorithm); adjacent tiles produce bit-identical boundary coordinates, avoiding proximity snapping.\n- Graph merging deduplicates nodes with a coordinate hash (rounded to 6 decimal places) and computes edge costs and travel times from per-class defaults.\n\n---\n\n## Transport modes \u0026 road classes\n\nRoad filtering follows the OpenMapTiles transportation schema.\n\n| Mode         | Allowed classes                                                                                              | Excluded                                                        |\n| ------------ | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------- |\n| `car`        | motorway(\\_link), trunk(\\_link), primary(\\_link), secondary(\\_link), tertiary(\\_link), minor, service, track | pedestrian/footway/cycleway/steps/bridleway/corridor subclasses |\n| `pedestrian` | path, minor, service, track (+ pedestrian/footway/steps/path/corridor/platform subclasses)                   | motorways and non-foot-access roads                             |\n| `bicycle`    | path, minor, service, tertiary, secondary, track (+ cycleway/path subclasses)                                | motorway, motorway_link, non-bicycle-access roads               |\n\nDefault per-class speeds are used to compute `travelTime` (km/h). These defaults produce conservative, predictable travel-time estimates.\n\n---\n\n## Development\n\nCommon commands:\n\n```bash\nnpm install        # install dependencies\nnpm run dev        # Vite dev server (serves example/)\nnpm run build      # build library to dist/\nnpm run test       # run Vitest test suite\nnpm run lint       # ESLint\nnpm run format     # Prettier\n```\n\nServe the `example/` demo locally with `npm run dev` and open `http://localhost:5173/example/`.\n\nTraining note: `npm run train` runs the selector training script `benchmark/train_engine_selector_ml.py` using `.venv/bin/python`. Ensure a Python virtualenv is available or update the script to point to your interpreter.\n\n---\n\n## Caveats\n\n- Route quality depends on OpenStreetMap data coverage and tagging. If routing inaccuracies appear, consider improving source OSM data.\n- Endpoints must snap to routable graph edges; snaps beyond `maxAcceptableSnapDistanceM` will fail with a clear reason (`no_node`, `poor_snap`).\n- Tile servers must allow CORS for uncached cross-origin tile requests — otherwise use `tileProxyTemplate` to proxy tiles through a same-origin endpoint.\n\nIf you see `reason: 'tile_cors'` with `code: 'MissingAllowOriginHeader'` the browser blocked a cross-origin uncached tile request. Fix by adding CORS headers or configuring `tileProxyTemplate`.\n\n---\n\n## References \u0026 links\n\n- [Live demo](https://abelvm.github.io/omt-router/example/)\n- OpenMapTiles schema: https://openmaptiles.org/schema/#transportation\n- OpenFreeMap metadata used in the example: https://tiles.openfreemap.org/planet\n- Performance helpers: https://abelvm.github.io/performance-helpers\n- Benchmark/training pipeline: [benchmark/README.md](benchmark/README.md)\n\n---\n\n## License\n\n[AGPL-3.0-only](./LICENSE) © Abel Vázquez Montoro\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/abelvm.github.io%2Fomt-router%2F","html_url":"https://awesome.ecosyste.ms/projects/abelvm.github.io%2Fomt-router%2F","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/abelvm.github.io%2Fomt-router%2F/lists"}