Learn about using node groups, which allow Yarn Spinner to choose which content to run, depending on conditions.
In Yarn Spinner, you can also create node groups. A node group is collection of nodes that share the same name that Yarn Spinner will choose from.
To create a node group, you create multiple nodes that all share the same name, and ensure that each of the nodes have at least one when: header.
The when:header tells Yarn Spinner about the conditions that must be met in order to run the node:
title: Guard
when: once
---
Guard: You there, traveller!
Player: Who, me?
Guard: Yes! Stay off the roads after dark!
===
title: Guard
when: always
---
Guard: I hear the king has a new advisor.
===
title: Guard
when: $has_sword
---
Guard: No weapons allowed in the city!
===
Node groups are combined into a single node that performs the appropriate checks and then runs one of the node group’s members. You start dialogue with a node group using its name. You can also use the jump or detour statements to run a node group from somewhere else in your Yarn scripts.
Node groups will be visualised in a box of their own in the Graph View of Yarn Spinner for Visual Studio Code:
You can add as many when: headers to a node as you want.

Dive into the Advanced features of Yarn Spinner Scripting.
If you're here, you've worked through the Beginner's Guide, setup the Yarn Spinner Editor, and learned the Scripting Fundamentals of Yarn Spinner.
Now it's time to look at some more advanced features, including:
Node Groups, Storylets, and Saliency, for complex, responsive storytelling with Yarn Spinner
Tags and Metadata, to give you flexibility on how your lines are handled in a game engine
Markup, for providing hints on how narrative text should be displayed, as well as running commands in a game engine within lines
Shadow Lines, for marking when a line is an identical duplicate of another line
Writing Together, using the Live Share Extension for Visual Studio Code.
Once you've completed it, you're ready to use Yarn Spinner with a game engine, such as
Learn about reusing the same line in multiple places, using shadow lines.
In Yarn Spinner Scripts, shadow lines let you reuse the same line in multiple places, without having to create duplicate copies.
Shadow lines are marked using the #shadow: hashtag. When you use the #shadow: tag, you specify the line ID of another line, which is called the source line. The source line must have an explicit #line: hashtag to identify it.
Here’s a simple example of using shadow lines:
title: Tavern
---
Ava: Hello, barkeep!
Guy: Hi there, how can I help?
Ava: I should go. #line:departure
===
title: Kitchen
---
Ava: Greetings, chef!
Guy: What are you doing back here?
Ava: I should go. #shadow:departure
===The script contains six lines, but only 5 string table entries will be created, because the line “I should go” is shadowed.
Shadow lines are required to have the same text in the Yarn script as their source line, but are allowed to have different hashtags (in addition to the #shadow: and #line: hashtags).
Learn about saliency and saliency strategies, which let you control how line groups and node groups select which content to run.
In Yarn Spinner, saliency lets you control how line groups and node groups select which content to run.
We recommend you read the before reading this page.
When a line group or node group needs to run content, it needs to make a decision about which item in the group to choose. The method for making this decision is called a saliency strategy.
Saliency strategies are provided with the following information about each item:
How many of its conditions passed (that is, the when: clauses on a node group, or the single condition on a line group)
How many of its conditions failed
The total complexity of all of its conditions:
The always condition has a complexity of zero.
Otherwise, the following values are added together:
A unique key that identifies the content.
You can either use one of Yarn Spinner's built-in saliency strategies, or create your own custom saliency strategy.
First: The first item in the group that has not failed any of its conditions is selected.
If the items of a node group are all in the same file, the ordering of the group is the order in which they appear in the file. If a node group’s nodes are split up across more than one file, the ordering of the nodes is not defined.
Best: The items that have not failed any conditions are sorted by their total complexity score, and the first item that has the highest score is selected.
If you don't set the saliency strategy anywhere yourself, the default will be Random Best Least Recently Viewed.
A saliency strategy is given a collection of possible options, and returns either one of them that should be run, or null to indicate that none of them should run.
When using Try Yarn Spinner, you can set the saliency strategy by calling one of the following built-in commands:
When using Visual Studio Code to Preview your dialouge, you can change the active saliency strategy in the drop-down menu at the top of the Preview view:
Your C# code can create custom saliency strategies. To do so, create a type that implements the IContentSaliencyStrategy interface, and assign it to your Dialogue object’s ContentSaliencyStrategy property.
IContentSaliencyStrategy has two required methods.
ContentSaliencyOption? QueryBestContent(IEnumerable<ContentSaliencyOption> content) determines which of a collection of options, if any, should run. It should return the best content from the available options, or null if none of them should run. This is the main method in which you write the specific logic for your custom strategy.
Calling this method does not indicate that the content has been selected; rather, it is a query to determine what should be selected. Your implementation of this method should not change any state, and should be read-only. The content returned by this method is not guaranteed to actually be run.
You can use a node group to check to see if any of its items can run, This can be useful when determining whether to show if a character should be marked as ready to talk, or whether any of its nodes have a special tag (for example, if a character has important information to discuss, as opposed to more general conversation.)
Learn the principles behind our storylets and saliency features.
When you do things right, people won't be sure you've done anything at all. -
Storylets and saliency represent an evolution in interactive storytelling techniques. To understand their significance, let's examine how narrative approaches have developed over time.
The earliest approach to storytelling was linear. Stories followed a single, author-defined path with each moment crafted to lead directly to the next.
The next evolution introduced branching, allowing stories to have multiple paths for players to explore.
Branching narratives offer remarkable flexibility. Some branches might be extensive with significant impact, while others could be minor, adding subtle flavor. Some paths might terminate, while others reconnect with the main storyline. Despite this flexibility, each step remains author-crafted, with branches fixed in the writer's intended order.
Storylets represent the next step in this evolution. They break the rigid connections between narrative elements, creating a more dynamic flow. Theoretically, a story could move from any storylet to any other storylet, creating a potential connection from every block to every other block.
Learn about tags and metadata, for adding additional context to lines in Yarn Spinner Scripts
A tag is a piece of information that you can add to content in Yarn Spinner that adds additional context or detail about that content.
There are two places you can add tags in Yarn scripts: you can add them to nodes, and you can add them to lines.
Tags aren't shown to the user; instead, they're used by your game, or by Yarn Spinner itself.
Tags can be added to the end of lines and options. Tags on lines start with a hash symbol (#), and cannot contain spaces. You can add as many tags as you like to line, but they must all be on the same line in the script.
Here's an example of a line with two tags:
Tags that you add to a line can be accessed from your game. The way that you access them depends on your game engine. For example, to access them in a Unity game, you use the LocalizedLine.Metadata property.
Some tags are used by Yarn Spinner itself, while all others are used by your own code, so it's up to you what content they should have, and how to handle them.
onceIf the condition has an expression, add the the total number of boolean operators (and, or, not, xor) present, plus 1.
Random Best Least Recently Viewed: The items that have not failed any conditions are sorted by how many times they have been selected by this strategy, and then by score. If there is more than one best item remaining, a random one of these is selected.
void ContentWasSelected(ContentSaliencyOption content) is called to indicate that a specific piece of content returned by a previous call to QueryBestContent has been selected. This method should update any appropriate state to represent this fact, such as by updating the total number of times the content has been selected.You can only change the saliency strategy in Try Yarn Spinner and when using Yarn Spinner in a game engine, like Unity.

Certain tags are used internally by Yarn Spinner, or are added for you if they don't exist.
The Yarn Spinner compiler adds a #lastline tag to every line that comes just before a set of options.
For example, the following excerpt:
is treated as though it had been written as:
In a Unity game, you can use this tag in a custom Dialogue View to be notified ahead of time when the player is about to be shown options.
The #line tag uniquely identifies a single line or option across all of your game's dialogue. This is used to identify lines for localisation. Every line's #line tag must be unique. If a line or option doesn't have a #line tag, it will be automatically added for you.
Here's an example of some Yarn script with #line tags:
For more details (including what the tag should look like), see Adding Line IDs.
Nodes can also have tags, which you can use to add labels that describe the node.
Node tags they work a bit differently than line tags: they are defined in the header with the tags key, and they don't have to begin with a hash symbol (#).
Here's an example of a node with two tags:
You can access the tags on a node via the Dialogue object's GetTagsForNode method.
The metadata of a line is only composed of tags. Because of this, you may find that the Yarn Spinner code and documentation refer to line tags and line metadata interchangeably.
Nodes can have other metadata in their headers. This metadata isn't exposed through the API, which means it's mostly used to store additional information for whoever is writing the Yarn dialogue or for editors to make use of.
However, currently there is one header that defines specific behavior within the Yarn Spinner compiler: the tracking header.
Nodes can track whether they have already been visited during the game. For this to work, the Yarn Spinner compiler needs to add some special code to the node. To avoid creating this code for nodes that don't need it, the compiler only adds this code if it finds a call to the visited() function with the node name in it.
In some cases, you may need the compiler to add this special code to a node even if no corresponding visited() call exists. To direct the compiler to do this, include the tracking header with the value of always:
Additionally, using a value of never instructs the compiler to never add this special code to the node. If you use the visited function with a node set to never use tracking, it will always return false.
For more information on visit tracking, see the documentation for Functions.
Tags and metadata may seem very complicated at first, and their uses may not be clear. The following example use cases explain how they can be used in your game. Keep in mind that this is not an exhaustive list of use cases.
Yarn provides markup to let you change attributes for specific parts of a line. In case most of your attributes apply to entire lines (for example, the color of a line), it may be easier to just use tags instead.
The #lastline tag can be used to display the last line of dialogue along with any options. This is handled within your code by checking if a line has the #lastline tag, and if it does, storing it before continuing with the execution of the Yarn dialogue.
Since metadata isn't shown directly to the player, you can use metadata for any internal workflows or tooling. For example, instead of tracking lines that need to be revised outside the Yarn files (which could lead to syncing problems), you could add line tags (such as #needsrevision) to the appropriate lines directly in the Yarn files, and process these lines as part of an internal tool or workflow. The Unity integration automatically generates a CSV file with all lines that contain metadata, making this super easy!
As referenced before, the Yarn Spinner integration for Unity uses line tags to link localised dialogue lines. This is better explained in the Localization and Assets section, when using Yarn Spinner for Unity.
Aside from that, every piece of metadata can be used by translators and adapters to help them understand how the text is being used, thus leading to better localised text.
Some games may require that certain lines of dialogue are displayed somewhere other than the dialogue window (for example, as flavor text for an item description, or in an item that acts as a log). Instead of manually duplicating these lines (which adds overhead during development and localisation), tags can be used along with code that checks for the tags and duplicates the lines while the game is running.
<<set_saliency first>>
<<set_saliency random>>
<<set_saliency best>>
<<set_saliency best_least_recent>>
<<set_saliency random_best_least_recent>>Homer: Hi, I'd like to order a tire balancing. #tone:sarcastic #duplicateHello there.
-> Hi!
-> What's up?Hello there. #lastline
-> Hi!
-> What's up?Mechanic: You're in orbit of Jupiter, at a rest station along the main tourism lines. There's a meteorite headed towards here that'll completely destroy this station in three days. #line:4c49c5
Mechanic: And you're a wayfinding robot bolted to the floor of said Jupiter Tourist Station. #line:5b6256
-> Bolted to the floor?! #line:f65d07
Mechanic: Yeah, like all tourist helper bots. #line:1b159b
-> Three days?! #line:40eaf7
Mechanic: More or less. I wouldn't make any long-term plans. #line:3a6c94title: Train_Dialogue
tags: #camera2 background:conductor_cabin
---
Why did you stop the train?
Now we won't arrive in time at the next stop!
===title: Node_Name
tracking: always
---
I know how many times you've been here.
===If narrative chunks are disconnected, how do they form a coherent experience? This is where saliency comes in—it's the mechanism that links story pieces together.
Saliency determines which storylet is most relevant (or "salient") at any given moment. Instead of an author-defined sequence, saliency selects the ordering dynamically. For example, if you have two storylets—one about entering any room in an apartment, and another specifically about entering the bedroom—when the player is in the bedroom, the more specific storylet would be more salient.
Interestingly, linear and branching narratives can be viewed as salient stories composed of storylets, where the most salient storylet is defined by the author's explicit connections. This perspective highlights a major strength of storylets: they can incorporate and blend previous structural approaches. This gives you precise control when needed while maintaining flexibility for dynamic narrative progression.
The storylet is the fundamental unit of this narrative system, but how large or small should a storylet be? The answer depends on your specific narrative needs.
Storylets typically exist at three levels of granularity:
Collection Level: The largest unit—a vignette, conversation, or paragraph. At this level, your story assembles by connecting self-contained moments. These moments generally function independently, so their precise order may be flexible, or they might be designed to flow naturally with a subset of other moments.
Line Level: Here, a storylet represents a single line of dialogue. Conversations build by assembling individual lines, which then form larger narrative moments. This approach is particularly effective for creating dynamic NPC barks in games.
Sub-Line Level: The smallest unit, where storylets are fragments within a single line. These pieces combine to form complete lines of dialogue, which then assemble into conversations.
Many games blend these approaches, often mixing storylet techniques with traditional linear or branching content. Rather than focusing exclusively on storylet size, consider what type of narrative experience you want to create and determine what level of storylet granularity will best support that vision.
How do we determine which storylet is "best" to present next? The approach varies based on your narrative goals.
The most common approach uses conditions on each storylet—boolean expressions like "are we in the bedroom?" or "does the player have more than 25 gold coins?" These conditions filter available storylets and help select among the remaining options. When multiple storylets are valid, you select the one with the highest "quality"—typically the one that satisfies the most conditions.
Another approach tags storylets with various attributes. When selecting the next storylet, you filter based on relevant tags. The filtering criteria might come directly from player choices or from systems guiding the narrative.
Some approaches aim to guide the narrative toward specific outcomes:
Pathfinding: Storylets exist on a graph, and the system attempts to progress from the current storylet toward a specific destination, influenced by player choices along the way.
Drama Management: A system with narrative goals selects storylets to work toward those goals. For example, Façade selects storylets to maximize conversational drama. Pathfinding can be viewed as drama management where the goal is reaching a specific point in the narrative graph.
Two less complex but still useful approaches include:
Player Selection: Present all available storylets and let the player choose.
Random Selection: Choose randomly from available storylets.
These methods often incorporate knockout or deprioritization systems to prevent repetition. They're also effective for resolving ambiguity when multiple storylets have equal saliency.
Storylets serve various narrative functions in games:
Perhaps the most common use is creating contextual NPC comments. Skyrim's infamous "arrow to the knee" line exemplifies this—triggered when the player has cleared a dungeon, a condition most players eventually satisfy.
Storylets create specific moments that add life to the game world without connecting directly to the main plot. Mass Effect's elevator conversations, filtered based on your current squad members, demonstrate this approach.
Storylets can create highly specific dialogue responding to gameplay moments, making NPCs seem more aware and reactive. Left 4 Dead's combat and downtime barks showcase this, as do Ellie's contextual reactions in The Last of Us.
In games without predetermined stories, storylets create meaningful moments and side-narratives. Civilization VII uses storylets for historical and alternative historical events, triggered by factors like civilization type, leaders, and current player actions.
Database-driven games use storylets to let players explore narrative space freely. Her Story exemplifies this approach, with self-contained story chunks that both stand alone and contribute to an overall narrative.
Some games build entire narratives from storylets. Mask of a Rose and Wildermyth assemble stories entirely from storylets based on player actions, allowing players to create their own unique narratives.
Yarn Spinner supports two primary levels of storylet granularity: line-based and node-based. Both integrate seamlessly with traditional branching and linear Yarn scripts.
Line Groups implement line-level storylets. They visually resemble option groups but use => instead of ->. Each line within a group represents a potential storylet, but only one will be selected.
The dialogue system receives the Barry line, then one selected line from Alice. The player might see:
The system doesn't indicate that the Alice line came from a storylet selection—it's simply presented as the next line of dialogue.
We can add conditions to modify selection:
Assuming high Barry suspicion and knowledge that he's a cop, the dialogue might present:
The final line is selected as the most salient option, even though multiple options satisfy their conditions.
Like option groups, line groups support nested content that only appears if that specific line is chosen:
Any Yarn dialogue or commands can be nested, including other storylets, jumps, and detours.
Node groups allow larger storylet chunks to be associated. They look like standard nodes but require a when header:
When <<jump Alice>> executes, it jumps to the most salient node in the "Alice" group. If Barry is highly suspicious and Alice knows he's a cop, the system selects the last node.
For this simple example, node groups require more writing than line groups for the same effect. However, for larger conversations with significant variability, node groups become more advantageous.
Like line groups, node groups can contain any valid Yarn content, including jumps, detours, and line groups.
The dialogue runner consults a saliency strategy when presenting a storylet, whether from a line group or node group. While you can create custom strategies to implement any approach, Yarn Spinner provides several built-in quality-based strategies:
Best (select the most salient)
Best Least Recently Viewed (prioritize salient content that hasn't been seen recently)
Random Best Least Recently Viewed (like above, with some randomization)
Random (completely random selection)
All built-in strategies first filter out storylets with failing conditions, though custom strategies can include failing conditions if desired.
The recommended default is Random Best Least Recently Viewed, which balances selection of the highest-saliency content while preventing repetition.




Barry: Oh is that so?
=> Alice: Yep.
=> Alice: Of course it is!
=> Alice: Why would you think otherwise?Barry: Oh is that so?
Alice: Of course it is!Barry: Oh is that so?
=> Alice: Yep.
=> Alice: Of course it is! <<if $barry_suspicion > 3>>
=> Alice: Why would you think otherwise? <<if $barry_suspicion > 5>>
=> Alice: I am not talking without my lawyer <<if $barry_suspicion > 5 && $knows_barry_is_cop>>Barry: Oh is that so?
Alice: I am not talking without my lawyerBarry: Oh is that so?
=> Alice: Yep.
Barry: lol lmao, thanks nerd.
=> Alice: Of course it is! <<if $barry_suspicion > 3>>
=> Alice: Why would you think otherwise? <<if $barry_suspicion > 5>>
=> Alice: I am not talking without my lawyer <<if $barry_suspicion > 5 && $knows_barry_is_cop>>
Barry: Why would you need a lawyer?
Alice: *cool silence*title: Barry
---
Barry: Oh is that so?
<<jump Alice>>
===
title: Alice
when: always
---
Alice: Yep.
Barry: lol lmao, thanks nerd.
===
title: Alice
when: $barry_suspicion > 3
---
Alice: Of course it is!
===
title: Alice
when: $barry_suspicion > 5
---
Alice: Why would you think otherwise?
===
title: Alice
when: $barry_suspicion > 5
when: $knows_barry_is_cop
---
Alice: I am not talking without my lawyer
Barry: Why would you need a lawyer?
Alice: *cool silence*
===




Markup lets you add attributes to text that is delivered in lines.
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 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 .
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:
You can also use markup to trigger events in your game from Yarn Spinner Scripts. To learn about this, check out the .
manyother
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! \