Logic Graphs¶
A logic graph is the visual scripting layer of IMMERSE. It lets you describe "when X happens, do Y, Z, and W" without writing code. You build it by dragging nodes and connecting wires.
Each room has its own logic graph. Cues in the room's cue list can fire trigger nodes in the graph; trigger nodes propagate to other nodes; those nodes apply side effects (DMX, GPIO, audio, video, transport).
When to use a logic graph vs. just stacking cues¶
Use cues when you want a sequence the operator can step through, one beat at a time.
Use a logic graph when you want one button-press to fan out into multiple simultaneous side effects, or when the same combination of effects fires from multiple places in the show.
Example: "door slam" is a perfect use case — when fired, you want a thump SFX + a relay click + a brief light flash, all simultaneously. Authoring this as three separate cues means the operator has to press GO three times in rapid succession, which they won't get right. Authoring it as a single trigger cue + a logic graph with three children fires all three from one GO.
The 8 node kinds¶
A logic graph in v0.1.0 supports 8 node kinds. Each has an input port (left side) and output port (right side), except triggers which only have output, and effect nodes which only have input.
| Kind | Inputs | Outputs | What it does |
|---|---|---|---|
| trigger | — | yes | Entry point. Fired by a cue or, in v0.2+, by an external event. |
| condition | yes | yes | (v0.1.0: passthrough) Will evaluate an expression and only propagate if true. |
| delay | yes | yes | (v0.1.0: passthrough log) Will wait N ms before propagating. |
| audio | yes | — | Play an audio file on a node. Same fields as an audio cue. |
| video | yes | — | Play a video on a node. |
| dmx | yes | — | Fire a Lighting Look. |
| gpio | yes | — | Drive a GPIO pin. |
| transport | yes | — | Start / stop / goto on the show TC. |
In v0.1.0, only a subset of these have full execution semantics: - trigger, dmx, gpio, transport — fully implemented - audio, video — log "deferred" (v0.2 will call Nodes for real) - condition, delay — passthrough (v0.2+ will evaluate / wait)
You can author with all 8 today; the Studio validator accepts them. Some just won't behave at runtime until v0.2.
Building a graph¶
Open the Logic module (Ctrl+4). The canvas is empty.
Add a node¶
Click a + <kind> button in the toolbar. The node appears at a default position. Drag to move it.
Edit node properties¶
Click a node to select. The Inspector on the right shows its fields. For an audio node:
- Label — what you call this node
- Audio Node — which Node
- File — which file to play
- Volume — 0..1
For a dmx node:
- Label
- Look — pick from the room's looks
(Same fields as the corresponding cue type.)
Wire nodes together¶
Click and drag from a node's output port (right side) to another node's input port (left side). A wire appears.
When the source fires, all wired-downstream nodes fire too.
Delete a wire¶
Click on the wire. Press Delete.
Delete a node¶
Click the node. Press Delete. Wires connected to it are also removed.
How firing works¶
When a cue fires a trigger: 1. Runtime starts at the trigger node 2. Walks the graph breadth-first 3. At each node, applies that node's side effect 4. Each node fires once per walk (cycles are broken by a visited-set)
So if your graph is:
…firing the trigger fires all three children simultaneously (within a few ms of each other — they're queued in JS event loop order, not literally parallel).
If you chain them:
In v0.1.0, the delay is a passthrough so flash and blackout fire ~immediately. In v0.2+, the delay will hold for 500 ms.
Patterns¶
Door slam (combined effect)¶
[trigger: door-slam] → [audio: slam.wav]
↘ [gpio: gp1 pulse 200ms]
↘ [dmx: flash-red look (50ms duration)]
One cue (Trigger type, references this trigger) fires all three.
Scene change (transport + lighting + ambient)¶
Conditional ending (v0.2+ when conditions evaluate)¶
[trigger: end] → [condition: scene == "act 1"] → [dmx: act-1-bow]
↘ [condition: scene == "act 2"] → [dmx: act-2-bow]
In v0.1.0, both DMX nodes will fire because conditions are passthrough. Author with this in mind.
Reusable trigger (same effect from multiple cues)¶
You don't need to duplicate the graph — one trigger can be fired from any cue (or even from multiple triggers in the future, when v0.2 adds trigger-input ports). Just have multiple cues all reference the same trigger node.
What graphs can't do (v0.1.0)¶
- Loops — cycles are broken; each node fires once per walk. No "play 5 times" via cycling.
- Variables / state — no way to remember "this fired twice already, do something different the third time"
- Math / expressions — condition node body is a string, but it's not parsed yet
- Cross-room — a graph in room A can't fire a node in room B
- External events — triggers only fire from cues. v0.2 may add network triggers (HTTP webhook fires a trigger).
Performance and limits¶
- Practical graph size: tested up to ~50 nodes per room. Large graphs render fine.
- Walk time: BFS over 50 nodes is sub-millisecond. Not a bottleneck.
- Side effect throughput: 50 GPIO calls in a single walk = 50 sequential HTTP POSTs to Pis. Takes 250-500ms total. Don't fan out to many GPIOs from a single trigger if timing matters.
Debugging graphs¶
Studio doesn't visualize "which path fired" at runtime — it has no live runtime connection. To debug:
- Validate first (Ctrl+8). Wires that point to nothing, nodes referencing missing audio nodes / looks, etc. all surface here.
- Fire-preview cues. Double-click a Trigger cue in the cue list — Studio logs the chain via notifications.
- Read the Runtime log at the venue. Each node fired during a walk is logged with its label. Mismatch between expected fired-count and actual reveals broken wires or missing references.
- Reduce, then add back. If a complex graph misbehaves, delete half the wires and test. Add back until it breaks. Faster than guessing.
Common mistakes¶
Wires going the wrong direction¶
Output → Input. If you wire input → output, Studio rejects it. (You'll see no wire appear.)
Trigger fires nothing¶
You added the trigger to the cue but didn't wire anything downstream. Trigger fires successfully but has no children, so nothing happens. Validator warns.
Trigger references missing logic node¶
You deleted the trigger node but a cue still references it. Validator catches this — cue references missing trigger node.
Visual cycles work, semantic cycles don't¶
You wire A → B → C → A. The BFS walk visits each node once and stops. It doesn't loop forever. Author intentionally — cycles are not "loops."
One trigger, multiple GO presses¶
You can fire a trigger more than once. Each press is a fresh BFS walk. Side effects layer up — second DMX fires while the first is still running, and last-write-wins on the wire. Plan for this.