Route 66 Road Trip Map

A live tracker for my road trip from Toronto to SF via Route 66

Syncs with photos from my phone to generate an interactive map with polaroid popups, an interpolated route, a day-by-day timeline, and live trip status. Copy this for your own trips!

Screenshot of the map

Built with React + MapLibre GL JS + OpenFreeMap tiles

Set up for your own trip

1. Fork the repo

Fork this repo on GitHub.

2. Enable GitHub Pages

Go to your repo's Settings → Pages and set the source to GitHub Actions.

3. Enable Actions

GitHub Actions runs the scripts to extract photo metadata and generate the route between photos.

4. Add your OpenRouteService API key

Sign up for a free key at openrouteservice.org, then add it as a repository secret named ORS_API_KEY under Settings → Secrets and variables → Actions → New repository secret.

This is used to snap your route to actual roads. Without it, the map falls back to straight lines between photos.

5. Update src/trip.config.js

Optional, modify these to edit trip metadata as well as to personalize the look and feel of the tracker

6. Add your photos and push

Drop GPS-tagged photos (JPG, HEIC, or PNG) into public/photos/ and push to main. Any photo taken on a modern iPhone or Android with location enabled will have GPS data.

GitHub Actions handles the rest automatically: it extracts EXIF metadata, generates thumbnails, fetches the road-snapped route, builds the site, and deploys it to GitHub Pages. The route also re-fetches hourly — useful if you're adding photos mid-trip.


Local development

You don't need to do any of this — CI handles everything automatically when you push. This is just for previewing changes locally.

npm install
npm run dev

To process photos locally (useful for previewing before pushing):

Create .env at the root of the repo and add ORS_API_KEY=your_key.

npm run process       # extract EXIF, generate thumbnails → src/data/photos.json
npm run update-route  # fetch road-snapped route from ORS → src/data/route.json

Tech stack

Piece What it does
React + Vite UI framework and build tool
MapLibre GL JS WebGL map rendering
OpenFreeMap Free map tiles (no API key needed)
OpenRouteService Road-snapped routing (free tier)
Nominatim Reverse geocoding (free, no key needed)
sharp + heic-convert Thumbnail generation and HEIC conversion
exifr EXIF metadata extraction
GitHub Pages Hosting
GitHub Actions CI/CD: process photos, fetch route, deploy

Project structure

public/photos/        ← drop your photos here
src/
  data/
    photos.json       ← generated automatically by CI
    route.json        ← generated automatically by CI
  components/
    WorldMap.jsx      ← MapLibre map, markers, route layers
    Polaroid.jsx      ← photo card component
    Tack.jsx          ← map marker pin
  App.jsx             ← main app, sidebar, timeline, state
scripts/
  process.js          ← photo processing script
  update-route.js     ← route fetching script
.github/workflows/
  deploy.yml          ← build + deploy on push
  update-route.yml    ← re-fetch route every hour

Notes

  • Photos without GPS are included in the sidebar timeline but not plotted on the map
  • HEIC files are automatically converted to JPG during processing; the originals are not deleted
  • The route is cached by a hash of your waypoints — it only re-fetches from ORS when photos change
  • The free ORS tier supports up to ~50 waypoints per request; the script batches automatically for longer trips
  • Sidebar stats (Photos, Cities, States/Provinces) come from photos.json; Distance Covered comes from route.json. If ORS has never succeeded, the stats section is hidden. If ORS fails on a re-run, the previous distance and route are shown unchanged — stale but consistent

Built With

Share this project:

Updates