In Yarn Spinner, all of your dialogue is stored in .yarn files. Yarn files are just plain text files, which you can edit in any text editor.
Yarn Spinner files contain nodes. Nodes are where you put your dialogue. You can have as many nodes as you link in a file. Nodes are used to separate out parts of the story, and make it easier to manage longer stories and branching.
Each node has, at the very minimum, a collection of headers, and a body. All nodes have at least one header, which is the title. The title is the name of the node, and the body contains the Yarn script that contains your game's dialogue.
The title of a node is important, because your game uses node titles to tell Yarn Spinner which node to start running. You also use the title of a node when you want to jump to another node.
Node titles are not shown to the player.
Node titles must start with a letter, and can contain letters, numbers and underscores.
So FirstNode, First_Node and Node1 valid, but First Node and 1stNode are not.
Node names cannot contain a . (period).Node names were able to contain a period in Yarn Spinner 1, and if your Yarn Spinner 1 .yarn scripts have periods in the node names, then the will translate them (and all jumps and options related) to use a _ (underscore) instead.
If you're using a text editor to write Yarn scripts, you'll need to write the node's header.
The plain-text version of a Yarn node looks like this:
In this example, the node's title is Node_Title, which is set on the first line in the title header. You can also add any other headers that you want.
The --- marker indicates where the body begins. After this point, you can put all of your Yarn script.
The === marker indicates where the node ends; after this point, you can begin another node.
The body of a node is made up of three different kinds of content: lines, commands, and options.
When you write Yarn Spinner dialogue, just about every line of text that you write in a node is a line. When a node is run, it runs each line, one at a time, and sends it to your game.
A line of dialogue is just the thing you want some entity or character to say, usually beginning with the name of the entity speaking.
For example, consider the following Yarn code from Night in the Woods:
When this code is run in the game, it looks like this:
Yarn Spinner sends each of these lines, one at a time, to the game. The game is responsible for taking the text, and presenting it to the player; in the case of Night in the Woods, this means drawing the speech bubble, animating each letter in, and waiting for the user to press a key to advance to the next line.
Lines of dialogue can contain just about any text, except for some special characters that Yarn Spinner uses to add extra information to a line.
If there is a set of characters without spaces before a colon (:) at the beginning of the line, Yarn Spinner will mark that as the name of the character. This information will then be passed to your game, so that you can change the way that lines are shown based on the character who's saying them. For example:
When you want to let the player decide what to say, you use an option. Options let you show multiple potential lines of dialogue to the player, and let the player select one.
Options are marked with a -> symbol. You write as many options as you'd like the player to see, and the player chooses one of them. The content of the option is like any other line of dialogue.
For example, consider the following code:
In this example, the line "Hi there! What do you feel like doing today?" will run. The player will then be given the choice to say either "I want to go swimming", or "I'd prefer to go hiking".
Shortcut options can have their own lines, which are run when the option is selected. If a different option is selected, they won't run. To write this, indent the lines that belong to a shortcut option.
In the following code, different lines will run based on which of the two shortcut options are selected.
This script will start with the line, "Hi there! What do you feel like doing today?". The player then has the choice of saying either "I want to go swimming", or "I'd prefer to go hiking". Depending on their choice, either the line "Okay, let's go swimming" or "Cool, we'll go hiking then". Finally, no matter what was selected, the line "Sounds good!" will run.
In addition to containing lines, options can also contain other options.
You can nest options as much as you like. However, this can get a bit challenging to read. It's often a good idea to use the <<jump>> command to jump to a different node:
Separating dialogue segments into nodes can for neater files that are easier to edit as they grow.
Sometimes it makes sense for the options presented or the outcomes of selecting different options to vary based on other things the player has done or said up until this point. This requires the use of logic and variables, which we'll discuss in the next section.
title: Node_Title
---
Here are some lines!
Wow!
===Mae: Well, this is great.
Mae: I mean I didn't expect a party or anything
Mae: but I figured *someone* would be here.
Mae: ...
Mae: Welcome home, Mae.This is a line of dialogue, without a character name.
Speaker: This is another line of dialogue said by a character called "Speaker".Companion: Hi there! What do you feel like doing today?
-> Player: I want to go swimming.
-> Player: I'd prefer to go hiking.Companion: Hi there! What do you feel like doing today?
-> Player: I want to go swimming.
Companion: Okay, let's go swimming.
-> Player: I'd prefer to go hiking.
Companion: Cool, we'll go hiking then.
Player: Sounds good!Companion: Hi there! What do you feel like doing today?
-> Player: I want to go swimming.
Companion: Okay, let's go swimming.
Companion: Where do you want to swim?
-> Player: The lake!
Companion: Nice! It's a great day for it.
-> Player: The swimming pool!
Companion: Oh, awesome! I heard they installed a new slide.
-> Player: I'd prefer to go hiking.
Companion: Cool, we'll go hiking then.
Player: Sounds good!title: Start
---
Companion: Hi there! What do you feel like doing today?
-> Player: I want to go swimming.
Companion: Okay, let's go swimming.
Companion: Where do you want to swim?
-> Player: The lake!
Companion: Nice! It's a great day for it.
-> Player: The swimming pool!
Companion: Oh, awesome! I heard they installed a new slide.
-> Player: I'd prefer to go hiking.
Companion: Cool, we'll go hiking then.
Player: Sounds good!
===title: Start
---
Companion: Hi there! What do you feel like doing today?
-> Player: I want to go swimming.
Companion: Okay, let's go swimming.
<<jump Swimming>>
-> Player: I'd prefer to go hiking.
Companion: Cool, we'll go hiking then.
<<jump Hiking>>
===
title: Swimming
---
Companion: Where do you want to swim?
-> Player: The lake!
Companion: Nice! It's a great day for it.
-> Player: The swimming pool!
Companion: Oh, awesome! I heard they installed a new slide.
<<jump Done>>
===
title: Hiking
---
Companion: Have you got your hiking boots ready?
-> Player: Yes.
Companion: Great, let's go!
-> Player: No.
Companion: We can swing by your place and pick them up!
<<jump Done>>
===
title: Done
---
Player: Sounds good!
===
Yarn Spinner is a tool for writers. In this section, you'll the syntax of Yarn, how to write Yarn scripts for use in your game. You'll also learn how to use the various tools that are available for creating your content.
You'll need an editor before you can write Yarn scripts, so we recommend checking out before going too far.
In Yarn Spinner, you can send instructions to your game through commands. Commands look like this:
<<wait 2>>
<<setsprite ShipName happy>>
<<fade_out 1.5>>Commands are sent to your game's Dialogue Runner, just like lines and options are. Commands are not shown to the player directly; instead, they're used for things like stage directions.
Yarn Spinner comes with some built-in commands; however, to get the most usefulness out of them, you'll want to define your own custom commands that make your game do what you need to.
There are two built-in commands in Yarn Spinner: wait, and stop.
waitThe wait command pauses the dialogue for a specified number of seconds, and then resumes. You can use integers (whole numbers), or decimals.
// Wait for 2 seconds
<<wait 2>>
// Wait for half a second
<<wait 0.5>>stopThe stop command immediately ends the dialogue, as though the game had reached the end of a node. Use this if you need to leave a conversation in the middle of an if statement, or a shortcut option.
You can create your own commands, so that your scripts can . For more information on how to create them in Unity games, see .
// Leave the dialogue now
<<stop>>
// Leave the dialogue if we don't have enough money
<<if $money < 50>>
Shopkeeper: You can't afford my pies!
<<stop>>
<<endif>>A function is a block of code that provides a value to your Yarn scripts, which you can use in if statements, or store in variables.
In Yarn Spinner scripts, functions perform two main kinds of task:
Functions let you get values that change over time, or that depend on other values. For example, the random function returns a different random number every time you call it.
Functions let you get data from your game back into your scripts.
You call a function inside an expression. For example:
Yarn Spinner comes with several built-in functions for you to use.
random returns a random number between 0 and 1 each time you call it.
random_range returns a random integer between a and b, inclusive.
dice returns a random integer between 1 and sides, inclusive.
For example, dice(6) returns a number between 1 and 6, just like rolling a six-sided die.
round rounds n to the nearest integer.
round_places rounds n to the nearest number with places decimal points.
floor rounds n down to the nearest integer, towards negative infinity.
ceil rounds n up to the nearest integer, towards positive infinity.
inc rounds n up to the nearest integer. If n is already an integer, inc returns n+1.
inc rounds n down to the nearest integer. If n is already an integer, inc returns n-1.
decimal returns the decimal portion of n. This will always be a number between 0 and 1. For example, decimal(4.51) will return 0.51.
int rounds n down to the nearest integer, towards zero.
You can define your own custom functions in Yarn Spinner. For more information, see .
The Yarn language is a full programming language, which means it has support for writing code that let you control how the dialogue in your game works. In this section, you'll learn how to use variables to control your dialogue.
Variables store information. Variables can store one of three types of information: numbers, strings, and booleans.
Every variable has a name. In Yarn Spinner, all variable names start with a dollar sign ($).
You put information into a variable by using the <<set>> command. For example, the following code puts a string, "Hello, Yarn!", into a variable called $greeting:
Each variable can only store one type of value. Variables can change their value at any time, but they can never change their type.
For example, the following code will work:
This works because while the value of each of the variable changes, the type doesn't. However, the following code will not work:
You can work with the values inside variables. For example, numbers can be multiplied, strings can be added together, and boolean values can have logical operations (like and and or) applied to them. When values are used together like this, it's called an expression.
An expression needs to be a single type. You can't work with values of different types in a single expression. For example, the following code will not work:
To show the contents of a variable, you put it inside braces ({ }) inside a line. The value of that variable will appear in its place.
For example:
Yarn Spinner doesn’t manage the storage of information in variables itself. Instead, your game provides a variable storage object to Yarn Spinner before you start running dialogue.
When Yarn Spinner needs to know the value of a variable, it will ask the variable storage object you’ve given it. When Yarn Spinner wants to set the value of a variable, it will provide the value and the name of the variable. In this way, your game has control over how data is stored.
The specifics of how variables need to be stored will vary depending on what game engine you're using Yarn Spinner in. To learn more about variable storage in Unity, see .
// Inside an if statement:
<<if dice(6) == 6>>
You rolled a six!
<<endif>>
// Inside a line:
Gambler: My lucky number is {random_range(1,10)}!Functions are not intended to be a way for you to send instructions to your game. For that purpose, you should use .
In particular, functions are not guaranteed to be called in the same order as they appear in your code, or even be called at all if Yarn Spinner believes the result can be cached. As much as possible, custom functions should be , and have no side effects besides returning a value based on parameters.
Number
Any whole or decimal number
1, 2.5, 3468900, -500
String
Any sequence of letters, numbers and other characters, enclosed in quotes.
"Hello", "✓", "A whole sentence."
Boolean
Either the value true or the value false.
true, false
As with node titles, variable names must not contain spaces. They must be made up of only letters, numbers and underscores, and the first character must be a letter.
<<set $greeting to "Hello, Yarn!">>// Set some initial values in some variables
<<set $myCoolNumber to 7>>
<<set $myFantasticString to "wow, text!">>
// Now change them!
<<set $myCoolNumber to 8>>
<<set $myFantasticString to "incredible!">>// Set some initial values in some variables
<<set $myCoolNumber to 7>>
<<set $myFantasticString to "wow, text!">>
// This will NOT work, because you can't change types!
<<set $myCoolNumber to "8">>
<<set $myFantasticString to 42>><<set $variableName to "a string value">><<set $numberOfSidesInATriangle = 2 + 1>>
<<set $numberOfSidesInASquare = $numberOfSidesInATriangle + 1>>// This will NOT work, because you can't add a string and a number:
<<set $broken = "hello" + 1>><<set $variableName to "a string value">>
The value of variableName is {$variableName}.The value of variableName is a string value.Markup allows you to 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.
Attributes apply to ranges of text:
Oh, [wave]hello[/wave] there!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!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].
Attributes can overlap:
You can put multiple attributes inside each other. For example:
You can close an attribute in any order you like. For example, this has the same meaning as the previous example:
Attributes can self-close:
A self-closing attribute has a length of zero.
The marker [/] is the close-all marker. It closes all currently open attributes. For example:
Attributes can have properties:
This attribute 'wave' has a property called 'size', which has an integer value of 2.
Attributes can have short-hand properies, like so:
This is the same as saying this:
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.
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:
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":
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.
If you need to escape a single square bracket character, put a backslash \ in front of it:
This will appear to the player as:
The backslash will not appear in the text.
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:
This will appear as:
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:
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:
You can use this to trim out the character names from lines in your game.
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
All three of these markers have a property called value, and use this to decide what text should be used in the line.
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 especially useful for when you need to insert a gendered pronoun in a line:
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.
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 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.
Yarn Spinner is able to 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, just like select. They then have a property for each of the current locale's plural classes. These can be:
one
two
few
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:
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:
The ordinal marker works similarly, but uses the ordinal plural class:
many
other
Oh, [wave]hello [bounce]there![/bounce][/wave]Oh, [wave]hello [bounce]there![/wave][/bounce][wave/][wave][bounce]Hello![/][wave size=2]Wavy![/wave][wave=2]Wavy![/wave][wave wave=2]Wavy![/wave][mood=angry]Grr![/mood]
[mood="angry"]Grr![/mood]A [wave/] BHere's some square brackets, just for you: \[ \]Here's some square brackets, just for you: [ ][nomarkup]Here's a big ol' [ bunch of ] characters, filled [[]] with square [[] brackets![/nomarkup]Here's a big ol' [ bunch of ] characters, filled [[]] with square [[] brackets!CharacterA: Hello!
CharacterB: Oh, hi![character name="CharacterA"]CharacterA: [/character]Hello!
[character name="CharacterB"]CharacterB: [/character]Oh hi!// 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!<<if $apple_count == 1>>
You have one apple!
<<else>>
You have {$apple_count} apples!
<<endif>>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: 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!"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!A [wave trimwhitespace=false/] B
// (produces "A B")Here's a backslash! \\Here's a backslash! \if statementsIn addition to storing information, variables are useful for controlling what's shown to the player. To do this, you use if statements.
An if statement allows you to control whether a collection of content is shown or not. When you write an if statement, you provide an expression, which is checked; if that expression evaluates to a "true" value, then all of the content in between the <<if>> and <<endif>> statements are run.
For example, consider the following code:
<<set $gold_amount to 5>>
Player: I'd like to buy a pie!
<<if $gold_amount < 10>>
Baker: Well, you can't afford one!
<<endif>>This example will set a variable, $gold_amount, to 5. It will then show the line "I'd like to buy a pie!", and before it continues, it will check to see if $gold_amount is less than 10. If that's the case (which it will be!), the line "Well, you can't afford one!" will run.
You can use the elseif and else statements to handle different situations in an if statement.
An elseif statement has an expression that gets checked if the if statement, or any previous elseif statements, don't run.
An else statement doesn't have an expression, and runs
For example:
This script will show different lines depending on the value of $gold_amount. The checks are done from top to bottom, which means that in order for an elseif or else to run, all of the checks above it have to have failed.
If it's less than 10, the line "Well, you can't afford one!" will run.
Otherwise, if it's less than 15, the line "You can almost afford one!" will run.
Otherwise, the line "Here you go!" will run.
When presenting options to the player, you may want to make some options not available. You can do this by adding a condition to the option.
For example, if you have a variable that tracks your player's "reputation points", called $reputation, you might want to make certain options only available if the value of $reputation is high enough.
Conditions on options are done by adding an if statement to the end of the option. They look like this:
When Yarn Spinner runs this collection of options, it will check the expression inside the if statement. If the expression is false, then the option will be marked as unavailable.
Now that you know how to work with , , and , there's one last part of the Yarn language to learn about: commands.
Player: I'd like to buy a pie!
<<if $gold_amount < 10>>
Baker: Well, you can't afford one!
<<elseif $gold_amount < 15>>
Baker: You can almost afford one!
<<else>>
Baker: Here you go!
<<endif>>Guard: You're not allowed in!
-> Sure I am! The boss knows me! <<if $reputation > 10>>
-> Please?