MapLibre Examples Gallery
The MapLibre GL JS examples gallery is the shared vocabulary of web mapping. This page tracks all 139 of its examples against maplibre-yaml — which ones the format expresses on its own, which need some page JavaScript alongside the YAML, and which point at gaps we’re tracking. Each badge names what you, the author, write. The page doubles as an honest capability matrix: badges flip as features land.
- YAML — you write one YAML document and nothing else; the title links to our version.
- YAML + JavaScript — you write the YAML plus a little page JavaScript (
mapReady(), the@maplibre-yaml/core/maplibremodule,updateLayerData(), or a protocol plugin). Each page shows the YAML, the page markup (controls ride<ml-map>’s corner slots) and the JS side by side; the JS shown is the JS the browser suite runs. - Gap — a missing YAML surface, tracked in the issue ledger.
- YAML + plugin — the document stays pure YAML (an ordinary layer names an effect, e.g.
effect: tonal-hatch) and the JavaScript ships in an installed package, through the experimental effects API (registerEffect()); the layer stays the fallback. No plugin for these rows ships in 0.7. Each needs one that is tracked in the issue ledger; until it lands, follow the upstream link. - JavaScript — a MapLibre job, not a document’s: deep imperative work (game loops, 3D Tiles streaming, renderers that read MapLibre internals, constructor-only callbacks) that a declarative format shouldn’t chase; follow the upstream link.
Every construct these examples use also carries a declared export class — what mlym emit does with it when you export to style.json (exports / exports with a fallback / doesn’t export). See Export classes.
Unlinked titles point at the upstream original; a badge-only row carries its reasoning after the title.
Mapzen classics
Section titled “Mapzen classics”Not upstream examples: looks from Mapzen’s Tangram era, rebuilt as plain
style spec. Each is its own export — mlym emit --strict compiles it with
nothing lost. These are the static tier; animated effects that refine
them are separate work and not shipped yet.
| Classic | Status |
|---|---|
| Crosshatch · after Tangram’s crosshatch | YAML |
| Blueprint · classic-style example | YAML |
Map basics
Section titled “Map basics”| Example | Status |
|---|---|
| Display a map · upstream | YAML |
| Display a satellite map · upstream | YAML |
| Display a non-interactive map · upstream | YAML |
| Change the default position for attribution · upstream | YAML |
Check if WebGL is supported · <ml-map> already turns a failed map construction into its on-map error card and ml-map:error; a listener replaces upstream’s alert. Telling no-WebGL apart (GPUInitializationError, maplibre-gl ≥ 6.7) needs the original error in the event (ml-chh.17) | YAML + JavaScript |
| Display a map with MLT · upstream | YAML |
Camera & animation
Section titled “Camera & animation”| Example | Status |
|---|---|
| Fly to a location · upstream | YAML + JavaScript |
| Jump to a series of locations · upstream | YAML + JavaScript |
| Set pitch and bearing · upstream | YAML |
| Slowly fly to a location · upstream | YAML + JavaScript |
| Animate a line · upstream | YAML + JavaScript |
| Animate a point · upstream | YAML + JavaScript |
| Animate a point along a route · upstream | YAML + JavaScript |
| Animate map camera around a point · upstream | YAML + JavaScript |
| Customize camera animations · upstream | YAML + JavaScript |
Customize the map transform constrain · the constrain function is host code: setTransformConstrain() after mapReady() (maplibre-gl ≥ 5.10); the sub-zero zoom is set from the same page code (the schema’s floor is 0) | YAML + JavaScript |
Enter a 360° photosphere · still out after U17: a photosphere plugin, plus maxPitch: 175, well above the schema’s 85° cap (ml-rww) | JavaScript |
| Fit a map to a bounding box · upstream | YAML |
| Fit to the bounds of a LineString · upstream | YAML |
Fly to a location based on scroll position · upstream · a type: scrollytelling document, run by the Astro <Scrollytelling> component | YAML |
| Hash routing · upstream | YAML |
Level of detail control · params-panel sliders (parameters:) feed ml-map:parameter-change, then one setSourceTileLodParams() call | YAML + JavaScript |
| Offset the vanishing point using padding · upstream | YAML + JavaScript |
| Render world copies · upstream | YAML |
| Restrict map panning to an area · upstream | YAML |
| Set center point above ground · upstream | YAML |
Walk around a map in first person · still out after U17: a first-person game loop driving the camera every frame, and pitch 90 / maxPitch: 95 above the 85° cap (ml-rww) | JavaScript |
Controls & gestures
Section titled “Controls & gestures”| Example | Status |
|---|---|
| Display map navigation controls · upstream | YAML |
| Locate the user · upstream | YAML |
| Cooperative gestures · upstream | YAML |
| Disable map rotation · upstream | YAML |
| Disable scroll zoom · upstream | YAML |
Navigate the map with game-like controls · interactive: false is YAML; the arrow keys call panBy/easeTo after mapReady(), the same camera JavaScript as fly-to | YAML + JavaScript |
| Toggle interactions · upstream | YAML + JavaScript |
| View a fullscreen map · upstream | YAML |
Sources & data
Section titled “Sources & data”| Example | Status |
|---|---|
| Add a vector tile source · upstream | YAML |
| Add a GeoJSON line · upstream | YAML |
| Add a GeoJSON polygon · upstream | YAML |
| Draw GeoJSON points · upstream | YAML |
| Add multiple geometries from one GeoJSON source · upstream | YAML |
| Display line that crosses 180th meridian · upstream | YAML |
View local GeoJSON · the YAML declares an empty GeoJSON source and its fill layer; a file input in a corner slot hands the parsed file to updateLayerData(), with no MapLibre API | YAML + JavaScript |
| View local GeoJSON (experimental) · the same page code as View local GeoJSON with the File System Access picker (Chromium only; the browser suite can’t drive it), so no page is planned | YAML + JavaScript |
| Add a raster tile source · upstream | YAML |
| Add a WMS source · upstream | YAML |
| Add a canvas source · upstream | YAML + JavaScript |
| Add a COG raster source · page pending: needs a hermetic COG fixture | YAML + JavaScript |
| Add a video · upstream | YAML |
| Animate a series of images · upstream | YAML + JavaScript |
| Add live realtime data · upstream | YAML |
| Update a feature in realtime · upstream | YAML |
| Update GeoJSON polygons · upstream | YAML + JavaScript |
Layers, icons & styling
Section titled “Layers, icons & styling”| Example | Status |
|---|---|
| Add an icon to the map · upstream | YAML |
| Add a generated icon to the map · upstream | YAML + JavaScript |
| Add a stretchable image to the map · upstream | YAML + JavaScript |
| Add an animated icon to the map · upstream | YAML + JavaScript |
Animate an icon on the GPU · the YAML carries the point source and the symbol layer that names the icon; addImage() registers a renderWithWebGL style image after mapReady(). Needs maplibre-gl ≥ 6.3 (U19). The effects API doesn’t fit, because effects enhance layers, not style images | YAML + JavaScript |
| Display a remote SVG symbol · upstream | YAML |
Elevate symbols above the terrain · upstream · symbol-height-offset, maplibre-gl ≥ 6.6 | YAML |
| Generate and add a missing icon to the map · upstream | YAML + JavaScript |
| Use a fallback image · upstream | YAML |
| Change a layer’s color with buttons · upstream | YAML |
| Add a new layer below labels · upstream | YAML |
Add a custom style layer · addLayer({type: 'custom'}, before) after mapReady(), with MercatorCoordinate from @maplibre-yaml/core/maplibre. The effects API doesn’t fit: an effect enhances an existing layer, and 0.7’s only backend shades fill-extrusion | YAML + JavaScript |
| Add a pattern to a polygon · upstream | YAML |
| Create a heatmap layer · upstream | YAML |
| Create and style clusters · upstream | YAML |
Display HTML clusters with custom properties · the clustered source with clusterProperties and the unclustered layers are YAML; the SVG donut markers are page JS (Marker from @maplibre-yaml/core/maplibre). YAML alone would need source-bound markers with a registered renderer (ml-chh.16) | YAML + JavaScript |
| Display and style rich text labels · upstream | YAML |
| Style labels with web fonts · upstream | YAML |
Style labels with font faces · upstream · font-faces rides the inline mapStyle (a style-root key with no YAML field); maplibre-gl ≥ 6.7 | YAML |
| Change the case of labels · upstream | YAML |
| Style labels with local fonts · upstream | YAML |
| Variable label placement · upstream | YAML |
| Variable label placement with offset · upstream | YAML |
Expressions & data-driven styling
Section titled “Expressions & data-driven styling”| Example | Status |
|---|---|
| Style lines with a data-driven property · upstream | YAML |
| Change building color based on zoom level · upstream | YAML |
| Create a gradient dashed line using an expression · upstream | YAML |
| Create a gradient line using an expression · upstream | YAML |
| Filter within a layer · upstream | YAML + JavaScript |
| Filter symbols by text input · upstream | YAML + JavaScript |
| Filter layer symbols using global state · upstream | YAML |
| Filter symbols by toggling a list · upstream | YAML |
| Visualize population density · upstream | YAML |
| Create a time slider · upstream | YAML |
Measure distances · the YAML declares the source and its layers; map clicks call updateLayerData(), and the distance readout sits in a corner slot | YAML + JavaScript |
| Draw a circle · upstream | YAML + JavaScript |
Terrain, 3D & globe
Section titled “Terrain, 3D & globe”| Example | Status |
|---|---|
| 3D terrain · upstream | YAML |
| Add a hillshade layer · upstream | YAML |
| Add 3D terrain from quantized mesh tiles · page pending: pre-release plugin, no hermetic fixture | YAML + JavaScript |
| Add a color relief layer · upstream | YAML |
| Add a multidirectional hillshade layer · upstream · maplibre-gl ≥ 5.5 | YAML |
| Add contour lines · upstream | YAML + JavaScript |
| Display a hybrid satellite map with terrain elevation · upstream | YAML |
| Sky, fog and terrain · upstream | YAML |
| Display buildings in 3D · upstream | YAML |
| Add a 3D model using three.js · a glTF model at a coordinate: the case for a models backend (ml-chh.19) | YAML + plugin |
| Add 3D tiles using three.js · still out after U17: OGC 3D Tiles streaming (3d-tiles-renderer with Draco/KTX2 transcoders), not a model at a coordinate | JavaScript |
| Add a 3D model to globe using three.js · still out after U17: the models backend on a globe; effects are mercator-only (ml-chh.19, ml-chh.20) | JavaScript |
| Add a 3D model with babylon.js · the same model and placement as the three.js version; the engine doesn’t matter to a backend (ml-chh.19) | YAML + plugin |
| Add a 3D model with shadow using three.js · models backend with a shadow param (ml-chh.19) | YAML + plugin |
| Adding 3D models using three.js on terrain · models backend that is terrain-aware; today’s effects declare absence under terrain (ml-chh.19) | YAML + plugin |
| Extrude polygons for 3D indoor mapping · upstream | YAML |
Fill-extrusion rounded corners · upstream · maplibre-gl ≥ 6.2; height and opacity sliders are parameters:, the corner-radius slider is not (the property is constant-only) | YAML |
| Display a globe with a vector map · upstream | YAML |
| Display a globe with an atmosphere · upstream | YAML |
Add a custom layer with tiles to a globe · still out after U17: a tile-mesh renderer that reads map.style.projection internals | JavaScript |
Add a simple custom layer on a globe · the custom-layer JavaScript on projection: globe (YAML since U15), using MapLibre’s public projectTile shader prelude; it repeats Add a custom style layer, so no page is planned | YAML + JavaScript |
| Create a heatmap layer on a globe with terrain elevation · upstream | YAML |
| Display a globe with a fill extrusion layer · upstream | YAML |
Zoom and planet size relation on globe · projection: globe is YAML (U15); a slot button calls flyTo with the latitude zoom compensation, the fly-to JavaScript on a globe | YAML + JavaScript |
Markers & popups
Section titled “Markers & popups”| Example | Status |
|---|---|
| Add a default marker · upstream | YAML |
| Add custom icons with markers · upstream | YAML |
Create a draggable marker · Marker({draggable: true}) from @maplibre-yaml/core/maplibre after mapReady(); YAML alone once markers gain draggable: and drag events (ml-chh.15) | YAML + JavaScript |
Animate a marker · a rAF loop moves a Marker from @maplibre-yaml/core/maplibre; document markers have no handle yet (ml-chh.15) | YAML + JavaScript |
Create a draggable point · layer mousedown/mousemove after mapReady() call updateLayerData(); the coordinates readout sits in a corner slot | YAML + JavaScript |
| Display a popup · upstream | YAML |
| Display a popup on click · upstream | YAML |
| Display a popup on hover · upstream | YAML |
| Attach a popup to a marker instance · upstream | YAML |
Internationalization
Section titled “Internationalization”| Example | Status |
|---|---|
| Change a map’s language · upstream | YAML + JavaScript |
Locale switching · config.locale (passed to the Map constructor) + controls.fullscreen: {position: top-left}; page pending (ml-chh.18) | YAML |
| Use locally generated ideographs · upstream | YAML |
Events & user interaction
Section titled “Events & user interaction”| Example | Status |
|---|---|
| Get features under the mouse pointer · upstream | YAML + JavaScript |
| Create a hover effect · upstream | YAML |
Animate symbol to follow the mouse · projection: globe + controls.globe are YAML; mousemove calls updateLayerData() | YAML + JavaScript |
| Center the map on a clicked symbol · upstream | YAML |
Display performance metrics · a corner-slot HUD fed by ml-map:load and the map’s idle/render events after mapReady() | YAML + JavaScript |
| Get coordinates of the mouse pointer · upstream | YAML + JavaScript |
Select features with boxzoomend callback · still out after U17: boxZoomEnd is a constructor-only callback that <ml-map> can’t take (config is data; boxZoom validates as a boolean), and setting it after construction needs a private field | JavaScript |
| Show polygon information on click · upstream | YAML |
Plugins, protocols & integrations
Section titled “Plugins, protocols & integrations”| Example | Status |
|---|---|
Geocode with Nominatim · the geocoder plugin gets its maplibregl from @maplibre-yaml/core/maplibre and is added with addControl() after mapReady() | YAML + JavaScript |
| PMTiles source and protocol · upstream | YAML + JavaScript |
Create deck.gl layer using REST API · deck’s MapboxOverlay is a control, so addControl() after mapReady(). deck is host code here, not a library backend (D-A1) | YAML + JavaScript |
Draw geometries with Terra Draw · a plugin control added with addControl() after mapReady() | YAML + JavaScript |
Draw polygon with mapbox-gl-draw · a plugin control added with addControl() after mapReady(); the area readout sits in a corner slot | YAML + JavaScript |
Sync movement of multiple maps · three <ml-map> elements; await each mapReady(), then syncMaps() | YAML + JavaScript |
| Toggle deck.gl layer · the deck.gl page code plus a show/hide button; it repeats Create deck.gl layer, so no page is planned | YAML + JavaScript |
| Use addProtocol to transform feature properties · upstream | YAML + JavaScript |
Census as of 2026-10-05 against maplibre-yaml core@0.6.0 + the 0.7 chrome tier, the gap units, and map-level 3D (terrain:, sky:, projection:), with the out-of-scope rows rescored against 0.7 (U17) and the last YAML-only pages built on maplibre-gl 6 (U18); badges renamed in 0.7 (Pure YAML → YAML, Escape hatch → YAML + JavaScript, Extension → YAML + plugin, JS territory → JavaScript), and the three inline-mapStyle font rows rescored to YAML since they carry no page JavaScript: 78 YAML (77 with pages, 1 badge only) · 51 YAML + JavaScript (26 with pages, 25 badge only) · 4 YAML + plugin · 0 gaps · 6 JavaScript (139 upstream examples — table rows only; the two Mapzen classics are counted separately). The triage reasoning lives in the repo at plans/feat-maplibre-examples-gallery.md.