Skip to content
glyphcss

Layers

Loading terrain…

Terrain, elevation contours and country borders share one map. Layers form an ordered list; geometry also uses depth testing.

const id = map.addLayer({ type: "line", source: borders, color: "#ff9e64" });
map.moveLayer(id); // move to the end
map.removeLayer(id);

Every layer accepts an optional id. addLayer(layer, beforeId) inserts before another layer; moveLayer(id, beforeId) reorders it.

TypeData / key options
backgroundcolor, density; no source
rasterElevation tile or provider; classifier, colors
contourField or elevation provider; levels, labels
lineVector lines; color, colorProperty, colors, padCells, filterAtResolution, simplify, sharedArcs
fillVector polygons; color, colorProperty, colors, drape
fill-extrusionVector buildings; heightProperty, height, heightScale
symbolDOM text labels; textProperty, priorityProperty
circleStamped glyph discs sized in CSS pixels; radius, radiusProperty, radiusScale, color
glyphPoints and labels in copied text; size, ramp, textProperty
heatmapDensity relief; radius, weightProperty, colors, bounds, height, threshold
modelYour polygons and attribution; no source
const cities = {
features: [{
geometryType: "point" as const,
rings: [[[-58.38, -34.6]]],
properties: { name: "Buenos Aires" },
}],
};
map.addLayer({ type: "glyph", source: cities, textProperty: "name", color: "#ff9e64" });

Vector layers accept a GlyphMapVectorFeatureCollection or GlyphMapVectorProvider. Static features use geometryType ("point", "line", "polygon") and rings; polygon hole groups use polygons. Add attribution to the collection to include its credits.

Provider layers can select sourceLayer; all vector layers accept filter: (feature) => boolean, applied after source-layer selection. Without terrain or a custom groundElevation, features sit on the datum.

map.addLayer({
type: "raster", source: reliefProvider,
classifier: GlyphMapClassifiers.etopo1V1, colors: terrainColors,
minElevation: 0, density: 2,
});

colors supplies one colour per classifier band. Optional minElevation / maxElevation flatten terrain outside a metre window; colours retain the original elevations. padCells keeps nearby provider tiles mounted. See terrain.

map.addLayer({
type: "contour", source: reliefProvider,
levels: { interval: 500 }, minElevation: 0,
color: "#ffe8b8", labels: true, labelEvery: 5,
});

levels accepts a count, an explicit elevation array, or { interval } in metres. Intervals stay fixed while panning. Elevation windows clip contours independently of terrain; match their floors. generalize is a smoothing radius in output cells: the field is smoothed at about that radius before the levels are cut and closed rings smaller than it are dropped, so a line keeps the bends a reader can see and loses per-sample jitter. It follows the zoom in half-octave steps, so zooming in brings detail back; omitted or 0 cuts the native grid. Labels default off; labelEvery defaults to 5. getContourFieldRange(id) reports the data range.

map.addLayer({ type: "fill", source: regions, color: "#4a5a3a", drape: "flat" });

drape: "surface" (default) follows terrain; "flat" keeps a datum overlay. A predicate can choose per feature. For OSM water, use glyphMapOpenMapTilesWaterDrape: ocean flat, lakes draped. colorProperty plus colors maps property values to colours.

map.addLayer({
type: "fill-extrusion", source: osm, sourceLayer: "building",
heightProperty: "render_height", baseOffsetProperty: "render_min_height",
height: 8, heightScale: 1, color: "#8a8f9c",
colorVariation: 0.5, facade: true,
});

Heights and base offsets are true metres above terrain, exempt from terrain exaggeration. height is the fallback; heightScale multiplies height. facade and colorVariation default off. See a live street view.

outline: "braille" opts into braille roof rings and, when tilted, vertical corner edges at the mesh’s planted base and roof heights. The body uses . so edges carry the shape. Only footprints spanning at least two projected cells get outlines; the cutoff follows zoom and output density. Scene depth and exact building planes hide occluded edges, while incident faces accept their own edge without a depth bias. All glyphs fit the universal atlas. Omitted preserves the original output. Building outlines currently support braille only.

Add fill: false alongside outline: "braille" for outlines only: no building mesh is mounted or rasterized. Terrain and nearer building faces still hide roof rings and vertical corners. fill defaults to true and is ignored without braille outlines.

Add blank: true with unfilled braille outlines to erase rear raster content inside the visible building faces. Face depth preserves nearer terrain, elevated roads and other nearer meshes; courtyards stay open. This skips lighting and solid glyph shading and reuses the outline pass’s projected faces. The default is false, preserving the see-through outline output. Tiny faces still blank covered cells even when their footprint is too small for an outline. DOM symbol labels remain overlays and are not erased by this cell mask.

For OpenMapTiles, pass buildingOutline: "braille" to glyphMapOpenMapTilesLayers. The /maps workbench and its code export draw braille lines and blanked outlines without fill for buildings by default; ?lines=box switches to box lines with the normal building fill.

map.addLayer({
type: "symbol", source: cities, textProperty: "name",
textAnchor: "left", textOffset: [1, 0], color: "#ffe8b8",
});
  • symbol labels points and lines, not polygons; text(feature) composes labels.
  • priorityProperty / minPriority control decluttering; labels wrap at 20 characters, up to three lines.
  • textAnchor defaults to "center"; textOffset defaults to [0, 0], in cells with y down.
  • glyph uses size / sizeProperty / sizeScale in cell rows; default size: 0 is one cell, with ramp ["·", "•", "●"].
  • Glyph altitude / altitudeProperty / altitudeScale use true metres above ground; onSelect(feature) handles selection.
  • Use symbol for DOM interaction; glyph and circle marks are stamped into the copied text.
  • circle is the same stamp as glyph, sized in CSS pixels instead of cell rows: radius / radiusProperty * radiusScale are divided by the grid’s cell height to get the disc radius in cell rows, and a radius under half a row becomes the single smallest mark (·). Features sharing a cell merge into one mark. color tints the mark; omitted keeps the terrain’s colour. There is no element per circle, and no density, ramp, altitude, label or onSelect; use glyph for those.

Line layers can opt into simplify: "vw". It reuses the bake pipeline’s latitude-corrected Visvalingam–Whyatt simplifier, with a tolerance of half the current output cell’s degrees (view.span / cols, adjusted for layer density). Quarter-octave zoom buckets cache each source line, so orbiting does not repeat simplification. Zooming in retains finer source detail. Endpoints stay fixed; closed rings that would collapse below a triangle retain their source geometry. Walking retains full source detail.

sharedArcs: true also reconstructs polygon boundary topology per source feature set or tile: exact shared edges (in either direction) become one arc, split at junctions before VW. Junction endpoints stay fixed, and the arc geometry and zoom buckets are cached. Explicit line features keep their own paths. Differently sampled edges are not snapped together; bake shared arcs before tile clipping when source tiles need consistent simplification.

The experimental experimentalGlyphStrategy: "box" joins accepted paths in one graph per layer and frame, including coincident feature/tile endpoints. Diagonal steps add one staircase corner using the same depth and ownership tests; when both corners are blocked, both cells point into the hidden corner instead. Immediate backtracks collapse before joining. A closed ring whose projected extent is under two cells becomes one depth-tested · at its geometry centroid. Open lines retain their joined cells, including short stubs; unjoined cells restore the surface instead of leaving dots. Box depth tests read the surface before the layer wrote any ink; staircase corners cannot borrow cells from a separate path.

Omitting these options leaves the default output unchanged. The /maps borders enable live VW and shared arcs, and its OpenStreetMap line rows enable VW; only boundaries request shared polygon arcs. The page draws its lines in braille by default; ?lines=box opts into box for comparison.

Lines accept colorProperty and colors with the same per-feature fallback as fills. filterAtResolution(feature, degreesPerCell) can make a live resolution cut after filter; it receives the actual overlay cell size and 0 while walking. A shared polygon arc carries the properties every polygon contributing to it agrees on, so a border between two polygons of one class keeps its colour and a border between two classes falls back to the layer color; explicit line features retain their own.

OptionApplies toEffect
densityAll layersMesh detail; strokes at 1 or omitted follow the surface grid, other values use an independent grid
renderModeMesh layersOverride scene mode; a different mode costs an extra pass
glyphPaletteMesh layersOverride the character ramp independently of colours; a different ramp costs an extra pass

Mesh layers are raster, fill, fill-extrusion, heatmap, and model.

const marker = map.addMarker({ at: [-58.38, -34.6], label: "Buenos Aires", elevation: 30 });
marker.remove();

Markers are individual DOM elements, separate from layers. marker.el exposes the element. elevation defaults to 0, passes through the projection’s elevation axis, and does not automatically follow terrain.