Skip to content

Inline text markup

Markup is part of the stored text. It round-trips through every format as plain characters, and a consumer that cannot honour a tag should strip it for display rather than rewriting the stored value.

MarkupWhereMeaningIf you cannot honour it
|Dialogue TextSentence split. "One.|Two." is shown as two successive lines, not one paragraph. Audio files pair with segments by position.Replace with a space or newline.
[f]Menu TextForce a menu even when this is the only offered choice.Ignore for display; honour in traversal.
[a]Menu TextAction line — the choice is something the player does, not says (Walk away). Desktop renders it in italics.Strip; optionally style.
[var=Name]EitherSubstituted with the variable’s current value at display time.Substitute; or show {Name} as the production exports do.
[var=?Name]Dialogue TextInput prompt (Desktop’s spelling). Pause, ask the player, store the answer in variable Name, remove the token from the displayed line.Strip, and treat the variable as unset.
[?Name], [x=?Name]Dialogue TextSame as [var=?Name]; anything left of =? is ignored.As above.
[pic=N]Dialogue TextPicture swap. Show the node’s own Pictures entry N (1-based) instead of the actor’s portrait, from this point in the line.Strip.
[pica=N]Dialogue TextShow the actor’s Pictures entry N.Strip.
[picc=N]Dialogue TextShow the conversant’s Pictures entry N.Strip.
[em1]…[/em1] … [em4]…[/em4]EitherEmphasis span. Four project-defined styles (colour, bold/italic/underline, label).Strip the tags, keep the text.
[gesture:…], [expression:…], [vocal:…], [mood:…], [pose:…]Dialogue TextPerformance cue. What a character does at this point in the line. See Performance cues.Strip.

Tags are case-insensitive. A bare [pic] with no = is not a tag and is shown literally.

  • Strip, never rewrite. The production exports (voiceover CSV, proofread text, screenplay) strip every tag and show [var=Name] as {Name}; they never save the stripped text back.
  • Split before you strip. | is a segment boundary; [var=…] and picture tags are per segment. Split first, then process each segment.
  • Input tokens are consumed. After the player answers [?Name], the displayed line has no trace of the token; to echo the answer, the author writes a separate [var=Name].
  • [f] and [a] are choice flags, not text. Strip them from menu labels. [f] changes traversal (see runtime semantics); [a] does not.
  • Emphasis is only honoured when matched. A properly matched, non-nested [emN]…[/emN] pair is a styled run; an open tag with no matching close is treated as plain text. Every tag literal is consumed either way, so tags never leak into displayed text.
  • | inside a bracketed tag is a bug the Unity preflight warns about: Dialogue System splits on | first and would tear the tag in half. Keep | outside brackets.

A performance cue says what a character does while a line is spoken: a facial expression, a body gesture, a vocal sound, a change of mood or a change of pose. It is written where it should happen.

[channel:name]
[channel:name,intensity:0.7,target:conversant]
PartValuesMeaning
channelexpression, gesture, vocal, mood, poseWhat kind of cue it is. expression, gesture and vocal are momentary. mood and pose hold until changed.
namea vocabulary name, such as surprised, shrug, angry, sit_chairWhat to perform.
intensity0 to 1, optionalHow strongly.
targetconversant or an actor’s name, optionalWho performs it. The default is the node’s speaker, so a listener can react to what is being said. Quote a name that contains a space or comma.
atmilliseconds, optionalExact time from the start of the segment’s speech. Written by exporters when audio timing is known; do not author it by hand.

= is accepted in place of : after the channel, and tags are case-insensitive.

A cue belongs to the | segment it sits in. Its position is its character offset in that segment’s spoken text, the text left after every tag is stripped. A player that can time cues fires each one as that point in the speech is reached; one that cannot fires it when the segment starts.

Dialogue Text: I never [gesture:shrug]agreed to that.|[expression:angry,intensity:0.8]You know I didn't.
Displayed: I never agreed to that.
You know I didn't.
Cues: segment 0, offset 8 → shrug, as "agreed" is spoken
segment 1, offset 0 → angry, as the second line starts

The same performance can be set for a whole line with the node’s custom fields Expression, Expression_intensity, Gesture, Mood and Pose, and a character’s baseline with the actor’s Mood and Pose. Fields set the default; inline cues add beats inside the line.

Rules for a consumer:

  • Never speak or display a cue. Strip it before text reaches the screen or a voice provider.
  • Unknown names are a no-op, never an error. A player performs what it can and ignores the rest.
  • Cues in Menu Text do not fire. Put the cue on the line that is spoken.
  • A cue never outlives its segment. Stop a momentary cue when the segment’s speech ends.

The four emphasis slots are defined per project — colour, bold / italic / underline, and a label (“Stage direction”, “Shouted”). In JSON they live in _editor.emphasis; in XML they are the EmphasisColorN, EmphasisStyleN and EmphasisColorNLabel attributes on the root element, exactly as Desktop writes them. The style string is three characters, one per flag, e.g. b-- for bold only, bi- for bold italic.

A consumer that does not render emphasis loses nothing but the styling.

Dialogue Text: Last crossing of the day.|Coming aboard, or staying with the rain?
Displayed: Last crossing of the day.
Coming aboard, or staying with the rain?
Dialogue Text: What do they call you?[?PlayerName]
Displayed: What do they call you? ← then an input box; answer → Variable["PlayerName"]
Next line: Welcome aboard, [var=PlayerName].
Displayed: Welcome aboard, Ines.
Menu Text: [f]Continue
→ a one-button menu even though it is the only option
Menu Text: [a]Walk away
→ label "Walk away", flagged as an action
Dialogue Text: I said [em2]no[/em2].[pic=2] Get off my boat.
Displayed: I said no. Get off my boat. (with "no" in emphasis style 2; the node's second picture shown from "Get off")