The map is a picker; the readout is the product
Most mapping apps treat the map as the answer. CoordKit treats it as an input device. The camera has bottom padding equal to the panel height, so the camera's own centre is the crosshair's point. There is no offset arithmetic anywhere in the codebase, and a pan is a continuous edit of the coordinate rather than a discrete guess.
That one decision cascades. Because the point is framed rather than tapped, the readout can live permanently at the bottom of the screen without ever being obscured. Because the readout is permanent, the tools can be modes of that panel instead of separate screens. Position, Convert, Measure, Compass and Speed swap its contents while the map, the framed point and the coordinate stay exactly where they were.
Precision you can argue with
A consumer GPS receiver will happily hand you eight decimal places of latitude while being twelve metres wrong. CoordKit refuses to print digits the fix does not support: the number of decimals shown is derived from the accuracy figure the device reports, so the readout degrades visibly when the sky closes in.
Elevation follows the same rule. The app prefers a public terrain dataset, falls back to the device's own altimeter, and tells you which one it used, because a barometric altitude and a surveyed height are different claims about the world.
The test suite is the architecture document
The most transferable thing in this codebase is not a feature. It is the set of tests that exist purely to stop a specific class of bug from ever returning.
- Riverpod 3 retries a failed provider, so a failure settles as
AsyncLoading with an error, and .when picks its loading branch forever. A test fails the build if .when( reappears in lib/.
- A
TextEditingController disposed right after await showDialog looks correct and is not. The route keeps rebuilding its subtree through the exit animation, so a still-animating TextField uses a dead controller and throws a frame later, on a device, never in a build log. A test enforces that these are state fields.
- Scroll-controlled sheets must set
useSafeArea: true, or a sheet that grows to full height puts its top under the status bar. Enforced.
- A native permission mismatch kills the process; it is not a catchable exception. iOS terminates an app that requests an access level with no matching usage string, and naming a photo album silently escalates the library request to read-write. A test cross-checks what the code asks for against what the manifests declare.
None of these are things a linter catches or a code review reliably remembers. Writing them down as prose would have been a document nobody re-reads. Writing them as failing tests makes the knowledge outlive the person holding it, which is most of what architecture is for.
What shipped
Six coordinate formats (decimal degrees, DMS, DD N/S/E/W, UTM, MGRS and Plus Codes) with smart detection on input, so pasting anything recognisable works. Distance and area measurement on a spherical model. A compass that flags magnetic interference instead of quietly pointing the wrong way. Speed with trip distance and a moving average. A camera that burns coordinates, elevation and time into the photo and its EXIF metadata, for when a screenshot is not evidence. Saved points with GPX, KML and CSV in both directions.
No advertising, at all. The ad SDK was removed outright rather than configured off, because a linked ad framework still ships a sample app id in both manifests and still forces a tracking permission string for a prompt the app never shows. Pro is the only revenue.