ReviewOS

craft-native/craft

feat(native): no Map primitive, so every screen built around a trail stays in the WebView

#340
Closed glennmichael123 opened this 9 days ago ·
9 days ago

The gap

The native primitive set — View, Text, Button, Link, Pressable, TextInput, Picker, Modal, Switch, Slider, ActivityIndicator, Image, ScrollView, FlatList, Icon, Svg — has no map view.

craft-native/craft#338 set this aside deliberately, and for HQ.training that is the right call: "We do not need an interactive map view — no tiles, no panning, no gestures." Wildloop is the other case. It is a trail app, the map is not an illustration of the screen, it is the screen, and no amount of server-drawn SVG substitutes for one you can pan.

What it blocks

8 of wildloop's 39 views mount a real map through createTrailMap (resources/composables/useTrailMap.ts):

Viewroute linemarkerterritory polygonfit to boundscamera-moved event
trails (catalog)✓✓✓✓
trail/[id]✓✓
activity/[id]✓✓
effort/[id]✓✓✓
event/[id]✓✓
territory/[id]✓
routes (planner)✓
plans

These are not peripheral screens. /trails is the catalog's main surface, territory/[id] is the territory game the product exists for, and activity/[id] is what somebody opens the moment a run ends. On the catalog the camera-moved event is load-bearing rather than cosmetic: panning re-queries the catalog for what is now in view.

What would be enough

A minimum that unblocks all eight:

  1. Vector tiles from a style. We already serve our own — https://tiles.wildloop.org/tiles.json, MVT, with the style built client-side in buildStyle(). So this is a renderer question, not a data or licensing one.
  2. A polyline overlay with per-feature colour and width. Difficulty colours and a casing stroke under the line are what drawTrailRoute draws today.
  3. Fit to bounds, with padding. fitPoints is used by six of the eight.
  4. Pan and zoom, and an event when the camera settles. That is all watchUserMoves needs.

Markers and polygons can come later if the host exposes a projection (lat/lng → screen point), because then a marker is an ordinary View positioned over the map. Tiles and the polyline are the two that cannot be worked around.

What this is not asking for

No 3D terrain, no offline tile packs, no clustering, no turn-by-turn. And explicitly not a web view: wildloop ships a WKWebView app today and the point of the exercise is to leave it.

One scope note

If the answer is MapKit on iOS and the Maps SDK on Android, that is two renderers to hold at parity — craft-native/craft#334's problem again, for the largest primitive in the set. MapLibre Native is worth weighing first: one engine on both platforms, and it already speaks the MVT and style JSON we serve.

Reproducing the need

# wildloop, on main
grep -rln createTrailMap resources/views/   # the eight screens above

Filed from the wildloop screen inventory for stacksjs/stx#1992: of 39 views, 23 are expressible in today's primitives, 10 are blocked by craft-native/craft#338 or craft-native/craft#339, and these 8 are blocked by the absence of a map. It is the largest single gap between wildloop and a native app, and the only one with no issue behind it.

9 days ago

Implemented on main and shipped in v0.0.174.

The native Map primitive now supports explicit regions, fitToBounds, flat numeric geometry arrays for MapPolyline/MapMarker, marker tap events carrying the marker id, and in-place overlay reconciliation on both iOS (MapKit) and Android (Google Maps). The renderer contract covers both hosts.

9 days ago

Closing as shipped in v0.0.174. The remaining map-SDK expansion (tiles, clustering, offline styling, directions) is intentionally outside the trail primitive scope.

Sign in to comment on this issue.