What the crystal generator’s node tree is actually doing, and why each piece works.

Open the interactive tutorial →

The outward rotation

What happens: each instance point’s Position, minus the center, gives a vector. Vector Length turns it into a distance. Map Range converts distance to a 0–1 factor. Align Rotation to Vector (Axis Z, Vector = Position) tilts each crystal along its own position vector, blended by that factor.

Why it works: the position vector already contains both answers: its direction is exactly the way an outward crystal should rotate, and its length says how far from center it is. Center crystals get factor ≈ 0 and stay upright; rim crystals get ≈ 1 and rotate fully. No conditions, no edge detection: the rotation falls out of data every point already has.

Bigger in the middle

What happens: a Points node makes one point at the origin. Geometry Proximity measures each crystal’s distance to it. Map Range turns that distance into a scale multiplier.

Why it works: it’s the same signal as the rotation (distance from center) reused as a size gradient. Flip the Map Range and the rim grows instead. Any center-out effect is this one measurement remapped.

Random crystal per point

What happens: the three crystal variants go through Join Geometry → Mesh Island → Split to Instances. Mesh Island tags each disconnected piece with an index, so the split produces a pool addressable as 0, 1, 2. A Random Value (Integer) per point feeds Instance on Points’ Instance Index, with Pick Instance checked.

Why it works: Instance on Points only accepts one instance input, so variety has to be made addressable: once each variant has a number, choosing one is just generating a random integer. Pick Instance is the switch that makes the index mean “choose one” instead of “stamp all three.” The base rocks use the identical three nodes.

Randomness that holds still

What happens: every Random Value hashes the element’s ID with a seed: same inputs, same output, every frame. Width, height, rotation, and the pick each get their own seed. Placement uses Poisson Disk distribution.

Why it works: hashing means nothing flickers during animation. Separate seeds keep properties uncorrelated; one shared seed would make every tall crystal also wide, and let you re-roll one property while the rest hold. Poisson Disk enforces minimum spacing, which is what natural scatter looks like; pure random clumps.

One slider grows everything

What happens: a single Grow input feeds two clamped Map Range nodes (one curve for width, one for height) multiplied into the scale. The base’s Map Range outputs 0.232–1.0 instead of 0–1.

Why it works: separate curves make the animation directable (sprout tall first, then thicken, or the reverse). The base’s 0.232 floor means it never fully vanishes, so nothing pops in from absolute zero at frame one.

Cheap until the end

What happens: everything upstream manipulates instances: transforms, not vertices. Realize Instances sits immediately before Group Output.

Why it works: an instance is a reference (“draw that mesh here, with this transform”), so a thousand crystals cost barely more than three. Realizing converts them to actual geometry, necessary for export, expensive in memory - so it’s deferred to the last possible node.


See each of these on the real tree →

Or grab the finished node group.