Minimapp
A game-inspired navigation mini-map for iOS and Android — heading-oriented follow camera, place search, driving routes, and automatic rerouting.
Overview
Minimapp is a navigation view that behaves like a game mini-map rather than a map app: the world rotates under a fixed player marker, the camera sits ahead of where you're going, and the whole surface is built to be readable at a glance while moving. It's a native Expo app with a development client, since react-native-maps is a native module and can't run inside Expo Go.
It deliberately does not use Mapbox. Mapbox requires an account for both a style token and a separate native-SDK download credential; react-native-maps needs no login at all on iOS and only a plain Google Maps API key on Android, which is written into the manifest at prebuild time and never bundled into the JS.
That choice costs real capability, and the README documents each loss rather than hiding it — custom map styling applies on Android only, camera zoom versus MapKit altitude needs an approximation, and there is no continuous camera padding. Location is foreground-only and no location data is sent to any backend.
Highlights
- A follow mode that orients the map to heading at a 42° pitch and keeps the player around 68% down the screen, plus an explore mode that suspends following the moment you pan, zoom, rotate or pitch.
- Place search against Nominatim, driving routes from OSRM drawn as a route line, and off-route detection that reroutes automatically with confirmation delay and cooldown.
- A pure motion engine publishing at 5 Hz: GPS and compass fixes are validated, outliers rejected, and positions converged toward targets by time-based interpolation.
- A heading filter that rejects isolated reversals, takes the shortest arc across north, and caps turn rate — with walking favoring fresh compass data and driving favoring GPS course under speed hysteresis.
- A deterministic driving simulation over a fixed circuit that needs no GPS permission, behind a __DEV__-guarded developer panel with live camera and sensor diagnostics.
- Explicit UI states for permission denial, permanent restriction, disabled location services, unreliable fixes, missing compass, stale signals, and map load failure.
- Unit tests covering north crossing, compass spikes, position convergence, GPS accuracy and ordering, source selection and reset, simulation continuity, date-line interpolation, and forward camera offset.
Design Notes
Off-center camera without camera padding
Mapbox can hold a continuously-following camera off-center; MapKit and Google Maps cannot. The player-below-center look is produced by aiming the camera at a point projected ahead of the player along their heading, so the real position falls behind it on screen — an approximation of perspective-correct padding, tunable by a single screen-fraction constant.
Heading rotation happens in the native layer
Rotating the player marker through React state would re-render on every display frame. The marker is a Marker with flat and a native rotation prop, and the camera is driven imperatively through animateCamera — so at 5 Hz there is no React state update, no GeoJSON reconstruction, and no worklet bridge call in the per-frame path. HUD metadata updates at roughly 1 Hz; camera diagnostics are read back and capped at ~3 Hz.
One data path for real and simulated fixes
Real GPS and mock fixes enter the same pipeline — validation and outlier rejection, then the motion engine, then the native puck and camera — so the simulation exercises the production path rather than a parallel one. Switching sources resets the engine; backgrounding the app tears down sensors and timers entirely.
Manual-pan detection differs per platform, and the fallback is written down
The isGesture flag that signals the user has taken over the camera is Google Maps only. iOS falls back to a 'did we just move the camera ourselves' time window combined with onPanDrag — slightly less precise, documented as such, rather than left as an unexplained platform difference.
Rerouting with hysteresis, not on the first bad fix
A single noisy fix 40 m off the line is not a wrong turn. Off-route has to hold for six seconds before a reroute fires, checks run on a 2 s cadence, and an 8 s cooldown between reroutes keeps a lost signal from hammering the routing API.
A passing bundle is not device validation
The camera approximations, animation timing and frame rate all depend on real hardware, and iOS is affected more than Android. A separate device-validation checklist tracks the acceptance checks that only a physical phone can answer, with an explicit warning not to read green unit tests as confirmation that native motion is stable.