colorx reference
# Overview
A faithful clone of Nuke's Expression node: four per-channel text fields
(r= g= b= a=) hold math that is compiled once
per render and evaluated per pixel. It runs as a filter over its source clip and loads in
Autodesk Flame (2021+), DaVinci Resolve / Fusion, Nuke, Natron, and any other
OpenFX host. The node appears under FORGE / color / colorx (labelled colorx).
The panel has four pages: Channels (the r/g/b/a expressions), Variables
(a block of name = formula statements), Constants (the k1..k4
knobs + Reference Colour), and Output (Mix, Clamp, and the Preset
pulldown).
# Install
Grab a prebuilt bundle from the latest release (macOS + Linux), or build from source.
- Unzip →
colorx.ofx.bundle. - Copy it to the OFX plugin path (root-owned — use
sudo):/Library/OFX/Plugins/on macOS,/usr/OFX/Plugins/on Linux. - macOS only — clear the download quarantine, or the host silently skips it:
sudo xattr -dr com.apple.quarantine "/Library/OFX/Plugins/colorx.ofx.bundle" - Restart the host — OFX plugins are scanned at launch.
Expression.ofx.bundle with
colorx.ofx.bundle (don't leave both installed — they share one identifier).# The pixel model
An expression sees only the current pixel — its r g b a and its
coordinates. That makes it perfect for generators and per-pixel grades, but it cannot blur,
sharpen, or sample neighbouring pixels.
x yare pixel coordinates, origin bottom-left (as in Nuke).cx cyare centred and aspect-preserved:0,0at the centre,±1at the left/right edges — use these for resolution-independent patterns.- Channels are normalised
0..1. For byte/short clips they are scaled on the way in and written back at the clip's bit depth (clamped); float clips pass through unclamped (HDR-safe). - An empty channel evaluates to
0; the defaultsr g b aare a pass-through.
# Predefined variables
Available to every expression, alongside any names you define.
| Name | Meaning |
|---|---|
| r g b a | Input channels, normalised 0..1. |
| x y | Pixel coordinates, origin bottom-left. |
| cx cy | Centred, aspect-preserved coords: (0,0) centre, ±1 at L/R edges. |
| width height | Image size (region of definition). |
| frame · t | Current frame / render time (continuous — can be fractional). t is the Nuke-parity alias. |
| pi e | Math constants (also callable as pi() e()). |
| k1 k2 k3 k4 | The Constants-page knobs (k1 defaults to 1, rest 0). Animatable. |
| ref.r ref.g ref.b | The Reference Colour swatch (RGB), default 0. |
| your aliases | A name you give a knob (e.g. call k1 "gamma" → gamma resolves to it). |
| your variables | Any name = formula you define in the Variables block. |
name = formula in the Variables block, derived from the image and evaluated in
order before the channels). A constant is dialled (a named knob + slider). Both are
usable anywhere in the channels. Use # to start a comment; separate statements with
; or a newline (Flame collapses newlines, so prefer ; there).# Knobs & output
| Control | Effect |
|---|---|
| k1 … k4 | Animatable scalar knobs. Reference by kN or by the alias you name them. Range is unbounded; display range −1…1. |
| Reference Colour | An RGB swatch, read as ref.r ref.g ref.b. |
| Mix | Blends original image (0) ↔ expression result (1). |
| Clamp Output | Clamps the result to 0..1 (applied before Mix). |
| Preset | A pulldown that loads a whole effect (channels + variables + knob values). See the gallery. |
| Expression syntax | A button that opens this reference page in your web browser. |
# Operators
| Group | Operators |
|---|---|
| Arithmetic | + - * / % ^ (power, right-associative) |
| Comparison | < <= > >= == != |
| Logical | && || ! |
| Conditional | cond ? a : b (ternary) |
Precedence follows C, with one deliberate choice: ^ binds tighter than unary minus, so
-2^2 == -4.
# Function library
Matches Nuke's Expression function set. Type to filter.
| Signature | Group | Description |
|---|---|---|
| sin(x) cos(x) tan(x) | trig | Sine, cosine, tangent (radians). |
| asin(x) acos(x) atan(x) | trig | Inverse trig (radians). |
| atan2(y, x) / atan(y,x) | trig | Two-argument arctangent — angle of the vector (x,y), full −π…π range. |
| sinh(x) cosh(x) tanh(x) | trig | Hyperbolic sine, cosine, tangent. |
| exp(x) | exp/log | e raised to x. |
| log(x) log10(x) log2(x) | exp/log | Natural, base-10, base-2 logarithms. |
| pow(x, y) | exp/log | x raised to y (same as x^y). |
| pow2(x) | exp/log | x*x. |
| sqrt(x) | exp/log | Square root. |
| ldexp(x, e) | exp/log | x · 2^e. |
| exponent(x) mantissa(x) | exp/log | Split a float into its base-2 exponent and mantissa. |
| abs(x) / fabs(x) | round | Absolute value. |
| floor(x) ceil(x) | round | Round down / up to an integer. |
| trunc(x) / int(x) | round | Truncate toward zero. |
| round(x) rint(x) | round | Round to nearest integer. |
| sign(x) | round | −1, 0, +1 by sign of x. |
| fmod(x, y) | round | Floating-point remainder (C-style — sign of the dividend). |
| hypot(x, y) | geom | Euclidean length √(x²+y²) — distance from origin. |
| radians(x) degrees(x) | geom | Convert between degrees and radians. |
| min(…) max(…) | range | Smallest / largest — variadic (max(r,g,b) works). |
| clamp(x) | range | Clamp to [0,1] (1-arg form). |
| clamp(x, a, b) | range | Clamp to [a,b]. |
| lerp(a, b, t) / mix | interp | Linear blend: a at t=0, b at t=1. |
| step(edge, x) | interp | 0 if x<edge, else 1. |
| smoothstep(a, b, x) | interp | Smooth Hermite ramp from 0 to 1 across [a,b]. |
| noise(x[, y[, z]]) | noise | Classic Perlin gradient noise, signed ~[−1,1]. 1–3 dimensions. |
| random(x[, y[, z]]) | noise | Deterministic per-cell hash in [0,1] — feed pixel coords for per-pixel values. |
| fBm(x, y, z, oct, lac, gain) | noise | Fractal Brownian motion — summed noise octaves (fractal detail). |
| turbulence(x, y, z, oct, lac, gain) | noise | Like fBm but on |noise| — billowy / veined look. |
| from_sRGB(x) to_sRGB(x) | colour | Convert between linear and sRGB. |
| from_rec709(x) to_rec709(x) | colour | Convert between linear and Rec.709. |
| from_byte(x) to_byte(x) | colour | Convert between 0..1 and 0..255. |
noise() is tableless Perlin (Gustavson/Ashima),
computed in float so it is identical across the CPU, CUDA and Metal back-ends. It is not a bit-exact
match to Nuke's own permutation. For an integer-frame seed that doesn't shimmer within a frame, wrap
time as floor(t).# Preset gallery
Every preset below is built into the Preset pulldown — picking one fills the
channels, the Variables block, and the suggested k1..k4. They're also copy-paste ready.
k1..k4 are the live sliders; ref is the Reference Colour.
UV (ST) pass
Red = horizontal, green = vertical coordinate pass. +0.5 samples each pixel's centre.
r = (x+0.5)/width
g = (y+0.5)/height
b = 0
a = 1Radial gradient
White at centre → black. k1 = radius (try 1.0).
vars: d = hypot(cx,cy)
r = clamp(1 - d/k1)
g = clamp(1 - d/k1)
b = clamp(1 - d/k1)
a = 1Angle sweep
A 0→1 ramp swept around the centre (conical gradient).
vars: ang = (atan2(cy,cx) + pi) / (2*pi)
r = ang
g = ang
b = ang
a = 1Rainbow (cosine palette)
A smooth horizontal rainbow.
vars: u = x/width
r = 0.5 + 0.5*cos(6.2831853*(u + 0.00))
g = 0.5 + 0.5*cos(6.2831853*(u + 0.33))
b = 0.5 + 0.5*cos(6.2831853*(u + 0.67))
a = 1Reference → white
Left = Reference Colour, right = white. Pick a colour to drive it.
vars: u = x/width
r = lerp(ref.r, 1, u)
g = lerp(ref.g, 1, u)
b = lerp(ref.b, 1, u)
a = 1Checkerboard
k1 = cell size in pixels (try 32).
vars: c = fmod(floor(x/k1) + floor(y/k1), 2)
r = c
g = c
b = c
a = 1Stripes
Vertical bars. k1 = period in pixels (try 32).
vars: f = x/k1 - floor(x/k1)
r = step(0.5, f)
g = step(0.5, f)
b = step(0.5, f)
a = 1Concentric rings
k1 = ring frequency (try 6).
vars: d = hypot(cx,cy)
r = 0.5 + 0.5*sin(d*k1*6.2831853)
g = 0.5 + 0.5*sin(d*k1*6.2831853)
b = 0.5 + 0.5*sin(d*k1*6.2831853)
a = 1Flower / rose
A petalled mask. k2 = number of petals (try 5).
vars: ang = atan2(cy,cx); rad = hypot(cx,cy);
m = step(rad, 0.4 + 0.3*cos(ang*k2))
r = m
g = m
b = m
a = 1Plasma
Retro demoscene plasma — animates on t. k1 = scale (try 3).
vars: v = sin(cx*k1*3) + sin(cy*k1*3 + t*0.1)
+ sin((cx+cy)*k1*2)
+ sin(hypot(cx,cy)*k1*4 - t*0.13)
r = 0.5 + 0.5*sin(v)
g = 0.5 + 0.5*sin(v + 2.0944)
b = 0.5 + 0.5*sin(v + 4.1888)
a = 1Clouds (fBm)
Soft drifting clouds. k1 = scale (try 3).
vars: n = fBm(cx*k1, cy*k1, t*0.05, 5, 2, 0.5);
c = clamp(n*0.5 + 0.5)
r = c
g = c
b = c
a = 1Marble
Veined marble from turbulence. k1 = scale (3), k2 = vein freq (2).
vars: tu = turbulence(cx*k1, cy*k1, t*0.05, 5, 2, 0.5);
m = 0.5 + 0.5*sin((cx + tu*2)*6.2831853*k2)
r = m
g = m
b = m
a = 1Colorized noise
Perlin pushed through the cosine palette. k1 = scale (try 3).
vars: n = fBm(cx*k1, cy*k1, t*0.05, 5, 2, 0.5)*0.5 + 0.5
r = 0.5 + 0.5*cos(6.2831853*(n + 0.00))
g = 0.5 + 0.5*cos(6.2831853*(n + 0.33))
b = 0.5 + 0.5*cos(6.2831853*(n + 0.67))
a = 1Film grain
Per-pixel grain on the image. k1 = amount (try 0.1). Offsets decorrelate the channels.
r = r + (random(x, y, t) - 0.5)*k1
g = g + (random(x+11, y, t) - 0.5)*k1
b = b + (random(x, y+7, t) - 0.5)*k1
a = aGamma
k1 = gamma (try 2.2).
r = pow(r, 1/k1)
g = pow(g, 1/k1)
b = pow(b, 1/k1)
a = aSaturation
k1: 0 = greyscale, 1 = unchanged, >1 = boosted.
vars: lum = 0.2126*r + 0.7152*g + 0.0722*b
r = lum + (r - lum)*k1
g = lum + (g - lum)*k1
b = lum + (b - lum)*k1
a = aDuotone
Shadows → Reference Colour, highlights → white, by luminance.
vars: lum = 0.2126*r + 0.7152*g + 0.0722*b
r = lerp(ref.r, 1, lum)
g = lerp(ref.g, 1, lum)
b = lerp(ref.b, 1, lum)
a = aPosterize
Quantise to bands. k1 = number of levels (try 6).
r = floor(r*k1)/k1
g = floor(g*k1)/k1
b = floor(b*k1)/k1
a = aVignette
Darken the edges. k1 = strength (try 0.7).
vars: d = hypot(cx,cy); v = clamp(1 - d*k1)
r = r*v
g = g*v
b = b*v
a = aScanlines (CRT)
k1 = line frequency (try 1.5).
vars: s = 0.6 + 0.4*sin(y*k1)
r = r*s
g = g*s
b = b*s
a = aHandy constants: 6.2831853 = 2π · 2.0944 = 2π/3 · 4.1888 = 4π/3.
The palette presets use Inigo Quilez's cosine palette.
# Hosts & GPU
The same expression runs on whichever back-end the host supports; results match across all of them.
GPU path on macOS — pixel-verified. CUDA on Linux/NVIDIA.
Multithreaded CPU path. Metal is gated off — Flame's macOS OFX host crashes on a Metal-advertising node.
Multithreaded CPU evaluation; each expression is compiled once per render.