Commands

A Command is a line in a Yarn Script that tells your game to do something. It’s written inside << and >>, with the Command’s name first and any arguments after it:

title: CommandsExample
---
<<play_sound door_creak>>
Rosa: Oh! You gave me a fright.
<<move Rosa 3 0>>
<<wait 1>>
Rosa: Here, you'll need this.
<<give_item "brass key" 1>>
===
Three Commands in a node. The first word inside each is the Command’s name, and the rest are its arguments.

When the dialogue reaches a Command, the Dialogue Runner calls the C# method you’ve connected to it. Once the method has finished, the dialogue carries on.

sequenceDiagram
  participant R as Dialogue Runner
  participant A as Audio code
  participant Rosa as Rosa (Character.cs)
  Note over R: #60;#60;play_sound door_creak#62;#62;
  R->>A: PlaySound("door_creak")
  A-->>R: returns
  Note over R: Shows "Oh! You gave me a fright."
  Note over R: #60;#60;move Rosa 3 0#62;#62;
  R->>Rosa: Move(3, 0)
  Rosa-->>R: returns a YarnTask
  Note over Rosa: Rosa moves for 1 second
  Rosa-->>R: the task finishes
  Note over R: Carries on with #60;#60;wait 1#62;#62;
The first two Commands from the node above. The Dialogue Runner calls a method for each one. The Move method returns a YarnTask, so the dialogue waits until Rosa has finished moving.

Writing a Command

The quickest way to make a Command is to add the [YarnCommand] attribute to a method. Give the attribute the Command’s name in Yarn, so [YarnCommand("play_sound")] is <<play_sound>>. If you leave the name out, the method’s name is used: [YarnCommand] on a method called PlaySound is <<PlaySound>>.

When your C# scripts compile, Yarn Spinner finds every method with the attribute and generates the code that adds it to each Dialogue Runner. You don’t have to add these Commands yourself.

The method has to be public, and so does the class it’s in. If either isn’t, you’ll see error YS1001 in the Console when your scripts compile.

There are two kinds of Command, depending on whether the method is static.

Commands that aren’t tied to a GameObject

A static method becomes a Command you can use anywhere:

using Yarn.Unity;

public static class AudioCommands
{
    [YarnCommand("play_sound")]
    public static void PlaySound(string soundName)
    {
        AudioManager.Play(soundName);
    }
}
A static Command. «play_sound door_creak» calls it with soundName set to door_creak.
<<play_sound door_creak>>
Using the static Command in Yarn.

AudioManager stands in for however your game plays sounds. Static Commands suit things the whole game uses, like playing sounds or saving.

Commands on a GameObject

A method that isn’t static belongs to a component, so the class has to be a MonoBehaviour or another kind of Component. In Yarn, the first argument is the name of the GameObject to call it on:

using UnityEngine;
using Yarn.Unity;

public class Character : MonoBehaviour
{
    [YarnCommand("move")]
    public async YarnTask Move(float x, float y)
    {
        var start = transform.position;
        var end = new Vector3(x, y, start.z);
        var elapsed = 0f;
        while (elapsed < 1f)
        {
            elapsed += Time.deltaTime;
            transform.position = Vector3.Lerp(start, end, elapsed);
            await YarnTask.Yield();
        }
    }
}
Line 4 The script goes on the character’s GameObject, which is called Rosa in the scene.
Line 6 The attribute makes this method the <<move>> Command.
Line 7 It isn’t static, so it’s a Command on a GameObject. In Yarn, the first argument, Rosa, says which GameObject to call it on. x and y come from the other two arguments, converted to float. It’s an async method that returns a YarnTask, so the dialogue waits until it has finished.
Lines 12–17 Move the GameObject to the new position over one second, waiting a frame between each step.
Character.cs, on a GameObject called Rosa. «move Rosa 3 0» calls it on Rosa.
<<move Rosa 3 0>>
Calling the Command on the GameObject called Rosa.

If every character in your game has the same script, each one gets a <<move>> Command, and the first argument says which character moves. The Dialogue Runner finds the GameObject with Unity’s GameObject.Find(), so it has to be active, and then looks for the script on that GameObject. If it can’t find the GameObject, or the GameObject doesn’t have the script, it logs an error.

Arguments

Arguments are separated by spaces. To pass an argument with a space in it, put it in double quotes: <<give_item "brass key" 1>>.

Each argument is converted to the type of the method’s parameter:

Parameter typeWhat you write in Yarn
stringAny text.
int, float, double and other number typesA number, like 3 or 0.5.
booltrue or false. Writing the parameter’s name means true: for a parameter called wait, <<fade wait>> passes true.
GameObjectThe name of an active GameObject in the scene. The Dialogue Runner finds it and passes it in. If there’s no such GameObject, it passes null.
A component type, like Transform or a script of your ownThe name of an active GameObject. The Dialogue Runner finds it, and passes in the first component of that type on it or its children. If there’s none, it passes null.
An array, as the last parameterAny number of arguments, each converted to the array’s element type.
How Command arguments are converted to each parameter type.

Parameters with default values can be left out. An array as the last parameter, like params string[] names, takes every argument that’s left, so <<unlock start_game pet_the_dog>> and <<unlock>> both work.

If there are too few or too many arguments, the Dialogue Runner logs an error saying how many the Command needs, and doesn’t call the method. If an argument can’t be converted, you’ll also see an error in the Console, and the method isn’t called.

To use a variable’s value as an argument, put it in curly braces: <<give_item {$reward} 1>>.

Making the dialogue wait

The dialogue carries on as soon as your method returns. To make it wait until something has finished, like an animation or a sound, have the method return one of these:

Return typeWhen the dialogue carries on
IEnumeratorThe method is a coroutine. The Dialogue Runner starts it and waits until it has finished.
CoroutineA coroutine you’ve started yourself with StartCoroutine(). The dialogue waits until it has finished.
YarnTaskAn async method. The dialogue waits until it has finished.
TaskAn async method using .NET’s Task. The dialogue waits until it has finished.
AwaitableAn async method using Unity’s Awaitable, in Unity 2023.1 and later. The dialogue waits until it has finished.
UniTaskAn async method using UniTask, if the UniTask package is installed. The dialogue waits until it has finished.
The return types that make the dialogue wait for a Command.

A Command marked with [YarnCommand] has to return void or one of these. Any other return type gives you error YS1003 when your scripts compile.

The move Command above is an async method that returns a YarnTask, so the next line only appears once Rosa has arrived. A coroutine works too:

[YarnCommand("wave")]
public IEnumerator Wave()
{
    animator.SetTrigger("Wave");
    yield return new WaitForSeconds(1.5f);
}
A Command in Character.cs that waits for an animation, as a coroutine. animator is an Animator set in the Inspector.

For more on writing async Commands, see Async and Cancellation.

Adding Commands from code

You can add a Command to a Dialogue Runner yourself, with any name and any method:

using UnityEngine;
using Yarn.Unity;

public class GameCommands : MonoBehaviour
{
    [SerializeField] DialogueRunner dialogueRunner;

    void Awake()
    {
        dialogueRunner.AddCommandHandler<string, int>("give_item", GiveItem);
    }

    void GiveItem(string itemName, int count)
    {
        Inventory.Add(itemName, count);
    }
}
Line 6 The Dialogue Runner. Drag it into this field in the Inspector.
Lines 8–11 Add the Command when the scene starts. The first argument is its name in Yarn. The types in angle brackets are the method’s parameter types, in order.
Line 13 An ordinary method, so <<give_item "brass key" 1>> passes a string and an int. It doesn’t have to be public.
Line 15 Your game’s own code. Inventory stands in for however your game keeps track of items.
Adding a «give_item» Command when the scene starts.

When you pass a method by name, list its parameter types in angle brackets, like AddCommandHandler<string, int>. You can pass a lambda instead, giving its parameters types: dialogueRunner.AddCommandHandler("open_door", (bool slowly) => door.Open(slowly));.

The method can return any of the types in Making the dialogue wait, and the dialogue waits for it in the same way.

To remove a Command, call dialogueRunner.RemoveCommandHandler("give_item").

Command names can’t have spaces in them. If you add a Command with a space in its name, or one with the same name as a Command that’s already been added, the Dialogue Runner logs an error and ignores it.

Choosing between the attribute and code

Both ways do the same job, so use whichever suits you.

  • [YarnCommand] works well for methods on your characters and objects, like moving or animating them. The Command sits next to the code it runs.
  • AddCommandHandler() works well for Commands that affect the whole game, like loading a scene or unlocking an achievement. You can add them all in one place, and see every one at once.

How attributed Commands are found

Yarn Spinner finds methods marked with [YarnCommand] when your C# scripts compile, not while the game runs. It generates code that adds them to every Dialogue Runner the first time the Dialogue Runner needs a Command.

This is controlled by Generate linkings for Functions and Commands in Yarn Spinner’s Project Settings. It’s on by default. If you turn it off, methods marked with [YarnCommand] aren’t added, and you have to add every Command yourself with AddCommandHandler().

Built-in Commands

Two Commands are always available:

CommandWhat it does
<<wait 2>>Waits for the number of seconds you give it before the dialogue carries on. It uses scaled time, so it stops counting while Time.timeScale is 0.
<<stop>>Ends the dialogue immediately.
Commands that are always available.

Seeing your Commands

Choose WindowYarn SpinnerCommands... to open the Yarn Commands window. It lists the Commands you’ve marked with [YarnCommand], along with wait and stop, and shows how to call each one. For the move Command above, it shows <<move target (Character) x (number) y (number)>>.

Type in the search field at the top to narrow the list. Commands you add with AddCommandHandler() aren’t listed, because they’re only added while the game runs.

PLACEHOLDER — Screenshot needed
The Yarn Commands window, with its search field and a list of Commands, including wait, stop and a Command on a GameObject, each showing how to call it.

When a Command isn’t found

If the dialogue reaches a Command that isn’t connected to anything, the Dialogue Runner logs an error like No Command "play_sound" was found. Did you remember to use the YarnCommand attribute or AddCommandHandler() function in C#?

To handle those Commands yourself, use the Dialogue Runner’s On Unhandled Command event, in the Events section of its Inspector. It passes the whole Command as text, like play_sound door_creak, and the error isn’t logged. The event only takes over when something is connected to it in the Inspector. Listeners you add from code with AddListener() aren’t counted.

Either way, the dialogue doesn’t carry on past an unknown Command. It stops at that Command, whether the error is logged or the event is called, and doesn’t move on to the next line. See Events.

Autocomplete in VS Code

The Yarn Spinner extension for VS Code can suggest your Commands as you type, and warn you about ones it doesn’t know. It reads them from the .ysls.json file that Yarn Spinner writes when your C# scripts compile. See The .ysls.json file.

Two attributes from the Yarn.Unity.Attributes namespace change what VS Code suggests for a string parameter:

  • [YarnNodeParameter] suggests the names of the nodes in your project.
  • [YarnEnumParameter("Mood")] suggests the cases of the enum called Mood from your Yarn Scripts.
[YarnCommand("jump_to")]
public static void JumpTo([YarnNodeParameter] string nodeName)
{
    Debug.Log($"Jumping to {nodeName}");
}
A Command whose argument VS Code fills in with node names.

These attributes only change the suggestions. The argument is still passed to your method as text, whatever it is.

For a scene that uses Commands and Functions together, see Putting It Together.

Next step Functions Getting values from your game to use in lines and conditions.