Point clouds. Sources generate position sets; modifiers transform them; `copy-to-points` lets you instance any type per point.
Generators
Cursor Trail Points
cursor-trail-points
Drop points along the pointer's path while drawing on the preview — evenly spaced with seeded radial scatter. Feed Loop Weave for the live loop-de-loop demo, or any points consumer. Press mode draws while the mouse button is held; hover drops wherever the pointer moves.
emit=press needs CursorState.pressed, tracked only by the editor and the live viewer; a context without it never reads as pressed, so use emit=hover there.
gotcha
lifetime (seconds) expires drops against wall-clock performance.now(), not scene time, so a decaying trail does not replay identically across renders of the same timeline.
gotcha
clear_on_loop (default on) wipes the whole trail when ctx.time jumps backward past the last eval, i.e. on a timeline loop.
gotcha
overflow=stop halts new drops once max_points is reached; overflow=ring instead evicts the oldest drop to keep accepting new ones.
gotcha
The group attribute holds each drop's monotonic id (its stable scatter-seed identity), not a semantic grouping value.
gotcha
Radial scatter is hashed on each drop's id, so re-evaluating never reshuffles an already-placed point's jitter.
Parameters
Name
Type
Default
Emit
emit
enum
"press"
press · hover
Spacing
spacing
scalar
0.005 … 0.5
0.04
Scatter
scatter
scalar
0 … 0.25
0.02
Seed
seed
scalar
0 … 9999
0
Max points
max_points
scalar
2 … 2000
200
Overflow
overflow
enum
"stop"
stop · ring
Lifetime (s)
lifetime
scalar
0 … 60
0
Clear on loop
clear_on_loop
boolean
true
Sockets
Direction
Name
Type
outputprimary
out
points
Grid
grid
Emit an X×Y grid of points. Fit mode spreads the counts across a fixed width/height; Step mode uses an explicit gap between points so the grid grows with the counts. Stamps ix/iy lattice coords so Points to Spline (layout = grid) can walk rows and columns after a warp, and cellW/cellH so downstream expressions can read the gap without re-deriving it from the counts.
spacingMode=fit derives the gap from width/height and the counts; spacingMode=step fixes the gap (spacingX/Y) and the footprint grows with the counts.
gotcha
Both modes center the grid on (x, y), so switching modes does not move it; a 1-count axis collapses onto the center line.
gotcha
ix/iy are integer lattice indices (0..countX-1, 0..countY-1) in row-major point order; Points to Spline layout=grid walks them even after a warp.
gotcha
cellW/cellH are the actual per-axis gap used to place the points (fit: span/(count-1), step: spacingX/Y, 0 on a 1-count axis) and are constant across the cloud.
Parameters
Name
Type
Default
Count X
countX
scalar
1 … 64
5
Count Y
countY
scalar
1 … 64
5
Spacing
spacingMode
enum
"fit"
fit · step
Width
width
scalar
0 … 2
0.8
Height
height
scalar
0 … 2
0.8
Spacing X
spacingX
scalar
0 … 1
0.1
Spacing Y
spacingY
scalar
0 … 1
0.1
Center X
x
scalar
0 … 1
0.5
Center Y
y
scalar
0 … 1
0.5
Sockets
Direction
Name
Type
outputprimary
out
points
Point
point
Emit Count points at (x, y). They start stacked at the same location but each has its own index, so per-point nodes (Point Expression, Modulate Points) can spread them apart. With Count 1, combine with Copy to Points to place one instance of an image or spline at a specific location. Wire a Gizmo into Transform to share placement (TRS applies on top of x/y).
space
in:position,param:x,param:y=canvas01
writes
attr:rotation, attr:scale
gotcha
rotation_deg is stored internally in radians (deg*PI/180) to match Copy-to-Points' convention.
gotcha
The position input, when wired, replaces x/y outright rather than blending with them.
gotcha
transform applies its TRS on top of x/y/rotation_deg/scale rather than instead of them.
Parameters
Name
Type
Default
Count
count
scalar
1 … 4096
1
X
x
scalar
0 … 1
0.5
Y
y
scalar
0 … 1
0.5
Rotation (deg)
rotation_deg
scalar
-360 … 360
0
Scale
scale
scalar
0 … 5
1
Sockets
Direction
Name
Type
input
position
position
vec2
input
Transform
transform
transform
outputprimary
out
points
Point Tracker
tracker-pointpolymorphic
Track N image features across frames. Place tracks on the preview, then step or run the transport in the Parameters tab. Outputs live points (and per-track vec2 sockets) from authored track data — tracking itself runs in the editor, not in compute.
writes
attr:confidence
flags
unstable, no-mask
gotcha
compute() only plays back recorded track data at the current frame; pattern_size/search_size/warp/predict/regrab*/lost_below/verify/stop_when_lost drive the editor's live tracking, not compute.
gotcha
position_<id> and offset_<id> aux outputs (one vec2 per track) are canvas01 point positions/deltas, not unitless vectors.
gotcha
reference=first_sample measures offset_<id> from each track's first recorded sample, not its placement frame, plus the track's authored offset.
gotcha
gap_fill=hold repeats a track's last known position through a lost/missing frame; interpolate fills between its neighboring samples instead.
gotcha
Disabled tracks are dropped from the primary points output, including a per-point confidence channel, but still emit their position/offset/confidence aux sockets.
gotcha
The path aux only computes when consumed and traces each track's raw, unsmoothed recorded trajectory — smooth_radius/smooth_mode affect points, not path.
gotcha
image aux is the input passthrough unless view_tracking_image is on, which swaps in the preprocessed (channel/denoise/bandpass) tracking image instead.
Emit N evenly-spaced positions along a spline. Each point carries a `progress` attribute (0 at the start of the path, 1 at the end; Animate wraps) that Copy to Points can read by name — pick variants, tint, or fade copies by how far along the spline they are. Named channels on the path (per-anchor, interpolated along the curve; per-subpath, copied onto every sample from that subpath) land on the points too, so an image sampled onto the rest pose survives a later rope sim. Domain Combined treats every subpath as one concatenated length (points can slide from one onto the next); Per subpath samples each subpath as its own loop, tagged with that subpath's group. In Per subpath, Amount Equal puts Count points on every subpath; By length scales Count so the longest subpath gets that many and shorter ones get proportionally fewer. Optionally aligns each point's rotation to the path tangent or normal. Turn on Animate to slide the points along the path with the Offset slider — points that reach the end wrap back to the start (a continuous stream; keyframe Offset or wire a Scene Time / LFO ramp to drive it). Primary output is a `points` value for direct wiring into Copy-to-Points / Set Position / etc. Aux outputs: a UV texture of positions (one pixel per point), a dot visualization image, and a `progress` string (the channel name, for wiring into attribute-name params).
progress is a named 0..1 attribute (0 at path start, 1 at end); wire the progress aux (its name string) into Copy to Points pick/tint/opacity, Map Attribute, or Filter Points.
gotcha
domain=per subpath samples each subpath as its own loop and stamps its groupIndex onto attr:group; domain=combined treats every subpath as one concatenated arc length.
gotcha
count_mode=by length only applies in domain=per subpath: the longest subpath gets count points, shorter ones scale down by arc-length ratio.
gotcha
On a curve3d input, align writes the tangent into nx/ny/nz (normals) instead of attr:rotation, and the 2D-only positions/viz auxes stay blank.
gotcha
animate distributes points as a uniform loop (count divisions) so the wrap seam stays evenly spaced; offset wraps at 1 and runs backward if negative.
gotcha
dot_radius is in pixels at render resolution (canvas W×H), not width-relative; the viz image is only painted when show_viz is on and something consumes aux:viz.
gotcha
the positions aux is an N×1 UV texture (RG = x,y in canvas01, N=count), not a full-canvas raster; any unsampled tail from a missing input stays zero.
Parameters
Name
Type
Default
Count
count
scalar
1 … 4096
24
Domain
domain
enum
"combined"
combined · per subpath
Amount
count_mode
enum
"equal"
equal · by length
Animate
animate
boolean
false
Offset
offset
scalar
0 … 1
0
Align to path
align
enum
"off"
off · tangent · normal
Angle offset
align_offset
scalar
-180 … 180
0
Dot radius (px)
dot_radius
scalar
0 … 50
3
Dot color
dot_color
color
"#ffffff"
Show visualization
show_viz
boolean
true
Sockets
Direction
Name
Type
input*
path
path
spline
outputprimary
out
points
outputaux
positions
uv
outputaux
viz
image
outputaux
progress
string
Scatter Points
scatter-pointspolymorphic
Scatter N points across the canvas, optionally weighted by a density input (brighter pixels = more points). Wire an image, or a spline directly — the spline's filled silhouette is the density, sampled without rasterizing to a texture. Deterministic — same seed, same layout.
gotcha
Positions are sampled in canvas UV then written out as authored coordinates (aspectUncorrectY), so density images and wired splines are probed exactly where they draw.
gotcha
Density readback (image or rasterized spline silhouette) is capped at 256px on the long edge — rejection sampling only needs relative weights, not resolution.
gotcha
Density weight = R channel × source alpha, so a transparent region of the density counts as zero regardless of its RGB.
gotcha
Rejection sampling caps at count×50 attempts; a mostly-black density can return fewer points than `count`.
gotcha
A wired spline's filled silhouette is rasterized directly (subpaths unioned, same as Rasterize Spline's stack-subpaths default) — no intermediate texture or GPU readback.
Parameters
Name
Type
Default
Count
count
scalar
1 … 4096
100
Seed
seed
scalar
0 … 10000
1
Rotation (deg)
rotation_deg
scalar
-360 … 360
0
Rotation jitter
rotation_jitter_deg
scalar
0 … 360
0
Scale
scale
scalar
0 … 5
1
Scale jitter
scale_jitter
scalar
0 … 2
0
Sockets
Direction
Name
Type
input
Density
density
image
outputprimary
out
points
Spline Intersections
spline-intersections
Emit a point at every crossing of the input spline's segments — the 'nodes at intersections' construction-drawing look. Feed the output into Copy to Points to stamp a marker at each crossing. By default only segments from different subpaths are tested (so a cluster of shapes + lines marks line×shape and line×line crossings); enable Self-intersections for self-crossing polylines. The original spline passes through on the aux output so one wire carries both the drawing and its nodes.
gotcha
By default only segments from different subpaths are tested; self_intersections adds within-subpath tests but skips adjacent segments (they share a construction vertex, not a crossing).
gotcha
Curves are flattened to polylines first (16 steps per curved cubic, 1 for a straight 2-anchor subpath), so a crossing inside a tight curve can be missed between sample steps.
gotcha
density thins evenly by taking every Nth crossing (step = round(1/density)), not a random subset; max_points then caps the result in discovery order.
gotcha
min_angle drops glancing crossings below that angle between the two segments' directions.
gotcha
Near-duplicate crossings from shared flattened vertices are merged within 1e-4 of spline coordinate units.
Parameters
Name
Type
Default
Density
density
scalar
0 … 1
1
Self-intersections
self_intersections
boolean
false
Min angle
min_angle
scalar
0 … 90
0
Max points
max_points
scalar
1 … 8000
3000
Sockets
Direction
Name
Type
input*
spline
spline
spline
outputprimary
out
points
outputaux
spline
spline
Spline to Points
spline-to-points
Extract the input spline's anchor points as a points value — one point per anchor, in subpath order. Each subpath tags its points with its groupIndex (or its subpath index when untagged), so Points to Spline rebuilds the subpaths and per-index nodes split naturally. Named channels on anchors (and subpath channels, as a fallback) become point attributes, so the round-trip through Points to Spline keeps them. The original spline passes through on the aux output. For evenly spaced samples along the curve instead of the raw anchors, use Points on Path.
writes
attr:group
gotcha
Each subpath's own groupIndex is copied onto its anchors' points (attr:group); an untagged subpath falls back to its own subpath index, not a shared 0.
gotcha
On a name collision, an anchor's own named-channel attrs win over the subpath's attrs; both merge onto the point.
gotcha
Closed subpaths emit each anchor once with no duplicated closing point, so point count equals anchor count exactly.
gotcha
The aux spline output is the unmodified original input, useful for comparing against a Points to Spline round-trip.
Sockets
Direction
Name
Type
input*
spline
spline
spline
outputprimary
out
points
outputaux
spline
spline
Modifiers
Advect Points
advect-pointspolymorphic
Move points through a velocity field derived from an image — the field is re-sampled at every step, so points follow its curves (unlike Displace's single push). Integrate mode traces N deterministic steps per eval and emits streamline trails (flow-field line art: noise → Advect → trails → Stroke). Accumulate mode keeps persistent positions and advances once per frame — endless drift that responds to an animating field, no Simulation Zone needed. Each slot carries an `age` channel (seconds since it joined the flow). Field modes: angle (luminance → heading), vector (signed RG map), gradient (flow toward bright), contour (orbit level sets). Raise Force slots to wire the same Point / Vortex / Wind / Gravity / Turbulence / Drag nodes the Particle Simulator takes — they add to the image field (or drive advection on their own).
space
param:step_size=canvas01
reads
time, attr:group
writes
attr:rotation, attr:age
flags
simulation
gotcha
step_size is a signed canvas-width fraction per step; the y-component is scaled by width/height so speed stays isotropic in pixels on non-square canvases.
gotcha
mode=accumulate persists positions in ctx.state and advances substeps only on frames where ctx.time actually changed; paused param tweaks re-emit without stepping.
gotcha
field_mode=vector reads 2*(channel − midlevel) on R/G (Displace's signed convention); gradient/contour follow the luminance gradient and stall on flat regions.
gotcha
accumulate's age is seconds since a slot joined the sim; seed-count growth joins new points into the run and shrink truncates from the top, neither resets it.
gotcha
align_rotation overwrites the rotation attribute with atan2 of the last velocity sample (sign-flipped by invert), replacing any incoming rotation.
gotcha
boundary=kill drops points leaving [0,1]² in integrate mode along with their other attributes; boundary=wrap splits trails at the torus seam instead of drawing across the canvas.
gotcha
Force sockets (force1..forceN, up to 8 via forceCount) reuse the particle-sim kernel: non-drag forces add as instantaneous velocity, drag applies last at dt=step_size.
gotcha
In accumulate mode the trails aux only accumulates history once something is wired to it; connecting it later starts a fresh short trail, not backfilled.
Parameters
Name
Type
Default
Mode
mode
enum
"integrate"
integrate · accumulate
Field
field_mode
enum
"angle"
angle · vector · gradient · contour
Force slots
forceCount
scalar
0 … 8
0
Steps
steps
scalar
1 … 1000
100
Substeps / frame
substeps
scalar
1 … 16
1
Step size
step_size
scalar
0 … 0.1
0.002
Invert flow
invert
boolean
false
Angle range (turns)
angle_turns
scalar
0 … 4
1
Angle offset (turns)
angle_offset
scalar
-1 … 1
0
Midlevel
midlevel
scalar
0 … 1
0.5
Boundary
boundary
enum
"clamp"
clamp · wrap · kill
Speed jitter
speed_jitter
scalar
0 … 1
0
Seed
seed
scalar
0 … 10000
1
Align rotation to flow
align_rotation
boolean
false
Trail stride
trail_stride
scalar
1 … 10
1
Trail length (frames)
trail_length
scalar
2 … 240
24
Sockets
Direction
Name
Type
input*
points
points
points
input
Field
field
image
input
Speed field
speed
image
outputprimary
out
points
outputaux
trails
spline
Attribute Blur
attribute-blurpolymorphic
Smooths a named channel on points or spline anchors: each iteration moves every element's value toward its neighborhood mean. Spatial domain averages neighbors within a radius; Index domain averages adjacent elements in order (per-subpath, wrapping when closed). A missing channel passes through unchanged.
space
out=in:points param:radius=canvas01
gotcha
radius is canvas01 units, matching Proximity Merge's authored-xy distance convention (raw dx/dy between positions, no aspect term).
gotcha
domain=index on point targets treats the whole array as one flat, edge-clamped sequence (no wrap); only spline-anchor mode splits per subpath and wraps closed ones.
gotcha
spatial domain seeds each element's mean with its own value at weight 1, so an element with no neighbors within radius is left unchanged regardless of strength.
Parameters
Name
Type
Default
Name
attr_name
string
"weight"
Target
target
enum
"points"
points · spline anchors
Domain
domain
enum
"spatial"
spatial · index
Radius
radius
scalar
0.001 … 1
0.05
Iterations
iterations
scalar
1 … 100
5
Strength
strength
scalar
0 … 1
1
Sockets
Direction
Name
Type
input*
Points
points
points
outputprimary
out
points
Attribute Math
attribute-mathpolymorphic
Componentwise math on a named channel (points or spline anchors): add/subtract/multiply/divide/min/max/power/abs against a constant or a second channel, greater than / less than / step (0/1 comparisons), or remap a range. Writes back in place, or to a new name via Output. A missing channel passes through unchanged.
space
out=in:points
gotcha
An arity-1 operand attribute broadcasts across every component of a higher-arity target; any other arity mismatch reads as 0 for every component.
gotcha
divide returns 0 when the operand is exactly 0, not Infinity/NaN.
gotcha
greater than and less than write 1 or 0 per component using a strict inequality against the operand (constant or second channel).
gotcha
step writes 1 when the channel ≥ the operand and 0 otherwise (GLSL step(operand, x)); equality sits on the 1 side.
gotcha
remap clamps t to [0,1] before lerping, so inputs outside In Lo..In Hi saturate at Out Lo/Hi instead of extrapolating.
gotcha
aux name emits the resolved output name (output_name or else attr_name) as a string even when the source channel is missing and nothing was written.
gotcha
Spline-anchor reads fall back to the subpath's own attrs when an anchor lacks the named value, but writing always stamps a per-anchor value, flattening that fallback.
Parameters
Name
Type
Default
Name
attr_name
string
"weight"
Target
target
enum
"points"
points · spline anchors
Operation
op
enum
"multiply"
add · subtract · multiply · divide · min · max · power · abs · greater than · less than · step · remap
Operand
operand
enum
"constant"
constant · attribute
Value
value
scalar
-1000 … 1000
1
With
operand_attr
string
""
In Lo
in_lo
scalar
-1000 … 1000
0
In Hi
in_hi
scalar
-1000 … 1000
1
Out Lo
out_lo
scalar
-1000 … 1000
0
Out Hi
out_hi
scalar
-1000 … 1000
1
Output
output_name
string
""
Sockets
Direction
Name
Type
input*
Points
points
points
outputprimary
out
points
outputaux
name
string
Attribute Read
attribute-readpolymorphic
Reads one point's column — a named channel, a dotted component (color.y), or a built-in like index, x, y, position, scale, rotation, or group — and outputs it as a scalar or vec2. Index picks the point (clamped); a missing channel reads as 0. For per-point reads that stay on the points wire, use Point Expression's attr("name") or Map Attribute.
space
out=unitless
flags
no-mask
gotcha
out inherits whichever attribute is named: position/x/y/scale read as canvas01, index/group/rotation/other channels are unitless — there is no unit conversion.
gotcha
Reading a multi-component named channel without a dot returns only component 0 (e.g. color yields red); use a dotted name like color.y for another channel.
gotcha
vec2 shape on scalar built-ins (index, rotation, group, z, nx/ny/nz) returns [value, 0]; only position/scale and multi-component channels fill both components.
Parameters
Name
Type
Default
Name
attr_name
string
"weight"
Type
shape
enum
"scalar"
scalar · vec2
Index
index
scalar
0 … 10000
0
Sockets
Direction
Name
Type
input*
points
points
points
outputprimary
out
scalar
Attribute Transfer
attribute-transferpolymorphic
Copies a named channel from a source (points or spline anchors) onto a target by proximity: nearest source, or a distance-weighted average within a radius. When nothing is in range, Fallback copies the nearest source or writes zero. The channel lands under the same name; a missing source channel passes the target through unchanged.
space
param:radius=canvas01 out=in:points
gotcha
mode=nearest ring-searches outward until it finds a source (ignores radius) unless fallback=zero, which keeps only a source within radius and writes 0 otherwise.
gotcha
mode=weighted averages sources within radius with linear falloff (weight = 1 − d/radius) over a 3×3 hash neighborhood; fallback=nearest copies the closest source on a miss, fallback=zero writes 0.
gotcha
radius is compared against authored point/spline-anchor positions (canvas01-scale distances, matching Proximity Merge), not pixels or UV.
gotcha
The transferred attribute keeps the source's arity and color flag, so a vec3 color channel arrives flagged as color rather than three scalars.
gotcha
If the named channel is absent on source (missing attribute, empty spline channel, or zero-count source), the target passes through unchanged.
Parameters
Name
Type
Default
Name
attr_name
string
"weight"
Target
target
enum
"points"
points · spline anchors
Source
source_target
enum
"points"
points · spline anchors
Mode
mode
enum
"nearest"
nearest · weighted
Fallback
fallback
enum
"nearest"
nearest · zero
Radius
radius
scalar
0.001 … 1
0.1
Sockets
Direction
Name
Type
input*
Points
points
points
input*
Source
source
points
outputprimary
out
points
Behavioral Growth
behavioral-growth
Give points rules and let them move — flocking, schooling, crowds, slime networks. Steering stacks the classic behaviours as weights you can mix: separation, alignment and cohesion for a flock, Seek toward wired Targets (negative values flee), Wander for restlessness, Flow to follow a wired field as an angle map, and Avoid to steer around Obstacles; tag agents with different group indices and turn on Predator/prey to watch a flock split around a chaser. Physarum is the slime-mould network — each agent sniffs the trail ahead and to each side, turns toward the strongest, and deposits its own trail, which diffuses and decays; the Deposit image aux is usually what you actually render. Vicsek is alignment plus angular noise alone, and the noise slider alone takes it from ordered swirls to chaos. Chemotaxis runs and tumbles up a wired field, searching rather than sliding. Integrate re-runs from the seed points every frame (deterministic and scrub-safe, and the Trails aux gives streamline art); Accumulate keeps the agents moving frame to frame as a living system.
Positions convert canvas-authored coords as x=u*W, y=v*W+(H-W)/2 (authoredToPxY), not v*H, so radii and speeds stay circular on non-square canvases.
gotcha
timeline=accumulate persists position/velocity across frames in state; timeline=integrate resimulates `steps` ticks from the seed points every eval, deterministic.
gotcha
mode=physarum always runs as accumulate since its trail field is path-dependent, so the timeline and steps params are hidden and irrelevant.
gotcha
predator_prey splits agents by attr:group: group 0 is prey, any nonzero group is a predator that chases/repels within r_neighbor.
gotcha
max_neighbors caps interaction count per agent (topological, not just radius), so denser flocks do not blow up the per-frame cost.
gotcha
diffuse_radius (physarum) is a box-blur radius in the trail field's OWN grid cells (sized by field_resolution), not render pixels.
gotcha
aux:deposit renders at the physarum field's own grid resolution (field_resolution), not the canvas render size.
Parameters
Name
Type
Default
Mode
mode
enum
"steering"
steering · physarum · vicsek · chemotaxis
Timeline
timeline
enum
"accumulate"
accumulate · integrate
Steps
steps
scalar
1 … 400
100
Substeps
substeps
scalar
1 … 16
1
Speed
speed
scalar
0.0002 … 0.02
0.002
Boundary
boundary
enum
"wrap"
wrap · bounce
Separation
w_separation
scalar
0 … 4
1.2
Separation radius
r_separation
scalar
0.002 … 0.2
0.015
Alignment
w_alignment
scalar
0 … 4
1
Cohesion
w_cohesion
scalar
0 … 4
0.6
Neighbour radius
r_neighbor
scalar
0.005 … 0.5
0.06
Seek / flee
w_seek
scalar
-2 … 2
0
Arrive
w_arrive
scalar
0 … 2
0
Arrive radius
arrive_radius
scalar
0.005 … 0.5
0.1
Wander
w_wander
scalar
0 … 2
0.1
Wander rate
wander_rate
scalar
0 … 1
0.3
Flow follow
w_flow
scalar
0 … 2
0
Obstacle avoid
w_avoid
scalar
0 … 4
0
Max force
max_force
scalar
0.01 … 2
0.15
Max neighbours
max_neighbors
scalar
4 … 256
24
Predator / prey
predator_prey
boolean
false
Noise
noise
scalar
0 … 1
0.15
Sensor angle
sensor_angle
scalar
5 … 90
22.5
Sensor distance
sensor_distance
scalar
0.002 … 0.1
0.012
Turn rate
turn_rate
scalar
1 … 180
45
Deposit
deposit_amount
scalar
0 … 1
0.2
Decay
decay
scalar
0.001 … 0.5
0.08
Diffuse
diffuse_radius
scalar
0 … 5
1
Field resolution
field_resolution
scalar
64 … 1024
384
Tumble rate
tumble_rate
scalar
0 … 1
0.2
Run bias
run_bias
scalar
0 … 1
0.8
Trail length
trail_length
scalar
2 … 240
24
Seed
seed
scalar
0 … 10000
0
Sockets
Direction
Name
Type
input*
Agents
points
points
input
Field
field
mask
input
Targets
targets
points
input
Obstacles
obstacles
mask
outputprimary
out
points
outputaux
trails
spline
outputaux
deposit
image
Copy to Points
copy-to-pointspolymorphic
Duplicate an image (or image group), spline, or point at every target point. Each copy respects per-point rotation and scale, anchored at the instance's content center (or canvas center / custom). Per-instance modulation works in every mode: scalar inputs drive every copy uniformly (e.g. audio amplitude on `scale_mul` makes everything pulse), and image inputs are sampled at each copy's position (e.g. noise on `scale_field` gives every copy a different size). In spline/point modes, `driver_field` (sampled at the target) and Driver attribute write a per-copy `driver` scalar — Rasterize/Stroke ramps and thickness can key off it — and the target point's named attributes are gathered onto each copied subpath so Attribute Transfer / Sample Texture at Points / Point Expression work as drivers for free. Variants — grouped splines / points, or image-group items — land per point via the pick mode: all, image-driven (`pick` input), seeded random, cycle, by the target point's own group, or by a named attribute on the target points. In image mode, named attributes can also tint each copy (Tint attribute, rgb) and fade it (Opacity attribute, alpha). Draw order controls stacking (painter's by-y, shuffled). In spline/point modes, Tag copies chooses the groupIndex the copies carry out: the instance's own tags, the copy's index (so downstream per-group styling — Stroke color/thickness sources, Select by Index — varies per copy), or the target point's group.
anchor=custom differs by mode: anchor_x/y are absolute canvas01 canvas coordinates for spline/point, but a uv01 fraction of the instance's own bounds for image/text.
gotcha
Nodes saved before pick_mode/anchor existed resolve to pick_mode="image" and anchor="canvas center", not today's defaults "all"/"content center".
gotcha
scale_mul, scale_field, and their derived multiplier are unclamped, so a negative value point-mirrors copies through their anchor instead of erroring.
gotcha
rotate_add_default and rotate_field_amount are radians (-π..π / 0..π), not degrees.
gotcha
Point mode outputs the full Cartesian product of target x instance points (not 1:1); pick_mode narrows which instance points apply per target point.
gotcha
In point mode only the target points' own named attributes survive onto the output; the instance points' own channels are dropped.
gotcha
pick_mode=attribute clamps pick_attr component 0 to [0,1] then floors value×N onto the sorted variant indices (1.0 → last; same as pick_mode=image luminance); a missing channel emits every variant.
Parameters
Name
Type
Default
Instance type
mode
enum
"image"
image · spline · point · text
Variant pick
pick_mode
enum
"all"
all · image · random · cycle · by index · target group · attribute
Pick attribute
pick_attr
string
""
Pick seed
pick_seed
scalar
0 … 9999
0
Anchor
anchor
enum
"content center"
content center · canvas center · custom
Anchor X
anchor_x
scalar
0 … 1
0.5
Anchor Y
anchor_y
scalar
0 … 1
0.5
Draw order
draw_order
enum
"points order"
points order · by y · shuffled
Tag copies
output_tag
enum
"instance groups"
instance groups · copy index · target group
Driver attribute
driver_attr
string
""
Scale × default
scale_mul_default
scalar
-4 … 4
1
Rotate + default (rad)
rotate_add_default
scalar
-3.141592653589793 … 3.141592653589793
0
Scale field — black
scale_field_lo
scalar
0 … 4
0.5
Scale field — white
scale_field_hi
scalar
0 … 4
1.5
Tint attribute
tint_attr
string
""
Opacity attribute
opacity_attr
string
""
Rotate field amount (rad)
rotate_field_amount
scalar
0 … 3.141592653589793
3.141592653589793
Sockets
Direction
Name
Type
input*
points
points
points
input*
instance
instance
image
input
Scale × (uniform)
scale_mul
scalar
input
Rotate + (uniform)
rotate_add
scalar
input
Scale field
scale_field
image
input
Rotate field
rotate_field
image
input
Driver field
driver_field
image
outputprimary
out
image
Drag Points
drag-points
Grab individual points with the mouse (or touch) and drag them — offsets persist inside the node, so any points-driven scene becomes hand-arrangeable, in the editor and in exported apps. Grabs the nearest point within the grab radius at press; the gesture owns it until release. Offsets are index-keyed: best on stable point sets (a count change resets them). Reset input clears all offsets.
space
param:grab_radius=pixels
flags
unstable
gotcha
grab_radius is render pixels, scaled by canvas width on BOTH axes to avoid an elliptical grab zone on non-square canvases.
gotcha
Offsets are keyed by point index, not identity: a count change on the points input resets all offsets, and a reorder silently moves offsets onto the wrong points.
gotcha
reset only clears offsets on a value crossing above 0.5; clear_on_loop clears instead when ctx.time jumps backward (a loop restart), not on any other reset.
gotcha
Only mints new point positions once an offset is live; with nothing ever grabbed the output is the same points reference passed straight through.
Parameters
Name
Type
Default
Grab radius (px)
grab_radius
scalar
1 … 200
16
Clear on loop
clear_on_loop
boolean
false
Sockets
Direction
Name
Type
input*
points
points
points
input
reset
reset
scalar
outputprimary
out
points
outputaux
active_index
scalar
outputaux
grabbed
scalar
Filter Points
filter-pointspolymorphic
Keep or discard points by predicate, or write the predicate as a 0/1 flag and leave every point in place. Bbox keeps points inside an XY window; Mask keeps points where the wired image's luminance is ≥ threshold; Index selects by array position (every Nth, a single index, a range, first, last, or first and last); Random keeps a stable random subset (hashed on index, so points don't flicker in/out — raising Amount reveals more of the same points, Seed re-rolls the selection). Invert flips which side is kept. Result compact drops the rest; flag writes a named 0/1 channel (default keep). Also accepts 3D points (from 3D Scatter Points): bbox becomes a world-space box with Z rows, index/random work identically, mask passes through.
points is polymorphic: a points3d wire switches bbox to world-space X/Y/Z rows (wx/wy/wz, default −10..10) and hides the 2D X/Y rows and the mask threshold.
gotcha
mask mode ignores a points3d input entirely (authored-space sampling has no meaning for world points) and passes it through unchanged, same as an unwired mask on 2D input.
gotcha
attribute mode compares a named channel's component 0 against attr_threshold; a missing channel passes every point through unchanged instead of dropping them.
gotcha
index_by (index mode) selects every-Nth, a single index, an inclusive range, first, last, or first and last; invert flips the predicate before compacting or writing the flag.
gotcha
result=flag writes a 0/1 float channel named flag_name (default keep) and leaves count unchanged; result=compact drops unmatched points and renumbers survivors from 0.
gotcha
index/random key off each point's position in the incoming array, not any stored identity, so a changed upstream count changes which points survive.
gotcha
random mode's hash matches Point Expression's rand(index) byte-for-byte (seed 0 == hash01(index)), so an equivalent expression selects the identical subset.
gotcha
Compact mode carries scale/rotation/group and named attributes through gatherPoints; flag mode overlays flag_name on the existing cloud without gathering.
Parameters
Name
Type
Default
Mode
mode
enum
"bbox"
bbox · mask · index · random · attribute
Name
attr_name
string
"weight"
Threshold
attr_threshold
scalar
-100 … 100
0.5
X min
x_min
scalar
-1 … 2
0
X max
x_max
scalar
-1 … 2
1
Y min
y_min
scalar
-1 … 2
0
Y max
y_max
scalar
-1 … 2
1
X min
wx_min
scalar
-10 … 10
-10
X max
wx_max
scalar
-10 … 10
10
Y min
wy_min
scalar
-10 … 10
-10
Y max
wy_max
scalar
-10 … 10
10
Z min
wz_min
scalar
-10 … 10
-10
Z max
wz_max
scalar
-10 … 10
10
Threshold
threshold
scalar
0 … 1
0.5
Select
index_by
enum
"every"
every · equal · range · first · last · first and last
Keep 1 of every
every
scalar
1 … 32
2
Offset
offset
scalar
0 … 32
0
Index
index_value
scalar
0 … 100000
0
From
index_min
scalar
0 … 100000
0
To
index_max
scalar
0 … 100000
0
Amount
amount
scalar
0 … 1
0.5
Seed
seed
scalar
0 … 999
0
Invert
invert
boolean
false
Result
result
enum
"compact"
compact · flag
Flag
flag_name
string
"keep"
Sockets
Direction
Name
Type
input*
points
points
points
input
Mask
mask
image
outputprimary
out
points
Map Attribute
map-attribute
Drives built-in point data from any point column — a named channel, or a built-in like index, x, y, scale.x, rotation, or group. Normalize through In Lo/Hi, shape with a 0–1 curve, then map through Out Lo/Hi and apply as a scale multiplier, a rotation offset (radians), or a position offset. The curve defaults to a linear ramp, so a straight diagonal is the old In→Out remap. A missing named channel passes through unchanged.
space
param:out_lo,param:out_hi=canvas01
reads
attr:scale, attr:rotation, attr:position
writes
attr:scale, attr:rotation, attr:position
gotcha
attr_name is read at runtime and can be any named channel or a built-in (index, x, y, scale.x, rotation, group, ...); an unknown name passes points through unchanged.
gotcha
map_target picks exactly one destination per point: scale multiplies existing scale, rotation adds radians to existing rotation, position x/y offsets one position axis.
gotcha
Position x/y offsets add directly into the point's stored canvas01 coordinate (authored space); for the other targets out_lo/out_hi become a scale multiplier or radians instead.
gotcha
The curve defaults to an identity (0,0)-(1,1) ramp, so an untouched curve behaves as a plain In Lo/Hi -> Out Lo/Hi linear remap.
Modulate per-point scale and rotation on a points value. Uniform inputs apply to every point; image fields are sampled at each point's UV and mapped through the configured ranges. Stack to layer modulations; feed the result into Copy to Points (or any consumer that respects per-point attributes).
reads
attr:scale, attr:rotation
writes
attr:scale, attr:rotation
gotcha
scale_field/rotate_field images are downsampled to a fixed 128x128 working buffer, so fine texture detail in the field is lost.
gotcha
Field sampling uses an async GPU readback (PBO + fence), so field-driven modulation lags the live image by about one frame.
gotcha
New scale multiplies the existing per-point scale and new rotation adds to the existing rotation, so stacked nodes compound rather than replace.
gotcha
With scale_mul=1, rotate_add=0 and no fields wired, the node is a no-op and returns the input points object unchanged.
Parameters
Name
Type
Default
Scale × default
scale_mul_default
scalar
0 … 4
1
Rotate + default (rad)
rotate_add_default
scalar
-3.141592653589793 … 3.141592653589793
0
Scale field — black
scale_field_lo
scalar
0 … 4
0.5
Scale field — white
scale_field_hi
scalar
0 … 4
1.5
Rotate field amount (rad)
rotate_field_amount
scalar
0 … 3.141592653589793
3.141592653589793
Sockets
Direction
Name
Type
input*
points
points
points
input
Scale × (uniform)
scale_mul
scalar
input
Rotate + (uniform)
rotate_add
scalar
input
Scale field
scale_field
image
input
Rotate field
rotate_field
image
outputprimary
out
points
Point Expression
point-expressionpolymorphic
Run a JavaScript expression once per point to compute its new position, scale, rotation, and groupIndex from its own `index` (and `count`, incoming `groupIndex`, current px/py/rot0/sx0/sy0 (px/py are authored [0,1]² Y-down; the rasterizer scales y about 0.5 by W/H so distances are width-relative), the `frame`/`t` clock, and wired uniforms). Assign `groupIndex = floor(index/2)` (or any rule) to partition points into subpaths — Points to Spline splits on the tag. Set `keep=false` to cull a point. Wire a spline into `path` to sample guide curves with pathPos(factor, sub) / pathLen(sub) / pathAngle(...). Wire a velocity field (Perlin curl, Spline Flow Field, Vector Field) into `field` and sample it with fieldX() / fieldY() / fieldAt() at the current point, or fieldX(u, v) at any UV. Deterministic rand(seed) hashes on index for stable per-point randomness; random() varies per frame. attr("name") reads a named point channel (attr("name", c) for a component) and setattr("name", v) writes a float channel — inspect them in the Spreadsheet panel. Target switches the element domain: `spline anchors` runs the code once per anchor instead (read px/py, handle offsets inx0/iny0/outx0/outy0, width0, subpath; write x, y, inx, iny, outx, outy, width, keep). Mark tunables as CHANNELS and hit Sync to mint standard controls you can drive: ch("name", default, min, max) → slider (number); toggle("name", true) → on/off pill (boolean); pick("name", "a", "b") → 2–3-way segmented pill or dropdown (option string); color("name", "#ff8800") → swatch ([r,g,b,a] 0..1); ramp("name", t, "#000000", "#ffffff") → gradient editor sampled at t ([r,g,b,a]); curve("name", x, 1, 0) → float-curve editor sampled at x (number). Seeds are literals after the name (ch positional; hex/number lists seed ramp stops / curve points evenly). Sync is add-only: existing rows keep their value — tune a channel with set_param using its NAME. Scalar, toggle, color and ramp channels are also wireable input sockets addressed by name (scalar / scalar / vec4 / color_ramp) — e.g. with ch("speed", 600) in the expression, wire an LFO or audio level into the `speed` input to drive it. This is the per-element field primitive — the per-point counterpart to the once-per-frame Expression node.
target=points writes x,y,rot,sx,sy,scale,keep,groupIndex; sx/sy are absolute (seeded from sx0/sy0); only scale multiplies — sx=2 is size 2, not 2× incoming.
gotcha
target=spline anchors runs once per anchor instead, reading/writing x,y,inx,iny,outx,outy,width,keep — a different tuple than the points domain.
gotcha
keep=false culls the point/anchor; a stray `return` in the block replaces the whole packed result and is caught by validateParams, not silently at runtime.
gotcha
rand(seed) is frame-independent (hashes only the seed); random() is a per-frame RNG seeded from nodeId+frame — use rand(index) for stable per-point noise.
gotcha
attr(name) reads only the INCOMING value's channels; same-pass setattr writes are not readable, so results never depend on point iteration order.
gotcha
fieldX/fieldY/fieldAt sample a wired velocity image at the current point's (px,py) by default, decoded as signed-RG like Advect Points' vector mode.
gotcha
ch/pick/toggle/color/ramp/curve read a channel row by name if it exists, else the inline default; Sync only adds missing rows, never overwrites one.
gotcha
on_error=passthrough keeps the element unchanged on a runtime exception (only the first error per eval is logged); zero drives its writable outputs to 0.
Parameters
Name
Type
Default
Target
target
enum
"points"
points · spline anchors
Channels
inputs
expr_inputs
[]
Expression
expression
string
"// read: index, count, groupIndex, px, py, rot0, sx0, sy0\n// write: x, y, rot, sx, sy, scale, keep, groupIndex (declare temps with let/const)\n// channels: attr(\"name\") reads, setattr(\"name\", v) writes — see Spreadsheet\n// tunables: ch(\"name\", default) · toggle(\"name\", true) · pick(\"name\", \"a\", \"b\")\n// color(\"name\", \"#hex\") · ramp(\"name\", t, \"#hex\", …) · curve(\"name\", x, 1, 0)\n// — then hit Sync to mint the controls (also wireable inputs)\n// field: fieldX() / fieldY() / fieldAt() sample a wired velocity field\nx = px;\ny = py;"
On error
on_error
enum
"passthrough"
passthrough · zero
Sockets
Direction
Name
Type
input*
Points
points
points
input
Path
path
spline
input
Field
field
image
outputprimary
out
points
Point Labels
point-labels
Draw a text label on every point, formatted from the point's own data — position (x, y), index, rotation, scale, or group. Pick a field or write a custom token template ({x} {y} {i} {n} {rot} {rad} {sx} {sy} {g}); coordinates read authored [0,1]² Y-down (raster y is scaled about 0.5 by W/H) or in pixels, with adjustable precision. Self-contained (points → image): each label lands on its point, placed on / above / below / left / right of it with an offset and scale. Style comes from a wired Text node, or the local font/size/color params.
field=position/x/y/custom respect units=normalized (canvas01) or pixels (x times canvas width, y times canvas height independently); other fields ignore units.
gotcha
offset_x/offset_y are per-axis UV fractions of the canvas's own width/height, added after the point's Y-down/aspect placement — not aspect-corrected to each other.
gotcha
placement picks which point of the label box sits at the (offset) target: 'on' centers it, 'above' puts the box's bottom edge there, etc.
gotcha
label_scale is baked into the rasterized font size (stays crisp) rather than stretching the box; any style/color/font/scale change clears the whole raster cache.
gotcha
style input (a wired Text node's text_instance) overrides font_family/size/color/alignment entirely; the local params are only the no-wire fallback.
gotcha
stable:false — re-checks font readiness every eval; an unready font paints nothing that frame and re-triggers once the async load completes.
Parameters
Name
Type
Default
Data
field
enum
"position"
position · x · y · index · rotation · scale · group · custom
Template
template
string
"{x}, {y}"
Units
units
enum
"normalized"
normalized · pixels
Decimals
precision
scalar
0 … 6
2
Placement
placement
enum
"on"
on · above · below · left · right
Offset X
offset_x
scalar
-0.5 … 0.5
0
Offset Y
offset_y
scalar
-0.5 … 0.5
0
Label scale
label_scale
scalar
0.1 … 8
1
Font
font_family
enum
"Inter"
Inter · Roboto · Open Sans · Lato · Montserrat · Poppins · Work Sans · DM Sans · Nunito · Raleway · Oswald · Bebas Neue · Playfair Display · Merriweather · Crimson Text · Cormorant Garamond · Space Mono · JetBrains Mono · Helvetica · Arial · Georgia · Times New Roman · Courier New
Size (px)
size
scalar
1 … 512
32
Color
color
color
"#ffffff"
Align
alignment
enum
"center"
left · center · right
Opacity
opacity
scalar
0 … 1
1
Sockets
Direction
Name
Type
input*
points
points
points
input
Style
style
text_instance
outputprimary
out
image
Points to String
points-to-string
Join a column of point data into one string — Y, X, index, rotation, scale, group, a named attribute, or a custom token template ({x} {y} {i} {attr:name}). Layout is comma-separated, one value per line, or a grid (N columns). Wire the string into a Text node's text. Coordinates read normalized [0,1] or in pixels, with adjustable precision. For a label sitting on each point, use Point Labels; for per-point strings into Copy to Points, use Points to Text.
reads
attr:rotation, attr:scale, attr:group
flags
no-mask
gotcha
field=attribute reads a named point channel by attr_name (component 0 only); an invalid identifier or missing channel formats as 0.
gotcha
field=custom and field=attribute both compile through the same {token} template language as Point Labels/Points to Text.
gotcha
layout=grid arranges the per-point strings into an N-column grid of TEXT (columns, column_sep) — it is still one joined string, not a spatial layout.
gotcha
units=pixels multiplies x by canvas width and y by canvas height independently (anisotropic), matching every other engine value.
Parameters
Name
Type
Default
Data
field
enum
"y"
position · x · y · index · rotation · scale · group · attribute · custom
Name
attr_name
string
"weight"
Template
template
string
"{x}, {y}"
Layout
layout
enum
"comma"
comma · lines · grid
Columns
columns
scalar
1 … 64
4
Column sep
column_sep
enum
"space"
space · tab · comma
Units
units
enum
"normalized"
normalized · pixels
Decimals
precision
scalar
0 … 6
2
Sockets
Direction
Name
Type
input*
points
points
points
outputprimary
out
string
Points to Surface
points-to-surface
Mesh a surface around particle clumps: builds a field from a points cloud and traces its outline as a spline (marching squares). `zhu-bridson` is the classic liquid surfacing — flat resting surfaces, calm concave regions; `metaballs` is the blobby lava-lamp merge look. Wire the Matter/Particle Simulator's points output in and liquid gets a skin — the spline coerces straight into any mask/image socket as a filled silhouette, or style it via Rasterize Spline / Stroke (each blob carries a groupIndex for per-blob ramp colors). `radius` sets how far particles reach before merging; `threshold` tightens or fattens the surface; `min blob` culls specks.
space
param:radius=canvas01
writes
attr:group
gotcha
radius is a canvas01 width-relative fraction like every other radius; particles within it (per algorithm's falloff) merge into one blob.
gotcha
zhu-bridson thresholds the signed distance to the kernel-weighted mean particle position (surface radius = threshold × radius); metaballs thresholds a summed (1−q²)³ field.
gotcha
min_blob culls output subpaths by shoelace area in canvas-area fraction ([0,1]² units), not a linear size.
gotcha
smoothing runs round(smoothing × 6) neighbor-average passes on the traced anchors.
gotcha
each traced blob gets a fresh sequential groupIndex (attr:group), independent of any groupIndex on the input points — Rasterize's ramp fill / Group Pick key off it.
gotcha
detail sets samples across the width only; sample-grid height is derived from canvas aspect, so the field stays isotropic regardless of canvas shape.
Parameters
Name
Type
Default
Algorithm
algorithm
enum
"zhu-bridson"
zhu-bridson · metaballs
Radius
radius
scalar
0.005 … 0.15
0.025
Threshold
threshold
scalar
0.05 … 1
0.5
Detail
detail
scalar
48 … 384
160
Smoothing
smoothing
scalar
0 … 1
0.4
Min blob area
min_blob
scalar
0 … 0.01
0.0002
Sockets
Direction
Name
Type
input*
points
points
points
outputprimary
out
spline
Points to Text
points-to-text
Format each point's own data into a string — position (x, y), index, rotation, scale, or group — one label per point. Pick a field or write a custom token template ({x} {y} {i} {n} {rot} {rad} {sx} {sy} {g}); coordinates read normalized [0,1] or in pixels, with adjustable precision. Emits a text_instance: wire it into Copy to Points (text mode, 'by index' pairing) to place each label on its point. Style comes from a wired Text node, or the local font/size/color params.
space
param:size=pixels
reads
attr:rotation, attr:scale, attr:group
flags
no-mask
gotcha
field=custom's {token} template is shared with Point Labels/Points to String; unrecognized {…} sequences pass through literally.
gotcha
units=pixels multiplies x by canvas width and y by canvas height independently (anisotropic) — not one aspect-scaled number.
gotcha
Pairing with Copy to Points (text mode, 'by index') matches strings to points strictly by INDEX; a filter/reorder/resample in between desyncs labels from dots.
gotcha
style input (a wired Text node's text_instance) overrides font_family/size/color/alignment entirely; the local params are only the no-wire fallback.
Parameters
Name
Type
Default
Data
field
enum
"position"
position · x · y · index · rotation · scale · group · custom
Template
template
string
"{x}, {y}"
Units
units
enum
"normalized"
normalized · pixels
Decimals
precision
scalar
0 … 6
2
Font
font_family
enum
"Inter"
Inter · Roboto · Open Sans · Lato · Montserrat · Poppins · Work Sans · DM Sans · Nunito · Raleway · Oswald · Bebas Neue · Playfair Display · Merriweather · Crimson Text · Cormorant Garamond · Space Mono · JetBrains Mono · Helvetica · Arial · Georgia · Times New Roman · Courier New
Size (px)
size
scalar
1 … 512
32
Color
color
color
"#ffffff"
Align
alignment
enum
"center"
left · center · right
Sockets
Direction
Name
Type
input*
points
points
points
input
Style
style
text_instance
outputprimary
out
text_instance
Sample Texture at Points
sample-texture-at-points
Reads a channel of an image at each point's position and writes the value into the chosen attribute (scale, rotation, or a named channel). The sampled [0..1] value remaps linearly to [Lo..Hi] before being combined via Replace / Multiply / Add.
reads
attr:scale, attr:rotation
writes
attr:scale, attr:rotation
gotcha
target picks which attribute is overwritten (scale, rotation, or a named channel via attr_name); the others pass through unchanged.
gotcha
blend=replace ignores the existing attribute entirely; multiply/add combine the remapped sample with the point's current scale/rotation/named value.
gotcha
target=scale writes the same value to both x and y (isotropic); for anisotropic scaling, chain two of these after splitting the source.
gotcha
target=named attribute writes a float channel named by attr_name (setattr-style); reserved names (position/x/y/index/rotation/scale/group/…) pass the points through unchanged.
gotcha
Point UV is aspect-corrected before sampling (py = 0.5 + (y-0.5)*canvasAspect) so the sample lands where the point visually sits on non-square canvases.
gotcha
No image wired, or an image whose pixels fail to read back, passes the points through unchanged rather than erroring.
Parameters
Name
Type
Default
Channel
channel
enum
"luminance"
luminance · r · g · b · a
Target
target
enum
"scale"
scale · rotation · named attribute
Name
attr_name
string
"lum"
Blend
blend
enum
"replace"
replace · multiply · add
Lo (black ⇒)
lo
scalar
-100 … 100
0
Hi (white ⇒)
hi
scalar
-100 … 100
1
Sockets
Direction
Name
Type
input*
points
points
points
input*
image
image
image
outputprimary
out
points
Set Named Attribute
set-named-attributepolymorphic
Writes a named channel (a Blender-style attribute) onto points, spline anchors, or spline subpaths: pick a name, a type, and a source — a constant, a 0→1 ramp over element order, a stable per-element random, or an image sampled at each element's position. Channels flow through downstream nodes, show as columns in the Spreadsheet panel, and point channels read back in Point Expression via attr("name"). Reserved names (the built-in x/y/index/rotation/scale/group columns) pass through unchanged.
space
in:points=canvas01 out=in:points
gotcha
The written channel's name comes from `attr_name`; an empty name or a reserved one (position/x/y/index/rotation/scale/group/z/nx/ny/nz) passes the input through unchanged.
gotcha
target=points writes a PointsValue.attributes channel; target=spline anchors/subpaths write to each anchor's or subpath's object-attached `attrs` instead.
gotcha
source=image samples nearest-texel at each element's own position (point, anchor, or subpath centroid) — float kind uses luminance, vec/color kinds use RGBA.
gotcha
source=index and source=random remap through lo/hi only when kind=float; other kinds ignore lo/hi and use the raw [0,1) value per component.
gotcha
source=random is a deterministic hash keyed on seed and element index, not Math.random, so it's stable across frames and re-evaluations.
gotcha
The `name` aux output is the channel's name as a string, meant to be wired into another node's attribute-name param so a rename here ripples downstream.
Parameters
Name
Type
Default
Name
attr_name
string
"weight"
Target
target
enum
"points"
points · spline anchors · spline subpaths
Type
kind
enum
"float"
float · vec2 · vec3 · vec4 · color
Source
source
enum
"constant"
constant · index · random · image
Value
value
scalar
-100 … 100
1
Value
value_vec
vec4
[0,0,0,0]
Color
color
color
"#ffffff"
Seed
seed
scalar
0 … 10000
0
Lo
lo
scalar
-100 … 100
0
Hi
hi
scalar
-100 … 100
1
Sockets
Direction
Name
Type
input*
Points
points
points
input
image
image
image
outputprimary
out
points
outputaux
name
string
Set Position
set-positionpolymorphic
Translate so the input's geometric center lands at (X, Y). Absolute placement — unlike Transform's offset translate, the result is always centered at the target regardless of where the input started.
Translates by (target − centroid): the centroid is the mean of anchor positions (spline) or point positions (points), so the result always lands centered at (x, y).
gotcha
The `position` vec2 input overrides x/y params entirely when connected.
gotcha
Spline handles are not touched directly — they're stored relative to their anchor, so the uniform shift carries them along unchanged.
gotcha
mode=points on an empty points input (count 0) passes it through with no shift, since there is no centroid to compute.
Parameters
Name
Type
Default
Type
mode
enum
"spline"
spline · points
X
x
scalar
0 … 1
0.5
Y
y
scalar
0 … 1
0.5
Sockets
Direction
Name
Type
input*
Spline
in
spline
input
position
position
vec2
outputprimary
out
spline
Stagger
stagger
Gives every point its own start time and writes a 0→1 `phase` channel: 0 before the point's start, a linear ramp over Duration, 1 after. Order picks who goes first — point index, reverse, center-out, edges-in, a seeded random, or ascending by any point column (a named channel, or a built-in like x / y / group; equal values start together). Spacing mode steps each start by Spacing; Fit mode spreads the starts so the whole sequence ends at Total. Jitter adds a stable per-point random delay, Start shifts the sequence, Loop repeats it (cycle or ping-pong). Unit sets whether all of those — and a wired Clock — read as frames or seconds; unwired, the Clock is the playhead. Read phase downstream with Map Attribute (its curve is the per-point easing), Filter Points, or Copy to Points' tint / opacity / variant pick. Extras also writes `<name>_t0` (each start) and `<name>_active` (1 only while in flight). Pure and stateless — scrub-exact, exportable, retimeable by Time Offset.
flags
no-mask
gotcha
attr_name (default `phase`) names the written channel; empty or a reserved point-attribute name passes the input through unchanged.
gotcha
unit scales Spacing/Total/Duration/Jitter/Start and a wired Clock into frames internally; an unwired Clock uses the scoped playhead in fractional frames.
gotcha
order=attribute sorts by order_attr (a named channel or built-in like x/y/group); a missing/blank column falls back to index order silently.
gotcha
Ordering is a dense rank, so tied keys share one start time (an unsorted grid ordered by y starts a whole row together).
gotcha
jitter is a stable per-point hash of seed and index (not Math.random), always positive, so it only ever delays a start, never advances it.
gotcha
loop=cycle wraps and loop=ping-pong folds the local clock over the whole sequence's period, so the cascade repeats as a unit, not per point.
gotcha
extras also writes `<name>_t0` (each point's start, in the node's own unit) and `<name>_active` (1 only while Start ≤ local time < Start+Duration).
gotcha
Pure function of input/params/clock with no internal state, so scrubbing, export, and Time Offset retiming are exact.
Parameters
Name
Type
Default
Name
attr_name
string
"phase"
Order
order
enum
"index"
Index · Reverse · Center out · Edges in · Random · By attribute