Godot
← Bring content into your game
Godot 4.x · GDScript
Start with one visible sentence. This small example reads the real Harbour export directly; it is not a complete dialogue player. Then connect the data to your game UI.
1 · Prepare files and scene
Create a scene with a Label root and save it. Put the complete Harbour export under res://story/. Attach FirstText.gd to the Label and run the scene with F6.
story.json · Export files explained
2 · Show the first text
extends Label
const TEXT_ID = "fd7b61a3-8233-4ba7-8f77-b88b119a91bf"
var story: Dictionary
func _ready() -> void:
var parser = JSON.new()
var error = parser.parse(FileAccess.get_file_as_string("res://story/story.json"))
if error != OK or not parser.data is Dictionary:
text = "Cannot read story/story.json"
return
story = parser.data
show_language("en")
func show_language(locale: String) -> void:
var record: Dictionary = story["content"]["texts"][TEXT_ID]
var translation: Dictionary = story["content"]["translations"].get(locale, {}).get(TEXT_ID, {})
var message: Dictionary = translation.get("message", record["sourceMessage"])
var line := ""
for segment in message["segments"]:
if segment["kind"] != "text":
text = "This example needs text-only segments"
return
line += segment["text"]
text = line
Expected: “Welcome to the harbour. I am Mira.” With locale = "de" or the language parameter de: “Willkommen im Hafen. Ich bin Mira.” A missing language uses source text. This sample supports text segments; it deliberately does not silently discard placeholders.
3 · From one sentence to a conversation
The fixed text ID above is for the first test. In your game choose flowRef/entryRef from story-index.json, read execution.entries[entryRef].nodeRef, then execution.nodes[nodeRef]. The current dialogue supplies text.textRef and speakerRef. Continuations depend on node kind.
Name/dialogue: Label.text. Answers: Button.text and the pressed signal, retaining the option ID. End: hide() the shared Control container. In the sample, show_language("de") changes the same text without advancing a node.
- Continue and End: follow connections, close the text box
- Choices: answer ID, order and selected continuation
- Conditions and variables: ten or two gold
- Language: the same IDs, newly resolved content
- Command: give an item or open a shop
- Call/Return: visit a substory and return
Inspect answers and the gold check in this language
Read the data for a choice
Insert this fragment where story is available after loading (for RPG Maker: const story = $gameTemp.vnleExample.story;). It prints IDs for inspection. Replace the output with your answer buttons. It covers the two Harbour answers and their following gold check, not a general interpreter.
# story is the Dictionary loaded above. These Harbour options have no conditions.
var choice: Dictionary = story["execution"]["nodes"]["42edfff8-b8fe-46bf-ae0d-9e2347b6e726"]
for option_id in choice["optionOrder"]:
var option: Dictionary = choice["options"][option_id]
print(option_id, " ", option["text"]["textRef"])
# Resolve each text and bind its option_id to a Button's pressed signal.
var branch: Dictionary = story["execution"]["nodes"]["c1c3c372-0a73-4cd0-851d-ede59d5709bb"]
var gold := 10 # Repeat with 2.
var next: Dictionary = branch["whenTrue"] if gold >= branch["condition"]["right"]["value"]["value"] else branch["whenFalse"]
print(next["nodeRef"])With 10 gold, next refers to “Pay five gold”; with 2 it refers to “Not enough gold”. In the actual game, run the check only when the selected path reaches this node. Each selected answer supplies its own continuation.
4 · Map your own images
This supplementary excerpt expects a current dialogue object named node and the UI elements named in its comments. For C++ and MonoGame, speakerRef has already been read as SpeakerId or speakerId. The key is Mira’s actual character ID; the image name and location belong to your game. Insert the lines at the indicated locations.
# Put mira.png at res://portraits/mira.png and add a TextureRect named Portrait.
var portraits = {"807b2957-7bab-4a28-83a4-1f3d1589bbc2": preload("res://portraits/mira.png")}
# node is the current dialogue dictionary, not a Godot scene node.
$Portrait.texture = portraits.get(node.get("speakerRef", ""))Resolve speaker names through content.characters[speakerRef].nameTextRef just like dialogue text. Missing mappings should hide the previous portrait or show a placeholder. Images are not selected by language.
Use image references from the complete export
5 · Ship files with the game
For FileAccess, preserve the raw JSON in the export: use Keep File where available, or the appropriate non-resource export filter. For images, use imported Texture2D resources or explicitly include the original PNG files. Run an exported build too.
Check your result
- English and German greetings display correctly; an unavailable language falls back to English.
- When adding flow: try both answers, gold 10/2, the return from the substory and End.
- Run the built game outside your project folder. JSON, fonts and portraits must be available there too.
Official documentation
API and setup references for this approach: