Mapbox GL JS — advanced web toolkit (v3)

SkillWeb & browsing

This 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.

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.accessToken before new 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 _inited flag (see verification.md).
  • Resolving token/style from .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.
  • Classic vs Standard style. Several techniques here (basemap palette recolour, the terrain boost-or-add 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.

Pick the technique

Read the matching reference file only when the task needs it:

TaskReference
Custom SVG/canvas markers, addImage/updateImage, namespacing, AA/fringing, circular image masks, anchoringreferences/markers.md
Dashed/cased trail lines, line-dasharray units, translucency over hillshade, colour-by-attribute, line-gradient/lineMetricsreferences/lines-and-trails.md
Hillshade, dense contours, 3D terrain (setTerrain), boost-or-add an existing style's terrainreferences/terrain.md
Symbol-layer text labels that never hide icons (text-optional), AllTrails-style placementreferences/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 offsetsreferences/popups.md
Style expressions — interpolate/step/match/case, the zoom-outermost rule, feature-state in expressionsreferences/expressions.md
Hover/select via feature-state (not setData), queryRenderedFeatures caveats, clustering, GeoJSON perf, event hygienereferences/interaction-and-performance.md
Data viz & 3D — fill-extrusion buildings/extruded data, heatmap layer, data-join choropleth (feature-state/match), proportional symbols, sky/fogreferences/dataviz-and-3d.md
three.js in the mapCustomLayerInterface + 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 pitchreferences/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 gotchareferences/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 JSONreferences/styles.md (+ assets/style-catalog.json)
setStyle wiping custom layers, the 0×0 resize() bug, SPA teardown / WebGL-context cap, token security, readiness eventsreferences/lifecycle.md
v3 Standard style — slots vs beforeId, setConfigProperty/lightPreset, why layer-walking (palette/terrain) breaks; localisation, RTL, globereferences/v3-standard-style.md
Headless screenshot + pixel-accurate marker-alignment checks (Playwright, map.project)references/verification.md

Bundled resources

  • Starter codeassets/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 scriptscripts/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 verifierscripts/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. --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
    

The three highest-value gotchas (full detail in the refs)

  1. Namespace every 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.
  2. Register icons as premultiplied 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.
  3. Data-driven 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.

Signals

GitHub stars
36
Forks
5
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
mapbox-ops
Source
github.com/0xdarkmatter/claude-mods