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

PortTypeDefault
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.int10

Outputs

PortType
Countint

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:

  1. Discovers its child nodes and sorts them topologically by their internal cables, so every node runs after the nodes feeding it.
  2. 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).
  3. 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), and Count (N). Each child's outputs are cached per pass, so sibling cables inside the body resolve exactly as they would in the open graph.
  4. 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:

RuleNodes
Allowed categoriesMath, Logic, Array, String, JSON, Color, Structure
Allowed by nameConstant, 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 Iteration Index picks 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 using Index and 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.

More Logic nodes