Triggers, events & booleans
A boolean is a state — true or false, held until it changes. A trigger is an event — a single moment when something happens. Knowing which one you want is the key to making things fire at the right time.
State vs event
These two feel similar but behave very differently:
A boolean answers "is it true right now?" — a light switch that stays on. It's a value you can read every frame: a checkbox, "is the runner inside the zone?", "is the volume above the threshold?".
A trigger answers "did it just happen?" — a doorbell that rings once. It fires on the moment of change, then it's gone: "the runner entered the zone", "the beat hit", "the button was pressed".
DNA doesn't have a separate "trigger" type — a trigger is simply a boolean caught at the instant it changes. That moment of change is called an edge: a rising edge when something turns true, a falling edge when it turns false.
Rule of thumb: if you'd say "while …" you want a boolean (a held state). If you'd say "when …" you want a trigger (an edge/event).
The trigger button
Some parameters show a trigger button instead of a checkbox. Click it and it fires for a single frame, then resets itself — the hand-operated version of an event: "reset this feedback loop now", "fire this burst now". A checkbox, by contrast, stays where you leave it.
Turning one into the other
Boolean → trigger: detect the edge — the single frame where the value flips. The logic.compare node gives you both: a
result(the held boolean) and anedge(fires only on the frame the result changes).Trigger → boolean: remember it. utility.hold captures a value the moment a trigger fires and holds it until the next one. A utility.state_machine steps to its next state on each incoming trigger and then stays there.
Which node does which
| Node | Gives you | State or event |
|---|---|---|
| logic.logic | AND / OR / NOT / XOR of booleans | State (no memory) |
| logic.compare | result (A vs B) + an edge that fires on change | Both — state and event |
| data.conditional | routes data based on a condition | State |
| utility.hold | sample-and-hold: grab a value when triggered | Event in, value held out |
| utility.state_machine | advances state on a trigger; fires on each transition | Event-driven |
| query.trigger | which elements entered / are inside / exited a region | Event (enter/exit) + state (inside) |
| query.collision_detect | the same enter/exit moments, for contact | Event |
Events need identity
For "entered" and "exited" to mean anything, DNA has to know which element is which from one frame to the next — that's what the @id attribute is for. Points from sop.scatter or a particle sim already carry one, so query.trigger can tell you exactly which element crossed the line, not just that something did. See Attributes.
Triggers live in time — they only make sense while playback is advancing. A paused graph never produces an edge, because nothing is changing frame to frame. See Time & playback.
See also
Time & playback — edges happen between frames
Queries (sim-free) — region & contact events (enter/exit)
Parameter widgets — the trigger button
Attributes —
@id, the identity that makes enter/exit possible