Skip to main content

Expression functions

Expressions are JavaScript, and two namespaces cover what design expressions usually need: Color transforms colors and prints them as text, and Math holds the standard JavaScript math functions plus clamp. Both are available wherever an expression runs: expression variables, Set Variable actions in expression mode, and conditions.

Completion

To open suggestions in an expression field, type . after Color or Math to list that namespace's members with a one-line description, or press Ctrl + Space to list the variables and the two namespaces. Suggestions do not open while you type a name (completion). Arrow keys move the highlight, Enter or Tab inserts the highlighted entry (functions come with their parentheses, caret inside), and Escape closes the list without leaving the field. While the caret sits inside a function's parentheses the list shows the function's typed signature with the current parameter highlighted and a line explaining it.

Color

Every function takes a color as either a color variable (or any [r, g, b, a] value with 0–1 components) or a color string in any accepted format, so Color.lighten(brand, 0.2) and Color.lighten('#336699', 0.2) are the same call. Transforms return a color; Color.format returns a string, Color.contrastRatio a number and Color.equals a boolean. Compare colors with Color.equals(a, b). Colors are [r, g, b, a] arrays, and JavaScript's === compares array references, not their channels.

Color.darken(brand, 0.2) // a slightly darker brand color
Color.format(Color.mix(brand, 'white'), 'hsl') // "hsl(211.11, 35.06%, 69.8%)" for #336699
Color.contrastPick(background, 'white', 'black')

Amounts are fractions from 0 to 1. Lightness and saturation move by a share of the remaining headroom, so already light or vivid colors still change instead of clipping. Lightness, saturation, hue and mixing work in the OKLCH color space, the same math as color adjustments on component inputs, so Color.lighten(c, 0.2) matches a Lightness adjustment of 0.2.

FunctionEffect
Color.lighten(color: color, amount: number) → colorMove lightness toward white
Color.darken(color: color, amount: number) → colorMove lightness toward black
Color.saturate(color: color, amount: number) → colorIncrease colorfulness
Color.desaturate(color: color, amount: number) → colorDecrease colorfulness
Color.rotateHue(color: color, degrees: number) → colorRotate the hue
Color.mix(color: color, target: color, ratio: number = 0.5) → colorBlend toward target
Color.tint(color: color, ratio: number = 0.5) → colorBlend toward white
Color.shade(color: color, ratio: number = 0.5) → colorBlend toward black
Color.alpha(color: color, alpha: number) → colorSet the alpha
Color.fade(color: color, factor: number) → colorMultiply the alpha
Color.grayscale(color: color) → colorRemove all colorfulness
Color.complement(color: color) → colorThe opposite hue
Color.invert(color: color) → colorInvert the red, green and blue channels
Color.contrastPick(background: color, light: color, dark: color) → colorWhichever of light and dark reads better on background
Color.contrastRatio(a: color, b: color) → numberThe WCAG contrast ratio between two colors, 1 to 21
Color.equals(a: color, b: color) → booleanWhether two colors are the same to 8-bit precision, alpha included
Color.parse(text: string) → colorThe [r, g, b, a] components of a color string
Color.format(color: color, kind: string = 'display') → stringPrint the color as a string

Format kinds

Color.format(c, kind) prints a color as a string. Every kind is one the color fields accept, so a formatted string can be pasted back anywhere.

kindExample
'display' (default)#336699, or #336699 50% when translucent
'hex'#336699 (alpha dropped)
'hex8'#336699FF
'rgb'rgb(51, 102, 153) or rgba(51, 102, 153, 0.5)
'hsl'hsl(210, 50%, 40%) or hsla(210, 50%, 40%, 0.5)
'hwb'hwb(210 20% 40%) or hwb(210 20% 40% / 0.5)
'hsb'hsb(210, 66.67, 60) or hsba(210, 66.67, 60, 0.5)

Errors

A value that is not a color, an amount that is not a number, or an unknown format kind fails the expression, and the variable shows the message, for example Color.darken: argument 1 is not a color: "teal-ish". The variable keeps its last good value until the expression is fixed.

Color is reserved: a variable cannot be named Color, so the functions stay reachable. Lowercase color is fine.

Math

The standard JavaScript Math object, unchanged, plus Math.clamp(value, min, max) to keep a number within bounds:

Math.clamp(width / 3, 80, 240) // never below 80 or above 240
Math.round(height * 0.618)
Math.max(gap, 8)

Math.random() gives a different number on every evaluation, so a variable using it changes whenever anything it depends on changes.

FunctionEffect
Math.abs(x: number) → numberThe absolute value of x
Math.acos(x: number) → numberThe arccosine of x, in radians
Math.acosh(x: number) → numberThe hyperbolic arccosine of x
Math.asin(x: number) → numberThe arcsine of x, in radians
Math.asinh(x: number) → numberThe hyperbolic arcsine of x
Math.atan(x: number) → numberThe arctangent of x, in radians
Math.atan2(y: number, x: number) → numberThe angle from the x axis to the point (x, y), in radians
Math.atanh(x: number) → numberThe hyperbolic arctangent of x
Math.cbrt(x: number) → numberThe cube root of x
Math.ceil(x: number) → numberx rounded up to an integer
Math.clamp(value: number, min: number, max: number) → numbervalue limited to the range min to max
Math.clz32(x: number) → numberThe number of leading zero bits in the 32-bit integer x
Math.cos(x: number) → numberThe cosine of x radians
Math.cosh(x: number) → numberThe hyperbolic cosine of x
Math.E: numberEuler's number, about 2.718
Math.exp(x: number) → numbere raised to the power x
Math.expm1(x: number) → numbere raised to the power x, minus 1
Math.f16round(x: number) → numberx rounded to the nearest 16-bit float
Math.floor(x: number) → numberx rounded down to an integer
Math.fround(x: number) → numberx rounded to the nearest 32-bit float
Math.hypot(...values: number) → numberThe square root of the sum of squares of the arguments
Math.imul(a: number, b: number) → numberThe 32-bit integer product of a and b
Math.LN10: numberThe natural logarithm of 10, about 2.303
Math.LN2: numberThe natural logarithm of 2, about 0.693
Math.log(x: number) → numberThe natural logarithm of x
Math.log10(x: number) → numberThe base-10 logarithm of x
Math.LOG10E: numberThe base-10 logarithm of e, about 0.434
Math.log1p(x: number) → numberThe natural logarithm of 1 + x
Math.log2(x: number) → numberThe base-2 logarithm of x
Math.LOG2E: numberThe base-2 logarithm of e, about 1.443
Math.max(...values: number) → numberThe largest of the arguments
Math.min(...values: number) → numberThe smallest of the arguments
Math.PI: numberThe ratio of a circle’s circumference to its diameter, about 3.142
Math.pow(base: number, exponent: number) → numberbase raised to the power exponent
Math.random() → numberA pseudo-random number from 0 up to 1; differs on every evaluation
Math.round(x: number) → numberx rounded to the nearest integer
Math.sign(x: number) → number-1, 0 or 1 by the sign of x
Math.sin(x: number) → numberThe sine of x radians
Math.sinh(x: number) → numberThe hyperbolic sine of x
Math.sqrt(x: number) → numberThe square root of x
Math.sumPrecise(values: number[]) → numberThe exact sum of an array of numbers, rounded once
Math.SQRT1_2: numberThe square root of 1/2, about 0.707
Math.SQRT2: numberThe square root of 2, about 1.414
Math.tan(x: number) → numberThe tangent of x radians
Math.tanh(x: number) → numberThe hyperbolic tangent of x
Math.trunc(x: number) → numberx with the fraction removed