godot-dialogue-system
Expert patterns for branching dialogue systems including dialogue graphs (Resource-based), character portraits, player choices, conditional dialogue (flags/quests), typewriter effects, localization support, and voice acting integration. Use for narrative games, RPGs, or visual novels. Trigger keywords: DialogueLine, DialogueChoice, DialogueGraph, dialogue_manager, typewriter_effect, branching_dialogue, dialogue_flags, localization, voice_acting.
What this skill does
# Dialogue System
Expert guidance for building flexible, data-driven dialogue systems.
## Available Scripts
### [dialogue_resource.gd](scripts/dialogue_resource.gd)
Data-driven conversation tree container using Resources for modular, branching narrative paths.
### [dialogue_node_data.gd](scripts/dialogue_node_data.gd)
Serialized data structure for a single line of dialogue, including speaker metadata and portraits.
### [dialogue_option_data.gd](scripts/dialogue_option_data.gd)
Interactive player choice definition with branching logic and scriptable availability conditions.
### [dialogue_manager_singleton.gd](scripts/dialogue_manager_singleton.gd)
Centralized AutoLoad orchestrator for traversing dialogue trees and broadcasting state signals.
### [dialogue_ui_controller.gd](scripts/dialogue_ui_controller.gd)
Reactive UI bridge that maps dialogue data to visual labels and dynamic choice buttons.
### [typebox_effect.gd](scripts/typebox_effect.gd)
Polished "Character-by-character" text reveal effect using Godot's built-in Tweens.
### [dialogue_event_bridge.gd](scripts/dialogue_event_bridge.gd)
Bridge node for triggering external game events (e.g. starting a quest) from conversation nodes.
### [branching_condition_validator.gd](scripts/branching_condition_validator.gd)
Expert logic for evaluating player stats or global flags to toggle dialogue choices.
### [localized_dialogue_resource.gd](scripts/localized_dialogue_resource.gd)
Advanced strategy for supporting multi-language conversation text via translation keys.
### [dialogue_portrait_manager.gd](scripts/dialogue_portrait_manager.gd)
Visual controller for managing character expressions and entry animations during dialogue.
## NEVER Do in Dialogue Systems
- **NEVER hardcode dialogue text directly in your GDScript files** — This makes translation impossible. Store text in Resources or external JSON/CSV files [12].
- **NEVER display choices that the player hasn't met the criteria for** — Hidden choices should stay hidden unless they are "grayed out" intentionally to show a missed path [13].
- **NEVER use loose strings for node transitions without validation** — Typos in `next_node_id` will crash the dialogue mid-convo. Use `assert()` or a central ID registry [14].
- **NEVER force a typewriter effect without a "Skip" option** — Forcing players to read at a fixed speed leads to frustration. Always allow clicking to finish the line [15].
- **NEVER store the current dialogue state inside a UI node** — If the UI is closed or the scene changes, the player loses their place. Use an AutoLoad `DialogueManager` [16].
- **NEVER use `get_node()` to find dialogue UI from the NPC script** — Use signals like `DialogueManager.start_dialogue(res)` to maintain a decoupled architecture.
- **NEVER use complex regex for simple text tags** — Godot's `RichTextLabel` supports BBCode tags natively. Use `[b]`, `[i]`, and `[url]` for formatting.
- **NEVER perform save/load operations inside a dialogue node** — Conversation nodes should be pure data. Delegate persistence to a dedicated `SaveSystem`.
- **NEVER block the main thread for text reveal timing** — Never use `OS.delay_msec()`. Use `create_timer()` or `Tween` to maintain smooth 60fps performance.
- **NEVER hardcode portrait paths** — Assign textures directly to the `DialogueNode` resource in the inspector or use a central `PortraitDatabase`.
---
## Available Scripts
> **MANDATORY**: Read the appropriate script before implementing the corresponding pattern.
### [dialogue_engine.gd](scripts/dialogue_engine.gd)
Graph-based dialogue with BBCode signal tags. Parses [trigger:event_id] tags from text, fires signals, and loads external JSON dialogue graphs.
### [dialogue_manager.gd](scripts/dialogue_manager.gd)
Data-driven dialogue engine with branching, variable storage, and conditional choices.
---
## Dialogue Data
```gdscript
# dialogue_line.gd
class_name DialogueLine
extends Resource
@export var speaker: String
@export_multiline var text: String
@export var portrait: Texture2D
@export var choices: Array[DialogueChoice] = []
@export var conditions: Array[String] = [] # Quest flags, etc.
@export var next_line_id: String = ""
```
```gdscript
# dialogue_choice.gd
class_name DialogueChoice
extends Resource
@export var choice_text: String
@export var next_line_id: String
@export var conditions: Array[String] = []
@export var effects: Array[String] = [] # Set flags, give items
```
## Dialogue Manager
```gdscript
# dialogue_manager.gd (AutoLoad)
extends Node
signal dialogue_started
signal dialogue_ended
signal line_displayed(line: DialogueLine)
signal choice_selected(choice: DialogueChoice)
var dialogues: Dictionary = {}
var flags: Dictionary = {}
func load_dialogue(path: String) -> void:
var data := load(path)
dialogues[path] = data
func start_dialogue(dialogue_id: String, start_line: String = "start") -> void:
dialogue_started.emit()
display_line(dialogue_id, start_line)
func display_line(dialogue_id: String, line_id: String) -> void:
var line: DialogueLine = dialogues[dialogue_id].lines[line_id]
# Check conditions
if not check_conditions(line.conditions):
# Skip to next
if line.next_line_id:
display_line(dialogue_id, line.next_line_id)
else:
end_dialogue()
return
line_displayed.emit(line)
# Auto-advance or wait for player
if line.choices.is_empty() and line.next_line_id:
# Wait for player to click
await get_tree().create_timer(0.1).timeout
elif line.choices.is_empty():
end_dialogue()
func select_choice(dialogue_id: String, choice: DialogueChoice) -> void:
choice_selected.emit(choice)
# Apply effects
for effect in choice.effects:
apply_effect(effect)
# Continue to next line
if choice.next_line_id:
display_line(dialogue_id, choice.next_line_id)
else:
end_dialogue()
func end_dialogue() -> void:
dialogue_ended.emit()
func check_conditions(conditions: Array[String]) -> bool:
for condition in conditions:
if not flags.get(condition, false):
return false
return true
func apply_effect(effect: String) -> void:
# Parse effect string, e.g., "set_flag:met_npc"
var parts := effect.split(":")
match parts[0]:
"set_flag":
flags[parts[1]] = true
"give_item":
# Integration with inventory
pass
```
## Dialogue UI
```gdscript
# dialogue_ui.gd
extends Control
@onready var speaker_label := $Panel/Speaker
@onready var text_label := $Panel/Text
@onready var portrait := $Panel/Portrait
@onready var choices_container := $Panel/Choices
var current_dialogue: String
var current_line: DialogueLine
func _ready() -> void:
DialogueManager.line_displayed.connect(_on_line_displayed)
DialogueManager.dialogue_ended.connect(_on_dialogue_ended)
visible = false
func _on_line_displayed(line: DialogueLine) -> void:
visible = true
current_line = line
speaker_label.text = line.speaker
portrait.texture = line.portrait
# Typewriter effect
text_label.text = ""
for char in line.text:
text_label.text += char
await get_tree().create_timer(0.03).timeout
# Show choices
if line.choices.is_empty():
# Wait for input to continue
pass
else:
show_choices(line.choices)
func show_choices(choices: Array[DialogueChoice]) -> void:
# Clear existing
for child in choices_container.get_children():
child.queue_free()
# Add choice buttons
for choice in choices:
if not DialogueManager.check_conditions(choice.conditions):
continue
var button := Button.new()
button.text = choice.choice_text
button.pressed.connect(func(): _on_choice_selected(choice))
choices_container.add_child(button)
func _on_choice_selected(choice: DialogueChoicRelated in Image & Video
watch
IncludedWatch a video (URL or local path). Downloads with yt-dlp, extracts auto-scaled frames with ffmpeg, pulls the transcript from captions (or Whisper API fallback), and hands the result to Claude so it can answer questions about what's in the video.
physical-ai-defect-image-generation
IncludedUse when the user wants to orchestrate defect image generation, run associated setup, or handle outputs on OSMO. The Day 0 path handles cold-start with USD-to-ROI, image-edit augmentation, and AnomalyGen to create initial PCBA datasets. The Day 1 path performs inference and labeling on real images. This skill helps with first-time asset setup, creation of finetuning checkpoints, and configuring deployment. Trigger keywords: defect image generation, dig workflow, dig pipeline, defect image detection workflow, aoi pipeline, aoi anomalygen, usd2roi anomalygen, day 0 pcba, day 1 pcba, day 1 real-photo alignment, day 1 manual roi, metal surface anomaly, glass defect, anomalygen finetune, setup_pcb, setup_metal, setup_glass, setup_pretrained, dig setup, dig datasets, dig pretrained checkpoint, dig image-edit endpoint.
accelint-react-best-practices
IncludedReact performance optimization and best practices. ALWAYS use this skill when working with any React code - writing components, hooks, JSX; refactoring; optimizing re-renders, memoization, state management; reviewing for performance; fixing hydration mismatches; debugging infinite re-renders, stale closures, input focus loss, animations restarting; preventing remounting; implementing transitions, lazy initialization, effect dependencies. Even simple React tasks benefit from these patterns. Covers React 19+ (useEffectEvent, Activity, ref props). Triggers - useEffect, useState, useMemo, useCallback, memo, inline components, nested components, components inside components, re-render, performance, hydration, SSR, Next.js, useDeferredValue, combined hooks.
elevenlabs-agents
IncludedBuild conversational AI voice agents with ElevenLabs Platform using React, JavaScript, React Native, or Swift SDKs. Configure agents, tools (client/server/MCP), RAG knowledge bases, multi-voice, and Scribe real-time STT. Use when: building voice chat interfaces, implementing AI phone agents with Twilio, configuring agent workflows or tools, adding RAG knowledge bases, testing with CLI "agents as code", or troubleshooting deprecated @11labs packages, Android audio cutoff, CSP violations, dynamic variables, or WebRTC config. Keywords: ElevenLabs Agents, ElevenLabs voice agents, AI voice agents, conversational AI, @elevenlabs/react, @elevenlabs/client, @elevenlabs/react-native, @elevenlabs/elevenlabs-js, @elevenlabs/agents-cli, elevenlabs SDK, voice AI, TTS, text-to-speech, ASR, speech recognition, turn-taking model, WebRTC voice, WebSocket voice, ElevenLabs conversation, agent system prompt, agent tools, agent knowledge base, RAG voice agents, multi-voice agents, pronunciation dictionary, voice speed control, elevenlabs scribe, @11labs deprecated, Android audio cutoff, CSP violation elevenlabs, dynamic variables elevenlabs, case-sensitive tool names, webhook authentication
humanizer
IncludedHumanize AI-generated text by detecting and removing patterns typical of LLM output. Rewrites text to sound natural, specific, and human. Uses 28 pattern detectors, 560+ AI vocabulary terms across 3 tiers, and statistical analysis (burstiness, type-token ratio, readability) for comprehensive detection. Use when asked to humanize text, de-AI writing, make content sound more natural/human, review writing for AI patterns, score text for AI detection, or improve AI-generated drafts. Covers content, language, style, communication, and filler categories.
generating-mermaid-diagrams
IncludedSalesforce architecture diagrams using Mermaid with ASCII fallback. Use this skill when generating text-based diagrams for Salesforce architecture, OAuth flows, ERDs, integration sequences, or Agentforce structure. TRIGGER when: user says "diagram", "visualize", "ERD", or asks for sequence diagrams, flowcharts, class diagrams, or architecture visualizations in Mermaid. DO NOT TRIGGER when: user wants PNG/SVG image output (use generating-visual-diagrams), or asks about non-Salesforce systems.