TrailMate

TrailMate

Offline-first hiking companion app with downloadable trail maps and SOS check-ins.

React NativeExpoTypeScriptSQLiteMapLibreZustand
View liveView repo

The problem

I went hiking in an area with no signal and realized every trail app I had installed was useless without a connection. I wanted an app that worked fully offline once a trail was downloaded, including maps, elevation profiles, and a way to let someone know I was safe.

Role and impact

Technical decisions and challenges

Bundling map tiles for every possible trail would have made the app enormous, but fetching tiles on demand defeats the point of an offline-first app. I compared pre-rendering vector tiles per region at build time versus letting users download a bounded tile package for just the trail they picked.

I went with on-demand MBTiles packages scoped to a bounding box around the selected trail, since it kept the base install small and let users only pay the storage cost for trails they actually plan to hike.

Continuous high-accuracy GPS tracking is one of the fastest ways to kill a phone's battery on a multi-hour hike. I evaluated always-on high-accuracy tracking versus an adaptive sampling rate based on movement speed.

I chose an adaptive sampling rate that widens the GPS polling interval when speed is low or the device is stationary, because it kept the trail recording accurate on moving segments while cutting background battery drain significantly during rest stops.

Detailed stack

LayerTechnologyWhy
MobileReact Native, Expo, MapLibreCross-platform with native map rendering and offline tile support
StorageSQLite, on-device MBTiles packagesLocal-first trail data and maps with no server dependency
StateZustandLightweight store for trail, GPS, and download state
Trail map screen with elevation profileDownload manager showing offline trail packages

What I would do differently

I would add a proper SOS flow that works over satellite messaging instead of just a local "mark as safe" check-in. Right now, the safety check-in only helps once you're back in signal range, which misses the exact scenario it's meant to cover.