Dialogue Nodes
How to create and structure dialogue nodes in Dialogue Forge
Dialogue Nodes
Every piece of dialogue in Dialogue Forge is a node. Nodes connect to form branching conversation trees.
Node Types
AI Message (type: 'ai')
What the character says. These display as left-aligned chat bubbles.
Typescript
{
id: 'greeting',
type: 'ai',
speaker: 'Stranger',
content: "Hello, traveler. What brings you here?",
nextNodeId: 'first_choice' // Auto-advances to this node
}Properties:
id— Unique identifier (use snake_case)speaker— Character name shown above the messagecontent— The dialogue text (supports\nfor line breaks)nextNodeId— Which node to go to next (optional—omit for endings)setFlags— Array of memory flags to set when this node plays
Choice Point (type: 'choice_point')
Where the player picks a response. Displays as buttons at the bottom.
Typescript
{
id: 'first_choice',
type: 'choice_point',
content: '', // Usually empty
choices: [
{
id: 'choice_friendly',
text: "I come in peace.",
nextNodeId: 'friendly_response',
setFlags: ['was_friendly']
},
{
id: 'choice_hostile',
text: "None of your business.",
nextNodeId: 'hostile_response',
setFlags: ['was_hostile']
}
]
}Choices
Each choice in a choice_point has:
| Property | Type | Description |
|---|---|---|
id | string | Unique identifier |
text | string | What the player sees on the button |
nextNodeId | string | Where this choice leads |
setFlags | string[] | Flags to set when chosen |
conditions | Condition[] | When to show this choice |
Memory Flags
Flags are strings that persist throughout the conversation. Use them to:
- Track choices —
setFlags: ['chose_treasure'] - Unlock options — Show choices only if a flag is set
- Lock options — Hide choices if a flag is set
- Change dialogue — Different AI responses based on flags
Setting Flags
On AI nodes:
Typescript
{
id: 'give_map',
type: 'ai',
speaker: 'Stranger',
content: "Take this map.",
setFlags: ['has_map'], // Player now has the map
nextNodeId: 'next_node'
}On choices:
Typescript
{
id: 'accept_quest',
text: "I'll help you.",
nextNodeId: 'quest_accepted',
setFlags: ['accepted_quest', 'is_ally'] // Multiple flags
}Conditional Choices
Show/hide choices based on flags:
Typescript
choices: [
{
id: 'use_map',
text: "I have a map that shows the way.",
nextNodeId: 'map_path',
conditions: [
{ flag: 'has_map', operator: 'is_set' }
]
},
{
id: 'bribe',
text: "Perhaps some gold will change your mind?",
nextNodeId: 'bribe_attempt',
conditions: [
{ flag: 'already_bribed', operator: 'is_not_set' }
]
}
]Operators:
is_set— Choice appears only if the flag existsis_not_set— Choice appears only if the flag does NOT exist
Multiple Conditions
All conditions must be true (AND logic):
Typescript
conditions: [
{ flag: 'has_key', operator: 'is_set' },
{ flag: 'guard_asleep', operator: 'is_set' },
{ flag: 'already_entered', operator: 'is_not_set' }
]
// Shows only if: has key AND guard is asleep AND haven't entered yetCreating Dialogue Trees
Basic Structure
Typescript
const myDialogue: DialogueTree = {
id: 'my-dialogue',
title: 'My Story',
startNodeId: 'start',
nodes: {
'start': { /* first node */ },
'node_2': { /* ... */ },
// ... more nodes
}
}Flow Patterns
Linear: A → B → C
Typescript
'a': { type: 'ai', content: '...', nextNodeId: 'b' },
'b': { type: 'ai', content: '...', nextNodeId: 'c' },
'c': { type: 'ai', content: '...' } // No nextNodeId = endingBranch: A → [choice] → B or C
Typescript
'a': { type: 'ai', content: '...', nextNodeId: 'choice_1' },
'choice_1': {
type: 'choice_point',
choices: [
{ text: 'Option 1', nextNodeId: 'b' },
{ text: 'Option 2', nextNodeId: 'c' }
]
}Merge: B and C → D
Typescript
'b': { type: 'ai', content: '...', nextNodeId: 'd' },
'c': { type: 'ai', content: '...', nextNodeId: 'd' },
'd': { type: 'ai', content: '...' }Loop: D → [choice] → back to A
Typescript
'choice_at_d': {
type: 'choice_point',
choices: [
{ text: 'Ask another question', nextNodeId: 'a' },
{ text: 'Leave', nextNodeId: 'ending' }
]
}Endings
A node without nextNodeId is an ending. The UI shows "End of dialogue" with a restart button.
Typescript
'bad_ending': {
id: 'bad_ending',
type: 'ai',
speaker: 'Narrator',
content: "You walk away into the mist, alone.\n\n— THE END —"
// No nextNodeId = this is an ending
}Tips
- Use descriptive IDs —
treasure_path_choicenotchoice_3 - Group related flags —
quest_dragon_accepted,quest_dragon_complete - Test branches — Use the Editor panel to see all nodes and flags
- Create loops carefully — Ensure there's always a way out
- Write endings — Every branch should eventually reach an ending node