From claude-mods
Build production Mapbox GL JS v3 maps with custom markers, thematic dataviz, 3D terrain, cinematic camera, style composition, and verified performance patterns.
How this skill is triggered — by the user, by Claude, or both
Slash command
/claude-mods:mapbox-opsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
An advanced toolkit for building production Mapbox GL JS map experiences on the **web**:
assets/circular_image_marker.jsassets/style-catalog.jsonreferences/camera-and-animation.mdreferences/dataviz-and-3d.mdreferences/expressions.mdreferences/interaction-and-performance.mdreferences/labels.mdreferences/lifecycle.mdreferences/lines-and-trails.mdreferences/markers.mdreferences/palette.mdreferences/popups.mdreferences/styles.mdreferences/terrain.mdreferences/v3-standard-style.mdreferences/verification.mdscripts/check-mapbox-facts.pyscripts/screenshot_map.pytests/run.shAn advanced toolkit for building production Mapbox GL JS map experiences on the web:
markers, thematic dataviz, 3D, terrain, cinematic camera, style composition, performance,
and the hard-won gotchas that bite. Scope: mapbox-gl-js v3.x in the browser (CDN
mapbox-gl-js/v3.x/) — not the native iOS/Android SDKs (different APIs). Plain GL JS,
framework-agnostic. Several patterns were distilled from a production trail map; adapt the
constants to your own design.
mapboxgl.accessToken before new mapboxgl.Map(...).'load' before adding sources/layers/images. In a throttled
or background tab 'load' can be missed — also bind 'idle' as a one-shot
fallback guarded by an _inited flag (see verification.md)..env: read the token FIRST (that triggers the
.env load), THEN read MAPBOX_STYLE. Reading the style before the token load
silently falls back to the default style. See palette.md.getStyle().layers walk) assume a classic style
(Streets/Outdoors/Light/Dark …-v12). The v3 default Standard style has no
enumerable named layers — use slots + setConfigProperty instead. See
v3-standard-style.md before porting to Standard.Read the matching reference file only when the task needs it:
| Task | Reference |
|---|---|
Custom SVG/canvas markers, addImage/updateImage, namespacing, AA/fringing, circular image masks, anchoring | references/markers.md |
Dashed/cased trail lines, line-dasharray units, translucency over hillshade, colour-by-attribute, line-gradient/lineMetrics | references/lines-and-trails.md |
Hillshade, dense contours, 3D terrain (setTerrain), boost-or-add an existing style's terrain | references/terrain.md |
Symbol-layer text labels that never hide icons (text-optional), AllTrails-style placement | references/labels.md |
Recolour a base style's land/vegetation fills (palette shift / choropleth-style match) | references/palette.md |
| Custom popups, circular photo cards, zoom-scaled offsets | references/popups.md |
Style expressions — interpolate/step/match/case, the zoom-outermost rule, feature-state in expressions | references/expressions.md |
Hover/select via feature-state (not setData), queryRenderedFeatures caveats, clustering, GeoJSON perf, event hygiene | references/interaction-and-performance.md |
Data viz & 3D — fill-extrusion buildings/extruded data, heatmap layer, data-join choropleth (feature-state/match), proportional symbols, sky/fog | references/dataviz-and-3d.md |
Camera & animation — flyTo/easeTo/fitBounds padding, freeCameraOptions cinematics/orbit, flight/first-person camera (roll, 6-DoF), animated day–night cycle (setLights), HUD synced to camera, point-along-line, draw-in lines, paint transitions, spinning globe, the essential/reduced-motion gotcha | references/camera-and-animation.md |
| Style library & composition — first-party style catalog, choosing a base by use case, custom/third-party styles, style switcher, light/dark, hand-rolled style JSON | references/styles.md (+ assets/style-catalog.json) |
setStyle wiping custom layers, the 0×0 resize() bug, SPA teardown / WebGL-context cap, token security, readiness events | references/lifecycle.md |
v3 Standard style — slots vs beforeId, setConfigProperty/lightPreset, why layer-walking (palette/terrain) breaks; localisation, RTL, globe | references/v3-standard-style.md |
Headless screenshot + pixel-accurate marker-alignment checks (Playwright, map.project) | references/verification.md |
Starter code — assets/circular_image_marker.js:
copy into a page to register a circular photo marker (canvas → premultiplied
ImageBitmap, destination-in mask, contact + drop shadow). Browser-only snippet,
not a CLI — adapt the frameColor/box constants to your design.
Verifier script — scripts/screenshot_map.py: drive headless Chromium to screenshot a served map page, assert a marker projects to its lng/lat, and surface console errors. Run it:
python -m http.server 8777 --directory <site-dir> & # serve the page
uv run --with playwright scripts/screenshot_map.py \
http://localhost:8777/preview/index.html out.png --expect 146.9 -36.1
# exit 0 = no console errors; 10 = errors found; 5 = playwright missing; 7 = map never ready
uv run --with playwright scripts/screenshot_map.py URL out.png --json | jq '.data'
Staleness verifier — scripts/check-mapbox-facts.py:
stdlib-only (no Playwright), guards the fast-moving facts this skill encodes
(SKILL-RESOURCE-PROTOCOL §7). --offline (default) asserts internal consistency —
the v3 Standard config enums (lightPreset/theme), terrain tileset IDs, the weather
(≥3.7) and camera-roll (≥3.5) version gates, and every style URL/id in
assets/style-catalog.json. --live resolves the
third-party style URLs and probes whether Mapbox GL JS has shipped a major past v3.
python scripts/check-mapbox-facts.py --offline # exit 0 ok, 4 inconsistency
python scripts/check-mapbox-facts.py --live --json # exit 7 network, 10 drift
addImage name (e.g. "rcpin-<glyph>"). Mapbox styles ship
sprite icons literally named parking/toilet/etc — an un-namespaced
hasImage() returns true for those and your icon is silently dropped.createImageBitmap(), not a raw
HTMLImageElement/ImageData — straight-alpha sources make Mapbox fringe a
white halo around anti-aliased edges. updateImage(name, bmp) recolours in place.icon-offset is silently ignored in GL JS v3. Use a constant
icon-offset (it scales with icon-size) or split markers into separate symbol
layers, each with its own constant anchor/offset.npx claudepluginhub 0xdarkmatter/claude-mods --plugin claude-modsOptimizes Mapbox GL JS web application performance with patterns for initialization waterfalls, bundle size, rendering, and memory management. Prioritized by user impact.
Create 2D and 3D maps and scenes using ArcGIS Maps SDK for JavaScript. Initialize MapViews, SceneViews, layers, navigation; supports ESM imports, CDN dynamic imports, autocasting, explicit classes.
Use when code loads or uses mapgl (library(mapgl), mapgl::), calls maplibre()/mapboxgl()/add_*_layer()/maplibre_proxy(), builds interactive WebGL maps in R, displays PMTiles on a map, or creates story maps / scrollytelling in R Shiny