Storytell is a simple language for writing interactive, text-based games. Each line in a script acts as a command:
plain text is shown to the player, and symbols at the start of lines control behavior. Segments start with #
,
choices with >>>
, pauses with `
, variables are created with =
,
and reusable blocks (macros) are defined with &
and called with \\
.
Text formatting uses square brackets [green]
, and animated lines can be disabled with |
.
Here's a minimal example showing a named segment, a variable, styled output, and a branching choice:
= 100 patience
& ENCOURAGE
You can do it!
&
# start
|[green]Welcome[end] back![reset]
You have [patience]% patience left.
>>> keep going,give up
# keep going
Good choice.
\\ ENCOURAGE
>>> end
# give up
That's okay too.
>>> end
# end
Thanks for playing!
Storytell lines are animated by default. To disable animation for a line or to create an empty line, prefix it with |
.
To display a waiting message that is not stored prefix the line with `
.
Use square brackets [color]
to style text with colors or control formatting. Common formatting tags are shown below.
Use empty lines marked with |
for spacing, and include [reset]
or a color at the start of a line
if you want to write symbols like #
or >>>
without triggering their behavior.
[green]
, [red]
, etc. – text color[reset]
– reset formatting[end]
– manual line break[noend]
– continue next line on the same console line
Storytell segments begin with #
and can be linked using >>>
followed by one or more comma-separated option labels.
Players navigate these options using arrow keys and confirm with space or enter.
If only one option is listed, that will be automatically selected. The next option will be visited each time; previous ones are considered fullfilled.
To jump to a previous option while also removing text, use <<<
instead. This scans the file from the beginning
and starts from the first entry with the given name. Here is an example that keeps looping:
# start
Ready to begin?
>>> yes, no
# yes
Great! Let's go.
<<< start
# no
Maybe next time.
Variables store numbers or text and are used to track game state. Assign values with =
, modify them using
+
, -
, *
, or /
, and replace them in text using square brackets.
The replacement can also be done in place of numbers or strings.
To set a variable to a random number (from 0 to a maximum), use ?
. Variable names use _
or .
to separate words.
You can conditionally run lines based on comparisons shown below.
Comparisons can be stacked for "and" logic. For conditional choices or segments, you can also use
a temporary variable with _underscores_
.
@
— equal!
— not equal<
, >
— less/greater (numbers only)
?100 patience
# intro
?50 annoyed
You have [patience]% patience left.
You got [annoyed]% annoyed.
-[annoyed] patience
<10 patience ="expl" _option_
>10 patience ="safe" _option_
>>> [_option_]
# expl
You exploded.
>>> the end
# safe
You're stable.
>>> the end
# the end
THE END
A simpler equivalent version of the above is:
?100 patience
# intro
?50 annoyed
You have [patience]% patience left.
You got [annoyed]% annoyed.
>10 patience >>> safe
You exploded.
>>> the end
# safe
You're stable.
# the end
THE END
Use %
blocks to create a persistent interface at the top of the screen. These are re-rendered as the story progresses.
Each HUD block starts and ends with a line containing just %
. To organize the interface, give each HUD block a name like % STATS
—
this allows overwriting HUD sections with the same name, and combines multiple sections with different names.
You can insert dynamic values (like variables) and use conditional drawing with standard logic syntax (e.g., > 7 health
).
Here is an example:
= 10 health
= 10 strength
% HEALTH
▌> 7 health [green][noend]
* health ❤
[end]
%
% STATS
Strength: [strength]
%
# start
Let’s begin your journey.
Macros define reusable text or logic blocks. Use &
to declare a macro and \\
to call it.
Macros expand inline where they're invoked and can help reduce repetition in your scripts. They can also contain any macro too as long as the latter has
been defined before the invokation point (this system is Turing complete).
You can also pass parameters to macros by naming them after the macro’s name. When calling the macro, provide values separated by commas.
Here is an example:
& GREET name
Hello, [name]!
&
# start
\\ GREET Hero
\\ GREET Friend