Visual Scripting 101
Build game logic using the Aether visual scripting editor -- create a node graph, validate it, and compile to IR.
In this tutorial you will use the Aether visual scripting editor to build game logic without writing code. You will create a script that triggers an event when a player enters a zone, validate the graph, and compile it to the intermediate representation (IR) that runs on the WASM runtime.
This tutorial references the visual-scripting-demo example in the Aether repository.
Prerequisites
- Aether source cloned and built
- A web browser (the visual editor runs as a local web app)
Launch the Visual Editor
- Start the editor from the workspace:
cargo run -p aether-visual-scripting-demo
This starts a local web server and opens the node editor at http://localhost:3000. You can also use:
aether run visual-editor
Editor Layout
The editor has three areas:
- Sidebar (left) -- All available node types grouped by category. Drag nodes onto the canvas.
- Canvas (center) -- The graph workspace. Pan with middle-click, zoom with scroll wheel.
- Inspector (right) -- Properties of the selected node. Edit constant values and variable names here.
Node Type Categories
Aether provides 33 node types across six categories.
Events -- Entry points that fire when something happens. Every graph needs at least one.
| Node | Fires when |
|---|---|
OnStart | Script loads |
OnInteract | Player interacts with the entity |
OnEnter / OnExit | Entity enters or leaves a trigger zone |
OnTimer | Configurable interval elapses |
OnCollision | Physics collision occurs |
Flow Control -- Branch (if/else), ForLoop, Sequence (execute outputs in order), Delay (pause execution).
Actions -- SetPosition, SetRotation, PlayAnimation, PlaySound, SpawnEntity, DestroyEntity, SendMessage, Log.
Math -- Add, Subtract, Multiply, Divide, Clamp, Lerp, RandomRange.
Logic -- Equal, NotEqual, Greater, Less, And, Or, Not.
Variables -- GetVariable (read), SetVariable (write).
Port Types
Each node has typed input and output ports. Only compatible types can connect.
| Type | Color | Description |
|---|---|---|
Flow | White | Execution order |
Bool | Red | True/false |
Int | Cyan | Integers |
Float | Green | Decimals |
String | Yellow | Text |
Vec3 | Purple | 3D vectors |
Entity | Orange | Entity reference |
Any | Gray | Accepts any type |
Build a Zone Trigger Script
You will create a script: "When a player enters a zone, log a message and move a marker to the player's position."
-
Drag an
OnEnternode from Events onto the canvas. It has a Flow output (white) and an Entity output (orange, the entity that entered). -
Drag a
Lognode from Actions. ConnectOnEnter.FlowtoLog.Flow. In the Inspector, set the message to"Player entered the zone". -
Drag a
GetVariablenode. Set the variable name tomarker_entityand type toEntity. -
Drag a
SetPositionnode. ConnectLog.FlowtoSetPosition.Flow. ConnectGetVariable.EntitytoSetPosition.Entity. ConnectOnEnter.Entitythrough a position lookup toSetPosition.Position.
Your graph should flow like this:
OnEnter ──Flow──> Log ──Flow──> SetPosition
|Entity ^Entity
+──> [position lookup] ─Vec3──> |Position
^Entity
GetVariable("marker_entity") ──────+
Validate the Graph
- Click Validate in the toolbar (or
Ctrl+Shift+V). The validator checks five rules:
- Type compatibility -- Source type must match or be coercible to the destination type.
Anymatches everything. - Direction -- Connections go from output to input ports only.
- Single input -- Each input port accepts at most one connection.
- No cycles -- Flow connections must form a DAG. Data connections may have cycles.
- Connected events -- At least one Event node must connect to downstream nodes.
Errors appear as red highlights. Common fixes:
- Type mismatch -- Add a conversion or comparison node between incompatible ports.
- Disconnected event -- Connect the event's Flow output to at least one action.
- Cycle detected -- Remove one connection in the circular path.
Compile to IR
- Click Compile (
Ctrl+Shift+C). The compiler transforms the graph into IR instructions:
LoadConst r0, "Player entered the zone"
Call log, [r0], _
LoadVar r1, "marker_entity"
LoadEntity r2, trigger_entity
GetPosition r3, r2
Call set_position, [r1, r3], _
Return
The pipeline has three stages:
-
Topological sort -- Nodes are ordered so dependencies are processed first.
-
IR generation -- Each node emits instructions:
LoadConst,Call,Branch,Jump,Return. -
WASM output -- IR compiles to a minimal WASM module for the
aether-scriptingruntime. -
Click Export WASM to download the
.wasmfile, or Copy IR to copy instructions to clipboard.
Build a Timed Door
Try a more complex script: a door that opens when a player steps on a pressure plate and closes after 5 seconds.
- Create this graph:
OnEnter ──> Branch(GetVariable("door_open"))
|True ──> [do nothing, already open]
|False ──> SetVariable("door_open", true)
──> PlayAnimation("door", "open")
──> Delay(5.0)
──> PlayAnimation("door", "close")
──> SetVariable("door_open", false)
- Validate and compile. The IR output includes
BranchandJumpinstructions for the conditional path.
Build Graphs Programmatically
You can also create and compile graphs in Rust code:
use aether_creator_studio::visual_script::{NodeGraph, NodeKind};
use aether_creator_studio::visual_script::compiler::compile_graph;
fn build_graph() {
let mut graph = NodeGraph::new("zone_trigger");
let on_enter = graph.add_node(NodeKind::OnEnter);
let log = graph.add_node(NodeKind::Log);
let set_pos = graph.add_node(NodeKind::SetPosition);
graph.connect(on_enter, "flow_out", log, "flow_in");
graph.connect(log, "flow_out", set_pos, "flow_in");
graph.connect(on_enter, "entity", set_pos, "entity");
let errors = graph.validate();
assert!(errors.is_empty(), "Errors: {:?}", errors);
let ir = compile_graph(&graph).expect("Compilation failed");
println!("{} IR instructions generated", ir.instructions.len());
}
Run the Bundled Demo
The Aether repository includes a full visual scripting demo with sample graphs:
cargo run -p aether-visual-scripting-demo
Next Steps
- Import a custom avatar (see Custom Avatar)
- Learn how compiled scripts execute on the WASM runtime in the API reference
- Explore all 33 node types in the Creator Studio documentation