X-GIS

Language

Function reference.

Every builtin the evaluator knows about. Use any of these inside a utility binding (utility-[expr]), a layer filter (filter:), a block property (extrude:, geometry:), or as a match-arm value.

Inputs are coerced — strings get parseFloat'd, booleans become 0/1, anything else becomes 0. Numeric ops follow JS semantics except division-by-zero returns 0 (no Infinity).

Math

Number-in / number-out helpers. Inputs are coerced via `toNumber` (strings parseFloat, booleans 0/1, anything else 0). Division-by-zero in the language operators returns 0 silently — these helpers follow the same convention.

clamp

clamp(value, min, max)

Pin value into the closed range [min, max]. Equivalent to min(max(value, min), max) but a single call.

size-[clamp(.speed / 50, 4, 24)]

min

min(a, b, …)

Smallest of all arguments. Variadic — pass any number of values.

stroke-[min(.width, 8)]
opacity-[min(.alpha, 0.7)]

max

max(a, b, …)

Largest of all arguments. Variadic.

stroke-[max(.width, 1)]

round

round(value)

Round half-up to the nearest integer.

size-[round(.zoom)]

floor

floor(value)

Round down to the next integer.

size-[floor(.density / 100)]

ceil

ceil(value)

Round up to the next integer.

size-[ceil(.depth)]

abs

abs(value)

Absolute value.

stroke-[abs(.delta)]

sqrt

sqrt(value)

Square root. Negative inputs return NaN; the toNumber pipeline coerces NaN to 0 in arithmetic.

size-[sqrt(.area)]

pow

pow(base, exponent)

Raise base to exponent. pow(x, 0.5) is equivalent to sqrt(x).

size-[pow(.population, 0.3)]

exp

exp(value)

Natural exponential — e ^ value.

size-[exp(.score / 1000)]

log

log(value)

Natural log — ln(value). Inputs ≤ 0 are clamped to 1e-10 to avoid -Infinity.

size-[log(.population)]

ln

ln(value)

Alias for log — kept so converted Mapbox styles using ["ln", x] round-trip 1:1.

log10

log10(value)

Base-10 log. Same negative-input clamp as log.

fill-[interpolate(log10(.population), 3, white-100, 7, red-500)]

log2

log2(value)

Base-2 log. Same clamp as log.

size-[log2(.zoom)]

scale

scale(value, factor)

Multiply value by factor. Pure sugar over * for chained pipe operations: .x | scale(2).

size-[.height | scale(0.5)]

Trigonometry

Standard trig in **radians**. Convert from degrees with `value * PI / 180` or use the `TAU` constant for full-revolution math.

sin

sin(radians)

Sine.

stroke-[sin(.angle) * 5]

cos

cos(radians)

Cosine.

size-[cos(.heading) * 10]

tan

tan(radians)

Tangent.

asin

asin(value)

Inverse sine. Inputs outside [-1, 1] return NaN.

acos

acos(value)

Inverse cosine. Inputs outside [-1, 1] return NaN.

atan

atan(value)

Inverse tangent.

atan2

atan2(y, x)

Two-arg arctangent — angle of the vector (x, y) in [-π, π]. Use this for "rotate to face direction" since it handles all four quadrants.

size-[atan2(.dy, .dx)]

Stops & gates

Builtins that pick or blend between values. Both work for any input — `zoom` (camera state), `.field` (feature property), arithmetic results.

interpolate

interpolate(input, x1, y1, x2, y2, …)

Linear interpolation between (xi, yi) stops. When input is below x1 returns y1; above the last xN returns yN; in between blends linearly. Numeric values blend; non-numeric (e.g. color hex) snap to the nearest stop without blending. The single most-used builtin — covers every Mapbox interpolate zoom-driven paint property.

opacity-[interpolate(zoom, 8, 40, 14, 100)]
stroke-[interpolate(zoom, 11, 1, 19, 2.5)]
fill-[interpolate(.population, 0, white-100, 1e6, red-500)]

step

step(input, default, stop1, val1, stop2, val2, …) // OR step(value, threshold, below, above)

Discrete-stop gate. Two shapes: the **N-stop** form (Mapbox-spec — preferred) returns default while input < stop1, then walks stops left-to-right and returns the val for the largest stop_i ≤ input. The legacy **2-stop** form (4 args) is below when value < threshold, else above. Distinguish by arg count: even = legacy, odd ≥ 5 = N-stop.

size-[step(.rank, 0.5, 5, 0.7, 10, 1)] // N-stop: default 0.5, jumps at rank 5 → 0.7, rank 10 → 1
opacity-[step(zoom, 10, 30, 100)] // legacy: < 10 → 30, else 100

Strings

String-coercing helpers. Numeric inputs stringify via `String()`; null / undefined drop. The label resolver runs strings through these the same way it does for inline `{template}` syntax.

concat

concat(a, b, c, …)

Concatenate any number of arguments after coercing each to its string form. Null / undefined are skipped (matches the Mapbox spec). Common shape inside label-[] for compound labels — bilingual names, prefix-suffix wraps, units suffixed to numbers.

label-[concat(.name, " (", .country, ")")]
label-[concat(round(.elevation_m), " m")]

downcase

downcase(value)

Lowercase the string form of value. Coerces non-strings via String().

label-[downcase(.name)]

upcase

upcase(value)

Uppercase the string form of value. Same coercion.

label-[upcase(.country_code)]

Constants

Compile-time constants. No-arg builtins.

PI

PI

π ≈ 3.14159. Half a revolution.

stroke-[sin(.heading * PI / 180) * 5]

TAU

TAU

2π ≈ 6.28318. Full revolution. Often nicer than 2 * PI.

pi

pi()

π as a zero-arg builtin call — same value as PI. Kept for 1:1 round-trip with Mapbox ["pi"].

e

e()

Euler's number — ≈ 2.71828. Mapbox ["e"] round-trip.

ln2

ln2()

ln(2) ≈ 0.69315. Mapbox ["ln2"] round-trip.

Array

Helpers for array values. The match-arm value path and geometry generators (`polygon`, `linestring`) produce arrays.

length

length(array)

Number of elements. Returns 0 for non-arrays.

size-[length(.tags)]

[i] index

array[i]

Zero-based subscript. Out-of-bounds returns null. Bracket form, not a function — read in the parser.

fill-[.colors[0]]

Geometry generators

Construct coordinate arrays / GeoJSON-shaped values from numbers. Used inside `geometry: <expr>` block-property to build a per-feature mesh from properties (e.g. draw a circle around each city sized by population).

circle

circle(cx, cy, radius, segments?)

Polygon ring approximating a circle. segments defaults to 32 (clamped ≥ 4). Returns a closed array of [lon, lat] pairs.

geometry: circle(.lon, .lat, .radius, 64)

arc

arc(cx, cy, radius, startRad, endRad, segments?)

Open polyline along an arc from startRad to endRad, both in radians. segments defaults to 32 (clamped ≥ 2).

geometry: arc(.cx, .cy, 5, 0, PI, 24)

polygon

polygon(points)

Wrap a [[lon, lat], …] ring as a GeoJSON Polygon. Caller must close the ring (or use circle which closes for you).

geometry: polygon(.boundary)

linestring

linestring(points)

Wrap a [[lon, lat], …] array as a GeoJSON LineString.

geometry: linestring(.path)

Runtime accessors

Identifiers the evaluator resolves against camera or feature state. Not function calls — just bare names.

zoom

zoom

Current camera zoom level (float). Sampled per-frame. Inject in any expression — most commonly inside interpolate(zoom, …).

opacity-[interpolate(zoom, 8, 40, 14, 100)]

.field

.field_name

Feature property accessor. .height reads the height property from the current feature's tags. Returns null when the property is missing — pair with ?? for a fallback.

fill-extrusion-height-[.height ?? 5]
filter: .class == "highway"

Was this page helpful?

Tell us what's missing