Roadtrip Companion

TLDR: Check out my cool roadtrip app; it’s perfect for a Memorial Day road trip!

A truism of the startup world is that there are no new ideas; everything you have ever thought of has been tried before. If you’re lucky, your timing is right, or you’ve figured out that one insight that gets it over the hump, or you just have more money — but you ain’t the first. Which is why I’ve always been surprised that, twenty-plus years after first thinking about this roadtrip companion app, nobody has made it happen. But then again I didn’t build it either, because the confluence of tech was never quite right for a side project. Until now!

Roadtrip Companion

Here’s the pitch. When you’re on a long drive — even on our supposedly personality-free interstate highway system — you’re driving through amazing history and culture and science. What’s growing on that field? What’s with the big tower over there? How did that mountain get its weird shape? Who plays at that baseball field? What’s with the big canal next to the road? Why is this town here, in the middle of nowhere? It never ends and the answers are awesome.

For years, I’ve wanted to have an app — not a routing tool or something to help me find a bathroom (both important things) — that continuously feeds me fun facts about wherever I am. And it has to work without a bunch of interaction, because my Rivian already bitches like a backseat driver, constantly nagging me to “look at the road.” So judgy.

Try it yourself at https://seanno.github.io/points/ … or maybe more interestingly, these simulated (as the crow flies) trips from Blaine, WA to Vancouver, BC or Bath, ME to East Boothbay, ME. it’s optimized for a mobile device in landscape mode, but it’s just a web app, so your desktop browser is fine too.

A quick feature tour

When you open the app, it requests location permission and plots that on top of a road map, courtesy of OpenStreetMap and Leaflet — more amazing open source technology that generous people have caused to exist in the world. Standard zoom and pan stuff works as you’d expect; use the “Recenter” button to focus the map back on you.

As your location updates, it keeps track of speed and heading, and queries (the grand-daddy of open source information) Wikidata to identify points of interest near and ideally in front of you. Every minute, a new point is plotted on the map and shown on the right-side pane, with a picture and (very) short description if available. As an aid to keeping your eyes on the road, clicking the “bell” enables a chime each time a new one is shown. Click the “FS” button to enter full-screen mode which looks way better, and if you want to advance through points more quickly, use the “Next” button.

This is neat, but the really cool part is hiding behind the “More” button. This prompts Claude AI to act as a local tour guide, giving you a couple of quick paragraphs about that location. It’s shown on screen and, much better for driving, is read aloud automatically.

One caveat on the AI integration — the app runs entirely client-side including the calls to Claude. This is great for lots of reasons but does mean that if I included my own Claude API key, anyone could grab it and use it for anything. Since this app was just for entertainment purposes, I avoid this by prompting for a key the first time the “More” button is clicked, and persisting it in browser local storage. You can get one at https://platform.claude.com and the cost is truly trivial, pennies per day of active use. If you just want to give it a try and aren’t a jerk, let me know and I can hook you up temporarily; drop me a note.

That’s it — simple, single purpose, and at least IMNSHO incredibly rewarding. I’ve spent drives the last few months fine-tuning the behavior, and it seems pretty dialed in.

Some interesting implementation details

Most of the interesting things about this app come down to managing the queue of locations so that things stay interesting and available.

Querying “ahead”

First of all, Wikidata is a truly huge RDF data store, and it responds to potentially really expensive SPARQL queries, including geolocation, for free. Not surprisingly, it can be a bit slow to respond and nobody damn well better complain about that. But it does require some care and feeding — the site makes its queries on a background thread, and tries to identify key points at which you’re almost out of good stuff so there’s time to find new ones, i.e.:

  • When the queue length gets too small (duh),
  • When you’ve travelled a certain distance, or
  • When all the remaining points are behind your direction of travel.

The app also tries to look “ahead” in space — using your heading and speed to target searches not just where you are right now, but where you’ll be over the next few minutes. There’s a lot of angular math going on here, and I’m thankful to have had Claude Code helping me out with all that. Yeesh.

What is “interesting” anyways?

I could keep tweaking this forever. RDF is really powerful, but it’s also kind of a pain in my a**. Everything is very general and hierarchical, without a lot of defined structure. You can see the basic query in the code; pretty much put together by trial and error.

The points returned are filtered and sorted using a few different heuristics:

This trickiest part of all this is the failure case. We prefer all of these rules, but the bottom line is that we always want to show something, so the code has to fall back if necessary.

The local tour guide

It is truly amazing how good Claude is at generating fun facts about just about any random location I’ve happened to drive by. We’re talking really obscure stuff, like drainage ditches and little pocket parks way out in the boonies.  My prompt isn’t even very sophisticated; it’s just magic.

But it does have a style, and that style can become really grating over time. “If you’re the kind of person who enjoys the history of community water systems” … “It’s the kind of place most people just drive by” … you’ll see what I mean.

My first idea for fixing this was to add more context — feed the model its last X descriptions and say “make it sound different.” But Claude itself came up with a better idea — we created a set of “prompt angles” that emphasize different approaches or styles, and randomly pick a new one with each request. A much cheaper option, and one that works very well. Nice.

Testing is hard

I have to admit that, especially in retirement, I’m pretty lazy about automated testing. At the risk of seeming (and maybe being) a bit arrogant, I’m just a pretty good coder. I walk through my code by hand, implement failure cases the first time, and am not afraid to throw away spaghetti and start over. Especially for projects where I’m a solo developer, the cost of a bunch of automation rarely pencils out.

In most ways, this holds true for this app as well. But the tough thing is — you can’t really see how all of these heuristics perform without actually getting in the car and driving around a lot, in a lot of places. And while I adore a good trip, it’s sadly not realistic to hit the road every time I tweak this code.

The obvious fix was to create a mock geolocation service that exposes the same basic geolocation API as the browser but using a synthetic route. This not only proves to be incredibly useful but also quite entertaining. I linked a few mock routes at the top of this piece; here are a few more just for kicks:

I’m looking forward to giving this a try next month when we’re on our amazing narrowboat canal trip in the UK. And as always, I’d love to hear your ideas and critiques — or just steal the code for your own purposes, it’s license-free!

Image of Government House in Saint John's, Antigua, showcasing a colonial-style building with a green roof surrounded by tropical landscaping.