Skip to content

Mapzen classics

Mapzen’s Tangram showed what a web map could look like when a style was allowed to be expressive: pen-and-ink cities, drafting sheets, maps you looked at for their own sake. These are two classics in that tradition, written as maplibre-yaml documents.

Each classic below appears twice, from one YAML document:

  • Live: <ml-map> runs the document, and the experimental effects package upgrades its buildings with a shader effect.
  • Exported: plain maplibre-gl runs the style.json that mlym emit --with-fallbacks produced from that same document when this site was built. That pane loads no maplibre-yaml code at all.

The two cameras are linked, so drag, zoom or rotate either map and the other one follows.

Lower Manhattan as a pen drawing, after the crosshatch style Patricio Gonzalez Vivo wrote for Tangram in 2015. Live, the tonal-hatch effect makes the stroke density follow the light on each face: lit walls go to paper, shaded walls to dense ink. Exported, every face gets the same light pen hatch, shaded by the document’s light:.

Live <ml-map> + @maplibre-yaml/effects effect loading…
Exported vanilla maplibre-gl, no library code static fallback

A drafting sheet in the Mapzen spirit. Live, the blueprint effect lays a grid on every roof and wall, with lines a fixed 4 metres apart that never stretch, and edges that glow. Exported, the buildings are flat-shaded blue blocks on the same drafting-grid ground.

Live <ml-map> + @maplibre-yaml/effects effect loading…
Exported vanilla maplibre-gl, no library code static fallback

Every construct in a maplibre-yaml document declares what happens to it on export (export classes). An effect is a runtime shader, and style.json has no way to express one. So the document always carries a complete static layer, and the effect enhances that layer rather than replacing it:

  • Without the effects package, <ml-map> renders the static layer as written.
  • Where the effect can’t run (globe projection, 3D terrain, no WebGL2), it reports that it’s unavailable and the static layer renders. The live pane’s badge shows which of the two you’re looking at.
  • mlym emit ships the static layer and prints one lossy warning, which is the exported pane above. mlym emit --strict refuses the document, because the exported map isn’t the map the effect draws.

The fallback is a real map, not a placeholder. That is what fallback-where-honest means: the expressive version where it can run, and an honest static version wherever it can’t, including on machines that have never heard of this library.

YAML is the source. Download a document, change the hatch gain, the blueprint grid spacing, a colour or the light, and open it in any page that loads <ml-map> and @maplibre-yaml/effects. See Effects for loading the package and the full list of params. Run mlym emit on your copy to get your own exported style.

crosshatch.yaml
crosshatch.yaml
# yaml-language-server: $schema=https://docs.maplibre-yaml.org/schema/latest/map.schema.json
# Mapzen classic: crosshatch — the launch-page document (docs /classics/).
# After Tangram's crosshatch style (tangrams/tangram-sandbox
# styles/crosshatch.yaml, @patriciogv 2015, MIT).
#
# This is the gallery's static preset (configs/gallery/crosshatch.yaml) plus
# one statement of intent: `effect: tonal-hatch` on the buildings, and the
# tonal atlas that effect samples. Everything else is plain style spec.
#
# - With @maplibre-yaml/effects loaded, <ml-map> upgrades the buildings to
# Tangram's tonal hatching: stroke DENSITY follows the light on each face.
# - Without it — or where the effect cannot run (globe, terrain, no WebGL2)
# — the buildings render exactly as authored below: the static fallback.
# - `mlym emit` (--with-fallbacks, the default) ships that same static
# layer with one lossy warning; `--strict` refuses, because the exported
# map is not the map the effect draws. That is fallback-where-honest.
#
# Download it, change a colour or the `gain`, and open it in any page that
# loads <ml-map>. The docs build compiles this file with `mlym emit` for the
# launch page's exported pane, and a test pins the two together.
type: map
id: crosshatch
config:
center: [-74.0118, 40.7075]
zoom: 15.9
pitch: 60
bearing: 29
# An inline base style that carries only the self-hosted serif italic
# glyphs (Libre Baskerville Italic, OFL — Tangram labelled in Baskerville
# italic). The document owns every layer.
mapStyle:
version: 8
glyphs: "https://docs.maplibre-yaml.org/fonts/{fontstack}/{range}.pbf"
sources: {}
layers: []
# Building shading. Tangram's lights are fixed to the world, so this one is
# anchored to the map: from the south-west (239°), 30° from overhead — the
# same light MapLibre's default gives at this camera's bearing, now staying
# put as the map turns. Tune `position`/`intensity` to change face contrast.
light:
anchor: map
position: [1.15, 239, 30]
intensity: 0.5
images:
earth: { url: "https://docs.maplibre-yaml.org/classics/crosshatch/earth.png", pixelRatio: 2 }
landuse: { url: "https://docs.maplibre-yaml.org/classics/crosshatch/landuse.png", pixelRatio: 2 }
water: { url: "https://docs.maplibre-yaml.org/classics/crosshatch/water.png", pixelRatio: 1 }
building-hatch: { url: "https://docs.maplibre-yaml.org/classics/crosshatch/building-fallback.png", pixelRatio: 4 }
# The 3x3 tonal atlas tonal-hatch samples: Tangram's hatch.png
# (tangrams/blocks filter/imgs, MIT), verbatim. No static layer uses it.
hatch-atlas: { url: "https://docs.maplibre-yaml.org/classics/crosshatch/hatch-atlas.png" }
sources:
omt:
type: vector
url: "https://tiles.openfreemap.org/planet"
attribution: '<a href="https://openfreemap.org">OpenFreeMap</a> © <a href="https://www.openmaptiles.org/">OpenMapTiles</a> Data from <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
layers:
# Tangram `earth`: paper, hatched with hatch_0 repeated per tile.
- id: earth
type: background
paint:
background-pattern: earth
# Tangram `landuse`: the denser hatch_2.
- id: parks
type: fill
source: omt
source-layer: park
paint:
fill-pattern: landuse
# A data-driven pattern: open sand reads as bare ground (the light earth
# hatch); vegetation and farmland take the dense landuse hatch.
- id: landcover
type: fill
source: omt
source-layer: landcover
filter: ["match", ["get", "class"], ["grass", "wood", "farmland", "sand"], true, false]
paint:
fill-pattern: ["match", ["get", "class"], "sand", "earth", "landuse"]
# Tangram `water`: #343434 lit through a crumpled-paper normal map.
- id: water
type: fill
source: omt
source-layer: water
paint:
fill-pattern: water
- id: roads
type: line
source: omt
source-layer: transportation
filter: ["match", ["get", "class"], ["motorway", "trunk", "primary", "secondary", "tertiary", "minor", "service"], true, false]
layout:
line-join: round
line-cap: round
paint:
line-color: "#343434"
line-width:
- interpolate
- ["exponential", 1.6]
- ["zoom"]
- 13
- ["match", ["get", "class"], ["motorway", "trunk"], 2, 0.6]
- 18
- ["match", ["get", "class"], ["motorway", "trunk"], 16, ["primary", "secondary"], 10, 6]
- id: buildings
type: fill-extrusion
source: omt
source-layer: building
minzoom: 13
paint:
# The static fallback: one light pen hatch on every face.
fill-extrusion-pattern: building-hatch
# Tangram exaggerates height by max(1, 0.5 + (1 - zoom/20) * 5) — linear
# in zoom (2.25x at z13 → 1x at z18), so one interpolate reproduces it.
fill-extrusion-height:
- interpolate
- ["linear"]
- ["zoom"]
- 13
- ["*", ["coalesce", ["get", "render_height"], 10], 2.25]
- 18
- ["coalesce", ["get", "render_height"], 10]
fill-extrusion-base: ["coalesce", ["get", "render_min_height"], 0]
fill-extrusion-vertical-gradient: true
# The runtime upgrade. The paint above is its fallback, and the effect
# stands at the same heights: it evaluates this layer's own expressions.
effect:
type: tonal-hatch
# Tangram's brightness exposure; ~0.72 matches the reference tone.
gain: 0.72
- id: place-labels
type: symbol
source: omt
source-layer: place
filter: ["match", ["get", "class"], ["neighbourhood", "suburb", "quarter"], true, false]
layout:
text-field: ["coalesce", ["get", "name:en"], ["get", "name"]]
text-font: ["Libre Baskerville Italic"]
text-size: 22
text-max-width: 7
text-pitch-alignment: viewport
paint:
text-color: "#000000"
text-halo-color: "#f9f3e3"
text-halo-width: 3.5
blueprint.yaml
blueprint.yaml
# yaml-language-server: $schema=https://docs.maplibre-yaml.org/schema/latest/map.schema.json
# Classic-style example: blueprint — the launch-page document (docs
# /classics/). A drafting sheet in the Mapzen spirit, not a port of a
# Tangram original.
#
# This is the gallery's static preset (configs/gallery/blueprint.yaml) plus
# one statement of intent: `effect: blueprint` on the buildings. Everything
# else is plain style spec.
#
# - With @maplibre-yaml/effects loaded, <ml-map> upgrades the buildings to
# a metre-scaled drafting grid on every face (lines never stretch) with
# glowing edges.
# - Without it — or where the effect cannot run (globe, terrain, no WebGL2)
# — the buildings render exactly as authored below: the static fallback.
# - `mlym emit` (--with-fallbacks, the default) ships that same static
# layer with one lossy warning; `--strict` refuses, because the exported
# map is not the map the effect draws. That is fallback-where-honest.
#
# Download it, change the grid spacing or the colours, and open it in any
# page that loads <ml-map>. The docs build compiles this file with
# `mlym emit` for the launch page's exported pane, and a test pins the two
# together.
type: map
id: blueprint
config:
center: [-74.0118, 40.7075]
zoom: 15.9
pitch: 60
bearing: 29
# Inline base style: OpenFreeMap's glyphs for the labels; the document
# owns every layer.
mapStyle:
version: 8
glyphs: "https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf"
sources: {}
layers: []
images:
grid: { url: "https://docs.maplibre-yaml.org/classics/blueprint/grid.png", pixelRatio: 2 }
sources:
omt:
type: vector
url: "https://tiles.openfreemap.org/planet"
attribution: '<a href="https://openfreemap.org">OpenFreeMap</a> © <a href="https://www.openmaptiles.org/">OpenMapTiles</a> Data from <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
layers:
- id: ground
type: background
paint:
background-pattern: grid
- id: water
type: fill
source: omt
source-layer: water
paint:
fill-color: "#072a63"
- id: shoreline
type: line
source: omt
source-layer: water
paint:
line-color: "#9fd3ff"
line-width: 1.2
line-opacity: 0.8
- id: parks
type: line
source: omt
source-layer: park
paint:
line-color: "#9fd3ff"
line-width: 1
line-dasharray: [3, 2]
line-opacity: 0.7
- id: roads
type: line
source: omt
source-layer: transportation
filter: ["match", ["get", "class"], ["motorway", "trunk", "primary", "secondary", "tertiary", "minor", "service"], true, false]
layout:
line-join: round
line-cap: round
paint:
line-color: "#d8f0ff"
line-opacity: 0.85
line-width:
- interpolate
- ["exponential", 1.6]
- ["zoom"]
- 13
- ["match", ["get", "class"], ["motorway", "trunk"], 1, 0.4]
- 18
- ["match", ["get", "class"], ["motorway", "trunk"], 5, ["primary", "secondary"], 3, 1.5]
- id: buildings
type: fill-extrusion
source: omt
source-layer: building
minzoom: 13
paint:
# The static fallback: flat-shaded blue blocks.
fill-extrusion-color: "#1a56b0"
fill-extrusion-height: ["coalesce", ["get", "render_height"], 10]
fill-extrusion-base: ["coalesce", ["get", "render_min_height"], 0]
fill-extrusion-vertical-gradient: true
# The runtime upgrade. The paint above is its fallback, and the effect
# stands at the same heights: it evaluates this layer's own expressions.
effect:
type: blueprint
line: "#cfeeff"
ground: "#1a56b0"
grid: 4 # metres between grid lines
- id: place-labels
type: symbol
source: omt
source-layer: place
filter: ["match", ["get", "class"], ["neighbourhood", "suburb", "quarter"], true, false]
layout:
text-field: ["coalesce", ["get", "name:en"], ["get", "name"]]
text-font: ["Noto Sans Regular"]
text-size: 15
text-transform: uppercase
text-letter-spacing: 0.25
text-max-width: 9
text-pitch-alignment: viewport
paint:
text-color: "#e6f6ff"
text-halo-color: "#0b3d91"
text-halo-width: 2.5

The static presets on their own, without effects, are in the gallery: Crosshatch and Blueprint.

Map data © OpenStreetMap contributors (ODbL), © OpenMapTiles, via OpenFreeMap. The crosshatch look and textures follow Tangram’s crosshatch style and the tangrams/blocks hatch atlas (© Mapzen, MIT). Font: Libre Baskerville (OFL).