All pages
Powered by GitBook
1 of 7

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Nodes, Lines, and Options

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.

Nodes

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.

Writing Nodes in Plain Text

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!
===

If you're using a graphical editor to write Yarn scripts, like Yarn Editor, it will handle this for you, and you can skip this section.

Node headers can contain any number of lines with the structure key: value. This can be used to store additional information, such as the location the conversation is taking place.

Node Content

Lines

Options

Options and Lines

Nested Options

upgrader script
Lines of dialogue running in Night in the Woods.

Writing in Yarn

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.

Editing with VS Code

Commands

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.

Built-in Commands

There are two built-in commands in Yarn Spinner: wait, and stop.

wait

The 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>>

stop

The 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 .

Making Your Own Commands

Creating Commands and Functions
// 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>>

Functions

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 .

Variables

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.

Type
Possible Values
Examples

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 .

Variables

// 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)}!

Built-In Functions

random()

random_range(number a, number b)

dice(number sides)

round(number n)

round_places(number n, number places)

floor(number n)

ceil(number n)

inc(number n)

dec(number n)

decimal(number n)

int(number n)

This is different to floor, because floor rounds to negative infinity.

Custom Functions

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.

# Defining Commands and Functions
commands
pure functions

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

Setting Variables

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.

Variables and Types

In earlier versions of Yarn Spinner, variables could also be null, which represented "no value". Starting with Yarn Spinner 2.0, variables are never null. All variables are required to have a value.

Variables and Expressions

Yarn Spinner provides built-in functions for converting between certain types:

  • The string function converts values of any type into a string.

  • The number function converts values of any type into a number (if it can be interpreted as one.)

  • The bool function converts values of any type into a boolean value (if it can be interpreted as one.)

Using Variables in Lines

Variables and Storage

Variable Storage
<<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

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

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:

ordinal class
for that number.

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/] B
    Here'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!

    Overlapping Attributes

    Self-closing Attributes

    The Close-All Marker

    Properties

    Short-hand Properties

    Property Types

    Whitespace Trimming

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

    Showing Special Characters to the Player

    Escaping single [ and ] characters

    If you need to show a blackslash in your text, use two blackslashes:

    This will appear as:

    The nomarkup Attribute

    The character Attribute

    Text Replacement Markers

    select

    plural and ordinal

    Plurals across different languages

    Pluralising with plural and ordinal

    A [wave trimwhitespace=false/] B 
    // (produces "A  B")
    Here's a backslash! \\
    Here's a backslash! \

    Flow Control

    if statements

    In 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.

    elseif and else

    The expression used in an if and elseif statement must result in a boolean value (that is, true or false.) For exame,<<if 1>> isn't allowed, but <<if 1 == 1>> is.

    Conditional Options

    Yarn Spinner always delivers every option in an option group to the game; it's up to the game to decide what to do with options that are marked as unavailable.

    For example, an unavailable option might be shown to the user, but not selectable, so that the user can see that they could have been able to say that if circumstances had been different.

    nodes
    lines
    options
    variables
    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?