maplibre-cartography
Cartographic principles for MapLibre GL JS — label and symbol legibility on imagery vs. vector basemaps, figure-ground for point…
Drawing elevation in MapLibre GL JS once a raster-dem source works — hillshade and `hillshade-method`, the `color-relief` layer and the `["elevation"]` expression, runtime contours with `maplibre-contour`, and 3D terrain with its camera and sky. Use when relief looks harsh,
$ npx -y skills add maplibre/maplibre-agent-skills --skill maplibre-terrain-rendering --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/maplibre-terrain-renderingContext preview
The summary Claude sees to decide when to auto-load this skill.
Drawing elevation in MapLibre GL JS once a raster-dem source works — hillshade and `hillshade-method`, the `color-relief` layer and the `["elevation"]` expression, runtime contours with `maplibre-contour`, and 3D terrain with its camera and sky. Use when relief looks harsh,
name: maplibre-terrain-rendering description: Drawing elevation in MapLibre GL JS once a raster-dem source works — hillshade and `hillshade-method`, the `color-relief` layer and the `["elevation"]` expression, runtime contours with `maplibre-contour`, and 3D terrain with its camera and sky. Use when relief looks harsh, flat, or absent, or when the layer type or property for an elevation effect is unclear. status: provisional
A `raster-dem` source is elevation, not a picture. Four different things draw it, each with its own layer type or API, and most of the wrong answers here are Mapbox GL JS properties that MapLibre never had.
These are symptoms as you would observe them, before you know the cause:
**Not this skill.** Elevation values that are wrong, spiky, or inverted, choosing an elevation tileset, `encoding`, and generating DEM tiles — the style specification's `raster-dem` source page, <https://maplibre.org/maplibre-style-spec/sources/#raster-dem>. Where hillshade sits among the other layers of a style — [maplibre-cartography](../maplibre-cartography/SKILL.md).
| Goal | What draws it | | ----------------------------------------------- | --------------------------------------------------------------------- | | Shaded relief under a 2D map | A `hillshade` layer. No `setTerrain` needed — the two are independent | | Color by height (hypsometric tint) | A `color-relief` layer (GL JS 5.6) | | Contour lines, without pre-generating a tileset | The `maplibre-contour` library, feeding a `vector` source | | A tilted, extruded surface you fly over | `map.setTerrain()` plus camera pitch |
All four read the same `raster-dem` source; one source can serve all of them.
Every `hillshade-*` property is a **paint** property.[1] The defaults that matter: `hillshade-exaggeration` `0.5`, `hillshade-illumination-direction` `335`, `hillshade-illumination-anchor` `viewport` (the light is fixed to the top of the screen, so it does not turn with the map's bearing unless you set `map`), `hillshade-shadow-color` `#000000`, `hillshade-highlight-color` `#FFFFFF`.
Harsh output usually comes from the shading **method**, not the colors. `hillshade-method` (GL JS 5.5) takes `standard` (the default), `basic`, `combined`, `igor`, and `multidirectional`.[1] `multidirectional` lights the surface from several independent directions in one pass and `igor` minimizes the effect on the map features drawn beneath it; both soften terrain on a single layer.
{
"id": "hillshade",
"type": "hillshade",
"source": "terrain-dem",
"paint": {
"hillshade-method": "multidirectional",
"hillshade-exaggeration": 0.4,
"hillshade-illumination-anchor": "map",
"hillshade-shadow-color": "rgba(30,40,80,0.45)",
"hillshade-highlight-color": "rgba(255,240,200,0.4)"
}
}**Do not stack several `hillshade` layers at different illumination directions.** It was the only way to get multi-directional shading before 5.5; since then it is one paint property against N extra draw passes over the same DEM. Pure black shadows and pure white highlights are the other harshness lever: give both an alpha, and use warm highlights with cool shadows over imagery.
`color-relief` (GL JS 5.6) colors a `raster-dem` source directly, client-side; there is no pre-rendering step and no `raster` layer involved. Its paint properties are `color-relief-color`, `color-relief-opacity` (default `1`), and, from GL JS 5.20, `resampling`.[1] The ramp is an `interpolate` expression over `["elevation"]`, which returns meters above the DEM's vertical datum and **is only valid inside `color-relief-color`**.[2]
{
"id": "hypsometric",
"type": "color-relief",
"source": "terrain-dem",
"paint": {
"color-relief-color": [
"interpolate",
["linear"],
["elevation"],
0,
"#2c7bb6",
500,
"#abd9e9",
1500,
"#ffffbf",
2500,
"#fdae61",
4000,
"#ffffff"
],
"color-relief-opacity": 0.8
}
}MapLibre has no `raster-color`, `raster-value`, or `raster-color-mix`; those belong to another renderer and will be dropped as unknown properties. A `raster` layer pointed at a DEM shows packed RGB, not a tint.
[`maplibre-contour`](https://github.com/onthegomap/maplibre-contour) derives vector contour tiles in a Web Worker from the same DEM tiles and serves them through a regis
Curated guidance for AI assistants building MapLibre applications — covering ecosystem and open-source best practices. Agent skills are markdown files that AI coding assistants read as context.
Cartographic principles for MapLibre GL JS — label and symbol legibility on imagery vs. vector basemaps, figure-ground for point…
Configuring fonts and glyphs for MapLibre GL JS and MapLibre Native — the style's `glyphs` URL, self-hosting or generating font…
Migrating from Mapbox GL JS to MapLibre GL JS — package and import changes, removing the access token, choosing tile sources,…
Serverless vector and raster tiles with PMTiles for MapLibre GL JS — single-file format, HTTP range requests, hosting on…
The step-by-step procedure for running this repo's Promptfoo evals with a generator and a judge over provider APIs. Use when…
How to turn a working session into a MapLibre agent skill — you researched something MapLibre's docs did not cover, got it wrong…