feat(web): move the map from Leaflet to MapLibre, the app's map, at 2D parity - #592
feat(web): move the map from Leaflet to MapLibre, the app's map, at 2D parity#592khagele wants to merge 1 commit into
Conversation
…D parity The website drew its map with Leaflet on Carto raster tiles while the app had moved to MapLibre on OpenFreeMap's vector styles (efiten#147): two engines, two basemaps, two treatments of the same colour tokens, and no road to the 3D views the app has. map.js now builds its map from mapcore.js, a port of the app's huntmap.js shape (the same styles, the bare fallback, the sky, overlays re-added on every style load), with the collections the layers read built in mapmodel.js, which the unit suite covers. Points, hex cells, the CoreScope layers, Locate's cloud and dots, the node positions and the ticker's ring are GeoJSON sources swapped whole; markers and popups are MapLibre's. Zoom keeps Leaflet's numbers in shared links and in the server's hex binning, converted at the edge, so no link and no cell changes. The e2e fixtures answer the hosted style inline so load fires offline, and the specs read sources through page hooks where they counted Leaflet's SVG paths. Closes efiten#465 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Master moved: #569, #574, #580, #581 and #589 are merged, master is at Notes below are from reading this PR's diff against master before those merges. Not a full audit, and the green checks are not part of it.
In Hex cells lost their touch tooltip. The pending-data replay through |
Closes #465
The problem
The website drew its map with Leaflet 1.9.4 on Carto raster tiles while the app had moved to MapLibre GL on OpenFreeMap's vector styles (#147). Two engines meant two basemaps, two treatments of the same colour tokens, and no road from the map to the 3D views the app has. Kasper's call (2026-09-06): port the map to the app's map, 2D parity first. Decisions in
docs/2026-09-06-map-on-maplibre.md.My changes in this PR
web/mapcore.js: the map, ported fromapp/src/huntmap.js's shape: the same two OpenFreeMap styles, the bare-background fallback when the style host is unreachable, the app's sky (web/sky.js, a copy pinned by the parity suite), and every overlay re-added on each style load. Sources for points, hex cells, the two CoreScope layers, Locate's inliers and outliers, the node-position connector and circles, and the ticker's ring; an image source for Locate's density cloud; markers in named groups; one popup at a time with open/close reaching the name-resolution deferral (Web: name-resolution redraw closes an open map popup #271); a closeless hover popup for the hex cell's line, since MapLibre has no tooltip.web/mapmodel.js: the pure half, unit-tested: the collections (tier colour and opacity per feature, the index a click resolves), the heat bytes (same ramp and floor), the image corners, bounds, and the zoom convention.?z=in shared links and thezthe server bins hex cells by are converted at the edge (leafletZoom,mapZoomFromLeaflet), so every existing link lands where it did and no cell changes size.web/map.jstalks to the map through bounds, zoom, centre, clicks and popups; the filters, pickers, ticker sync, ignore list, urlstate, gates and notices are unchanged.loadfires offline and at once; the specs that counted Leaflet's SVG paths read a source's feature count through a page hook, click a coordinate through__mapProject, and read the heat image through__locateHeat.Verification
--fail-on-flaky-testsOne test added: hovering a hex cell shows its best RSSI, count and hunters, with real pointer movement, since a synthetic mousemove never reaches the WebGL canvas.
Browser, the real OpenFreeMap style, 12 stubbed hex cells and a 60-point Locate: cells draw with their tier colours, the density cloud sits over the grid's bounds, centroid and strongest markers stand, the info card reads "60 points · search radius ~439 m · encircle 100%"; a theme switch swaps the style and puts the 12 cells back; the zoom buttons and the attribution take the surface colour in both themes.
Not in this PR
fitBoundsjumps, as the app's does.raster-fade-duration: 0) so a Locate re-render does not cross-fade between polls.🤖 Generated with Claude Code