// WORKING APP 01 - 2026
MtnMkr
An accurate 3D model of any US mountain, built in the browser from USGS lidar, with your tracks and photos draped over it. All 58 Colorado 14ers open in about a second.
What it is
A browser app that builds an accurate 3D model of any US mountain from USGS lidar - 1 m resolution where Google Earth manages 10-30 m - and drapes your trip over it: GPX tracks, geotagged photos, notes. All 58 Colorado 14ers open in about a second. It works offline, shares as a URL, and exports to single-file HTML, ePub, and AR-ready USDZ.
Why I built it
I wanted route models of the peaks I actually climb, with my own tracks and photos, on terrain detailed enough to read a couloir. And after the first version shipped with a Python backend, I wanted to answer a harder question: could a real GIS app run with no server at all?
How it works
It can. The unlock was noticing that USGS sends CORS headers on the elevation exports themselves, so the browser fetches 3DEP directly, decodes float32 heightmaps, and renders a 2048-grid mesh in Three.js. Picking is a heightfield raymarch rather than a raycast, because raycasting 2 million triangles on every pointer move is far too slow.
The 14ers are pre-baked into static tiles on Cloudflare R2 - uint16-quantized heights, roughly 12 MB a peak - and discovered through a published manifest the client adopts. A pre-built peak, a client-built one, and a shared link all resolve to the same cache entry. A service worker makes the whole thing work offline, search runs against a bundled GNIS index, and every byte of data is US-government public domain.
- Three terrain sources - pre-baked tile, optional backend, live USGS build - behind one resolver, all landing on the same cache key.
- Trip data from GPX, KML, KMZ, and geotagged photos, projected onto the terrain surface rather than floating above it.
- Exports to a self-contained HTML viewer, an ePub, and a USDZ that opens in AR Quick Look on iOS.
- Offline by service worker, with the current area and trip persisted to IndexedDB.
What I learned
Three bugs earned their keep. Pre-baked tiles that could never be hit, because the UI's default grid size hashed to a different cache key than the bake did - the tiles were there, correct, and unreachable. A service worker that pinned every returning visitor to a retired bake, because it cached the one mutable file cache-first. And an ePub that froze in Apple Books over a bare hidden attribute: valid HTML, invalid in the strict XHTML an ePub actually has to be.