Flow as text
Every Opal flow graph can be edited two ways: as nodes on the canvas, or as readable text. It's the same graph either way — text is a view over it, not a separate file. If you'd rather type behavior than wire nodes, this is for you.
Look for the Text button in the flow board toolbar, next to Tidy and Fit. Click it to see the open graph as text; click it again to return to nodes.
on tap actor self:
if variable equals key "isOpen" value true:
bounce self
else:
say self key "Locked" value 2000That block is the node graph above — one On Tap rule with a condition that branches to a bounce or a "Locked" message.
One graph, two views
Editing as text and editing as nodes both change the same graph and share the same undo history (Ctrl+Z). Switching views never converts or duplicates anything.
Reading a graph
A graph reads top to bottom, indented like an outline. Each line is one step; indentation groups the branches and blocks beneath it.
The event line
The first line is the trigger — the on <event> that starts the graph:
on tap actor self:
on collision actor #enemies:
on timer key "wave" value 1000:
on sceneStart:Actors and targets name who the event is about:
| In text | Means |
|---|---|
self | The object that owns the graph |
target | The other object in the event (collision partner, drop target, …) |
hit / source | Context objects for specific events |
#groupName | Any object in that group |
"objectId" | One specific object, by id |
Actions
Actions are verbs. The verb is the action's name; a subject and any settings follow:
bounce self
shake self value 2 duration 500
spawn object key "enemy" target self offset (10, 0)
go to scene key "level2"
set variable key "score" value 10The subject (self, target, …) comes first when the action acts on an object. Settings are name value pairs — key "…" for names and text, plain numbers for amounts, (x, y) for offsets.
Conditions
if splits the flow; else is optional:
on tap actor self:
if variable at least key "coins" value 3:
go to scene key "shop"
else:
say self key "Not enough coins" value 1500Variables
Graph-local variables are declared once, under the event line:
on sceneStart:
var timer: number = 0
var armed: boolean = falseExpressions
Any setting can be a computed expression instead of a fixed value. Write setting = <expression>:
on sceneStart:
var multiplier: number = 3
set variable key "score" value = var("score") + 10 * var("multiplier")Expressions support:
| Kind | Examples |
|---|---|
| Numbers, text, true/false | 10, "win", true |
| Graph variables | var("multiplier") |
| Arithmetic | + - * / % |
| Comparisons | > < >= <= == != |
| Logic | && || not(x) |
| Functions | min(a, b), max, abs, round, clamp(v, lo, hi), lerp(a, b, t) |
Parentheses group as you'd expect: set variable key "n" value = (var("a") + 1) * 2.
It's safe to edit
The text view is built so you can't lose work:
- A typo never breaks your graph. If the text doesn't parse, nothing is applied — your node graph and undo history are untouched — and the error is shown so you can fix it in place.
- Every apply is one undo step. Commit a text edit, press
Ctrl+Z, and it reverts as a single change, exactly like a node edit. - Committing happens when you leave the field (click away) or toggle back to nodes. Nothing is applied while you're mid-type.
When a graph opens read-only
Some graphs use parts the text grammar can't fully express yet. Rather than risk dropping them, those graphs open read-only with a banner naming what's involved — you can read the text, but you edit that graph in the node view.
A graph is read-only when it contains:
- Component actions or Script nodes — their configuration lives outside the text grammar
- Component or Expression conditions
- Value wires the grammar can't render yet (e.g. reading a component field or scene value into a setting)
- Comments or disconnected nodes that the text outline wouldn't include
Everything else — events, if/else, action verbs, variables, and variable-based expressions — is fully editable. The editable set grows as the grammar expands; read-only is always the safe fallback, never a data risk.
What text doesn't show
Text captures the logic of a graph — the trigger, the steps, the connections, the variables. It does not capture visual layout: node positions and pan/zoom are the node view's concern and are regenerated automatically when you switch back. Two graphs that behave identically read as identical text.
Tips
- Reach for text on dense logic — a long
if/elsechain is often faster to read and edit as an outline than as a fan of wires. - Stay in nodes for wiring-heavy graphs — data-flow webs and component calls are clearer on the canvas (and may be read-only in text for now).
- The two views round-trip — flip to text to skim what a graph does, flip back to nodes to fine-tune connections.
- Undo works across both — edit in text, undo, and continue in nodes seamlessly.
Related docs
- Visual scripting — the node view: events, wires, the catalog, and the inspector
- Scripts — write reusable behavior in code, including behavior scripts on objects
- Testing and debugging — the live Flow overlay and Graph Explorer