Mapbox GL JS — advanced web toolkit (v3)
SkillWeb & browsingThis skill gives your AI working knowledge of Mapbox GL JS version 3, the library behind interactive web maps. Once added, your AI can build map features such as custom markers, clustered points, 3D terrain, heatmaps, and color-coded regions, and it can animate the camera between views. It also covers common performance pitfalls so the map code it writes stays fast.
Available today. Use it from your connected AI after setup.
No other account needed.
Add the skill, then describe the map you want built or fixed, whether it involves markers, layers, style, or 3D. You can also ask it to check that an existing map renders correctly.
Then ask your AI: use the Mapbox GL JS — advanced web toolkit (v3) skill
What your AI can do with it
- Add custom markers and map layers to web pages
- Cluster dense point data so busy maps stay readable
- Write style expressions that control how layers look
- Show 3D terrain and raised building shapes
- Create heatmaps and color-coded region maps
- Animate camera moves and verify map output without opening a browser
What this skill tells your AI
The instructions your AI receives, as published by 0xdarkmatter/claude-mods in skills/mapbox-ops/SKILL.md and read by ahel’s review.
An 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.
Setup invariants
- Set
mapboxgl.accessTokenbeforenew mapboxgl.Map(...). - The map needs
'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_initedflag (see verification.md). - Resolving token/style from
.env: read the token FIRST (that triggers the.envload), THEN readMAPBOX_STYLE. Reading the style before the token load silently falls back to the default style. See palette.md. - Classic vs Standard style. Several techniques here (basemap palette recolour,
the terrain boost-or-add
getStyle().layerswalk) assume a classic style (Streets/Outdoors/Light/Dark…-v12). The v3 default Standard style has no enumerable named layers — use slots +setConfigPropertyinstead. See v3-standard-style.md before porting to Standard.
Pick the technique
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 |
three.js in the map — CustomLayerInterface + shared GL context, animated 3D objects/models, the baked-matrix vs reconstructed-camera (Threebox CameraSync) fork, raycast picking, ENU-metre scene space, constant screen-size actors, terrain elevation, far-plane clipping at pitch | references/three-custom-layer.md |
Camera & animation — flyTo/easeTo/fitBounds padding, freeCameraOptions cinematics/orbit, flight/first-person camera (bearing+pitch choreography; roll is MapLibre-only), 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 |
Bundled resources
-
Starter code — assets/circular_image_marker.js: copy into a page to register a circular photo marker (canvas → premultiplied
ImageBitmap,destination-inmask, contact + drop shadow). Browser-only snippet, not a CLI — adapt theframeColor/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) version gate, the no-native-camera-roll fact (roll is MapLibre GL JS v5, not Mapbox), and every style URL/id in assets/style-catalog.json.--liveresolves 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
The three highest-value gotchas (full detail in the refs)
- Namespace every
addImagename (e.g."rcpin-<glyph>"). Mapbox styles ship sprite icons literally namedparking/toilet/etc — an un-namespacedhasImage()returnstruefor those and your icon is silently dropped. - Register icons as premultiplied
createImageBitmap(), not a rawHTMLImageElement/ImageData— straight-alpha sources make Mapbox fringe a white halo around anti-aliased edges.updateImage(name, bmp)recolours in place. - Data-driven
icon-offsetis silently ignored in GL JS v3. Use a constanticon-offset(it scales withicon-size) or split markers into separate symbol layers, each with its own constant anchor/offset.
Signals
- GitHub stars
- 36
- Forks
- 5
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
mapbox-ops- Source
- github.com/0xdarkmatter/claude-mods