Your First Dialogue
Let’s get something talking. We will go from an empty project to a narrator greeting the player, in about ten lines of Rust.
Install Bubbles
In a fresh Rust project, add Bubbles to your Cargo.toml:
cargo add bubbles-dialogue@0.8.0
Or by hand:
[dependencies]
bubbles-dialogue = "0.8.0"
The crates.io package key is bubbles-dialogue. In Rust you still use bubbles::… everywhere; only the dependency name in Cargo.toml is hyphenated.
Requires Rust 1.94 or later. Bubbles targets a recent stable toolchain so it can lean on modern features without
unsafe.
Write a dialogue
Paste this into src/main.rs:
use bubbles::{compile, DialogueEvent, HashMapStorage, Runner};
fn main() -> Result<(), bubbles::DialogueError> {
let program = compile(r#"
title: Start
---
Narrator: Hi. I'm the narrator.
===
"#)?;
let mut runner = Runner::new(program, HashMapStorage::new());
runner.start("Start")?;
while let Some(event) = runner.next_event()? {
if let DialogueEvent::Line { speaker, text, .. } = event {
println!("{}: {text}", speaker.as_deref().unwrap_or("*"));
}
}
Ok(())
}
Run it:
cargo run
You should see:
Narrator: Hi. I'm the narrator.
That is a full Bubbles loop. Take a second to appreciate how little is happening.
What just happened?
Three moving parts:
- The script. A
.bubnode calledStart, with one line of narration. Every node starts withtitle:, a---header separator, the body, and a closing===. - The compile step.
compileparses and validates the source, returning aProgram. Do this once at load time. - The runner.
Runner::newtakes theProgramand a variable storage backend.HashMapStorageis the default in-memory one. We callstartwith the node name, then pull events out withnext_eventuntil it hands backNone.
Add another node
Let’s make the narrator actually go somewhere. Update the script:
title: Start
---
Narrator: Hi. I'm the narrator.
<<jump Adventure>>
===
title: Adventure
---
Narrator: Let's go on an adventure.
===
Run it again. Now you’ll see both lines.
Narrator: Hi. I'm the narrator.
Narrator: Let's go on an adventure.
<<jump Adventure>> is a command - anything between << and >> is a built-in directive. We’ll meet more of them throughout the guide.
Tip: You do not need newlines between nodes, but they help readability. Bubbles happily parses them smushed together.
Give the player a choice
Dialogue without branching is just narration. Let’s add options:
title: Adventure
---
Narrator: Where do you go?
-> The forest.
Narrator: You hear wolves.
-> The mountain.
Narrator: The air is thin, but the view is worth it.
===
Running it now prints the prompt, then… nothing happens. Bubbles is politely waiting for you to pick an option. Our Rust loop only handles Line events - we ignore the Options event entirely.
Fixing that is the next chapter.
Next: The Event Loop