Typewriter and Effects

The Line Presenter uses a typewriter to put each line’s text on screen. You can use one of the typewriters that come with Yarn Spinner or write your own. The fade in Effects works from any script.

The built-in typewriters

The Line Presenter’s Typewriter Style chooses one of three built-in typewriters: Instant, By Letter or By Word. The Line Presenter page explains what each one does and how to set its speed.

PLACEHOLDER — Screenshot needed
The Inspector for a Line Presenter with the Typewriter Style menu open, showing Instant, By Letter (selected), By Word and Custom, above Letters per Second and Event Handlers.
PLACEHOLDER — Video needed
The Dialogue System prefab in a scene, with Rosa’s lines typing out one letter at a time in the panel at the bottom of the screen at the default speed of 60 letters per second, followed by two options.

Whichever you choose, when the player presses the Line Advancer’s Hurry Up Line input while a line is still typing out, the rest of the line appears at once. See Line Advancer.

The By Letter and By Word typewriters use Unity’s game time, so they stop typing while Time.timeScale is 0.

Pausing partway through a line

To make the typewriter stop for a moment in the middle of a line, put [pause/] where you want it to stop:

Rosa: The lamp went out, and then [pause/]I heard footsteps.
Rosa: Somebody was on the stairs. [pause=500/]Somebody heavy.
Two pauses: one second, then half a second.

Put the space before [pause/], not after it. A tag like this one removes the space that follows it, so then[pause/] I would show as “thenI”.

On its own, [pause/] waits for 1 second. Give it a whole number to wait that many milliseconds, like [pause=500/], or a decimal to wait that many seconds, like [pause=0.5/].

Pauses work with all three built-in typewriters, including Instant, which shows the text up to the pause, waits, and then shows the rest. If the player hurries up the line during a pause, the pause ends and the rest of the line appears.

To make your own markup that does something while a line types out, see Markup.

Writing your own typewriter

If none of the built-in typewriters does what you want, you can write your own. A typewriter is a class that implements IAsyncTypewriter. To choose it in the Inspector, make it a MonoBehaviour.

This one types a line out letter by letter, and waits a little longer after each full stop, comma, exclamation mark and question mark:

using System;
using System.Collections.Generic;
using System.Threading;
using TMPro;
using UnityEngine;
using Yarn.Markup;
using Yarn.Unity;

public class PunctuationTypewriter : MonoBehaviour, IAsyncTypewriter
{
    [SerializeField] float charactersPerSecond = 40f;
    [SerializeField] float punctuationPause = 0.3f;

    public TMP_Text TextElement { get; set; }
    public List<IActionMarkupHandler> ActionMarkupHandlers { get; } = new();

    public void PrepareForContent(MarkupParseResult line)
    {
        TextElement.maxVisibleCharacters = 0;
        TextElement.text = line.Text;
        foreach (var handler in ActionMarkupHandlers)
        {
            handler.OnPrepareForLine(line, TextElement);
        }
    }

    public async YarnTask RunTypewriter(MarkupParseResult line, CancellationToken token)
    {
        foreach (var handler in ActionMarkupHandlers)
        {
            handler.OnLineDisplayBegin(line, TextElement);
        }

        var textInfo = TextElement.GetTextInfo(line.Text);

        for (int i = 0; i < textInfo.characterCount; i++)
        {
            foreach (var handler in ActionMarkupHandlers)
            {
                await handler.OnCharacterWillAppear(i, line, token).SuppressCancellationThrow();
            }

            TextElement.maxVisibleCharacters = i + 1;

            if (token.IsCancellationRequested)
            {
                continue;
            }

            var delay = 1f / charactersPerSecond;
            if (".,!?".IndexOf(textInfo.characterInfo[i].character) >= 0)
            {
                delay += punctuationPause;
            }
            await YarnTask.Delay(TimeSpan.FromSeconds(delay), token).SuppressCancellationThrow();
        }

        TextElement.maxVisibleCharacters = textInfo.characterCount;

        foreach (var handler in ActionMarkupHandlers)
        {
            handler.OnLineDisplayComplete();
        }
    }

    public void ContentWillDismiss()
    {
        foreach (var handler in ActionMarkupHandlers)
        {
            handler.OnLineWillDismiss();
        }
    }

    public void ContentDidDismiss()
    {
        TextElement.maxVisibleCharacters = 0;
    }
}
Line 9 A MonoBehaviour that implements IAsyncTypewriter, so you can add it to a GameObject and assign it to the Line Presenter.
Lines 11–12 Serialized fields appear in the Inspector, so you can change them without editing the script.
Line 14 TextElement is the Line Presenter’s Line Text, which it sets when the scene starts.
Line 15 The handlers to call as the line types out. The Line Presenter adds the [pause] handler and its Event Handlers to this list, and so does a Line Advancer whose Presenter is this Line Presenter.
Lines 17–25 The Line Presenter calls PrepareForContent before the panel fades in. Put the text in the text field, and hide all of it to start with.
Line 27 The Line Presenter calls RunTypewriter once for each line, and treats the line as finished when it returns. token tells you when the player wants to hurry.
Line 34 GetTextInfo gives the characters TextMeshPro will draw, without any markup tags, so each position matches a character on screen.
Lines 38–41 Give each handler a chance to act before the character appears. This is where [pause] waits.
Line 43 Show one more character.
Lines 45–48 If the player has hurried up the line, carry on to the end without waiting.
Lines 50–54 Work out how long to wait before the next character, and add Punctuation Pause if this one is a full stop, comma, exclamation mark or question mark.
Line 55 Wait. Hurrying up the line cancels token, which ends the wait early.
Line 58 Show the whole line.
Lines 60–63 Tell each handler the line has finished appearing.
Lines 66–77 ContentWillDismiss is called before the panel fades out, and ContentDidDismiss after it has gone.
A custom typewriter that waits after punctuation.

To use it:

  1. Add the PunctuationTypewriter component to a GameObject in your scene.
  2. Select the Line Presenter, and set Typewriter Style to Custom.
  3. Drag the GameObject into Custom Typewriter, which appears under Typewriter Style.

Its settings, Characters Per Second and Punctuation Pause in this example, are on the PunctuationTypewriter component, where you can change them.

If Typewriter Style is Custom and Custom Typewriter is empty, the Line Presenter shows each line all at once and logs a warning.

Call each handler in ActionMarkupHandlers the way the example does. Without them, [pause] and the Line Presenter’s Event Handlers don’t work, and the Line Advancer never learns that the line has finished, so pressing Hurry Up Line a second time doesn’t move on. The built-in typewriters, in Runtime/Views/Typewriter/ in the Yarn Spinner package, show how.

Effects

Effects has a fade you can call from any script, without adding anything to your scene.

MethodWhat it does
FadeAlphaAsync(canvasGroup, from, to, duration, token)Fades a Canvas Group’s Alpha between any two levels of transparency, from 0 to 1. Returns a YarnTask you can await.
FadeAlpha(canvasGroup, from, to, duration, token)The same fade, as a coroutine to use with StartCoroutine().
The methods in Effects.

If token is cancelled, the fade jumps straight to to. If duration is 0, the fade happens at once. The Line Presenter and Options Presenter use FadeAlphaAsync for their own fades.

A Command can return the fade’s YarnTask, and the dialogue waits for it to finish before it carries on. Commands run between lines, when the Line Presenter has hidden its panel, so use them for things that stay on screen, such as a title card:

using System.Threading;
using UnityEngine;
using Yarn.Unity;

public class TitleCard : MonoBehaviour
{
    [SerializeField] CanvasGroup canvasGroup;

    [YarnCommand("fade_out")]
    public YarnTask FadeOut(float duration = 1f)
    {
        return Effects.FadeAlphaAsync(canvasGroup, 1, 0, duration, CancellationToken.None);
    }
}
Line 7 The Canvas Group to fade. Drag it into this field in the Inspector.
Lines 9–10 The fade_out Command, with an optional duration in seconds.
Line 12 Returning the fade makes the dialogue wait until it has finished.
A Command that fades out a title card.
<<fade_out TitleCard 2>>
Rosa: Are you here about the lamp?
Fading out the title card before the conversation starts.

The first value after the Command’s name, TitleCard, is the name of the GameObject with the TitleCard component on it. See Commands.

Next step Markup Formatting text, and running game code partway through a line.