nuxx.net
Making, baking, and (un-)breaking things in Southeast Michigan.

Archive June 2026

trailmaps.app + Map Generator

trailmaps.app Website on 2026-Jun-25

I’ve been using it for a while now, so I guess it’s a good time to announce the revamp / relaunch / whatever of trailmaps.app. This is a personal project website which started one frosty January morning as I sat in an Ishpeming rental waiting for temps to rise before heading out on a fatbike ride and is now a hub for hosting maps I’ve generated of various trail systems.

The site started out as a hand-written HTML landing page, hand-made Leaflet maps, and directory indexes of my trail map PDFs where I learned a bunch about showing OpenStreetMap (OSM) data via the web, generating tiles, etc (for example, see Making an Online RAMBA Trails Map from 2021). Now it’s now hosting feature-rich web-based maps that help people find their way around mountain bike trails.

The root of the idea was cooked up on a long drive; I wanted something akin to the subway-map-style’d official RAMBA print map (parallel lines over a single trail to illustrate the trail’s membership in multiple routes), but web based. And maybe usable on a phone. And after the early learning then quite a bit of work this spring… Here it is.

Instead of just doing a single map (one-map-at-a-time coding / tile generation / etc) as I had in the past, I now have a full-on map generator that takes data from OSM and other online/open/free sources, combines it all, and generates static content that’s easy to host and cachable so it works if a device loses cell service. It’s basically as close to an app as one can get while still staying web-based.

By being hand-curated (that is, not just auto-generated off of all OSM data) these maps also fill a long-standing gap with other online maps (eg: Trailforks, MTB Project, Strava, RideWithGPS) in that they don’t style (color) the routes the way official park maps and signage do, making what a rider sees on their phone challenging to align with what they see on a signpost next to a trail.

For example, compare these maps of the Shelden Trails at Stony Creek Metropark to the PDF of the official park map which is at the trailhead, and whose color-matched signs are along all loops.

  • Trailforks: Only difficulty colored.
  • MTB Project: Only difficulty colored.
  • Strava: Only dashed lines or a heatmap, unless someone’s created a route.
  • RideWithGPS: Just dashed green lines, unless someone’s created a route.

Then look at the trailmaps.app map of the Shelden Trails at Stony Creek Metropark, for example, the Beach trail.

There’s a bunch more features that this brought about, which I won’t dive into as much depth, but which I’m still quite proud / happy with. The end results are what I want in maps, and it’s nicely reusable:

  • Reusable map generation engine; I write a YAML description of the map (title, OSM references, info that can’t be found in OSM) and it makes the map. If the engine or data gets updated, re-run the map and/or website generation tools.
  • PWA (Progressive Web Apps), so they are installable app-ish, but without the app store overhead.
  • OSM data is not fetched live — it’s a snapshot taken map-generation time — meaning errant edits don’t break the map.
  • Zero user/usage tracking, including having all assets loaded from trailmaps.app. (I’m trying to support less and less online tracking while still providing a good tool.)
  • Ability to generate maps custom from non-OSM data, such as race or group ride routes.
  • Thorough, proper (read: non-shady) SEO such as OpenGraph previews and metadata, making link embedding, sharing, and site discovery by search engines work well.
  • Hostable for cheap since the only server requirements are TLS and RANGE requests. A $5/mo Nanode from Akamai (formerly Linode) easily does it all.
  • Stand-alone maps (each map is a self-contained site) makes it possible for them to be hosted elsewhere, such as if one was made for a trail club/org, etc.

And yes, I heavily used AI-assisted development for this. It was quite educational as since I knew the inputs and outputs, use the maps myself, and was able to do quite a bit of QA, the result is great. At my day job in IT there is (as typical) a huge emphasis in using AI tooling to assist us with our work. This served as a nights-and-weekends project that was quite educational and will benefit me in day-job stuff while achieving a personal goal of making something I wanted and useful for others. It also illustrated the interesting balance between what AI-generation is good at (code, bug finding) and what it’s not (wording, stylistic choices that aren’t simple clones, avoiding feature bloat).

I’m subsequently making the map generator itself available under the MIT license so others can use it. I do have an extensive toolchain for generating the website (takes a definition file and generates the maps, creates preview images, updates the index, rsync’s it to the server) but that part is staying closed / non-released because it’s very my-setup-specific.

cyclingmaking thingsmapping

Vibe Coded Fixes

Working in Claude Code to fix broken image links in this blog.

For all the potential problems that come with vibe coded stuff, generating/composing one-off fix-it scripts can be damned handy. For example, this blog got a big tune-up over the past day: almost 2000 embedded images have been unbroken.

For a lot of years I maintained a personal online photo gallery using Gallery2, but as it hadn’t been maintained since 2012, used a lot of server space, and had a very not-modern feel to it, I shut it down in mid-2020 and made a static archive that I just hosted at home. The biggest problem with doing so was that this blog had a lot of images hotlinked into there, so all those posts broke.

Fixing this manually was a pain, and while I kept a copy of the database+images around, somehow using that to fix things was a Big Task that I never started on.

Enter the modern world of AI-assisted coding and over the past few days of vacation, between riding bikes and walks and such, I prompted Claude to develop a solution. What it generated was a series of scripts that identified all posts containing images hotlinked to the old gallery location, found the related images, uploaded them into the Media Library, then edited each post to make it work.

That’s 1994 blog posts whose images have been restored; things like my Low-Cost Fat Bike Stand post are now working again.

This is where I find a ton of benefit to AI tools such as this: putting together the middle (the code) to fix up problems. If the inputs and desired outputs are known, and one can sanity check the system as it evolves, a lot can get done. And quickly. Tools like this have also been hugely beneficial at work, saving me absurd amounts of time with analyzing log files (eg: network captures, Process Monitor output) where I no longer have to timeline things myself.

I’m past the point where I’m surprised, but I’m still really impressed. This has been a long-standing back-of-my-mind problem/quirk with my site that I’d just sort of accepted… But here we are, it’s fixed. Yay!

computersnuxx.net