Skip to main content

BehaviorBuilder

Fluent typed configuration builder for AnimationController.

Instead of constructing raw config tables by hand, chain builder methods and call :Build() to produce a validated, frozen BuiltBehavior.

local Motix = require(ReplicatedStorage.Motix)

local Behavior = Motix.BehaviorBuilder.new()
	:Animation("Idle")
		:AssetId("rbxassetid://IDLE_ID")
		:Layer("Base")
		:Looped(true)
		:Priority(0)
		:FadeIn(0.2)
		:FadeOut(0.2)
	:Done()
	:Layer("Base")
		:Order(0)
		:BaseWeight(1.0)
		:LerpRate(8.0)
	:Done()
	:State("Idle")
		:OnEntry():Play("Idle"):Done()
		:OnExit():Stop("Idle"):Done()
		:ActiveLayer("Base")
		:Transition("Walk", "IsWalking"):Priority(10):Done()
	:Done()
	:Predicate("IsWalking", function()
		return humanoid.MoveDirection.Magnitude > 0.1
	end)
	:InitialState("Idle")
	:Build()

Builder overview:

Method Configures
:Animation(name) Opens the animation sub-builder
:Layer(name) Opens the layer sub-builder
:State(name) Opens the state sub-builder
:Predicate(name, fn) Registers a boolean predicate function
:InitialState(name) Sets the initial state machine state
:Clone() Returns an independent copy of this builder
:Merge(other) Merges a built behavior into this builder (non-destructive)
:When(condition, fn) Conditionally applies a block without breaking the chain
:Build() Validates and returns a frozen BuiltBehavior
Presets

Use BehaviorBuilder.Humanoid() as a starting point for standard humanoid characters. It includes Idle, Walk, and Run animations on Base and UpperBody layers with a predicate-driven state machine.

Build-time validation

All validation is deferred to :Build(). The builder never throws mid-chain. Errors are collected and reported together when :Build() is called. :Build() returns nil if any error is found.

Functions

new

BehaviorBuilder.new() → BehaviorBuilder

Creates a new empty builder.

Humanoid

BehaviorBuilder.Humanoid() → BehaviorBuilder

Returns a pre-configured builder for a standard humanoid character.

Includes three animations (Idle, Walk, Run) with placeholder asset IDs, two layers (Base at order 0, UpperBody additive at order 1), and a predicate-driven state machine with IsIdle, IsWalking, and IsRunning predicates.

Replace the placeholder rbxassetid://0 values with real animation IDs before calling :Build().

local Behavior = Motix.BehaviorBuilder.Humanoid()
	-- Override or extend before building
	:Build()
TIP

Use this as a starting point. Chain additional animations, layers, or states on top before calling :Build().

Animation

BehaviorBuilder:Animation(
Namestring--

Unique animation name.

) → AnimationBuilder

Opens the animation configuration sub-builder for an animation with the given name.

The name must be unique within this builder. It is also the name used to look up the animation in AnimationRegistry and the string passed to Controller:Play().

Available setters:

Method Type Default Description
:AssetId(id) string required The rbxassetid://... for this animation.
:Layer(name) string required The layer this animation belongs to.
:Group(name) string? nil Exclusive group name. Only one animation per group may play at a time.
:Priority(n) number 0 Conflict priority within the layer or group. Higher wins.
:Looped(v) boolean false Whether the animation loops.
:FadeIn(t) number 0.1 Fade-in time in seconds.
:FadeOut(t) number 0.1 Fade-out time in seconds.
:Speed(s) number 1.0 Playback speed multiplier.
:Weight(w) number 1.0 Blend weight for this animation within its layer. Range (0, 1].
:CanInterrupt(v) boolean true Whether a lower-priority group member can interrupt this animation.
:MinDuration(d) number? nil Minimum seconds before this animation can be interrupted by a group conflict.
:Tag(tag) string Appends a single tag. Multiple calls allowed.
:Tags(tags) { string } {} Replaces the entire tag list.
:Additive(v) boolean false Whether the animation track is played in additive blending mode.
:Metadata(t) table? nil Arbitrary key-value table stored with the config.

Call :Done() to return to the root builder.

:Animation("Reload")
	:AssetId("rbxassetid://RELOAD_ID")
	:Layer("UpperBody")
	:Group("WeaponAction")
	:Priority(5)
	:Looped(false)
	:FadeIn(0.1)
	:FadeOut(0.15)
	:CanInterrupt(false)
:Done()

Layer

BehaviorBuilder:Layer(
Namestring--

Unique layer name.

) → LayerBuilder

Opens the layer configuration sub-builder for a layer with the given name.

The name must be unique within this builder. It must match the Layer field of at least one animation config or a state's ActiveLayer / SuppressLayer entry.

Available setters:

Method Type Default Description
:Order(n) number required Integer order for blending priority. Lower values are evaluated first. Must be unique.
:BaseWeight(w) number 1.0 Default layer weight when active. Range [0, 1].
:LerpRate(r) number 8.0 Speed in units per second at which weight interpolates toward its target. Use math.huge for instant snapping.
:Additive(v) boolean false When true, this layer composes with lower layers rather than replacing them.
:Isolated(v) boolean false When true, this layer does not interact with other layers during blending.

Call :Done() to return to the root builder.

:Layer("UpperBody")
	:Order(1)
	:BaseWeight(1.0)
	:Additive(true)
	:LerpRate(6.0)
:Done()

State

BehaviorBuilder:State(
Namestring--

Unique state name.

) → StateBuilder

Opens the state configuration sub-builder for a state with the given name.

States define what happens when the state machine enters or exits them, which layers are active or suppressed, and what conditions trigger transitions to other states.

Available methods:

Method Description
:OnEntry() Returns a directive list builder for entry actions.
:OnExit() Returns a directive list builder for exit actions.
:Transition(toState, condition) Adds a transition rule.
:ActiveLayer(name) Marks a layer as active (set to BaseWeight) when this state is entered.
:SuppressLayer(name) Marks a layer as suppressed (set to 0) when this state is entered.

Directive list builder methods (returned by :OnEntry() and :OnExit()):

Method Effect
:Play(animName) Plays the animation when the directive fires
:Stop(animName, immediate?) Stops the animation when the directive fires
:StopGroup(groupName, immediate?) Stops the group when the directive fires
:Done() Returns to the state builder

Transition builder methods (returned by :Transition()):

Method Description
:Priority(n) Priority for this transition rule. Higher wins when multiple conditions are true simultaneously.
:Done() Returns to the state builder

Call :Done() on the state builder to return to the root builder.

:State("Jump")
	:OnEntry():Play("JumpRise"):Done()
	:OnExit():Stop("JumpRise"):StopGroup("WeaponAction"):Done()
	:ActiveLayer("Base")
	:SuppressLayer("UpperBody")
	:Transition("Idle", "IsGrounded"):Priority(10):Done()
:Done()

States with no transitions are terminal states. The state machine stays in them indefinitely until RequestStateTransition is called.

Predicate

BehaviorBuilder:Predicate(
Namestring,--

The condition name referenced in :Transition(toState, conditionName).

Fn() → boolean--

The predicate function.

) → BehaviorBuilder

Registers a named predicate function.

Predicates are called every frame by the state machine to evaluate transition conditions. The function must return a boolean. Keep predicates cheap: avoid yielding, remote reads, or per-call allocations.

A predicate registered once can be referenced by any number of transitions across any number of states.

:Predicate("IsGrounded", function()
	return humanoid.FloorMaterial ~= Enum.Material.Air
end)

InitialState

BehaviorBuilder:InitialState(
Namestring--

The name of the initial state.

) → BehaviorBuilder

Sets the initial state for the state machine.

Must match one of the state names defined with :State(). Required: :Build() returns nil if InitialState is not set or references an undefined state.

:InitialState("Idle")

Clone

BehaviorBuilder:Clone() → BehaviorBuilder

Returns an independent BehaviorBuilder that is a deep copy of this builder.

Animations, layers, states, predicates, and initial state are all cloned. Changes to either builder after cloning do not affect the other.

local Base  = Motix.BehaviorBuilder.Humanoid()
local Armed = Base:Clone()
	:Animation("Fire")
		:AssetId("rbxassetid://FIRE_ID")
		:Layer("UpperBody")
		:Looped(false)
	:Done()
	:Build()
-- Base is unchanged

Merge

BehaviorBuilder:Merge(
OtherBuiltBehavior--

A built behavior to merge in.

) → BehaviorBuilder

Merges a built behavior into this builder.

Animations, layers, states, and predicates from Other are added to this builder. If a name collision is detected (animation, layer, or state with the same name already exists), the incoming item is skipped and a warning is logged.

Predicates from Other overwrite existing predicates with the same name.

local WeaponBehavior = Motix.BehaviorBuilder.new()
	:Animation("Fire"):AssetId("..."):Layer("UpperBody"):Looped(false):Priority(5):Done()
	:Build()

local FullBehavior = Motix.BehaviorBuilder.Humanoid()
	:Merge(WeaponBehavior)
	:Build()

When

BehaviorBuilder:When(
Conditionany,--

Truthy value gates the block. Falsy skips it.

Fn(builderBehaviorBuilder) → ()--

Block to apply if condition is truthy.

) → BehaviorBuilder

Conditionally applies a block of builder calls without breaking the fluent chain.

If Condition is falsy the builder is returned unchanged. The callback receives self and is called for its side effects.

local Behavior = Motix.BehaviorBuilder.Humanoid()
	:When(isCombatMode, function(b)
		b:Animation("ADS"):AssetId("..."):Layer("UpperBody"):Looped(true):Done()
	end)
	:Build()

Build

BehaviorBuilder:Build() → BuiltBehavior?--

Frozen built behavior, or nil if validation failed.

Validates the current configuration and returns a frozen BuiltBehavior.

All validation errors are collected and logged together. Returns nil if any error is found. Call :Build() multiple times to produce independent frozen results from the same builder.

The returned BuiltBehavior exposes one method:

BuiltBehavior:CreateController(characterId, animator, isOwningClient, owningPlayer?)

Returns a ControllerConfig table ready to pass to Motix.new().

local Behavior = BehaviorBuilder.new()
	-- ...
	:Build()

local Config = Behavior:CreateController(
	character.Name,
	character.Humanoid:FindFirstChildOfClass("Animator"),
	isOwningClient,
	player
)

local Controller = Motix.new(Config)
Show raw api
{
    "functions": [
        {
            "name": "new",
            "desc": "Creates a new empty builder.",
            "params": [],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "BehaviorBuilder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 74,
                "path": "docs/BehaviorBuilder.lua"
            }
        },
        {
            "name": "Animation",
            "desc": "Opens the animation configuration sub-builder for an animation with the given name.\n\nThe name must be unique within this builder. It is also the name used to look up the\nanimation in `AnimationRegistry` and the string passed to `Controller:Play()`.\n\n**Available setters:**\n\n| Method | Type | Default | Description |\n|---|---|---|---|\n| `:AssetId(id)` | `string` | required | The `rbxassetid://...` for this animation. |\n| `:Layer(name)` | `string` | required | The layer this animation belongs to. |\n| `:Group(name)` | `string?` | `nil` | Exclusive group name. Only one animation per group may play at a time. |\n| `:Priority(n)` | `number` | `0` | Conflict priority within the layer or group. Higher wins. |\n| `:Looped(v)` | `boolean` | `false` | Whether the animation loops. |\n| `:FadeIn(t)` | `number` | `0.1` | Fade-in time in seconds. |\n| `:FadeOut(t)` | `number` | `0.1` | Fade-out time in seconds. |\n| `:Speed(s)` | `number` | `1.0` | Playback speed multiplier. |\n| `:Weight(w)` | `number` | `1.0` | Blend weight for this animation within its layer. Range `(0, 1]`. |\n| `:CanInterrupt(v)` | `boolean` | `true` | Whether a lower-priority group member can interrupt this animation. |\n| `:MinDuration(d)` | `number?` | `nil` | Minimum seconds before this animation can be interrupted by a group conflict. |\n| `:Tag(tag)` | `string` | | Appends a single tag. Multiple calls allowed. |\n| `:Tags(tags)` | `{ string }` | `{}` | Replaces the entire tag list. |\n| `:Additive(v)` | `boolean` | `false` | Whether the animation track is played in additive blending mode. |\n| `:Metadata(t)` | `table?` | `nil` | Arbitrary key-value table stored with the config. |\n\nCall `:Done()` to return to the root builder.\n\n```lua\n:Animation(\"Reload\")\n\t:AssetId(\"rbxassetid://RELOAD_ID\")\n\t:Layer(\"UpperBody\")\n\t:Group(\"WeaponAction\")\n\t:Priority(5)\n\t:Looped(false)\n\t:FadeIn(0.1)\n\t:FadeOut(0.15)\n\t:CanInterrupt(false)\n:Done()\n```",
            "params": [
                {
                    "name": "Name",
                    "desc": "Unique animation name.",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "AnimationBuilder"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 122,
                "path": "docs/BehaviorBuilder.lua"
            }
        },
        {
            "name": "Layer",
            "desc": "Opens the layer configuration sub-builder for a layer with the given name.\n\nThe name must be unique within this builder. It must match the `Layer` field of at least\none animation config or a state's `ActiveLayer` / `SuppressLayer` entry.\n\n**Available setters:**\n\n| Method | Type | Default | Description |\n|---|---|---|---|\n| `:Order(n)` | `number` | required | Integer order for blending priority. Lower values are evaluated first. Must be unique. |\n| `:BaseWeight(w)` | `number` | `1.0` | Default layer weight when active. Range `[0, 1]`. |\n| `:LerpRate(r)` | `number` | `8.0` | Speed in units per second at which weight interpolates toward its target. Use `math.huge` for instant snapping. |\n| `:Additive(v)` | `boolean` | `false` | When true, this layer composes with lower layers rather than replacing them. |\n| `:Isolated(v)` | `boolean` | `false` | When true, this layer does not interact with other layers during blending. |\n\nCall `:Done()` to return to the root builder.\n\n```lua\n:Layer(\"UpperBody\")\n\t:Order(1)\n\t:BaseWeight(1.0)\n\t:Additive(true)\n\t:LerpRate(6.0)\n:Done()\n```",
            "params": [
                {
                    "name": "Name",
                    "desc": "Unique layer name.",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "LayerBuilder"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 156,
                "path": "docs/BehaviorBuilder.lua"
            }
        },
        {
            "name": "State",
            "desc": "Opens the state configuration sub-builder for a state with the given name.\n\nStates define what happens when the state machine enters or exits them, which layers are\nactive or suppressed, and what conditions trigger transitions to other states.\n\n**Available methods:**\n\n| Method | Description |\n|---|---|\n| `:OnEntry()` | Returns a directive list builder for entry actions. |\n| `:OnExit()` | Returns a directive list builder for exit actions. |\n| `:Transition(toState, condition)` | Adds a transition rule. |\n| `:ActiveLayer(name)` | Marks a layer as active (set to BaseWeight) when this state is entered. |\n| `:SuppressLayer(name)` | Marks a layer as suppressed (set to 0) when this state is entered. |\n\n**Directive list builder methods** (returned by `:OnEntry()` and `:OnExit()`):\n\n| Method | Effect |\n|---|---|\n| `:Play(animName)` | Plays the animation when the directive fires |\n| `:Stop(animName, immediate?)` | Stops the animation when the directive fires |\n| `:StopGroup(groupName, immediate?)` | Stops the group when the directive fires |\n| `:Done()` | Returns to the state builder |\n\n**Transition builder methods** (returned by `:Transition()`):\n\n| Method | Description |\n|---|---|\n| `:Priority(n)` | Priority for this transition rule. Higher wins when multiple conditions are true simultaneously. |\n| `:Done()` | Returns to the state builder |\n\nCall `:Done()` on the state builder to return to the root builder.\n\n```lua\n:State(\"Jump\")\n\t:OnEntry():Play(\"JumpRise\"):Done()\n\t:OnExit():Stop(\"JumpRise\"):StopGroup(\"WeaponAction\"):Done()\n\t:ActiveLayer(\"Base\")\n\t:SuppressLayer(\"UpperBody\")\n\t:Transition(\"Idle\", \"IsGrounded\"):Priority(10):Done()\n:Done()\n```\n\nStates with no transitions are terminal states. The state machine stays in them\nindefinitely until `RequestStateTransition` is called.",
            "params": [
                {
                    "name": "Name",
                    "desc": "Unique state name.",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "StateBuilder"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 210,
                "path": "docs/BehaviorBuilder.lua"
            }
        },
        {
            "name": "Predicate",
            "desc": "Registers a named predicate function.\n\nPredicates are called every frame by the state machine to evaluate transition conditions.\nThe function must return a boolean. Keep predicates cheap: avoid yielding, remote reads,\nor per-call allocations.\n\nA predicate registered once can be referenced by any number of transitions across any\nnumber of states.\n\n```lua\n:Predicate(\"IsGrounded\", function()\n\treturn humanoid.FloorMaterial ~= Enum.Material.Air\nend)\n```",
            "params": [
                {
                    "name": "Name",
                    "desc": "The condition name referenced in `:Transition(toState, conditionName)`.",
                    "lua_type": "string"
                },
                {
                    "name": "Fn",
                    "desc": "The predicate function.",
                    "lua_type": "() -> boolean"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "BehaviorBuilder"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 234,
                "path": "docs/BehaviorBuilder.lua"
            }
        },
        {
            "name": "InitialState",
            "desc": "Sets the initial state for the state machine.\n\nMust match one of the state names defined with `:State()`. Required: `:Build()` returns\n`nil` if `InitialState` is not set or references an undefined state.\n\n```lua\n:InitialState(\"Idle\")\n```",
            "params": [
                {
                    "name": "Name",
                    "desc": "The name of the initial state.",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "BehaviorBuilder"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 249,
                "path": "docs/BehaviorBuilder.lua"
            }
        },
        {
            "name": "Clone",
            "desc": "Returns an independent `BehaviorBuilder` that is a deep copy of this builder.\n\nAnimations, layers, states, predicates, and initial state are all cloned. Changes to\neither builder after cloning do not affect the other.\n\n```lua\nlocal Base  = Motix.BehaviorBuilder.Humanoid()\nlocal Armed = Base:Clone()\n\t:Animation(\"Fire\")\n\t\t:AssetId(\"rbxassetid://FIRE_ID\")\n\t\t:Layer(\"UpperBody\")\n\t\t:Looped(false)\n\t:Done()\n\t:Build()\n-- Base is unchanged\n```",
            "params": [],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "BehaviorBuilder"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 273,
                "path": "docs/BehaviorBuilder.lua"
            }
        },
        {
            "name": "Merge",
            "desc": "Merges a built behavior into this builder.\n\nAnimations, layers, states, and predicates from `Other` are added to this builder.\nIf a name collision is detected (animation, layer, or state with the same name already\nexists), the incoming item is skipped and a warning is logged.\n\nPredicates from `Other` overwrite existing predicates with the same name.\n\n```lua\nlocal WeaponBehavior = Motix.BehaviorBuilder.new()\n\t:Animation(\"Fire\"):AssetId(\"...\"):Layer(\"UpperBody\"):Looped(false):Priority(5):Done()\n\t:Build()\n\nlocal FullBehavior = Motix.BehaviorBuilder.Humanoid()\n\t:Merge(WeaponBehavior)\n\t:Build()\n```",
            "params": [
                {
                    "name": "Other",
                    "desc": "A built behavior to merge in.",
                    "lua_type": "BuiltBehavior"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "BehaviorBuilder"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 297,
                "path": "docs/BehaviorBuilder.lua"
            }
        },
        {
            "name": "When",
            "desc": "Conditionally applies a block of builder calls without breaking the fluent chain.\n\nIf `Condition` is falsy the builder is returned unchanged. The callback receives `self`\nand is called for its side effects.\n\n```lua\nlocal Behavior = Motix.BehaviorBuilder.Humanoid()\n\t:When(isCombatMode, function(b)\n\t\tb:Animation(\"ADS\"):AssetId(\"...\"):Layer(\"UpperBody\"):Looped(true):Done()\n\tend)\n\t:Build()\n```",
            "params": [
                {
                    "name": "Condition",
                    "desc": "Truthy value gates the block. Falsy skips it.",
                    "lua_type": "any"
                },
                {
                    "name": "Fn",
                    "desc": "Block to apply if condition is truthy.",
                    "lua_type": "(builder: BehaviorBuilder) -> ()"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "BehaviorBuilder"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 317,
                "path": "docs/BehaviorBuilder.lua"
            }
        },
        {
            "name": "Build",
            "desc": "Validates the current configuration and returns a frozen `BuiltBehavior`.\n\nAll validation errors are collected and logged together. Returns `nil` if any error is\nfound. Call `:Build()` multiple times to produce independent frozen results from the same\nbuilder.\n\nThe returned `BuiltBehavior` exposes one method:\n\n**`BuiltBehavior:CreateController(characterId, animator, isOwningClient, owningPlayer?)`**\n\nReturns a `ControllerConfig` table ready to pass to `Motix.new()`.\n\n```lua\nlocal Behavior = BehaviorBuilder.new()\n\t-- ...\n\t:Build()\n\nlocal Config = Behavior:CreateController(\n\tcharacter.Name,\n\tcharacter.Humanoid:FindFirstChildOfClass(\"Animator\"),\n\tisOwningClient,\n\tplayer\n)\n\nlocal Controller = Motix.new(Config)\n```",
            "params": [],
            "returns": [
                {
                    "desc": "Frozen built behavior, or nil if validation failed.",
                    "lua_type": "BuiltBehavior?"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 351,
                "path": "docs/BehaviorBuilder.lua"
            }
        },
        {
            "name": "Humanoid",
            "desc": "Returns a pre-configured builder for a standard humanoid character.\n\nIncludes three animations (Idle, Walk, Run) with placeholder asset IDs, two layers\n(Base at order 0, UpperBody additive at order 1), and a predicate-driven state machine\nwith `IsIdle`, `IsWalking`, and `IsRunning` predicates.\n\nReplace the placeholder `rbxassetid://0` values with real animation IDs before\ncalling `:Build()`.\n\n```lua\nlocal Behavior = Motix.BehaviorBuilder.Humanoid()\n\t-- Override or extend before building\n\t:Build()\n```\n\n:::tip\nUse this as a starting point. Chain additional animations, layers, or states on top before\ncalling `:Build()`.\n:::",
            "params": [],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "BehaviorBuilder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 378,
                "path": "docs/BehaviorBuilder.lua"
            }
        }
    ],
    "properties": [],
    "types": [],
    "name": "BehaviorBuilder",
    "desc": "Fluent typed configuration builder for [AnimationController].\n\nInstead of constructing raw config tables by hand, chain builder methods and call\n`:Build()` to produce a validated, frozen `BuiltBehavior`.\n\n```lua\nlocal Motix = require(ReplicatedStorage.Motix)\n\nlocal Behavior = Motix.BehaviorBuilder.new()\n\t:Animation(\"Idle\")\n\t\t:AssetId(\"rbxassetid://IDLE_ID\")\n\t\t:Layer(\"Base\")\n\t\t:Looped(true)\n\t\t:Priority(0)\n\t\t:FadeIn(0.2)\n\t\t:FadeOut(0.2)\n\t:Done()\n\t:Layer(\"Base\")\n\t\t:Order(0)\n\t\t:BaseWeight(1.0)\n\t\t:LerpRate(8.0)\n\t:Done()\n\t:State(\"Idle\")\n\t\t:OnEntry():Play(\"Idle\"):Done()\n\t\t:OnExit():Stop(\"Idle\"):Done()\n\t\t:ActiveLayer(\"Base\")\n\t\t:Transition(\"Walk\", \"IsWalking\"):Priority(10):Done()\n\t:Done()\n\t:Predicate(\"IsWalking\", function()\n\t\treturn humanoid.MoveDirection.Magnitude > 0.1\n\tend)\n\t:InitialState(\"Idle\")\n\t:Build()\n```\n\n**Builder overview:**\n\n| Method | Configures |\n|---|---|\n| `:Animation(name)` | Opens the animation sub-builder |\n| `:Layer(name)` | Opens the layer sub-builder |\n| `:State(name)` | Opens the state sub-builder |\n| `:Predicate(name, fn)` | Registers a boolean predicate function |\n| `:InitialState(name)` | Sets the initial state machine state |\n| `:Clone()` | Returns an independent copy of this builder |\n| `:Merge(other)` | Merges a built behavior into this builder (non-destructive) |\n| `:When(condition, fn)` | Conditionally applies a block without breaking the chain |\n| `:Build()` | Validates and returns a frozen BuiltBehavior |\n\n:::tip Presets\nUse `BehaviorBuilder.Humanoid()` as a starting point for standard humanoid characters.\nIt includes Idle, Walk, and Run animations on `Base` and `UpperBody` layers with a\npredicate-driven state machine.\n:::\n\n:::caution Build-time validation\nAll validation is deferred to `:Build()`. The builder never throws mid-chain. Errors are\ncollected and reported together when `:Build()` is called. `:Build()` returns `nil` if\nany error is found.\n:::",
    "source": {
        "line": 65,
        "path": "docs/BehaviorBuilder.lua"
    }
}