AnimationController
Per-character animation controller for Motix.
AnimationController manages all active animations for a single character or entity. It
drives a built-in state machine, routes play requests through layer conflict resolution and
exclusive group management, and provides per-frame weight interpolation for smooth blending.
Create one controller per character. Controllers do not share state.
local Motix = require(ReplicatedStorage.Motix)
-- Build the behavior once per character type
local Behavior = Motix.BehaviorBuilder.Humanoid():Build()
-- Create a controller for a specific character
local Config = Behavior:CreateController(
character.Name,
character.Humanoid:FindFirstChildOfClass("Animator"),
true, -- isOwningClient
Players.LocalPlayer
)
local Controller = Motix.new(Config)
Controller.OnPlay:Connect(function(animName)
print("Playing:", animName)
end)
Controller:Play("Idle")
The AnimationController module is re-exported as the return value of the root Motix
module, so Motix.new(Config) creates a controller directly.
Registry required
AnimationRegistry must be initialized before any controller is created. Call
AnimationRegistry.GetInstance():Init(configs) once at startup.
Properties
OnPlay
AnimationController.OnPlay: Signal<string>Fires when an animation begins playing on this controller.
The argument is the animation config name. Connect once at initialization to react to any animation on this controller.
Controller.OnPlay:Connect(function(animationName)
-- React to any animation starting
end)
OnStop
AnimationController.OnStop: Signal<string>Fires when an animation stops on this controller.
The argument is the animation config name.
Controller.OnStop:Connect(function(animationName)
-- React to any animation stopping
end)
Functions
new
Creates a new AnimationController from a ControllerConfig.
The config is typically produced by BuiltBehavior:CreateController(). Constructing it
manually is valid but not recommended. Use the builder instead to ensure all required
fields are present and validated.
ControllerConfig fields:
| Field | Type | Description |
|---|---|---|
CharacterId |
string |
Unique identifier for this character. Used by MotixNet for ownership tracking. |
Animator |
Animator? |
The Roblox Animator instance. Ignored on the server. |
IsOwningClient |
boolean |
Whether this is the client that owns this character. Controls whether MotixNet sends intents. |
OwningPlayer |
Player? |
The player who owns this character. Optional, used by MotixNet. |
LayerProfiles |
{ LayerProfile } |
Layer definitions. Must match the layers referenced in animation configs. |
States |
{ StateDefinition } |
State definitions for the state machine. |
InitialState |
string |
The state the machine starts in. |
Predicates |
{ [string]: () -> boolean } |
Named predicate functions for state transitions. |
local Config = Behavior:CreateController(
characterId,
animator,
isOwningClient,
player
)
local Controller = Motix.new(Config)
Play
AnimationController:Play(AnimationName: string--
The registered name of the animation to play.
) → ()Queues an animation to play on the next frame.
If the animation is already playing, the request is a no-op. The request is processed during the controller's frame tick through layer conflict resolution and group management.
Controller:Play("Fire")
CAUTION
The animation name must be registered in AnimationRegistry. An unregistered name
produces a warning and the request is dropped.
PlayTag
AnimationController:PlayTag(Tag: string--
The tag to look up.
) → ()Plays all animations with the given tag.
Equivalent to calling Play for each animation registered under the tag. Tag membership
is set via :Tag() or :Tags() on the animation builder.
Controller:PlayTag("footstep")
If no animations are registered under the tag, this is a no-op.
Stop
AnimationController:Stop(AnimationName: string,--
The registered name of the animation to stop.
Immediate: boolean?--
If true, stop without fade. Default false.
) → ()Stops an animation.
If Immediate is true, the animation stops without any fade-out. Otherwise, the
animation fades out using its configured FadeOutTime.
If the animation is in the pending queue but has not started playing, it is removed from the queue immediately.
Controller:Stop("Idle") -- fade out
Controller:Stop("Idle", true) -- immediate stop
StopGroup
AnimationController:StopGroup(GroupName: string,--
The group name to stop.
Immediate: boolean?--
If true, stop all group members immediately. Default false.
) → ()Stops all animations in the given exclusive group.
Equivalent to calling Stop on every animation in the group that is currently active or
queued.
Controller:StopGroup("WeaponAction")
Controller:StopGroup("WeaponAction", true) -- immediate
RequestStateTransition
AnimationController:RequestStateTransition(StateName: string,--
The target state name.
Priority: number--
Higher values win when multiple transitions compete in the same frame.
) → ()Requests a manual state transition.
The transition is queued and processed in the next frame's state machine tick. If multiple transitions are queued in the same frame, the highest priority wins.
Manual transitions bypass predicate evaluation. The target state must be defined in the behavior.
humanoid.Jumping:Connect(function()
Controller:RequestStateTransition("Jump", 100)
end)
GetActiveGroupAnimMap
AnimationController:GetActiveGroupAnimMap() → {[string]: string}--
Map from group name to active animation name.
Returns a map from exclusive group name to the currently active animation name in that group.
Only includes groups that have an animation actively playing (not fading out). Useful for debugging or for game logic that needs to know which animation owns a group slot.
local GroupMap = Controller:GetActiveGroupAnimMap()
if GroupMap["WeaponAction"] == "Reload" then
-- Block fire input while reloading
end
If an invariant is violated (two animations active in the same group), a warning is logged and both entries are included.
AttachInspector
AnimationController:AttachInspector() → DebugInspectorAttaches a debug inspector to the controller and returns it.
The inspector provides a live view of active animations, layer weights, and state machine status. Attach this during development to verify that layers, groups, and state transitions behave as expected.
local Inspector = Controller:AttachInspector()
Destroy
AnimationController:Destroy() → ()Tears down the controller completely.
Disconnects the frame loop, stops all active animations immediately, destroys all pooled
wrappers, fires OnStop for any active animations, and destroys the OnPlay and OnStop
signals.
After this call the controller is inert. Do not call any method on it after Destroy.
Controller:Destroy()