Unreal
Yarn Spinner for Unreal is in Pre-release now.
Yarn Spinner for Unreal Engine is a pure-C++ implementation of the Yarn Spinner dialogue system for Unreal Engine. It runs compiled Yarn programs with the goal of full feature parity with Yarn Spinner for Unity, including node groups, saliency, detours, smart variables, localisation, markup, and voice over support.
The entire plugin is intended to be Blueprint-accessible. You can set up dialogue, handle commands, read/write variables, save/load state, swap projects at runtime, and build custom presenters entirely from Blueprints with no C++ required.
A sample project will be coming soon, during the pre-release period!
Requires Unreal Engine 5.4 or later. If you want to use Yarn Spinner for Unreal Engine with an earlier version of Unreal Engine, please contact us via https://yarnspinner.dev
Yarn Spinner for Unreal Engine is not yet for sale (it will always be available here for free, too). We rely on your support to keep everything free and accessible. If you want to support us during the Alpha period, you can support us on GitHub Sponsors or Patreon. GitHub sponsors of $25 and above, and Patreon members of the "Scribe" or above tier will receive a license to the paid version when it is released.
Please submit issues or feature requests via this form during the pre-release period: https://yarnspinner.dev/pre-release-feedback
Differences from Yarn Spinner for Unity
The VM, protobuf parser, library, and markup system were all written to match Unity's behaviour, but there are some differences:
CLDR plural rules -- Unity includes the full Unicode CLDR v42.0 database (~150 languages). This implementation has rules covering ~130 languages. Coverage is comprehensive, but if you're using
[plural]or[ordinal]markup tags with a some languages, you might get the default "one/other" fallback instead of the correct plural form.No Unicode NFC normalisation -- Unity normalises markup input text to NFC (composed) form before parsing. Unreal doesn't have a built-in NFC normaliser, so precomposed and decomposed Unicode characters are treated as-is. This only matters if your Yarn scripts contain combining characters like
e+\u0301instead ofé.Async model -- Unity uses C#
async/awaitwithYarnTaskandCancellationTokenSourcechains. This implementation uses Unreal delegates and a two-tierUYarnCancellationTokensystem (hurry-up then next-content). The behaviour is the same, but the presenter API uses UE-idiomatic patterns instead of tasks.Command discovery -- Unity uses
[YarnCommand]attributes on methods. This implementation uses Blueprint-callableUFUNCTIONmethods on registered command handler objects, plus a C++AddCommandHandlerAPI. Both approaches register commands, just with diffeent syntax.Error handling -- Unity throws exceptions for invalid states (missing variables, bad option indices, etc.). This implementation uses
UE_LOGwarnings/errors and defensive fallbacks where possible, which is more idiomatic for Unreal Engine.Localisation -- Unity has multiple line provider backends (built-in, Unity Localization package, Addressables). This implementation uses Unreal's
FTextand string table system. You can subclass the line provider to plug in your own localisation pipeline.Blueprint support -- This implementation exposes the full dialogue system to Blueprints. Every component is Blueprintable, every control method is BlueprintCallable, all events are BlueprintAssignable, and presenter methods are BlueprintNativeEvent. A
UYarnBlueprintLibraryprovides 30+ static utility functions. See Blueprint Support for details.Persistence -- Unity has
SaveStateToPersistentStorage/LoadStateFromPersistentStorage. This implementation providesSaveVariablesToSlot/LoadVariablesFromSlotviaUYarnBlueprintLibrary, using Unreal's nativeUSaveGamesystem.
License
This project uses the Yarn Spinner Public License. You're free to use it in your own projects, commercial or otherwise. The only restrictions are around redistributing it as part of a competing dialogue tool, and using it to train AI models. Full details are in LICENSE.md.
Installation
Copy the
YarnSpinner/folder from this repository into your Unreal project'sPlugins/directory (so thatYarnSpinner.upluginis atPlugins/YarnSpinner/YarnSpinner.uplugin).Open your project in the Unreal Editor -- the plugin will be detected automatically.
Install
ysc(the Yarn Spinner Console tool) from :dotnet tool install YarnSpinner.Console --global --version 3.1.0-alpha1Write your dialogue in
.yarnfiles. Create a.yarnprojectfile that defines which.yarnfiles to include viasourceFilesglobs.Drag your
.yarnprojectinto the Content Browser. The plugin automatically runsysc compile, parses the compiled program, string table, and metadata, and creates aUYarnProjectasset.Add a
UYarnDialogueRunnercomponent to an actor, assign your imported Yarn Project asset, and callStartDialogue().
A game can have multiple .yarnproject files, each with its own sourceFiles scope -- useful for separating story dialogue, NPC barks, tutorials, etc. Each one compiles independently into its own UYarnProject asset.
How It Works
The Yarn Spinner compiler (ysc) compiles a .yarnproject and all .yarn files in its sourceFiles scope into a single binary (.yarnc), a string table CSV, and a metadata CSV. The editor plugin runs ysc automatically at import time via a custom UFactory, parses the outputs into an in-memory program representation (UYarnProgram), and cleans up the temp files. At runtime, a stack-based virtual machine executes the program. The VM handles control flow, variable storage, function calls, saliency selection, and content delivery. A dialogue runner component orchestrates the VM and routes lines, options, and commands to presenter components in your scene.
Compilation is always the full set of source files as defined by the project -- there's no incremental or per-file compilation. The editor plugin watches your .yarn source files on disk and automatically reimports the associated UYarnProject asset when any change is detected -- edits, new files, or changes to the .yarnproject itself. Rapid saves are debounced into a single reimport. You can also reimport manually via right-click in the Content Browser.
You write dialogue in Yarn, drag in the .yarnproject, and the plugin handles compilation, file watching, and everything else.
Architecture
The plugin has three layers:
Core (Source/YarnSpinner/) contains the runtime engine. The protobuf parser reads compiled .yarnproject binaries. The virtual machine (FYarnVirtualMachine) executes instructions. The built-in library provides operators and functions (arithmetic, comparisons, visited, random_range, format, etc.). Variable storage (IYarnVariableStorage) holds game state. The markup parser applies CLDR plural rules, [select]/[plural]/[ordinal] replacement markers, and the adoption agency algorithm for nested tags. The saliency system selects content when multiple candidates match. The smart variable evaluation VM resolves computed variables.
Dialogue Runner (UYarnDialogueRunner) is the main component you add to your actor. It owns the VM, registers built-in functions, discovers commands from handler objects, coordinates presenters, and exposes delegates for dialogue lifecycle events (OnDialogueStart, OnNodeStart, OnNodeComplete, OnDialogueComplete, OnUnhandledCommand). All configuration is done through its UPROPERTY fields in the Details panel. Every control method is BlueprintCallable and every event is BlueprintAssignable.
Presenters display content to the player. UYarnDialoguePresenter is the base class -- it delivers lines with typewriter animation and handles the hurry-up/next-content cancellation flow. UYarnOptionsPresenter shows dialogue choices. UYarnVoiceOverPresenter plays audio files synced to lines. UYarnWidgetPresenter manages UMG widgets for dialogue UI. All presenters are Blueprintable -- subclass them in Blueprints and override RunLine, RunOptions, and other events without writing C++.
Blueprint Support
The plugin is designed for Blueprint-first development. Every component, method, and event is accessible from Blueprints.
What You Can Do From Blueprints (No C++ Required)
Dialogue control -- start, stop, pause, and resume dialogue. Check if dialogue is running. Get the current node name. Swap Yarn projects at runtime.
Command handling -- add any Blueprint to the runner's CommandHandlerObjects array. Functions matching command names are discovered and called automatically with type-converted parameters. No string parsing needed.
Variable access -- read and write Yarn variables by name. Get/set typed values (string, float, bool). List all variables. Check if a variable exists. Listen for variable changes with callbacks.
Save/load -- one-call save and load of all Yarn variables to disk via Unreal's USaveGame system. Manage save slots (check existence, delete).
Runtime project swap -- change which Yarn project a runner uses at runtime via SetYarnProject. Useful for level transitions, DLC, or modding.
Custom presenters -- subclass UYarnDialoguePresenter in Blueprints and override RunLine and RunOptions to build custom dialogue UI without any C++.
Custom option widgets -- subclass UYarnOptionWidget to customise option button appearance. Override SetupOption, SetOptionUnavailable, OnOptionSelected, OnOptionDeselected.
Event binding -- bind to OnDialogueStart, OnDialogueComplete, OnNodeStart, OnNodeComplete, OnUnhandledCommand, OnVariableChanged, OnOptionSelected, OnVoiceOverStarted, OnVoiceOverComplete.
Localisation -- change locale at runtime, query available locales, add runtime localised strings.
Project inspection -- query node names, line IDs, tags, variable declarations, and project statistics from Blueprints.
Debug overlay -- add a UYarnDebugHUDComponent for a real-time debug display showing variables, execution history, and current dialogue state. Toggle with a configurable key.
UYarnBlueprintLibrary
A static function library providing 30+ utility functions accessible from any Blueprint. All functions appear under Yarn Spinner in the action menu.
Project Inspection
GetAllNodeNames, HasNode, GetNodeCount, GetLineCount, GetAllLineIDs, GetNodeTags, GetAllDeclaredVariableNames, GetDeclaredVariableDefaultValue
Variable Access
GetAllVariableNames, GetAllVariables, HasVariable, GetVariableAsString, GetVariableAsNumber, GetVariableAsBool, SetStringVariable, SetNumberVariable, SetBoolVariable
Persistence
SaveVariablesToSlot, LoadVariablesFromSlot, DoesVariableSlotExist, DeleteVariableSlot
Value Conversion
MakeYarnValueFromString, MakeYarnValueFromNumber, MakeYarnValueFromBool, YarnValueToString, GetYarnValueTypeName
Runner Helpers
GetDialogueRunner (find on actor), GetAllDialogueRunners (find all in level)
Components
UYarnDialogueRunner
The central component. Add it to an actor, assign a Yarn Project asset, and call StartDialogue().
Configuration properties (all editable in Details panel):
YarnProject(BlueprintReadOnly) -- the imported Yarn project asset to runStartNode(BlueprintReadWrite) -- which node to begin from (default:"Start")bAutoStart(BlueprintReadWrite) -- start dialogue when the game beginsVariableStorage(BlueprintReadWrite) -- where game state is stored (auto-created if not set)DialoguePresenters(BlueprintReadWrite) -- array of presenter components that receive lines and optionsLineProvider(BlueprintReadWrite) -- localisation provider (auto-created if not set)CommandHandlerObjects(BlueprintReadWrite) -- array of objects with functions matching command namesSaliencyStrategy(BlueprintReadWrite) -- how to pick between competing content candidatesbRunSelectedOptionAsLine(BlueprintReadWrite) -- re-display the chosen option as a line of dialoguebVerboseLogging(BlueprintReadWrite) -- log all VM execution for debugging
BlueprintCallable methods:
SetYarnProject-- swap to a different Yarn project at runtimeStartDialogue/StartDialogueFromStart-- begin dialogueStopDialogue-- stop immediatelyIsDialogueRunning-- check if activeContinue-- advance to next contentRequestHurryUp/RequestNextLine/RequestHurryUpOption-- cancellation flowSelectOption-- pick an option by indexGetCurrentNodeName-- get executing node nameGetCurrentCancellationToken/GetCurrentOptionsCancellationToken-- for presenter use
BlueprintAssignable events:
OnDialogueStart-- dialogue has begunOnDialogueComplete-- dialogue has endedOnNodeStart(NodeName) -- a node started executingOnNodeComplete(NodeName) -- a node finished executingOnUnhandledCommand(CommandText) -- unhandled command received
UYarnDialoguePresenter
Base presenter class for displaying dialogue lines. Handles typewriter-style text reveal with configurable speed (letters per second), auto-advance timing, and the two-tier cancellation system (hurry-up reveals text instantly, next-content advances to the next line). Supports character name extraction and markup-processed text.
BlueprintNativeEvent methods (override in Blueprint subclasses):
RunLine(Line, bCanHurry) -- display a line of dialogue. Must callOnLinePresentationCompletewhen done.RunOptions(Options) -- display dialogue choices. Must callOnOptionSelected(Index)when the player picks one.OnDialogueStarted/OnDialogueComplete-- dialogue lifecycleOnNodeEnter/OnNodeExit(NodeName) -- node lifecycleOnHurryUpRequested/OnNextLineRequested-- cancellation eventsOnOptionsHurryUpRequested-- option cancellationOnPrepareForLines(LineIDs) -- pre-load upcoming lines
BlueprintCallable methods:
OnLinePresentationComplete-- signal that line presentation is doneOnOptionSelected(Index) -- signal that an option was chosenSetAutoAdvanceEnabled/IsAutoAdvanceEnabled-- auto-advance controlStartAutoAdvanceTimer/CancelAutoAdvanceTimer-- timer managementGetDialogueRunner-- get the owning runnerIsHurryUpRequested/IsNextContentRequested-- check cancellation state
BlueprintReadOnly state:
bIsPresentingLine/bIsPresentingOptions-- current presentation stateCurrentLine/CurrentOptions-- current content being presented
UYarnWidgetPresenter
Ready-to-use text presenter that creates and manages a UMG widget. Handles typewriter effects with configurable speed.
TypewriterSpeed(BlueprintReadWrite) -- characters per second (0 = instant)BackgroundColor/TextColor/CharacterNameColor(BlueprintReadWrite) -- appearanceWidgetClass(BlueprintReadWrite) -- custom widget classGetDialogueWidget()(BlueprintCallable) -- get the widget instance
UYarnOptionsPresenter
Shows dialogue choices. Receives an option set from the runner, creates UI for each option, handles selection via mouse/keyboard/gamepad, and reports the selected option back.
Configuration (all BlueprintReadWrite):
OptionWidgetClass-- the option button widget classOptionsContainer-- panel to add option widgets tobShowUnavailableOptions/bStrikethroughUnavailable-- unavailable option displaybShowLastLine-- show the last line above optionsbUseFadeEffect/FadeInDuration/FadeOutDuration-- fade effectsbEnableKeyboardNavigation-- keyboard/gamepad navigationNavigateUpKey/NavigateDownKey/ConfirmKey(and alternates) -- configurable keys
BlueprintCallable methods:
SelectOptionByIndex/SelectNextOption/SelectPreviousOption-- navigationConfirmSelectedOption-- confirm selectionGetSelectedOptionIndex/AreOptionsVisible-- query state
BlueprintAssignable events:
OnOptionSelected(OptionIndex)OnOptionsDisplayComplete/OnOptionsDismissed
UYarnOptionWidget
Individual option button widget. Subclass in Blueprints to customise appearance.
BlueprintNativeEvent methods:
SetupOption(Option, Index) -- initialise with option dataSetOptionUnavailable-- style as unavailableOnOptionSelected/OnOptionDeselected-- focus state
Bound widgets (add these to your UMG widget):
OptionText(UTextBlock, BindWidget)OptionButton(UButton, BindWidget)
UYarnVoiceOverPresenter
Plays audio files synced to dialogue lines. Looks up audio assets by line ID and plays them through a UAudioComponent. Supports fade-in/fade-out and interruption.
bEndLineWhenVoiceOverComplete(BlueprintReadWrite) -- auto-advance on audio endFadeOutTimeOnInterrupt/WaitTimeBeforeStart/WaitTimeAfterComplete(BlueprintReadWrite) -- timingAudioComponent(BlueprintReadWrite) -- audio component to useGetVoiceOverClip(BlueprintNativeEvent) -- override to customise audio lookupOnVoiceOverStarted/OnVoiceOverComplete(BlueprintAssignable) -- events
UYarnInMemoryVariableStorage
Default variable storage. Stores variables in a TMap. Implements the IYarnVariableStorage interface.
BlueprintCallable methods:
SetString/SetNumber/SetBool/SetValue-- set variables (BlueprintNativeEvent)TryGetValue/Contains-- read variables (BlueprintNativeEvent)Clear-- remove all variables (BlueprintNativeEvent)GetAllVariables-- get all variables as typed maps (float, string, bool)SetAllVariables-- restore from typed maps (with optional clear)GetAllVariablesAsMap-- get all as a single FYarnValue mapGetDebugString-- formatted debug outputAddStringChangeListener/AddNumberChangeListener/AddBoolChangeListener-- per-variable callbacksRemoveChangeListener-- remove a callbackRegisterSmartVariableEvaluator/UnregisterSmartVariableEvaluator-- smart variable support
BlueprintAssignable events:
OnVariableChanged(VariableName, NewValue)
UYarnBuiltinLineProvider
Full localisation support. Auto-detects system culture, supports fallback locales.
bAutoDetectCulture/TextLocaleCode(BlueprintReadWrite) -- locale configurationbUseFallback/FallbackLocaleCode(BlueprintReadWrite) -- fallback configurationGetLocaleCode/SetLocaleCode(BlueprintCallable) -- runtime locale controlGetAvailableLocales(BlueprintCallable) -- list available translationsAddLocalizedString(BlueprintCallable) -- add runtime translations
UYarnDebugHUDComponent
Debug overlay for monitoring dialogue state at runtime.
DialogueRunner(BlueprintReadWrite) -- runner to monitorDebugWidgetClass(BlueprintReadWrite) -- custom debug widget classToggleKey(BlueprintReadWrite) -- key to show/hide (default: F3)bShowByDefault(BlueprintReadWrite) -- show at startbAutoLogEvents(BlueprintReadWrite) -- auto-log dialogue eventsScreenAnchor(BlueprintReadWrite) -- position on screenToggleDebugHUD/ShowDebugHUD/HideDebugHUD/IsDebugHUDVisible(BlueprintCallable)
Custom Commands
Commands can be handled three ways:
1. Blueprint Command Handler Objects (recommended for Blueprints) -- Add any UObject to the runner's CommandHandlerObjects array. Create functions matching command names. Parameters auto-convert from strings to the function's parameter types (FString, float, int, bool, FVector, FRotator, etc.).
2. C++ Lambda Registration:
3. OnUnhandledCommand event -- catch-all for commands not handled by methods 1 or 2. Fires with the full command text string.
From Yarn:
Localisation
Localisation uses the Yarn Spinner compiler's CSV string table export. The compiler generates a -Lines.csv file containing all line IDs and their text. Translate the CSV, reimport, and the plugin resolves localised text at runtime through the line provider. The built-in line provider supports auto-detection of system culture, manual locale override, and fallback locales -- all configurable from Blueprints at runtime.
Voice Over
The UYarnVoiceOverPresenter component plays audio assets matched to dialogue line IDs. Place your audio files in a content directory structure that maps to line IDs, configure the presenter with the base path, and it will automatically find and play the right audio for each line. Supports USoundBase assets (wav, ogg, etc.). Override GetVoiceOverClip in a Blueprint subclass for custom audio resolution.
Last updated
Was this helpful?
