Table of Contents
- ActionNode
- ButtonNode
- CaseSwitchNode
- ChangeSwitchNode
- ChangeSwitchNodeV2
- ClampNode
- ConnectionVariableNode
- CounterNode
- DelayNode
- DisplayNode
- EventGateNode
- EventOrderNode
- EventSwitchNode
- ExpressionNode
- FeedbackNode
- InternalActionNode
- InternalFeedbackNode
- IntervalNode
- LogicNode
- MathNode
- NFCNode
- OscListenerNode
- PriorityStackNode
- RestNode
- SchedulerNode
- StateGateNode
- StaticValueNode
- StringMergeNode
- TcpClientNode
- TcpServerNode
- UdpReceiverNode
- UdpSenderNode
- WebSocketClientNode
- WebSocketServerNode
- WorkflowRouterNode
- WorkflowVariableNode
- WorkflowVariableReadNode
- WorkflowVariableWriteNode
ActionNode
The ActionNode executes actions on connections, triggering them based on configurable conditions: on startup, when data changes, or when an event is received.
Features
- Flexible Triggering: Trigger on startup, data change, or incoming event
- Dynamic Options: Action options are validated against the action's own schema
- Input Overrides: Connection ID and action key can be overridden from inputs
- Change Detection: Tracks previous data to only fire when inputs actually change
Usage
Trigger on Event
Connect a trigger signal to the trigger input and enable triggerOnEvent. The action fires each time a trigger event arrives.
Trigger on Change
Enable triggerOnChange. The action fires whenever any input value changes.
Trigger on Startup
Enable triggerOnStartup. The action fires once when the workflow starts.
Node Structure
Config Schema
-
connectionId(string, optional): ID of the connection to run the action on -
actionKey(string, optional): Key identifying the action to execute -
triggerOnEvent(boolean, optional): Fire when a trigger event is received -
triggerOnStartup(boolean, optional, default:false): Fire on workflow startup -
triggerOnChange(boolean, optional, default:false): Fire when inputs change - Additional action-specific option fields
Input Schema
-
trigger(optional): Trigger signal — fires the action when an event arrives -
connectionId(string, optional): Override the configured connection ID -
actionKey(string, optional): Override the configured action key - Additional passthrough fields for action options
Output Schema
- (no outputs)
Implementation Details
- Merges input values with config values; inputs take precedence
- Validates action option inputs dynamically against the action definition's schema
- Executes via RPC with a 5000ms timeout
- Subscribes to action feedback after execution
Integration
The ActionNode is registered in:
-
NodeRegistryasaction -
NodeTypeSchemaas'action'
Example Workflow Usage
-
PTZ Camera Control: Connect a button press to
trigger, configure the connection and action key for pan/tilt -
Startup Initialisation: Enable
triggerOnStartupto send an init command when the workflow loads -
Reactive Control: Enable
triggerOnChangeand wire a variable so the action fires whenever the variable changes
ButtonNode
The ButtonNode provides a clickable UI button inside the workflow editor. Pressing it emits a trigger event that can be used to kick off downstream logic.
Features
- UI Interaction: Button is clickable directly in the workflow editor canvas
-
Event Emission: Publishes a
triggerevent on press, driving downstream nodes - Timestamp Output: Exposes the timestamp of the last press as a state value
Usage
Place a ButtonNode on the canvas and connect its timestamp output (or trigger event handle) to any node that accepts a trigger input, such as an ActionNode or DelayNode.
Node Structure
Config Schema
- (no configuration)
Input Schema
- (no inputs)
Output Schema
-
timestamp(number): Unix timestamp (ms) of the most recent button press
Implementation Details
- Responds to the
pressUI action - Publishes a
triggerevent immediately on press - Calls
workflow.rerenderFromNode()so downstream nodes update synchronously
Integration
The ButtonNode is registered in:
-
NodeRegistryasbutton -
NodeTypeSchemaas'button'
Example Workflow Usage
- Manual Trigger: Use as a manual start button to kick off a sequence of actions
- Test Harness: Wire a ButtonNode to any chain to manually drive it during development
CaseSwitchNode
The CaseSwitchNode is a workflow node that acts as a conditional router, passing through input values based on a conditional match. It's similar to a switch statement in programming languages.
Features
- Conditional Routing: Routes input based on a conditional value match
- Dynamic Input Cases: Supports multiple input cases with configurable conditions
- First Match Wins: Returns the first input case that matches the condition
- No Match Handling: Returns undefined when no condition matches
-
Default Fallback: Optional
defaultinput is returned when no case matches
Usage
Basic Switch
Conditional Input: "yes"
Cases:
- case1: condition="yes", input="Hello"
- case2: condition="no", input="Goodbye"
Result: "Hello" (first match)
Multiple Cases
Conditional Input: "red"
Cases:
- case1: condition="red", input="Stop"
- case2: condition="yellow", input="Caution"
- case3: condition="green", input="Go"
Result: "Stop" (matches "red")
No Match (with Default)
Conditional Input: "blue"
Cases:
- case1: condition="red", input="Stop"
- case2: condition="yellow", input="Caution"
Default: input="Unknown"
Result: "Unknown" (no case matched, returned default)
Node Structure
Input Schema
-
conditional(required): The value to match against case conditions -
case1,case2, ...,caseN(dynamic): Input values for each case -
default(optional): Fallback value used when no case matches
Config Schema
-
label(optional): Custom label for the node -
enabled(default:true): Whether the node is enabled -
inputVariables(array): Array of case configurations-
name(string): Case name (used as input handle ID) -
description(optional): Case description -
condition(string): Condition value to match against
-
Output Schema
-
result: The matched input value (or undefined if no match) -
matched(boolean): Whether a match was found -
matchedIndex(number, optional): Index of the matched case
Implementation Details
The CaseSwitchNode works by:
- Converting the conditional input to a string
- Iterating through all configured cases in order
- Comparing each case's condition with the conditional value
- Returning the first matching case's input value
- If no match is found, returning undefined (or the
defaultinput if provided)
Integration
The CaseSwitchNode is registered in:
-
NodeRegistryascaseSwitch -
NodeTypeSchemaas'caseSwitch'
Example Workflow Usage
- Status Router: Route different status messages based on a status code
- Language Selector: Route content based on language preference
- Error Handler: Route different error responses based on error type
- Menu System: Route to different menu options based on user selection
Comparison with Other Nodes
- LogicNode: Performs boolean operations, CaseSwitchNode routes based on value matching
- WorkflowRouter: Routes entire workflows, CaseSwitchNode routes individual values
- ExpressionNode: Evaluates expressions, CaseSwitchNode performs conditional routing
ChangeSwitchNode
The ChangeSwitchNode watches a boolean input and records timestamps whenever the value transitions between true and false. It acts as a change detector with separate outputs for each transition direction.
Features
- Change Detection: Only updates outputs when the boolean value actually changes
-
Dual Timestamp Outputs: Separate outputs for the last
truetransition and lastfalsetransition - State Preservation: Remembers the last value and timestamps across renders
Usage
Connect a boolean signal to valueA. The trueResult output updates with the current timestamp each time the value transitions to true, and falseResult updates when it transitions to false.
Input: false → true → true → false
trueResult: [updated] [unchanged]
falseResult: [unchanged] [updated]
Node Structure
Config Schema
- (no configuration)
Input Schema
-
valueA(boolean, optional): Boolean value to monitor
Output Schema
-
trueResult(number): Timestamp (ms) of the last transition totrue -
falseResult(number): Timestamp (ms) of the last transition tofalse
Implementation Details
- Stores
lastValue,lastTrueResult, andlastFalseResultin node state - Compares incoming value to
lastValue; if identical, outputs are unchanged - Does not emit events — use ChangeSwitchNodeV2 if event-driven behaviour is needed
Comparison with ChangeSwitchNodeV2
| Feature | ChangeSwitchNode | ChangeSwitchNodeV2 |
|---|---|---|
| State-based output | ✓ | ✓ |
| Emits events on change | ✗ | ✓ |
Integration
The ChangeSwitchNode is registered in:
-
NodeRegistryaschangeSwitch -
NodeTypeSchemaas'changeSwitch'
Example Workflow Usage
- Edge Detection: Detect rising and falling edges of a boolean feedback value
- Timestamp Logging: Record when a signal last went high or low
ChangeSwitchNodeV2
The ChangeSwitchNodeV2 is the event-emitting version of ChangeSwitchNode. It watches a boolean input and both updates timestamp outputs and emits events whenever the value transitions between true and false.
Features
- Change Detection: Only reacts when the boolean value actually changes
-
Dual Timestamp Outputs: Separate outputs for the last
trueandfalsetransitions -
Event Emission: Publishes
trueResultorfalseResultevents on each transition, enabling reactive downstream processing
Usage
Connect a boolean signal to valueA. On each true transition a trueResult event fires; on each false transition a falseResult event fires. Both events carry the current timestamp.
Input: false → true → true → false
Events emitted: trueResult falseResult
Node Structure
Config Schema
- (no configuration)
Input Schema
-
valueA(boolean, optional): Boolean value to monitor
Output Schema
-
trueResult(number): Timestamp (ms) of the last transition totrue -
falseResult(number): Timestamp (ms) of the last transition tofalse
Output Events
-
trueResult: Emitted when value transitions totrue -
falseResult: Emitted when value transitions tofalse
Implementation Details
- Behaves identically to ChangeSwitchNode with the addition of event publishing
- Calls
workflow.rerenderFromNode()on each transition so downstream nodes react immediately - Both output handles are event handles (
isOutputHandleEvent()returnstruefor both)
Comparison with ChangeSwitchNode
| Feature | ChangeSwitchNode | ChangeSwitchNodeV2 |
|---|---|---|
| State-based output | ✓ | ✓ |
| Emits events on change | ✗ | ✓ |
Integration
The ChangeSwitchNodeV2 is registered in:
-
NodeRegistryaschangeSwitchV2 -
NodeTypeSchemaas'changeSwitchV2'
Example Workflow Usage
-
Trigger on Rising Edge: Connect the
trueResultevent to an ActionNode to fire an action only when the signal goes high -
Toggle Animations: Use
trueResult/falseResultevents to start/stop different sequences
ClampNode
The ClampNode constrains a numeric value to stay within a configured minimum and maximum range.
Features
-
Value Clamping: Ensures the output never exceeds
maxor falls belowmin -
Configurable Bounds: Both bounds are set in config and validated (
minmust be ≤max) - Type Coercion: String inputs are coerced to numbers before clamping
Usage
min: 0, max: 100, value: 150 → result: 100
min: 0, max: 100, value: -10 → result: 0
min: 0, max: 100, value: 50 → result: 50
Node Structure
Config Schema
-
min(number, default:0): Lower bound -
max(number, default:1, must be ≥min): Upper bound
Input Schema
-
value(unknown, coerced to number, optional): Value to clamp
Output Schema
-
result(number): Clamped value
Implementation Details
- Uses
Math.min(Math.max(value, min), max) - Validation rejects configs where
min > max
Integration
The ClampNode is registered in:
-
NodeRegistryasclamp -
NodeTypeSchemaas'clamp'
Example Workflow Usage
- Volume Control: Clamp a volume level to 0–100 before sending it to a mixer
- Safe Range: Ensure a position or speed value never exceeds hardware limits
ConnectionVariableNode
The ConnectionVariableNode reads the current value of a variable from a specific connection and subscribes to live updates whenever that variable changes.
Features
- Live Variable Subscription: Automatically updates whenever the connection variable changes
- Reactive: Triggers a workflow re-render on each update
- Config-Driven: Connection ID and variable key are set in config and can be changed at runtime
Usage
Configure the connectionId and variableKey. The value output will reflect the current value of that variable, updating automatically as the connection reports changes.
Node Structure
Config Schema
-
connectionId(string): ID of the connection to read from -
variableKey(string): Key of the variable to read
Input Schema
- (no inputs)
Output Schema
-
value(string | number | boolean | null | undefined): Current value of the variable
Implementation Details
- Subscribes to variable changes via the system router
- Caches the current config; when config changes, cleans up the old subscription and creates a new one
- Fetches the current value on each render to ensure freshness
- Cleans up the subscription on node unmount
Integration
The ConnectionVariableNode is registered in:
-
NodeRegistryasconnectionVariable -
NodeTypeSchemaas'connectionVariable'
Example Workflow Usage
- Live Status: Read a mixer fader level variable and feed it into a LogicNode or DisplayNode
- Reactive Logic: Drive conditional behaviour based on a connection's current variable state
- Cross-Node Data: Pipe a connection variable into a MathNode or ExpressionNode for further processing
CounterNode
The CounterNode maintains a persistent numeric counter that can be incremented, decremented, set, or reset through both state inputs and events.
Features
- Full Counter Operations: Increment by 1, decrement by 1, add an amount, subtract an amount, set to a value, or reset to the initial value
- Event and State Support: Operations can be driven by both state inputs and event signals
- Configurable Initial Value: Set the starting value for the counter and for resets
- UI Actions: Supports direct increment/decrement/set actions from the editor UI
Usage
initialValue: 0
increaseOne event → value: 1
increaseOne event → value: 2
decreaseOne event → value: 1
set input: 10 → value: 10
reset event → value: 0
Node Structure
Config Schema
-
initialValue(string | number, coerced to number, default:0): Starting value and reset target
Input Schema
-
set(string | number, optional): Set the counter to this value -
reset(string | number | boolean, optional): Reset toinitialValuewhen truthy -
increaseOne(string | number | boolean, optional): Increment by 1 when truthy -
increaseAmount(string | number, optional): Add this amount to the counter -
decreaseOne(string | number | boolean, optional): Decrement by 1 when truthy -
decreaseAmount(string | number, optional): Subtract this amount from the counter
Input Events
-
increaseOne: Increment by 1 -
decreaseOne: Decrement by 1 -
increaseAmount: Add the event payload value -
decreaseAmount: Subtract the event payload value -
set: Set to the event payload value -
reset: Reset toinitialValue
Output Schema
-
value(number): Current counter value
Output Events
-
value: Emitted whenever the counter value changes
Implementation Details
- Tracks
lastSeenInputsto detect state changes between renders - Operations from both state inputs (on change detection) and events are supported
- The counter value is persisted in node state between renders
Integration
The CounterNode is registered in:
-
NodeRegistryascounter -
NodeTypeSchemaas'counter'
Example Workflow Usage
- Tally Counter: Count button presses or event occurrences
- Loop Index: Use with an IntervalNode to increment a counter each tick and reset at a limit
- Score Tracker: Increment/decrement a score based on feedback events
DelayNode
The DelayNode passes a payload value through after a configurable time delay. Multiple payloads can be in-flight simultaneously, each delayed by the same duration.
Features
- Configurable Delay: Set the delay in milliseconds (0 ms – 10 minutes)
-
Input Override: Delay duration can be overridden at runtime via the
delayinput - Buffered Payloads: Multiple events arriving in quick succession are each delayed independently
- Timeout Management: Pending timeouts are cleared if the delay config changes
Usage
delay: 1000ms, payload: "hello"
After 1 second → passthrough: "hello"
delay: 500ms, payloads arrive at t=0 and t=200ms
t=500: "first payload" emitted
t=700: "second payload" emitted
Node Structure
Config Schema
-
delay(number, min:0, max:600000, default:1000): Delay in milliseconds
Input Schema
-
delay(number, optional): Overrides config delay for this render -
payload(unknown, optional): Value to delay
Input Events
-
payload: Queues the carried value to be emitted after the delay
Output Schema
-
passthrough(unknown): The payload value, emitted after the delay
Implementation Details
- Each incoming
payloadevent schedules asetTimeoutfor the configured delay - When the delay config changes, all pending timeouts are cancelled and the array is cleared
- Timeout handles are stored in an array and cleaned up on node unmount
Integration
The DelayNode is registered in:
-
NodeRegistryasdelay -
NodeTypeSchemaas'delay'
Example Workflow Usage
- Debounce: Add a short delay before an action to avoid triggering on transient signals
- Timed Sequence: Chain multiple DelayNodes to create a timed sequence of actions
- Hold Signal: Delay a feedback value by a fixed offset to synchronise it with another signal
DisplayNode
The DisplayNode is a simple passthrough node for visualising a value inside the workflow editor. It caches and forwards whatever value it receives, making it useful for debugging and monitoring.
Features
- Value Visualisation: Displays the current value directly on the node in the editor canvas
-
Event Support: Responds to
valueevents as well as state updates - Passthrough Output: Forwards the received value downstream unchanged
- Configurable Label: The display label can be customised
Usage
Connect any output to the value input. The current value is shown on the node and is also available as an output for further processing.
Node Structure
Config Schema
-
label(string, optional, default:'Value'): Label shown on the node -
enabled(boolean, default:true): Whether the node is active
Input Schema
-
value(unknown): The value to display and pass through
Output Schema
-
value(unknown): The input value, forwarded unchanged
Implementation Details
- Caches the most recent value in an internal property
- Responds to
valueevents viaonEvent, updating the cache and re-rendering - Primarily intended for UI observability during workflow development
Integration
The DisplayNode is registered in:
-
NodeRegistryasdisplay -
NodeTypeSchemaas'display'
Example Workflow Usage
- Debug Monitor: Insert between two nodes to inspect intermediate values during development
- Status Display: Wire a connection variable to a DisplayNode to show its current value on the canvas
EventGateNode
The EventGateNode is an event-driven gate that passes events through only when open, and blocks them when closed. It supports both state-based and event-based control modes.
Features
- Event Gating: Blocks or passes events based on gate state
- Two Control Modes: Gate state can be driven by a continuous boolean input (state mode) or by discrete open/close/toggle events (event mode)
- Configurable Initial State: The gate can start open or closed
- Pass-through Output: Forwards the last allowed event payload as a state value
Usage
State Mode
Set controlMode to 'state' and connect a boolean to the open input. Events pass through whenever open is truthy.
Event Mode
Set controlMode to 'event' and send open, close, or toggle events to control the gate. An event input event passes a payload through only if the gate is currently open.
Node Structure
Config Schema
-
label(string, optional): Node label -
controlMode('state'|'event', default:'event'): How the gate is controlled -
initiallyOpen(boolean, default:true): Starting open/closed state
Input Schema
-
open(boolean | string | number, optional): Gate control signal (state mode)
Output Schema
-
value(unknown, optional): Last payload that passed through the gate -
isOpen(boolean): Current open/closed state of the gate
Output Events
-
out: Emitted when a payload passes through the gate
Input Events (event mode)
-
open: Open the gate -
close: Close the gate -
toggle: Toggle the gate state -
reset: Reset to the configured initial state -
event: Pass a payload through (only if gate is open)
Implementation Details
- In event mode, gate state persists between renders
-
isOutputHandleEvent()returnstruefor theouthandle - In state mode, gate state is derived directly from the
openinput each render
Integration
The EventGateNode is registered in:
-
NodeRegistryaseventGate -
NodeTypeSchemaas'eventGate'
Example Workflow Usage
- Conditional Event Routing: Only allow trigger events through when a feedback state is active
- One-shot Gate: Open the gate via an event, let one payload through, then close it
- Arming Circuit: Open the gate only when a specific condition is met, preventing accidental action triggers
EventOrderNode
The EventOrderNode validates that a set of events arrives in a specific sequential order. It emits a fulfilled event only when all events have been received in the correct sequence.
Features
- Ordered Sequence Validation: Tracks whether events arrive in the configured order (event1 → event2 → … → eventN)
- Two Modes: Choose between ignoring out-of-order events (Wait) or resetting the sequence (Reset)
- Configurable Sequence Length: Supports sequences of 2–20 events
-
Completion Event: Emits
fulfilledwhen the full sequence is correctly completed
Usage
Connect event sources to the numbered event inputs in order. Trigger event1 first, then event2, and so on. When the final event in the sequence arrives, the fulfilled event fires.
Sequence: event1 → event2 → event3
Correct: event1 ✓ → event2 ✓ → event3 ✓ → [fulfilled emitted]
Wrong (Reset mode): event1 ✓ → event3 ✗ → [reset, start over]
Wrong (Wait mode): event1 ✓ → event3 ✗ → [ignored, still waiting for event2]
Node Structure
Config Schema
-
mode('Wait'|'Reset', default:'Reset'): Behaviour when an out-of-order event is received -
numberOfInputs(number, min: 2, max: 20, default: 10): Length of the required sequence
Input Schema
-
event1…event10(fixed set): Event inputs in sequence order
Output Schema
-
state(boolean): Whether the full sequence has been completed -
next(number): Index of the next expected event in the sequence
Implementation Details
- Maintains
expectedEventIndexandcurrentStatein node state - Wait mode: Out-of-order events are silently ignored
-
Reset mode: Out-of-order events reset
expectedEventIndexto 0 - On sequence completion, publishes the
fulfilledevent and resets for the next cycle
Integration
The EventOrderNode is registered in:
-
NodeRegistryaseventOrder -
NodeTypeSchemaas'eventOrder'
Example Workflow Usage
- Combination Lock: Require a specific sequence of button presses before triggering an action
- Multi-step Handshake: Validate that a set of network or device events arrive in the correct protocol order
- Safety Interlock: Only allow an action when a required startup sequence has completed in order
EventSwitchNode
The EventSwitchNode sets its output value by responding to named events. Each event is mapped to a specific value, making it easy to drive a downstream value from discrete event signals.
Features
- Event-Driven Value Selection: Each named event sets the output to its configured value
- Configurable Event Map: Any number of events can be defined, each with a name and value
-
Reset Support: A
resetevent returns the output to the initial value - Persistent Value: The current value is stored and survives re-renders
Usage
Define a set of events and their corresponding values in the config. When any of those events fires, the output value updates to the mapped value.
Events config:
- name: "on", value: true
- name: "off", value: false
Fire "on" → output: true
Fire "off" → output: false
Fire "reset" → output: <initialValue>
Node Structure
Config Schema
-
label(string, optional): Node label -
enabled(boolean, default:true): Whether the node is active -
initialValue(unknown, optional): Value to use before any event fires, and after areset -
events(array of{name, value}, default:[]): The event-to-value mappings
Input Schema
- (no inputs)
Output Schema
-
value(unknown): The current value as set by the most recent event
Input Events
-
reset: Reset the output toinitialValue -
event_<name>: Set the output to the value mapped to<name>
Implementation Details
- Caches
currentValuebetween renders - On
onConfigChange, applies any change toinitialValue - Event names in the config are prefixed with
event_internally
Integration
The EventSwitchNode is registered in:
-
NodeRegistryaseventSwitch -
NodeTypeSchemaas'eventSwitch'
Example Workflow Usage
- State Machine: Drive a string output through a set of named states via events
- Scene Selector: Map scene-select button presses to scene name strings
- Mode Toggle: Cycle between operating modes by firing named events
ExpressionNode
The ExpressionNode is a workflow node that evaluates expressions using the companion expression library. It mimics the LogicNode structure but provides more powerful expression evaluation capabilities with configurable inputs.
Features
- Expression Evaluation: Supports complex mathematical and logical expressions
- Variable Injection: Can use variables from the workflow context
- Configurable Inputs: Supports 1-20 dynamic input variables
- Expression Mode: Uses the TextWithVariableInput component in expressionable mode
- Error Handling: Provides clear error messages for invalid expressions
Usage
Basic Expression
_EXP_(1 + 2)
Result: 3
Using Dynamic Input Variables
_EXP_($(var1) + $(var2))
With input variables: var1: 5, var2: 3
Result: 8
Using Variables and Dynamic Inputs
_EXP_($(var1) > $(threshold) ? 'High' : 'Low')
With input variables: var1: 15, threshold: 10
Result: 'High'
String Interpolation
Hello $(var1)!
With input variables: var1: 'World'
Result: Hello World!
Node Structure
Input Schema
-
expression(optional): The expression string to evaluate -
variables(optional): Variables available to the expression -
var1,var2, ...,varN(dynamic): Input variables based on numOfInputs configuration
Config Schema
-
label(optional): Custom label for the node -
enabled(default:true): Whether the node is enabled -
numOfInputs(default:1, min:1, max:20): Number of dynamic input variables -
expression(default:'_EXP_()'): The default expression
Output Schema
-
result: The evaluated result (can be any type)
Implementation Details
The ExpressionNode uses the companion expression library:
-
ParseExpression: Parses the expression string into an AST -
ResolveExpression: Evaluates the parsed expression with variables -
ExpressionFunctions: Provides built-in functions for expressions
The node supports two modes:
-
Expression Mode: When the input starts with
_EXP_(and ends with) -
Variable Injection Mode: For simple string interpolation with
$(variable)syntax
Integration
The ExpressionNode is registered in:
-
NodeRegistryasexpression -
NodeTypeSchemaas'expression'
Example Workflow Usage
-
Simple Calculator: Set numOfInputs to 2, expression to
_EXP_($(var1) + $(var2)) -
Conditional Logic: Set numOfInputs to 3, expression to
_EXP_($(var1) > $(var2) ? $(var3) : 'default') -
String Formatting: Set numOfInputs to 1, expression to
Hello $(var1), the time is $(time.hh:mm:ss)!
FeedbackNode
The FeedbackNode monitors the state of a feedback source on a connection and exposes it as a boolean output. It subscribes to live updates, so the output reflects the current state at all times.
Features
- Live Subscription: Automatically updates when the feedback state changes on the connection
-
Boolean Output: Normalises feedback state to
true,false, ornull - Dynamic Options: Feedback options are validated against the feedback definition's schema
- Config-Driven Resubscription: Cleanly resubscribes when connection or feedback key changes
Usage
Configure the connection ID, feedback key, and any required options. The state output will reflect the current boolean state of that feedback source.
Node Structure
Config Schema
-
connectionId(string): ID of the connection to monitor -
feedbackKey(string): Key identifying the specific feedback to watch -
options(record of string → string | number): Feedback-specific options
Input Schema
- (no inputs)
Output Schema
-
state(boolean | null): Current state of the feedback (nullif not yet received)
Implementation Details
- Subscribes to feedback state changes via the system router
- Validates options against the feedback definition schema on each config change
- Unsubscribes from the previous feedback before resubscribing when config changes
- Cleans up all subscriptions on node unmount
Integration
The FeedbackNode is registered in:
-
NodeRegistryasfeedback -
NodeTypeSchemaas'feedback'
Example Workflow Usage
- Mute Indicator: Monitor an audio console mute feedback and drive a logic node based on its state
-
Conditional Action: Wire
stateinto a LogicNode to only execute an action when a specific feedback is active -
Display Status: Connect
stateto a DisplayNode to visualise a connection's current feedback state
InternalActionNode
The InternalActionNode executes internal system actions — actions that are not tied to a specific device connection. It supports the same triggering modes as ActionNode.
Features
- Internal Actions: Targets the built-in system action registry rather than a connection
- Flexible Triggering: Trigger on startup, data change, or incoming event
- Dynamic Options: Action options are validated against the action's own schema
- Input Overrides: Action key can be overridden from inputs
Usage
Select an internal action key in the config and choose a trigger mode. Connect a trigger signal to the trigger input for event-driven execution.
Node Structure
Config Schema
-
actionKey(string, optional): ID of the internal action to execute -
triggerOnEvent(boolean, optional): Fire when a trigger event is received -
triggerOnChange(boolean, optional): Fire when inputs change - Additional action-specific option fields
Input Schema
-
trigger(optional): Trigger signal — fires the action when an event arrives -
actionKey(string, optional): Override the configured action key - Additional passthrough fields for action options
Output Schema
- (no outputs)
Implementation Details
- Uses the
internalActionsregistry to resolve and validate the action - Executes via
rpcClient.orchestrator.runInternalActionwith a 5000ms timeout - Otherwise behaves identically to ActionNode
Integration
The InternalActionNode is registered in:
-
NodeRegistryasinternalAction -
NodeTypeSchemaas'internalAction'
Example Workflow Usage
- Page Navigation: Trigger an internal page-change action from a button press
- System Reset: Fire a system-level reset action on workflow startup
InternalFeedbackNode
The InternalFeedbackNode monitors the state of an internal system feedback source (not tied to a device connection) and exposes its state as a boolean output.
Features
- Internal Feedback: Targets the built-in internal feedback registry
- Live Subscription: Updates automatically when the feedback state changes
-
Boolean Output: Normalises feedback state to
true,false, ornull - Mapping Support: Decodes option mappings from JSON strings when needed
Usage
Select an internal feedback key and configure any required options. The state output will reflect the current boolean state.
Node Structure
Config Schema
-
feedbackKey(string): ID of the internal feedback to monitor -
options(record of string → string | number | boolean | array): Feedback-specific options
Input Schema
- (no inputs)
Output Schema
-
state(boolean | null): Current state of the feedback
Implementation Details
- Uses the
internalFeedbacksregistry to resolve and validate the feedback - Decodes option values that are JSON strings (e.g. mappings stored as serialised arrays)
- Cleans up subscriptions on node unmount
Integration
The InternalFeedbackNode is registered in:
-
NodeRegistryasinternalFeedback -
NodeTypeSchemaas'internalFeedback'
Example Workflow Usage
- Page State: Monitor which page is currently active and use the result to drive conditional logic
- System Status: Expose an internal system state as a boolean for downstream processing
IntervalNode
The IntervalNode fires a trigger event repeatedly at a fixed interval, like a clock tick. It is useful for polling, periodic actions, and animation loops.
Features
-
Periodic Triggering: Emits a
triggerevent at every configured interval - Configurable Rate: Set interval from 100ms to 10 minutes
- Auto-Restart: Clears and restarts the interval whenever the config changes
- Timestamp Output: Exposes the timestamp of the most recent tick
Usage
Set the interval in milliseconds. The node will emit a trigger event and update timestamp on every tick.
interval: 1000ms → trigger event fires every second
Node Structure
Config Schema
-
interval(number, min:100, max:600000, default:1000): Interval in milliseconds
Input Schema
- (no inputs)
Output Schema
-
timestamp(number): Unix timestamp (ms) of the most recent tick
Output Events
-
trigger: Emitted on every interval tick
Implementation Details
- Uses
setIntervalinternally - Restarts the interval when the config changes to apply the new duration immediately
- Calls
workflow.rerenderFromNode()on each tick to propagate the updated timestamp - Cleans up the interval on node unmount
Integration
The IntervalNode is registered in:
-
NodeRegistryasinterval -
NodeTypeSchemaas'interval'
Example Workflow Usage
- Polling Loop: Trigger a feedback read or variable check every second
- Animation Tick: Drive an animation or counter update at a regular cadence
- Heartbeat: Send a periodic keep-alive action to a connected device
LogicNode
The LogicNode evaluates a logical or comparison operation between two values and outputs a boolean result. It supports numeric comparisons, strict equality, and boolean logic operators.
Features
-
Comparison Operators:
==,!=,>,<,>=,<=,===,!== -
Boolean Operators:
AND,OR,XOR,NOT - Input and Config Values: Both values can be supplied via config (static) or inputs (dynamic)
- Type Coercion: Numeric comparisons coerce string inputs to numbers
Usage
Comparison
valueA: 10, operator: ">", valueB: 5 → result: true
valueA: "on", operator: "==", valueB: "on" → result: true
Boolean Logic
valueA: true, operator: "AND", valueB: false → result: false
valueA: true, operator: "NOT" → result: false
Node Structure
Config Schema
-
valueA(string | number | boolean, optional): Left-hand operand -
operator(enum, optional): One of==!=><>=<====!==ANDORXORNOT -
valueB(string | number | boolean, optional): Right-hand operand
Input Schema
-
valueA(string | number | boolean, optional): Overrides configvalueA -
operator(enum, optional): Overrides configoperator -
valueB(string | number | boolean, optional): Overrides configvalueB
Output Schema
-
result(boolean): Result of the logical operation
Implementation Details
- Default operator is
==when none is configured -
NOTis a unary operator — onlyvalueAis used - Numeric operators (
>,<,>=,<=) cast both values to numbers before comparing - Input values take precedence over config values
Integration
The LogicNode is registered in:
-
NodeRegistryaslogic -
NodeTypeSchemaas'logic'
Example Workflow Usage
-
Threshold Check:
valueA= sensor reading,operator=>,valueB= threshold constant -
Gate Condition: Feed
resultinto a StateGateNode or EventGateNode -
Inverter: Use
NOTto invert a boolean feedback state
MathNode
The MathNode performs a basic arithmetic operation on two numbers and outputs the result.
Features
- Four Arithmetic Operations: Addition, subtraction, multiplication, division
- Type Coercion: String inputs are coerced to numbers automatically
- Input and Config Values: Both operands can come from config (static) or inputs (dynamic)
Usage
numberA: 10, operation: "add", numberB: 5 → result: 15
numberA: 10, operation: "subtract", numberB: 3 → result: 7
numberA: 4, operation: "multiply", numberB: 6 → result: 24
numberA: 20, operation: "divide", numberB: 4 → result: 5
Node Structure
Config Schema
-
numberA(string | number, coerced to number, optional): Left-hand operand -
operation('add'|'subtract'|'multiply'|'divide', optional): Operation to perform -
numberB(string | number, coerced to number, optional): Right-hand operand
Input Schema
-
numberA(string | number, coerced to number, optional): Overrides confignumberA -
operation(enum, optional): Overrides configoperation -
numberB(string | number, coerced to number, optional): Overrides confignumberB
Output Schema
-
result(number): Result of the arithmetic operation
Implementation Details
- Default operation is
add - Input values take precedence over config values
- Division does not guard against divide-by-zero; the result will be
InfinityorNaN
Integration
The MathNode is registered in:
-
NodeRegistryasmath -
NodeTypeSchemaas'math'
Example Workflow Usage
- Offset: Add a fixed offset to a sensor value before sending it downstream
- Scale: Multiply a normalised (0–1) value by 100 to get a percentage
- Counter Arithmetic: Combine with CounterNode to compute derived values
NFCNode
The NFCNode listens for NFC card read events from a specific surface position (or all positions) and exposes the tag ID, surface, position, and timestamp.
Features
- NFC Event Subscription: Reacts to NFC card reads from physical surface positions
- Position Filtering: Can listen to all positions or a specific position ID
-
Event Emission: Publishes an
nfcReadevent with the full read payload - Persistent Last Read: Stores the most recent read so state values are always current
Usage
Leave positionId as null to receive reads from any position, or configure a specific position ID to filter to a single position.
Node Structure
Config Schema
-
positionId(string | null, default:null): Position to listen to, ornullfor all positions
Input Schema
- (no inputs)
Output Schema
-
nfcId(string | null): ID of the NFC tag that was read -
surfaceId(string | null): Surface where the tag was read -
positionId(string | null): Position where the tag was read -
timestamp(number | null): Timestamp of the read event
Output Events
-
nfcRead: Emitted on each NFC read, carrying the full payload
Implementation Details
- Subscribes to position NFC events via the system router
- Filters by
positionIdif one is configured - Calls
workflow.rerenderFromNode()on each read to update downstream nodes - Cleans up the subscription on node unmount
Integration
The NFCNode is registered in:
-
NodeRegistryasnfc -
NodeTypeSchemaas'nfc'
Example Workflow Usage
- Access Control: Trigger an action when a specific NFC tag is scanned at a position
- Asset Tracking: Log or display the ID of the last NFC tag read
-
Multi-Position Monitor: Listen to all positions and route based on
positionIdoutput
OscListenerNode
The OscListenerNode starts an OSC (Open Sound Control) UDP server and listens for incoming messages on configured paths. Each matched path emits a named event carrying the message parameters.
Features
- OSC Server: Hosts a UDP-based OSC listener on a configurable port
-
Path Matching: Supports exact paths, named params (
:name), wildcards (*,**), and glob patterns - Named Endpoints: Each endpoint has a stable ID that becomes the event handle name
- Parameter Extraction: Named route parameters are extracted and available as outputs
- Legacy Path Support: Backwards-compatible with the older array-of-strings path format
Usage
Configure endpoints with OSC paths. When a matching OSC message arrives, the corresponding event fires with the message parameters.
Endpoint: id="scene", path="/scene/:name"
Incoming: /scene/main → event "scene" fires, params.name = "main"
Endpoint: id="fader", path="/fader/*"
Incoming: /fader/1 → event "fader" fires
Node Structure
Config Schema
-
label(string, optional): Node label -
enabled(boolean, default:true) -
port(number, min:1024, max:65535): UDP port to listen on -
endpoints(array of{id, path}, default:[]): Named endpoint definitions -
paths(array of string, default:[]): Legacy path list (deprecated)
Input Schema
- Dynamic fields matching endpoint IDs (for state-based access)
Output Schema
- Dynamic fields for each endpoint: carries the last received parameters and payload
-
params(object): Named route parameters extracted from the path pattern
Output Events
- One event per endpoint ID, fired when a matching message is received
Implementation Details
- Starts an OSC UDP server on mount and restarts it on config changes
- Path patterns are compiled to regex for efficient matching
- Named params use
:paramNamesyntax; wildcards use*(single segment) or**(multi-segment) - Results are cached per endpoint ID so state values are always populated
Integration
The OscListenerNode is registered in:
-
NodeRegistryasosc -
NodeTypeSchemaas'osc'
Example Workflow Usage
-
Mixing Console: Listen for
/channel/:num/fadermessages and route them to connection actions - Lighting Control: Receive OSC cues from a lighting console and trigger companion actions
- Multi-Parameter: Use named params to extract values directly from the OSC path
PriorityStackNode
The PriorityStackNode selects a value from a set of inputs based on a configurable priority rule. When multiple inputs are active, the priority mode determines which one wins.
Features
- Multiple Priority Modes: top-to-bottom, bottom-to-top, last-changed, first-changed
- Fallback Value: Returns a configurable fallback when no inputs are active
- Active Input Tracking: Maintains a set of currently active inputs and their change timestamps
- Ordered Output: Also exposes the full ordered list of active input IDs
Usage
Add named inputs in the config. When those inputs receive truthy values, they are considered "active". The node selects the value of the highest-priority active input according to the chosen mode.
Inputs config: [A, B, C] (priority mode: topToBottom)
A = "hello" (truthy), B = false, C = "world" (truthy)
Result: "hello" (A has higher priority than C)
Node Structure
Config Schema
-
label(string, optional): Node label -
enabled(boolean, default:true) -
fallbackValue(unknown, optional): Value returned when no inputs are active -
inputs(array of{id, label}, default:[]): The named inputs to manage -
priorityMode('topToBottom'|'bottomToTop'|'lastChange'|'firstChange', default:'topToBottom'): How to select the winner
Input Schema
- Dynamic inputs matching the configured input IDs (boolean | string | number)
Output Schema
-
value(unknown, optional): Value of the highest-priority active input, orfallbackValue -
ordered(string[]): Ordered list of active input IDs from highest to lowest priority
Implementation Details
- An input is active if its value is truthy (non-zero, non-empty, non-false, non-null)
-
topToBottom/bottomToTopuse the position of the input in theinputsconfig array -
lastChange/firstChangeuse the timestamp of when each input last became active - Change timestamps are stored per input ID in
lastChangeTs
Integration
The PriorityStackNode is registered in:
-
NodeRegistryaspriorityStack -
NodeTypeSchemaas'priorityStack'
Example Workflow Usage
- Layer Priority: Show the most recently activated overlay source
- Fallback Input: Select from a ranked list of video sources, showing the highest-priority active one
-
Last-In-Wins: Use
lastChangemode so the most recently activated input always wins
RestNode
The RestNode hosts a Fastify HTTP server with configurable REST API endpoints. GET endpoints return current input values; POST endpoints emit events and cache received request bodies.
Features
- HTTP Server: Spins up a Fastify server on a configurable port
- GET and POST Endpoints: GET returns live state data; POST captures body data and fires an event
- Bearer Token Auth: Optional token-based authentication per request
-
Rate Limiting: Configurable request rate limits via
@fastify/rate-limit - Named Endpoints: Each endpoint has a stable ID used as the event handle
- Auto-Restart: Server restarts automatically on config changes
Usage
GET Endpoint
Configure a GET endpoint with path /status. The response will include the current value of the status input.
POST Endpoint
Configure a POST endpoint with path /trigger. When a POST request arrives, a trigger event fires with the request body as its payload.
Node Structure
Config Schema
-
label(string, optional): Node label -
enabled(boolean, default:true) -
port(number, min:1024, max:65535): HTTP port -
rateLimit(optional):{max: number, timeWindow: number}— request rate limit -
bearerTokens(array of{id, token}, default:[]): Allowed bearer tokens -
endpoints(array of{id, path, method}, default:[]): Configured endpoints
Input Schema
- Dynamic fields matching GET endpoint IDs (data returned in GET responses)
Output Schema
- Dynamic fields matching POST endpoint IDs (last received body data)
Output Events
- One event per POST endpoint ID, fired on each request
Implementation Details
- Uses Fastify with
@fastify/rate-limitplugin - Bearer token authentication checks the
Authorization: Bearer <token>header - POST endpoints cache the request body and emit an event
- GET endpoints return the current input value for that endpoint ID
- Server is fully restarted on any config change
Integration
The RestNode is registered in:
-
NodeRegistryasrest -
NodeTypeSchemaas'rest'
Example Workflow Usage
- Webhook Receiver: Receive webhook POSTs from external services and trigger workflow actions
- Status API: Expose current workflow state as a GET endpoint for external monitoring
- Remote Control: Trigger companion actions via HTTP requests from a control surface or script
SchedulerNode
The SchedulerNode triggers on a cron schedule. It emits a trigger event and updates a timestamp output each time the cron expression fires.
Features
- Cron Scheduling: Uses standard cron expressions for flexible scheduling
-
Event Emission: Publishes a
triggerevent on each scheduled tick - Auto-Restart: Stops and restarts the cron task when the expression changes
- Comprehensive Logging: Logs cron lifecycle events for debugging
Usage
Set a valid cron expression in cronExpression. The node fires at each matching time.
cronExpression: "*/5 * * * *" → fires every 5 minutes
cronExpression: "0 9 * * 1-5" → fires at 9am on weekdays
cronExpression: "0 0 * * *" → fires at midnight every day
Node Structure
Config Schema
-
cronExpression(string): A valid cron expression
Input Schema
- (no inputs)
Output Schema
-
timestamp(number): Unix timestamp (ms) of the most recent cron tick
Output Events
-
trigger: Emitted on each cron tick
Implementation Details
- Uses the
node-cronlibrary - Manages a single
ScheduledTaskinstance, replacing it when the expression changes - Logs
scheduled,started,stopped, anddestroyedlifecycle events - Cleans up the task on node unmount
Integration
The SchedulerNode is registered in:
-
NodeRegistryasscheduler -
NodeTypeSchemaas'scheduler'
Example Workflow Usage
- Daily Report: Trigger a sequence of actions every morning at a specific time
- Business Hours: Fire events only during working hours using day-of-week and hour ranges
- Periodic Sync: Refresh connection state or send a sync command at regular intervals
StateGateNode
The StateGateNode passes a payload value through to its output when the gate is open, and blocks it when closed. Unlike EventGateNode it operates on continuous state values rather than events.
Features
-
State Gating: Passes
payloadthrough when open; returnsfallbackor cached value when closed - Two Control Modes: Gate state driven by a boolean input (state mode) or by discrete events (event mode)
- Fallback Value: Optional fallback output when the gate is closed
- Value Caching: Remembers the last payload seen while open
Usage
State Mode
Connect a boolean to the open input. While truthy, payload is forwarded to value. While falsy, value returns the fallback (or the last cached payload).
Event Mode
Send open, close, or toggle events to control the gate. The payload input is the value being gated.
Node Structure
Config Schema
-
label(string, optional): Node label -
controlMode('state'|'event', default:'state'): How the gate is controlled -
initiallyOpen(boolean, default:true): Starting state -
open(boolean, optional): Static open state (used as config default in state mode)
Input Schema
-
payload(unknown, optional): Value to gate -
open(boolean | string | number, optional): Gate control signal (state mode) -
fallback(unknown, optional): Value returned when gate is closed
Output Schema
-
value(unknown, optional): Gated payload or fallback -
isOpen(boolean): Current gate state
Input Events (event mode)
-
open: Open the gate -
close: Close the gate -
toggle: Toggle the gate state -
reset: Reset toinitiallyOpenstate
Implementation Details
- In state mode, gate state is computed from the
openinput on each render - In event mode, gate state persists and is modified by events
- When closed: returns
fallbackif provided, otherwise returns the last cached payload value
Comparison with EventGateNode
| Feature | StateGateNode | EventGateNode |
|---|---|---|
| Gates continuous values | ✓ | ✗ |
| Gates events | ✗ | ✓ |
| State and event control modes | ✓ | ✓ |
Integration
The StateGateNode is registered in:
-
NodeRegistryasstateGate -
NodeTypeSchemaas'stateGate'
Example Workflow Usage
- Hold Last Value: Gate a sensor reading; when the gate closes, hold the last known value
- Conditional Display: Only pass a value to a display when a condition is met
- Safety Interlock: Block a value from reaching an ActionNode until an enable signal is asserted
StaticValueNode
The StaticValueNode outputs a fixed, configured value of a chosen type. It is useful for injecting constants into a workflow.
Features
- Type Selection: Choose between string, number, or boolean output types
- Type Coercion: The configured value is cast to the selected type at runtime
- Enabled Toggle: When disabled, the node returns a safe default for the selected type
Usage
type: "string", value: "hello" → result: "hello"
type: "number", value: "42" → result: 42
type: "boolean", value: true → result: true
Defaults when disabled:
- string →
"" - number →
0 - boolean →
false
Node Structure
Config Schema
-
label(string, optional): Node label -
enabled(boolean, default:true) -
type('string'|'number'|'boolean', default:'string'): Output type -
value(string | number | boolean, default:''): The static value to output
Input Schema
- (no inputs)
Output Schema
-
result(string | number | boolean): The configured static value cast to the selected type
Implementation Details
- Type casting is done via a
castValuemethod - When disabled, the type default is returned instead of the configured value
Integration
The StaticValueNode is registered in:
-
NodeRegistryasstaticValue -
NodeTypeSchemaas'staticValue'
Example Workflow Usage
- Constant Threshold: Provide a fixed number threshold to a LogicNode
- Label String: Inject a fixed string label into a StringMergeNode
- Feature Flag: Use a boolean constant to enable/disable a branch of logic
StringMergeNode
The StringMergeNode concatenates multiple named input values into a single string, joined by a configurable separator.
Features
- Dynamic Inputs: Any number of named input variables can be defined
- Configurable Separator: Choose any separator string (empty by default)
- Null/Undefined Skipping: Missing or undefined inputs are omitted from the result
Usage
separator: " ", var1: "Hello", var2: "World" → result: "Hello World"
separator: "-", var1: "2024", var2: "01", var3: "15" → result: "2024-01-15"
separator: "", var1: "foo", var2: undefined → result: "foo"
Node Structure
Config Schema
-
label(string, optional): Node label -
enabled(boolean, default:true) -
separator(string, default:''): String placed between each value -
inputVariables(array of{name, description}, default:[]): Named inputs to merge
Input Schema
- Dynamic fields for each configured input variable name
Output Schema
-
result(string): Concatenated string, or''if disabled
Implementation Details
- Iterates over
inputVariablesin order, collecting non-null/undefined values - Joins with
separatorusingArray.prototype.join - Returns
''when disabled
Integration
The StringMergeNode is registered in:
-
NodeRegistryasstringMerge -
NodeTypeSchemaas'stringMerge'
Example Workflow Usage
-
Date Formatter: Merge year, month, and day with
-separator - Message Builder: Combine a fixed prefix with a dynamic variable value
-
CSV Row: Join multiple values with
,to build a CSV line
TcpClientNode
The TcpClientNode connects to a remote TCP server, sends messages, and receives data. It automatically reconnects on disconnect and supports delimiter-based message framing.
Features
- Auto-Reconnect: Reconnects automatically at a configurable interval after disconnection
- Idle Disconnect: Optionally disconnects after a period of inactivity
- Delimiter Framing: Buffer incoming data until a delimiter (LF, CRLF, CR, null byte) before emitting
- JSON Parsing: Attempts to JSON-parse each received message and exposes the result
-
Connection Events: Optionally emits a
connectionevent on (re)connect -
Send on Change: Sends the
send_statevalue whenever it changes
Usage
Configure the host and port. Wire a string to send_state to send it whenever the value changes. Incoming messages appear on lastMessage and lastObject.
Node Structure
Config Schema
-
label(string, optional): Node label -
enabled(boolean, default:true) -
host(string, min length:1): Remote hostname or IP address -
port(number, min:1, max:65535): Remote port -
reconnectInterval(number, default:5000): Reconnect delay in ms -
disconnectWhenIdle(boolean, default:false): Disconnect after idle period -
idleDisconnectDelay('0'|'200'|'1000'|'10000'|'60000', default:'1000'): Idle timeout in ms -
emitOnConnect(boolean, default:false): Emitconnectionevent on connect -
delimiter('none'|'null'|'lf'|'crlf'|'cr', default:'none'): Message delimiter -
bufferUntilDelimiter(boolean, default:false): Buffer data until delimiter is found -
maxBufferSize(number, default:65536): Max buffer size before truncation
Input Schema
-
send_state(string, optional): Message to send to the remote server
Output Schema
-
isConnected(boolean): Whether the TCP connection is active -
lastMessage(string): Most recently received message -
lastObject(unknown): JSON-parsed version of the last message (if parseable)
Output Events
-
message: Emitted on each received message -
connection: Emitted on connect (ifemitOnConnectis enabled)
Integration
The TcpClientNode is registered in:
-
NodeRegistryastcpClient -
NodeTypeSchemaas'tcpClient'
Example Workflow Usage
- Device Control: Send commands to a device over TCP and process its responses
- Telnet-Style Interface: Connect to a text-based TCP service and parse responses
- Raw Protocol: Use no delimiter for binary/streaming protocols
TcpServerNode
The TcpServerNode listens for incoming TCP connections, broadcasts messages to all connected clients, and exposes data received from any client.
Features
- Multi-Client Support: Accepts and manages multiple simultaneous TCP connections
-
Broadcast: Sends the
send_statevalue to all currently connected clients - Delimiter Framing: Per-client message buffering with configurable delimiters
- JSON Parsing: Attempts to parse received messages as JSON
- Client Tracking: Exposes connection count, last sender IP/port, and last received message
-
Error Reporting: Surfaces server errors via the
errorMessageoutput
Usage
Configure a port to listen on. Wire a string to send_state to broadcast it to all clients. Incoming messages from any client appear on the lastMessage and related outputs.
Node Structure
Config Schema
-
label(string, optional): Node label -
enabled(boolean, default:true) -
port(number, min:1024, max:65535): TCP port to listen on -
delimiter('none'|'null'|'lf'|'crlf'|'cr', default:'none'): Message delimiter -
bufferUntilDelimiter(boolean, default:false): Buffer per-client data until delimiter -
maxBufferSize(number, default:65536): Max per-client buffer size
Input Schema
-
send_state(string, optional): Message to broadcast to all connected clients
Output Schema
-
isConnected(boolean): Whether at least one client is connected -
connectionCount(number): Number of currently connected clients -
lastMessage(string): Most recently received message (from any client) -
lastObject(unknown): JSON-parsed version of the last message -
lastTimestamp(number): Timestamp of the last received message -
lastFromIp(string): IP address of the last sender -
lastFromPort(number): Port of the last sender -
errorMessage(string): Last server error message
Integration
The TcpServerNode is registered in:
-
NodeRegistryastcpServer -
NodeTypeSchemaas'tcpServer'
Example Workflow Usage
- Control Surface Server: Accept connections from multiple control surfaces and broadcast state
- Data Aggregator: Collect incoming data from multiple TCP clients and process it centrally
- Echo Server: Receive messages and send responses back to all clients
UdpReceiverNode
The UdpReceiverNode binds a UDP socket on a configured port and receives datagrams from any sender. It supports delimiter-based message buffering and exposes sender metadata alongside the received data.
Features
- UDP Listener: Binds a UDP socket and receives datagrams from multiple senders
- Per-Sender Buffering: Message buffering tracked per source address
- Delimiter Framing: Buffer data until a delimiter before treating it as a complete message
- JSON Parsing: Attempts to parse each message as JSON
- Sender Metadata: Exposes the IP address and port of the last sender
-
Event Emission: Emits a
messageevent on each received message
Usage
Configure the port. Incoming UDP datagrams are available on lastMessage and lastObject. The message event fires on each datagram.
Node Structure
Config Schema
-
label(string, optional): Node label -
enabled(boolean, default:true) -
port(number, min:1024, max:65535): UDP port to bind on -
delimiter('none'|'null'|'lf'|'crlf'|'cr', default:'none'): Message delimiter -
bufferUntilDelimiter(boolean, default:false): Buffer per-sender data until delimiter -
maxBufferSize(number, default:65536): Max buffer size per sender
Input Schema
- (no inputs)
Output Schema
-
lastMessage(string): Most recently received message -
lastObject(unknown): JSON-parsed version of the last message -
lastAddress(string): IP address of the last sender -
lastPort(number): Port of the last sender -
lastTimestamp(number): Timestamp of the last received message -
errorMessage(string): Last socket error message
Output Events
-
message: Emitted on each received datagram
Integration
The UdpReceiverNode is registered in:
-
NodeRegistryasudpReceiver -
NodeTypeSchemaas'udpReceiver'
Example Workflow Usage
- OSC Alternative: Receive raw UDP messages from devices that don't support OSC framing
- Sensor Data: Ingest UDP telemetry from sensors or embedded devices
- Broadcast Receiver: Listen for UDP broadcast packets on the local network
UdpSenderNode
The UdpSenderNode sends UDP datagrams to a configured host and port. The destination can be overridden at runtime via input values.
Features
- UDP Sending: Sends datagrams to a configured or dynamically specified host/port
-
Input Overrides: Host and port can be overridden per-render via
host_inputandport_input - Message Delimiter: Optionally appends a delimiter to each outgoing message
- Local Port Binding: Can bind to a specific local port, or use 0 for auto-assignment
-
Send Confirmation: Emits a
sentevent and updates last-sent metadata after each send
Usage
Configure the default host and port. Wire a string to send_state to send it. Override the destination dynamically using host_input and port_input.
Node Structure
Config Schema
-
label(string, optional): Node label -
enabled(boolean, default:true) -
host(string, optional): Default destination hostname or IP -
port(number, optional): Default destination port -
localPort(number, optional): Local port to bind (0= auto) -
delimiter('none'|'null'|'lf'|'crlf'|'cr', default:'none'): Appended delimiter
Input Schema
-
send_state(string, optional): Message to send -
host_input(string, optional): Overrides confighost -
port_input(number, optional): Overrides configport
Output Schema
-
lastSentMessage(string): Last message that was sent -
lastSentAddress(string): Destination address of the last send -
lastSentPort(number): Destination port of the last send -
errorMessage(string): Last send error message
Output Events
-
sent: Emitted after each successful send
Integration
The UdpSenderNode is registered in:
-
NodeRegistryasudpSender -
NodeTypeSchemaas'udpSender'
Example Workflow Usage
- Device Command: Send UDP control commands to a device that accepts UDP input
-
Dynamic Routing: Use
host_inputandport_inputto route messages to different destinations based on workflow state - Broadcast: Send to the subnet broadcast address to reach all devices on the local network
WebSocketClientNode
The WebSocketClientNode connects to a remote WebSocket server, sends messages, and receives data. It automatically reconnects on disconnect and supports idle-based disconnection.
Features
- Auto-Reconnect: Reconnects automatically at a configurable interval
- Idle Disconnect: Optionally disconnects after a period without outgoing messages
- JSON Parsing: Attempts to parse each received message as JSON
-
Connection Events: Optionally emits a
connectionevent on (re)connect -
Send on Change: Sends the
send_statevalue whenever it changes
Usage
Configure the WebSocket url. Wire a string to send_state to send messages. Received messages appear on lastMessage and lastObject.
Node Structure
Config Schema
-
label(string, optional): Node label -
enabled(boolean, default:true) -
url(string, min length:1): WebSocket URL to connect to (e.g.ws://host:port/path) -
reconnectInterval(number, default:5000): Reconnect delay in ms -
disconnectWhenIdle(boolean, default:false): Disconnect after idle period -
idleDisconnectDelay('0'|'200'|'1000'|'10000'|'60000', default:'1000'): Idle timeout in ms -
emitOnConnect(boolean, default:false): Emitconnectionevent on connect
Input Schema
-
send_state(string, optional): Message to send to the server
Output Schema
-
isConnected(boolean): Whether the WebSocket is currently connected -
lastMessage(string): Most recently received message -
lastObject(unknown): JSON-parsed version of the last message
Output Events
-
message: Emitted on each received message -
connection: Emitted on connect (ifemitOnConnectis enabled)
Integration
The WebSocketClientNode is registered in:
-
NodeRegistryaswebSocketClient -
NodeTypeSchemaas'webSocketClient'
Example Workflow Usage
- API Integration: Connect to a WebSocket API and react to incoming messages
- Real-Time Data: Subscribe to a live data feed and pass values downstream
- Bidirectional Control: Send commands and receive state updates over a single WebSocket connection
WebSocketServerNode
The WebSocketServerNode hosts a WebSocket server that accepts client connections, broadcasts messages to all connected clients, and exposes data received from any client.
Features
- Multi-Client Support: Accepts and manages multiple simultaneous WebSocket connections
-
Broadcast: Sends the
send_statevalue to all connected clients - Client ID Tracking: Each connecting client receives an auto-incremented ID
- JSON Parsing: Attempts to parse received messages as JSON
-
Connection Events: Optionally emits a
connectionevent when a new client connects -
Error Reporting: Surfaces server errors via the
errorMessageoutput
Usage
Configure a port. Clients connect via ws://host:port. Wire a string to send_state to broadcast it. Incoming messages appear on lastMessage and related outputs.
Node Structure
Config Schema
-
label(string, optional): Node label -
enabled(boolean, default:true) -
port(number, min:1024, max:65535): WebSocket port to listen on -
emitOnConnect(boolean, default:false): Emitconnectionevent when a client connects
Input Schema
-
send_state(string, optional): Message to broadcast to all connected clients
Output Schema
-
isConnected(boolean): Whether at least one client is connected -
connectionCount(number): Number of currently connected clients -
lastMessage(string): Most recently received message (from any client) -
lastObject(unknown): JSON-parsed version of the last message -
lastTimestamp(number): Timestamp of the last received message -
lastFromId(string): Client ID of the last sender -
errorMessage(string): Last server error message
Output Events
-
connection: Emitted when a client connects (ifemitOnConnectis enabled)
Integration
The WebSocketServerNode is registered in:
-
NodeRegistryaswebSocketServer -
NodeTypeSchemaas'webSocketServer'
Example Workflow Usage
- Browser Dashboard: Serve real-time state to a web dashboard connected via WebSocket
- Control Protocol: Accept commands from custom WebSocket clients and trigger workflow actions
- State Broadcast: Push workflow state updates to all listening clients whenever values change
WorkflowRouterNode
The WorkflowRouterNode is a dynamic signal router that maps configurable sources to destinations across one or more levels. Routes are persisted to the database and survive restarts.
Features
- Dynamic Routing: Connects any source to any destination at runtime
- Multi-Level: Supports up to 10 independent routing levels (e.g. for video, audio, data)
- Scalable: Up to 1000 sources and 1000 destinations per router
- Persistent Routes: Routes are saved to the database with a 5-second debounce
- Cross-Workflow Validation: Validates that source and destination nodes belong to the same workflow
- Dynamic I/O: Source and destination counts can be changed without losing existing routes
Usage
Configure the number of sources, destinations, and levels. Use the editor UI to assign routes. The output_<dest> values reflect the current value of whatever source is routed to each destination. An unrouted_<dest> value appears when no source is assigned.
Node Structure
Config Schema
-
label(string, default:'Router'): Node label -
sourceCount(number, min:1, max:1000, default:10): Number of source inputs -
destinationCount(number, min:1, max:1000, default:10): Number of destination outputs -
levels(number, min:1, max:10, default:1): Number of independent routing levels
Input Schema
- Dynamic inputs for each source (boolean | string | number | null)
Output Schema
-
output_<N>for each destination: Current value of the routed source, or fallback if unrouted -
unrouted_<N>(boolean): Whether destination N is currently unrouted -
ordered(array): Ordered list of active source IDs by destination
Implementation Details
- Built with the Effect library for typed error handling and resource management
- Routes are stored in the database with a 5-second write debounce to reduce I/O
- In-memory cache is the source of truth; the database is used only for persistence and initial load
- Orphaned ports (from reduced source/destination counts) are cleaned up on config change
- Cross-workflow routing is blocked with a validation error
Integration
The WorkflowRouterNode is registered in:
-
NodeRegistryasworkflowRouter -
NodeTypeSchemaas'workflowRouter'
Example Workflow Usage
- Video Router: Route camera feeds to output destinations with a visual matrix UI
- Audio Routing: Assign audio sources to mix bus destinations across multiple levels
- Signal Matrix: General-purpose N×M routing matrix for any type of signal value
WorkflowVariableNode
The WorkflowVariableNode stores a typed value scoped to the current workflow. It acts as a shared memory cell: other nodes can write to it and read from it. Values can optionally be persisted to the database.
Features
- Typed Storage: Stores a string, number, or boolean value with type enforcement
-
Read and Write: Exposes both a
writeinput and areadoutput on the same node - Optional Persistence: Can save the value to the database so it survives restarts
- Live Sync: Broadcasts changes via Redis so all nodes reacting to this variable update immediately
-
Controlled/Uncontrolled Modes: When
writeis connected, the node is controlled by that input; when disconnected, it manages its own state
Usage
Connect a value to write to update the variable. Read the current value from the read output. Other nodes in the same workflow can reference this variable by its variableKey.
Node Structure
Config Schema
-
schema({type: 'string' | 'number' | 'boolean'}): The type of the variable -
initialValue(unknown): Value used on first creation -
variableKey(string): Unique identifier for this variable within the workflow -
persist(boolean, default:false): Whether to persist the value to the database
Input Schema
-
write(string | number | boolean | object | null, optional): Value to write to the variable
Output Schema
-
read(string | number | boolean | object | null, optional): Current value of the variable
Implementation Details
- Initialises from Redis, the persisted database value, or
initialValue(in that priority order) - Persistence is throttled to a maximum of once every 30 seconds
- Type casting produces a friendly error message if the written value cannot be cast to the configured type
- Cross-node reactivity via Redis pub/sub
Integration
The WorkflowVariableNode is registered in:
-
NodeRegistryasworkflowVariable -
NodeTypeSchemaas'workflowVariable'
Example Workflow Usage
- Shared State: Store a mode value that multiple branches of the workflow read
- Persisted Counter: Track a count that survives workflow restarts
- Cross-Node Communication: Write from one part of the workflow and read in another without direct connections
WorkflowVariableReadNode
The WorkflowVariableReadNode reads the current value of a variable from another workflow. It subscribes to live updates so the output always reflects the latest value.
Features
- Cross-Workflow Read: Accesses variables defined in a different workflow
- Live Subscription: Automatically updates when the target variable changes
- Schema Validation: Validates the received value against the target variable's type schema
- Reactive: Triggers a re-render when the value changes
Usage
Configure the workflowId of the workflow that owns the variable, and the variableKey of the variable to read. The read output reflects its current value.
Node Structure
Config Schema
-
workflowId(string): ID of the workflow that owns the variable -
variableKey(string): Key of the variable to read
Input Schema
- (no inputs)
Output Schema
-
read(string | number | boolean | object | null, optional): Current value of the variable
Implementation Details
- Subscribes to variable change notifications for the target workflow/key pair
- Validates the incoming value against the target variable's type schema
- Cleans up the subscription on node unmount or config change
Comparison with WorkflowVariableNode
| Feature | WorkflowVariableNode | WorkflowVariableReadNode |
|---|---|---|
| Same-workflow variable | ✓ | ✗ |
| Cross-workflow read | ✗ | ✓ |
| Write support | ✓ | ✗ |
Integration
The WorkflowVariableReadNode is registered in:
-
NodeRegistryasworkflowVariableRead -
NodeTypeSchemaas'workflowVariableRead'
Example Workflow Usage
- Global Config: Read a configuration value maintained in a dedicated "globals" workflow
- Shared Counter: Display or use a counter that is owned and managed by another workflow
- Cross-Workflow Sync: Synchronise state between two workflows without direct connections
WorkflowVariableWriteNode
The WorkflowVariableWriteNode writes a value to a variable defined in another workflow. It validates the written value against the target variable's type schema before writing.
Features
- Cross-Workflow Write: Updates a variable in a different workflow
- Type Validation: Strictly validates the value against the target variable's schema (no coercion)
-
Reactive: Re-validates and writes whenever the
writeinput changes
Usage
Configure the workflowId of the target workflow and the variableKey. Connect the value to write to the write input. The value will be written to the target variable whenever it changes.
Node Structure
Config Schema
-
workflowId(string): ID of the workflow that owns the variable -
variableKey(string): Key of the variable to write to
Input Schema
-
write(string | number | boolean | object | null, optional): Value to write
Output Schema
- (no outputs)
Implementation Details
- Validates the value against the target variable's type schema before writing
- Uses strict type validation — values are not coerced to the target type
- Subscribes to the target schema to stay up to date with type changes
- Cleans up subscriptions on node unmount
Comparison with WorkflowVariableNode
| Feature | WorkflowVariableNode | WorkflowVariableWriteNode |
|---|---|---|
| Same-workflow variable | ✓ | ✗ |
| Cross-workflow write | ✗ | ✓ |
| Read support | ✓ | ✗ |
Integration
The WorkflowVariableWriteNode is registered in:
-
NodeRegistryasworkflowVariableWrite -
NodeTypeSchemaas'workflowVariableWrite'
Example Workflow Usage
- Remote Update: Write a computed value from one workflow into a variable owned by another
- Coordinator Pattern: Have a "controller" workflow update shared variables consumed by multiple "view" workflows