Skip to content

Animation state machines

The WbpAnimStateMachine module is a full authoring and runtime system for driving UUserWidget animation behavior with named states, explicit transitions, built-in rules, live debugging, testing tools, snapshots, sub-state machines, parallel tracks, Curve Atlas timed property sequences, Enhanced Input bindings, and Sequencer integration.

Blueprint and C++ controls support looping, reverse and ping-pong playback, interruption priorities, delayed transitions, completion events, history, nested machines, and parallel animation tracks.

Integrations cover Enhanced Input, mapping contexts, focus, Gameplay Tags, forwarded Gameplay Ability System events, view-model properties, and Sequencer. Automatic ticking, snapshots, and reduced-motion behavior are included.

The editor provides graph authoring, common UI presets, validation, live debugging, transition breakpoints, test sequences, coverage, fuzz testing, and definition comparisons. Transition blending exposes callbacks and blend values so the widget can implement its crossfade.

For a task-focused walkthrough, use the User Guide. For types and runtime behavior, use the Technical Reference.

Most UI animation workflows in Unreal start out simple:

  • call PlayAnimation
  • wait for an event
  • call another animation
  • branch on hover, focus, input source, or gameplay state

That works for one button or one panel. It starts breaking down when a widget has real authored behavior:

  • a button that supports mouse hover, controller focus, pressed, disabled, and validation error states
  • a modal that has intro, idle, confirm, cancel, and outro flows
  • a toast that appears, waits, dismisses automatically, and can also be dismissed early
  • a loading or matchmaking panel with layered base flow, activity pulse, and error overlays

At that point the animation logic often becomes a web of:

  • scattered Blueprint branches
  • duplicated condition checks
  • fragile animation-name strings
  • transitions that silently fail
  • behaviors that are hard to debug in PIE

WbpAnimStateMachine solves that by making UI behavior explicit. Instead of asking “which animation do I play next?”, you define:

  • the states the widget can be in
  • the transitions allowed between those states
  • the rules that must pass before a transition is allowed
  • the tooling needed to debug and test the result

The result is a workflow that is easier to reason about, easier to reuse, and easier to trust.

The module works especially well for widgets with recognizable behavior over time. Common examples include:

  • buttons
  • toggle buttons
  • tabs
  • cards
  • tooltips
  • modals
  • toasts
  • loading screens
  • menu panels
  • nested composite widgets
  • scripted UI reveals driven by Sequencer

It is just as useful for small indie UI as it is for larger production interfaces. Small teams get speed and clarity. Larger teams get validation, debugger tooling, graph authoring, snapshots, tracks, and better long-term maintainability.

There are three core pieces:

This is still where the real UMG animations live.

The state machine does not replace your widget blueprint. It orchestrates it.

This is a UWbpAnimStateMachineDefinition data asset that stores:

  • states
  • transitions
  • rules
  • graph layout
  • notes
  • input bindings
  • presets
  • sub-machine references

This is the authored behavior of the widget.

This is a UWbpAnimStateMachine instance created for a widget at runtime.

It evaluates transitions, drives animations, stores blackboard values, binds input, tracks history, and powers the debugger.

The module is not just a runtime helper. It ships as a full workflow:

  • dedicated asset editor
  • graph authoring
  • details validation and health summaries
  • debugger tab
  • tester and random-walk fuzzing
  • persistent test sequence assets
  • snapshots for save/load
  • sub-state machines
  • parallel tracks
  • input bindings
  • CommonUI activation bridge
  • Curve Atlas timed property sequences
  • Sequencer track support
  • export utilities
  • example definitions
  • automated test suite

That is important because UI behavior is not only about playing animations. It is about making authored behavior understandable to the people building and debugging it.

Imagine a simple modal dialog.

Without a state machine, the logic usually becomes:

  • construct widget
  • play intro animation
  • when intro finishes, enable input
  • on confirm, play confirm pulse
  • on close, play outro animation
  • when outro finishes, remove from parent

With WbpAnimStateMachine, that becomes:

  • states: Hidden, Intro, Idle, Confirming, Outro
  • transitions:
  • Hidden -> Intro
  • Intro -> Idle on animation finished
  • Idle -> Confirming manually
  • Idle -> Outro manually
  • Confirming -> Outro on animation finished
  • Outro -> Hidden on animation finished

Now the behavior is visible, searchable, testable, and debuggable in one place.

To get the most out of the module, you should have:

  • a widget blueprint
  • one or more UMG animations authored in that widget
  • the plugin enabled in your project

Recommended habit:

  • keep your state names close to your animation names where practical

Example:

  • state Hover
  • animation Hover

That is not required, but it makes authoring and maintenance much easier.

The quickest way to learn the module is to build a simple button or panel flow from a preset.

In the Content Browser:

  1. Right-click
  2. Choose Miscellaneous
  3. Choose Data Asset
  4. Pick WbpAnimStateMachineDefinition
  5. Name it something like DA_ButtonAnimStateMachine

The asset opens in its own editor with three main surfaces:

  • Graph
  • Details
  • Debugger

This is where most authoring happens.

Set OwnerWidgetClass to the widget blueprint that will use this definition.

This is one of the most important setup steps, because it allows the editor to:

  • show animation dropdowns from the real widget
  • show entry, exit, and condition function dropdowns from the real widget class
  • validate authored names against the widget

If you skip this step, you can still author data, but you lose a lot of quality-of-life and validation value.

Choose a preset and click Apply Preset.

Available presets are designed to give you a believable starting point rather than an empty canvas.

Typical examples include:

  • Button
  • ToggleButton
  • Panel
  • Toast
  • Tab
  • LoadingScreen
  • Carousel

Applying a preset fills in a useful first version of:

  • InitialState
  • States
  • Transitions

This is a great way to learn how the system thinks.

Step 5. Match the animations in your widget

Section titled “Step 5. Match the animations in your widget”

If your definition has states like:

  • Idle
  • Hover
  • Pressed
  • Focused
  • Disabled

your widget should contain matching animations or intentionally remapped AnimationName values.

The state machine will look up and play those widget animations at runtime.

Step 6. Create the runtime machine in the widget

Section titled “Step 6. Create the runtime machine in the widget”

In Blueprint, the common path is:

  • create and store a WbpAnimStateMachine reference
  • call CreateAndInitializeStateMachine
  • keep that result on the widget

In C++, the common path looks like this:

StateMachine = UWbpAnimStateMachine::CreateStateMachine(this, DefinitionAsset);

Once the machine exists, the widget can transition between states instead of manually playing animations.

A state represents a named UI mode. A widget is always in one current state.

For example, a button might have:

  • Idle
  • Hover
  • Pressed
  • Focused
  • Disabled

A modal might have:

  • Hidden
  • Intro
  • Idle
  • Outro

Each state can describe more than just an animation. It can also define behavior around that animation.

Important state fields include:

  • StateName
  • AnimationName
  • PlayMode
  • PlaybackRate
  • StartTime
  • bRestoreState
  • ReEnterPolicy
  • InterruptPriority
  • AutoTransitionDelay
  • AutoTransitionState
  • EntryFunctionName
  • ExitFunctionName
  • Group
  • StateTags
  • DesignerNotes
  • EditorNodeColor
  • SubMachineDefinition
  • SubMachineMode

Sometimes a widget is already in a state and receives another request to enter it again.

ReEnterPolicy controls what happens in that case.

Typical policies include:

  • ignore the request
  • restart the animation
  • fire enter-style events without fully restarting

This matters a lot for behaviors like:

  • replaying a pulse state
  • re-triggering a pressed state
  • avoiding needless resets on focus or hover spam

A state can automatically move to another state after a delay.

This is useful for things like:

  • a toast becoming visible for three seconds and then dismissing
  • a loading hint disappearing after a short dwell time

You author that with:

  • AutoTransitionDelay
  • AutoTransitionState

States can call widget functions when they are entered or exited.

This is useful when animation is only part of the behavior and the state should also:

  • play audio
  • toggle other widget visibility
  • set additional data
  • notify a controller object

Transitions define the legal paths between states.

If states are the places your widget can be, transitions are the roads between them.

This is one of the most powerful parts of the system because it forces UI behavior to be explicit.

Important transition fields include:

  • FromState
  • ToState
  • Trigger
  • BlendTime
  • ConditionFunctionName
  • Rules
  • RuleMatchMode
  • TransitionTag
  • DesignerNotes
  • bEnableBreakpoint

TransitionGuard is a C++-only integration hook. Blueprint-authored guards should use ConditionFunctionName or the built-in transition Rules list.

Transition blending supplies callbacks and blend values. The widget owns the crossfade implementation; setting blend timing does not by itself blend arbitrary widget properties.

These occur only when code or Blueprint explicitly requests them.

Examples:

  • Idle -> Hover
  • Hover -> Pressed
  • Focused -> Idle

These happen when the current state animation finishes.

Examples:

  • Intro -> Idle
  • Pressed -> Hover
  • Outro -> Hidden

This is one of the cleanest ways to author chained UI motion.

If FromState is None, the transition can match from any current state.

This is useful for authored rules like:

  • Any -> Disabled
  • Any -> Focused
  • Any -> Error

Transitions can carry breakpoints for PIE debugging.

When a breakpoint-enabled transition fires, the debugger can pause execution so you can inspect:

  • current and previous state
  • blackboard values
  • transition history
  • why a machine got here

This is especially valuable for difficult state flows that only misbehave in live gameplay.

A big strength of the module is that transitions do not have to rely only on custom Blueprint condition functions.

The runtime supports built-in rule blocks that can evaluate:

  • blackboard float values
  • blackboard bool values
  • blackboard name values
  • blackboard int values
  • blackboard string values
  • time spent in the current state
  • animation progress
  • current state
  • previous state

This lets you author many common cases directly in data.

Examples:

  • only allow dismiss if CanDismiss == true
  • only allow the next state once animation progress is greater than 0.8
  • only allow a return transition if the previous state was Hover

That means fewer custom helper functions and a more readable asset.

The blackboard is a lightweight per-machine data store used to drive rules and stateful behavior.

Supported types include:

  • float
  • bool
  • FName
  • int32
  • FString
  • UObject*

Typical UI blackboard values include:

  • HasUnread
  • SelectedTab
  • CanDismiss
  • InputSource
  • CurrentPage
  • ErrorMode

You can read and write blackboard values from Blueprint or C++, and the debugger can display them live during PIE.

This makes the state machine much more than a simple animation player. It becomes a small UI behavior controller.

The Blueprint library is designed to make the module pleasant to use in real widget graphs.

Core Blueprint helpers include:

  • CreateAndInitializeStateMachine
  • GoToState
  • GoBack
  • CanTransitionTo
  • GetAvailableTransitions
  • GetCurrentState
  • IsInState
  • blackboard setters and getters
  • snapshot save and restore helpers
  • track helpers
  • input binding helpers
  • Sequencer helpers

One of the biggest Blueprint ergonomics wins is GoToStateAndWait.

This is a latent Blueprint call that lets you write simple authored flow in sequence instead of wiring temporary delegates.

Example pattern:

  1. GoToStateAndWait(Intro)
  2. continue execution after the target state is entered
  3. GoToState(Idle)
  4. continue with the rest of the scripted UI flow

This is especially useful for:

  • intros
  • tutorials
  • popups
  • scripted menu flows

Not every system that wants to drive the UI will already hold a direct pointer to the state machine.

Use FindMachineByDefinition(Widget, Definition) when you want to locate a machine that is already running on a widget.

This is useful for:

  • controller-level UI orchestration
  • game systems that need to trigger widget behavior indirectly
  • utilities that need to find a specific authored machine without storing it everywhere

The module supports two levels of restore behavior.

SaveState and RestoreState store only the current state name.

This is useful when the state itself is all that matters.

SaveMachineSnapshot and RestoreMachineSnapshot store:

  • current state
  • full blackboard values

This is the better choice when the widget carries real UI context, such as:

  • selected tab
  • sort mode
  • content mode
  • error flags
  • selection references

If a widget is meant to feel persistent across sessions or screen rebuilds, full snapshots are often the right answer.

Not every widget should be modeled as a single monolithic state machine.

That is what UWbpAnimStateMachineGroup is for.

Parallel tracks let one widget host multiple named machines, each responsible for its own layer of behavior.

Common track patterns include:

  • Base for the main panel flow
  • Hover for pointer and focus feedback
  • Attention for pulses or alerts
  • Modal for overlay state

This avoids giant combined states like:

  • Visible_Hovered_Attention
  • Visible_Focused_Disabled

Instead, the behaviors stay composable.

Large widgets often have a state that contains its own internal authored behavior.

Example:

  • parent state Searching
  • child machine states Pulse, Spin, Found

That is where sub-state machines help.

A state can reference a child definition through:

  • SubMachineDefinition
  • SubMachineMode

Useful modes include:

  • run child concurrently with parent
  • pause the parent while the child runs
  • enter the child and wait for it to exit

This is one of the most important scaling features in the module because it lets you compose authored behaviors instead of flattening everything into one large graph.

The module can bind transitions directly to UInputAction events.

This means a definition can author input-driven UI behavior without every widget having to manually bind all of it in Blueprint.

Each authored input binding can define:

  • InputAction
  • TriggerEvent
  • TargetState
  • bForce
  • CallerPriority

At runtime, the machine looks for an UEnhancedInputComponent on the owning player’s controller and binds automatically during initialization.

This is especially useful for:

  • controller-driven menu focus
  • confirm and cancel flows
  • gamepad navigation states
  • tab switching

If your project uses the CommonUI plugin, UWbpAnimCommonActivatableMixin provides a ready-made bridge between the CommonUI activation lifecycle and state machine transitions.

The mixin deliberately avoids a hard CommonUI plugin dependency. It works by reflecting the widget’s delegate properties at runtime. If a widget is not a CommonUI activatable widget, the bind call returns false and logs a clear warning - nothing breaks.

In any UCommonActivatableWidget subclass:

  1. Call BindActivationEvents(Self, StateMachine, "Active", "Inactive") during construct.
  2. From NativeOnActivated, call NotifyActivated(Self).
  3. From NativeOnDeactivated, call NotifyDeactivated(Self).

Because automatic FMulticastScriptDelegate binding requires a UFUNCTION trampoline that cannot be generated at runtime, the two notify calls are the bridge. They are a two-line addition to any activatable widget.

Instead of writing GoToState calls inside every widget subclass’s activate and deactivate overrides, you author the target state names once on the binding and call the two notify helpers everywhere else.

If your project uses Gameplay Ability System, you can wire ability events directly to UI state changes without embedding GoToState calls inside individual abilities.

A hit-react widget, a low-health pulse, a death screen — each of these needs to respond to a gameplay event. Without this feature, every ability or event handler manually finds the right widget and calls GoToState. With GAS bindings, you declare the mapping once on the definition asset and forward events with a single call.

  1. In the definition asset, open the GAS Events category and add one entry per event-to-state mapping. Each entry stores an EventTag, a target state name, and optional force/priority settings. If force is enabled, the binding still needs a CallerPriority that meets or exceeds the current state’s InterruptPriority.
  2. In your gameplay code (ability, delegate, C++ listener), call StateMachine->HandleGameplayEvent(Tag) whenever a relevant event fires.
  3. The machine evaluates all bindings using FGameplayTag::MatchesTag (parent tags match children) and calls GoToState for each match.

Matching bindings run in declaration order. Each GoToState call is independent, so if two bindings match the same tag, the second runs from whatever state the first one left the machine in. That can be useful for chained reactions, but it also means later bindings may be blocked by the transition table from the new current state.

The machine intentionally does not subscribe to UAbilitySystemComponent itself. UI widgets may not have ASC access, may be pooled across characters, or may be driven by different game objects depending on context. A single forwarding call gives you full control over which ASC instance is the source, without baking that assumption into the state machine.

FGameplayTag comes from the GameplayTags module, which is already a dependency of this module. Adding GAS event bindings to a definition asset does not require the GameplayAbilities plugin to be enabled.

The module includes a dedicated WBP Anim State Sequencer track for driving widget state transitions from Movie Scene playback.

This is useful when UI state changes should be authored on a timeline instead of only through widget logic.

Example uses:

  • splash screens
  • title card sequences
  • cinematic menu reveals
  • onboarding flows
  • guided UI walkthroughs

Typical workflow:

  1. bind the widget in Sequencer
  2. add a WBP Anim State track
  3. add sections for target states
  4. choose the target machine or machine group track
  5. author the desired timing on the timeline

This turns the module into something that can participate in broader Unreal presentation workflows instead of living only inside widget Blueprints.

The graph is where the module starts to feel like a real authored environment.

You can use it to:

  • place and organize states visually
  • create transitions by dragging between states
  • inspect transitions
  • search large graphs
  • zoom and pan around the canvas
  • auto-arrange layouts
  • align and distribute nodes
  • organize related areas with group boxes
  • leave notes for other authors

The graph includes:

  • pan and zoom
  • minimap
  • search
  • frame all
  • frame selected
  • rubber-band selection
  • multi-select
  • copy, paste, duplicate, and delete
  • zoom-level detail scaling
  • grid snap toggle
  • group boxes
  • sticky notes
  • standard graph comments
  • auto-arrange
  • selected transition inspector
  • transition context menus
  • state and transition quick editing
  • Backspace/Delete deletion

The default native graph favors stable node presentation over collapse/expand behavior.

For large machines, use search, frame-selection, comments, group boxes, minimap navigation, and the graph toolbar’s layout modes. The native graph is now the single visual authoring surface.

Transitions can be created by dragging from any node edge rather than only one hidden hotspot.

That makes the graph feel far more discoverable, especially for new users or larger graphs.

Group boxes are useful for visually organizing clusters of states like:

  • controller focus flow
  • accessibility-specific paths
  • loading and error behaviors

Sticky notes are useful for freeform authored comments like:

  • TODO reminders
  • warnings
  • mobile-only notes
  • design intent

Those features matter more than they may sound. They make large graphs much easier for teams to maintain together.

The debugger is one of the most valuable parts of the module once a project grows beyond trivial cases.

Open the definition asset and switch to the Debugger tab while PIE is running.

You can inspect:

  • live machine instances using that definition
  • current and previous state
  • time in state
  • animation progress
  • transition summaries
  • blocked transition reasons
  • blackboard values
  • transition logs
  • state timelines
  • runtime stats
  • condition breakpoints
  • transition breakpoints
  • multi-instance compare views

This turns state-machine debugging from guesswork into a concrete workflow.

Instead of asking “why did my widget not animate?”, you can usually answer:

  • what state it is in now
  • what it tried to do
  • what blocked it
  • what blackboard values were present at the time

The tester panel exists for the moments where the widget is not fully integrated yet but you still want to validate behavior.

It supports:

  • simulating transition scripts
  • tracking state coverage
  • random-walk fuzz testing
  • saving sequences as UWbpAnimTestSequenceAsset data assets
  • loading those assets back into the tester

The tester is intentionally a graph-reachability simulator, not a full runtime execution environment. It does not execute Blueprint condition functions, transition rule arrays, or InterruptPriority checks for forced transitions. Use PIE and the live debugger for those runtime-accurate checks.

This is especially helpful for:

  • validating a machine before gameplay code is done
  • spotting unreachable states
  • finding states that block all outgoing transitions
  • confirming that a preset or imported machine behaves as expected

Every sequence you build in the tester panel can now be saved as a Content Browser data asset. Enter a content path in the State Machine Test Asset field, or choose an existing UWbpAnimTestSequenceAsset with the picker, then press Save. Later, press Load to restore the sequence exactly.

This turns one-off manual test runs into repeatable, reviewable regression checks that live next to the rest of your project data.

The module also ships a suite of automated Unreal Engine tests (UIFoundry.WbpAnimStateMachine.*) covering the core runtime APIs:

  • basic transitions and state tracking
  • blackboard read/write round-trips for all supported types
  • snapshot save and restore
  • transition guard blocking and clearing
  • history and GoBack
  • gameplay event bindings, including exact tag matches, parent-to-child tag matches, uninitialized/no-match returns, and invalid target skips
  • definition validation (editor builds only)

Definition assets support utility actions for documentation, reuse, and pipeline workflows.

Available export-style actions include:

  • Export State Diagram (SVG)
  • Export Definition (JSON)
  • Import Definition (JSON)
  • Generate State Enum Header

These are written under:

  • Saved/WbpAnimStateMachineExports

Generated enum headers go to:

  • Saved/WbpAnimStateMachineExports/GeneratedHeaders

The generated enum is useful when you want a more explicit C++ workflow, but remember:

  • it is not automatically compiled into your project
  • if you want to use it in game code, move it into your project’s compiled Source tree

Use a button preset and map the main authored interaction states:

  • Idle
  • Hover
  • Pressed
  • Focused
  • Disabled

Then drive them from pointer and focus events or input bindings.

This gives you one consistent source of truth for button behavior instead of ad hoc PlayAnimation calls.

A classic toast setup looks like:

  • Spawn
  • Visible
  • Dismiss

You can author:

  • a transition from Spawn to Visible
  • an auto-transition from Visible after a delay
  • a final dismiss state and cleanup flow

This is one of the cleanest demonstrations of why authored state flow is better than hand-wired one-off animation logic.

A modal often looks like:

  • Hidden
  • Intro
  • Idle
  • Outro

Using finish-driven transitions makes this extremely clean:

  • Hidden -> Intro
  • Intro -> Idle
  • Idle -> Outro
  • Outro -> Hidden

Use a parent machine for the top-level screen state and a child machine for a smaller local flow.

For example:

  • parent machine handles Idle, Searching, Error
  • child machine inside Searching handles Pulse, Spin, Found

This keeps graphs readable even as the UI grows more capable.

If you want the module to stay pleasant as your project grows, these habits help a lot:

  • set OwnerWidgetClass immediately
  • use presets for your first pass
  • keep state names simple and stable
  • prefer built-in rules before creating many custom condition functions
  • use parallel tracks instead of forcing unrelated behaviors into one machine
  • use sub-state machines when one state has meaningful internal flow
  • add notes and group boxes to larger graphs
  • use breakpoints early when a flow becomes hard to reason about
  • use full snapshots when UI state includes real user context
  • treat the debugger as part of authoring, not only emergency troubleshooting
  • save regression sequences as data assets so you can replay them after graph changes
  • use UWbpAnimCommonActivatableMixin for CommonUI widgets to avoid duplicating transition calls in every subclass
  • call GoToState from gameplay or ability code at clear integration boundaries instead of scattering transition calls through the UI

If you are adopting the module for the first time, this is a good order:

  1. create a button or panel definition from a preset
  2. wire it into a widget and use GoToState
  3. add one or two built-in transition rules
  4. debug it in PIE
  5. try a toast or modal flow
  6. add a snapshot save/restore path
  7. save a test sequence as a data asset and reload it to confirm the machine still behaves correctly
  8. move up to tracks, sub-machines, or Sequencer as your UI grows
  9. add CommonUI mixin bindings or gameplay-code transition adapters when the project grows to need them

That path gives you the fastest return without having to use every advanced feature on day one.

Use the rest of the documentation based on what you need:

If you only remember one thing, remember this:

the module works best when you stop thinking in terms of “which animation should I play?” and start thinking in terms of “what state is this widget in, and what transitions are allowed from here?”