Skip to content

Geometry

Features -> Features transforms. They rewrite geometry before anything is painted, so downstream paint ops stay simple.

20 ops: bbox, boundary, buffer, centroid, contour, convex-hull, dash, densify, dot-density, feature-boolean, hatch, medial-axis, resample, simplify, smooth, transform, triangulate, voronoi, voronoi-fracture, wave.

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

Axis-aligned bounding box of every input vertex (pooled across polygons, lines, and points), emitted as a single rectangular polygon.

A tile rendered with bbox
The bounding box of every input vertex — here, a shrunken cloud of water centroids. style
Field Type Required Description
features @node yes Reference to another node (@name).

Convert each polygon to its boundary rings (exterior + holes) as polylines. Existing polylines and points pass through.

A tile rendered with boundary
Polygon rings turned into lines — the coastline of every water body. style
Field Type Required Description
features @node yes Reference to another node (@name).

Minkowski sum / offset with a disk. Polygons accept negative distance for erosion; lines and points are inflated by |distance|.

A tile rendered with buffer
Roads dilated into polygons, then filled. style
Field Type Required Description
distance number | $param | @node yes Offset distance in tile pixels. Positive inflates, negative erodes (polygons only).
features @node yes Reference to another node (@name).
join miter | round | bevel no

Replace input geometry with one point per polygon / polyline centroid.

A tile rendered with centroid
One point per input polygon, drawn as a dot. style
Field Type Required Description
features @node yes Reference to another node (@name).
include-lines boolean no
include-polygons boolean no

Isolines from a ScalarField (marching squares with linear sub-cell interpolation), chained into polylines. One feature group per level with properties {"level": <number>}, so data-driven paint can style by level. Levels are base + k·interval, or the explicit levels array (which overrides both), clamped by min/max. Chain dem → contour → stroke for elevation contours, or density → contour → stroke for point-density isolines.

Field Type Required Description
base number | $param | @node no Offset the interval grid: levels sit at base + k·interval.
field @node yes Reference to another node (@name).
interval number | $param | @node no Spacing between levels, in field units. Required unless levels is given.
levels array of number | string no Explicit levels to extract; overrides interval/base. A level may be a $param; the list is sorted and de-duplicated per render.
max number no Emit no level above this value.
min number no Emit no level below this value.

Convex hull of every input vertex as a single polygon.

A tile rendered with convex-hull
The convex hull of every input vertex — here, a shrunken cloud of water centroids. style
Field Type Required Description
features @node yes Reference to another node (@name).

Cut polylines into dash/gap segments. Lengths are in canvas pixels (consistent with *-px brush parameters). Polygons and points pass through unchanged.

A tile rendered with dash
Coastlines cut into dashes before painting. style
Field Type Required Description
dash-px number (0…∞) | $param | @node yes
features @node yes Reference to another node (@name).
gap-px number (0…∞) | $param | @node yes
phase-px number | $param | @node no Initial offset into the dash/gap pattern, in pixels. May be negative.

Insert intermediate vertices so no segment of any polyline or polygon ring exceeds target-px. Original vertices are preserved.

Field Type Required Description
features @node yes Reference to another node (@name).
target-px number (0…∞) yes

Scatter points inside polygons at a per-feature areal density (dot density map).

A tile rendered with dot-density
Dots spread over the landmass at 12,000 people per km², one dot per 100 people. A real dot density map reads the density from each feature with density-expr instead of stating one constant. style
Field Type Required Description
density number (0…∞) | $param | @node no Constant density in units per square kilometre, used where density-expr is absent.
density-expr no Per-feature MapLibre expression giving density in units per square kilometre, e.g. [“/”, [“get”, “POP”], [“get”, “AREA_KM2”]].
dot-value number | $param | @node no Units one dot stands for. 100 means one dot per 100 people.
features @node yes Reference to another node (@name).
jitter number (0…1) | $param | @node no How far a dot may stray from its cell centre, as a fraction of the cell. 0 leaves a visible grid.
seed integer (0…∞) no Lattice salt; change it to reshuffle the dots without changing their density.
spacing-px number | $param | @node no Lattice cell size in screen pixels. One dot per cell at most, so this caps how dense the scatter can get.

Polygon boolean operation between two Features inputs. Subject = a, clip = b. Lines and points on either input are dropped — booleans are defined on polygons only.

Field Type Required Description
a @node yes Reference to another node (@name).
b @node yes Reference to another node (@name).

Parallel-line hatching of input polygons.

A tile rendered with hatch
Parallel-line hatching of the landmass polygons. style
Field Type Required Description
angle-deg number | $param | @node no Hatch direction (degrees, CCW from +X).
features @node yes Reference to another node (@name).
phase number | $param | @node no Per-line offset in spacing units (0..1 cycles through one period).
spacing number (0…∞) | $param | @node yes Perpendicular spacing between consecutive lines, in tile pixels.

Approximate medial axis of each input polygon, emitted as polylines. Smaller densify-px → more accurate but slower; min-branch-px prunes short side branches after stitching.

A tile rendered with medial-axis
The skeleton of each polygon — a river’s centreline from its bank. style
Field Type Required Description
densify-px number (0.5…∞) | $param | @node no
features @node yes Reference to another node (@name).
min-branch-px number (0…∞) | $param | @node no

Resample each polyline / polygon ring to evenly-spaced vertices at spacing-px along arc length. Original vertices are not preserved.

Field Type Required Description
features @node yes Reference to another node (@name).
spacing-px number (0…∞) yes

Douglas-Peucker simplify polylines and polygon rings; points pass through.

A tile rendered with simplify
Coastlines simplified with a generous tolerance, so the loss is visible. style
Field Type Required Description
epsilon number (0…∞) | $param | @node yes Max perpendicular distance a vertex may be from the simplified line, in tile pixels.
features @node yes Reference to another node (@name).

Chaikin corner-smoothing over each input polyline and polygon ring. Each iteration roughly doubles the vertex count; 2–3 iterations are usually enough.

A tile rendered with smooth
Coastlines smoothed, rounding off the vertex-to-vertex corners. style
Field Type Required Description
features @node yes Reference to another node (@name).
iterations integer (0…8) no

Translate / rotate / scale every input vertex. Rotation happens around pivot (defaults to the origin) before the final translation. The scalar fields take a $param or an @node port and follow it per render; the [x, y] arrays are literal, and seed the matching scalars. Uniform scale multiplies the per-axis factors.

A tile rendered with transform
Water polygons scaled about their own centre. style
Field Type Required Description
features @node yes Reference to another node (@name).
pivot array of number no Literal [x, y] rotation centre in feature space.
rotation-deg number | $param | @node no
scale number | $param | @node no
scale-x number | $param | @node no
scale-xy array of number no Literal per-axis scale. scale-x / scale-y override it; uniform scale multiplies it.
scale-y number | $param | @node no
translate array of number no Literal [x, y] shift. translate-x / translate-y override it.
translate-x number | $param | @node no
translate-y number | $param | @node no

Delaunay triangulation of the input’s point set. Each triangle becomes a closed polygon. Polygons and lines on input are ignored.

A tile rendered with triangulate
Delaunay mesh over the building centroids. The op triangulates points, so polygons come through centroid first. style
Field Type Required Description
features @node yes Reference to another node (@name).

Voronoi diagram of the input’s point set. Output is a Features value carrying the Voronoi edges as polylines (each polyline is a single 2-point edge). Polygons and lines in the input are ignored — use centroid to derive points from them.

A tile rendered with voronoi
Voronoi cells around each input point. style
Field Type Required Description
features @node yes Reference to another node (@name).

Fracture each polygon in features into Voronoi sub-cells using the points in seeds as Voronoi sites. Cells are clipped against the source polygon. Lines/points on features and lines/polygons on seeds are ignored.

A tile rendered with voronoi-fracture
Polygons shattered into Voronoi shards — the crackle-glaze effect. style
Field Type Required Description
features @node yes Reference to another node (@name).
seeds @node yes Reference to another node (@name).

Displace polylines laterally with a sine wave. Lengths in canvas pixels. Sharp corners may kink (no tangent smoothing). Polygons/points pass through.

A tile rendered with wave
Road geometry perturbed sideways — the wobble behind hand-drawn styles. style
Field Type Required Description
amplitude-px number | $param | @node yes Peak lateral deviation in pixels. May be negative to flip phase.
features @node yes Reference to another node (@name).
noise-amp-px number | $param | @node no Peak 1D-value-noise jitter added on top of the sine, in pixels. 0 = pure sine (default).
noise-scale-px number (0.5…∞) | $param | @node no Cell length of the noise jitter along arc length, in pixels. Defaults to wavelength-px.
phase-px number | $param | @node no Offset into the wave at the polyline start, in pixels.
samples-per-wavelength number (2…256) no Subdivisions per wavelength. Higher = smoother but more vertices. Default 16.
seed integer (0…∞) no Optional explicit u32 seed for the world-anchored 2D value noise. Default: a fixed constant so adjacent tiles agree across the seam.
wavelength-px number (0.5…∞) | $param | @node yes

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.