Skip to content

WBP Anim State Machine Walkthroughs

WBP Anim State Machine - Hands-On Walkthroughs

Section titled “WBP Anim State Machine - Hands-On Walkthroughs”

This document walks through six complete, real-world UI setups from first principles.

It is written for people who are new to Widget Blueprints or Unreal Blueprints in general. Every step, including things experienced developers would consider obvious, is spelled out explicitly.


If you have used Widget Blueprints before, skip ahead to Walkthrough 1. If not, read this section first.

A Widget Blueprint (WBP) is a type of Unreal asset that describes a piece of on-screen UI. It is made up of two parts:

  • The Designer tab - a visual canvas where you place UI elements such as images, text, buttons, and panels by dragging and dropping them.
  • The Graph tab - a Blueprint scripting area where you write the logic that controls those elements.

A Widget Blueprint is not displayed on screen by itself. You create an instance of it at runtime, usually by calling Create Widget from another Blueprint (such as a HUD or a Player Controller), and then add it to the viewport.

Inside a Widget Blueprint, the Animations panel (usually at the bottom left of the Designer tab) lets you create named animations. Each animation can move, fade, scale, or colour any element in the widget over time, using keyframes on a mini timeline.

These animations are the building blocks the state machine plays back. When the machine enters a state called Hover, it looks up a widget animation also called Hover and plays it.

You do not need to wire any Blueprint nodes to play an animation. The machine handles that automatically once the state and animation names match.

Think of the state machine as a traffic controller for your widget’s animations. Instead of writing Play Animation Hover in twenty different places across your Blueprint graph, you define:

  • States - the named modes the widget can be in (Idle, Hover, Pressed)
  • Transitions - the allowed moves between those states (Idle -> Hover, Hover -> Pressed)
  • Rules - optional conditions that must be true before a transition fires

Then, from Blueprint, you only ever say: “go to Hover”. The machine decides whether that is allowed, fires the correct animation, and keeps a record of where it came from.

The behavior is described in a Definition asset - a data asset you create in the Content Browser that stores states, transitions, and rules. It is separate from the widget blueprint. One definition asset can be reused by multiple different widget blueprints.

  1. A Widget Blueprint containing your UMG animations.
  2. A Definition asset (WbpAnimStateMachineDefinition) describing the states and transitions.
  3. A few Blueprint nodes inside the widget to create the machine and ask it to move between states.

Timeline animation vs Curve Atlas sequence

Section titled “Timeline animation vs Curve Atlas sequence”

Most walkthroughs use normal UMG animations because that is the common Widget Blueprint workflow. A state can also drive a lightweight timed property sequence from CurveAtlasDuration and CurveAtlasBindings.

Use a UMG animation when you want to edit keys directly in the Widget Blueprint timeline. Use a Curve Atlas sequence when a state only needs reusable curve-driven property motion such as opacity, transform, tint, or visibility thresholding. Both approaches still live inside the same state machine and can use OnAnimationFinished transitions when playback is finite.


Goal: A button widget that smoothly transitions between Idle, Hover, and Pressed states in response to mouse input.

Time estimate: 20-30 minutes for a first attempt.

A Widget Blueprint with three UMG animations - Idle, Hover, and Pressed - driven by a state machine. Hovering over the widget plays the hover animation. Clicking plays the pressed animation. Moving the mouse away returns to idle.


  1. In the Content Browser, right-click in a folder such as Content/UI/Widgets.
  2. Choose User Interface -> Widget Blueprint.
  3. Name it WBP_Button.
  4. Double-click it to open the Widget Blueprint editor.

The editor opens to the Designer tab by default.

Step 2 - Add a visual element to the widget

Section titled “Step 2 - Add a visual element to the widget”

For this walkthrough you just need something visible. A simple image or a coloured box is enough.

  1. In the Palette panel on the left, find Image.
  2. Drag an Image widget onto the canvas.
  3. In the Details panel on the right, set its size - for example, 400 x 100 - and give it a background colour under Brush -> Tint. Any colour is fine.
  4. Name it something like BG in the Hierarchy panel.

Animations live in the Animations panel at the bottom left. If you do not see it, make sure you are on the Designer tab, not the Graph tab.

  1. Click + Animation in the Animations panel.
  2. Name it exactly Idle (case matters - the state machine matches by name).
  3. The animation timeline opens at the bottom.
  4. Select the BG image in the Hierarchy.
  5. Click + Track in the timeline header and choose BG.
  6. Add a Render Opacity or Render Transform -> Scale track.
  7. Set keyframes so the button looks like its default resting state - for example, opacity 1.0 at time 0 and time 0.5 seconds. A flat, looping animation is fine for idle.
  1. Click + Animation again.
  2. Name it exactly Hover.
  3. Select BG, add a track, and keyframe a subtle scale or brightness change - for example, scale from 1.0 to 1.05 between 0 and 0.15 seconds.
  4. This animation will play once when the mouse enters. Choose Play Once as its play mode in the state configuration later.
  1. Click + Animation again.
  2. Name it exactly Pressed.
  3. Keyframe a quick scale-down pulse - for example, scale from 1.0 to 0.95 at 0.05 s, then back to 1.0 at 0.15 s.

Tip: The names Idle, Hover, and Pressed are case-sensitive. The state machine will look for an animation with the exact same name as the state. If the animation is named hover (lowercase h) but the state is Hover, the animation will not play - but the machine will still work correctly, it simply will not find the animation.


  1. In the Content Browser, right-click in a folder such as Content/UI/StateMachines.
  2. Choose Miscellaneous -> Data Asset.
  3. In the picker that opens, type WbpAnimStateMachineDefinition and select it.
  4. Name the asset DA_Button.
  5. Double-click it to open the asset editor.

The editor opens with the native Graph tab plus supporting tabs for Details, Debugger, Test, and Diff.

This is the single most important setup step. It tells the editor which widget blueprint owns the animations and functions you want to reference.

  1. Click the Details tab.
  2. Find the Owner Widget Class property.
  3. Click the dropdown and search for WBP_Button. Select it.

Once this is set, animation dropdowns and function dropdowns throughout the editor will populate from your real widget.

  1. In the Details tab, find Preset To Apply.
  2. Click the dropdown and select Button.
  3. Click Apply Preset.

This fills in a sensible starting set of states and transitions. Switch to the Graph tab - you should now see state nodes arranged on the canvas:

  • Idle
  • Hover
  • Pressed
  • Focused
  • Disabled

And transitions connecting them.

For this walkthrough we only need Idle, Hover, and Pressed. The extra states are not harmful - unused states are silently ignored at runtime.

If the nodes feel too spread out or the graph has been hand-edited, use the graph toolbar’s layout actions. Compact is usually best for a small button machine, while Flow keeps the initial state and common transition direction easy to read.

Step 7 - Review the states in the Details tab

Section titled “Step 7 - Review the states in the Details tab”

Click the Details tab and scroll to the States array. Expand the first few entries to see the defaults.

  • Idle - PlayMode: Loop, AnimationName: Idle
  • Hover - PlayMode: Play Once, AnimationName: Hover
  • Pressed - PlayMode: Play Once, AnimationName: Pressed

These defaults already match the animation names you created in Step 3. If your animation names differ, update AnimationName here.

Scroll to the Transitions array in the Details tab, or just read the arrows in the Graph tab.

The Button preset has:

  • Idle -> Hover - Manual (triggered by calling GoToState)
  • Hover -> Idle - Manual
  • Hover -> Pressed - Manual
  • Pressed -> Hover - On Animation Finished

The Pressed -> Hover transition fires automatically when the Pressed animation finishes playing. You do not need to call GoToState for that one.

Save the asset with Ctrl+S.


Step 9 - Add a variable to the Widget Blueprint

Section titled “Step 9 - Add a variable to the Widget Blueprint”
  1. Open WBP_Button in the Widget Blueprint editor.
  2. Click the Graph tab.
  3. In the My Blueprint panel on the left, click the + button next to Variables.
  4. Name the new variable StateMachine.
  5. In the Details panel on the right, change its Variable Type to WbpAnimStateMachine (search for it). Make sure it is an Object Reference, not a class reference or struct.
  6. Leave Instance Editable unchecked.

Step 10 - Create and initialize the machine on Construct

Section titled “Step 10 - Create and initialize the machine on Construct”
  1. In the Event Graph, find or add the Event Construct node (right-click -> search “Construct”).
  2. Right-click on an empty area of the graph and search for Create And Initialize State Machine.
  3. Connect the Exec output of Event Construct to the input of Create And Initialize State Machine.
  4. On the Create And Initialize State Machine node:
  • Target: connect Self (right-click -> “Get a reference to self” or type “Self” in the search).
  • Definition: click the asset picker and select DA_Button.
  1. Drag the Return Value pin of the node and choose Set -> StateMachine. This stores the machine in the variable you created.

Your graph should now read:

Event Construct -> Create And Initialize State Machine -> Set StateMachine

Step 11 - Add On Mouse Enter and On Mouse Leave overrides

Section titled “Step 11 - Add On Mouse Enter and On Mouse Leave overrides”
  1. In the My Blueprint panel, scroll down to Functions -> Override.
  2. Click Override and choose On Mouse Enter.
  3. An override function node appears. Inside it, right-click and search Go To WBP State.
  4. Connect the exec flow into the Go To WBP State node.
  5. On the Go To WBP State node:
  • Target: drag a Get StateMachine node and connect it.
  • State: type Hover.
  • State Definition: click the picker and select DA_Button (this enables the state name dropdown - you can also just type the name).
  1. Repeat for On Mouse Leave, choosing state Idle.
  1. Override On Mouse Button Down (same Override button in My Blueprint).
  2. Add a Go To WBP State node inside it, connecting the machine and state Pressed.
  3. At the end of the function, add a Return Node with Return Value = Handled - this tells Unreal the widget consumed the mouse event.

Note: On Mouse Button Down requires the widget to be focusable or to have Is Volatile enabled, and it only fires for the left mouse button by default. If the node never fires in PIE, check that the widget has Is Focusable checked in the Details panel of the Designer tab.

To see the button in PIE you need to add it to the viewport from somewhere. The simplest place for testing is the Level Blueprint.

  1. In the main editor toolbar, click Blueprints -> Open Level Blueprint.
  2. In the Level Blueprint event graph, right-click and add Event Begin Play.
  3. Right-click and search Create Widget. Select it.
  4. On the Create Widget node, set Class to WBP_Button.
  5. Drag from the Return Value pin and search for Add to Viewport. Connect it.
Event Begin Play -> Create Widget (WBP_Button) -> Add to Viewport
  1. Save and close the Level Blueprint.

Press Play in the Unreal editor.

  • Move the mouse over the button area. The hover animation should play.
  • Move the mouse away. The idle animation should restart.
  • Click the button. The pressed animation plays, then automatically transitions back to hover when it finishes.

If nothing happens, continue to the Debugging section below.


Open DA_Button in the asset editor and switch to the Debugger tab. Press Play in the main editor window. The Debugger tab should now show one live machine instance.

Look at:

  • Current State - this should change as you hover and click.
  • Transition Log - each attempt to transition is logged here, including blocked attempts and the reason they were blocked.
  • Blackboard - empty for this walkthrough, that is fine.

“Nothing happens when I hover”

  • Check that On Mouse Enter is connected correctly and reaches the Go To WBP State node.
  • Open the Debugger tab and look at the Transition Log while hovering. If a transition attempt appears but is blocked, it will show the reason.
  • Confirm the transition Idle -> Hover exists in the definition’s Transitions array. The preset should have added it.

“The animation name is wrong”

  • Open the Details tab of the definition. Expand the Hover state in the States array. Check that Animation Name matches the exact name of the animation in the widget. The names are case-sensitive.

“Pressed goes back to Idle instead of Hover”

  • The Pressed -> Hover transition has Trigger: On Animation Finished. When the Pressed animation ends, it goes to Hover automatically. That is correct behavior. Then Hover -> Idle fires when you explicitly call GoToState(Idle) on mouse leave.
  • If you want Pressed to return directly to Idle, change the Pressed -> Hover transition to Pressed -> Idle.

Goal: A modal panel that plays an intro animation when it opens, sits in an idle state, plays an outro animation when dismissed, then removes itself from the viewport.

Time estimate: 25-35 minutes.

A Widget Blueprint with four states: Hidden, Intro, Idle, and Outro. The transitions between Intro -> Idle and Outro -> Hidden fire automatically when those animations finish. The widget removes itself from the viewport when it enters the Hidden state.


  1. In the Content Browser, right-click -> User Interface -> Widget Blueprint.
  2. Name it WBP_Modal.
  3. Open it.
  4. In the Designer tab, add an Image or SizeBox to represent the modal panel.
  5. Name the root element ModalPanel in the Hierarchy.

In the Animations panel, create:

A single keyframe with ModalPanel at opacity 0 (or scale 0). Because this is a loop animation used as a persistent “invisible” state, set just one keyframe at time 0.

Keyframe the panel from invisible to fully visible over about 0.3 seconds. For example:

  • At time 0: opacity 0, scale (0.9, 0.9)
  • At time 0.3: opacity 1, scale (1.0, 1.0)

A looping animation while the modal is fully visible. This can be a single keyframe at full opacity and normal scale - no movement needed. The machine will hold here until dismissed.

The reverse of Intro:

  • At time 0: opacity 1, scale (1.0, 1.0)
  • At time 0.25: opacity 0, scale (0.9, 0.9)

  1. Content Browser -> Miscellaneous -> Data Asset -> WbpAnimStateMachineDefinition.
  2. Name it DA_Modal.
  3. Open it.
  4. In Details, set Owner Widget Class to WBP_Modal.
  1. Set Preset To Apply to Panel.
  2. Click Apply Preset.

The Panel preset creates a Hidden -> Intro -> Idle -> Outro -> Hidden flow with finish-driven transitions already wired.

Switch to the Graph tab and confirm you can see the four state nodes connected in a ring.

Click the Details tab and expand each state:

Hidden

  • PlayMode: Loop
  • AnimationName: Hidden

Intro

  • PlayMode: Play Once
  • AnimationName: Intro

Idle

  • PlayMode: Loop
  • AnimationName: Idle

Outro

  • PlayMode: Play Once
  • AnimationName: Outro

Make sure the AnimationName values match the names you created in Step 2.

Step 6 - Add an ExitFunctionName to the Hidden state

Section titled “Step 6 - Add an ExitFunctionName to the Hidden state”

When the machine enters Hidden, we want the widget to remove itself from the viewport. We can do this by pointing the state at a widget function.

  1. Expand the Hidden state entry in the States array.
  2. Find the Exit Function Name field and leave it blank - we want the entry callback for Hidden, not exit.
  3. Find Entry Function Name.
  4. Type HandleHidden - this is the function we will create in the widget Blueprint.

Entry Function Name calls a function on the owning widget when the machine enters this state. The function must have no parameters and must be a regular Blueprint function (not an event).

Save the definition with Ctrl+S.


Step 7 - Add variables and functions to WBP_Modal

Section titled “Step 7 - Add variables and functions to WBP_Modal”

Open WBP_Modal in the Widget Blueprint editor.

  1. In My Blueprint -> Variables, click +.
  2. Name it StateMachine, type WbpAnimStateMachine Object Reference.
  1. In My Blueprint -> Functions, click +.
  2. Name it HandleHidden.
  3. Inside the function, right-click and search Remove from Parent.
  4. Connect the exec flow into Remove from Parent.

This function will be called by the machine when the Hidden state is entered.

Step 8 - Create and initialize the machine on Construct

Section titled “Step 8 - Create and initialize the machine on Construct”
  1. Open the Event Graph tab.
  2. Add Event Construct.
  3. Add Create And Initialize State Machine:
  • Target: Self
  • Definition: DA_Modal
  1. Connect Return Value to Set StateMachine.
Event Construct -> Create And Initialize State Machine (DA_Modal) -> Set StateMachine

We want other Blueprints to be able to open the modal. A clean pattern is to expose a public function.

  1. In My Blueprint -> Functions, click +.
  2. Name it Open. Make sure Access Specifier is Public in the Details panel on the right.
  3. Inside the function, add a Go To WBP State node:
  • Target: Get StateMachine
  • State: Intro
  • State Definition: DA_Modal
Open function -> Go To WBP State (Intro)
  1. Add another public function named Close.
  2. Inside it, add Go To WBP State:
  • State: Outro
Close function -> Go To WBP State (Outro)

The machine will play the Outro animation, and when it finishes, automatically transition to Hidden, which calls HandleHidden, which removes the widget from the viewport.

If your modal has a confirm button inside it:

  1. Select the button widget in the Hierarchy.
  2. In the Details panel, scroll to Events and click + next to On Clicked.
  3. A new event node appears in the Event Graph.
  4. Add a Go To WBP State node from the On Clicked event:
  • State: Outro

One call to GoToState(Outro) dismisses the modal, plays the outro, removes itself from the viewport - no additional wiring needed.


Step 12 - Create the modal from another Blueprint

Section titled “Step 12 - Create the modal from another Blueprint”

Open the Level Blueprint (or whichever Blueprint should show the modal).

  1. Add Event Begin Play (or a key press event such as M).
  2. Add Create Widget:
  • Class: WBP_Modal
  1. Drag from Return Value -> Add to Viewport.
  2. Drag from Return Value again -> Open (the function you created on the widget).
Key M pressed
-> Create Widget (WBP_Modal)
-> Add to Viewport
-> Open

Press Play. Press M (or whatever key you used). The modal should:

  1. Appear from invisible via the Intro animation.
  2. Sit in Idle (looping its idle animation, or holding).
  3. When dismissed (if you added a close button), play the Outro.
  4. Disappear when Outro finishes.

Open DA_Modal in the asset editor and switch to the Debugger tab while PIE is running to watch the state changes in real time.


”The modal appears immediately without the intro animation”

Section titled “”The modal appears immediately without the intro animation””
  • Check that the Initial State on the definition is set to Hidden. If it is set to Idle, the machine starts in Idle and skips Intro.
  • In the Debugger tab, look at Current State immediately after the widget is added to the viewport. It should be Hidden.
  • Open the definition Details tab. Confirm that the Entry Function Name on the Hidden state is exactly HandleHidden - check for typos, extra spaces, or wrong casing.
  • In My Blueprint, confirm the function is named HandleHidden (not an event, a regular function).
  • The function picker in the state’s Entry Function Name field shows valid functions from OwnerWidgetClass. If HandleHidden does not appear in the picker, double-check that Owner Widget Class is set to WBP_Modal.

”Outro plays but then nothing happens”

Section titled “”Outro plays but then nothing happens””
  • Verify that the Outro -> Hidden transition has Trigger set to On Animation Finished.
  • Check that the Outro animation in the widget has actual keyframes - an animation with zero duration may finish instantly and the timing can behave unexpectedly.
  • Look at the Transition Log in the Debugger. A blocked transition entry will show the reason.

Goal: A toast (brief on-screen message) that appears, waits a configurable number of seconds, then dismisses itself. It should also be dismissible early by a close button.

Time estimate: 20-30 minutes.

A widget with three states - Spawn, Visible, and Dismiss - where Visible uses an auto-transition to move to Dismiss after a set delay. The blackboard stores the auto-dismiss duration.


  1. Content Browser -> Widget Blueprint. Name it WBP_Toast.
  2. In the Designer tab, add:
  • A Canvas Panel at the root.
  • An Image for the background.
  • A Text Block named MessageText for the toast message.
  • A small Button named CloseButton for early dismissal.
  1. Arrange them how you like.
  • Slide in from below or fade in over 0.25 seconds.
  • Example: at time 0, offset (0, 60) and opacity 0. At time 0.25, offset (0, 0) and opacity 1.
  • A short looping animation (can be a gentle pulse or just hold at full opacity).
  • Because it loops, the machine stays here until something moves it out.
  • Reverse of Spawn: fade and slide out over 0.25 seconds.

  1. Content Browser -> Data Asset -> WbpAnimStateMachineDefinition. Name it DA_Toast.
  2. Open it.
  3. Set Owner Widget Class to WBP_Toast.
  1. Preset To Apply: Toast.
  2. Apply Preset.

This gives you Spawn -> Visible -> Dismiss with:

  • Spawn -> Visible trigger: On Animation Finished
  • Visible -> Dismiss trigger: Manual (you will add an auto-transition in the next step)
  • Dismiss has an on-finish transition that removes the widget

Step 5 - Configure the auto-transition on Visible

Section titled “Step 5 - Configure the auto-transition on Visible”

The Visible state should automatically move to Dismiss after N seconds.

  1. In the Details tab, find the Visible state in the States array.
  2. Expand it.
  3. Set Auto Transition Delay to 3.0 (three seconds).
  4. Set Auto Transition State to Dismiss.

Now, three seconds after the machine enters Visible, it will automatically call GoToState(Dismiss) without any Blueprint wiring.

Tip: You can make this configurable by using a blackboard value instead. See the optional step below.

The Dismiss animation plays once and then… what? The preset’s Dismiss state should have an OnAnimationFinished transition to a Hidden state, or alternatively you can wire a function.

If the preset added a Hidden state, add Entry Function Name = HandleHidden to it, and create a HandleHidden function in the widget that calls Remove From Parent.

If not, add it manually:

  1. In the Details tab, click the + button next to the States array to add a new state.
  2. Name it Hidden.
  3. Set Animation Name to Hidden (create a matching trivial animation in the widget, or leave it blank if you do not need one).
  4. Set Entry Function Name to HandleHidden.
  5. In the Transitions array, add a new entry:
  • From State: Dismiss
  • To State: Hidden
  • Trigger: On Animation Finished
  1. Save the definition.

Back in WBP_Toast, add a function named HandleHidden that calls Remove From Parent.


  1. In WBP_Toast, select CloseButton in the Hierarchy.
  2. In the Details panel, click + next to On Clicked.
  3. In the event node that appears, add Go To WBP State:
  • Target: Get StateMachine
  • State: Dismiss

A toast is only useful if you can set its message text. Add a public function:

  1. My Blueprint -> Functions -> +. Name it SetMessage.
  2. Add an input parameter: Name Message, Type Text.
  3. Inside the function, drag from Message -> Set Text (Text Block), targeting MessageText.

Step 9 - Create and initialize the machine in WBP_Toast

Section titled “Step 9 - Create and initialize the machine in WBP_Toast”

In the Event Graph:

Event Construct
-> Create And Initialize State Machine (DA_Toast)
-> Set StateMachine

After initializing, call Go To WBP State (Spawn) to begin the appearance animation immediately:

Event Construct
-> Create And Initialize State Machine (DA_Toast)
-> Set StateMachine
-> Go To WBP State (Spawn)

Step 10 - Spawn the toast from another Blueprint

Section titled “Step 10 - Spawn the toast from another Blueprint”

Open the Level Blueprint (or HUD Blueprint):

Key T pressed
-> Create Widget (WBP_Toast)
-> Add to Viewport
-> Set Message (Message = "Save complete!")

You do not need to call Open separately because the machine automatically starts in Spawn (assuming the definition’s Initial State is Spawn) and drives the animation itself.


Press Play, then press T. The toast should:

  1. Slide in from below.
  2. Sit visible for three seconds.
  3. Slide out and remove itself.

Pressing the close button at any point should immediately begin the dismiss animation.


Optional: Make the duration configurable via the Blackboard

Section titled “Optional: Make the duration configurable via the Blackboard”

Instead of hard-coding 3.0 seconds in the definition:

  1. Set Auto Transition Delay on Visible back to 0.
  2. Open WBP_Toast’s Event Construct.
  3. After creating the machine, call Set Blackboard Float:
  • Target: Get StateMachine
  • Key: AutoDismissSeconds
  • Value: 3.0 (or expose this as a variable that callers can set before spawning)
  1. Back in the definition, on the Visible state’s auto-transition, check whether the definition supports a blackboard-driven delay rule.

Alternatively - and more simply - just leave the hard-coded delay and expose a SetDuration function on the widget that sets a float variable, then use that variable in the Rule for the Visible -> Dismiss transition via a BlackboardFloat > Value rule block.


”The toast appears but never auto-dismisses”

Section titled “”The toast appears but never auto-dismisses””
  • Open the definition Details tab. Find the Visible state. Confirm Auto Transition Delay is greater than 0 and Auto Transition State is Dismiss.
  • In the Debugger, watch Time In State while the machine is in Visible. It should count up. When it reaches the delay value, the transition should fire.

”The toast removes itself immediately”

Section titled “”The toast removes itself immediately””
  • The Spawn state’s animation may have zero duration. Check that the Spawn animation has actual keyframes with a duration.
  • Alternatively, the machine may be starting in Visible instead of Spawn. Check Initial State on the definition - it should be Spawn.

”The close button does not dismiss early”

Section titled “”The close button does not dismiss early””
  • Confirm the Visible -> Dismiss Manual transition exists in the Transitions array. The auto-transition covers the delay path; the Manual transition covers the close-button path. Both can exist simultaneously.

Walkthrough 4: Tab Panel with Parallel Tracks

Section titled “Walkthrough 4: Tab Panel with Parallel Tracks”

Goal: A panel widget with three tabs. Each tab has its own selected and unselected animations. A separate animation track handles the panel’s show/hide flow independently from the tab selection state.

Time estimate: 35-45 minutes.

Without parallel tracks, every combination of “which tab is selected” and “is the panel visible” would require its own state. You end up with states like Visible_Tab1, Visible_Tab2, Hidden_Tab1, and so on - a combinatorial explosion.

With two tracks:

  • Base track: Hidden -> Intro -> Idle -> Outro -> Hidden
  • Tabs track: Tab1 -> Tab2 -> Tab3 (and back)

They run independently. You control them separately. The panel’s show/hide behavior never interferes with tab selection.


  1. Content Browser -> Widget Blueprint. Name it WBP_TabPanel.
  2. In the Designer tab, create a layout with:
  • Three tab buttons named Tab1Button, Tab2Button, Tab3Button
  • A content area below the tabs (an Image or Border panel)
  1. The tab buttons should visually indicate which one is selected.

Step 2 - Create animations for the Base track

Section titled “Step 2 - Create animations for the Base track”

These animations control the panel’s overall show/hide flow.

  • Intro - fade/slide the entire panel in over 0.3 seconds
  • Idle - hold at full opacity, loop
  • Outro - fade/slide out over 0.25 seconds
  • Hidden - invisible hold

Step 3 - Create animations for the Tabs track

Section titled “Step 3 - Create animations for the Tabs track”

These animations control the selected state of each tab.

  • Tab1 - Tab1Button is highlighted; Tab2 and Tab3 are at reduced opacity
  • Tab2 - Tab2Button is highlighted; others are reduced
  • Tab3 - Tab3Button is highlighted; others are reduced

Each should be a looping animation so the machine holds the selected state until you explicitly switch tabs.


You need two separate definition assets - one per track.

  1. Content Browser -> Data Asset -> WbpAnimStateMachineDefinition. Name it DA_TabPanel_Base.
  2. Open it. Set Owner Widget Class to WBP_TabPanel.
  3. Apply the Panel preset.
  4. Confirm Intro, Idle, Outro, Hidden states are present.
  5. Add HandleHidden as the Entry Function of the Hidden state (same as the Modal walkthrough).
  6. Save.
  1. Create another definition asset: DA_TabPanel_Tabs.
  2. Open it. Set Owner Widget Class to WBP_TabPanel.
  3. Do not apply a preset - add states manually.

In the Details tab:

  • Click + next to States three times.

  • Configure each:

    State 1

  • StateName: Tab1

  • AnimationName: Tab1

  • PlayMode: Loop

State 2

  • StateName: Tab2
  • AnimationName: Tab2
  • PlayMode: Loop

State 3

  • StateName: Tab3

  • AnimationName: Tab3

  • PlayMode: Loop

  • Set Initial State to Tab1.

In the Transitions array, add six entries for full two-way navigation:

FromToTrigger
Tab1Tab2Manual
Tab1Tab3Manual
Tab2Tab1Manual
Tab2Tab3Manual
Tab3Tab1Manual
Tab3Tab2Manual

Save.


Step 5 - Create a WbpAnimStateMachineGroup in WBP_TabPanel

Section titled “Step 5 - Create a WbpAnimStateMachineGroup in WBP_TabPanel”

The group is the host object that holds both tracks.

  1. Open WBP_TabPanel Widget Blueprint.
  2. In the Graph tab, My Blueprint -> Variables -> +. Name it MachineGroup, type WbpAnimStateMachineGroup Object Reference.
  3. Also add a separate variable BaseMachine of type WbpAnimStateMachine Object Reference (optional - you can always retrieve the track by name from the group, but storing the reference is convenient).

Step 6 - Set up the group in Event Construct

Section titled “Step 6 - Set up the group in Event Construct”

In the Event Graph:

  1. Add Event Construct.
  2. Right-click -> search Create State Machine Group. Add it.
  • Target: Self
  1. Connect Return Value -> Set MachineGroup.
  2. Drag from Get MachineGroup -> Add Track:
  • Track Name: Base
  • Definition: DA_TabPanel_Base
  1. Drag from Return Value of Add Track -> Set BaseMachine (for convenience).
  2. Add another Add Track call:
  • Track Name: Tabs
  • Definition: DA_TabPanel_Tabs

Your Event Construct should read:

Event Construct
-> Create State Machine Group (Self)
-> Set MachineGroup
Get MachineGroup
-> Add Track (Base, DA_TabPanel_Base) -> Set BaseMachine
-> Add Track (Tabs, DA_TabPanel_Tabs)

The group needs to be ticked to evaluate time-based conditions, focus detection, and auto-transitions.

  1. In My Blueprint -> Functions -> Override, find and add On Tick.
  2. Inside On Tick, add Tick Group (search for it):
  • Target: Get MachineGroup
  • Delta Time: connect the Delta Seconds pin from the On Tick event.
  1. Add a public function Open.
  2. Inside it, Go To State On Track:
  • Target: Get MachineGroup
  • Track Name: Base
  • State: Intro
  1. Add a public function Close.
  2. Inside it, Go To State On Track:
  • Target: Get MachineGroup
  • Track Name: Base
  • State: Outro
  1. Add a regular function HandleHidden.
  2. Inside it: Remove From Parent.

For each tab button, wire an On Clicked event to Go To State On Track targeting the Tabs track:

Tab1Button -> On Clicked

On Clicked (Tab1Button)
-> Go To State On Track
Target: Get MachineGroup
Track Name: Tabs
State: Tab1

Repeat for Tab2 and Tab3.


  1. Open the Level Blueprint.
  2. On a key press: Create Widget (WBP_TabPanel) -> Add to Viewport -> Open.
  3. Press Play. Press the key.

The panel should:

  • Slide in via the Base track’s Intro.
  • Land in Idle.
  • Clicking tab buttons should switch the tab highlight animation on the Tabs track.
  • Tab switching should not affect the panel’s show/hide state.
  • Calling Close should play the Outro animation and remove the panel.

  • Open the debugger. The machine instance list shows all active machines by definition. Confirm you see two active machines - one for DA_TabPanel_Base and one for DA_TabPanel_Tabs.
  • If only one appears, check that both Add Track calls in Event Construct are connected correctly.

”Tab switching works but the panel never appears”

Section titled “”Tab switching works but the panel never appears””
  • Confirm the Base track’s machine was created. Check Go To State On Track - make sure Track Name is spelled Base exactly (case-sensitive).

”On Tick override is not available in my widget”

Section titled “”On Tick override is not available in my widget””
  • On Tick is only available in Widget Blueprints if Tick Frequency is not set to Never. In the Designer tab, select the widget root and check the Details panel. Set Tick Frequency to Auto or Always under Widget -> Tick Frequency.

Goal: Create a state that animates widget properties from a UCurveLinearColor row instead of a UMG animation timeline.

Time estimate: 15-25 minutes if you already have a Widget Blueprint and state machine definition.

A small Pulse state that fades and scales a widget by sampling a color curve over time. The state can play once and then transition back to Idle, or loop until another state is requested.

  1. Open your Widget Blueprint.
  2. Pick a visible widget such as an Image, Border, or panel.
  3. Give it a stable name, for example PulseTarget.
  4. Save the Widget Blueprint.

You can leave the binding widget name empty later if you want to drive the owning widget itself, but naming the target makes the setup easier to read.

  1. In the Content Browser, create a Curve Linear Color asset.
  2. Name it something like C_UI_Pulse.
  3. Edit the curve so time 0.0 represents the start value and time 1.0 represents the end value.
  4. Use the RGBA channels as property values. For example:
  • R: opacity
  • G: X scale
  • B: Y scale
  • A: optional visibility or secondary scalar

For a simple pulse, set values so opacity rises from 0.6 to 1.0, and scale rises from 1.0 to 1.08.

If your project uses Curve Atlases for shared UI curves:

  1. Add the C_UI_Pulse row to a Curve Linear Color Atlas.
  2. Assign that atlas in the state binding later.

The runtime evaluates the curve row directly. The atlas reference is used for authoring clarity and validation, so the editor can warn when a binding points at a curve that is not registered in the selected atlas.

  1. Open the WbpAnimStateMachineDefinition.
  2. Add a state named Pulse.
  3. Leave AnimationName empty if this state should be curve-only.
  4. Set PlayMode:
  • Play Once if the pulse should finish and move on.
  • Loop if the pulse should keep running.
  • PingPong if the pulse should breathe back and forth.
  1. Set CurveAtlasDuration, for example 0.35.

In the Pulse state’s CurveAtlasBindings array, add bindings such as:

  • WidgetName: PulseTarget
  • Curve: C_UI_Pulse
  • Atlas: your atlas asset, if used
  • Property: Render Opacity
  • Scalar Channel: R

Add a second binding for scale:

  • WidgetName: PulseTarget
  • Curve: C_UI_Pulse
  • Property: Render Scale

For vector properties such as render scale, the binding reads the sampled curve’s R and G channels as X and Y.

For a one-shot pulse:

  1. Add a manual transition from Idle to Pulse.
  2. Add an On Animation Finished transition from Pulse back to Idle.
  3. Keep Pulse set to Play Once.

Curve-only finite states use the same finish path as UMG animation-backed states, so the On Animation Finished transition still works when CurveAtlasDuration completes.

Curve Atlas sequences are tick-driven. In the owning widget, make sure MachineTick(DeltaTime) runs from the widget’s tick path, the same way you would for notifies or tick conditions.

If MachineTick is not called, the state can still enter, but the curve sequence will not advance.

  1. Play in editor.
  2. Trigger Go To WBP State with Pulse.
  3. Confirm the widget property changes over the configured duration.
  4. If the state is one-shot, confirm it returns to Idle.
  5. Run validation in the state machine editor.

Common warnings:

  • CurveAtlasDuration is set but no bindings exist.
  • Bindings exist but duration is 0.
  • A binding has no curve row.
  • A curve row is not registered in the selected atlas.

This walkthrough shows how to route Gameplay Ability System event tags into a Widget Blueprint state machine without making every ability manually call GoToState.

Example use cases:

  • hit-react UI
  • low-health pulse
  • ability cooldown flash
  • death or disabled overlay

In your definition asset, add states such as:

  • Idle
  • HitReact
  • LowHealth
  • Dead

Set each state’s AnimationName to the matching Widget Blueprint animation, or leave it empty if the state is driven by Curve Atlas bindings or entry functions.

Add the transitions that should be legal during normal play:

  • Idle -> HitReact
  • HitReact -> Idle with On Animation Finished
  • Idle -> LowHealth
  • LowHealth -> Idle
  • Any -> Dead if death should be reachable from anywhere

Use normal transitions where possible. They keep the state graph honest and make blocked behavior easier to debug.

In the definition’s GAS Events array, add entries like:

  • EventTag: Gameplay.Damage
  • TargetState: HitReact
  • bForce: false
  • CallerPriority: 0

Add another entry:

  • EventTag: Gameplay.Health.Low
  • TargetState: LowHealth
  • bForce: false
  • CallerPriority: 0

Tags are matched with FGameplayTag::MatchesTag, so a binding for Gameplay.Damage also matches Gameplay.Damage.Fire and Gameplay.Damage.Ice. Use a more specific tag if you only want one event.

The state machine does not subscribe to UAbilitySystemComponent automatically. Forward the event from your gameplay code or Blueprint listener:

AbilitySystem->AddGameplayEventTagContainerDelegate(
FGameplayTagContainer(DamageTag),
FGameplayEventTagMulticastDelegate::FDelegate::CreateWeakLambda(this,
[StateMachine](FGameplayTag Tag, const FGameplayEventData*)
{
if (StateMachine)
{
StateMachine->HandleGameplayEvent(Tag);
}
}));

Blueprint flow:

  1. Subscribe to the gameplay event.
  2. Get the widget’s state machine reference.
  3. Call Handle Gameplay Event with the incoming tag.
  4. Use the returned integer to see how many bindings successfully triggered.

If multiple GAS bindings match the same incoming tag, they are evaluated in declaration order. Each GoToState call is independent, so the second matching binding runs from whatever state the first binding left the machine in.

That means this setup:

  • Gameplay.Damage -> HitReact
  • Gameplay.Damage -> LowHealth

can attempt both transitions. The second attempt may succeed or fail depending on whether HitReact -> LowHealth is legal after the first binding runs.

bForce bypasses the transition table, but it does not bypass interrupt protection. If the current state has InterruptPriority = 10, a GAS binding with bForce = true and CallerPriority = 0 will still be rejected.

Use force for genuinely urgent states such as death, disconnect, or modal shutdown:

  • EventTag: Gameplay.Death
  • TargetState: Dead
  • bForce: true
  • CallerPriority: 100

Press Validate State Machine. Validation checks that:

  • every GAS event tag is valid
  • every GAS binding target state exists

Then test in PIE with the Debugger tab open. The transition log is the best place to see whether a gameplay event matched no binding, matched a binding but failed transition rules, or was blocked by interrupt priority.


Tip 1: State names and animation names are case-sensitive

Section titled “Tip 1: State names and animation names are case-sensitive”

The machine compares AnimationName exactly against the list of animations on the widget. hover and Hover are different names. When nothing plays but the machine transitions correctly, the first place to check is the case of the animation name.

Without OwnerWidgetClass set on the definition, the animation name dropdowns are empty, function dropdowns are empty, and validation cannot catch name mismatches. Set it first, before doing anything else.

Tip 3: Use the Debugger tab, not just print strings

Section titled “Tip 3: Use the Debugger tab, not just print strings”

The Debugger tab in the definition asset editor is the fastest way to understand what a machine is doing. It shows:

  • The exact current state
  • How long the machine has been in that state
  • Every transition attempt, including blocked ones with reasons
  • Blackboard values live

Open it during PIE instead of adding print strings throughout your Blueprint graphs.

Tip 4: The transition must exist for GoToState to succeed

Section titled “Tip 4: The transition must exist for GoToState to succeed”

Calling GoToState(Hover) when you are in Idle will silently fail if there is no Idle -> Hover transition in the definition. The Debugger’s Transition Log will show “No valid transition found” in this case. This is intentional - the machine enforces the authored graph.

To allow a transition from any state (e.g., always allow GoToState(Disabled) regardless of current state), set From State to None on the transition. This is called a wildcard transition.

Tip 5: Use Force when transitions are blocked by rules

Section titled “Tip 5: Use Force when transitions are blocked by rules”

If a transition has rules attached and you need to bypass them for one specific call (such as forcibly disabling the widget regardless of current conditions), pass bForce = true in the Go To WBP State node. Force bypasses rule evaluation and the transition table, but it still respects the current state’s InterruptPriority; the caller priority must meet or exceed that value.

Tip 6: One definition asset can power many widgets

Section titled “Tip 6: One definition asset can power many widgets”

Multiple widget blueprint instances can use the same DA_Button definition simultaneously. Each gets its own independent runtime machine. The Debugger lists them all and lets you switch between instances.

Presets give you a solid starting graph in seconds. Most real-world buttons and panels need minor adjustments from the preset - a state renamed, a transition removed, a rule added. Starting from a preset is almost always faster than building from scratch.

On Animation Finished transitions only fire when the state’s Play Mode is Play Once or Reverse. If a state uses Loop or Ping-Pong, the animation never finishes, so those transitions never fire. If a transition is not firing when the animation ends, check the state’s Play Mode first.

Tip 9: Entry and Exit Functions must be regular functions, not Events

Section titled “Tip 9: Entry and Exit Functions must be regular functions, not Events”

Blueprint Events (such as Event BeginPlay or custom events) cannot be called by name from the machine. The Entry Function Name and Exit Function Name fields only work with regular Blueprint Functions (the blue node with an f icon). If you accidentally created a Custom Event instead of a Function, move the logic into a proper function.

Tip 10: The machine’s outer is the widget

Section titled “Tip 10: The machine’s outer is the widget”

The machine is created with the widget as its outer object. This means it shares the widget’s lifetime and can call functions on the widget directly. You do not need to pass the widget around separately.


These six walkthroughs cover the most common patterns. Once you are comfortable with them:

  • Read the User Guide for the full feature surface, including snapshots, input bindings, sub-state machines, Curve Atlas sequences, and the Sequencer track.
  • Use the Anim Workbench Walkthroughs when you want to audit, repair, compare, or bind the Widget Blueprint animation clips that your state machine plays.
  • Read the Technical Reference if you are working in C++ or want to understand the internals.
  • Use the Native graph implementation history when you need migration context for the current graph editor surface.