{"id":"c1d38c22-f906-446a-b543-398c3c43db5f","slug":"roadstyle","kind":"mcp","name":"roadstyle","summary":"Road cartography for Python: turn road edges (OSM, osmnx, GeoPandas) into styled, interactive, offline HTML maps (MapLibre) with Street View","owner":"Khoshkhah","repoUrl":"https://github.com/Khoshkhah/roadstyle","license":"MIT","licenseTier":"permissive","trust":"community","stars":1,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-05-30T06:19:27.000Z","addedAt":"2026-10-14T05:14:04.962Z","logoUrl":"https://avatars.githubusercontent.com/u/34841421?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["utilities","browser-web","data-analytics"],"tags":["cartography","geopandas","gis","map","maplibre","openstreetmap","osm","osmnx"],"runtime":"python","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-14T13:38:10.468Z","sample":false,"url":"https://conduits.dev/tools/roadstyle","language":"Jupyter Notebook","transports":["stdio"],"install":{"pypi":"roadstyle-mcp"},"requirements":{"env":[{"name":"CARTO_API_KEY","secret":true,"required":false,"description":"CARTO basemap key; without it maps use the keyless esri_street base map"}],"upstreamMayCharge":false},"tools":null,"readme":"<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/Khoshkhah/roadstyle/main/assets/roadstyle-logo.svg\" alt=\"roadstyle logo\" width=\"96\">\n</p>\n\n<h1 align=\"center\">roadstyle</h1>\n\n<p align=\"center\">\n  <b>Beautiful, interactive road maps from Python.</b><br>\n  One offline HTML file with real road cartography, Google Street View and a JavaScript API.\n</p>\n\n<p align=\"center\">\n  <a href=\"https://pypi.org/project/roadstyle/\"><img src=\"https://img.shields.io/pypi/v/roadstyle.svg\" alt=\"PyPI\"></a>\n  <a href=\"https://pypi.org/project/roadstyle/\"><img src=\"https://img.shields.io/pypi/pyversions/roadstyle.svg\" alt=\"Python versions\"></a>\n  <a href=\"https://github.com/Khoshkhah/roadstyle/actions/workflows/test.yml\"><img src=\"https://github.com/Khoshkhah/roadstyle/actions/workflows/test.yml/badge.svg?branch=main\" alt=\"Tests\"></a>\n  <a href=\"https://khoshkhah.github.io/roadstyle/\"><img src=\"https://img.shields.io/badge/docs-khoshkhah.github.io%2Froadstyle-ff6b35.svg\" alt=\"Docs\"></a>\n  <a href=\"https://github.com/Khoshkhah/roadstyle/blob/main/LICENSE\"><img src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"License: MIT\"></a>\n</p>\n\n<p align=\"center\">\n  <a href=\"#install\">Install</a> ·\n  <a href=\"#quickstart\">Quickstart</a> ·\n  <a href=\"#gallery\">Gallery</a> ·\n  <a href=\"#for-ai-agents\">AI agents</a> ·\n  <a href=\"https://khoshkhah.github.io/roadstyle/\">Documentation</a>\n</p>\n\n![A roadstyle map of Monaco in 3D: bridges, tunnels and roundabouts drawn in order, Rue de la Colle selected, and the floating Street View window showing it](https://raw.githubusercontent.com/Khoshkhah/roadstyle/main/docs/img/hero.jpg)\n\n## Why roadstyle\n\n- **Real road cartography.** Casing and fill, widths that change with zoom, street names, one-way\n  arrows, tunnels drawn under and bridges over, and optional 3D bridge decks.\n- **One offline file.** Map, data and styling in a single HTML page: open it without a server,\n  email it, or put it on any website.\n- **Street View built in.** Click any road to see it in Google Street View, facing the way it runs.\n- **Any road data.** A GeoDataFrame, a file, DuckDB, Arrow, [osmnx](https://osmnx.readthedocs.io/)\n  or [duckOSM](https://github.com/Khoshkhah/duckOSM).\n- **Colour by your data.** Speed, traffic or any column, with a legend and a menu of colourings.\n- **Scriptable.** A `window.rs*` JavaScript API and events for your own dashboard.\n- **Ready for AI agents.** An MCP server and an agent skill.\n\n## Install\n\n```bash\npip install roadstyle              # core\npip install \"roadstyle[all]\"       # + studio, numeric ramps, vector tiles, lonboard, DuckDB, …\n```\n\nPython ≥ 3.10. Individual extras and the dev setup: [Install](https://khoshkhah.github.io/roadstyle/get-started/#install).\n\n## Quickstart\n\n**From OpenStreetMap, no data needed.** Any place, with [osmnx](https://osmnx.readthedocs.io/) (`pip install osmnx`):\n\n```python\nimport osmnx as ox\nimport roadstyle as rs\n\nG = ox.graph_from_place(\"Tartu, Estonia\", network_type=\"drive\", simplify=False)\nG = ox.simplify_graph(G, edge_attrs_differ=[\"bridge\", \"tunnel\"])   # keep tunnels and bridges apart\nrs.render_edges(ox.graph_to_gdfs(G, nodes=False)).save(\"tartu.html\")\n```\n\n**From your own data.** Any file or GeoDataFrame with line geometry and a `highway` column:\n\n```python\nimport geopandas as gpd\nimport roadstyle as rs\n\nedges = gpd.read_file(\"edges.gpkg\")        # LineStrings + a `highway` column, any CRS\nrs.render_edges(edges).save(\"map.html\")    # open map.html: no server (Street View needs one)\n```\n\n**More looks:**\n\n```python\nrs.render_edges(edges, basemap=\"dark_matter\", view_3d=True)            # dark, 3D bridge decks\nrs.render_edges(edges, palette=\"carto\", basemap=\"positron\")            # the classic OSM look\nrs.render_edges(edges, color_by=\"aadt\", cmap=\"viridis\")                # colour by your data\nrs.render_edges(edges, palette=\"mono\", color_options={                 # several colourings,\n    \"Traffic\": {\"color_by\": \"aadt\", \"cmap\": \"viridis\"},                #   switched in the browser\n    \"Speed\":   {\"color_by\": \"maxspeed_kmh\", \"cmap\": \"magma\"}})\nrs.render_edges(edges, tiles=True)                                     # 100k+ edges\nrs.render_dashboard(edges).save(\"dashboard.html\")                      # map + query sidebar\nrs.render_street_view(edges).save(\"street_view.html\")                  # map and Street View side by side\n```\n\nNo Python? `roadstyle edges.gpkg -o map.html --basemap dark_matter`, or click through it in the\nworkbench: `pip install \"roadstyle[studio]\" && roadstyle studio`.\n\n## Gallery\n\n<table>\n<tr>\n<td width=\"33%\" valign=\"top\"><a href=\"https://khoshkhah.github.io/roadstyle/gallery/\"><img src=\"https://raw.githubusercontent.com/Khoshkhah/roadstyle/main/docs/img/gallery/road_look.jpg\" alt=\"The road map look\" width=\"100%\"></a><br><b>The road map look</b><br><sub><code>rs.render_edges(edges)</code></sub></td>\n<td width=\"33%\" valign=\"top\"><a href=\"https://khoshkhah.github.io/roadstyle/gallery/\"><img src=\"https://raw.githubusercontent.com/Khoshkhah/roadstyle/main/docs/img/gallery/bridges_tunnels.jpg\" alt=\"Bridges and tunnels\" width=\"100%\"></a><br><b>Bridges and tunnels</b><br><sub><code>rs.render_edges(edges)</code></sub></td>\n<td width=\"33%\" valign=\"top\"><a href=\"https://khoshkhah.github.io/roadstyle/gallery/\"><img src=\"https://raw.githubusercontent.com/Khoshkhah/roadstyle/main/docs/img/gallery/colour_by_data.jpg\" alt=\"Colour by your data\" width=\"100%\"></a><br><b>Colour by your data</b><br><sub><code>color_by=\"maxspeed_kmh\"</code></sub></td>\n</tr>\n<tr>\n<td width=\"33%\" valign=\"top\"><a href=\"https://khoshkhah.github.io/roadstyle/gallery/\"><img src=\"https://raw.githubusercontent.com/Khoshkhah/roadstyle/main/docs/img/gallery/bridges_3d.jpg\" alt=\"3D bridges\" width=\"100%\"></a><br><b>3D bridges</b><br><sub><code>view_3d=True</code></sub></td>\n<td width=\"33%\" valign=\"top\"><a href=\"https://khoshkhah.github.io/roadstyle/gallery/\"><img src=\"https://raw.githubusercontent.com/Khoshkhah/roadstyle/main/docs/img/gallery/street_view.jpg\" alt=\"Street View\" width=\"100%\"></a><br><b>Street View</b><br><sub><code>click a road</code></sub></td>\n<td width=\"33%\" valign=\"top\"><a href=\"https://khoshkhah.github.io/roadstyle/gallery/\"><img src=\"https://raw.githubusercontent.com/Khoshkhah/roadstyle/main/docs/img/gallery/dashboard.jpg\" alt=\"Dashboard\" width=\"100%\"></a><br><b>Dashboard</b><br><sub><code>rs.render_dashboard(edges)</code></sub></td>\n</tr>\n</table>\n\nEvery look with its code: **[the gallery](https://khoshkhah.github.io/roadstyle/gallery/)**.\n\n## What goes in\n\nOnly `geometry` and `highway` are required. Other columns switch features on:\n\n| Column | Powers |\n|---|---|\n| `geometry` (LineString, any CRS) | the edges. Each edge is **directed**: a two-way road is two edges with reversed geometry |\n| `highway` (OSM class) | colour, width, casing, draw order |\n| `name` | street labels, popup title |\n| `oneway` | direction arrows |\n| `bridge` / `tunnel` / `layer` | grade separation: tunnels below, bridges on decks above |\n| `edge_id` | popups; 64-bit ids stay exact |\n| anything else | shown in the popup, queryable from JavaScript |\n\n[duckOSM](https://github.com/Khoshkhah/duckOSM) (`duckosm export-gis`) exports exactly this, and\n[osmnx](https://osmnx.readthedocs.io/) edges work as they are: `rs.render_edges(ox.graph_to_gdfs(G, nodes=False))`.\n\n## Drive it from JavaScript\n\nThe saved page exposes `window.rs*` functions and `rs:*` events:\n\n```js\nconst ids = rsQuery(p => p.maxspeed_kmh > 30); // feature ids whose properties match\nrsColor(ids, \"#ff00aa\");  rsFocus(ids);       // paint them, fit the camera\ndocument.addEventListener(\"rs:select\", e => console.log(e.detail.properties));\n```\n\nEvery function and event: [JavaScript API](https://khoshkhah.github.io/roadstyle/reference/javascript/).\n\n## For AI agents\n\n**MCP server.** Lets any MCP-capable AI app (Claude Code, Claude Desktop, Cursor, …) draw road maps\nwithout writing code: `render_place(\"Tartu, Estonia\")`, `render_file(\"roads.gpkg\")` and `snapshot`.\nEach saves an HTML map and returns its path plus a PNG preview the agent can look at.\n\n```bash\nclaude mcp add roadstyle -- uvx roadstyle-mcp\n```\n\n<details>\n<summary>Claude Desktop, and where the maps go</summary>\n\nIn `claude_desktop_config.json`:\n\n```json\n{\"mcpServers\": {\"roadstyle\": {\"command\": \"uvx\", \"args\": [\"roadstyle-mcp\"]}}}\n```\n\nMaps are saved in `~/roadstyle-maps/`. The PNG preview needs Chromium, once:\n`uvx --from roadstyle-mcp playwright install chromium`.\n\n</details>\n\n**Claude Code plugin.** The MCP server and the skill below in one install:\n\n```text\n/plugin marketplace add Khoshkhah/roadstyle\n/plugin install roadstyle@roadstyle\n```\n\n**For agents that write code:**\n\n- [`skills/roadstyle/SKILL.md`](https://github.com/Khoshkhah/roadstyle/blob/main/skills/roadstyle/SKILL.md): a\n  skill for agents that *use* roadstyle (the one call, the data contract, the JS API, the traps).\n  Install it for Claude Code:\n  ```bash\n  mkdir -p ~/.claude/skills/roadstyle && curl -fsSL -o ~/.claude/skills/roadstyle/SKILL.md \\\n    https://raw.githubusercontent.com/Khoshkhah/roadstyle/main/skills/roadstyle/SKILL.md\n  ```\n- [`AGENTS.md`](https://github.com/Khoshkhah/roadstyle/blob/main/AGENTS.md): for agents working *on* this repo.\n- [`llms.txt`](https://khoshkhah.github.io/roadstyle/llms.txt): the docs site as a link list for LLMs.\n\n## API keys\n\nBoth keys are optional. roadstyle works without them, just with less.\n\n- **CARTO**, for the default base map. Without a key its tiles are stamped *API KEY REQUIRED*;\n  set `CARTO_API_KEY`, or use a keyless base map (`esri_street`, `esri_dark_gray`, `osm`, `blank`).\n- **Google Maps**, for Street View. Street View works with no key. A key adds a **Linked** mode:\n  a real panorama, with the map marker walking and turning with you.\n\n<details>\n<summary>Setting up the CARTO key</summary>\n\nThe default base map (`voyager`) and `positron` and `dark_matter` come\nfrom CARTO. Without a key, their tiles are stamped *API KEY REQUIRED*. Get a free key at\n[carto.com/basemaps/apikey](https://carto.com/basemaps/apikey), then use any one of these:\n\n```bash\nexport CARTO_API_KEY=\"…\"                                          # environment variable\n```\n```json\n{ \"config\": { \"api_keys\": { \"carto\": \"…\" } } }\n```\nSave that JSON as `~/.config/roadstyle/roadstyle.json`, or as `roadstyle.json` in the folder you run\nfrom. In Python you can pass `rs.render_edges(edges, api_key=\"…\")` instead. With no key at all, use\na keyless base map: `esri_street`, `esri_dark_gray`, `osm` or `blank`.\n\n</details>\n\n<details>\n<summary>Setting up the Google Maps key</summary>\n\nStreet View works with no key: the keyless Google embed. With a\nGoogle **Maps JavaScript API** key, the Street View panel and window get a **Linked / Classic**\nswitch. Linked is a real panorama: the map marker walks and turns with you, and only Google's own\nstreet photos are shown. Classic is the keyless embed. To get a key:\n\n1. In the [Google Cloud console](https://console.cloud.google.com/), create a project and enable\n   **Maps JavaScript API** (Google asks for a billing account on the project).\n2. Under *APIs & Services > Credentials*, create an **API key**.\n3. Restrict it: *Application restrictions* = **Websites**, listing your site's addresses\n   (e.g. `https://example.com/*`); *API restrictions* = **Maps JavaScript API** only.\n\nThen pass it in:\n\n```python\nrs.render_edges(edges, street_view_key=\"AIza…\")         # the floating Street View window\nrs.render_street_view(edges, street_view_key=\"AIza…\")   # the side-by-side page\n```\n\nThe key is written into the page, as every browser key is, so the site restriction in step 3 is\nwhat protects it. It also means Linked works only on the addresses you listed: to try it on\n`localhost`, add `http://localhost:*/*` to the list. Keep the key out of git, for example in an\nenvironment variable.\n\n</details>\n\nMore: [settings & base maps](https://khoshkhah.github.io/roadstyle/reference/settings/#base-maps-api-keys) ·\n[Google Street View](https://khoshkhah.github.io/roadstyle/guides/street-view/).\n\n## Documentation\n\n**[khoshkhah.github.io/roadstyle](https://khoshkhah.github.io/roadstyle/)**, with live maps on every page.\n\n| Where | What you find |\n|---|---|\n| **[Get started](https://khoshkhah.github.io/roadstyle/get-started/)** | install, a first map, what your data needs |\n| **Guides** | [style the roads](https://khoshkhah.github.io/roadstyle/guides/style/) · [colour by your data](https://khoshkhah.github.io/roadstyle/guides/colour/) · [your own layers](https://khoshkhah.github.io/roadstyle/guides/overlays/) · [Google Street View](https://khoshkhah.github.io/roadstyle/guides/street-view/) · [big networks](https://khoshkhah.github.io/roadstyle/guides/big-networks/) · [dashboards & JavaScript](https://khoshkhah.github.io/roadstyle/guides/dashboards/) · [on a website](https://khoshkhah.github.io/roadstyle/guides/website/) |\n| **[Gallery](https://khoshkhah.github.io/roadstyle/gallery/)** | a picture and one line of code per look |\n| **Reference** | [every parameter](https://khoshkhah.github.io/roadstyle/reference/parameters/) · [JavaScript API](https://khoshkhah.github.io/roadstyle/reference/javascript/) · [settings & base maps](https://khoshkhah.github.io/roadstyle/reference/settings/) · [command line](https://khoshkhah.github.io/roadstyle/reference/cli/) |\n| **[Changelog](https://github.com/Khoshkhah/roadstyle/blob/main/CHANGELOG.md)** | what changed in each release |\n\n## Built on\n\n- **[MapLibre GL JS](https://maplibre.org/)** (BSD-3-Clause) draws every web map: roadstyle writes its style and\n  data, and a copy of MapLibre is inlined in each saved page so it opens offline.\n- **[OpenStreetMap](https://www.openstreetmap.org/copyright)** data (© OpenStreetMap contributors, ODbL) and the\n  **[openstreetmap-carto](https://github.com/gravitystorm/openstreetmap-carto)** style, whose road classes,\n  colours and widths roadstyle follows.\n- **[HiGHS](https://highs.dev/)**, through [SciPy](https://scipy.org/), solves which road is drawn on top.\n- **[GeoPandas](https://geopandas.org/)** and **[Shapely](https://shapely.readthedocs.io/)** for the geometry;\n  **[lonboard](https://developmentseed.org/lonboard/)** (deck.gl) and **[folium](https://python-visualization.github.io/folium/)**\n  for the notebook back-ends.\n\n## License\n\n[MIT](https://github.com/Khoshkhah/roadstyle/blob/main/LICENSE). Base-map tiles come from\nthird-party services (CARTO, OSM, Esri) with their own attribution and terms.\n"}