Skip to content

Painting

Ops that consume Features and put pixels on a canvas — flat fills, scatter dabs, brush strokes, stamps, text.

13 ops: brush-file, circles, fill-dabs, fill-solid, label-boxes, label-placement, line, line-stamp, stamp, stroke, text, text-draw, text-labels.

Ops with no demo image below produce no visible result on their own — they feed other nodes rather than paint.

Brush source. src is an @asset ref or a literal path/name resolved by the host’s AssetLoader.

Field Type Required Description
src string yes Asset reference (@name) or literal path.

Filled disks at every feature point (tiny-skia), with per-feature radius, color, opacity, and optional stroke ring. The crisp vector counterpart to MapLibre’s circle layer. Each paint property has an optional *-expr MapLibre-expression sibling evaluated per feature group.

A tile rendered with circles
A filled circle at every input point, with a stroke. style
Field Type Required Description
blur number (0…∞) | $param | @node no MapLibre circle-blur: the fraction of the circle’s outer radius (to the outside of the stroke ring) over which fill and ring fade out to the edge, with a smoothstep. 0 (the default) keeps a crisp edge; 1 fades from the centre; above 1 fades even the centre.
blur-expr — no A MapLibre number expression for blur, evaluated per feature group; overrides the constant blur.
color color | $param | @node no sRGB hex color, $param reference, or @node scalar port.
color-expr — no A MapLibre color expression (JSON array, e.g. [“match”, [“get”, “c”], “a”, “#f00”, “#0f0”]), evaluated per feature group; overrides the constant color.
features @node yes Reference to another node (@name).
opacity number (0…1) | $param | @node no —
opacity-expr — no A MapLibre number expression giving opacity, evaluated per feature group; multiplies the fill’s alpha, and the stroke ring’s too unless stroke-opacity or stroke-opacity-expr is set. Overrides the constant opacity.
radius number (0…∞) | $param | @node no —
radius-expr — no A MapLibre number expression (px), evaluated per feature group; overrides the constant radius.
stroke-align center | outside | inside | $param no Where the stroke ring sits against radius. center straddles it, half inside and half outside; outside lies wholly outside it, from radius to radius + stroke-width, as MapLibre draws circle-stroke-width; inside lies wholly within it, so the circle never grows past radius. The fill always reaches radius; under an opaque, unblurred outside ring it runs a pixel further, so fill and ring meet without a seam.
stroke-color color | $param | @node no sRGB hex color, $param reference, or @node scalar port.
stroke-color-expr — no A MapLibre color expression for the stroke ring, evaluated per feature group; overrides the constant stroke-color.
stroke-opacity number (0…1) | $param | @node no The stroke ring’s opacity (MapLibre circle-stroke-opacity), in place of opacity, which then applies to the fill alone. Left out, the ring takes opacity.
stroke-opacity-expr — no A MapLibre number expression for the stroke ring’s opacity, evaluated per feature group; overrides stroke-opacity. A group whose expression doesn’t resolve to a number falls back to stroke-opacity, or to opacity when that is left out.
stroke-width number (0…∞) | $param | @node no —
stroke-width-expr — no A MapLibre number expression (px) for the stroke ring, evaluated per feature group; overrides the constant stroke-width. A ring is drawn only when width > 0.

Watercolor scatter-dab fill with world-deterministic jitter (seamless across tiles). Color and opacity each have an optional *-expr MapLibre-expression sibling evaluated per feature group; the dabs land and jitter where they would without it, and each takes the paint of the group whose polygon covers its centre.

A tile rendered with fill-dabs
The same polygons as scatter dabs — many soft, faint stamps instead of coverage. style
Field Type Required Description
color color | $param | @node yes sRGB hex color, $param reference, or @node scalar port.
color-expr — no A MapLibre color expression (JSON array, e.g. [“match”, [“get”, “class”], “water”, “#4a6c99”, “#8a9a5b”]), evaluated per feature group; overrides the constant color. As with color, the alpha is ignored — opacity or opacity-expr sets the dabs’ opacity. A group whose expression doesn’t resolve to a color falls back to color.
features @node yes Reference to another node (@name).
hardness number (0…1) | $param | @node no —
opacity number (0…1) | $param | @node yes —
opacity-expr — no A MapLibre number expression giving the per-dab opacity, evaluated per feature group; overrides the constant opacity. A group whose expression doesn’t resolve to a number falls back to opacity.
opacity-jitter number (0…1) | $param | @node no —
paint number (0…1) | $param | @node no —
position-jitter number (0…1) | $param | @node no —
radius-px number (0…∞) | $param | @node yes —
size-jitter number (0…1) | $param | @node no —
spacing-px number (0…∞) | $param | @node yes —
value-jitter number (0…1) | $param | @node no —

Solid polygon fill with optional outline and Gaussian blur.

A tile rendered with fill-solid
Flat polygon fill, with an outline. style
Field Type Required Description
blur-sigma number (0…∞) | $param | @node no —
blur-sigma-max number (0…∞) no Upper bound on blur-sigma for padding, required when blur-sigma is an @node port. Values above it are clamped.
edge color | $param | @node no sRGB hex color, $param reference, or @node scalar port.
edge-alpha number (0…1) | $param | @node no Opacity multiplied into the outline’s own alpha. fill-alpha fades the fill alone, so to fade the outline with it, as MapLibre’s fill-opacity fades fill-outline-color, give both the same value.
edge-alpha-expr — no A MapLibre number expression for the outline’s opacity, evaluated per feature group at paint time. When present it overrides the constant edge-alpha; a group whose expression doesn’t resolve to a number falls back to edge-alpha.
edge-expr — no A MapLibre color expression for the outline (MapLibre data-driven fill-outline-color), evaluated per feature group at paint time. When present it overrides the constant edge; the color’s alpha is the outline’s opacity, as edge’s is, times edge-alpha; fill-alpha does not fade it. A group whose expression doesn’t resolve to a color falls back to edge, or draws no outline when edge is left out.
edge-width number (0…∞) | $param | @node no —
features @node yes Reference to another node (@name).
fill color | $param | @node yes sRGB hex color, $param reference, or @node scalar port.
fill-alpha number (0…1) | $param | @node no —
fill-expr — no A MapLibre color expression (JSON array, e.g. [“match”, [“get”, “class”], “water”, “#88c”, “#ccc”] or [“interpolate”, [“linear”], [“get”, “area”], 0, “#eef”, 1000, “#049”]), evaluated per feature group at paint time. When present it overrides the constant fill; a group whose expression doesn’t resolve to a color falls back to fill. Unlocks continuous data-driven fills that constant fill can’t express.
opacity-expr — no A MapLibre number expression (JSON array) giving fill opacity, evaluated per feature group at paint time. When present it overrides the constant fill-alpha; a group whose expression doesn’t resolve to a number falls back to fill-alpha.

The boxes a label-placement node measured its labels by, as polygons — one per box — so any geometry and paint op can draw them: a bordered or rounded badge (buffer → stroke), an offset shadow (transform), or a debug overlay of placement. Reads the decisions already made, so nothing is placed twice and the boxes match what text-draw draws; labels placed from a neighbour tile’s candidates are included, so boxes continue across tile edges. Each polygon carries the labelled feature’s properties plus part (text, icon, background, glyph or collision), placed (false for a candidate that did not place, with include: all), label-id (shared by every box of one label, the same on every tile) and label-layer (the id of the text-labels node the label came from, which tells apart two layers labelling the same features, such as a number and a name on the same points). These overwrite a feature property of the same name.A placed label also carries overlapped (true when it overlaps a label placed before it, which only overlap: always or fallback permits) and variant-index: where the position it took sits in the list it was tried from (anchor-offsets, or the anchors of the deprecated anchor-variants), 0 for the first position, for a lone one and for a line label, and absent when the variant shown draws no text. A label that did not place carries drop-reason instead: collision when it lost its collision test, dedupe when its layer’s dedupe-key-expr dropped it because a label with the same key had already placed within dedupe-distance-px, culled when its box reaches past its layer’s max-extent-px, so it never reached placement (it takes no space and is not drawn). A point label gives its text block (no padding), icon (rotated by icon-rotate), background box (with background-padding or background-color) and the collision box or boxes it was tested with, padding included. A label turned by rotate-deg gives its text and background as quads turned about its anchor, and its collision box as their axis-aligned bounds. A line label gives one glyph quad per glyph, rotated along the path, and the axis-aligned collision box placement tested for each glyph.

Field Type Required Description
extent integer (1…∞) no Coordinate extent of the emitted geometry, matching the features it is combined with.
filter-expr — no A MapLibre filter expression (JSON array, e.g. [“>”, [“coalesce”, [“get”, “variant-index”], 0], 0]), evaluated per box against every property the box carries, part included, with geometry-type Polygon. A box is emitted only when the expression is truthy; one whose expression errors is dropped. Picks out, say, the labels that moved off their first position, to draw a leader line to their feature.
include placed | all | $param no placed emits the labels that placed; all adds the candidates that lost their collision test or were dropped by dedupe-key-expr, and the point labels culled by max-extent-px, with placed: false, at their first anchor. Duplicate copies of one label are never emitted.
labels @node no Only this text-labels layer of the placement (it must be wired into the placement node too). Default: every layer.
parts array of text | icon | background | glyph | collision no Which boxes to emit. Default: every kind a label has.
placement @node yes Reference to another node (@name).

Place the labels of every text-labels layer against one shared collision index, the way maplibre-gl-js does — so a POI label can knock out an overlapping road name. labels lists the layers bottom-first (paint order, as in stack); priority is top-down, so the last entry places first and wins. Feed the result to each layer’s text-draw node.

Field Type Required Description
labels array of @node yes text-labels layers, bottom first. The topmost layer places first.

Brush stroke along MVT polylines. Color, radius and opacity each have an optional *-expr MapLibre-expression sibling evaluated per feature group; the pressure jitter is seeded by world position, so it is the same whichever values a group resolves to.

Field Type Required Description
brush @node yes Reference to another node (@name).
color color | $param | @node yes sRGB hex color, $param reference, or @node scalar port.
color-expr — no A MapLibre color expression (JSON array, e.g. [“match”, [“get”, “class”], “river”, “#48b”, “#888”]), evaluated per feature group; overrides the constant color. As with color, the alpha is ignored — the stroke’s opacity comes from the brush, opacity or opacity-expr. A group whose expression doesn’t resolve to a color falls back to color.
dtime number (0…∞) | $param | @node no —
dtime-stroke-curve array of array of number | $param no Piecewise-linear [[t, y], ...] multiplier on dtime. y scales the per-vertex dtime — y=3 makes the brush linger 3× longer (slower hand), y=0.3 sweeps through 3× faster. Used with dynamics-driven brushes that respond to stroke speed.
features @node yes Reference to another node (@name).
hardness-stroke-curve array of array of number | $param no Piecewise-linear [[t, y], ...] driving a libmypaint stroke input on the brush. t is normalized stroke progress in [0, 1]; y is an offset added to the setting’s base value. radius is log-space (y=-2.3 ≈ ×0.1, y=+0.69 ≈ ×2); opaque and hardness are linear.
opacity number (0…1) | $param | @node no —
opacity-expr — no A MapLibre number expression giving the brush opacity, evaluated per feature group; overrides opacity (or the brush’s own). A group whose expression doesn’t resolve to a number keeps opacity, or the brush’s.
opacity-stroke-curve array of array of number | $param no Piecewise-linear [[t, y], ...] driving a libmypaint stroke input on the brush. t is normalized stroke progress in [0, 1]; y is an offset added to the setting’s base value. radius is log-space (y=-2.3 ≈ ×0.1, y=+0.69 ≈ ×2); opaque and hardness are linear.
pressure-base number (0…1) | $param | @node no —
pressure-jitter number (0…1) | $param | @node no —
radius-expr — no A MapLibre number expression (px, e.g. [“interpolate”, [“linear”], [“zoom”], 10, 1, 16, 4]) giving the brush radius, evaluated per feature group with the tile’s zoom; overrides radius-px (or the brush’s own radius). A group whose expression doesn’t resolve to a number keeps radius-px, or the brush’s radius.
radius-px number (0…∞) | $param | @node no —
radius-stroke-curve array of array of number | $param no Piecewise-linear [[t, y], ...] driving a libmypaint stroke input on the brush. t is normalized stroke progress in [0, 1]; y is an offset added to the setting’s base value. radius is log-space (y=-2.3 ≈ ×0.1, y=+0.69 ≈ ×2); opaque and hardness are linear.

Repeat a sprite along each polyline, rotated to the line’s tangent (MapLibre line-pattern). Points/polygons ignored. width-px scales the image height to the stroke width; spacing-px sets the advance (0 = the scaled image width, seamless). Provide either an image input (one pattern for every line) or, for a data-driven line-pattern, a sheet input from a sprite node plus a name-expr that names each feature’s pattern.

Field Type Required Description
features @node yes Reference to another node (@name).
image @node no Reference to another node (@name).
name-expr — no A MapLibre expression giving each feature’s pattern icon name (MapLibre data-driven line-pattern), cropped per group from the sheet. Used instead of an image input; a group whose name doesn’t resolve to an icon in the sheet is not drawn.
offset-expr — no A MapLibre number expression (px) giving the offset, evaluated per feature group; overrides the constant offset-px. A group whose expression doesn’t resolve to a number falls back to offset-px.
offset-px number | $param | @node no MapLibre line-offset: run the pattern this many pixels to the right of the line’s direction of travel, or to the left when negative, the line moved as stroke’s offset-px moves it, with a corner that would reach more than twice the offset out bevelled. 0 stamps along the line itself.
opacity number (0…1) | $param | @node no —
opacity-expr — no A MapLibre number expression giving opacity, evaluated per feature group; overrides the constant opacity. A group whose expression doesn’t resolve to a number falls back to opacity.
scale number (0…∞) | $param | @node no Extra uniform scale on top of the width fit. Default 1.0.
sheet @node no A sprite node: the sheet name-expr names patterns from.
spacing-px number (0…∞) | $param | @node no Advance between stamps. 0 = the scaled image width (seamless tiling).
sprite string no Deprecated: load the sheet with a sprite node and wire it to sheet. An @sprite-source ref the node loads the sheet from itself; ignored when sheet is wired.
width-expr — no A MapLibre number expression (px, e.g. [“interpolate”, [“linear”], [“zoom”], 10, 2, 16, 8]) giving the stroke width, evaluated per feature group with the tile’s zoom; overrides the constant width-px. A group whose expression doesn’t resolve to a number falls back to width-px.
width-px number (0…∞) | $param | @node no Stroke width; the image height is fit to it. 0 = native height.

Stamp a sprite at every input point. Lines and polygons are ignored. Rotation, scale and position jitter are world-deterministic — a given point gets the same jitter no matter which tile renders it, and the three do not correlate. Provide either an image input (one sprite for every point) or, for a data-driven icon-image, a sheet input from a sprite node plus a name-expr that names each feature’s icon.

Field Type Required Description
anchor center | left | right | top | bottom | top-left | top-right | bottom-left | bottom-right | $param no Which part of the sprite sits on the point (MapLibre icon-anchor): bottom puts its bottom edge’s middle there, say, for a pin. Rotation and scale turn about the point. Default center.
anchor-expr — no A MapLibre string expression naming the anchor per feature group (data-driven icon-anchor): one of the anchor names. It takes the place of anchor for that group; a group whose result is not an anchor name, or whose evaluation fails, uses anchor, and a result that is not an anchor name is reported once per node.
features @node yes Reference to another node (@name).
image @node no Reference to another node (@name).
name-expr — no A MapLibre expression giving each feature’s icon name (MapLibre data-driven icon-image), cropped per group from the sheet. Used instead of an image input; any icon the sheet contains is croppable, so no enumeration is needed. A name the sheet lacks stamps nothing.
offset array of number no Shift [x, y] in px from the anchored position, right and down positive (MapLibre icon-offset). Like the sprite it is scaled by scale and turned by the rotation. Default [0, 0].
opacity number (0…1) | $param | @node no —
opacity-expr — no A MapLibre number expression giving opacity, evaluated per feature group; overrides the constant opacity.
position-jitter-px number (0…∞) | $param | @node no Per-point random offset, ±value pixels, drawn independently on x and y. Breaks up the regular lattice a point-grid leaves. Default 0 (no offset).
rotation-deg number | $param | @node no Constant rotation around each point, in degrees clockwise.
rotation-deg-expr — no A MapLibre number expression (degrees clockwise), evaluated per feature group; overrides the constant rotation-deg.
rotation-jitter-deg number (0…∞) | $param | @node no Per-point random rotation, ±value degrees.
scale number (0…∞) | $param | @node no Uniform scale applied to the sprite. Default 1.0 (native size).
scale-expr — no A MapLibre number expression, evaluated per feature group; overrides the constant scale. A group whose expression doesn’t resolve to a number falls back to scale.
scale-jitter number (0…∞) | $param | @node no Per-point random scale, ±value as a fraction of scale (0.2 = ±20%).
sheet @node no A sprite node: the sheet name-expr names icons from.
sprite string no Deprecated: load the sheet with a sprite node and wire it to sheet. An @sprite-source ref the node loads the sheet from itself; ignored when sheet is wired.

Crisp constant-width vector stroke along feature polylines (tiny-skia), with cap/join and an optional dasharray, in pixels or in stroke widths. The sharp counterpart to line (painterly brush) — for clean cartographic road/boundary lines.

A tile rendered with stroke
Crisp constant-width stroke, with a dash pattern. style
Field Type Required Description
cap butt | round | square | $param no —
color color | $param | @node yes sRGB hex color, $param reference, or @node scalar port.
color-expr — no A MapLibre color expression (JSON array, e.g. [“match”, [“get”, “class”], “river”, “#48b”, “#888”]), evaluated per feature group at paint time. When present it overrides the constant color; a group whose expression doesn’t resolve to a color falls back to color. Unlocks data-driven stroke colors.
dash-unit px | width | $param no What dasharray is measured in. px (the default) keeps the dashes the same length whatever the width; width multiplies each length by the stroke’s width, as MapLibre’s line-dasharray does, so with a width-expr each feature group’s dashes scale with the width it resolves to. A casing’s dashes scale with width-px, not with the gap.
dasharray array of number (0…∞) | $param no On/off lengths, in pixels or, with dash-unit: width, in multiples of the stroke width; omit for solid. Each length may be a $param.
features @node yes Reference to another node (@name).
gap-width-expr — no A MapLibre number expression (JSON array) giving the casing gap in pixels, evaluated per feature group at paint time. When present it overrides the constant gap-width-px; a group whose expression doesn’t resolve to a number falls back to gap-width-px.
gap-width-px number | $param | @node no MapLibre line-gap-width: when > 0 the stroke becomes a casing — two parallel bands of width-px each, their inner edges this many pixels apart (outer footprint gap + 2 * width, centred on the line). 0 strokes the centreline.
join miter | round | bevel | $param no —
miter-limit number (0…∞) | $param | @node no MapLibre line-miter-limit: how far a miter join may reach from the line, in half-widths, before it is bevelled instead, so sharp corners do not spike. MapLibre’s default is 2, which ezu translate writes; ezu’s default of 4 keeps longer points. Values of 1 or less bevel every join. When set, it also bounds the corners of an offset-px line.
offset-expr — no A MapLibre number expression (JSON array) giving the offset in pixels, evaluated per feature group at paint time. When present it overrides the constant offset-px; a group whose expression doesn’t resolve to a number falls back to offset-px.
offset-px number | $param | @node no MapLibre line-offset: draw the line this many pixels to the right of its direction of travel, or to the left when negative. Each vertex moves along the bisector of the segments meeting there, far enough to keep both segments the offset away; a corner sharper than that allows within miter-limit offsets, or twice the offset (MapLibre’s default line-miter-limit) when miter-limit is not set, is bevelled. A casing’s gap is centred on the offset line. 0 strokes the line where it is.
opacity number (0…1) | $param | @node no —
opacity-expr — no A MapLibre number expression (JSON array) giving stroke opacity, evaluated per feature group at paint time. When present it overrides the constant opacity; a group whose expression doesn’t resolve to a number falls back to opacity.
width-expr — no A MapLibre number expression (JSON array, e.g. [“interpolate”, [“linear”], [“zoom”], 10, 1, 16, 4]) giving stroke width in pixels, evaluated per feature group at paint time. When present it overrides the constant width-px; a group whose expression doesn’t resolve to a number falls back to width-px.
width-px number (0…∞) | $param | @node no —

Text labels (MapLibre symbol-placement): placement: point (default) labels each feature point, line / line-center walk each polyline with tangent-rotated glyphs. The font stacks come from a fonts node wired to fonts, and font names the one the labels use; text is a literal string or a MapLibre string expression evaluated per feature group. Paint properties and the layout knobs (in em) have optional *-expr siblings evaluated per feature group. Collision is on by default and is deterministic across tiles: candidates come from this tile plus the 8 neighbour tiles, so borders stay seamless. The node asks features to carry the neighbours: the features node reads them (host-bound under <source>.<layer>@dx,dy) with its own filter and zoom band, and each op between that works feature by feature applies itself to them too. An op that merges features passes none on, and the build warns that collision is then centre-tile-only. icon-name / icon-name-expr add MapLibre’s icon-image half: the icon is placed together with the text against the same index, so a symbol shows both or neither unless icon-optional / text-optional say otherwise. font and text are required unless the symbol is icon-only.

Field Type Required Description
allow-overlap boolean no Deprecated: use overlap (true is "always", false is "never"). MapLibre text-allow-overlap: place the label even if it collides. It still reserves its box (blocking later labels) unless ignore-placement. Ignored when overlap is set. Default false.
anchor center | left | right | top | bottom | top-left | top-right | bottom-left | bottom-right | $param no Which part of the label block sits on the point (point placement). Default center. Ignored when anchor-offsets is set.
anchor-expr — no A MapLibre string expression (data-driven MapLibre text-anchor), evaluated per feature group with the tile’s zoom, naming which part of the label block sits on the point: one of center, left, right, top, bottom, top-left, top-right, bottom-left, bottom-right. It takes the place of anchor for that group, with offset-em (or radial-offset) shifting the block as it would for that constant anchor, and justify: auto following it. A group whose result is not an anchor name, or whose evaluation fails, uses anchor; a result that is not an anchor name is reported once per node. Ignored, with a warning, when anchor-offsets or anchor-variants is set, since those name the anchors themselves. Point placement only.
anchor-offsets array of object no The positions a point label tries, in order: on collision it moves to the next, and takes the first whose box is free. Each entry names the anchor that sits on the point and how far the block shifts from there: offset-em [x, y] in em, right and down positive, or radial-em, an em distance pushed away from the point in the anchor’s direction (corners split it across both axes, and top / bottom measure it to the visible text, as MapLibre’s text-radial-offset does). Give one of the two, or neither for no shift. The same anchor may appear more than once, so a label can try a near spot and then a farther one. label-boxes reports the position taken as variant-index. MapLibre’s text-variable-anchor-offset is the nearest counterpart, but it also nudges top and bottom anchors by a baseline gap that offset-em does not; ezu translate folds that gap into the offsets it writes. When set, anchor, anchor-expr, offset-em, anchor-variants and radial-offset are ignored for point placement. Point placement only.
anchor-variants array of center | left | right | top | bottom | top-left | top-right | bottom-left | bottom-right no Deprecated: use anchor-offsets, with { "anchor": …, "radial-em": … } entries for a radial-offset. MapLibre text-variable-anchor: anchors tried in order on collision, the first free one placed (point placement). Overrides anchor when set.
background-color color | $param | @node no Fill a box behind each label’s text: the laid-out block’s bounds, every line included, grown by background-padding, with background-radius-px corners. The box fits the text however long it is. anchor and offset-em position the box rather than the text, so with anchor: top-left the box’s top-left corner sits on the point and the text starts background-padding inside it; changing the padding never moves the anchored corner. The box is the label’s collision box. It draws under the halo and glyphs, and over the layer’s icons; opacity applies to it as to the text. Point placement only: line-placed labels draw without it. Absent (default): no fill; the box still exists, unpainted, when background-padding is set.
background-padding array of number no [top, right, bottom, left] px between the label’s text and the edge of its background box, in the order icon-text-fit-padding uses. Setting it gives each point label the box even without background-color: the box then paints nothing, but anchor and offset-em still position it, it is still the label’s collision box, and label-boxes still reports it as background — a way to reserve space around a label or measure a badge drawn by other ops. Default [0, 0, 0, 0].
background-radius-px number (0…∞) | $param | @node no Corner radius of the background box’s background-color fill in px, clamped to half its shorter side. Default 0 (square corners).
collide boolean no Whether to run deterministic label collision. Default true (MapLibre’s default). Set false to draw every label (the pre-collision behaviour).
color color | $param | @node no sRGB hex color, $param reference, or @node scalar port.
color-expr — no A MapLibre color expression, evaluated per feature group; overrides the constant color.
dedupe-distance-px number no The distance in px, anchor to anchor, within which a placed label hides later labels with the same dedupe-key-expr key. Required with dedupe-key-expr; must be greater than 0.
dedupe-key-expr — no A MapLibre expression, evaluated per feature group, giving the key that marks labels as duplicates of each other: once a label of this layer has placed, a later label with an equal key whose anchor is nearer than dedupe-distance-px to it is dropped, so a name shared by several neighbouring features is shown once. Labels are visited in placement order (sort-key-expr, then feature order), and only labels that actually placed count, so a label that lost its collision never hides its duplicates. A deduped label takes no space, and label-boxes with include: all reports it with drop-reason: dedupe. A null or empty result never dedupes; other values compare by their text. Applies within this layer only, needs dedupe-distance-px and collision on, and works the same across tiles as long as the distance stays within the 8 neighbour tiles. Point placement only — line labels have spacing-px.
features @node yes Reference to another node (@name).
filter-expr — no Deprecated: remove it. The filter for the neighbour tiles the node reads itself with source/layer; ignored without them.
font — no The stack the labels use, by name: an array of font names as MapLibre’s text-font gives them (joined with , to form the name), or that name as one string. It must be one of the fonts node’s stacks. Also the fallback for font-expr and for format sections naming no declared stack. Without fonts wired (deprecated): an ordered fallback stack of font and/or glyphs source names from the document’s sources, which the node loads itself.
font-expr — no A MapLibre expression yielding an array of font names, evaluated per feature group (MapLibre data-driven text-font); overrides the constant font. Each result is canonicalized (names joined with ,) and looked up among the fonts node’s stacks; an undeclared stack, a non-array result, or an eval error falls back to font.
font-stacks object no Deprecated: declare the stacks on a fonts node and wire it to fonts; ignored when fonts is wired. Named stacks the node loads itself: canonical stack key (font names joined with ,) → ordered font/glyphs source names, consulted by font-expr and by format sections. Stacks are numbered in key order, which fixes each one’s stable id.
fonts @node no A fonts node: the font stacks font, font-expr and format sections pick from by name.
halo-color color | $param | @node no sRGB hex color, $param reference, or @node scalar port.
halo-color-expr — no A MapLibre color expression for the halo, evaluated per feature group; overrides the constant halo-color.
halo-width number (0…∞) | $param | @node no Halo radius in px around each glyph. Default 0 (no halo).
halo-width-expr — no A MapLibre number expression (px), evaluated per feature group; overrides the constant halo-width.
icon-allow-overlap boolean no MapLibre icon-allow-overlap. A symbol carries one overlap decision, so with text present this and overlap: always must both be set for the symbol to ignore collision. Default false.
icon-anchor center | left | right | top | bottom | top-left | top-right | bottom-left | bottom-right | $param no Which part of the icon sits on the point (MapLibre icon-anchor). Default center.
icon-ignore-placement boolean no MapLibre icon-ignore-placement; with text present it pairs with ignore-placement the same way as the overlap flags. Default false.
icon-name string no Constant MapLibre icon-image: the sprite to draw at each point, cropped from icon-sheet. Needs icon-sheet.
icon-name-expr — no A MapLibre expression naming each feature’s icon (data-driven icon-image), cropped from icon-sheet; overrides icon-name. A group resolving to an empty/unknown name draws no icon and places as a text-only symbol.
icon-offset array of number no MapLibre icon-offset: shift [x, y] in px, itself scaled by icon-size. Default [0, 0].
icon-opacity number (0…1) | $param | @node no —
icon-opacity-expr — no A MapLibre number expression giving the icon’s opacity; overrides icon-opacity.
icon-optional boolean no MapLibre icon-optional: let the text place when the icon’s box is blocked. Default false — icon and text place as one unit.
icon-padding-expr — no A MapLibre number expression (px), evaluated per feature group; overrides icon-padding-px.
icon-padding-px number (0…∞) no MapLibre icon-padding: collision-box inflation around the icon, in px. Default 2.
icon-rotate-deg number no MapLibre icon-rotate: rotation in degrees clockwise about the anchor point, as MapLibre turns an icon: an icon whose icon-anchor is off its centre, or that has an icon-offset, swings round the point with the offset turning with it, as stamp turns its image. The icon collides by the axis-aligned bounds of its turned, padded box, the envelope MapLibre takes, as a turned label does. Default 0.
icon-rotate-deg-expr — no A MapLibre number expression (degrees clockwise); overrides icon-rotate-deg.
icon-sheet @node no A sprite node: the sheet icon-name / icon-name-expr crop the icon from.
icon-size number (0…∞) no MapLibre icon-size: multiplier on the sprite’s authored display size (atlas pixels over its pixel ratio). Default 1.
icon-size-expr — no A MapLibre number expression, evaluated per feature group; overrides icon-size.
icon-sprite string no Deprecated: load the sheet with a sprite node and wire it to icon-sheet. An @sprite-source ref the node loads the sheet from itself; ignored when icon-sheet is wired.
icon-text-fit none | width | height | both | $param no MapLibre icon-text-fit: stretch the icon to the box its label occupies, on the named axes. The sprite’s stretchX/stretchY/content metadata decides which bands absorb the growth, so a shield keeps its corners; a sprite without it scales whole. The fitted box is also the icon’s collision box. Default none.
icon-text-fit-padding array of number no MapLibre icon-text-fit-padding: [top, right, bottom, left] px added around the label’s box before the icon is fitted to it. Default [0, 0, 0, 0].
ignore-placement boolean no MapLibre text-ignore-placement: don’t let this label block later ones (skip inserting its collision box). Default false.
justify auto | left | center | right | $param no Line alignment within the wrapped block. Default auto (follows the anchor’s horizontal side).
justify-expr — no A MapLibre string expression (data-driven MapLibre text-justify), evaluated per feature group with the tile’s zoom, naming auto, left, center or right; takes the place of justify for that group. A result that names no value (reported once per node) or an evaluation error uses justify.
keep-upright boolean no Flip a right-to-left label so it reads upright (MapLibre text-keep-upright). Line placement only. Default true.
layer string no Deprecated: remove it, with source. The layer the node reads from the neighbour tiles itself.
letter-spacing-em number no Extra advance per glyph in em. Default 0.
letter-spacing-em-expr — no A MapLibre number expression in em (data-driven MapLibre text-letter-spacing), evaluated per feature group; takes the place of letter-spacing-em for that group.
line-height number no Baseline-to-baseline distance in em. Default 1.2.
line-height-expr — no A MapLibre number expression in em (data-driven MapLibre text-line-height), evaluated per feature group; takes the place of line-height for that group.
max-angle-deg number (0…∞) no Max cumulative bend in degrees the line may turn over a label-length window before the anchor is rejected (MapLibre text-max-angle). Line placement only. Default 45.
max-extent-px number (0…∞) no Canvas pad this node requests; labels whose bbox half-extent exceeds it are culled with a warning (label-boxes with include: all still reports them, with drop-reason: culled). Default 128.
max-width-em number (0…∞) no Wrap target width in em. Default 10; 0 disables wrapping.
max-width-em-expr — no A MapLibre number expression in em (data-driven MapLibre text-max-width, a zoom curve say), evaluated per feature group; takes the place of max-width-em for that group.
max-zoom integer (0…24) no Style layer zoom gate: draw nothing above this zoom, neighbour tiles’ labels included.
min-zoom integer (0…24) no Style layer zoom gate: draw nothing below this zoom, neighbour tiles’ labels included.
min-zoom-field string no Deprecated: remove it. The per-feature min_zoom property for the neighbour tiles the node reads itself with source/layer; ignored without them.
offset-em array of number no Block shift [x, y] in em, applied after anchoring. Default [0, 0]. For point placement, ignored when anchor-offsets is set.
offset-em-expr — no A MapLibre expression yielding an [x, y] number array in em (data-driven MapLibre text-offset), evaluated per feature group with the tile’s zoom; takes the place of offset-em for that group, wherever offset-em applies: the single fixed position (with anchor or anchor-expr), the per-anchor shift of anchor-variants, and the along / across shift of a line label. A result that is not two numbers, or an evaluation error, uses offset-em. Ignored, with a warning, on point placement when anchor-offsets is set.
opacity number (0…1) | $param | @node no —
opacity-expr — no A MapLibre number expression giving opacity, evaluated per feature group; multiplies both fill and halo alpha. Overrides the constant opacity.
outline-sdf boolean no Render outline-font glyphs through the SDF field-sampling path (maplibre-gl-js style, which draws every glyph from an SDF) instead of a per-glyph vector fill / stroke. The halo then comes from a distance threshold rather than a stroke, matching MapLibre’s halo shape and cost. SDF glyph (glyphs) stacks are unaffected. Default true.
overlap never | always | fallback | $param no What a label does when it collides with labels placed before it. never (default): it tries each of its positions (anchor-offsets) and drops if none is free. always (MapLibre text-allow-overlap): it shows at its first position without trying the others, whatever it overlaps. fallback: it tries every position as never does, and the symbol’s text-only or icon-only fallbacks when icon-optional / text-optional allow them, and only when all are blocked shows at its first position, overlapping; label-boxes marks it overlapped. A shown label still reserves its box (blocking later labels) unless ignore-placement. On a symbol with an icon, always takes effect only with icon-allow-overlap set too, while fallback applies to the whole symbol.
padding-expr — no A MapLibre number expression (MapLibre text-padding), evaluated per feature group; overrides the constant padding-px for that group’s collision boxes.
padding-px number (0…∞) no Collision-box inflation in px on every side. Default 2.
placement point | line | line-center | $param no MapLibre symbol-placement. point (default) labels each feature point, and each polygon once at its polygon-anchor. line repeats labels along each polyline every spacing-px; line-center places one at each line’s arc-length midpoint. Line placement ignores wrapping (max-width-em) and lays out a single line along the path.
polygon-anchor pole | centroid | $param no Where point placement labels a polygon. pole (default) is its pole of inaccessibility, the interior spot farthest from its outline, where MapLibre places it. centroid is its area-weighted centroid with any holes cut out, the polygon’s balance point, for a label that belongs in the middle of an area such as a block number; where the centroid falls outside the polygon (a C or U shape) the pole is used instead. Past a source’s max-zoom the anchor is found on the polygon as the source tile holds it, so every deeper zoom labels it in the same place. At the zooms the source serves, each tile finds the anchor on the polygon as that tile was cut, so a polygon reaching further past a tile edge than the tile’s buffer gets a separate anchor in each tile it crosses, as in MapLibre; stitching the features node does not change that, and tiles generated with a buffer wider than the polygon do. Point placement only.
radial-offset number no Deprecated: use anchor-offsets entries with radial-em. MapLibre text-radial-offset: em distance each anchor-variants entry pushes the block away from the point in its direction. Default 0.
rotate-deg number no MapLibre text-rotate: degrees clockwise the label turns about its anchor point, the shift from offset-em or anchor-offsets turning with it, and its background box and strikethrough with it. The label collides by the axis-aligned bounds of its turned, padded box, the envelope MapLibre takes, so a label turned 45° reserves more room than it covers; label-boxes reports its text and background as turned quads and its collision box as those bounds. An icon-text-fit icon fits the unturned text and turns only by icon-rotate-deg. Point placement only: a line label’s glyphs follow the path, and the field is ignored there with a warning. Default 0.
rotate-deg-expr — no A MapLibre number expression (degrees clockwise, data-driven MapLibre text-rotate), evaluated per feature group with the tile’s zoom; overrides rotate-deg for that group.
size number (0…∞) | $param | @node no Font size in px. Default 16.
size-expr — no A MapLibre number expression (px), evaluated per feature group; overrides the constant size.
sort-key-expr — no A MapLibre number expression (MapLibre symbol-sort-key), evaluated per feature group; lower values place first under collision. Absent = 0.
source string no Deprecated: remove it, with layer; the neighbour tiles come through features. With layer, makes the node read the neighbour tiles’ copies of that layer itself, raw, instead of taking them from features.
spacing-px number (1…∞) no Gap in px between successive line anchors (MapLibre symbol-spacing). Line placement only. Default 250.
strikethrough boolean no Strike the label through: one horizontal bar per wrapped line, spanning the line’s advance extent, in the label’s color / color-expr and opacity. It sits at the primary font’s strikeout stroke (else half its x-height, else 0.3 em above the baseline); a glyphs stack carries no metrics and takes the 0.3 em fallback. With halo-width > 0 the bar gets the same halo as the glyphs, drawn underneath. Part of the drawn label, so it moves with the placed anchor and draws identically across tile seams; it does not change the collision box. Point placement only — line-placed labels ignore it. Default false.
strikethrough-expr — no A MapLibre boolean expression, evaluated per feature group; overrides the constant strikethrough (a non-boolean result falls back to it).
strikethrough-width number (0…∞) no Strikethrough bar thickness in px, rounded to whole pixels. Default 0.07 em of the label’s size, at least 1 px.
text — no The label: a literal string, or a MapLibre string expression (evaluated per feature group; empty/failed → the group draws nothing).
text-optional boolean no MapLibre text-optional: let the icon place when the text’s box is blocked. Default false.
transform none | uppercase | lowercase | $param no Case transform applied before shaping. Default none.
transform-expr — no A MapLibre string expression (data-driven MapLibre text-transform), evaluated per feature group with the tile’s zoom, naming none, uppercase or lowercase; takes the place of transform for that group. A result that names no value (reported once per node) or an evaluation error uses transform.

Draw one label layer’s placed labels: labels is the layer’s text-labels node, placement the shared label-placement node that decided it (wire the same text-labels node into both). Styling and layout live on text-labels; this node only rasterizes the winners.

Field Type Required Description
labels @node yes Reference to another node (@name).
max-extent-px number (0…∞) no Canvas pad (px) this layer’s labels need to cross a tile border un-clipped. Mirrors the text-labels field of the same name.
placement @node yes Reference to another node (@name).

Text labels (MapLibre symbol-placement): placement: point (default) labels each feature point, line / line-center walk each polyline with tangent-rotated glyphs. The font stacks come from a fonts node wired to fonts, and font names the one the labels use; text is a literal string or a MapLibre string expression evaluated per feature group. Paint properties and the layout knobs (in em) have optional *-expr siblings evaluated per feature group. Collision is on by default and is deterministic across tiles: candidates come from this tile plus the 8 neighbour tiles, so borders stay seamless. The node asks features to carry the neighbours: the features node reads them (host-bound under <source>.<layer>@dx,dy) with its own filter and zoom band, and each op between that works feature by feature applies itself to them too. An op that merges features passes none on, and the build warns that collision is then centre-tile-only. icon-name / icon-name-expr add MapLibre’s icon-image half: the icon is placed together with the text against the same index, so a symbol shows both or neither unless icon-optional / text-optional say otherwise. font and text are required unless the symbol is icon-only. Emits placement candidates instead of pixels: wire this node into a label-placement node and draw the result with text-draw.

Field Type Required Description
allow-overlap boolean no Deprecated: use overlap (true is "always", false is "never"). MapLibre text-allow-overlap: place the label even if it collides. It still reserves its box (blocking later labels) unless ignore-placement. Ignored when overlap is set. Default false.
anchor center | left | right | top | bottom | top-left | top-right | bottom-left | bottom-right | $param no Which part of the label block sits on the point (point placement). Default center. Ignored when anchor-offsets is set.
anchor-expr — no A MapLibre string expression (data-driven MapLibre text-anchor), evaluated per feature group with the tile’s zoom, naming which part of the label block sits on the point: one of center, left, right, top, bottom, top-left, top-right, bottom-left, bottom-right. It takes the place of anchor for that group, with offset-em (or radial-offset) shifting the block as it would for that constant anchor, and justify: auto following it. A group whose result is not an anchor name, or whose evaluation fails, uses anchor; a result that is not an anchor name is reported once per node. Ignored, with a warning, when anchor-offsets or anchor-variants is set, since those name the anchors themselves. Point placement only.
anchor-offsets array of object no The positions a point label tries, in order: on collision it moves to the next, and takes the first whose box is free. Each entry names the anchor that sits on the point and how far the block shifts from there: offset-em [x, y] in em, right and down positive, or radial-em, an em distance pushed away from the point in the anchor’s direction (corners split it across both axes, and top / bottom measure it to the visible text, as MapLibre’s text-radial-offset does). Give one of the two, or neither for no shift. The same anchor may appear more than once, so a label can try a near spot and then a farther one. label-boxes reports the position taken as variant-index. MapLibre’s text-variable-anchor-offset is the nearest counterpart, but it also nudges top and bottom anchors by a baseline gap that offset-em does not; ezu translate folds that gap into the offsets it writes. When set, anchor, anchor-expr, offset-em, anchor-variants and radial-offset are ignored for point placement. Point placement only.
anchor-variants array of center | left | right | top | bottom | top-left | top-right | bottom-left | bottom-right no Deprecated: use anchor-offsets, with { "anchor": …, "radial-em": … } entries for a radial-offset. MapLibre text-variable-anchor: anchors tried in order on collision, the first free one placed (point placement). Overrides anchor when set.
background-color color | $param | @node no Fill a box behind each label’s text: the laid-out block’s bounds, every line included, grown by background-padding, with background-radius-px corners. The box fits the text however long it is. anchor and offset-em position the box rather than the text, so with anchor: top-left the box’s top-left corner sits on the point and the text starts background-padding inside it; changing the padding never moves the anchored corner. The box is the label’s collision box. It draws under the halo and glyphs, and over the layer’s icons; opacity applies to it as to the text. Point placement only: line-placed labels draw without it. Absent (default): no fill; the box still exists, unpainted, when background-padding is set.
background-padding array of number no [top, right, bottom, left] px between the label’s text and the edge of its background box, in the order icon-text-fit-padding uses. Setting it gives each point label the box even without background-color: the box then paints nothing, but anchor and offset-em still position it, it is still the label’s collision box, and label-boxes still reports it as background — a way to reserve space around a label or measure a badge drawn by other ops. Default [0, 0, 0, 0].
background-radius-px number (0…∞) | $param | @node no Corner radius of the background box’s background-color fill in px, clamped to half its shorter side. Default 0 (square corners).
collide boolean no Whether to run deterministic label collision. Default true (MapLibre’s default). Set false to draw every label (the pre-collision behaviour).
color color | $param | @node no sRGB hex color, $param reference, or @node scalar port.
color-expr — no A MapLibre color expression, evaluated per feature group; overrides the constant color.
dedupe-distance-px number no The distance in px, anchor to anchor, within which a placed label hides later labels with the same dedupe-key-expr key. Required with dedupe-key-expr; must be greater than 0.
dedupe-key-expr — no A MapLibre expression, evaluated per feature group, giving the key that marks labels as duplicates of each other: once a label of this layer has placed, a later label with an equal key whose anchor is nearer than dedupe-distance-px to it is dropped, so a name shared by several neighbouring features is shown once. Labels are visited in placement order (sort-key-expr, then feature order), and only labels that actually placed count, so a label that lost its collision never hides its duplicates. A deduped label takes no space, and label-boxes with include: all reports it with drop-reason: dedupe. A null or empty result never dedupes; other values compare by their text. Applies within this layer only, needs dedupe-distance-px and collision on, and works the same across tiles as long as the distance stays within the 8 neighbour tiles. Point placement only — line labels have spacing-px.
features @node yes Reference to another node (@name).
filter-expr — no Deprecated: remove it. The filter for the neighbour tiles the node reads itself with source/layer; ignored without them.
font — no The stack the labels use, by name: an array of font names as MapLibre’s text-font gives them (joined with , to form the name), or that name as one string. It must be one of the fonts node’s stacks. Also the fallback for font-expr and for format sections naming no declared stack. Without fonts wired (deprecated): an ordered fallback stack of font and/or glyphs source names from the document’s sources, which the node loads itself.
font-expr — no A MapLibre expression yielding an array of font names, evaluated per feature group (MapLibre data-driven text-font); overrides the constant font. Each result is canonicalized (names joined with ,) and looked up among the fonts node’s stacks; an undeclared stack, a non-array result, or an eval error falls back to font.
font-stacks object no Deprecated: declare the stacks on a fonts node and wire it to fonts; ignored when fonts is wired. Named stacks the node loads itself: canonical stack key (font names joined with ,) → ordered font/glyphs source names, consulted by font-expr and by format sections. Stacks are numbered in key order, which fixes each one’s stable id.
fonts @node no A fonts node: the font stacks font, font-expr and format sections pick from by name.
halo-color color | $param | @node no sRGB hex color, $param reference, or @node scalar port.
halo-color-expr — no A MapLibre color expression for the halo, evaluated per feature group; overrides the constant halo-color.
halo-width number (0…∞) | $param | @node no Halo radius in px around each glyph. Default 0 (no halo).
halo-width-expr — no A MapLibre number expression (px), evaluated per feature group; overrides the constant halo-width.
icon-allow-overlap boolean no MapLibre icon-allow-overlap. A symbol carries one overlap decision, so with text present this and overlap: always must both be set for the symbol to ignore collision. Default false.
icon-anchor center | left | right | top | bottom | top-left | top-right | bottom-left | bottom-right | $param no Which part of the icon sits on the point (MapLibre icon-anchor). Default center.
icon-ignore-placement boolean no MapLibre icon-ignore-placement; with text present it pairs with ignore-placement the same way as the overlap flags. Default false.
icon-name string no Constant MapLibre icon-image: the sprite to draw at each point, cropped from icon-sheet. Needs icon-sheet.
icon-name-expr — no A MapLibre expression naming each feature’s icon (data-driven icon-image), cropped from icon-sheet; overrides icon-name. A group resolving to an empty/unknown name draws no icon and places as a text-only symbol.
icon-offset array of number no MapLibre icon-offset: shift [x, y] in px, itself scaled by icon-size. Default [0, 0].
icon-opacity number (0…1) | $param | @node no —
icon-opacity-expr — no A MapLibre number expression giving the icon’s opacity; overrides icon-opacity.
icon-optional boolean no MapLibre icon-optional: let the text place when the icon’s box is blocked. Default false — icon and text place as one unit.
icon-padding-expr — no A MapLibre number expression (px), evaluated per feature group; overrides icon-padding-px.
icon-padding-px number (0…∞) no MapLibre icon-padding: collision-box inflation around the icon, in px. Default 2.
icon-rotate-deg number no MapLibre icon-rotate: rotation in degrees clockwise about the anchor point, as MapLibre turns an icon: an icon whose icon-anchor is off its centre, or that has an icon-offset, swings round the point with the offset turning with it, as stamp turns its image. The icon collides by the axis-aligned bounds of its turned, padded box, the envelope MapLibre takes, as a turned label does. Default 0.
icon-rotate-deg-expr — no A MapLibre number expression (degrees clockwise); overrides icon-rotate-deg.
icon-sheet @node no A sprite node: the sheet icon-name / icon-name-expr crop the icon from.
icon-size number (0…∞) no MapLibre icon-size: multiplier on the sprite’s authored display size (atlas pixels over its pixel ratio). Default 1.
icon-size-expr — no A MapLibre number expression, evaluated per feature group; overrides icon-size.
icon-sprite string no Deprecated: load the sheet with a sprite node and wire it to icon-sheet. An @sprite-source ref the node loads the sheet from itself; ignored when icon-sheet is wired.
icon-text-fit none | width | height | both | $param no MapLibre icon-text-fit: stretch the icon to the box its label occupies, on the named axes. The sprite’s stretchX/stretchY/content metadata decides which bands absorb the growth, so a shield keeps its corners; a sprite without it scales whole. The fitted box is also the icon’s collision box. Default none.
icon-text-fit-padding array of number no MapLibre icon-text-fit-padding: [top, right, bottom, left] px added around the label’s box before the icon is fitted to it. Default [0, 0, 0, 0].
ignore-placement boolean no MapLibre text-ignore-placement: don’t let this label block later ones (skip inserting its collision box). Default false.
justify auto | left | center | right | $param no Line alignment within the wrapped block. Default auto (follows the anchor’s horizontal side).
justify-expr — no A MapLibre string expression (data-driven MapLibre text-justify), evaluated per feature group with the tile’s zoom, naming auto, left, center or right; takes the place of justify for that group. A result that names no value (reported once per node) or an evaluation error uses justify.
keep-upright boolean no Flip a right-to-left label so it reads upright (MapLibre text-keep-upright). Line placement only. Default true.
layer string no Deprecated: remove it, with source. The layer the node reads from the neighbour tiles itself.
letter-spacing-em number no Extra advance per glyph in em. Default 0.
letter-spacing-em-expr — no A MapLibre number expression in em (data-driven MapLibre text-letter-spacing), evaluated per feature group; takes the place of letter-spacing-em for that group.
line-height number no Baseline-to-baseline distance in em. Default 1.2.
line-height-expr — no A MapLibre number expression in em (data-driven MapLibre text-line-height), evaluated per feature group; takes the place of line-height for that group.
max-angle-deg number (0…∞) no Max cumulative bend in degrees the line may turn over a label-length window before the anchor is rejected (MapLibre text-max-angle). Line placement only. Default 45.
max-extent-px number (0…∞) no Canvas pad this node requests; labels whose bbox half-extent exceeds it are culled with a warning (label-boxes with include: all still reports them, with drop-reason: culled). Default 128.
max-width-em number (0…∞) no Wrap target width in em. Default 10; 0 disables wrapping.
max-width-em-expr — no A MapLibre number expression in em (data-driven MapLibre text-max-width, a zoom curve say), evaluated per feature group; takes the place of max-width-em for that group.
max-zoom integer (0…24) no Style layer zoom gate: draw nothing above this zoom, neighbour tiles’ labels included.
min-zoom integer (0…24) no Style layer zoom gate: draw nothing below this zoom, neighbour tiles’ labels included.
min-zoom-field string no Deprecated: remove it. The per-feature min_zoom property for the neighbour tiles the node reads itself with source/layer; ignored without them.
offset-em array of number no Block shift [x, y] in em, applied after anchoring. Default [0, 0]. For point placement, ignored when anchor-offsets is set.
offset-em-expr — no A MapLibre expression yielding an [x, y] number array in em (data-driven MapLibre text-offset), evaluated per feature group with the tile’s zoom; takes the place of offset-em for that group, wherever offset-em applies: the single fixed position (with anchor or anchor-expr), the per-anchor shift of anchor-variants, and the along / across shift of a line label. A result that is not two numbers, or an evaluation error, uses offset-em. Ignored, with a warning, on point placement when anchor-offsets is set.
opacity number (0…1) | $param | @node no —
opacity-expr — no A MapLibre number expression giving opacity, evaluated per feature group; multiplies both fill and halo alpha. Overrides the constant opacity.
outline-sdf boolean no Render outline-font glyphs through the SDF field-sampling path (maplibre-gl-js style, which draws every glyph from an SDF) instead of a per-glyph vector fill / stroke. The halo then comes from a distance threshold rather than a stroke, matching MapLibre’s halo shape and cost. SDF glyph (glyphs) stacks are unaffected. Default true.
overlap never | always | fallback | $param no What a label does when it collides with labels placed before it. never (default): it tries each of its positions (anchor-offsets) and drops if none is free. always (MapLibre text-allow-overlap): it shows at its first position without trying the others, whatever it overlaps. fallback: it tries every position as never does, and the symbol’s text-only or icon-only fallbacks when icon-optional / text-optional allow them, and only when all are blocked shows at its first position, overlapping; label-boxes marks it overlapped. A shown label still reserves its box (blocking later labels) unless ignore-placement. On a symbol with an icon, always takes effect only with icon-allow-overlap set too, while fallback applies to the whole symbol.
padding-expr — no A MapLibre number expression (MapLibre text-padding), evaluated per feature group; overrides the constant padding-px for that group’s collision boxes.
padding-px number (0…∞) no Collision-box inflation in px on every side. Default 2.
placement point | line | line-center | $param no MapLibre symbol-placement. point (default) labels each feature point, and each polygon once at its polygon-anchor. line repeats labels along each polyline every spacing-px; line-center places one at each line’s arc-length midpoint. Line placement ignores wrapping (max-width-em) and lays out a single line along the path.
polygon-anchor pole | centroid | $param no Where point placement labels a polygon. pole (default) is its pole of inaccessibility, the interior spot farthest from its outline, where MapLibre places it. centroid is its area-weighted centroid with any holes cut out, the polygon’s balance point, for a label that belongs in the middle of an area such as a block number; where the centroid falls outside the polygon (a C or U shape) the pole is used instead. Past a source’s max-zoom the anchor is found on the polygon as the source tile holds it, so every deeper zoom labels it in the same place. At the zooms the source serves, each tile finds the anchor on the polygon as that tile was cut, so a polygon reaching further past a tile edge than the tile’s buffer gets a separate anchor in each tile it crosses, as in MapLibre; stitching the features node does not change that, and tiles generated with a buffer wider than the polygon do. Point placement only.
radial-offset number no Deprecated: use anchor-offsets entries with radial-em. MapLibre text-radial-offset: em distance each anchor-variants entry pushes the block away from the point in its direction. Default 0.
rotate-deg number no MapLibre text-rotate: degrees clockwise the label turns about its anchor point, the shift from offset-em or anchor-offsets turning with it, and its background box and strikethrough with it. The label collides by the axis-aligned bounds of its turned, padded box, the envelope MapLibre takes, so a label turned 45° reserves more room than it covers; label-boxes reports its text and background as turned quads and its collision box as those bounds. An icon-text-fit icon fits the unturned text and turns only by icon-rotate-deg. Point placement only: a line label’s glyphs follow the path, and the field is ignored there with a warning. Default 0.
rotate-deg-expr — no A MapLibre number expression (degrees clockwise, data-driven MapLibre text-rotate), evaluated per feature group with the tile’s zoom; overrides rotate-deg for that group.
size number (0…∞) | $param | @node no Font size in px. Default 16.
size-expr — no A MapLibre number expression (px), evaluated per feature group; overrides the constant size.
sort-key-expr — no A MapLibre number expression (MapLibre symbol-sort-key), evaluated per feature group; lower values place first under collision. Absent = 0.
source string no Deprecated: remove it, with layer; the neighbour tiles come through features. With layer, makes the node read the neighbour tiles’ copies of that layer itself, raw, instead of taking them from features.
spacing-px number (1…∞) no Gap in px between successive line anchors (MapLibre symbol-spacing). Line placement only. Default 250.
strikethrough boolean no Strike the label through: one horizontal bar per wrapped line, spanning the line’s advance extent, in the label’s color / color-expr and opacity. It sits at the primary font’s strikeout stroke (else half its x-height, else 0.3 em above the baseline); a glyphs stack carries no metrics and takes the 0.3 em fallback. With halo-width > 0 the bar gets the same halo as the glyphs, drawn underneath. Part of the drawn label, so it moves with the placed anchor and draws identically across tile seams; it does not change the collision box. Point placement only — line-placed labels ignore it. Default false.
strikethrough-expr — no A MapLibre boolean expression, evaluated per feature group; overrides the constant strikethrough (a non-boolean result falls back to it).
strikethrough-width number (0…∞) no Strikethrough bar thickness in px, rounded to whole pixels. Default 0.07 em of the label’s size, at least 1 px.
text — no The label: a literal string, or a MapLibre string expression (evaluated per feature group; empty/failed → the group draws nothing).
text-optional boolean no MapLibre text-optional: let the icon place when the text’s box is blocked. Default false.
transform none | uppercase | lowercase | $param no Case transform applied before shaping. Default none.
transform-expr — no A MapLibre string expression (data-driven MapLibre text-transform), evaluated per feature group with the tile’s zoom, naming none, uppercase or lowercase; takes the place of transform for that group. A result that names no value (reported once per node) or an evaluation error uses transform.

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.