Saga is a small interactive fiction/story-game compiler written in Odin. It takes a directory of Markdown-like .saga files and emits a standalone HTML story with choices, state, widgets, images, character profiles, and dialogue bubbles.
Saga v0.1 provides a compact, author-friendly story language and a generated HTML runtime that is easy to preview locally.
- Markdown-style scene headings:
# Start,## ChildScene,### NestedScene. - Passage text with optional conditions.
- Additive and fallback choice buttons with transfers.
- One-shot transfers for choices.
- Cross-module story files.
- Simple state/effect expressions for story state and setup metadata.
- Root-relative image assets.
- Dock widgets such as Inventory, Contacts, and Settings.
- Modal widgets for items, character profiles, saves, and JavaScript-backed custom widgets.
- Inline character dialogue bubbles with portraits.
- Local browser save/load slots via
localStorage, with JSON import/export. - Compile-time validation for targets, widgets, dialogue speakers, and image assets.
From the repository root:
odin run src -- examples/test_drive/main.saga examples/test_drive/out.htmlThen open:
examples/test_drive/out.html
The generated HTML is standalone: it embeds the compiled story data, CSS, and JavaScript runtime.
The main sample story lives in:
examples/test_drive/
It demonstrates:
- multi-file stories,
- inventory and contacts widgets,
- item and character modals,
- character portraits,
- dialogue bubbles,
- image assets,
- conditional choices,
- one-shot choices,
- and multiple endings.
See examples/test_drive/README.md for details.
A tiny story can look like this:
# Start
`visited ?= false`
> Rain taps against the shutters.
+ *-> [Open the letter](#.Letter)
+ -> [Step outside](#Village)
## Letter
`visited := true`
> 
> The letter says: Find the bell before moonrise.
+ -> [Continue](#Village)
# Village
> The road north disappears into rain.
+ -> [Walk north](/ruins.saga#Gate)
A character profile and dialogue bubble:
@widget std:character
# BlueScarf
> 
> The woman with the blue scarf.
# Market
>> [Blue Scarf](/characters.saga#BlueScarf) Then you are already late.
>> Find the archivist's mark beneath the tower.
For the full language reference, see docs/grammar.txt.
saga <entry.saga> <output.html>Arguments:
entry.saga— the entry story file. Its directory is treated as the story root.output.html— generated standalone HTML file.
When building from source during development, use:
odin run src -- <entry.saga> <output.html>src/ Compiler and HTML generator
src/runtime.js Generated story runtime, injected into HTML
src/style.css Generated story stylesheet, injected into HTML
docs/grammar.txt Saga language reference
docs/authoring.md Practical guide for writing stories
docs/backlog.md Near-term project backlog
examples/test_drive/ Full sample story
Run tests:
odin test srcBuild the sample story:
odin run src -- examples/test_drive/main.saga examples/test_drive/out.htmlIf you use Nix:
nix develop
odin test srcBuild the release package with Nix:
nix buildThis builds the saga binary and packages the test-drive story as result/test_drive.zip with out.html and assets/ at the zip root.
Current v0.1 limitations to keep in mind:
- expressions are evaluated by the generated JavaScript runtime,
- statements are single-line,
- and release packaging/documentation can still be improved.
See docs/backlog.md for follow-up work.
Saga itself is licensed under the GNU GPLv3-or-later. See LICENSE.
Stories created with Saga remain owned by their authors and do not need to use the GPL. Generated HTML output may be distributed by the story author under the terms they choose, while the embedded Saga runtime/style code remains GPL-licensed.
See TERMS.md for the full project/story/output licensing policy.