Skip to content

Auto-Layout

Every AI mutation to a Blueprint, Animation Blueprint, or Control Rig graph triggers an automatic layout pass over the affected nodes. The result is always neat rows and columns — no spaghetti graphs, no manual cleanup.

The layout pass rearranges nodes so:

  • Exec nodes flow left to right along the execution wires
  • Pure data nodes (getters, math, breaks) sit to the left of the exec node they feed
  • Pure nodes are pin-aligned vertically with the input pin they connect to
  • Long wires get reroute knots automatically when they’d otherwise span > 2 columns or > 300px vertically
  • Redundant pure getters (e.g. two GetActorLocation nodes feeding different exec nodes) are deduplicated when safe

The result looks like something a human laid out by hand, not a topo-sort spew.

Auto-layout runs automatically after every AI mutation:

  • After any operation that adds, moves, deletes, or reconnects a node in a graph
  • After batched operations (the whole batch finishes, then one layout pass)
  • After rerouting changes (insert reroute, remove reroute)

You don’t have to ask for it. It just happens.

For human edits (manually placing nodes), the layout pass does not run — you stay in control of nodes you positioned yourself.

You can run the layout pass on demand from the AI chat:

Layout the EventGraph on BP_Pickup.

Or directly via CLI:

Terminal window
python cli.py apply '{"op":"layout_graph","asset":"/Game/Pickups/BP_Pickup","graph":"EventGraph"}'
OpWhat it does
layout_graphFull layout pass on a single graph
optimize_graphDedupe redundant pure getters only — no movement
set_node_positionMove one node to specific coordinates
add_rerouteInsert a reroute knot at a given position
insert_reroute_on_linkSplit an existing wire with a reroute
add_comment_boxWrap a set of nodes in a colored comment box
debug_layoutPrint the layout decisions for a graph (no mutation)
debug_optimizePrint the dedupe candidates for a graph (no mutation)

Each accepts the same asset + graph parameters as the rest of the operation set — see JSON Schema.

The pass runs six phases in order. You can see them in debug_layout output:

  1. Optimize — find pure getters that could be merged, dedupe where it’s safe (no side effects, identical pins, no Sequence dependency).
  2. Build the exec model — classify every node as exec, pure, event, reroute, or comment; identify the exec entry points (BeginPlay, Tick, dispatchers, …).
  3. Build exec trees — walk each exec entry along execution wires, producing a tree per entry.
  4. Compute subtree heights — sum the vertical space each subtree needs once pure rows are placed.
  5. Position — lay out exec nodes left-to-right by tree depth; lay out pure nodes to the left of their consumers, pin-aligned.
  6. Insert reroutes — for any wire that would cross > 2 columns horizontally or > 300px vertically, insert a reroute knot at the midpoint.

The phases are deterministic — the same graph in the same state always produces the same layout.

The defaults work for most graphs. To change reroute behavior, pass overrides:

Terminal window
python cli.py apply '{
"op":"layout_graph",
"asset":"/Game/Pickups/BP_Pickup",
"graph":"EventGraph",
"reroute_min_columns": 3,
"reroute_min_pixels": 400
}'
ParameterDefaultWhat it controls
reroute_min_columns2Min exec-column span before inserting a reroute
reroute_min_pixels300Min vertical distance before inserting a reroute
optimizetrueRun the dedupe pass before positioning
add_reroutestrueSkip phase 6 if false

Layout preserves manually-authored comment boxes — it computes the bounding box of the original node set, then resizes the comment to fit the new positions. Comments added by AI ops (add_comment_box) are tracked the same way.

Drawing comment-aware layout: comments aren’t reflowed across other comments, so a “Sequence A” group stays separate from a “Sequence B” group even if their nodes interleave numerically.

Generated graphs without auto-layout look like this:

[Event] - [Branch] [Branch] [Print]
\ \ /
[PureGetter] X
/ \
[Math] [GetVar]

After auto-layout:

[Event] --> [Branch] --> [Print]
| ^
v |
[Math] [GetVar]
^
|
[PureGetter]

You can read it left-to-right, the pure data flows feed in from the left, the exec spine is one straight horizontal line. Every Blueprint the AI emits looks like this without you doing anything.