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 → 1opacity-[step(zoom, 10, 30, 100)] // legacy: < 10 → 30, else 100Strings
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"