Introduction to Loreline

Loreline is an open-source scripting language for writing interactive fiction. It handles branching dialogue, player choices, characters, and story state in a syntax designed to be readable by writers while still offering real programming tools (variables, conditionals, functions) when the story needs them.

Loreline works everywhere: game engines, web apps, or standalone projects. It adapts to your tools, the stories you write stay portable.

A first look

Here is a minimal Loreline script:

The warm aroma of coffee fills the café.

barista: Hi there! How are you doing today?

choice
  Having a great day
    barista: Wonderful! Coffee will make it even better.

  Need caffeine...
    barista: Say no more! Let me help with that.

  Your name is Alex, right?
    barista.name = "Alex"
    barista: Oh, I didn't expect you'd remember it!

That's the core pattern. The Writer's Guide goes into this in detail.

Clean yet explicit by design

Loreline keeps additional punctuation to a minimum. Narrative text and dialogue can be written as-is, without any special delimiter. Jumping to another section is a simple ->. Assigning a variable is just =. Conditions don't need a closing keyword, indentation is enough. A choice option can carry an inline if that hides it when the condition isn't met.

At the same time, the main structural elements (beat, choice, character, state, if, else) are plain English keywords rather than symbols. They're easy to understand at a glance, without needing to learn what each special character means. This is a deliberate trade-off: readable words over cryptic punctuation.

Other tools lean more on symbols or delimiters: Yarn Spinner uses <<if>>...<<endif>> and <<set>>; Ink has its own set of markers for choices, knots, and diverts. Loreline tries to stay close to plain text, and the editor is smart enough to apply correct syntax highlighting from those minimal cues alone:

The café is quiet this morning.

choice
  Order a coffee
    coffeesOrdered += 1
    if coffeesOrdered > 3
      barista: <concerned> That's quite a lot of coffee today...
    else
      barista: One more coming right up!

  Order a decaf if coffeesOrdered > 2
    barista: Good call. I'll make it a nice one.

For writers, this means the script reads closer to plain language, with less visual noise between the story and the structure.

Story structure

A story is organized into beats, named sections that work like scenes or chapters. A beat can jump to another with ->, or call one with BeatName() as a detour that returns to the caller when finished:

beat EnterCafe
  The morning sun streams through the café windows.
  barista: Welcome! I don't think I've seen you here before.
  TakeOrder()
  barista: Enjoy your coffee!
  -> EndScene

beat TakeOrder
  barista: So, what can I get started for you?

Characters are a first-class concept: you declare them with fields that can be read and updated throughout the story:

character barista
  name: Alex
  mood: friendly
  friendship: 0

Persistent data lives in a state block. Conditionals (if, else if, else) let the story react to earlier decisions, and choices can have inline conditions to show or hide options dynamically.

if barista.friendship > 2
  barista: Hey! Good to see you again :)

Other features

Beyond the core syntax, Loreline also supports:

barista: <friendly> Good to see you!

sarah: I'll have a <strong>very strong coffee</strong> today.
sarah: Did you know $barista.name runs the café next door?

james: Great, let's go, I need to finish reading ${james.currentBooks[0]}.

barista: You've ordered $coffeesOrdered coffee|coffees so far today.
pick
  A jazz tune drifts softly from a speaker on the shelf.
--
  The espresso machine hisses and sputters.
--
  Laughter erupts from a table by the window.
barista: Your order will be ready in $random(2, 5) minutes!
// Will display a random number between 2 and 5
import inventories
import characters

// Story that uses inventories (inventories.lor)
// and characters (characters.lor)...
JavaScript example
// Save the current state (e.g. at a checkpoint)
const saveData = interpreter.save();
localStorage.setItem('save', JSON.stringify(saveData));

// Later, restore and resume
const saved = JSON.parse(localStorage.getItem('save'));
interpreter = Loreline.resume(script, onDialogue, onChoice, onFinish, saved);

Platforms and integration

Loreline is compatible with any C# engine (including Unity), C++, JavaScript, TypeScript, Python, Lua, or JVM project. The API works the same way everywhere: load a Loreline script, then play it by providing callbacks for dialogue, choices, and story completion.

All targets share a common codebase written in Haxe, which ensures consistent behaviour across languages and lets updates ship everywhere at once with no major feature differences. A suite of over 160 test files covers the runtime to help keep it reliable as the language evolves.

JavaScript example
import { Loreline } from 'loreline';

const script = Loreline.parse(source);

Loreline.play(script,

  // Called to display dialogue
  (interp, character, text, tags, callback) => {
    if (character) {
      const name = interp.getCharacterField(character, 'name');
      console.log((name || character) + ': ' + text);
    } else {
      console.log(text);
    }
    callback();
  },

  // Called to display a choice
  (interp, options, callback) => {
    options.forEach((opt, i) => {
      if (opt.enabled) console.log('  [' + (i + 1) + '] ' + opt.text);
    });
    callback(0);
  },

  // Called when execution ends
  (interp) => {
    console.log('--- The End ---');
  }
);
Platform Notes
JavaScript / TypeScript Works in Node.js and the browser. Available as an npm package.
C# / .NET Integrates with Unity, Godot (.NET), and any .NET project.
C++ Standalone library with no external dependencies.
Python Works with Python 3.8+, no external dependencies.
Java / JVM Works with Java 8+ (and Kotlin). Single JAR with no external dependencies.
Lua Works with Lua 5.1+, no external dependencies.
Haxe Available as a haxelib package with full API access.

See the integration guides for setup instructions for each platform.

Tooling

Comparison with Ink and Yarn Spinner

Ink and Yarn Spinner are the two other tools commonly used for interactive narrative. Each takes a different approach to syntax and structure.

This comparison is in no way claiming one tool is better or worse than the others. Ink and Yarn Spinner are mature, well-documented, and have been used in shipped games for years. Loreline is newer and takes a different approach. The best choice comes down to team familiarity, target engine, and which scripting style fits how you want to write.

Here is the same short script written in all three languages:

state
  coffeesOrdered: 0

character barista
  name: Alex

beat CoffeeShop
  The warm aroma of coffee fills the cafe.
  barista: Hi there! What can I get you?

  choice
    A regular coffee
      barista: Coming right up!

    A decaf if coffeesOrdered > 2
      barista: Switching to decaf? Probably wise.

  coffeesOrdered += 1
  if coffeesOrdered > 3
    barista: That's quite a lot of coffee today...
VAR coffeesOrdered = 0

=== CoffeeShop ===
The warm aroma of coffee fills the cafe.
Alex: Hi there! What can I get you?

+ A regular coffee
  Alex: Coming right up!
+ {coffeesOrdered > 2} A decaf
  Alex: Switching to decaf? Probably wise.
-
~ coffeesOrdered = coffeesOrdered + 1
{coffeesOrdered > 3:
  Alex: That's quite a lot of coffee today...
}
-> DONE
title: CoffeeShop
---
<<declare $coffeesOrdered = 0>>

The warm aroma of coffee fills the cafe.
Alex: Hi there! What can I get you?

-> A regular coffee
    Alex: Coming right up!
-> A decaf <<if $coffeesOrdered > 2>>
    Alex: Switching to decaf? Probably wise.

<<set $coffeesOrdered = $coffeesOrdered + 1>>
<<if $coffeesOrdered > 3>>
    Alex: That's quite a lot of coffee today...
<<endif>>
===

All three scripts tell the same story with comparable length but different conventions. For a detailed feature-by-feature breakdown, see the detailed comparison.

Try Loreline

The fastest way to get started is the Playground, where you can write and run Loreline scripts directly in the browser, no setup needed. When you're ready to go further, the Writer's Guide covers the full language step by step.