sources
sources is the single home for everything external: document-scoped files
(brushes, images, fonts) sit next to tile-scoped pyramids (MVT, PMTiles, DEM,
raster imagery). Each entry’s type selects the variant. brush and image
name their file with src, sprite with image and index, and every other
variant with url (geojson may carry its document inline as data instead).
"sources": { "glazing": { "type": "brush", "src": "file:brushes/watercolor_glazing.myb" }, "basemap": { "type": "mvt", "url": "https://papers.reearth.land/protomaps/tilejson.json" }, "terrain": { "type": "dem", "encoding": "terrarium", "max-zoom": 14, "on-missing": "upsample", "url": "https://terrain.reearth.land/…/{z}/{x}/{y}.webp" }}Nothing is bundled into the library — see sources and assets for why, and for how the host binds the bytes.
URI schemes (document-scoped)
Section titled “URI schemes (document-scoped)”A brush or image src, a sprite’s image, and a font’s url take:
| Scheme | Resolves to |
|---|---|
file:PATH |
local file, relative to --assets-dir (or absolute). The extension may be omitted — it is inferred from the source type |
http(s)://… |
fetched by the host before the first render, then cached in the in-memory bank |
data:[<mediatype>][;base64],… |
decoded in-process, no I/O — works in every host including wasm. image/* loads as an image; anything else is tried as a brush |
builtin:NAME |
whatever the host registered under NAME at runtime |
system:FAMILY |
font only — a face resolved from installed fonts. Machine-dependent, unavailable on wasm |
Document-scoped types
Section titled “Document-scoped types”brush — a MyPaint .myb brush. Any .myb works; the example styles ship
CC0 brushes by David Revoy next to their style JSON.
image — a PNG/WebP image, for place, tiling, and texture work.
sprite — a sprite sheet: an atlas image plus an index mapping icon names
to atlas sub-rects. The index is a URL/path to a sprite .json or an inline map
of the same shape. An icon node crops a named rect into a Sprite for stamp
(symbol icons) or tiling (fill-pattern). Nine-slice stretchX/stretchY/
content metadata is honoured by icon-text-fit.
font — outline font bytes (TTF/OTF/TTC) for the text node’s font stack,
named with a url.
glyphs — a MapLibre glyph-PBF endpoint ({fontstack}/{range} template)
serving pre-rendered SDF ranges, fetched lazily. The no-font-files alternative to
font, and what ezu translate falls back to.
Tile-scoped types
Section titled “Tile-scoped types”mvt — an XYZ MVT URL template, or a TileJSON document. The host fetches one
tile per render, decodes every layer, and binds each under <source>.<layer> —
the source and layer a features node names. A style may declare any number
of mvt / pmtiles sources (a basemap and an overlay, say, or one per data set);
each is fetched and bound under its own name.
Optional min-zoom / max-zoom give the zoom range the source serves, as a
MapLibre source’s minzoom / maxzoom do: below min-zoom the source binds
nothing and its layers draw nothing; past max-zoom each tile is cut from the
covering ancestor at max-zoom, its geometry reprojected into the requested tile.
on-missing says what a tile missing within that range means, as for raster
and dem: empty draws no features, upsample reprojects the nearest ancestor
that exists (no higher than min-zoom), and error fails the render. Left out,
the host decides, which is how vector sources have always behaved: the CLI looks
up to --overzoom-levels parents up (4 by default).
pmtiles — a PMTiles archive (local path or http(s)://). Layers bind exactly
as mvt, and it takes the same min-zoom / max-zoom.
dem — a raster-DEM pyramid. url may be an XYZ template, a TileJSON
document, or a .pmtiles archive. encoding is terrarium, mapbox-rgb or
custom and must match the data, since the RGB channels mean different things.
custom decodes each pixel as
R*red-factor + G*green-factor + B*blue-factor - base-shift, MapLibre’s
custom encoding; the factors default to 1 and base-shift to 0, and
they may only be given with custom:
"terrain": { "type": "dem", "url": "https://example.com/dem/{z}/{x}/{y}.png", "encoding": "custom", "red-factor": 6553.6, "green-factor": 25.6, "blue-factor": 0.1, "base-shift": 10000 }The host
stitches the 3×3 neighbourhood into a per-tile ScalarField with geo_scale
populated, so hillshade and slope produce real-world angles, and binds it
under tile.<source-name> for the dem node.
raster — an RGBA imagery pyramid (satellite, pre-rendered basemaps; PNG /
WebP / JPEG). url may be an XYZ template, a TileJSON document, or a .pmtiles
archive. Stitched over the padded canvas and bound under the source name for the
raster node.
geojson — GeoJSON in WGS84 lon/lat, carried inline as data or named by
url. Either way the host reads the document once per style and projects it
into each tile’s frame, binding it as one layer named <source>.<source>. A
url may be http(s)://, file: (resolved against --assets-dir, so features
can sit beside the style rather than inside it), or a data: URL:
"sources": { // The whole document, in the style. "pins": { "type": "geojson", "data": { "type": "FeatureCollection", "features": [] } }, // Or beside it. "routes": { "type": "geojson", "url": "file:routes.geojson" }, // Or anywhere. "places": { "type": "geojson", "url": "https://example.com/places.geojson" }}Unlike the tiled sources, a GeoJSON document is not tile-addressed: one document covers the world, so rendering a whole pyramid reads it exactly as many times as rendering one tile does.
Pyramid options
Section titled “Pyramid options”For raster and dem:
| Field | Meaning |
|---|---|
min-zoom |
shallowest zoom the source has. Below it nothing is fetched or bound, so the raster node draws transparent pixels and the dem node a zero field (MapLibre’s source minzoom) |
max-zoom |
deepest zoom the source has. Deeper requests always upsample from this ancestor |
neighbor-fetch |
fetch the 8 neighbouring tiles too and stitch them, so the pad region holds real pixels (and, for dem, slopes stay seamless across tile edges). Default true |
on-missing |
in-range 404 policy: empty (default — transparent / zero elevation), upsample (walk up parents and upsample the covered sub-region), or error (fail the render, so a server can answer 404) |
elevation-offset |
dem only: metres subtracted from every decoded sample, to rebase a geoid-relative dataset. Default 0 |
resampling |
raster only: how tile pixels are sampled when they do not land one to one on the canvas (an overzoomed tile, or a tile size other than the canvas’s). linear (default) blends the nearest four; nearest repeats the one underneath, so each tile pixel stays a hard-edged block (MapLibre’s raster-resampling) |
A pyramid’s tile size is not declared, unlike MapLibre’s tileSize: each tile’s
edge is read from its decoded image, which may be any square size, and the tile
is resampled onto the canvas, so a 256 px and a 512 px pyramid render the same
ground. dem still accepts a tile-size from
older styles and ignores it.
Attribution
Section titled “Attribution”Any source may declare an attribution string. Sources that do not inherit
upstream metadata — TileJSON’s attribution field, or PMTiles archive metadata —
when the host opens them. The document’s own top-level attribution is merged in.
Document::attributions() returns the declared list; GET /style/attribution and
the wasm renderer.attribution return the merged result.
Map renders on this site are made fromOpenStreetMap data viaProtomaps (© OpenStreetMap contributors), elevation from Re:Earth Terrain,Mapterhorn andEGM2008 (NGA), and aerial imagery from GSI Japan(© 国土地理院). The painterly styles use CC0 brushes byDavid Revoy.