This guide is the author-facing workflow for Phase 72 dialogue content. It connects the graph data format, runtime behavior, localization, narrative importers, and validation gates that protect shipped conversations.
Source Of Truth#
- Tree format contract: DialogueTreeFormat_V2_Contract.json
- Runtime contract: DialogueRuntimeEngine_V2_Contract.json
- Authoring guide contract: DialogueAuthoringGuide_V2_Contract.json
- Sample tree: asha-storm-market-intro.v2dialogue.json
- Sample localization: asha-storm-market-intro.v2dialogueloc.json
- Ink fixture: asha-storm-market-route.ink
- Yarn Spinner fixture: asha-storm-market-route.yarn
- Runtime implementation: V2DialogueRuntime.cpp
- Automation spec: DialogueRuntime.spec.cpp
Authoring Workflow#
- Choose or create a stable
dialogueIdthat starts withdlg.. - Define participants before writing nodes. Use
speaker.playerfor player choices and stable NPC ids such asnpc.asha_stormfor authored speakers. - Write the conversation as a
*.v2dialogue.jsongraph withtext,choice,condition,action, andrandomnodes. - Put branching requirements on edge
conditions, not in prose. - Put side effects in
actionnodes or edgeactionswhen the side effect must happen atomically with a selected transition. - Add every player-facing line id to the localization table before review.
- Run the validation commands in this guide and include the command output in the content review.
- Land tree, localization, imported source, and documentation changes in the same review when they are part of one authored conversation.
Stable Ids#
Dialogue content is saved, localized, tested, and analyzed by stable ids. Do not encode authored order into ids unless that order is permanent.
| Artifact | Prefix | Example |
|---|---|---|
| Dialogue | dlg. |
dlg.asha_storm.market_intro |
| Node | n. |
n.player_choice |
| Edge | e. |
e.choice.ask_route |
| Choice | choice. |
choice.ask_route |
| Line | loc.dialogue. |
loc.dialogue.asha.market_intro.route_response |
| Subtitle | sub.dialogue. |
sub.dialogue.asha.market_intro.route_response |
| Participant | npc. |
npc.asha_storm |
If a shipped id needs to change, keep the old id in redirect metadata for the release that migrates saves and analytics.
Graph Rules#
Every tree starts at startNodeId and must reach an explicit terminal text
node. Terminal nodes set terminal: true and have no outgoing edges.
Use these node kinds consistently:
| Kind | Use For |
|---|---|
text |
One speaker line resolved through localization. |
choice |
Player-authored choice menus from outgoing edges. |
condition |
Silent branching based on game state. |
action |
Silent side effects before traversal continues. |
random |
Deterministic weighted variants, never story gates. |
Every non-terminal node needs an outgoing edge. Every node must be reachable
from startNodeId, and every reachable node must be able to reach a terminal
node. Condition nodes must also be reachable; otherwise the branch is authored
but untestable. Runtime and CI validation use AuditDialogueTreeGraph to report
unreachable nodes, dead ends, missing terminal paths, and unreachable condition
nodes.
Conditions#
Use conditions for game-state facts that determine whether a transition is available. Supported condition references are:
quest_stateinventory_countrelationship_valuetime_of_dayplayer_statlocal_variablepersistent_variableglobal_story_variablechoice_history
Conditions should be specific enough for QA to set up. Prefer a named quest, item, stat, NPC, or story variable over a generic flag. When two outcomes are required, author an explicit fallback edge with a lower priority.
Actions#
Actions represent side effects. Supported action references are:
set_variableemit_eventgrant_itemmodify_relationshipplay_animationspawn_entitystart_quest
Action nodes are best for visible or story-significant side effects. Edge actions are reserved for consequences that must be recorded exactly when a choice is selected.
Variables And Choice Consequences#
Use local variables for state that only matters during the active conversation.
Use persistent NPC variables for per-character memory, and global story
variables for cross-character state. Choice consequences are recorded by
choiceId and by dialogueId.choiceId, so future conversations can query
whether the player made a previous choice.
Localization And Voice#
All player-facing text uses loc.dialogue.* line ids. Tree files reference line
ids; localization tables provide text, voice cues, and subtitle timing per
locale. The source locale is en-US.
Voiced text nodes should include both voiceCue and subtitleTimingId.
Localized voice can be missing during development, but localized subtitle text
must be present for every required line id before content review.
Text Tags And Display#
Inline dialogue tags use square brackets and are stripped before typewriter display. Supported tag kinds are pause, emotion, emphasis, speed, and event.
Examples:
Hold [pause=0.5][concerned]steady [speed=1.2]now.
The typewriter display consumes tag-stripped plain text, reveals by characters-per-second, supports fast-forward, and can skip directly to the full line. Author tags for presentation cues, not for branching logic.
Bark And Priority Usage#
Barks are short context-sensitive lines selected by context, required tags, blocked tags, priority, and cooldown. Use barks for combat, exploration, and idle responses that do not require graph traversal.
Dialogue priority determines whether queued conversations interrupt the active
conversation. Use Ambient for low-stakes barks, Casual for optional
conversations, Standard for normal authored conversations, Urgent for
interruptions that matter immediately, and Critical for non-skippable safety
or story-critical moments.
Ink And Yarn Spinner Imports#
Use the importers when writers author in external narrative tools. The supported
subset imports line-based Ink knots and Yarn Spinner title blocks into
FV2DialogueTree and FV2DialogueLocalizationTable.
Supported metadata tokens:
#line:loc.dialogue...#speaker:npc...#choice:choice...#tag:quest#condition:global_story_variable:story.market_unlocked=true#action:start_quest:Quest.MarketRoutes=active
Yarn commands such as <<set $asked_for_route = true>> become action nodes. Ink
commands such as ~ set asked_for_route = true do the same. Jumps and diverts
become graph edges.
Review Checklist#
Before content review, confirm:
- The tree uses schema
v2.dialogue.tree.v1andformatVersion: 1. - Every node, edge, choice, and line id has the correct prefix.
- Every non-terminal node has an outgoing edge.
- Every node is reachable from
startNodeId. - Every reachable node can reach an explicit terminal node.
- Every condition node and condition-bearing edge is reachable.
- Every choice edge has
choiceId,choiceLineId, andchoiceTags. - Every random edge has a positive
weight. - Every voiced text node has
voiceCueandsubtitleTimingId. - Every required line id is present in the localization table.
- Any imported Ink or Yarn source is committed with the generated tree changes.
Validation Commands#
Run these commands after changing dialogue authoring docs, trees, localization, imported source, or runtime graph behavior:
python3 V2/ue/Tools/check-v2-dialogue-authoring-guide.py
python3 V2/ue/Tools/check-v2-dialogue-unit-tests.py
python3 V2/ue/Tools/check-v2-dialogue-narrative-importers.py
python3 V2/ue/Tools/check-v2-dialogue-tree-format.py
python3 V2/ue/Tools/check-v2-dialogue-runtime-engine.py
python3 V2/ue/Tools/check-v2-ci-workflow.py
python3 -m json.tool V2/ue/Content/V2/Gameplay/Dialogue/DialogueAuthoringGuide_V2_Contract.json
python3 -m json.tool V2/ue/Build/Horde/v2-buildgraph-job.json
python3 V2/tools/validate-v2-docs.py
pnpm exec prettier --check V2/docs/modes/dialogue-authoring-guide.md V2/ue/Content/V2/Gameplay/Dialogue/DialogueAuthoringGuide_V2_Contract.json V2/ue/Build/Horde/v2-buildgraph-job.json