Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commitdf78e4f826

README.md

AnimGraph

DAG of animation nodes implemented in pure Luau. Nodes are stored in a slot vector; freed slots are reused on the next addNode (mirrors the legacy Rust crate's Vec<Option<AnimNode>> pattern). An AnimGraph has exactly one designated "output" node. Each frame the engine calls graph:update(dt) followed by graph:evaluate(), which recursively walks reachable nodes and returns the pose buffer for the output node.

The module re-exports the Node hierarchy on the returned table so callers can reach AnimGraph.Clip.new(...), AnimGraph.Mixer.new(...), etc. without separate requires.

Exports

  • AnimGraph.new(opts: { layout: Layout? }?) -> AnimGraph — construct a new graph; layout defaults to a sensible default.
  • AnimGraph:addNode(node: Node) -> number — insert a node, return its slot id (reuses freed slots).
  • AnimGraph:removeNode(id: number) — free the node at slot id and call :destroy() on it.
  • AnimGraph:setOutput(id: number) — designate which node is the graph's final output.
  • AnimGraph:update(dt: number) — advance every reachable node.
  • AnimGraph:evaluate() -> TypedBuffer? — return the output node's pose buffer (caller MUST NOT destroy).
  • AnimGraph:crossfade(from: number, to: number, duration: number) — sugar that wires a temporary Mixer between two nodes, ramps weights over duration, then collapses to the new output when the ramp completes.
  • AnimGraph.Clip, AnimGraph.Mixer, AnimGraph.BlendSpace2D, AnimGraph.Node — re-exports of the node constructors.

Types:

  • Layout = { ... } — pose layout used by the graph and its nodes.

Usage

local AnimGraph = require("@builtin::systems.anim.AnimGraph")

local graph = AnimGraph.new({ layout = myLayout })
local idle  = graph:addNode(AnimGraph.Clip.new("idle"))
local walk  = graph:addNode(AnimGraph.Clip.new("walk"))

graph:setOutput(idle)
graph:crossfade(idle, walk, 0.25)  -- blend to walk over 250ms

-- Each frame:
graph:update(dt)
local pose = graph:evaluate()

Notes

  • The output node MUST be set before evaluate is called; otherwise the return value is nil.
  • crossfade collapses the temporary mixer when the ramp completes, so long-running graphs don't accumulate orphan mixers.
  • Buffer ownership: nodes own their internal buffers and free them in :destroy(). Callers of evaluate borrow the returned buffer — do NOT destroy it.
  • removeNode frees the slot id and calls :destroy() on the node; the next addNode may reuse the same id.