Pardon our dust while we move our docs here. The Godot (GDScript) docs are on this site, and the Yarn language, Unity, Godot (C#) and Unreal docs are still at docs.yarnspinner.dev.

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 effects in YarnEffects work from any script.

The built-in typewriters

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

The Inspector for a YarnLinePresenter with the Typewriter Mode menu open, showing Instant, Letter (selected), Word and Custom, next to Custom Typewriter, Justify Text, Characters per Second and Words per Second
The Typewriter Mode menu on the Line Presenter. Letter is the default.
The Letter typewriter at its default speed of 60 characters per second, in the scene from Adding Presenters.

Whichever you choose, when the player presses Continue Action while a line is still typing out, the rest of the line appears at once.

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 presses Continue Action 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 Resource that extends YarnTypewriter and replaces its run_typewriter function.

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

class_name PunctuationTypewriter
extends YarnTypewriter

@export var characters_per_second: float = 40.0
@export var punctuation_pause: float = 0.3

func run_typewriter(
		line: YarnMarkupParseResult,
		display_text: String,
		token: YarnCancellationToken
) -> void:
	var label := text_element
	label.text = display_text
	label.visible_characters = 0
	var text := label.get_parsed_text()

	for i in range(label.get_total_character_count()):
		if token != null and token.is_hurry_up_requested:
			break
		label.visible_characters = i + 1
		var delay := 1.0 / characters_per_second
		if i < text.length() and text[i] in ".,!?":
			delay += punctuation_pause
		var timer := label.get_tree().create_timer(delay, false)
		await timer.timeout

	label.visible_characters = -1
Lines 1–2 Give the script a class_name, so it shows up by name when you choose a typewriter in the Inspector, and extend YarnTypewriter.
Lines 4–5 Exported variables appear in the Inspector under Custom Typewriter, so you can change them without editing the script.
Lines 7–11 The Line Presenter calls run_typewriter once for each line, and treats the line as finished when it returns. display_text is the line’s text with markup already turned into BBCode. token tells you when the player wants to hurry.
Lines 12–14 text_element is the Line Presenter’s text label, which it sets before each line. Put the text in the label, and hide all of it to start with.
Line 15 get_parsed_text() gives the text without any BBCode, so each position matches a character on screen.
Lines 17–19 Go through the text one character at a time. If the player has pressed Continue Action, stop typing.
Line 20 Show one more character.
Lines 21–23 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.
Lines 24–25 Wait. Passing false makes the timer stop while the game is paused.
Line 27 Show the whole line. This also covers the player hurrying, which leaves the loop early.
A custom typewriter that waits after punctuation.

To use it, select the Line Presenter, set Typewriter Mode to Custom, then click Custom Typewriter and choose New PunctuationTypewriter. Its settings, Characters per Second and Punctuation Pause in this example, appear underneath, where you can change them.

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

The example above doesn’t handle [pause] or the Line Presenter’s Event Handlers. The built-in typewriters call each handler in action_markup_handlers as the line types out. If you want your typewriter to support them, do the same. addons/yarn_spinner/ui/typewriter.gd shows how.

Effects

YarnEffects is a set of small animations you can call from any script, without adding anything to your scene.

FunctionWhat it does
fade_in(target, duration)Fades a node in, from transparent to fully visible.
fade_out(target, duration)Fades a node out.
fade_alpha(target, from, to, duration)Fades a node between any two levels of transparency, from 0 to 1.
shake(target, intensity, duration)Shakes a Control around its position, then puts it back.
punch_scale(target, scale, duration)Quickly grows a Control and shrinks it back again.
typewriter(label, text, characters_per_second, token)Types text into a RichTextLabel one character at a time.
typewriter_words(label, text, words_per_second, token)Types text into a RichTextLabel one word at a time.
typewriter_with_line(label, line, characters_per_second, pause_handler, token)Types a line into a RichTextLabel, and handles [pause] if you pass it a YarnPauseEventProcessor.
The functions in YarnEffects.

The durations, intensity, scale, pause_handler and token are optional. Each function returns a signal that’s emitted when the animation has finished, so you can await it. The three typewriter functions are mostly useful when you’re building your own Presenter.

To shake the dialogue box partway through a line, use markup. This event handler shakes the Line Presenter’s panel wherever a line has [shake_box/] in it, and the typewriter waits for the shake to finish before carrying on:

extends YarnActionMarkupHandlerNode

@export var panel: Control

var _positions: Array[int] = []


func on_prepare_for_line(
		line: Variant,
		_text_control: Control = null
) -> void:
	_positions.clear()
	for attribute in (line as YarnMarkupParseResult).attributes:
		if attribute.name == "shake_box":
			_positions.append(attribute.position)


func on_character_will_appear(
		character_index: int,
		_line: Variant,
		_token: Variant = null
) -> Signal:
	if character_index in _positions:
		return YarnEffects.shake(panel, 12.0, 0.4)
	return Signal()
Line 1 Event handlers extend YarnActionMarkupHandlerNode, so they’re nodes in your scene and can use other nodes.
Line 3 The node to shake, set in the Inspector.
Line 5 Where in the line each [shake_box/] is.
Lines 8–15 on_prepare_for_line is called when a line arrives, before any of it is shown. Look through the line’s markup, and record the position of each [shake_box/].
Lines 18–22 on_character_will_appear is called immediately before each character appears.
Lines 23–24 If there’s a [shake_box/] here, shake the panel. Returning a signal makes the typewriter wait until it’s emitted.
Line 25 Otherwise, return an empty Signal() so the typewriter carries on without waiting.
An event handler that shakes the dialogue box at [shake_box/].
Rosa: Wait. Did you hear that?
Rosa: The lamp, it's flickering [shake_box/]again!
A line that shakes the box partway through.
The dialogue box shaking at the [shake_box/] tag, partway through Rosa's second line.

To use it, add a Node to your scene with this script, set its Panel to the Line Presenter’s PanelContainer, and add the node to the Line Presenter’s Event Handlers. See Markup for how event handlers work.

A Command can also return one of these signals, and the dialogue waits for the animation 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 character. See Commands.

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