Custom Flow nodes
A Flow declaration script uses a constrained JavaScript-shaped API. Each file exports one definition with export default. Opal compiles opal.flowNode into a real Object Flow node in the palette.
Reusable components, Flow nodes, and graph templates belong to the project. Scene Behaviors stay with their scene.
Branch node
Start with a transform check — no extra component required:
export default opal.flowNode("IsBelowWorld", {
label: "Is Below World",
group: "World",
description: "Passes when the actor's world Y is below the kill line.",
fields: {
killY: { type: "number", default: 900, label: "Kill Y" },
},
when: "worldY > killY",
});- The first argument is the node id (PascalCase). Graphs store it as a
script_*type. whenis a string expression, not a function body. Truthy → pass, otherwise fail.fieldsbecome Inspector controls and wirableparam:*ports.- Skip
componentfor transform-only checks (worldY,worldX,x,y,rotation). Stage +Y is down, so “below” is a larger Y.
Save, open Object Flow, drop the node, wire pass/fail.
When the object has Health, you can put that component’s fields in scope:
export default opal.flowNode("AlmostDead", {
label: "Almost Dead",
group: "Scripts",
component: "health",
fields: {
threshold: { type: "number", default: 0.10 },
},
when: "hp / maxHp <= threshold",
});component: "health" puts hp and maxHp in the expression. You do not write self.hp in when.
Value node
Use value instead of when to emit a data port (no exec pass/fail). Opal infers number, boolean, or text from the expression. Value nodes evaluate when their data is read. You cannot set both when and value in the same script.
export default opal.flowNode("HealthPercent", {
label: "Health %",
group: "Combat",
component: "health",
fields: {
scale: { type: "number", default: 100, label: "Scale" },
},
value: "hp / maxHp * scale",
});Field types
| Type | Control |
|---|---|
number | Numeric input |
text | Text |
toggle | Checkbox (boolean) |
select | Dropdown; needs options: [...] |
label overrides the Inspector title. Field ids are in scope in when / value next to component fields.
outputs: { pass: "wounded", fail: "fine" } renames the branch ports. falseOutput: "else" is an optional failed-branch name.
Templates and scene scripts
These are also export default project/scene declarations:
| Call | Meaning |
|---|---|
opal.graphTemplate("TapBounce", { event, nodes, edges }) | Reusable Flow you can drop onto an object |
opal.sceneScript("SpawnWave", { event, nodes, edges }) | Scene-level behavior (for example sceneStart) |
Script Studio’s Your First Flow Node tutorial inserts a complete Health branch example. The World check above is the smaller first node.