Skip to content

Raster

Image-processing ops over Raster (and, where noted, Sprite): generators, composition, colour, warp, morphology, dither, terrain.

40 ops: blend, blur, brightness-contrast, channel-shuffle, circle, color-ramp, color-to-alpha, density, dilate, displace, dither, edge-detect, erode, field-math, flow-field, flow-smear, gradient-conic, gradient-diamond, gradient-linear, gradient-radial, hillshade, hsl, invert, levels, map-range, mix, mosaic, noise, place, posterize, quantize, saturate, sharpen, slope, solid, stack, threshold, tiling, vibrance, warp.

Composite over onto base with a W3C blend mode. clip: true clips result to base alpha (Photoshop-style clipping mask, i.e. source-atop): the result takes the base’s alpha, so clipping onto a 0.12-alpha wash caps the whole overlay at 0.12 — when you mean “restrict this to an area”, give an opaque shape as mask instead. composite: "destination-out" makes over erase base (brush-eraser effect when over is a brush-shaped raster). Optional mask raster’s alpha modulates source coverage.

The shared basemap, before blendThe same tile after blend
A colour multiplied over the base — one of sixteen W3C blend modes. style
Field Type Required Description
base @node yes Reference to another node (@name).
clip boolean | $param | @node no —
composite over | source-over | destination-out | dest-out | erase no —
mask @node no Reference to another node (@name).
mode normal | multiply | screen | overlay | darken | lighten | color-dodge | color-burn | hard-light | soft-light | difference | exclusion | hue | saturation | color | luminosity no —
opacity number (0…1) | $param | @node no —
over @node yes Reference to another node (@name).

Gaussian blur on a raster, sprite or scalar field; the output is the same kind as the input. Rasters are blurred in fixed point and fields in a fixed order of float operations, so both render the same bytes on every host. Blurring an elevation field (dem) before hillshade, slope or flow-field generalises the terrain: small gullies drop out and the major ridges stay, so the shading follows the ridge crests. A field keeps its nodata value and geographic scale; nodata samples are left out of the average, and a pixel with nothing but nodata in reach stays nodata. Grows upstream pad by 3σ, so sigma needs an upper bound the build can see: a literal, a $param with max, or sigma-max alongside an @node port (the port’s value is then clamped to it).

The shared basemap, before blurThe same tile after blur
Gaussian blur, σ = 6 px. style
Field Type Required Description
input @node yes Reference to another node (@name).
sigma number (0…∞) | $param | @node yes —
sigma-max number (0…∞) no Upper bound on sigma for padding, required when sigma is an @node port. Values above it are clamped.

Linear brightness shift and contrast slope around mid-gray. Both in [-1, 1], 0 = no change.

The shared basemap, before brightness-contrastThe same tile after brightness-contrast
Darkened, with contrast raised around mid-grey. style
Field Type Required Description
brightness number (-1…1) | $param | @node no —
contrast number (-1…1) | $param | @node no —
input @node yes Reference to another node (@name).

Rearrange RGBA channels. Each output (r/g/b/a) names which input channel feeds it, or a constant (0/1). Identity by default. Operates in non-premultiplied sRGB.

The shared basemap, before channel-shuffleThe same tile after channel-shuffle
Channels permuted — red and blue swapped. style
Field Type Required Description
a r | g | b | a | 0 | 1 no —
b r | g | b | a | 0 | 1 no —
g r | g | b | a | 0 | 1 no —
input @node yes Reference to another node (@name).
r r | g | b | a | 0 | 1 no —

Centred disk source. kind: raster (default) renders at canvas size with radius = radius-frac × tile-size. kind: sprite renders at width-px × height-px with radius = radius-frac × min(width, height).

A tile rendered with circle
A canvas-sized circle — the sprite behind MapLibre’s circle layers. style
Field Type Required Description
color color | $param | @node yes sRGB hex color, $param reference, or @node scalar port.
hardness number (0…1) | $param | @node no —
height-px integer (1…∞) no —
kind raster | sprite no —
radius-frac number (0…1) | $param | @node yes —
width-px integer (1…∞) no —

Map a ScalarField (or a Raster, by its luminance — a gradient map) to colour through a stop table, interpolating between stops in space. Samples outside [stops[0].value, stops[-1].value] clamp to the end colours. A field’s missing samples (NaN or its nodata value) are fully transparent. Canonical use case is hypsometric tinting over a DEM (stops[i].value = elevation in metres). Give ramp-expr instead of stops to drive the ramp from a MapLibre color expression over heatmap-density.

Field Type Required Description
field @node yes Reference to another node (@name).
opacity number (0…1) | $param | @node no Uniform output-alpha multiplier (layer opacity). Default 1.0. Feed an expr node via @node for a zoom curve.
ramp-expr — no A MapLibre color expression over heatmap-density (e.g. a heatmap-color value). When present it overrides stops: the expression is baked into a 256-entry LUT per eval (zoom in context), inputs clamp to [0, 1], and lookups interpolate linearly between entries — mirroring MapLibre’s 256-px ramp texture. stops is only required when this is absent.
space rgb | hsl | hsv | hcl | lab no Colour space the stops interpolate in. rgb (default) is a straight sRGB lerp; hsl/hsv/hcl interpolate hue on the shortest path; hcl/lab are perceptual (ported from the MapLibre style spec).
stops array of object no Either half of a stop may be a $param, so a ramp can be recoloured or rescaled at render time. The table is sorted by value on every eval, so a param may reorder it.

Make pixels close to color transparent. Distance ≤ threshold → alpha 0, distance ≥ threshold + softness → alpha unchanged, linear in between. Distance is Chebyshev (max per-channel) in non-premultiplied sRGB.

The shared basemap, before color-to-alphaThe same tile after color-to-alpha
The paper colour knocked out to transparency. style
Field Type Required Description
color color | $param | @node yes sRGB hex color, $param reference, or @node scalar port.
input @node yes Reference to another node (@name).
softness number (0…1) | $param | @node no —
threshold number (0…1) | $param | @node no —

Kernel-density estimate of the input’s point features as a ScalarField (the MapLibre heatmap kernel: support = radius px, falloff exp(-0.5·3²·(d/radius)²)/√(2π)). Points only — lines and polygons contribute nothing, so a line or polygon layer comes out an all-zero field with no error; put centroid in front of it. Buffer points outside the tile still contribute, so tile borders match. Output is raw accumulated density, unclamped and scaling with intensity, so probe its range before placing ramp stops. Map it with color-ramp or extract isolines with contour. Grows upstream pad by radius.

Field Type Required Description
features @node yes Reference to another node (@name).
intensity number (0…∞) | $param | @node no Global multiplier on every point’s contribution.
intensity-expr — no A MapLibre number expression giving the intensity multiplier, evaluated per feature group; overrides the constant intensity.
radius number (0…∞) | $param | @node no Kernel radius in px. Pad is computed at build time, so this needs a static bound: a literal, or a $param with max.
radius-expr — no A MapLibre number expression (px), evaluated per feature group; overrides the constant radius. Evaluated values are clamped to radius’s static bound so the pad stays sound.
weight-expr — no A MapLibre number expression giving a point’s weight, evaluated per feature group. A group without it (or whose expression doesn’t resolve to a number) weighs 1.

Per-channel morphological max over a square kernel, on a raster, sprite or scalar field; the output is the same kind as the input. Grows bright / opaque regions; pair with erode to clean up speckle noise (open / close). Being a max, it also flattens detail finer than the kernel — a few px of radius-px is enough to erase grain, so add grain after morphology, never before. On an elevation field (dem) it raises each sample to the highest in reach, widening peaks and ridges and narrowing valleys; dilate then erode (a closing) fills pits and gullies narrower than the kernel while leaving broad slopes alone. A field keeps its nodata value and geographic scale; nodata samples are left out, and a pixel with nothing but nodata in reach stays nodata. Separable box implementation; grows upstream pad by radius-px.

A tile rendered with dilate
Dilation of a water mask — coverage grows by the kernel radius. style
Field Type Required Description
input @node yes Reference to another node (@name).
radius-px integer (0…256) | $param | @node yes —
radius-px-max number (0…∞) no Upper bound on radius-px for padding, required when radius-px is an @node port. Values above it are clamped.

Photoshop-style displacement map. Output pixel reads input at a position offset by the displacement raster’s R/G channels (0.5 means no offset). input may be a raster, sprite or scalar field, and the output is the same kind. Displacing an elevation field (dem) bends it before contour or hillshade, the same way the map bends the imagery drawn over it, and the contour lines stay level lines of one surface, so they never cross. A field keeps its nodata value and geographic scale; nodata samples are left out of the interpolation, a read with only nodata around it stays nodata, and the field always clamps at its edge. Grows upstream pad by amp-px so warped samples stay seamless across tile borders, provided the displacement source is itself seamless (e.g. noise with anchor: world).

The shared basemap, before displaceThe same tile after displace
Displaced by a separate low-frequency noise raster. style
Field Type Required Description
amp-px number (0…∞) | $param | @node yes —
amp-x-px number (0…∞) | $param | @node no —
amp-x-px-max number (0…∞) no Upper bound on amp-x-px for padding, required when amp-x-px is an @node port. Values above it are clamped.
amp-y-px number (0…∞) | $param | @node no —
amp-y-px-max number (0…∞) no Upper bound on amp-y-px for padding, required when amp-y-px is an @node port. Values above it are clamped.
boundary clamp | transparent | mirror no —
displacement @node yes Reference to another node (@name).
input @node yes Reference to another node (@name).

Reduce to a fixed palette with dithering so gradients survive a small palette. method: "floyd-steinberg" (default) diffuses error to neighbours; method: "ordered" uses a 4×4 Bayer matrix with strength amount (0..1). Nearest-colour distance uses space (lab default / rgb). Alpha preserved.

The shared basemap, before ditherThe same tile after dither
The same four inks, error-diffused — gradients survive the reduction. style
Field Type Required Description
amount number (0…1) no Ordered-dither strength (ignored for floyd-steinberg).
input @node yes Reference to another node (@name).
method floyd-steinberg | ordered no —
palette array of string yes Each entry is #rrggbb / #rrggbbaa (alpha ignored for matching) or a $param, so a palette can be recoloured at render time.
space lab | rgb no —

Sobel gradient magnitude per channel, scaled by strength and clamped to [0, 255]. Pass-through over Raster / Sprite. Use after a hillshade for stylised outlines, or on a flat fill to derive an outline mask.

A tile rendered with edge-detect
Sobel over a flat water fill — the outline mask the op is usually used for. style
Field Type Required Description
input @node yes Reference to another node (@name).
strength number (0…∞) | $param | @node no Scale factor applied to the gradient magnitude before clamping.

Per-channel morphological min over a square kernel, on a raster, sprite or scalar field; the output is the same kind as the input. Shrinks bright / opaque regions; classic mask cleanup after color-to-alpha. Removes anything thinner than the kernel outright, so erode then dilate (an opening) keeps only features wider than radius-px — a way to select by size when the source carries no size attribute. Detail finer than the radius does not survive either op: add grain after morphology, never before. On an elevation field (dem) it lowers each sample to the lowest in reach, narrowing peaks and ridges and widening valleys; an opening shaves off spikes and ridges narrower than the kernel. A field keeps its nodata value and geographic scale; nodata samples are left out, and a pixel with nothing but nodata in reach stays nodata. Separable box implementation; grows upstream pad by radius-px.

A tile rendered with erode
Erosion of the same mask — coverage shrinks, and the narrow channels vanish. style
Field Type Required Description
input @node yes Reference to another node (@name).
radius-px integer (0…256) | $param | @node yes —
radius-px-max number (0…∞) no Upper bound on radius-px for padding, required when radius-px is an @node port. Values above it are clamped.

Per-pixel arithmetic over scalar fields, with the same functions as math: unary fns use a; binary a b; clamp(a, b=lo, c=hi), lerp(a, b, c=t). Each operand is a field (@node outputting a ScalarField) or a number (literal, $param, or @node scalar port) applied to every pixel; at least one must be a field, and all fields must be the same size. Add a little noise to a DEM to roughen it, mix two fields by a third with lerp, or scale a field by a $param. A pixel is missing in the output where any field operand is missing (NaN or its nodata value), or where the result is not a finite number (sqrt of a negative, div by zero). The output keeps the nodata value and geographic scale of the first field operand, and writes missing pixels as that nodata, or NaN.

Field Type Required Description
a number | $param | @node yes $param reference, or @node that outputs a ScalarField or a Scalar.
b number | $param | @node no $param reference, or @node that outputs a ScalarField or a Scalar.
c number | $param | @node no $param reference, or @node that outputs a ScalarField or a Scalar.
fn abs | neg | floor | ceil | round | sqrt | add | sub | mul | div | mod | min | max | pow | clamp | lerp yes —

Direction raster from an elevation field: which way the ground falls, rises, or runs level at each pixel. R = 0.5 + 0.5·vx and G = 0.5 + 0.5·vy in pixel axes (+x east, +y south), B = 0, opaque; flat 50% grey means no direction. This is displace’s encoding, so the output feeds displace directly, and it is what flow-smear reads to streak a texture along the terrain. The vector’s length is the slope angle over max-deg (capped at 1), or 1 everywhere the ground slopes with normalize. Missing samples (NaN or the field’s nodata value) get the opaque no-flow grey, so displace and flow-smear leave them in place; a missing neighbour counts as the centre value, so the ground around a hole does not flow into or out of it.

Field Type Required Description
direction downhill | uphill | along no downhill follows the fall line, uphill points the other way, and along follows the contour lines with downhill on its right-hand side (counter-clockwise around a summit on a north-up map).
exaggeration number | $param | @node no Multiplier on the gradient before the slope angle is taken, as in hillshade.
field @node yes Reference to another node (@name).
max-deg number | $param | @node no Slope angle (degrees) at which the vector reaches full length. Ignored with normalize.
normalize boolean | $param | @node no If true, every sloping pixel gets a vector of length 1; only perfectly flat ground stays at zero.

Smears input along the streamlines of a direction field (line integral convolution): each pixel becomes the average of input sampled along the curve through it, re-reading the field at every step so strokes bend with it. The field is flow-field’s encoding — R/G = 0.5 + 0.5·v in pixel axes, flat grey meaning no direction — and a pixel’s walk is length-px times the field’s length there, so flat ground stays sharp. For hachures or contour strokes, smear a world-anchored noise along dem → flow-field, then threshold or color-ramp the result. Seamless across tile borders when input is world-anchored; grows the upstream pad by length-px + 1.

Field Type Required Description
field @node yes Reference to another node (@name).
input @node yes Reference to another node (@name).
length-px number (0…∞) | $param | @node no Walk length in px each way, at full field length.
length-px-max number (0…∞) no Upper bound on length-px for padding, required when length-px is an @node port. Values above it are clamped.
sides both | forward no both smears each way along the field, so a speck becomes a stroke centred on it; forward smears only the way the field points, so a speck trails a comet tail downstream.
taper flat | smooth no flat weights every sample alike; smooth fades them towards the ends of the walk (a Hann window), softening the stroke ends.

Conic (sweep) gradient around center. Gradient parameter is the clockwise angle from start-angle (degrees) normalized to [0, 1). 0° points along +x. kind: sprite switches to sprite-local [0, 1] coords.

A tile rendered with gradient-conic
A conic gradient sweeping around the centre. style
Field Type Required Description
anchor tile | world no —
center array of number no —
height-px integer (1…∞) no —
kind raster | sprite no —
space rgb | hsl | hsv | hcl | lab no Colour space the stops interpolate in; hue-based spaces take the shortest path.
start-angle number | $param | @node no —
stops array of array of — yes [[t, color], ...]. Either half of a pair may be a $param; the table is sorted by t on every eval, so stops need not be declared in order.
width-px integer (1…∞) no —

Diamond gradient from center. Gradient parameter is Manhattan (|dx| + |dy|) distance / radius. kind: sprite switches to sprite-local [0, 1] coords.

A tile rendered with gradient-diamond
A diamond gradient — square distance rather than radial. style
Field Type Required Description
anchor tile | world no —
center array of number no —
height-px integer (1…∞) no —
kind raster | sprite no —
radius number (0…∞) | $param | @node no —
space rgb | hsl | hsv | hcl | lab no Colour space the stops interpolate in; hue-based spaces take the shortest path.
stops array of array of — yes [[t, color], ...]. Either half of a pair may be a $param; the table is sorted by t on every eval, so stops need not be declared in order.
width-px integer (1…∞) no —

Linear gradient from start to end (fractional coords). kind: raster (default) samples in tile/world coords; kind: sprite samples in [0, 1] sprite coords at width-px × height-px.

A tile rendered with gradient-linear
A linear gradient across the canvas. style
Field Type Required Description
anchor tile | world no —
end array of number no —
height-px integer (1…∞) no —
kind raster | sprite no —
space rgb | hsl | hsv | hcl | lab no Colour space the stops interpolate in; hue-based spaces take the shortest path.
start array of number no —
stops array of array of — yes [[t, color], ...]. Either half of a pair may be a $param; the table is sorted by t on every eval, so stops need not be declared in order.
width-px integer (1…∞) no —

Radial gradient from center outward. Gradient parameter is Euclidean distance / radius. aspect > 1 stretches the ellipse along X, < 1 along Y. kind: sprite switches to sprite-local [0, 1] coords.

A tile rendered with gradient-radial
A radial gradient from the canvas centre. style
Field Type Required Description
anchor tile | world no —
aspect number (0…∞) | $param | @node no —
center array of number no —
height-px integer (1…∞) no —
kind raster | sprite no —
radius number (0…∞) | $param | @node no —
space rgb | hsl | hsv | hcl | lab no Colour space the stops interpolate in; hue-based spaces take the shortest path.
stops array of array of — yes [[t, color], ...]. Either half of a pair may be a $param; the table is sorted by t on every eval, so stops need not be declared in order.
width-px integer (1…∞) no —

Analytical hillshade (Horn 1981) from a ScalarField. mode: shade outputs grayscale; mode: relief outputs transparent black scaled by 1-shade for multiply-blend over a base map. Missing samples (NaN or the field’s nodata value) are fully transparent in both modes; a missing neighbour counts as the centre value, so the edge of a hole shades as level ground instead of a cliff.

Field Type Required Description
altitude-deg number | $param | @node no Light elevation above the horizon (degrees).
azimuth-deg number | $param | @node no Light direction (0 = north, clockwise).
exaggeration number | $param | @node no Extra vertical exaggeration on top of z-factor.
field @node yes Reference to another node (@name).
highlight-color color | $param | @node no sRGB hex color, $param reference, or @node scalar port.
mode shade | relief no —
multidirectional boolean | $param | @node no ESRI-style 4-direction weighted hillshade — softer, more legible at small zooms.
shadow-color color | $param | @node no sRGB hex color, $param reference, or @node scalar port.
z-factor number | $param | @node no Multiplier on elevation before gradient — use ~1/cos(lat) for high latitudes.

HSL adjustment: rotate hue by hue-shift degrees, shift saturation/lightness in [-1, 1] (0 = no change, +1 = toward max, -1 = toward 0).

The shared basemap, before hslThe same tile after hsl
Hue rotated and saturation raised. style
Field Type Required Description
hue-shift number | $param | @node no —
input @node yes Reference to another node (@name).
lightness number (-1…1) | $param | @node no —
saturation number (-1…1) | $param | @node no —

Negate RGB channels (1 - c). Alpha is preserved.

The shared basemap, before invertThe same tile after invert
Every channel inverted. style
Field Type Required Description
input @node yes Reference to another node (@name).

Photoshop-style levels: remap input range [in-black, in-white] through gamma onto output range [out-black, out-white]. All values in [0, 1] (non-premultiplied sRGB). gamma > 1 lightens midtones; gamma < 1 darkens them.

The shared basemap, before levelsThe same tile after levels
Input range remapped — the tonal-range expansion before a screen. style
Field Type Required Description
gamma number (0.01…∞) | $param | @node no —
in-black number (0…1) | $param | @node no —
in-white number (0…1) | $param | @node no —
input @node yes Reference to another node (@name).
out-black number (0…1) | $param | @node no —
out-white number (0…1) | $param | @node no —

Linearly remap scalar field values from [in-min, in-max] to [out-min, out-max]. With clamp: true, results outside the output range are pinned to the range bounds. Missing samples (NaN or the field’s nodata value) stay missing: the output keeps the field’s nodata value and geographic scale, and writes missing pixels as that nodata, or NaN. Useful for normalising elevation or distance fields before a color-ramp.

Field Type Required Description
clamp boolean | $param | @node no —
field @node yes Reference to another node (@name).
in-max number | $param | @node no —
in-min number | $param | @node no —
out-max number | $param | @node no —
out-min number | $param | @node no —

Interpolate two rasters per-pixel by scalar t (0..1) in colour space. A straight colour tween (contrast with blend, which composites with alpha). t accepts a literal, $param, or @node scalar for param-driven theming.

The shared basemap, before mixThe same tile after mix
A straight crossfade between two rasters. style
Field Type Required Description
a @node yes Reference to another node (@name).
b @node yes Reference to another node (@name).
space rgb | hsl | hsv | hcl | lab no Colour space the interpolation runs in; hue-based spaces take the shortest path.
t number (0…1) | $param | @node no —

Quantize a raster into uniform square blocks. mode selects how each block is summarized: average (default) takes the mean of covered pixels (smooth, classic mosaic); nearest takes the block’s centre pixel (crisp, no inter-colour blending). World-anchored by default so adjacent map tiles share the same block grid.

The shared basemap, before mosaicThe same tile after mosaic
Averaged into 8 px blocks, on a world-anchored grid. style
Field Type Required Description
anchor world | tile no world (default) makes the block grid seamless across map tiles by growing the upstream pad. tile restarts the grid at every map tile’s top-left and requires no extra padding.
block integer (1…∞) | $param | @node yes Block edge length in canvas pixels. With anchor: world the block size sets the canvas padding, which is fixed before anything renders — so this needs an upper bound the build can see: a literal, a $param with max, or block-max beside an @node port.
block-max number (0…∞) no Upper bound on block for padding, required when block is an @node port. Values above it are clamped.
input @node yes Reference to another node (@name).
mode average | nearest no average (default) blends covered pixels into a mean colour. nearest samples the block’s centre pixel verbatim — produces hard block edges without inter-colour averaging.

Procedural noise source. With kind: raster (default) the noise is mapped to RGBA via low-color/high-color/opacity. With kind: scalar it emits a ScalarField of raw fBm values — compose with map-range before feeding hillshade/color-ramp. Every type lands in [-1, 1]. white/value/perlin/simplex sit around 0. worley and cell both divide the plane into cells around scattered sites: worley is 1 − 2·distance to the nearest site, +1 on the site and falling towards the cell’s edge, and cell is the nearest site’s own random value, flat across its cell and spread evenly over [-1, 1] — one tone per cell, for stones, panes or patches. anchor=world (default) keeps the field seamless across tile borders.

A tile rendered with noise
Fractal noise, world-anchored so it is continuous across tiles. style
Field Type Required Description
anchor tile | world no —
gain number | $param | @node no —
high-color color | $param | @node no sRGB hex color, $param reference, or @node scalar port.
kind raster | scalar no —
lacunarity number | $param | @node no —
low-color color | $param | @node no sRGB hex color, $param reference, or @node scalar port.
octaves integer (1…12) no —
opacity number (0…1) | $param | @node no —
scale-px number | array of number yes Noise wavelength in pixels. A single number for isotropic noise; an [x, y] array for anisotropic noise (larger value = longer wavelength along that axis, i.e. stretched pattern).
seed integer (0…∞) no Field seed. Omitted, anchor: world uses a fixed seed so every tile samples the same field, and anchor: tile uses the host’s per-tile seed so each tile gets its own. Set it to pin either.
type white | value | perlin | simplex | worley | cell no —
warp-amp number | $param | @node no —
warp-freq number | $param | @node no —

Draw the source raster onto the canvas exactly once. fit:none (default) uses position/anchor/scale; cover/contain/stretch derive the destination rect from the canvas (and treat position-px as an offset from canvas center). Companion to tiling (repeats) and stamp (per-point).

Field Type Required Description
anchor top-left | top-center | top-right | center-left | center | center-right | bottom-left | bottom-center | bottom-right no Only used when fit=none.
fit none | cover | contain | stretch no —
input @node yes Reference to another node (@name).
opacity number (0…1) | $param | @node no —
position-px array of number no fit=none: canvas pixel where the image’s anchor point lands. Other fits: offset from canvas center.
rotation-deg number | $param | @node no Rotation (degrees clockwise) around the placement anchor / canvas center.
scale number (0…∞) | $param | @node no Uniform scale for fit=none. Ignored for other fits.

Quantise each RGB channel into steps evenly-spaced levels (in non-premultiplied sRGB). Alpha preserved. Pair with levels to control which tonal band gets the strongest banding.

The shared basemap, before posterizeThe same tile after posterize
Each channel snapped to four levels. style
Field Type Required Description
input @node yes Reference to another node (@name).
steps integer (2…256) no —

Snap each pixel to the nearest colour in palette, measuring distance in space (lab = perceptual ΔE, default; or rgb). Alpha is preserved. Use for limited-palette / poster / pixel-art looks; see dither for the error-diffused variant.

The shared basemap, before quantizeThe same tile after quantize
Mapped to a four-ink palette, no dithering. style
Field Type Required Description
input @node yes Reference to another node (@name).
palette array of string yes Each entry is #rrggbb / #rrggbbaa (alpha ignored for matching) or a $param, so a palette can be recoloured at render time.
space lab | rgb no Colour space the nearest-colour distance is measured in.

Scale CIELAB chroma uniformly by amount (1 = identity, 0 = greyscale, >1 = more saturated). Hue and lightness are preserved.

The shared basemap, before saturateThe same tile after saturate
Saturation pushed up. style
Field Type Required Description
amount number (0…∞) | $param | @node no —
input @node yes Reference to another node (@name).

4-neighbour Laplacian sharpen on a raster, sprite or scalar field; the output is the same kind as the input. Amplifies each pixel relative to its orthogonal neighbours by amount. Around 0.5–1.0 is a typical unsharp-mask look; negative values give a soft halo. Sharpening an elevation field (dem) before hillshade or slope steepens the flanks of ridges and valleys, so the shading draws crisper crests; a field is not clamped, so values can overshoot past the field’s range next to a sharp step. A field keeps its nodata value and geographic scale; a nodata neighbour counts as the centre value, so a hole does not distort its rim, and a nodata sample stays nodata. Grows upstream pad by 1.

The shared basemap, before sharpenThe same tile after sharpen
Unsharp-mask style sharpening. style
Field Type Required Description
amount number | $param | @node no Sharpening strength. 0 = pass-through, ~1 = strong.
input @node yes Reference to another node (@name).

Slope angle as grayscale, normalised to 0..1 against max-deg. Missing samples (NaN or the field’s nodata value) are fully transparent; a missing neighbour counts as the centre value, so the edge of a hole reads as level ground instead of a sheer drop.

Field Type Required Description
field @node yes Reference to another node (@name).
invert boolean | $param | @node no If true, flat = white and steep = black.
max-deg number | $param | @node no Slope angle (degrees) that maps to white.

Solid-colour source. kind: raster (default) fills the full canvas; kind: sprite emits a Sprite at width-px × height-px for use as a synthetic placement/tiling source.

A tile rendered with solid
A single flat colour over the whole canvas. style
Field Type Required Description
color color | $param | @node yes sRGB hex color, $param reference, or @node scalar port.
height-px integer (1…∞) no —
kind raster | sprite no —
width-px integer (1…∞) no —

Composite an ordered list of raster layers bottom-to-top with plain source-over (equivalent to a chain of blend nodes with mode: normal, composite: over, opacity: 1), folded into one pass over a single accumulator. Fully-transparent layers are skipped. For per-layer opacity, blend modes, clipping, masks, or the eraser composite, use blend.

The shared basemap, before stackThe same tile after stack
Several rasters composited bottom-to-top in one pass. style
Field Type Required Description
layers array of @node yes Raster (or sprite) layers, bottom first. The output mirrors the bottom layer’s kind.

Binarise a scalar field: emit low for samples ≤ value, high otherwise. With softness > 0 the transition is a linear ramp of width softness centred on value. Missing samples (NaN or the field’s nodata value) stay missing: the output keeps the field’s nodata value and geographic scale, and writes missing pixels as that nodata, or NaN.

Field Type Required Description
field @node yes Reference to another node (@name).
high number | $param | @node no —
low number | $param | @node no —
softness number (0…∞) | $param | @node no —
value number | $param | @node no —

Repeat a raster across the canvas with bilinear wrap-around sampling. Primary use case is paper / canvas texture composition. Does not stretch-to-fit — use a dedicated cover/contain node if that’s what you want.

Field Type Required Description
anchor world | tile no world (default) makes the pattern seamless across map tiles; tile restarts the pattern at every map tile’s top-left.
input @node yes Reference to another node (@name).
offset-px array of number no Pattern offset in canvas pixels [x, y].
opacity number (0…1) | $param | @node no —
rotation-deg number | $param | @node no Rotation of the pattern in degrees (clockwise).
scale-px number (0.5…∞) no Canvas pixels per one source repetition. Defaults to the source image’s native width.

Adaptively boost CIELAB chroma — low-chroma pixels rise more than already-vivid ones (amount = strength, 0 = identity). Hue and lightness preserved.

The shared basemap, before vibranceThe same tile after vibrance
Saturation raised on muted colours only, leaving saturated ones alone. style
Field Type Required Description
amount number (0…∞) | $param | @node no —
input @node yes Reference to another node (@name).

Domain warp via an internal noise field, on a raster, sprite or scalar field; the output is the same kind as the input. With anchor: world (default) the warp is seamless across tile borders; the upstream pad grows by amp-px to keep samples inside the available raster. Warping an elevation field (dem) before contour makes the contour lines wobble together without ever crossing, since they stay level lines of one surface; warping a noise field with kind: scalar gives a swirled field to threshold or ramp. A field keeps its nodata value and geographic scale; nodata samples are left out of the interpolation, and a read with only nodata around it stays nodata. A field always clamps at its edge; boundary applies to images.

The shared basemap, before warpThe same tile after warp
Pixels pushed around by internal noise — the paper-wobble op. style
Field Type Required Description
amp-px number (0…∞) | $param | @node yes —
amp-x-px number (0…∞) | $param | @node no —
amp-x-px-max number (0…∞) no Upper bound on amp-x-px for padding, required when amp-x-px is an @node port. Values above it are clamped.
amp-y-px number (0…∞) | $param | @node no —
amp-y-px-max number (0…∞) no Upper bound on amp-y-px for padding, required when amp-y-px is an @node port. Values above it are clamped.
anchor tile | world no —
boundary clamp | transparent | mirror no —
gain number | $param | @node no —
input @node yes Reference to another node (@name).
lacunarity number | $param | @node no —
octaves integer (1…12) no —
scale-px number (0…∞) | $param | @node yes —
seed integer (0…∞) no Field seed. Omitted, anchor: world uses a fixed seed so every tile samples the same field, and anchor: tile uses the host’s per-tile seed so each tile gets its own. Set it to pin either.
type white | value | perlin | simplex | worley | cell no —

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.