Context: per-element values

One node can feed thousands of copies — and each copy can quietly carry its own number.

This is the idea that makes node graphs click. A single node doesn't just hold one value. When it feeds many elements — many points, many duplicates, many loop passes — a value can resolve differently for each one. Once you see it, a huge amount of the app stops feeling like magic.

The simplest version: per-row attributes

Most things you make are collections — a bag of elements (points, shapes, copies) that all travel together. Every element in that bag can carry its own labelled values, called attributes. You write an attribute with an @ in front of its name.

A few you'll meet constantly:

The trick is that @id isn't one number. It's a different number on every element. So when you reference @id somewhere downstream, you're not asking "what is the id?" — you're asking "what is this element's id?", and you get a different answer for each.

Think of an attribute like a column in a spreadsheet. The node is the whole sheet; @id is the column. Each row reads its own cell.

Make it click: colour 200 points by their @id

Here's the canonical example. Scatter some points, then tint each one differently — without touching them one by one.

  1. Add a scatter source so you have, say, 200 points. Each one automatically gets its own @id (0 through 199).

  2. Add an The Expression language node and write a per-element rule. For example: @Cd = @id / @total

  3. Every point now reads its own @id, divides by the total count, and gets a brightness from 0 (the first point) to 1 (the last). The result is a smooth ramp across all 200 points — from one tiny rule.

The Expression node ran once per point, and each run saw that point's own @id. You never wrote a loop. You wrote the rule for one element, and the app applied it across the whole bag.

Want a colour sweep instead of grey? Feed @id / @total into a Scene values and read the colour out. Same per-element idea, prettier result.

Copies: each duplicate gets its own context

The utility.iterator node stamps copies of whatever you feed it — in a line, a grid, a circle, along a path, or onto existing points. Crucially, each copy knows which copy it is.

While it builds the copies, the Iterator hands each one a set of per-copy values you can read:

So "scale each copy a bit more than the last" is just reading @index and turning it into a scale. "Fade copies along a path" is just reading @path_t. You author the relationship once; every copy fills in its own number.

The per-copy inputs on the Iterator (rotation, offset, scale, colour, and so on) accept either a single value or a list. Give it one value and every copy shares it; give it a list and each copy reads its own entry.

Loops: each pass is its own context

Loops are the time-based cousin of copies. Instead of many elements side by side, you get many passes, one after another — and each pass has its own context too.

Same mental model as copies: you describe what one pass does, and the loop supplies the changing context (@index, the running state) for each one.

Why this matters

Per-element context is the thing that lets one small graph describe enormous variety. You don't build 200 points, 50 copies, or 30 loop passes by hand — you build the rule, and the app resolves it freshly for every element, copy, or pass.

When something downstream "knows" which point it is, which copy it is, or which pass it is, this is why: it's reading a per-element value like @id, @index, or @path_t.

A value only varies per element if it actually is a per-element attribute. A plain number typed into a parameter is one value shared by everything. To get variety, read an attribute (@id, @index, @path_t) or feed the Iterator a list instead of a single value.

See also