Logic node
Loop
A data-loop container: the Loop evaluates its internal subgraph N times per frame and collects every published output into an array, one element per iteration. It is the node-graph equivalent of a for loop — double-click to enter the body, build a small data patch inside, and read the results outside as arrays. The Loop is the data half of the Loop/Replicator pair: it produces numbers, strings, and structures, while its visual sibling Replicator produces cloned pixels.
Inputs
| Port | Type | Default |
|---|---|---|
| IterationsHow many times the inner subgraph runs each frame, one array element per pass. Clamped to 0…1024; 0 gives empty arrays, and high counts cost a full body run every frame. | int | 10 |
Outputs
| Port | Type |
|---|---|
| Count | int |
How It Works
The Loop is a dive-in container, like a Macro Group. Its children are deliberately excluded from the global execution plan — the Loop's own process() drives them. Each frame it:
- Discovers its child nodes and sorts them topologically by their internal cables, so every node runs after the nodes feeding it.
- Splits the body into loop-invariant children (not downstream of an Iteration node — evaluated once per frame) and varying children (the Iteration node and everything downstream of it — evaluated once per iteration).
- Runs the varying set N times. Before each pass it seeds the Iteration node's outputs directly:
Index(0…N−1),T(Index / (N−1), or 0 when N ≤ 1), andCount(N). Each child's outputs are cached per pass, so sibling cables inside the body resolve exactly as they would in the open graph. - After each pass, samples every published output and appends the value to that output's array.
The evaluation is sequential and deterministic — iteration 1 always runs after iteration 0, and the whole body completes within a single frame.
Values in: the wildcard + port. Drop any cable onto the Loop's + input and the value is published into the body: a boundary input port is created, an internal Port node (named after the source port) is auto-created and bridged, and the value appears inside the body on that Port node's Out. Published inputs are constant across the N iterations of one frame.
Values out: published outputs. Select any node inside the body and publish one of its outputs (Inspector → Published Ports). Because the Loop's boundary is array-typed (publishedOutputsBecomeArrays), that boundary port emits a .structure array with one element per iteration — feed it into the Array node family or index it with Array Get.
Smart change detection. The Loop fingerprints everything its result depends on: iteration count, body topology, every child's parameter values (including live inspector drags and stored settings such as a Math Expression formula), the published-port bridges, and the resolved external values of published inputs. If the fingerprint is unchanged, the cached arrays are returned without running a single pass — a static 256-entry lookup table costs one hash per frame, not 256 evaluations. Bodies that contain live nodes (Time, Get Variable, Render Size — values that change outside the graph's sight) re-evaluate every frame; a live external source feeding a published input busts the cache naturally through its value.
Child policy (v1). Only pure data nodes are allowed inside the body; the node palette filters itself accordingly while you are dived in:
| Rule | Nodes |
|---|---|
| Allowed categories | Math, Logic, Array, String, JSON, Color, Structure |
| Allowed by name | Constant, Get Variable, Time, Render Size, Iteration, Port, Reroute, Comment Box |
| Blocked (stateful/event — per-iteration state undefined) | Smooth, FFT, Integrator, Counter, Do Once, Delay, Array Accumulate, Array Sample, Array Set |
| Blocked (no nesting in v1) | Loop, Replicator |
Deleting the Loop deletes its entire body (standard container behavior), and its result cache is cleared.
Parameters in Depth
Iterations (int, default 10) — how many times the body runs per frame. The value is clamped to the range 0…1024; at 0 (or with an empty body) every published output emits an empty array. The port accepts a connected int or float (floats are truncated). Remember the body executes N times every frame while live — Iterations is a per-frame pass count, not a one-shot counter.
+ (wildcard, any type) — the publish-input port. Each cable connected here becomes a named boundary input (a fresh + appears below it), bridged to an auto-created Port node inside the body. The published value is frame-constant: all N iterations of a frame see the same number. Any port type is accepted, including whole arrays — publish an array in and index it per-iteration with Array Get for a map-style transform.
Count (int output) — the clamped iteration count actually used this frame. Alongside it, every output you publish from inside the body appears on the Loop as an additional array output, in the type-color of a structure cable.
Use Cases
- Lookup table / curve baking: set Iterations to 256; inside, Iteration
T→ Math Expression shaping curve → publish the result. Outside you get a 256-entry array, recomputed only when the formula or count changes — sample it with Array Get or Array Interpolate. - Array map: connect an existing array (for example from Audio FFT) to the
+port; inside, Array Get with IterationIndexpicks the current element, a Math chain transforms it, and the published result is the transformed array — a per-element map with no manual unrolling. - Spacing offsets: Iteration
Index→ Math (Multiply) with a Constant 0.1 → publish. The output is[0, 0.1, 0.2, …], ready for any consumer that indexes it with Array Get. - Ring coordinates: Iteration
T→ Math (Multiply by 360) → Math sin/cos → publish X and Y. Two synchronized arrays describing a circle, driven by one Iterations value. - Structure batches: build a JSON Object or Make Structure per iteration, keyed by
Index, and publish it — the boundary emits an array of N structures for JSON Stringify, OSC Sender, or further JSON processing. - Additive series: with Time published in via
+, compute one harmonic per iteration (Math Expression usingIndexand the published time), publish the partials, and reduce them outside with Array Sum for an N-partial oscillator value.
Tips
- Iterations is capped at 1024, and the body runs N times every frame at display rate when live — keep bodies lean and let the fingerprint cache do the work for static patches.
- The Iteration node only exists inside containers: it is hidden from the palette at root level and seeded by the owning Loop each pass. Outside a running body it reports zeros.
- Stateful nodes (Counter, Smooth, Do Once, Delay…) are blocked inside because "state per iteration" is undefined in v1 — restructure the patch so state lives outside the Loop and enters through the
+port. - Published inputs are constant within a frame. If you need a value that differs per iteration, derive it inside from Iteration
Index/T, or publish an array and index it with Array Get. - A body containing Time, Get Variable, or Render Size re-evaluates every frame even if nothing visibly changed — remove live nodes from the body (publish their values in instead) when the result is actually static; an unchanged published value then keeps the cache valid.
- For visual clones, use the Replicator node instead — it shares the same body machinery but renders one internal generator N times into a single texture.
Open Loop in the interactive catalog →
Loop is one of 381 nodes in Grafit Pro.
Free download. Every feature for 7 days, no card. Then €99.99 once — or keep playing your projects as a Player.