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

  1. 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.

NodeFires when
OnStartScript loads
OnInteractPlayer interacts with the entity
OnEnter / OnExitEntity enters or leaves a trigger zone
OnTimerConfigurable interval elapses
OnCollisionPhysics 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.

TypeColorDescription
FlowWhiteExecution order
BoolRedTrue/false
IntCyanIntegers
FloatGreenDecimals
StringYellowText
Vec3Purple3D vectors
EntityOrangeEntity reference
AnyGrayAccepts 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."

  1. Drag an OnEnter node from Events onto the canvas. It has a Flow output (white) and an Entity output (orange, the entity that entered).

  2. Drag a Log node from Actions. Connect OnEnter.Flow to Log.Flow. In the Inspector, set the message to "Player entered the zone".

  3. Drag a GetVariable node. Set the variable name to marker_entity and type to Entity.

  4. Drag a SetPosition node. Connect Log.Flow to SetPosition.Flow. Connect GetVariable.Entity to SetPosition.Entity. Connect OnEnter.Entity through a position lookup to SetPosition.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

  1. 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. Any matches 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

  1. 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:

  1. Topological sort -- Nodes are ordered so dependencies are processed first.

  2. IR generation -- Each node emits instructions: LoadConst, Call, Branch, Jump, Return.

  3. WASM output -- IR compiles to a minimal WASM module for the aether-scripting runtime.

  4. Click Export WASM to download the .wasm file, 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.

  1. 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)
  1. Validate and compile. The IR output includes Branch and Jump instructions 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