Build an Operator Graph
std/visuals has ready-made operators — gfx.Noise, gfx.Blur, gfx.Displace, gfx.Composite
and more — that you wire into a graph instead of writing GLSL. Every operator, with its uniforms
and inputs, is in the std/visuals reference.
Chain operators
Section titled “Chain operators”Each constructor takes a name. Set uniforms with <<, and chain with >>, which feeds the left
node into the right one’s main input:
use "std/visuals" as gfx;
let field = gfx.Noise("field");field.parameter("period") << 2.0;
let soft = gfx.Blur("soft");soft.parameter("radius") << 8.0;
field >> soft >> screen;PLAY;A uniform takes a number, a signal, a meter feed, or an array of 2–4 numbers for a vector:
edge.parameter("strength") << Sine(8).range(0.5, 2.0);blur.parameter("radius") << drums.rms.smooth(80).range(0, 20);ramp.parameter("color0") << #[0.1, 0.0, 0.2];Feed a second input
Section titled “Feed a second input”An operator with two inputs names its second one. Bind a node to it with <<:
comp.parameter("b") << other; // Composite's input Bdisp.parameter("by") << field; // what Displace displaces bylook.parameter("gradient") << ramp; // Lookup's colour gradientUse one node in several places
Section titled “Use one node in several places”Keep the node in a variable and wire it wherever it is needed. It is drawn once per frame, and every consumer reads that result:
use "std/visuals" as gfx;
let field = gfx.Noise("field");field.parameter("period") << 2.0;
let soft = gfx.Blur("soft");soft.parameter("radius") << 6.0;let softer = gfx.Blur("softer");softer.parameter("radius") << 24.0;
let comp = gfx.Composite("comp");comp.parameter("operand") << 2.0; // subtract: A - Bfield >> soft >> comp; // Acomp.parameter("b") << (field >> softer); // B
comp >> screen;PLAY;Write a helper that builds nodes
Section titled “Write a helper that builds nodes”The name is the operator: the same name gives back the same node. A helper that builds its nodes with fixed names hands every caller the same ones, so take the name as an argument:
use "std/visuals" as gfx;
fn glow(name, src) { let b = gfx.Blur(name); b.parameter("radius") << 12.0; return src >> b;}
glow("halo", gfx.Noise("field")) >> screen;PLAY;Loop last frame back in
Section titled “Loop last frame back in”To read what the graph drew in the previous frame, build it inside gfx.feedback. The function
gets prev, last frame’s output; wire it into an input, and return the node that is the output:
use "std/visuals" as gfx;
let look = gfx.feedback(fn(prev) { let field = gfx.Noise("field"); field.parameter("period") << 3.0;
let disp = gfx.Displace("trail"); disp.parameter("amount") << 0.1; disp.parameter("by") << prev; return field >> disp;});
look >> screen;PLAY;Each frame displaces the noise by the frame before, which leaves a flowing trail.
The trail survives your edits. To wipe it and let it build again, reset the node the function returned:
look.reset();examples/05_visuals/04_voronoi_feedback.non is a whole patch built this way: cells that swell and
warp with a polyrhythm, using fan-out, feedback and audio-driven uniforms together.
Related
Section titled “Related”- The Visual Graph — names, wiring, fan-out and feedback, and why they work this way
- Bind Audio to a Shader — the audio feeds you bind to uniforms