{"id":20103,"date":"2026-03-12T08:40:22","date_gmt":"2026-03-12T12:40:22","guid":{"rendered":"https:\/\/nuxx.net\/blog\/?p=20103"},"modified":"2026-03-24T15:48:16","modified_gmt":"2026-03-24T19:48:16","slug":"updated-mtb-trail-mapping-workflow-thanks-claude","status":"publish","type":"post","link":"https:\/\/nuxx.net\/blog\/2026\/03\/12\/updated-mtb-trail-mapping-workflow-thanks-claude\/","title":{"rendered":"Updated MTB Trail Mapping Workflow: Thanks, Claude!"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/03\/rb_via_osm_to_ai.png\"><img loading=\"lazy\" decoding=\"async\" width=\"924\" height=\"1024\" src=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/03\/rb_via_osm_to_ai-924x1024.png\" alt=\"\" class=\"wp-image-20104\" srcset=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/03\/rb_via_osm_to_ai-924x1024.png 924w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/03\/rb_via_osm_to_ai-271x300.png 271w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/03\/rb_via_osm_to_ai-768x851.png 768w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/03\/rb_via_osm_to_ai-1386x1536.png 1386w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/03\/rb_via_osm_to_ai.png 1805w\" sizes=\"auto, (max-width: 924px) 100vw, 924px\" \/><\/a><figcaption class=\"wp-element-caption\">River Bends Park OSM data, with DEM hillshade layer, ready for Adobe Illustrator<\/figcaption><\/figure>\n<\/div>\n\n\n<p>After a bunch of years I&#8217;ve updated my <a href=\"https:\/\/nuxx.net\/blog\/2012\/06\/05\/mtb-trail-mapping-workflow-with-openstreetmaps\/\" data-type=\"post\" data-id=\"4308\">MTB trail mapping workflow<\/a> with a much-improved tool for getting OpenStreetMap (OSM) data into Adobe Illustrator. I&#8217;ve been experimenting with AI development tools, and I&#8217;ve been looking for projects, and this one fit the bill.<\/p>\n\n\n\n<p>My old workflow used <a href=\"https:\/\/nuxx.net\/files\/osm2ai.pl\"><code>osm2ai.pl<\/code><\/a>, a rather crude script (which I found years ago) that&#8217;d take an OSM file and turn it into vectors that I&#8217;d then group and style in Illustrator. While the tool claimed to filter objects into layers, I never got this working right, so there was a lot of manual work before I could begin styling the map. Each map took a couple of hours solely selecting, joining, grouping, and deleting stuff.<\/p>\n\n\n\n<p>With some time on my hands during a mountain biking trip I began prompting <a href=\"https:\/\/claude.com\/product\/claude-code\">Claude Code<\/a>, via <a href=\"https:\/\/code.visualstudio.com\/\">Visual Studio Code<\/a>, for something similar: a tool which would take OSM data and make it usable in Illustrator. After a bit of back and forth I ended up with this: <a href=\"https:\/\/github.com\/c0nsumer\/osm_to_ai\">c0nsumer\/osm_to_ai<\/a>.<\/p>\n\n\n\n<p>I very intentionally had Claude write <em>everything<\/em> on this, from the script to the readme, and it seems to have been a success. A bit of experience was gained, and I now have a tool that&#8217;ll read in OSM data (either exported from tools or queried live) and produce an Illustrator-compatible <a href=\"https:\/\/en.wikipedia.org\/wiki\/SVG\">SVG<\/a> that has trails grouped by OSM tag, colored, etc. All ready to finish up in Illustrator. It even has an extra layer of <a href=\"https:\/\/www.usgs.gov\/3d-elevation-program\">USGS 3DEP<\/a> hillshade data, something I&#8217;ve wanted for years after seeing it on the <a href=\"https:\/\/www.noquetrails.org\/\">Noquemanon Trails Network<\/a> maps (but didn&#8217;t know how to do in Illustrator).<\/p>\n\n\n\n<p>This was both a good exercise in using AI tools to assist in simple software development and helped streamline my mapping process. While I have a general discomfort with AI-developed code ending up with potentially uncertain output, <em>this<\/em> output is immediately validated visually, so it&#8217;s fine.<\/p>\n\n\n\n<p>Unplanned, but on quick check this seems to have the side-effect of being compatible with Affinity Designer. While this wasn&#8217;t (yet) an intention, I&#8217;ve been looking for a good way to move away from Illustrator due to software cost (this is volunteer stuff, after all) but the old <code>osm2ai.pl<\/code> needed replacing before I could do that. This will make that possible.<\/p>\n\n\n\n<p>So what next? Maybe I&#8217;ll see if I can make the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Geospatial_PDF\">PDF maps geospatial<\/a>. This has long been a goal of mine, as it&#8217;d allow my maps to be opened in something like <a href=\"https:\/\/store.avenza.com\/\">Avenza Maps<\/a> and they&#8217;d show one&#8217;s actual location on the trail. But for now, I&#8217;ll start here.<\/p>\n\n\n\n<p>As an overview, here&#8217;s the <code>--help<\/code> output to show what it can do:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(venv) PS C:\\Users\\svigneau\\Desktop\\OSMtoAI> python .\\osm_to_ai.py --help\nusage: osm_to_ai.py &#91;-h] (--file PATH | --bbox BBOX | --overpass FILE) --output PATH &#91;--width PX] &#91;--dem PATH] &#91;--fetch-dem] &#91;--dem-resolution METERS] &#91;--sun-azimuth DEGREES]\n                    &#91;--sun-altitude DEGREES] &#91;--save-osm PATH]\n\nConvert OSM data to an Adobe Illustrator-compatible layered SVG.\n\noptions:\n  -h, --help            show this help message and exit\n  --file PATH           .osm file to read\n  --bbox BBOX           Bounding box: min_lon,min_lat,max_lon,max_lat\n  --overpass FILE       File containing an Overpass QL query\n  --output PATH         Output .svg file\n  --width PX            SVG width in pixels (height is auto-calculated, default: 800)\n  --dem PATH            GeoTIFF DEM file to generate a hillshade layer (any CRS)\n  --fetch-dem           Download a USGS 3DEP DEM automatically and use it for hillshade. Saves a sidecar .tif next to --output for reuse.\n  --dem-resolution METERS\n                        Target DEM pixel size in metres for --fetch-dem (default: 3). Use 1 for lidar-quality where available, 3 for 1\/9 arc-second, 10 for 1\/3 arc-second.\n  --sun-azimuth DEGREES\n                        Sun azimuth in degrees clockwise from north (default: 315 = NW)\n  --sun-altitude DEGREES\n                        Sun altitude above horizon in degrees (default: 45)\n  --save-osm PATH       Save the downloaded OSM XML to a file for later reuse with --file\n\nExamples:\n  python osm_to_ai.py --file mypark.osm --output mypark.svg\n  python osm_to_ai.py --bbox \"-71.12,42.36,-71.10,42.38\" --output mypark.svg\n  python osm_to_ai.py --overpass query.overpassql --output mypark.svg\n  python osm_to_ai.py --file mypark.osm --dem elevation.tif --output mypark.svg\n  python osm_to_ai.py --file mypark.osm --fetch-dem --output mypark.svg\n  python osm_to_ai.py --file mypark.osm --fetch-dem --sun-azimuth 270 --sun-altitude 35 --output mypark.svg\n\n(venv) PS C:\\Users\\svigneau\\Desktop\\OSMtoAI><\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>After a bunch of years I&#8217;ve updated my MTB trail mapping workflow with a much-improved tool for getting OpenStreetMap (OSM) data into Adobe Illustrator. I&#8217;ve&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/nuxx.net\/blog\/2026\/03\/12\/updated-mtb-trail-mapping-workflow-thanks-claude\/\">Continue reading<span class=\"screen-reader-text\">Updated MTB Trail Mapping Workflow: Thanks, Claude!<\/span><\/a><\/div>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11,57],"tags":[],"class_list":["post-20103","post","type-post","status-publish","format-standard","hentry","category-making-things","category-mapping","entry"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/posts\/20103","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/comments?post=20103"}],"version-history":[{"count":1,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/posts\/20103\/revisions"}],"predecessor-version":[{"id":20105,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/posts\/20103\/revisions\/20105"}],"wp:attachment":[{"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/media?parent=20103"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/categories?post=20103"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/tags?post=20103"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}