Markup

Markup lets you add attributes into your text, like [a]hello[/a]. These attributes can be used by your game to do things like change the formatting of the text, add animations, and more.

When text is parsed, the tags are removed from the text, and you receive information about the range of the plain text that the attributes apply to.

What happens to markup in your game

Yarn Spinner doesn’t make text wave, shake or change colour by itself. When a line runs, Yarn Spinner removes the markup, and gives your game the plain text and a list of the attributes, with where each one starts and how long it is. What each attribute does is up to your game.

A few attributes are handled by Yarn Spinner itself, in every engine. select, plural and ordinal change the words in the line, nomarkup turns markup off, and character marks the character’s name.

What happens to everything else depends on where the line is shown:

Where the line is shownWith no extra setupTo make [wave] wave
UnityThe line is shown as plain text.For formatting like bold and colour, add a Palette Marker Processor with a Markup Palette. For animation, write your own code, or use Text Animator.
Godot (GDScript)[b], [i], [u], [s], [code], [style], [color] and [link] are shown as formatted text. Other tags, like [wave], are removed, and their text is shown without formatting.Add a palette that turns [wave] into Godot’s own [wave] effect.
Godot (C#)The line is shown as plain text.Add a Palette Marker Processor with a Markup Palette, and give it a custom marker that turns [wave] into Godot’s own [wave] effect.
UnrealThe line is shown as plain text.Add a Markup Event Handler that watches for wave, and make the effect in Blueprints.
Try Yarn Spinner[b], [i], [wave], [shake], [color] and a few others are shown with their effect.Nothing to set up.
What each engine does with markup, out of the box.

Attributes

Attributes apply to ranges of text:

Oh, [wave]hello[/wave] there!
A line with the wave attribute around hello.

Yarn Spinner will take this text, and produce two things: the plain text, and a collection of attributes. The plain text is the text without any markers; in this example it will be:

Oh, hello there!
The plain text, with the markup removed.

Attributes represent ranges of the plain text that have additional information. They contain a position, a length, and their name, as well as their properties.

In this example, a single attribute will be generated, with a position of 4, a length of 5, and a name of “wave”.

Attributes are opened like [this], and closed like [/this].

Overlapping Attributes

Attributes can overlap:

You can put multiple attributes inside each other. For example:

Oh, [wave]hello [bounce]there![/bounce][/wave]
A bounce attribute nested inside wave.

Close attributes in the reverse order that you opened them. This line closes wave before bounce, which is a markup error, so the player sees the tags as plain text:

Oh, [wave]hello [bounce]there![/wave][/bounce]
Attributes closed in the wrong order, which is a markup error.

To close several attributes at once, use the close-all marker [/], described below.

Self-closing Attributes

Attributes can self-close:

[wave/]
A self-closing wave attribute.

A self-closing attribute has a length of zero.

The Close-All Marker

The marker [/] is the close-all marker. It closes all currently open attributes. For example:

[wave][bounce]Hello![/]
Closing wave and bounce with the close-all marker.

Properties

Attributes can have properties:

[wave size=2]Wavy![/wave]
A wave attribute with a size property of 2.

This attribute ‘wave’ has a property called ‘size’, which has an integer value of 2.

Short-hand Properties

Attributes can have short-hand properies, like so:

[wave=2]Wavy![/wave]
A wave attribute with a short-hand property.

This is the same as saying this:

[wave wave=2]Wavy![/wave]
The same attribute, with the property written out in full.

This attribute ‘wave’ has a property called ‘wave’, which has an integer value of 2. The name of the attribute is taken from the first property.

Property Types

Properties can be any of the following types:

  • Integers
  • Floats
  • ’true’ or ‘false’
  • Strings

Single words without quote marks are parsed as strings. For example, the two following lines are identical:

[mood=angry]Grr![/mood]
[mood="angry"]Grr![/mood]
Two ways of setting the mood property to the string angry.

Whitespace Trimming

If a self-closing attribute has white-space before it, or it’s at the start of the line, then it will trim a single whitespace after it. This means that the following text produces a plain text of “A B”:

A [wave/] B
A self-closing attribute that trims the space after it.

If you don’t want to trim whitespace, add a property trimwhitespace, set to false:

A [wave trimwhitespace=false/] B 
// (produces "A  B")
Keeping both spaces with trimwhitespace=false.

Showing Special Characters to the Player

You may want to show text containing the [ and ] characters to your player. To prevent the markup parser from treating as special characters, you can escape them. Text that has been escaped will be treated as plain text, and will not be interpreted by the parser.

There are two ways to escape your markup: escaping single characters, and using the nomarkup attribute.

Escaping single [ and ] characters

If you need to escape a single square bracket character, put a backslash \ in front of it:

Here's some square brackets, just for you: \[ \]
Escaping square brackets with backslashes.

This will appear to the player as:

Here's some square brackets, just for you: [ ]
The line as the player sees it, without the backslashes.

The backslash will not appear in the text.

If you need to show a backslash in your text, use two backslashes:

Here's a backslash! \\
Two backslashes, to show one.

This will appear as:

Here's a backslash! \
The line as the player sees it, with one backslash.

The nomarkup Attribute

If you want to escape a longer run of text, or if you have many square brackets, escaping a single character at a time can be cumbersome. In these cases, you may want to escape an entire region of text, using the nomarkup attribute. This attribute makes the parser ignore any markup characters inside it.

If you want to include characters like [ and ], wrap them in the nomarkup attribute:

[nomarkup]Here's a big ol' [ bunch of ] characters, filled [[]] with square [[] brackets![/nomarkup]
Square brackets inside the nomarkup attribute.

This will appear as:

Here's a big ol' [ bunch of ] characters, filled [[]] with square [[] brackets!
The line as the player sees it, with every bracket shown.

The character Attribute

The character attribute is used to mark the part of the line that identifies the character that’s speaking.

Yarn Spinner will attempt to add this character for you, by looking for character names in lines that look like this:

CharacterA: Hello!
CharacterB: Oh, hi!
Two lines that start with character names.

The markup parser will mark everything from the start of the line up to the first : (and any trailing whitespace after it) with the character attribute. This attribute has a property, name, which contains the text from the start of the line up to the :. If a : isn’t present, or a character attribute has been added in markup, it won’t be added.

This means that the example above is treated the same as this:

[character name="CharacterA"]CharacterA: [/character]Hello!
[character name="CharacterB"]CharacterB: [/character]Oh hi!
The same two lines, with the character attribute written out.

You can use this to trim out the character names from lines in your game.

Text Replacement Markup

Certain attributes in Yarn Spinner’s markup are replacement markers, which Yarn Spinner uses to insert or replace text based on the value of a variable.

There are three built-in replacement markers:

  • The select marker uses the value of a variable to choose an outcome.
  • The plural marker uses the value of a number to decide on the plural class for that number.
  • The ordinal marker uses the value of a number to decide on the ordinal class for that number.

All three of these markers have a property called value, and use this to decide what text should be used in the line.

You can also make your own custom replacement markers.

select

The select marker is the simplest of the built-in replacement markers. It takes the value of the value property, and uses that to choose a replacement.

It’s useful when you need to insert a gendered pronoun in a line:

// In this example, the $gender variable is a string that
// contains either "m", "f", or "nb".

I think [select value={$gender} m="he" f="she" nb="they" /] will be there!

// Depending on the value of $gender, this line can appear
// as one of these possible options:
I think he will be there!

// or:
I think she will be there!

// or:
I think they will be there!
Choosing a pronoun from $gender with select.

plural and ordinal

The plural and ordinal markers take a number in its value property, and use that to determine the plural or ordinal number class of that value.

Plurals across different languages

Different languages have different rules for how numbers are pluralised.

In many languages, the term you use to refer to a thing depends on the the number of that thing. This is known as a plural class: in English, you can have one apple, but many apples, and you have have one mouse, but many mice.

However, the rules vary significantly across different languages. English has two: “single”, and “other”. However, for example, Polish has multiple.

  • In English, you say “one apple, two apples, five apples”.
  • In Polish, you say “jedno jabłko, dwa jabłka, pięć jabłek”.

Notice how the Polish word for “apple”, “jabłko”, takes multiple forms as the number changes, whereas it takes two forms in English.

In Yarn Spinner, individual lines are replaced depending on the user’s locale, but the logic surround them is not. This means that, if you want to be able to translate your game into multiple languages, you can’t write Yarn code like this:

<<if $apple_count == 1>>
    You have one apple!
<<else>>
    You have {$apple_count} apples!
<<endif>>
Pluralising apple with an if statement, which only suits languages with English plural rules.

If you did it this way, the logic would only work for languages that have the same rules for plurals as English. (There are several of them that do, but far more that don’t.)

Complicating this further, there are two main kinds of plural classes: cardinal plural classes, and ordinal plural classes.

  • Cardinal plural classes are the kind we just saw (for example, “one apple, two apples”).
  • Ordinal plural classes refer to the positioning of a thing; in English, ordinal numbers are things like “1st, 2nd, 3rd.”

As with cardinal plural classes, different languages have different ordinal plural classes.

Pluralising with plural and ordinal

Yarn Spinner can take a number and the user’s current locale, and determine the correct cardinal or ordinal plural class of that number, for that locale. You can then use the plural class to decide on what text to show.

plural and ordinal have a property called value, like select. They then have a property for each of the current locale’s plural classes. These can be:

  • one
  • two
  • few
  • many
  • other

The two markers differ based on what kind of plural class they work with:

  • plural selects a number’s cardinal plural class.
  • ordinal selects a number’s ordinal plural class.

Not every language uses every category; for example, English only uses “one” and “other” for cardinal plural classes.

For each of these properties, you provide the text that should appear.

For example:

PieMaker: Hey, look! [plural value={$pie_count} one="A pie" other="Some pies" /]!

// This will appear as either:
PieMaker: Hey, look! A pie!

// or: 
PieMaker: Hey, look! Some pies!
PieMaker’s line, using plural to choose between A pie and Some pies.

You can include the actual value in the resulting text by using the % character. This character will be replaced with the value provided to the value property:

PieMaker: I just baked [plural value={$pie_count} one="a pie" other="% pies" /]!

// This will appear as, for example:
PieMaker: I just baked a pie!"

// or:
PieMaker: I just baked 4 pies!"
Putting the value of $pie_count into the line with %.

The ordinal marker works similarly, but uses the ordinal plural class:

Runner: The race is over! I came in [ordinal value={$race_position} one="%st" two="%nd" few="%rd" other="%th" /] place!

// This will appear as, for example:
Runner: The race is over! I came in 1st place!

// or:
Runner: The race is over! I came in 23rd place!
The Runner’s finishing place, written with ordinal.

Using markers in your game

You can also use markup to trigger events in your game from Yarn Spinner Scripts. To learn about this, see the Inline Events Sample Guide.