StoryFlow Component
The StoryFlow Component is the core actor component that drives dialogue execution in your Unreal Engine project. It manages the runtime, processes node graphs, and broadcasts events your UI can respond to.
Overview
UStoryFlowComponent is a UActorComponent declared with UCLASS(BlueprintType, ClassGroup=(StoryFlow), meta=(BlueprintSpawnableComponent)). This means you can add it to any actor in your level — an NPC, a trigger volume, a game mode, or any other actor that needs to run dialogue.
Internally, the component manages two key objects:
FStoryFlowExecutionContext— The execution engine that walks the node graph, manages the call stack, handles script transitions, and produces dialogue state.FStoryFlowEvaluator— The expression evaluator that resolves variable chains, boolean logic, arithmetic, string operations, and type conversions during execution.
You do not interact with these objects directly. The component exposes a clean Blueprint API for starting dialogue, selecting options, reading variables, and listening to events.
One Component Per Dialogue
Each UStoryFlowComponent runs one dialogue at a time. If you need multiple concurrent dialogues (for example, an NPC conversation and a tutorial prompt), use separate components on separate actors. All components share global state through the UStoryFlowSubsystem.
Adding the Component
In Blueprint
- Open the actor Blueprint that should run dialogue (for example, your NPC actor).
- In the Components panel, click Add and search for "StoryFlow".
- Select StoryFlow Component from the list.
- The component appears in your component hierarchy, ready to configure in the Details panel.
In C++
// In your actor's header
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "StoryFlow")
UStoryFlowComponent* StoryFlowComponent;
// In your actor's constructor
AMyNPC::AMyNPC()
{
StoryFlowComponent = CreateDefaultSubobject<UStoryFlowComponent>(
TEXT("StoryFlowComponent")
);
} Configuration Properties
All configuration properties are exposed in the Details panel when you select the component. They are also available in C++ and Blueprints via EditAnywhere and BlueprintReadWrite.
General Settings
Script FString Path to the script file relative to your StoryFlow project root. For example, "npcs/elder" or "main.json". The .json extension is optional. Uses meta=(GetOptions="GetAvailableScripts") to provide a dropdown of all imported scripts in the editor.
LanguageCode FString default: "en" The language code used for string table lookup. Determines which localized text is displayed in dialogue. Currently, the StoryFlow Editor only supports English ("en"). Multi-language localization is planned for a future release — once supported, you will be able to use codes like "es", "fr", "de", "ja", etc.
DialogueWidgetClass TSubclassOf<UStoryFlowDialogueWidget> Optional. If set, the component will automatically create and manage an instance of this widget class when dialogue starts. The widget is added to the viewport and removed when dialogue ends. Leave empty if you manage your own UI.
Script Dropdown
The Script property uses GetOptions metadata, which means the Details panel shows a dropdown list of all available scripts from your imported StoryFlow project. You do not need to type paths manually — just select from the list.
Audio Settings
These properties control how dialogue audio is played. They appear under the StoryFlow | Audio category in the Details panel.
bStopAudioOnDialogueEnd bool default: true When enabled, all audio spawned by this component is stopped when the dialogue ends. Disable this if you want audio to continue playing after the conversation finishes (for example, ambient music).
DialogueSoundClass USoundClass* Assigns all dialogue audio to a specific sound class. Use this to control volume through your game's audio mix (for example, a "Dialogue" or "Voice" sound class).
DialogueVolumeMultiplier float default: 1.0 Volume multiplier applied to all dialogue audio. Clamped between 0.0 and 2.0. Useful for per-component volume adjustments without changing the sound class mix.
DialogueConcurrency USoundConcurrency* Controls how multiple audio sources from this component interact. Use a concurrency setting to limit simultaneous sounds or define priority and fade behavior when dialogue audio overlaps.
Audio Format
Unreal Engine imports MP3 files as FileMediaSource, not USoundWave. The StoryFlow Editor plugin automatically decodes MP3 files to WAV during import so they work with PlaySound2D. For best results, export your audio as WAV from the StoryFlow Editor.
Events and Delegates
The component broadcasts events through BlueprintAssignable multicast delegates under the StoryFlow | Events category. Bind to these in Blueprint (using Event Dispatchers) or in C++ to react to dialogue state changes.
| Delegate | Parameters | Description |
|---|---|---|
OnDialogueStarted | None | Fired when dialogue execution begins. Use this to show your dialogue UI, disable player movement, or enter a dialogue camera mode. |
OnDialogueUpdated | FStoryFlowDialogueState | The primary UI update event. Fired every time the dialogue state changes — new text, new options, character change, or variable interpolation update. The FStoryFlowDialogueState struct contains everything needed to render the current dialogue. |
OnDialogueEnded | None | Fired when dialogue execution completes (reaching an End node or calling StopDialogue). Use this to hide your UI, re-enable player input, or trigger post-dialogue logic. |
OnVariableChanged | FString VariableId, FStoryFlowVariant NewValue, bool bIsGlobal | Fired whenever a variable is modified during execution. Provides the variable ID, its new value, and whether it is a global variable. Useful for updating HUD elements, triggering animations, or logging state changes. |
OnScriptStarted | FString ScriptPath | Fired when execution enters a new script via a runScript node. Provides the path of the script being entered. |
OnScriptEnded | FString ScriptPath | Fired when execution returns from a script. Provides the path of the script that just finished. |
OnError | FString ErrorMessage | Fired when the runtime encounters an error (for example, a missing script, invalid node connection, or stack overflow). Use this for logging or showing error feedback during development. |
OnBackgroundImageChanged | FString ImagePath | Fired when a setBackgroundImage node is executed. Provides the path to the new background image. Use this to update scene backgrounds or full-screen visual novel imagery. |
OnAudioPlayRequested | FString AudioPath, bool bLoop | Fired when a playAudio node is executed. Provides the audio asset path and whether it should loop. Use this if you want to handle audio playback yourself instead of relying on the component's built-in audio system. |
OnDialogueUpdated is Your Main Hook
In most projects, OnDialogueUpdated is the only event you need to build a complete dialogue UI. It fires whenever the dialogue state changes and provides the full FStoryFlowDialogueState including text, character, options, images, and audio. See Displaying Dialogue for details on the state struct.
Binding in Blueprint:
- Select the StoryFlow Component in your actor's Blueprint.
- In the Details panel, scroll to the Events section.
- Click the + button next to the event you want to bind (for example,
OnDialogueUpdated). - A new event node is created in your Event Graph, ready for you to add logic.
Binding in C++:
// In BeginPlay or wherever you set up your component
StoryFlowComponent->OnDialogueUpdated.AddDynamic(
this, &AMyNPC::HandleDialogueUpdated
);
StoryFlowComponent->OnDialogueEnded.AddDynamic(
this, &AMyNPC::HandleDialogueEnded
);
// Handler signatures
void AMyNPC::HandleDialogueUpdated(const FStoryFlowDialogueState& DialogueState)
{
// Update your UI with the new dialogue state
}
void AMyNPC::HandleDialogueEnded()
{
// Clean up UI, re-enable player input
} Control Functions
These BlueprintCallable functions control the dialogue flow. Call them from Blueprint event graphs, player input handlers, or C++ game logic.
| Function | Parameters | Description |
|---|---|---|
StartDialogue | None | Begins dialogue execution using the Script property configured on the component. Fires OnDialogueStarted followed by the first OnDialogueUpdated. |
StartDialogueWithScript | FString ScriptPath | Begins dialogue execution with the specified script, overriding the component's Script property. Useful for dynamically choosing which dialogue to run (for example, based on quest state or NPC mood). |
SelectOption | FString OptionId | Selects a dialogue option by its ID. The OptionId comes from the FStoryFlowDialogueOption entries in the current dialogue state. Advances execution along the chosen path. |
AdvanceDialogue | None | Advances the dialogue when the current node is a narrative-only node (no options to select). Equivalent to the player clicking "continue" or pressing a key to proceed. |
StopDialogue | None | Immediately stops dialogue execution. Fires OnDialogueEnded. Use this when the player walks away, a cutscene interrupts, or you need to abort the conversation. |
PauseDialogue | None | Pauses dialogue execution. The dialogue state is preserved, but no further events are fired until resumed. Useful for pause menus or mid-dialogue gameplay sequences. |
ResumeDialogue | None | Resumes a paused dialogue. Execution continues from exactly where it was paused. |
Basic Blueprint flow example:
// Player interacts with NPC
void AMyNPC::OnInteract(APlayerCharacter* Player)
{
if (!StoryFlowComponent->IsDialogueActive())
{
StoryFlowComponent->StartDialogue();
}
}
// Player presses "Continue" key
void AMyNPC::OnContinuePressed()
{
if (StoryFlowComponent->IsDialogueActive()
&& !StoryFlowComponent->IsWaitingForInput())
{
StoryFlowComponent->AdvanceDialogue();
}
}
// UI button calls this when the player picks an option
void AMyNPC::OnOptionSelected(const FString& OptionId)
{
StoryFlowComponent->SelectOption(OptionId);
} State Access
These BlueprintPure functions let you query the current state of the dialogue without modifying it. They are safe to call from UI update logic, animation Blueprints, or any read-only context.
| Function | Return Type | Description |
|---|---|---|
GetCurrentDialogue | FStoryFlowDialogueState | Returns the current dialogue state. Contains the full snapshot of text, character, options, images, audio, and text blocks. Returns an empty state if no dialogue is active. |
IsDialogueActive | bool | Returns true if a dialogue is currently running (started but not ended). Useful for input gating and UI visibility checks. |
IsWaitingForInput | bool | Returns true if the dialogue is waiting for the player to select an option. When false and dialogue is active, the player can advance with AdvanceDialogue. |
IsPaused | bool | Returns true if the dialogue is currently paused via PauseDialogue. |
GetStoryFlowSubsystem | UStoryFlowSubsystem* | Returns a reference to the UStoryFlowSubsystem. Useful for accessing shared global state, the project asset, or performing save/load operations. |
GetProject | UStoryFlowProjectAsset* | Returns the project data asset containing all imported scripts, characters, and resolved media assets. |
Variable Access
These BlueprintCallable functions (under the StoryFlow | Variables category) let you read and write StoryFlow variables from game code. Each variable type has its own getter and setter pair.
| Function | Parameters | Return Type |
|---|---|---|
GetBoolVariable | FString VariableId, bool bGlobal = false | bool |
SetBoolVariable | FString VariableId, bool Value, bool bGlobal = false | void |
GetIntVariable | FString VariableId, bool bGlobal = false | int32 |
SetIntVariable | FString VariableId, int32 Value, bool bGlobal = false | void |
GetFloatVariable | FString VariableId, bool bGlobal = false | float |
SetFloatVariable | FString VariableId, float Value, bool bGlobal = false | void |
GetStringVariable | FString VariableId, bool bGlobal = false | FString |
SetStringVariable | FString VariableId, FString Value, bool bGlobal = false | void |
GetEnumVariable | FString VariableId, bool bGlobal = false | FString |
SetEnumVariable | FString VariableId, FString Value, bool bGlobal = false | void |
GetCharacterVariable | FString CharacterPath, FString VariableName | FStoryFlowVariant |
SetCharacterVariable | FString CharacterPath, FString VariableName, FStoryFlowVariant Value | void |
ResetVariables | None | void |
bGlobal Parameter
The bGlobal parameter (default false) determines whether the function accesses a local script variable or a global project variable. If you set a variable as global in the StoryFlow Editor, you must pass bGlobal = true when reading or writing it from code. Accessing a global variable with bGlobal = false (or vice versa) will target the wrong variable store.
Example — Checking and setting variables:
// Check if the player has completed a quest (global variable)
bool bQuestDone = StoryFlowComponent->GetBoolVariable(
TEXT("mainQuestCompleted"), true // bGlobal = true
);
// Give the player gold (local script variable)
int32 CurrentGold = StoryFlowComponent->GetIntVariable(TEXT("gold"));
StoryFlowComponent->SetIntVariable(TEXT("gold"), CurrentGold + 100);
// Set a character-specific variable
StoryFlowComponent->SetCharacterVariable(
TEXT("characters/elder"),
TEXT("trustLevel"),
FStoryFlowVariant::FromInt(5)
);
// Reset all local variables to their default values
StoryFlowComponent->ResetVariables(); ResetVariables Scope
ResetVariables only resets local script variables to their default values. Global variables are not affected. To reset global variables, use the UStoryFlowSubsystem directly.
Lifecycle
The component follows a straightforward lifecycle tied to its owning actor:
- BeginPlay — The component retrieves a reference to the
UStoryFlowSubsystemfrom the game instance. It then initializes its internalFStoryFlowExecutionContextwith the subsystem's shared state (global variables, runtime character copies, and once-only option tracking). After initialization, the component is ready to start dialogue. - During Play — You call
StartDialogueto begin execution. The component walks the node graph, fires events, and waits for player input. You can pause, resume, or stop at any time. - EndPlay — The component stops any active dialogue, releases its audio components, and cleans up the execution context. Global state in the subsystem is not affected by a single component's destruction.
// Simplified lifecycle overview
void UStoryFlowComponent::BeginPlay()
{
Super::BeginPlay();
// Get the subsystem from the game instance
Subsystem = GetOwner()->GetGameInstance()
->GetSubsystem<UStoryFlowSubsystem>();
// Initialize execution context with shared state
ExecutionContext.Initialize(
Subsystem->GetGlobalVariables(),
Subsystem->GetRuntimeCharacters(),
Subsystem->GetOnceOnlyTracker()
);
}
void UStoryFlowComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
if (IsDialogueActive())
{
StopDialogue();
}
ExecutionContext.Cleanup();
Super::EndPlay(EndPlayReason);
} Relationship with UStoryFlowSubsystem
The UStoryFlowSubsystem is a GameInstanceSubsystem that lives for the entire game session. It acts as the central authority for shared state, while each UStoryFlowComponent operates as an independent dialogue runner.
What the subsystem manages:
- Global Variables — A single global variable store shared by all components. When one component's dialogue sets a global variable, every other component sees the updated value immediately.
- Runtime Characters — Working copies of character data loaded from the project asset. Character variables modified during gameplay are shared across all components.
- Once-Only Options — Tracks which "show once" dialogue options have already been selected. This tracking persists across different components and script files within the same session.
- Project Asset — Holds the imported StoryFlow project (
UStoryFlowProject) with all scripts, characters, and resolved media assets.
What each component manages independently:
- Local Variables — Each component has its own local variable scope for the currently executing script.
- Execution State — Call stack, current node position, and flow state are per-component.
- Audio Playback — Each component spawns and manages its own audio components.
- Delegates — Events are fired per-component, so each actor's UI only receives updates for its own dialogue.
Multiple NPCs, Shared World
This architecture means you can have dozens of NPCs running independent dialogues while sharing the same world state. A merchant NPC can check a global mainQuestCompleted variable that was set by a quest-giver NPC's dialogue, and both share the same character relationship data — all without any manual synchronization.