Learn how to write Moontale passages


Moontale supports most standard Markdown syntax.





Paragraph 1

Paragraph 2

Paragraph 1

Paragraph 2


Line 1

Line 2

Line 1

Line 2













# Heading 1

Heading 1



## Heading 2

Heading 2



### Heading 3




* Item 1

* Item 2

* Item 3

- Item 1

- Item 2

- Item 3

  • Item 1

    • Item 2

  • Item 3



1. One

1. One A

2. Two

1) One

1) One A

2) Two

  1. One

    1. One A

  2. Two








Horizontal rule







The following Markdown elements are not supported:

  • Hyperlinks, of the form [Label](Target) and https://...

  • Images, of the form ![Image](Source)

  • Raw HTML tags

Moontale supports the Twine standard format for passage links.

  • [[Passage]]

  • [[Label->Passage]]

  • [[Passage<-Label]]

The Twine editor looks for links like these, and uses them to draw pretty lines between passages. When you rename a passage in the editor, it will automatically update any links that use the syntax above.

You can also use code to create a link: $Link('Passage')[Label] - but the link lines and auto-updating won't work in this case, so you should use the standard syntax wherever possible.

In links with a separate label and target, the label can contain any inline syntax: bold/italics, variables, expressions, etc. It cannot contain line-based syntax such as headers or lists. The target is not parsed further, so [[Label->$foo]] will look for a passage named $foo, not the value of the foo variable. To calculate the target dynamically, use $Link(foo)[Label].

A passage link with a blank label, like [[ ->Passage]] will embed the passage directly in the body rather than creating a clickable link. This is equivalent to $Display('Passage') , but with the benefits of link lines, rename handling and so on.


There are three ways to embed Lua code into a passage:

  • Variables: $x

  • Expressions: <$ x $>

  • Scripts: {$ show(x) $}

The Variable syntax will look up the value of the variable in question, and display it. The variable name must begin with an ASCII letter or underscore, which is followed by a contiguous sequence of ASCII letters, numbers, or underscores. This ensures that monetary values in the text e.g. $1.10 will display as intended.

If for some reason you want to look up a variable with a non-identifier name, you can use <$ _G['1.10'] $>

Short-form variables are of course limited to a single identifier. To show the result of an expression - a function call, arithmetic, or similar - you can use the expression syntax: <$ 1 + 2 + 3 $> will print '6'. You can add whitespace and new-lines anywhere you could ordinarily with Lua, without affecting the output.

If your expression is limited to a sequence of property accesses ( ) and calls ( foo(bar) or foo{a = 1}), and doesn't include any line breaks, you can omit the <$ $> tokens: $ show('abc') end).baz is valid! Note that extra whitespace around the joining . and ( ) tokens isn't allowed. Indexers with [ ] aren't valid because they would conflict with the Changer syntax.

Remember that The Parser is Dumb. Scanning for 'call' expressions is done by balancing ( and ) , so if you have a string literal with ) it will cause issues! Use the <$ $> markers in this case.

Expressions are limited to a single, well, expression. If you want to run code with statements, such as to set variables and define functions, you can use the script block syntax, e.g. {$ x = 5 $}, which will set the value of 'x' to '5'. Script blocks only generate output if explicit calls to show() and friends are made. As with expressions, you can add whitespace anywhere you like.

Internally, short-form variables expand to expressions, which in turn expand to script blocks with an inner call to show(). So $foo expands to <$ foo $> which expands to {$ show(foo) $}.


When using untagged Lua expressions in markdown, Moontale adds an additional 'call' operator: << >> , the 'Lambda' syntax, which wraps its body in an anonymous function and passes it to the preceding expression. This makes interactivity Changers easier to write: instead of $ x = x + 1 end) you can write $<<x = x + 1>>. You can combine multiple statements with ;, for example $<<x = x + 1; y = y - 1>>

A Lambda is always a parameter-less function; if the caller passes in any arguments, you won't be able to access them. You can, however, return values with return as the final statement, if needed.

Lambdas are not parsed in tagged expressions (<$ $>), nor in script blocks ({$ $}).


If a short-form variable or expression immediately precedes a 'content block' - any content surrounded by [ and ] - it will be treated as a 'changer' with the content block applied to it. Changer blocks can be nested infinitely.

A content block without an attached changer expression will generate a warning (because there is no reason to do this) but will otherwise be shown normally. So [Text] will display as Text.

You can also apply changers to any of the link syntaxes, e.g. $[[Label->Target]].

Last updated