Offline-first GPX track viewer and live tracker for runs/hikes. Static PWA, no build step, one dependency (vendored Leaflet).
The header shows status and distance; ⌖ centers the map on you (after you allow location) and drops an Apple-style blue dot with an accuracy halo. Do steps 1–3 at home on network — only step 4 works offline.
- Center the map on where you want to run (⌖ for your current area).
- Pick 3 / 5 / 7 / 10 km from the Auto dropdown, then follow the header's prompts: tap your starting point, two points you want to run through (this is how you say "through the park" or "along the river"), and your finish point — tap the finish near the start for a loop.
- The app builds a ring of waypoints circling the area between your two via points, sized to the distance you asked for, and routes a genuine loop around it — out one way, back another, not an out-and-back — trying a few ring sizes and keeping whichever lands closest to the ask. The header shows the real resulting distance. (If your points are far from the start, the connector there and back eats into short-distance asks — that's geometry, not a bug.)
- Don't like it? Pick the distance again to redo, or Undo to clear (during the taps, Undo steps back one point). Like it? Save. You can also extend it by tapping more waypoints — it's a normal planned route once generated.
"nice" comes from your via points plus the foot router's preference for paths, parks, and trails.
- Browse/zoom the map to your area (⌖ jumps to where you are; the app reopens wherever you last left the map).
- Tap Plan — it highlights purple and enables Undo/Save.
- Tap the map to set point A, then keep tapping waypoints (B, C, D, …). Each new leg
is routed along actually walkable OSM ways via the public
FOSSGIS Valhalla router, with costing tuned to
prefer footpaths, trails, and park ways over residential streets (strongest in
semi-auto). Taps snap to the nearest path — you don't need to tap exactly on the
trail. The header keeps a running total:
Planning · 7.4 km. - Mis-tapped? Undo removes the last leg. No walkable path (e.g. across water) or no network? That leg falls back to a straight line and the header says so.
- To make a loop, tap back near your starting point as the final waypoint.
- Tap Save, give the route a name — it lands in the saved-tracks dropdown, drawn in red. (Tapping Plan again instead discards, after a confirmation.)
- Get a
.gpxfrom anywhere: JOSM (File > Export to GPX, see PLAN.md Phase 1), a friend's ↗ share from this app, or an export from Garmin. Anything with<trkpt>(or<rtept>) points works. - Tap Load GPX and pick the file. It's validated, drawn in red, zoomed to fit, and saved under its filename.
All tracks — planned or loaded — live in the dropdown and persist offline in the
browser's IndexedDB (they survive restarts, but aren't files on disk). Pick one to
load it; ↗ shares the selected track as a .gpx file (iOS share sheet on the
phone, file download on desktop); ✕ deletes it. The last-used track reloads
automatically next time you open the app.
With the track loaded and on Wi-Fi, tap ⤓ Tiles. The app pre-downloads every map tile covering the track (zoom 13–16, plus ~500 m of margin) into the offline cache — watch the header count up. After that, map + track work with no signal.
- Load your track, tap Start, allow location.
- The blue dot follows your GPS fix and the map pans with you. The screen stays awake (see iOS notes); dim it to save battery.
- The header shows green On route while you're within 30 m of the planned track, and amber Off route · 85 m when you've strayed — glance, correct, carry on.
- Tap Stop when you're done. Nothing is recorded or uploaded; the app only compares live position against the plan.
On every deploy that changes app files, bump SHELL in sw.js (shell-v1 → shell-v2) — the service worker is cache-first with no freshness check, so that bump is what ships the update.
- Share > Add to Home Screen to run it standalone.