Cross-type helpers: scalar math, vec2 packing, grouping, arraying, and polymorphic transforms that work on image / spline / point inputs.
Accumulator
accumulatorpolymorphic
Accumulate over time. Wire a scalar to integrate or sum a growing number. Wire points (or a vec2 — autocoerced to one point) and each playing frame appends onto a persistent set: Scatter with a time-driven seed piles up instead of replacing. Wire a spline and each frame appends its subpaths onto a persistent spline you can Stroke. Each piled point or subpath carries an `age` channel (seconds since it joined). Index mode defaults to add-on-top (append); generation tags each batch, unique assigns a stable id per item. Auto-resets on scene time 0; an optional reset input clears while held.
space
in:input=canvas01|unitless out=in:input
writes
attr:age, attr:group
flags
simulation, unstable
gotcha
The wired input's socket type wins over the type param — type only picks the domain when nothing is wired to input.
gotcha
Points/spline growth happens once per advancing scene-time sample; re-evaluating at the same timestamp does not re-add, and scrubbing backward freezes rather than reversing.
gotcha
Scalar mode=integrate multiplies input by dt (frame-rate independent, reads as units/second); mode=sum adds the raw input every evaluation.
gotcha
index_mode=append passes any incoming group tags through untouched; generation stamps a whole incoming batch with one incrementing id; unique gives every item its own incrementing id.
gotcha
overflow=ring drops the oldest points/subpaths once max_points/max_subpaths is exceeded; overflow=stop keeps the current set and discards the rest of the incoming batch.
gotcha
A wired vec2 autocoerces to a single point at that (x, y); a wired spline flips the node into spline output even if type=scalar is still selected.
gotcha
Any incoming age attribute is stripped and replaced: age is owned by this node and derived live from each item's join time, so pause/scrub read it correctly.
Parameters
Name
Type
Default
Type
type
enum
"scalar"
scalar · points · spline
Mode
mode
enum
"integrate"
integrate · sum
Initial
initial
scalar
-1000 … 1000
0
Range
range
enum
"free"
free · clamp · wrap
Min
min
scalar
-1000 … 1000
0
Max
max
scalar
-1000 … 1000
1
Indices
index_mode
enum
"add on top"
add on top · generation · unique
Max points
max_points
scalar
1 … 65536
4096
Max subpaths
max_subpaths
scalar
1 … 16384
1024
Overflow
overflow
enum
"stop"
stop · ring
Sockets
Direction
Name
Type
input*
input
input
scalar
input
reset
reset
scalar
outputprimary
out
scalar
Animated Value
animated-value
A keyframable value with a wired clock: keyframe Value as usual, then wire a scalar into Time and the curve is sampled at that time instead of the playhead — offset it, stretch it, ping-pong it, or drive it from audio. Unwired, it behaves like a keyframed Constant. Unit sets whether Time is read as frames or seconds.
space
in:time=time
flags
clock=time
gotcha
Wired time is read as frames or seconds per unit and converted to ticks for keyframe sampling; unwired, it behaves like a keyframed Constant.
gotcha
Out-of-range times clamp to the end keyframes; there is no extrapolation, looping, or ping-pong built in.
gotcha
compute() just returns params.value; resampling keyframes at the wired clock happens in the evaluator via clockInput, not in this node's compute.
gotcha
Wiring time only changes WHEN keyframes are sampled — a wire into value still overrides keyframes as usual, same precedence as any node.
Parameters
Name
Type
Default
Value
value
scalar
-1000 … 1000
0
Unit
unit
enum
"frames"
frames · seconds
Sockets
Direction
Name
Type
input
Time
time
scalar
outputprimary
out
scalar
Array
arraypolymorphic
Tile an image, spline, or points into a grid. Image mode supports modulator inputs for per-cell scale/position/rotation variation; spline / point modes emit transformed CPU geometry — feed Displace or Transform downstream for noise / uniform tweaks.
sizeW/H, patternOffsetX/Y, and localX/Y are width-relative canvas01 fractions in spline/point mode but per-axis raster uv01 fractions in image mode.
gotcha
The index aux only exists in image mode (resolveAuxOutputs drops it otherwise); spline/point copies carry no new per-tile index and just repeat the source item's own attributes.
gotcha
Copy Scale (localScaleX/Y) both spreads each source point away from its own (0.5,0.5) anchor and multiplies its scale channel, so it is not a pure per-tile resize.
gotcha
Point/spline copies are placed relative to a (0.5, 0.5) natural anchor per cell (Copy to Points convention); off-center source geometry will not land on the cell center.
gotcha
sizeMode=fit derives the cell step from countX/Y (1/count); sizeMode=step fixes the step via sizeW/H instead, so the two modes can disagree once the counts are large.
Parameters
Name
Type
Default
Instance type
mode
enum
"image"
image · spline · point
Distribution
distribution
enum
"grid"
grid
Count X
countX
scalar
1 … 64
3
Count Y
countY
scalar
1 … 64
3
Size Mode
sizeMode
enum
"fit"
fit · step
Cell W
sizeW
scalar
0.01 … 2
0.333
Cell H
sizeH
scalar
0.01 … 2
0.333
Pattern X
patternOffsetX
scalar
-1 … 1
0
Pattern Y
patternOffsetY
scalar
-1 … 1
0
Direction
direction
enum
"flow-rows"
flow-columns · flow-rows
Copy X
localX
scalar
-1 … 1
0
Copy Y
localY
scalar
-1 … 1
0
Copy Rotate
localRotate
scalar
-360 … 360
0
Copy Scale X
localScaleX
scalar
0.01 … 4
1
Copy Scale Y
localScaleY
scalar
0.01 … 4
1
Scale Mod Amt
modScaleAmount
scalar
0 … 4
1
Pos Mod Amt
modPosAmount
scalar
0 … 1
0.25
Rot Mod Amt
modRotAmount
scalar
0 … 360
90
Sockets
Direction
Name
Type
input*
instance
instance
image
input
scale mod
mod_scale
image
input
pos mod
mod_pos
image
input
rot mod
mod_rot
image
outputprimary
out
image
outputaux
index
image
Bounding Box
bounding-boxpolymorphic
Measure the bounding box of an image (alpha extent), mask, spline, or points and output it as edge scalars, midpoint/corner points, the box as a spline, and optional full-canvas guide lines.
Masks and images share one <=256px alpha/R-channel proxy readback (cached per value identity) — not the mask-to-image coercion shader, which writes alpha=1 everywhere.
gotcha
No content (fully transparent image, empty spline/points) yields empty outputs — zero-length points/spline and size=[0,0] — never a full-canvas box.
gotcha
guides_v/guides_h only exist when guides=true; they are full canvas-height/width lines through the box edges, not the box outline.
gotcha
Spline bounds include the flattened bezier curve, not just anchors, so a bulging curve can extend the box past its own anchor points.
Parameters
Name
Type
Default
Canvas Guides
guides
boolean
false
Sockets
Direction
Name
Type
input*
Image
source
image
outputprimary
out
spline
outputaux
left
scalar
outputaux
right
scalar
outputaux
top
scalar
outputaux
bottom
scalar
outputaux
mid_left
points
outputaux
mid_right
points
outputaux
mid_top
points
outputaux
mid_bottom
points
outputaux
corner_tl
points
outputaux
corner_tr
points
outputaux
corner_bl
points
outputaux
corner_br
points
outputaux
center
points
outputaux
size
vec2
Clamp
clamp
Clamp a scalar into [Lo, Hi]. Lo and Hi can be wired or set in the panel; if Lo > Hi they are swapped before clamping.
gotcha
value/lo/hi each fall back independently to their like-named param when unwired — wiring only one leaves the others on their param values.
gotcha
lo/hi are swapped automatically when lo > hi, so an inverted range just flips which bound is which instead of erroring.
Parameters
Name
Type
Default
Value
value
scalar
-1000 … 1000
0
Lo
lo
scalar
-1000 … 1000
0
Hi
hi
scalar
-1000 … 1000
1
Sockets
Direction
Name
Type
input
Value
value
scalar
input
Lo
lo
scalar
input
Hi
hi
scalar
outputprimary
out
scalar
Color
color-literalpolymorphic
Emits one or more colors as vec4 values (not images). The + on the node header adds another color output; each color square on the node opens a picker in place, and the H/S/L/A row at the bottom edits whichever square is selected. Wire an image into the palette input and the outputs switch to a palette extracted from it (color 1 = most dominant). Use to drive color-math nodes or any exposed color param.
gotcha
Wiring an image into the palette input overrides every stored color entirely; outputs become a k-means palette (color 1 = most dominant).
gotcha
count (1..8) unlocks color2..color8 as declared color params, each minting a matching vec4 aux output; alpha applies to every output.
gotcha
Palette extraction is deterministic (maximin-seeded k-means, no RNG) so it is stable across evals; a video image re-extracts every frame.
gotcha
Primary output is always color 1 (or the dominant palette color), kept for back-compat with saves that predate the count param.
Parameters
Name
Type
Default
Color
color
color
"#ffffff"
Color 2
color2
color
"#ffffff"
Color 3
color3
color
"#ffffff"
Color 4
color4
color
"#ffffff"
Color 5
color5
color
"#ffffff"
Color 6
color6
color
"#ffffff"
Color 7
color7
color
"#ffffff"
Color 8
color8
color
"#ffffff"
Alpha
alpha
scalar
0 … 1
1
Colors
count
scalar
1 … 8
1
Sockets
Direction
Name
Type
input
palette from
image
image
outputprimary
out
vec4
Combine
collectpolymorphic
Bundle N homogeneous inputs. Type follows the first wire (image, spline, points, or 3D object) and can still be set from the header. Inputs auto-grow — there's always one spare empty socket. For images, produces an image_group. For splines and points, concatenates into a single value with per-subpath / per-point groupIndex metadata matching the socket order (a=0, b=1, c=2…). Nodes that don't understand groupIndex just treat the output as a normal spline/points value; Select by Index and Count Indices key off the tags. For 3D objects, groups the inputs into one object3d for the 3D Scene node — primitives wire straight in.
space
out=in:a
gotcha
Disconnected sockets are dropped, not stubbed — the group's effective size is the count of connected sockets, independent of count/slots.
gotcha
Spline/points 'groups' aren't containers — they're flattened into one value tagged with per-item groupIndex (a=0, b=1, c=2...), compacted over connected sockets only.
gotcha
mode=object clears and re-adds children into one retained THREE.Group every eval; geometry wires land here via the geometry-to-object3d auto-wrap.
gotcha
Switching mode changes the output socket type (image_group / spline / points / object3d), so downstream wires must accept the new type.
Parameters
Name
Type
Default
Type
mode
enum
"image"
image · spline · points · object
Sockets
Direction
Name
Type
input
a
a
image
input
b
b
image
outputprimary
out
image_group
Combine Vec2
combine-vec2
Build a vec2 from two scalars. Inputs default to the x/y params when unconnected, so the node also doubles as a vec2 constant.
gotcha
x/y inputs fall back independently to their like-named params when unwired, so the node also works as a vec2 constant.
Parameters
Name
Type
Default
X
x
scalar
-10 … 10
0
Y
y
scalar
-10 … 10
0
Sockets
Direction
Name
Type
input
x
x
scalar
input
y
y
scalar
outputprimary
out
vec2
Compare
compare
Compare two scalars with one of >, <, ≥, ≤, ==, !=. Output is 1 (true) or 0 (false). Equality variants use an epsilon window so floating-point fuzz doesn't flip results.
gotcha
a/b wired inputs override their like-named params independently — wiring only one leaves the other on its param value.
gotcha
epsilon only applies to == and !=; the four inequality ops compare exactly with no tolerance.
Parameters
Name
Type
Default
Op
op
enum
">"
> · < · >= · <= · == · !=
A
a
scalar
-1000 … 1000
0
B
b
scalar
-1000 … 1000
0
Epsilon
epsilon
scalar
0 … 1
0.0001
Sockets
Direction
Name
Type
input
A
a
scalar
input
B
b
scalar
outputprimary
out
scalar
Constant
constant
Emits a single scalar value, in float or integer mode, snapped to a configurable step (2 → 2, 4, 6…; 1.2 → 1.2, 2.4, 3.6…). Use to feed exposed scalar inputs without routing through a Math node.
gotcha
Quantizes value to the step increment on every compute, so a keyframed or wired-in value is snapped too, not just the UI slider.
gotcha
mode=integer forces the effective step to a whole number (min 1) and rounds the final value, overriding a fractional step param.
gotcha
step defaults to 0.001 to match the value param's pre-step historic default, keeping old saves' exact values through the quantize.
Parameters
Name
Type
Default
Value
value
scalar
-1000 … 1000
1
Mode
mode
enum
"float"
float · integer
Step
step
scalar
0.001 … 1000
0.001
Sockets
Direction
Name
Type
outputprimary
out
scalar
Count Indices
group-lengthpolymorphic
Count distinct group members as a scalar. Image mode counts image_group items; spline and points modes count distinct groupIndex values carried on subpaths / points (un-grouped input reports 1).
reads
attr:group
gotcha
Switching Type (mode) changes the accepted input socket type (image_group / spline / points), disconnecting an existing wire of a different kind.
gotcha
Spline/points count distinct groupIndex values; untagged subpaths or points fall into an implicit index-0 bucket, so an un-grouped input always reports 1.
Parameters
Name
Type
Default
Type
mode
enum
"image"
image · spline · points
Sockets
Direction
Name
Type
input*
Collection
group
image_group
outputprimary
out
scalar
CSV
csvpolymorphic
Loads a CSV and exposes each column as an output socket carrying the cell at the selected row. Numeric columns emit scalars, text columns emit strings (wire straight into a Text node's exposed text). Drive the row to step through the data.
flags
no-mask
gotcha
Output sockets are positional ids (col:0, col:1, …); the column header is only the display label, so re-parsing keeps wires attached as long as column order is unchanged.
gotcha
A column emits scalar only if every one of its cells parses as numeric; otherwise the whole column emits string.
gotcha
row is floored; rowMode=clamp holds at row 0 or the last row past the ends, rowMode=wrap uses row mod rowCount.
gotcha
An empty or unparsed CSV yields no aux outputs at all (rowCount <= 0 short-circuits to {}).
Parameters
Name
Type
Default
CSV
csv
csv_file
—
Header row
hasHeader
boolean
true
Delimiter
delimiter
enum
"auto"
auto · comma · tab · semicolon
Row
row
scalar
0 … 100000
0
Past ends
rowMode
enum
"clamp"
clamp · wrap
Sockets
Direction
Name
Type
—
(no sockets)
Draggable
draggable
Make a shape grabbable: wire the shape's mask into handle, its offset output into a Transform translate on the same shape, and the shape drags by hand — editor and exported apps alike. The hit test follows the moved shape with no feedback cycle (it samples the un-translated mask at cursor − offset). Aux: held / hover / press / click. Reset input snaps back to rest.
space
out=canvas01 param:slop=pixels
flags
unstable
gotcha
The vec2 offset output is canvas01 authored units, exactly what Transform's translate param expects; it is not raw canvas UV or a pixel offset.
gotcha
handle unwired means the region sampler always returns null, so press/hover never registers and the shape can never be grabbed.
gotcha
slop is pixels of on-screen travel; a release within slop of the press fires click, otherwise it's a drag release with no click pulse.
gotcha
The hit test samples the UN-translated handle mask offset by the PREVIOUS eval's total offset, so hover tracking during a live drag lags one eval behind.
Parameters
Name
Type
Default
Threshold
threshold
scalar
0 … 1
0.5
Click slop (px)
slop
scalar
0 … 40
4
Drag axis
axis
enum
"both"
both · x · y
Drag sensitivity
sensitivity
scalar
0 … 10
1
Clear on loop
clear_on_loop
boolean
false
Sockets
Direction
Name
Type
input
handle
handle
mask
input
reset
reset
scalar
outputprimary
out
vec2
outputaux
held
scalar
outputaux
hover
scalar
outputaux
press
scalar
outputaux
click
scalar
Expression
expressionpolymorphic
Type a JavaScript math expression instead of wiring a chain of Math nodes. Each input socket is a named variable (x, y, z…); the + adds more. Outputs a scalar or vector. Globals: t, frame, PI, TAU, sin, cos, clamp, lerp, smoothstep, random, and the rest of Math.
space
out=unitless
reads
time
flags
no-mask
gotcha
Recompute is gated on the source text: only expressions mentioning t, time, frame, or random (word-boundary) bust the cache every frame; others evaluate once and cache as a constant.
gotcha
random() is deterministic per node and frame (mulberry32 seeded from hash(nodeId) XOR frame), so re-evaluating the same frame gives the same sequence.
gotcha
Every input socket is scalar; connecting image/mask/audio relies on the engine's universal coercion to a representative scalar, not on any per-socket logic here.
gotcha
An unconnected input falls back to that variable's own `default` field (from the Inputs list, itself defaulting to 1), not to 0.
gotcha
MCP/recipes wire by variable name (`<id>:in:x`), not the minted ein- id. Grow vars with params.inputs = [{name, default?}] or add_edge to a new name; ids stay by index across renames.
gotcha
A compile error or an empty expression outputs a zero shaped by out_type; the error text only surfaces via a one-time console.warn, not in the graph UI.
gotcha
out_type picks scalar vs vec2/3/4; a scalar result broadcasts to every vector component, an array result fills components in order and pads missing ones with 0.
Parameters
Name
Type
Default
Inputs
inputs
expr_inputs
[{"id":"ein-x0","name":"x","default":1}]
Expression
expression
string
"x"
Output
out_type
enum
"scalar"
scalar · vec2 · vec3 · vec4
Sockets
Direction
Name
Type
input
x
in:ein-x0
scalar
outputprimary
out
scalar
Float Curve
float-curve
Remap a scalar through an editable curve: the input is x in [0..1], the output is the curve's y there. Inputs outside 0..1 hold the endpoint values. Use Remap to bring other ranges into 0..1 first.
gotcha
The value input, when wired, overrides the value param entirely; the param only applies unwired.
gotcha
Curve points are clamped to [0,1] on both axes and re-sorted by x, so dragging a point past its neighbor changes evaluation order.
gotcha
Interpolation is monotone cubic Hermite, so the curve never overshoots past a control point's y even between widely-spaced points.
On-canvas position / rotation / scale / pivot control. Outputs a transform value you can wire into primitives (Circle, Rectangle, Point, …) and Transform so several shapes share one placement. Wire another Gizmo into this node's Transform input to parent them.
Outputs a transform value only; nothing moves until it's wired into a primitive or Transform that applies parent ops first, then this node's TRS.
gotcha
An identity local transform (defaults unchanged) is dropped when composing over a wired parent, so a default Gizmo just passes the parent through.
gotcha
pivotX/Y are absolute canvas01 coordinates (default 0.5,0.5 = canvas center), not a 0..1 fraction of the consumer's own bounds.
Parameters
Name
Type
Default
Translate X
translateX
scalar
-1 … 1
0
Translate Y
translateY
scalar
-1 … 1
0
Scale X
scaleX
scalar
0.01 … 10
1
Scale Y
scaleY
scalar
0.01 … 10
1
Rotate (°)
rotate
scalar
-360 … 360
0
Pivot X
pivotX
scalar
0 … 1
0.5
Pivot Y
pivotY
scalar
0 … 1
0.5
Sockets
Direction
Name
Type
input
Transform
transform
transform
outputprimary
out
transform
Hit Region
hit-region
Turn any shape into a button: gates pointer signals on a mask region (wire a Circle, Text, SVG, or any spline — the silhouette becomes the hit area). Outputs hover, and press / click / release / held for gestures that STARTED inside, with real button grab semantics (leaving mid-drag doesn't drop the gesture). drag_delta tracks the owned gesture — Hit Region → Trigger Envelope is an interactive button; drag_delta → Transform is a crude handle.
space
param:slop=pixels aux:drag_delta=canvas01
flags
unstable
gotcha
The hit test is a live 1×1 GPU sample-and-readback at the cursor, uncached, run once for hover plus once per press edge — no memoization to go stale.
gotcha
GRAB semantics: press hit-tests once at the PRESS position; once owned, held/click stay true even if the cursor leaves the region mid-drag, until release.
gotcha
click requires the owned gesture to release within slop of its start; slop is CSS pixels of on-screen pointer travel, not render-resolution pixels.
gotcha
drag_delta is nonzero only while held, in canvas01 (authored, aspect-corrected) units — the same convention Transform's x/y offsets use.
gotcha
No region wired means every signal (hover/press/click/held) reads false; the sampler returns null and null never clears the threshold.
gotcha
retimeable:false — hit-testing always reads the live wall-clock cursor state, not the position at whatever timeline frame is being evaluated.
Parameters
Name
Type
Default
Threshold
threshold
scalar
0 … 1
0.5
Click slop (px)
slop
scalar
0 … 40
4
Sockets
Direction
Name
Type
input
region
region
mask
outputprimary
out
scalar
outputaux
hover
scalar
outputaux
press
scalar
outputaux
release
scalar
outputaux
click
scalar
outputaux
drag_delta
vec2
Lerp
lerppolymorphic
Linear interpolation (mix) between A and B by t. Works on scalars, vec2, points sets, or splines (matching counts required for points/splines). t can be wired or set in the panel; Clamp restricts it to [0..1].
space
out=in:a
gotcha
Point (points) and spline lerp require matching counts (point count; subpath count and anchors-per-subpath) - a mismatch returns A unchanged.
gotcha
Only attributes present on both A and B at the same arity are lerped; B-only attributes are dropped, A-only ones pass through unlerped.
gotcha
Spline closed flag and point groupIndices are always taken from A, never interpolated.
gotcha
Normals lerp per-component then renormalize; a plain lerp would shorten the vector.
gotcha
t input, when wired, overrides the t param; clamp then clips to [0,1], but the param itself ranges -2..2 for extrapolation.
Parameters
Name
Type
Default
Type
type
enum
"scalar"
scalar · vec2 · points · spline
t
t
scalar
-2 … 2
0.5
Clamp t to [0..1]
clamp
boolean
false
A
a_value
scalar
-1000 … 1000
0
B
b_value
scalar
-1000 … 1000
1
Sockets
Direction
Name
Type
input
A
a
scalar
input
B
b
scalar
input
t
t
scalar
outputprimary
out
scalar
LFO
lfo
Periodic scalar oscillator — sine, triangle, sawtooth, or square. Frequency is in Hz, phase is in cycles. Output rides in [-amplitude, +amplitude] + offset.
reads
time
flags
unstable
gotcha
frequency, phase, amplitude, and offset each take the wired scalar input over their same-named param when connected.
gotcha
phase wraps via ((time*frequency+phase)%1+1)%1, so negative frequency or phase still produce a valid, non-jumping phase.
gotcha
square is a hard step: +1 for phase<0.5, -1 otherwise, with no smoothing at the transition.
Parameters
Name
Type
Default
Shape
shape
enum
"sine"
sine · triangle · sawtooth · square
Frequency (Hz)
frequency
scalar
0 … 100
1
Phase (cycles)
phase
scalar
-1 … 1
0
Amplitude
amplitude
scalar
0 … 100
1
Offset
offset
scalar
-100 … 100
0
Sockets
Direction
Name
Type
input
Frequency (Hz)
frequency
scalar
input
Phase (cycles)
phase
scalar
input
Amplitude
amplitude
scalar
input
Offset
offset
scalar
outputprimary
out
scalar
List
listpolymorphic
Parses pasted or loaded text into a list — newlines, commas, tabs, pipes, semicolons, JSON arrays, bulleted/numbered lists, or range shorthand (1..10, a..e, 0..20 step 2). Outputs the whole list for the list transform nodes, plus the item at an animatable index (a scalar for numeric lists, a string otherwise) and the item count.
flags
no-mask
gotcha
itemType=auto infers scalar vs string from whether every cell is numeric; forcing number/text re-types the WHOLE list, not just the indexed item.
gotcha
Because the item socket's type is inferred from the currently stored text param, driving text from an upstream wire can leave item typed one step behind a change in the incoming data's numeric-ness.
gotcha
index is floored; indexMode=clamp holds at 0/length-1, indexMode=wrap uses ((i%length)+length)%length; an empty list returns 0 (scalar) or "" (string) instead of leaving item disconnected.
Parameters
Name
Type
Default
Items
text
string
""
Format
format
enum
"auto"
auto · lines · comma · semicolon · tab · pipe · whitespace · json · range
Trim items
trim
boolean
true
Drop empties
dropEmpty
boolean
true
Remove duplicates
dedupe
boolean
false
Item type
itemType
enum
"auto"
auto · text · number
Index
index
scalar
0 … 100000
0
Past ends
indexMode
enum
"clamp"
clamp · wrap
Sockets
Direction
Name
Type
outputprimary
out
list
outputaux
item
string
outputaux
count
scalar
Logic
logicpolymorphic
Boolean gate over scalar inputs. Any non-zero is treated as true. Output is 1 (true) or 0 (false). Ops: and, or, xor, not (1-input).
gotcha
op=not is single-input: the b socket and param are hidden and b is ignored regardless of what is wired.
Parameters
Name
Type
Default
Op
op
enum
"and"
and · or · xor · not
A
a
scalar
0 … 1
0
B
b
scalar
0 … 1
0
Sockets
Direction
Name
Type
input
A
a
scalar
input
B
b
scalar
outputprimary
out
scalar
Math
mathpolymorphic
Scalar math: arithmetic, comparison, rounding, trig, and conversion. Each input can be a connected scalar or a value typed in the panel.
space
out=unitless|raster|canvas01
gotcha
Output type follows priority: any scalar_field wired into a/b/c compiles the op into a downstream SDF field expression, else mode=uv runs a per-pixel shader, else it's a plain scalar.
gotcha
In mode=uv, Logarithm, Smooth Minimum/Maximum, Wrap, and Arctan2 are not implemented in the shader and silently pass through input A unchanged.
gotcha
clamp clamps the result to [0,1] in scalar, uv, and field modes (the field AST wraps the expression in its own clamp node).
gotcha
Which of B/C sockets appear depends on the operation (INPUT_COUNT): e.g. Wrap needs Value/Min/Max, Snap needs Value/Increment.
Parameters
Name
Type
Default
Mode
mode
enum
"scalar"
scalar · uv
Operation
operation
enum
"Add"
Add · Subtract · Multiply · Divide · Multiply Add · Power · Logarithm · Square Root · Inverse Square Root · Absolute · Exponent · Minimum · Maximum · Less Than · Greater Than · Sign · Compare · Smooth Minimum · Smooth Maximum · Round · Floor · Ceiling · Truncate · Fraction · Truncated Modulo · Floored Modulo · Wrap · Snap · Ping-Pong · Sine · Cosine · Tangent · Arcsine · Arccosine · Arctangent · Arctan2 · Hyperbolic Sine · Hyperbolic Cosine · Hyperbolic Tangent · To Radians · To Degrees
A
a
scalar
-1000 … 1000
0
B
b
scalar
-1000 … 1000
0
C
c
scalar
-1000 … 1000
0
Clamp to 0-1
clamp
boolean
false
Sockets
Direction
Name
Type
input
A
a
scalar
input
B
b
scalar
outputprimary
out
scalar
Mirror
mirrorpolymorphic
Mirror an image, spline, or points across the X / Y axis (or both), or repeat them radially around a center with a count slider — with an optional kaleidoscope reflection per wedge. Bisect cuts the input to one half-plane (X / −X / Y / −Y) before mirroring, so only the kept side is reflected. Copies can tag groupIndex per copy for ramp-by-group fills or Group Pick downstream.
Radial copies rotate in pixel-isotropic space (dy/aspect) so they stay rigid on non-square canvases; axis flips and the 180 degree copy are aspect-free.
gotcha
On points, a single flip mirrors the point's frame: rotation negates and the flipped axis's scale.x/scale.y negates; two flips compose to a plain 180 degree rotation.
gotcha
tagGroups stamps group as the copy index (0..copies-1) on every emitted point/subpath; off, the incoming group passes through unchanged. Hidden when an image is wired.
gotcha
kaleidoscope (mode=radial only) adds one Y-flipped mirror copy per wedge, doubling the copy count to build dihedral symmetry.
gotcha
mode=bisect clips to the keep half-plane then mirrors. keep=x is x≥centerX (right), -x is x≤centerX (left), y is y≥centerY (down), -y is y≤centerY (up).
gotcha
In mode=bisect, points on the mirror plane are kept once (not doubled by the reflected copy); closed curves that cross the plane become open arcs with endpoints on the plane.
gotcha
An image is inverse-sampled per copy and source-overed (later copies win where they overlap); opaque full-frame plates should use mode=bisect so each pixel has one contributor.
Parameters
Name
Type
Default
Mode
mode
enum
"x"
X · Y · Both · Radial · Bisect
Side
keep
enum
"x"
X · −X · Y · −Y
Center X
centerX
scalar
0 … 1
0.5
Center Y
centerY
scalar
0 … 1
0.5
Count
count
scalar
1 … 64
6
Kaleidoscope
kaleidoscope
boolean
false
Keep source
includeSource
boolean
true
Group per copy
tagGroups
boolean
false
Sockets
Direction
Name
Type
input*
Image
source
image
outputprimary
out
image
Number to String
number-to-string
Formats a number as text — decimal places, zero-padding, thousands separators, prefix/suffix. Wire it into a Text node's text to show an animated value (counters, scores, percentages).
flags
no-mask
gotcha
Non-finite input (NaN/Infinity) formats as 0, not as literal "NaN"/"Infinity" text.
gotcha
trimZeros only strips trailing fractional zeros (and the dot) when decimals>0; it never touches the integer part.
gotcha
pad zero-pads the integer digits only, inside the sign (-7 -> "-007", not "0-07"); thousands grouping is applied after padding.
Parameters
Name
Type
Default
Value
value
scalar
-1000000 … 1000000
0
Decimals
decimals
scalar
0 … 10
0
Trim zeros
trimZeros
boolean
false
Min digits
pad
scalar
0 … 12
0
Thousands
thousands
boolean
false
Prefix
prefix
string
""
Suffix
suffix
string
""
Sockets
Direction
Name
Type
input
Value
value
scalar
outputprimary
out
string
Pointer
pointer
Mouse / touch interaction signals: cursor position (authored space), press / release / click pulses, held and drag-active levels, per-gesture drag delta, and an accumulated drag offset with axis lock and sensitivity — the virtual-scrub control. Click vs drag is split by the slop threshold. Wire click into Trigger Envelope for motion, drag_offset into a Transform translate, press into an Accumulator for click counting.
Position and the vec2 aux outputs are authored space (y-down, aspect-uncorrected) — wire straight into Transform translate or point params.
gotcha
slop compares on-screen CSS pixels of pointer travel (clientX/Y), not canvas render-resolution pixels, so it doesn't scale with the project's render resolution.
gotcha
duration and the held-bucket used for re-eval use wall-clock performance.now(), not scene time, so a live held gesture's reported duration ignores timeline scrubbing.
gotcha
reset > 0.5 zeroes drag_offset, click_count, and click_position and holds them there while high; clear_on_loop does the same automatically whenever scene time jumps backward.
gotcha
Presses claimed by editor overlay gestures (gizmos, spline tools, paint) never reach this node; held/press/click stay at rest during those.
Parameters
Name
Type
Default
Click slop (px)
slop
scalar
0 … 40
4
Drag axis
axis
enum
"both"
both · x · y
Drag sensitivity
sensitivity
scalar
0 … 10
1
Clear on loop
clear_on_loop
boolean
false
Sockets
Direction
Name
Type
input
reset
reset
scalar
outputprimary
out
vec2
outputaux
held
scalar
outputaux
press
scalar
outputaux
release
scalar
outputaux
click
scalar
outputaux
click_position
vec2
outputaux
drag_active
scalar
outputaux
drag_delta
vec2
outputaux
drag_offset
vec2
outputaux
duration
scalar
outputaux
click_count
scalar
Proximity Join/Merge
proximity-mergepolymorphic
Combine multiple splines (or point sets) and weld the parts that fall within a distance threshold in UV space. Join stitches open subpath endpoints into continuous / closed paths (a real topology change); Snap clusters nearby anchors/points to their shared centroid. Inputs auto-grow — there's always one spare empty socket — and a single socket also accepts a spline group from the Combine node. Animate exposes a `t` scalar (0..1) that slides parts together, committing the join/collapse at t=1 with no pop.
space
param:distance=uv01 out=in:in
gotcha
distance measures raw per-axis UV deltas, not aspect-corrected canvas distance: on a non-square canvas the same value reaches further in x than in y or vice versa.
gotcha
mode=points also blends rotation and scale.x/y (and any named point attribute) toward the cluster mean at the same t as position, not just position.
gotcha
dedupe only fires once t reaches 1 (the commit); with animate on and t<1 the checkbox has no visible effect yet.
gotcha
join's weld anchor is marked broken whenever both welded ends carried real handles, so the seam reads as a sharp corner, not a smoothed curve.
gotcha
A joined chain only self-closes into a closed subpath when it has 3+ anchors and its two free ends also land within distance; shorter chains stay open.
Parameters
Name
Type
Default
Type
mode
enum
"spline"
spline · points
Operation
op
enum
"snap"
join · snap
Distance
distance
scalar
0 … 1
0.05
Animate
animate
boolean
false
t
t
scalar
0 … 1
1
Dedupe at t=1
dedupe
boolean
false
Sockets
Direction
Name
Type
input
Spline
in
spline
outputprimary
out
spline
Random
randompolymorphic
Random scalar or vec2. Seeded mode is deterministic per frame; Frame mode re-rolls each eval. Uniform draws from [Lo, Hi]; Gauss returns normals centered on (Lo+Hi)/2 with ±3σ ≈ Hi-Lo.
space
out=unitless
reads
time
flags
unstable
gotcha
mode=seeded hashes (seed, frame index), so it is reproducible per frame but only changes when the frame advances; mode=frame re-rolls Math.random() every eval and is not reproducible across runs.
gotcha
gauss maps a Box-Muller sample by +/-3 sigma into [lo, hi] (sigma=(hi-lo)/6), so ~99.7% of samples land inside the range but outliers can exceed lo/hi.
gotcha
In seeded mode, multiple downstream reads within the same frame return the identical cached value rather than being redrawn per pull.
gotcha
shape=vec2 draws two independent samples from the same seed via different hash salts, not one value duplicated on both axes.
Parameters
Name
Type
Default
Shape
shape
enum
"scalar"
scalar · vec2
Mode
mode
enum
"seeded"
seeded · frame
Distribution
distribution
enum
"uniform"
uniform · gauss
Seed
seed
scalar
0 … 100000
42
Lo
lo
scalar
-1000 … 1000
0
Hi
hi
scalar
-1000 … 1000
1
Sockets
Direction
Name
Type
outputprimary
out
scalar
Relax
relaxpolymorphic
Iteratively even out geometry. Points: push apart every pair closer than the radius (de-clump a Scatter). Splines: Laplacian-smooth anchor positions along each subpath (endpoints pinned, closed wraps; handles unchanged). Mix blends back toward the original.
space
param:radius=canvas01 out=in:in
gotcha
Points mode uses a spatial hash sized to radius; pairs beyond adjacent cells never interact, and each iteration applies all pushes Jacobi-style with a fixed 0.5 damping.
gotcha
Spline mode Laplacian-smooths only anchor positions per subpath; handles ride along unchanged, so re-fit with Set Spline Type afterwards if curvature drifted.
gotcha
Spline mode pins the endpoints of an open subpath and wraps around a closed one; points mode has no pinning, every point can move.
gotcha
Exactly-coincident point pairs separate along a deterministic per-index hashed angle instead of a random one, keeping output stable and cacheable frame to frame.
Parameters
Name
Type
Default
Type
mode
enum
"points"
points · spline
Iterations
iterations
scalar
1 … 100
5
Mix
mix
scalar
0 … 1
1
Radius
radius
scalar
0 … 1
0.05
Sockets
Direction
Name
Type
input*
In
in
points
outputprimary
out
points
Remap
remappolymorphic
Remap an input from [in_min, in_max] to [out_min, out_max]. Mode chooses between Scalar (CPU value) and Image (per-pixel shader) for the primary path. The Input Field socket + Field output are always available — wire a scalar_field in to get a remapped scalar_field out, inlined into the SDF shader.
space
out=in:input
gotcha
mode=scalar and mode=image are mutually exclusive on the primary socket; the Input Field input and Field aux output stay active regardless of mode.
gotcha
With nothing wired to Input Field, the field output falls back to wrapping the scalar input as a constant field (or 0 if neither is wired), never left empty.
gotcha
clamp only clamps the normalized t to 0..1 before scaling; off, values outside in_min..in_max extrapolate past out_min/out_max instead of holding.
gotcha
in_max minus in_min is floored at 1e-6, so equal in_min/in_max doesn't divide by zero but pins the result near out_max instead of erroring.
Parameters
Name
Type
Default
Mode
mode
enum
"scalar"
scalar · image
In min
in_min
scalar
-10 … 10
0
In max
in_max
scalar
-10 … 10
1
Out min
out_min
scalar
-10 … 10
0
Out max
out_max
scalar
-10 … 10
1
Clamp
clamp
boolean
true
Sockets
Direction
Name
Type
input*
Input
input
scalar
input
Input Field
input_field
scalar_field
outputprimary
out
scalar
outputaux
field
scalar_field
Sample & Hold
sample-holdpolymorphic
Latch a value on each rising edge of the trigger and hold it until the next one. Latch the Pointer's position on click, an audio level on a beat, a Random per press. Type retypes the value socket (scalar / vec2 / vec3 / vec4). Follow mode passes the input through until the first trigger; zero rests at 0.
space
out=in:value
flags
unstable
gotcha
Rising edge is trigger crossing 0.5 (lastTrigger<=0.5 && trig>0.5), a fixed threshold; an unwired trigger stays at 0 and never latches.
gotcha
Changing type mid-session pads or truncates the existing latch to the new arity instead of clearing it.
gotcha
initial=follow passes the wired value straight through until the first rising edge; initial=zero holds 0 until then.
gotcha
The latch is session-only node state that does not reset when the playhead loops back to time 0; only deleting the node clears it.
Parameters
Name
Type
Default
Type
type
enum
"scalar"
scalar · vec2 · vec3 · vec4
Before first trigger
initial
enum
"follow"
follow · zero
Sockets
Direction
Name
Type
input
value
value
scalar
input
trigger
trigger
scalar
outputprimary
out
scalar
Scene Time
scene-time
Emits the current playback time as a scalar in seconds or frames. Modes: linear, ping-pong (period in frames + amplitude + min/max, with an easing curve on each ramp), or stepped with easing. Connect to an exposed scalar input to drive animation.
reads
time
flags
unstable
gotcha
mode=pingpong ignores unit, scale, and offset entirely; period_frames is always frame-based and min/max/amplitude alone own the output range.
gotcha
unit=frames and pingpong both use the tick-derived fractional frame (tick/ticksPerFrame), not integer frame count, so motion stays smooth when the render loop outruns project fps.
gotcha
Integer frame count is used only as a fallback when ticksPerFrame<=0.
gotcha
mode=stepped floors base/step_size to an index and eases only the fractional remainder between steps: easing=step is a hard staircase, smoothstep glides mid-step and holds near boundaries.
gotcha
ease_intensity blends the eased curve against the raw linear ramp: 0=linear, 1=the exact named curve, >1 exaggerates it (overshoot/snap); shared by pingpong and stepped.
Terminal that rasterizes an SDF with two-light bevel shading. Outer / Inner / Emboss / Pillow styles. Each light has its own angle / elevation / opacity; highlight + shadow colors and blend modes are shared. Replaces SDF Rasterize when you want a 3D-button or relief look.
space
param:depth=canvas01 param:soften=pixels
gotcha
depth is a canvas-UV distance, the same coordinate space as every other SDF radius/thickness, not pixels; it is aspect-correct dependent like SDF Rasterize.
gotcha
soften is a pixel multiplier on the central-difference step used to derive the bevel's lighting normal; it softens the highlight/shadow edge without changing depth.
gotcha
This is a terminal that replaces SDF Rasterize — it renders the bevel shading itself, it does not feed into a separate Rasterize node downstream.
gotcha
Light 1 and Light 2 each get independent angle/elevation/highlight/shadow strength, but share one highlight color+blend mode and one shadow color+blend mode.
SDF primitive — a circle of radius r at (x, y). Wire `position` to feed a transformed coordinate space (Translate / Repeat / Mirror / etc.) — unwired defaults to canvas UV.
Builds an SDF tree only; nothing is drawn until SDF Rasterize (or To Mask / To Distance Image) evaluates it per pixel.
gotcha
Unwired position = canvas UV; wire a Translate/Repeat/Mirror position chain to change the space the disc is evaluated in.
gotcha
radius is width-relative only while SDF Rasterize aspect_correct is on; off, it becomes a per-axis UV fraction and the disc squashes on non-square canvases.
Parameters
Name
Type
Default
X
x
scalar
-1 … 2
0.5
Y
y
scalar
-1 … 2
0.5
Radius
radius
scalar
0 … 2
0.2
Paint
paint
boolean
false
Color
color
color
"#ffffff"
Sockets
Direction
Name
Type
input
Position
position
position
input
Center
center
vec2
input
Radius
radius
scalar
outputprimary
out
sdf
SDF Displace
sdf-displace
Modifier — perturb the distance field by sampling an image's red channel. Sampled value [0..1] remaps to [-Amount..+Amount] and adds to the distance. Wire a Noise output for wobbly edges; wire a mask for a hard cutout.
space
param:amount=canvas01
gotcha
Sampled at the canvas-UV position, not the shape's own (possibly transformed) position — displacement is a fixed screen-space perturbation regardless of upstream Position ops.
gotcha
Only the image's red channel is read; the [0..1] value remaps to [-amount..+amount] and adds straight onto the signed distance.
gotcha
With no field image wired, the SDF passes through unchanged rather than being blanked.
gotcha
A scalar wired to the `amount` socket overrides the amount param entirely, it is not added to it.
Parameters
Name
Type
Default
Amount
amount
scalar
-0.5 … 0.5
0.02
Sockets
Direction
Name
Type
input*
SDF
sdf
sdf
input*
Field
field
image
input
Amount
amount
scalar
outputprimary
out
sdf
SDF From Image
sdf-from-image
Convert an image into a signed distance field. Distance mode thresholds a channel and runs a jump-flooding distance transform (inside negative); Raw mode treats the image as an already-baked distance field (0.5 = edge). Output composes with Union / Morph / Round / Rasterize.
space
param:spread=pixels param:range=canvas01
gotcha
mode=distance thresholds the chosen channel then runs a jump-flooding transform (inside negative); spread is the half-range in pixels, at render resolution, the field ramps over before clamping.
gotcha
mode=raw skips the transform and reads the channel directly as an already-baked field (0.5 = boundary), scaled by range in canvas-UV distance units.
gotcha
The computed field is cached per node instance, recomputing only when the source image's identity or the mode/channel/threshold/spread params change; other slider drags hit the cache.
gotcha
The unwired `position` input defaults to canvas UV, like other SDF primitives' Position socket; wire a Translate/Scale/Rotate chain to sample the field somewhere else.
Parameters
Name
Type
Default
Mode
mode
enum
"distance"
distance · raw
Source
source
enum
"luminance"
luminance · alpha · red · green · blue
Threshold
threshold
scalar
0 … 1
0.5
Invert
invert
boolean
false
Spread (px)
spread
scalar
1 … 1024
128
Distance range
range
scalar
0.001 … 1
0.5
Paint
paint
boolean
false
Color
color
color
"#ffffff"
Sockets
Direction
Name
Type
input*
Image
image
image
input
Position
position
position
outputprimary
out
sdf
SDF Intersection
sdf-intersection
Boolean intersection of two SDFs (max). Result is inside only where both A and B are inside.
gotcha
Fixed two-input (a, b) — unlike SDF Union this does not auto-grow additional sockets.
gotcha
Leaving either input unwired treats it as the empty sentinel (distance ~1e10 everywhere), which blanks the whole intersection rather than passing the other input through.
Sockets
Direction
Name
Type
input
A
a
sdf
input
B
b
sdf
outputprimary
out
sdf
SDF Line Segment
sdf-line-segment
SDF primitive — a thick line (capsule) between (Ax, Ay) and (Bx, By) with the given thickness. Endpoints are rounded. Wire `position` to feed a transformed coordinate space.
Builds an SDF tree only; nothing is drawn until SDF Rasterize (or To Mask / To Distance Image) evaluates it per pixel.
gotcha
Unwired position = canvas UV; wire a Translate/Repeat/Mirror position chain to change the space the segment is evaluated in.
gotcha
thickness is width-relative only while SDF Rasterize aspect_correct is on; off, it becomes a per-axis UV fraction and the capsule squashes on non-square canvases.
Parameters
Name
Type
Default
Ax
ax
scalar
-1 … 2
0.25
Ay
ay
scalar
-1 … 2
0.5
Bx
bx
scalar
-1 … 2
0.75
By
by
scalar
-1 … 2
0.5
Thickness
thickness
scalar
0 … 1
0.04
Paint
paint
boolean
false
Color
color
color
"#ffffff"
Sockets
Direction
Name
Type
input
Position
position
position
input
A
a
vec2
input
B
b
vec2
input
Thickness
thickness
scalar
outputprimary
out
sdf
SDF Material
sdf-material
Paint an SDF subtree. Sets the color every shape below it renders with, unless a shape (or a nearer Material) paints itself. Distance is untouched. Constant mode takes a color (or a wired Color node); Ramp mode samples a gradient at a scalar field — wire SDF Repeat's Cell ID through a noise node to give every tile its own color.
gotcha
Materials inherit CSS-fill style: this paints every unpainted shape below it; a nearer Material node or a primitive's own Paint toggle wins for its own subtree.
gotcha
Distance is untouched, so inserting or removing this node anywhere in a chain never changes the shape, only color.
gotcha
color_mode=ramp with no field wired to `t` holds the ramp at a fixed midpoint (0.5) rather than falling back to the color param.
gotcha
Wiring a vec3/vec4 into the `color` socket overrides the color param entirely; a wired vec4's alpha is dropped since the material carries color only.
gotcha
Color blending across shapes only happens inside SDF Smooth Union, driven by that node's Smoothness; this node does not blend colors itself.
SDF position-pipeline op — reflect the sample position about X, Y, or both axes through the center.
space
in:center,param:center_x,param:center_y=canvas01
gotcha
Mirrors the SAMPLE position (inverse-domain fold), so downstream shapes appear reflected across the center rather than being flipped in place.
gotcha
Output type is `position`, meant to feed a shape's Position socket or chain into another position op (e.g. Polar) — wiring it directly as an SDF or mask does nothing.
gotcha
axis=both folds across X and Y simultaneously in one step, not as two independently weighted reflections.
Parameters
Name
Type
Default
Axis
axis
enum
"x"
x · y · both
Center X
center_x
scalar
-1 … 2
0.5
Center Y
center_y
scalar
-1 … 2
0.5
Sockets
Direction
Name
Type
input
Position
position
position
input
Center
center
vec2
outputprimary
out
position
SDF Morph
sdf-morph
Morph between two SDFs by interpolating their distance fields (mix). Amount 0 = A, 1 = B; topology can change mid-morph. Keyframe or wire Amount to animate.
gotcha
amount is clamped to [0,1]; a scalar wired to the socket overrides the amount param entirely rather than combining with it.
gotcha
Leaving one side unwired degrades to a straight passthrough of the other shape rather than blending toward the empty sentinel's huge distance.
gotcha
Topology can change mid-morph (a disc splitting in two, a square sprouting points) since it interpolates the distance FIELD, not the boundary geometry.
Parameters
Name
Type
Default
Amount
amount
scalar
0 … 1
0.5
Sockets
Direction
Name
Type
input
A
a
sdf
input
B
b
sdf
input
Amount
amount
scalar
outputprimary
out
sdf
SDF Onion
sdf-onion
Modifier — turn the SDF into a hollow shell of the given thickness. Stack multiple Onions for concentric rings.
space
in:thickness,param:thickness=canvas01
gotcha
thickness is a canvas-UV distance, like the underlying SDF; whether it reads as width-relative pixels depends on SDF Rasterize's aspect_correct setting.
gotcha
A wired thickness scalar overrides the thickness param entirely, it is not combined with it.
gotcha
thickness is clamped to >= 0 (Math.max(0, t)); unlike SDF Round's radius, a negative value cannot be used to shrink anything here.
Parameters
Name
Type
Default
Thickness
thickness
scalar
0 … 0.5
0.01
Sockets
Direction
Name
Type
input*
SDF
sdf
sdf
input
Thickness
thickness
scalar
outputprimary
out
sdf
SDF Polar
sdf-polar
SDF position-pipeline op — fold the sample position into N rotational sectors around the center. Compose with Mirror for kaleidoscope symmetry.
space
in:center,param:center_x,param:center_y=canvas01
gotcha
Folds the sample position into `segments` sectors of 2*pi/segments around center, so downstream shapes are replicated radially rather than duplicated as separate graph copies.
gotcha
rotation is in radians, not degrees, and spins where the sector boundaries fall (effectively rotating the whole kaleidoscope pattern).
gotcha
Output type is `position`, meant to feed a shape's Position socket or chain into another position op (e.g. Mirror) — wiring it directly as an SDF or mask does nothing.
Parameters
Name
Type
Default
Segments
segments
scalar
1 … 64
6
Center X
center_x
scalar
-1 … 2
0.5
Center Y
center_y
scalar
-1 … 2
0.5
Rotation (rad)
rotation
scalar
-3.141592653589793 … 3.141592653589793
0
Sockets
Direction
Name
Type
input
Position
position
position
input
Center
center
vec2
outputprimary
out
position
SDF Polygon
sdf-polygon
SDF primitive — a regular N-gon. Sides 3 = triangle, 4 = square, 5 = pentagon, 6 = hexagon… Wire a scalar field into Sides Field for per-pixel / per-tile variation in side count (set Quantize Sides on for clean integer counts; pair with SDF Repeat.cell_id → Noise for per-tile randomness).
Builds an SDF tree only; nothing is drawn until SDF Rasterize (or To Mask / To Distance Image) evaluates it per pixel.
gotcha
Unwired position = canvas UV; wire a Translate/Repeat/Mirror position chain to change the space the polygon is evaluated in.
gotcha
radius is width-relative only while SDF Rasterize aspect_correct is on; off, it becomes a per-axis UV fraction and the polygon squashes on non-square canvases.
gotcha
Wiring sides_field overrides the sides param entirely; quantize_sides then rounds each pixel's field value to the nearest integer >=3, otherwise the shape interpolates smoothly between side counts.
Parameters
Name
Type
Default
X
x
scalar
-1 … 2
0.5
Y
y
scalar
-1 … 2
0.5
Radius
radius
scalar
0 … 2
0.25
Sides
sides
scalar
3 … 24
6
Quantize Sides
quantize_sides
boolean
true
Paint
paint
boolean
false
Color
color
color
"#ffffff"
Sockets
Direction
Name
Type
input
Position
position
position
input
Center
center
vec2
input
Radius
radius
scalar
input
Sides Field
sides_field
scalar_field
outputprimary
out
sdf
SDF Rasterize
sdf-rasterize
Sample an SDF at every pixel and produce an image. Foreground / Background colors fill inside / outside; Contour adds an outline at the zero-crossing. One shader compile + one draw call total per topology.
space
param:contour_width,param:softness=pixels
gotcha
softness and contour_width are pixel counts at render resolution, not canvas01 — both scale by 1/max(width, height) internally.
gotcha
aspect_correct rescales the SDF's own sample coordinate (not the output raster) so a circle stays circular on non-square canvases; upstream primitives' radii rely on this same correction.
gotcha
The shader is cached by the tree's structural hash: changing any param (radius, position, colors) only rebinds uniforms, while changing the graph topology triggers a recompile.
gotcha
contour_alpha defaults to 0, so setting contour_width alone draws nothing until contour_alpha is raised above 0.
Parameters
Name
Type
Default
Foreground
foreground
color
"#ffffff"
FG Alpha
fg_alpha
scalar
0 … 1
1
Background
background
color
"#000000"
BG Alpha
bg_alpha
scalar
0 … 1
1
Contour
contour
color
"#000000"
Contour Alpha
contour_alpha
scalar
0 … 1
0
Contour Width (px)
contour_width
scalar
0 … 32
0
Softness (px)
softness
scalar
0 … 16
1
Aspect Correct
aspect_correct
boolean
true
Sockets
Direction
Name
Type
input*
SDF
sdf
sdf
outputprimary
out
image
SDF Rectangle
sdf-rectangle
SDF primitive — a rectangle (with optional rounded corners) centered at (x, y) with the given width × height. Wire `position` to feed a transformed coordinate space.
Builds an SDF tree only; nothing is drawn until SDF Rasterize (or To Mask / To Distance Image) evaluates it per pixel.
gotcha
Unwired position = canvas UV; wire a Translate/Repeat/Mirror position chain to change the space the rectangle is evaluated in.
gotcha
width/height are full extents but halved internally (sx=width/2, sy=height/2); corner_radius is clamped to never exceed half the smaller dimension.
gotcha
width/height are width-relative only while SDF Rasterize aspect_correct is on; off, they become per-axis UV fractions and the rectangle squashes on non-square canvases.
gotcha
Wiring `size` overrides width and height together; there is no socket to override just one of them.
Parameters
Name
Type
Default
X
x
scalar
-1 … 2
0.5
Y
y
scalar
-1 … 2
0.5
Width
width
scalar
0 … 2
0.4
Height
height
scalar
0 … 2
0.4
Corner Radius
corner_radius
scalar
0 … 1
0
Paint
paint
boolean
false
Color
color
color
"#ffffff"
Sockets
Direction
Name
Type
input
Position
position
position
input
Center
center
vec2
input
Size
size
vec2
outputprimary
out
sdf
SDF Repeat
sdf-repeat
SDF position-pipeline op — tile the sample position. Infinite by default; toggle Bounded for a finite tile count. Use the Jitter params for per-cell pseudo-random rotation / position / scale (each tile varies independently — what wiring an upstream Noise scalar into SDF Rotate cannot give you).
Emits a position value only; nothing changes until it feeds a shape's position input or a scalar field's position downstream.
gotcha
bounded=false tiles infinitely; bounded=true clamps the cell index to +/-limit_x/limit_y so tiling stops past that many cells from center.
gotcha
rotation/position/scale jitter hash each cell's seeded integer ID so every tile varies independently, unlike wiring a Noise scalar into a downstream Rotate (same angle everywhere).
gotcha
aux cell_id is the per-pixel integer cell ID (vec2), constant within a tile; wire it into SDF Noise's position for per-tile modulation.
Parameters
Name
Type
Default
Spacing X
spacing_x
scalar
0.001 … 2
0.25
Spacing Y
spacing_y
scalar
0.001 … 2
0.25
Center X
center_x
scalar
-1 … 2
0.5
Center Y
center_y
scalar
-1 … 2
0.5
Bounded
bounded
boolean
false
Tiles X (±)
limit_x
scalar
0 … 32
3
Tiles Y (±)
limit_y
scalar
0 … 32
3
Rotation Jitter (rad)
rotation_jitter
scalar
0 … 3.141592653589793
0
Position Jitter X
position_jitter_x
scalar
0 … 0.5
0
Position Jitter Y
position_jitter_y
scalar
0 … 0.5
0
Scale Jitter
scale_jitter
scalar
0 … 1
0
Seed
seed
scalar
0 … 1000
0
Sockets
Direction
Name
Type
input
Position
position
position
input
Spacing
spacing
vec2
input
Center
center
vec2
outputprimary
out
position
outputaux
cell_id
position
SDF Rotate
sdf-rotate
SDF position-pipeline op — rotate the per-pixel sample position around a pivot. Wire a scalar field into Angle for per-pixel rotation (per-tile when paired with SDF Repeat.cell_id → SDF Noise).
space
in:position,in:pivot,param:cx,param:cy=canvas01
gotcha
The wired angle scalar is radians while the rotation param is degrees; swapping between wiring and the param without conversion changes the amount.
gotcha
Precedence when multiple angle sources are present: angle_field (scalar_field) beats angle (scalar) beats the rotation param.
gotcha
Wire a scalar_field into angle_field for per-pixel rotation; pair SDF Repeat's cell_id aux into SDF Noise's position for independent per-tile spin.
gotcha
Emits a position value only; nothing visibly changes until a downstream shape or field consumes this position.
Parameters
Name
Type
Default
Angle (°)
rotation
scalar
-360 … 360
0
Pivot X
cx
scalar
-1 … 2
0.5
Pivot Y
cy
scalar
-1 … 2
0.5
Sockets
Direction
Name
Type
input
Position
position
position
input
Angle (rad)
angle
scalar
input
Angle Field
angle_field
scalar_field
input
Pivot
pivot
vec2
outputprimary
out
position
SDF Round
sdf-round
Inflate the boundary of an SDF by `radius`. Sharp corners become rounded; the entire shape grows by radius. Negative radius shrinks it.
space
in:radius,param:radius=canvas01
gotcha
radius is a canvas-UV distance, like the underlying SDF; whether it reads as width-relative pixels depends on SDF Rasterize's aspect_correct setting.
gotcha
A wired radius scalar overrides the radius param entirely, it is not combined with it.
gotcha
radius is unclamped (can go negative to shrink); unlike SDF Onion's thickness, there is no floor at zero.
Parameters
Name
Type
Default
Radius
radius
scalar
-1 … 1
0.02
Sockets
Direction
Name
Type
input*
SDF
sdf
sdf
input
Radius
radius
scalar
outputprimary
out
sdf
SDF Scale
sdf-scale
SDF position-pipeline op — scale the per-pixel sample position around a pivot. The exposed scale matches the visible effect on downstream shapes.
space
in:position,param:cx,param:cy=canvas01
gotcha
sx/sy is the visible scale of downstream shapes (2 makes them appear twice as big); internally the sample position is divided by scale, so the exposed value is already the intuitive direction.
gotcha
Pivot (cx/cy) is param-only on this node, unlike SDF Rotate which also accepts a wired pivot vec2.
gotcha
Emits a position value only; nothing visibly changes until a downstream shape or field consumes this position.
Parameters
Name
Type
Default
Scale X
sx
scalar
0.01 … 10
1
Scale Y
sy
scalar
0.01 … 10
1
Pivot X
cx
scalar
-1 … 2
0.5
Pivot Y
cy
scalar
-1 … 2
0.5
Sockets
Direction
Name
Type
input
Position
position
position
input
Scale
scale
vec2
outputprimary
out
position
SDF Shade
sdf-shade
Shading terminal for SDFs: fill, color bleed, relief lighting, glow and contours composited in one pass. Per-shape colors come from SDF Material / a primitive's Paint swatch; Fill Color is the fallback for unpainted shapes. Aux outputs expose the normal, height, glow and bleed layers for re-compositing.
softness, soften, and contour_width are pixels at render resolution (scaled by 1/max(width,height)).
gotcha
depth, glow_radius, bleed_radius, and contour_spacing are canvas-UV distances compared directly against the signed distance, independent of resolution.
gotcha
aspect_correct governs how this terminal itself samples the tree, separate from any upstream Rasterize; off, the canvas-UV distances scale per-axis and distort on non-square canvases.
gotcha
Aux normal/height/glow/bleed/mask each cost one extra full-screen draw and only render when that socket is actually wired or viewed.
gotcha
height_mode=curve samples height_curve through a 256-entry LUT rebuilt only when the curve points change; the other four height modes ignore height_curve entirely.
Smooth intersection of two SDFs. Smoothness rounds the corners where boundaries meet — same as Smooth Union, but for intersection (max).
space
in:smoothness,param:smoothness=canvas01
gotcha
smoothness is a canvas-UV distance compared directly against the signed distance (same units as a shape's radius); 0 degenerates to a plain max intersection.
gotcha
An unwired A or B is treated as the empty sentinel (distance 1e10), so the smooth max collapses to 1e10 too: the result is empty, not a passthrough of the wired side.
Parameters
Name
Type
Default
Smoothness
smoothness
scalar
0 … 0.5
0.05
Sockets
Direction
Name
Type
input
A
a
sdf
input
B
b
sdf
input
Smoothness
smoothness
scalar
outputprimary
out
sdf
SDF Smooth Subtraction
sdf-smooth-subtraction
Smooth subtraction (A − B) with a rounded cut. Smoothness blends the boundary where B carves into A — at 0 it degenerates to plain Subtraction.
space
in:smoothness,param:smoothness=canvas01
gotcha
smoothness is a canvas-UV distance compared directly against the signed distance (same units as a shape's radius); 0 degenerates to plain Subtraction.
gotcha
An unwired A (base) is the empty sentinel, so the result is empty; an unwired B (cut) leaves A unchanged, since subtracting nothing does nothing.
Parameters
Name
Type
Default
Smoothness
smoothness
scalar
0 … 0.5
0.05
Sockets
Direction
Name
Type
input
A (base)
a
sdf
input
B (cut)
b
sdf
input
Smoothness
smoothness
scalar
outputprimary
out
sdf
SDF Smooth Union
sdf-smooth-unionpolymorphic
Smooth (blob) union of any number of SDFs. Smoothness sets the blend width — when boundaries come within Smoothness of each other they merge into a curved metaball-style join. Inputs auto-grow: wire the empty socket and another appears.
space
in:smoothness,param:smoothness=canvas01
gotcha
smoothness is a canvas-UV distance compared directly against the signed distance (same units as a shape's radius); 0 degenerates to a plain min union.
gotcha
N-ary via auto-growing sockets (a, b, ... always one spare); the fold is left-to-right in socket order since smin is not associative.
gotcha
Unwired slots are dropped rather than treated as the empty sentinel, so extra unused sockets add nothing to the emitted tree.
gotcha
When shapes carry SDF Material colours, each smin fold blends colour by the same factor it blends distance, so the colour boundary tracks the geometric blend.
Parameters
Name
Type
Default
Smoothness
smoothness
scalar
0 … 0.5
0.05
Sockets
Direction
Name
Type
input
A
a
sdf
input
B
b
sdf
input
Smoothness
smoothness
scalar
outputprimary
out
sdf
SDF Spline
sdf-spline
SDF primitive — signed distance to a spline (flattened to line segments on CPU, looped per-pixel in the SDF shader). Closed splines compose like polygons (use Round / Smooth Union / etc.); open splines act as strokes (unsigned distance — wrap with Round to expand into a fill). Cap is 1024 segments; lower Subdivisions if you have many anchors.
space
in:position=canvas01
gotcha
Unwired position defaults to canvas UV, as on other SDF primitives; wire a Translate/Rotate/Repeat chain to route it.
gotcha
force_open forces the unsigned stroke distance path even when the input spline is geometrically closed.
gotcha
The flattened segment texture is cached per node and re-uploaded only when the spline's geometry hash or subdivisions changes; other param/input changes reuse it.
Parameters
Name
Type
Default
Subdivisions / curve
subdivisions
scalar
1 … 64
16
Force Open (stroke)
force_open
boolean
false
Paint
paint
boolean
false
Color
color
color
"#ffffff"
Sockets
Direction
Name
Type
input*
Spline
spline
spline
input
Position
position
position
outputprimary
out
sdf
SDF Star
sdf-star
SDF primitive — an N-pointed star. Sharpness 2 = sharpest spike, equal-to-points = regular polygon. 3 ≤ Points ≤ 24. Wire `position` to feed a transformed coordinate space.
Builds an SDF tree only; nothing is drawn until a terminal (Rasterize / Shade / To Mask / To Distance Image) evaluates it per pixel.
gotcha
Unwired position = canvas UV; wire a Translate/Repeat/Mirror position chain to change the space the star is evaluated in.
gotcha
radius is width-relative only while the consuming terminal's aspect_correct is on; off, it becomes a per-axis UV fraction and the star squashes on non-square canvases.
gotcha
sharpness is clamped to [2, points] at compute time, so raising it past points has no further effect beyond a regular polygon.
Parameters
Name
Type
Default
X
x
scalar
-1 … 2
0.5
Y
y
scalar
-1 … 2
0.5
Radius
radius
scalar
0 … 2
0.25
Points
points
scalar
3 … 24
5
Sharpness
sharpness
scalar
2 … 24
2.5
Paint
paint
boolean
false
Color
color
color
"#ffffff"
Sockets
Direction
Name
Type
input
Position
position
position
input
Center
center
vec2
input
Radius
radius
scalar
outputprimary
out
sdf
SDF Subtraction
sdf-subtraction
Boolean subtraction (A − B). Result is inside A but outside B — useful for cutting holes.
gotcha
Computed as max(a, -b): an unwired A (base) is the empty sentinel, so the result is empty; an unwired B (cut) leaves A unchanged.
gotcha
When shapes carry SDF Material colours, B (the cutter) never contributes colour or bleed weight; only A's colour and wash survive the cut.
Sockets
Direction
Name
Type
input
A (base)
a
sdf
input
B (cut)
b
sdf
outputprimary
out
sdf
SDF to Distance Image
sdf-to-distance-image
Render an SDF as a grayscale distance visualization. Range sets how much of the field spans the full ramp — smaller values reveal fine detail near the boundary. Negative / Zero / Positive colors customize the ramp.
space
param:range=canvas01
gotcha
range is a canvas-UV distance (same units as a shape's radius), not pixels; it does not scale with output resolution.
gotcha
aspect_correct here is this node's own uniform governing how it samples the tree, independent of any aspect_correct on an upstream Rasterize.
gotcha
An unwired or non-SDF input yields a fully transparent image, not the neg_color/zero_color/pos_color ramp.
Parameters
Name
Type
Default
Range
range
scalar
0.001 … 2
0.5
Inside Color
neg_color
color
"#000000"
Zero Color
zero_color
color
"#808080"
Outside Color
pos_color
color
"#ffffff"
Alpha
alpha
scalar
0 … 1
1
Aspect Correct
aspect_correct
boolean
true
Sockets
Direction
Name
Type
input*
SDF
sdf
sdf
outputprimary
out
image
SDF to Mask
sdf-to-mask
Render an SDF as a binary mask at the chosen iso-level (default 0 = the boundary). Softness feathers the edge in pixels. Invert flips inside ↔ outside. Output is an image suitable for any mask/image consumer.
space
param:threshold=canvas01 param:softness=pixels
gotcha
threshold is a canvas-UV distance (same units as a shape's radius); positive values shrink the mask inward, negative values inflate it outward, without touching the SDF tree itself.
gotcha
softness is pixels at render resolution, a different unit family from threshold, and does not scale with output size.
gotcha
aspect_correct here is this node's own uniform governing how it samples the tree, independent of any aspect_correct on an upstream Rasterize.
gotcha
An unwired or non-SDF input yields a fully transparent image rather than a solid mask.
Parameters
Name
Type
Default
Threshold
threshold
scalar
-1 … 1
0
Softness (px)
softness
scalar
0 … 32
1
Invert
invert
boolean
false
Aspect Correct
aspect_correct
boolean
true
Sockets
Direction
Name
Type
input*
SDF
sdf
sdf
outputprimary
out
image
SDF to Spline
sdf-to-spline
Extract the iso-line of an SDF as a spline (closed where loops form, open where chains run off the grid). Resolution sets the marching-squares grid size — 256 is a good default; raise it for smoother curves at the cost of a bigger CPU readback. Async Readback trades a one-frame contour lag during playback for eliminating the sync GPU readback stall (the whole cost of this node in GPU-heavy graphs); exports are frame-exact either way.
space
param:iso=canvas01
flags
unstable
gotcha
aspect_correct has no visible effect here: the readback target is always resolution x resolution (square), so its aspect ratio is always 1 regardless of the toggle.
gotcha
iso direction: negative values trace concentric loops inside the shape, positive values trace a puffed-out boundary outside it; 0 (default) is the exact SDF zero-crossing.
gotcha
async_readback lags the output spline by one frame during playback (paused steady state is exact); exports and the first eval after a cold start always take the exact sync path.
Parameters
Name
Type
Default
Iso Level
iso
scalar
-1 … 1
0
Resolution
resolution
scalar
32 … 1024
256
Aspect Correct
aspect_correct
boolean
true
Async Readback (1-frame lag)
async_readback
boolean
false
Sockets
Direction
Name
Type
input*
SDF
sdf
sdf
outputprimary
out
spline
SDF Translate
sdf-translate
SDF position-pipeline op — translate the per-pixel sample position. Feeds into a shape's `position` input. Default upstream position is canvas UV.
space
in:position,in:offset,param:tx,param:ty=canvas01
gotcha
Internally the sample position is shifted by -offset so the visible shape moves by +offset (tx, ty), the intuitive direction.
gotcha
Emits a position value only; nothing visibly changes until a downstream shape or field consumes this position.
Parameters
Name
Type
Default
Offset X
tx
scalar
-2 … 2
0
Offset Y
ty
scalar
-2 … 2
0
Sockets
Direction
Name
Type
input
Position
position
position
input
Offset
offset
vec2
outputprimary
out
position
SDF Triangle
sdf-triangle
SDF primitive — a triangle through three corners (A, B, C). For a regular triangle, prefer SDF Polygon with sides=3. Wire `position` to feed a transformed coordinate space.
Builds an SDF tree only; nothing is drawn until a terminal (Rasterize / Shade / To Mask / To Distance Image) evaluates it per pixel.
gotcha
Unwired position = canvas UV; wire a Translate/Repeat/Mirror position chain to change the space the triangle is evaluated in.
gotcha
Vertex coordinates are width-relative only while the consuming terminal's aspect_correct is on; off, they become per-axis UV fractions and the triangle skews on non-square canvases.
Parameters
Name
Type
Default
Ax
ax
scalar
-1 … 2
0.5
Ay
ay
scalar
-1 … 2
0.25
Bx
bx
scalar
-1 … 2
0.25
By
by
scalar
-1 … 2
0.75
Cx
cx
scalar
-1 … 2
0.75
Cy
cy
scalar
-1 … 2
0.75
Paint
paint
boolean
false
Color
color
color
"#ffffff"
Sockets
Direction
Name
Type
input
Position
position
position
input
A
a
vec2
input
B
b
vec2
input
C
c
vec2
outputprimary
out
sdf
SDF Twist
sdf-twist
SDF position-pipeline op — spiral the sample position around the center by Strength radians per unit distance. Strength accepts either a scalar (uniform per draw) or a scalar field (per-pixel; pair with SDF Repeat.cell_id → SDF Noise for per-tile variation). Large values violate the unit-gradient SDF property; a thin Rasterize contour line hides the resulting aliasing.
strength is radians of twist per unit distance from center, growing unbounded with radius; large values break the SDF's unit-gradient property and alias the Rasterize edge.
gotcha
Precedence when multiple strength sources are wired: strength_field (scalar_field) beats strength (scalar) beats the strength param.
gotcha
Emits a position value only; nothing visibly changes until a downstream shape or field consumes this position.
Parameters
Name
Type
Default
Center X
center_x
scalar
-1 … 2
0.5
Center Y
center_y
scalar
-1 … 2
0.5
Strength
strength
scalar
-50 … 50
3
Sockets
Direction
Name
Type
input
Position
position
position
input
Center
center
vec2
input
Strength
strength
scalar
input
Strength Field
strength_field
scalar_field
outputprimary
out
position
SDF Union
sdf-unionpolymorphic
Boolean union of any number of SDFs (min). Result is inside if any input is inside. Inputs auto-grow: wire the empty socket and another appears. For a blended boundary use SDF Smooth Union.
gotcha
N-ary via auto-growing sockets (a, b, ... always one spare); wiring the spare socket adds another.
gotcha
Unwired slots are dropped rather than folded in as the empty sentinel, so extra unused sockets add nothing to the emitted tree.
Sockets
Direction
Name
Type
input
A
a
sdf
input
B
b
sdf
outputprimary
out
sdf
Select by Index
group-pickpolymorphic
Filter to one index of a group. For images, indexes into an image_group's array. For splines and points, keeps only subpaths / points whose groupIndex matches the chosen index — Group's output uses socket-order tags (a=0, b=1, c=2…). Index clamps to valid range.
space
out=in:group
reads
attr:group
gotcha
index clamps against the count of DISTINCT sorted groupIndex values, not the raw index range — e.g. groups [0,5,9] with index=1 picks group 5.
gotcha
Untagged subpaths/points are treated as groupIndex 0, so index=0 on an un-grouped input returns everything unchanged.
gotcha
groupIndex is stripped from the output — the picked subset is a plain single-group value downstream, no longer group-tagged.
gotcha
Switching Type (mode) changes the accepted input socket type and the output type (image_group/image, spline, or points), disconnecting mismatched wires.
Parameters
Name
Type
Default
Type
mode
enum
"image"
image · spline · points
Index
index
scalar
0 … 100
0
Sockets
Direction
Name
Type
input*
Collection
group
image_group
input
index
index
scalar
outputprimary
out
image
Smooth
smooth
Exponential smoothing filter on a scalar. Time is the smoothing time-constant (seconds) — larger values produce heavier damping. Useful for de-jittering tracker outputs (hand, object) or audio levels.
flags
simulation, unstable
gotcha
alpha = 1 − exp(−dt/time) where dt is the wall-clock ctx.time delta, not a frame count, so retiming or a frame-rate change doesn't change the smoothing time constant.
gotcha
reset=true (or the very first evaluation) snaps the output straight to the target, skipping the filter for that evaluation.
gotcha
If the scene is paused (dt=0) or time is scrubbed backward, alpha collapses to 0 and the output holds rather than extrapolating.
gotcha
The `value` input, when wired, overrides the `value` param entirely as the smoothing target.
Parameters
Name
Type
Default
Value
value
scalar
-1000 … 1000
0
Smoothing time (s)
time
scalar
0 … 10
0.25
Snap to input
reset
boolean
false
Sockets
Direction
Name
Type
input
Value
value
scalar
outputprimary
out
scalar
Split Vec2
split-vec2
Pull the x and y components out of a vec2 as scalars. Primary = x, aux = y.
gotcha
An unwired input, or one wired to a non-vec2 value, outputs 0 for both x and y rather than erroring.
Sockets
Direction
Name
Type
input*
in
in
vec2
outputprimary
out
scalar
outputaux
y
scalar
String
string-literal
Emits a single text value. Wire it into an exposed string param (e.g. a Text node's text) to drive that text, or share one string across several nodes.
flags
no-mask
Parameters
Name
Type
Default
Text
value
string
""
Sockets
Direction
Name
Type
outputprimary
out
string
Switch
switchpolymorphic
Picks one of N inputs by index. Accepts any socket type: leave Type on "auto" and the node adopts whatever you wire in — mixed inputs coerce to the one type they share (a scalar beside a vec4 becomes vec4; a mask beside an image becomes image). Inputs auto-grow — there's always one spare empty socket. Wire a scalar to Index for live switching.
space
out=in:*
gotcha
type=auto adopts whatever is wired into the numbered in0, in1, … slots; only those vote (index and mask never retype the node), topmost wire wins ties.
gotcha
Inputs auto-grow: connected numbered slots stay in order plus one trailing spare; disconnecting a middle slot drops it and later indices shift.
gotcha
The picked value passes through untouched and borrowed (ownsTextures: false) — the node never releases the upstream texture itself.
gotcha
index is rounded and clamped into [0, slotCount-1]; an unwired index slot falls back to the index param, and an empty slot at the picked index outputs nothing.
gotcha
render and vector socket types are excluded from the switchable type list.
Parameters
Name
Type
Default
Type
type
enum
"auto"
auto · scalar · vec2 · vec3 · vec4 · image · mask · uv · spline · points · string · element · image_group · text_instance · audio · sdf · position · scalar_field · object3d · camera · force · emitter · collider · particles · transform
Index
index
scalar
0 … 255
0
Sockets
Direction
Name
Type
input
Index
index
scalar
input
Input 0
in0
scalar
input
Input 1
in1
scalar
outputprimary
out
scalar
Time Offset
time-offsetpolymorphic
Shifts everything upstream in time: the branch wired into it re-evaluates at the playhead minus Offset (in frames), so its keyframes, clips, and procedural animation play later — or earlier with a negative offset. Wire or keyframe Offset for time-warping. Live and simulated nodes upstream (video, webcam, audio, cursor, sims) can't time-travel and pass through un-shifted.
space
out=in:in
flags
no-mask
gotcha
offset is in frames, not seconds; positive samples the past (After Effects convention), negative looks ahead and pure upstream keyframes clamp at their ends.
gotcha
Chaining a Time Offset through another Time Offset throws at compute; sum both offsets into one node instead.
gotcha
Carries only scalar/vec2/vec3/vec4/string/spline/points/points3d/image/mask/uv/notes/color_ramp/transform; audio, particles, sdf, 3D geometry, and lists cannot be wired through it.
gotcha
Upstream simulation, live (video/webcam/audio/cursor/trackers), Iterate, or another Time Offset closure can't be retimed and passes through un-shifted instead.
gotcha
The offset param itself is sampled on the outer (un-shifted) clock, so keyframing or wiring it drives time-warping rather than being retimed itself.
Parameters
Name
Type
Default
Offset (frames)
offset
scalar
-10000 … 10000
0
Sockets
Direction
Name
Type
input
In
in
scalar
outputprimary
out
scalar
Transform
transformpolymorphic
Scale, rotate, and translate the input around a pivot. Works on images, splines, or points. Wire a Gizmo into Transform to drive the same placement from a shared on-canvas control (that replaces this node's own TRS). `space=local` (Source, the default) is a fraction of the incoming shape's bounds so scale/rotate stay about the shape when you move it; `space=global` (Canvas) pins the pivot to a fixed frame point. Image mode can Tile the source past its edges (AE RepeTile) with per-side extent and Unfold. For SDFs use the Position-pipeline operators (Position Translate / Scale / Rotate) — they compose with Position Repeat / Mirror / Polar for tile-local transforms.
Behavior follows the connected input's type (image/spline/points), not a mode param; the legacy `mode` param is hidden and no longer read.
gotcha
Wiring a `transform` socket (e.g. from a Gizmo) replaces this node's own TRS params entirely, using inverse-affine math on images or direct math on spline/points.
gotcha
space=local (default) makes pivotX/Y a fraction of the incoming shape's bbox so scale/rotate track it; space=global pins the pivot to a fixed canvas point; images always act as global.
gotcha
tile (image-only) wraps sampling past the edges by tileLeft/Right/Up/Down source-widths, with tileUnfold mirroring odd copies edge-to-edge.
gotcha
On points, rotation and scale compose with the point's existing rotation (additive) and scale (multiplicative) rather than replacing them.
Parameters
Name
Type
Default
Translate X
translateX
scalar
-1 … 1
0
Translate Y
translateY
scalar
-1 … 1
0
Scale X
scaleX
scalar
0.01 … 10
1
Scale Y
scaleY
scalar
0.01 … 10
1
Rotate (°)
rotate
scalar
-360 … 360
0
Pivot X
pivotX
scalar
0 … 1
0.5
Pivot Y
pivotY
scalar
0 … 1
0.5
Pivot from
space
enum
"local"
Canvas · Source
Tile
tile
boolean
false
Left
tileLeft
scalar
0 … 16
1
Right
tileRight
scalar
0 … 16
1
Up
tileUp
scalar
0 … 16
1
Down
tileDown
scalar
0 … 16
1
Unfold
tileUnfold
boolean
false
Sockets
Direction
Name
Type
input*
Image
image
image
input
Transform
transform
transform
outputprimary
out
image
Trigger Envelope
trigger-envelope
Rising edge in, attack / hold / release envelope out (0→1→0 scalar). Stretches a one-frame pulse — a Pointer click, an audio beat, a Compare crossing — into usable motion. Wall clock responds while paused; timeline clock makes deterministic triggers export-exact. Retrigger restarts or ignores edges mid-envelope.
reads
time
flags
unstable
gotcha
clock=wall (default) uses performance.now(), so the envelope keeps animating while the timeline is paused; clock=timeline uses scene time and only moves with playback/export.
gotcha
A rising edge is the trigger crossing from <=0.5 to >0.5; retrigger=restart resets the envelope on each edge, retrigger=ignore drops edges while still active.
gotcha
Switching the clock param mid-envelope kills the running envelope (resets to idle) instead of comparing a wall-clock start time against scene time.
Emits a single vec2 value. Use to feed exposed vec2 inputs without routing through Combine Vec2.
Parameters
Name
Type
Default
X
x
scalar
-1000 … 1000
0
Y
y
scalar
-1000 … 1000
0
Sockets
Direction
Name
Type
outputprimary
out
vec2
Vec3
vec3-literal
Emits a single vec3 value.
Parameters
Name
Type
Default
X
x
scalar
-1000 … 1000
0
Y
y
scalar
-1000 … 1000
0
Z
z
scalar
-1000 … 1000
0
Sockets
Direction
Name
Type
outputprimary
out
vec3
Wedge
wedgepolymorphic
Batch-render variation source. Defines a set of values — scalar (explicit list, range, seeded random, or the bare iteration index), color, vec2, or string — and emits one per render when the export runs a wedge batch: wire it into a seed, a Switch index, a fill color, a Text string, or any exposed param. Outside a batch it emits the value at Preview, so scrubbing Preview auditions variations live. Multiple Wedge nodes zip: the batch runs max(counts) iterations and shorter wedges hold their last value.
space
out=unitless
flags
no-mask
gotcha
mode (range/random/index) only applies when type=scalar; every other type always uses the explicit values list regardless of mode.
gotcha
enabled=false reports count=1 to the batch driver and always emits the Preview value — a way to render just one variation without unwiring the node.
gotcha
mode=random's sequence is a deterministic hash of (seed, index), so the same seed reproduces the same variation set across sessions and machines.