Kagari
Type to search documentation.

Modules

std::narrative::text

Stability: Stable — text values, the builtins t![…] desugars to, text effects and text styles.

std::narrative::text declares Text, the type of every message, name and label; the builtin functions that the form t![…] desugars to; ToText, the bound of interpolation; text effects (TextEffect and its constructors), which style a piece of text and cue its reveal; and TextStyle, the style of a whole text box.

Every function is a const fn. Text, TextEffect and Mark are re-exported from std::narrative. The prelude imports Text, TextEffect and the constructors emphasis, dots, color_text, bold, pause, click_wait and mark; everything else is imported from std::narrative::text.

Overview

ItemKindSummary
Textbuiltin structConstant text, plain or rich
ruby, mono_ruby, effect, concatbuiltin const fnWhat t![…] items desugar to
ToText, to_textbuiltinInterpolation
Mark, Weight, Emphasis, Reveal, Pause, Outline, ShadowdataParts of a text effect
TextEffect, PLAINstruct, constantA text effect
color_text … markconst fnText-effect constructors
TextAlign, EmphasisStyle, TextStyle, text_styledata, const fnThe style of a text box

Struct: Text

kis
#[builtin] pub struct Text;

Constant text: plain ("Mio") or rich (t![…]).

  • Kind: — · Builtin: yes

  • A string literal has type Text: who = "Mio" needs no t!.

  • Text is Eq and finite: in the story, the values of Text are the constant texts of the program. fn code can build other texts at runtime with to_text.

  • Because of that, an entry scene’s parameter and return types must not contain Text (E3009).

t![…] desugaring

t![…] is a form; each item becomes one call:

ItemDesugars to
"…"the string literal
["数多"]("あまた")ruby("数多", "あまた")
["漢字"]("かん"|"じ")mono_ruby("漢字", ["かん", "じ"])
!["赤い"](e)effect("赤い", e); with a ruby item as base: effect(ruby(…), e)
{expr}to_text(expr)

The whole form is then:

  • "" with no items;
  • the single item’s expression with one item, so t![{DAY}] is to_text(DAY);
  • concat([…]) of the items otherwise.
kix
t!["Day " {DAY} ": " !["the festival"](emphasis())]
// concat(["Day ", to_text(DAY), ": ", effect("the festival", emphasis())])

The form’s syntax is described in Forms.

Function: ruby(base, reading)

kis
#[builtin] pub const fn ruby(base: Text, reading: Text) -> Text;
  • base Text — the base text; must be a string literal (E3021).
  • reading Text — the reading.
  • Returns: Text — base with reading set over it as ruby (group ruby: one reading over the whole base).
  • Kind: const fn · Builtin: yes

A ruby nested inside another ruby’s base drops its reading. Ruby dictionaries (ruby declared once for recurring words) are not planned: ruby is written at each use.

Function: mono_ruby(base, readings)

kis
#[builtin] pub const fn mono_ruby<const N: usize>(base: Text, readings: [Text; N]) -> Text;
  • base Text — the base text; must be a string literal.
  • readings [Text; N] — one reading per character of base; must be an array literal.
  • Returns: Text — base with one ruby reading per character.
  • Kind: const fn · Builtin: yes

N must equal the number of base characters (E3021).

Function: effect(base, effect)

kis
#[builtin] pub const fn effect(base: Text, effect: TextEffect) -> Text;
  • base Text — the text to style.
  • effect TextEffect — the effect; must be a constant expression (E3022).
  • Returns: Text — base with effect applied to it.
  • Kind: const fn · Builtin: yes

Function: concat(items)

kis
#[builtin] pub const fn concat<const N: usize>(items: [Text; N]) -> Text;
  • items [Text; N] — the parts.
  • Returns: Text — the items one after another. No whitespace is added or folded.
  • Kind: const fn · Builtin: yes

Trait: ToText

kis
#[builtin] pub trait ToText {}
impl ToText for Text {}
impl ToText for String {}
impl<const LO: i64, const HI: i64> ToText for Int<LO, HI> {}
impl ToText for u8 {}
impl ToText for u16 {}
impl ToText for u32 {}
impl ToText for u64 {}
impl ToText for u128 {}
impl ToText for i8 {}
impl ToText for i16 {}
impl ToText for i32 {}
impl ToText for i64 {}
impl ToText for i128 {}
impl ToText for usize {}
impl ToText for isize {}
impl ToText for Rat {}
impl ToText for Decimal {}

Types a {expr} item of t![…] may interpolate: Text, String, every integer type, Rat and Decimal.

  • Kind: — · Builtin: yes

Function: to_text(value)

kis
#[builtin] pub const fn to_text<T: ToText>(value: T) -> Text;
  • value T — the value to show.

  • Returns: Text — value as text; what {expr} in t![…] desugars to.

  • Kind: const fn · Builtin: yes

  • {expr} needs expr: T with T: ToText.

  • Integers are written in decimal, Rat and Decimal exactly.

  • In the story, to_text of a finite value is tabulated like any const fn call, so a line with {DAY} is still a finite function of the story state.

  • In the backlog, interpolated values are recorded as they were shown, unless the step sets history.

kix
static mut DAY: Int<1, 7> = 1;
#[scene]
pushdown fn Morning() {
s!(t!["Day " {DAY}]);
}

Struct: Mark

kis
pub struct Mark(pub u8);

A named point in a text’s reveal, which renders can anchor the timeline on (Screen::at_mark, see std::screen). Set with mark(n). Mark holds a Rust integer, so it is not finite; the story uses it in constant expressions.

  • Kind: — · Builtin: no

Enum: Weight

kis
pub enum Weight {
Regular,
Bold,
}

Font weight.

  • Kind: — · Builtin: no

Enum: Emphasis

kis
pub enum Emphasis {
Styled,
Dots,
}

How emphasized text is drawn.

  • Styled — with the window’s TextStyle::emphasis.
  • Dots — emphasis dots (bouten) over every character, whatever the window’s style.
  • Kind: — · Builtin: no

Enum: Reveal

kis
pub enum Reveal {
Player,
PerChar(Duration),
Scaled(Decimal),
Instant,
}

How fast text appears.

VariantSpeed
Playerthe text_speed setting
PerChar(d)d per character, whatever the setting
Scaled(x)the player’s speed × x, with x > 0
Instantall at once
  • Kind: — · Builtin: no

Enum: Pause

kis
pub enum Pause {
Time(Duration),
Click,
}

A stop in the reveal before the effect’s base.

  • Time(d) — stops for d.
  • Click — stops until a click, which continues the text.
  • Kind: — · Builtin: no

Struct: Outline

kis
pub struct Outline {
pub color: Color,
pub width: u32,
}

A text outline: color, and width in pixels.

  • Kind: — · Builtin: no

Struct: Shadow

kis
pub struct Shadow {
pub color: Color,
pub offset: Offset,
pub blur: u32,
}

A text shadow: color, offset in pixels, and blur radius in pixels.

  • Kind: — · Builtin: no

Struct: TextEffect

kis
pub struct TextEffect {
pub color: Option<Color>,
pub size: Option<Decimal>,
pub weight: Option<Weight>,
pub italic: Option<bool>,
pub font: Option<FontAsset>,
pub outline: Option<Outline>,
pub shadow: Option<Shadow>,
pub emphasis: Option<Emphasis>,
pub reveal: Option<Reveal>,
pub pause: Option<Pause>,
pub mark: Option<Mark>,
}

Styles and cues applied to a piece of text; None fields inherit (leave the window’s style in place). size is a scale of the window’s text size.

  • Kind: — · Builtin: no

A text effect is a value, not a function. The effect of !["…"](…) must be a constant expression, so a message is still a constant of its step. Effects combine with and:

kix
const RED: Color = rgb(220, 40, 40);
const LINE: Text = t!["It was " !["right there"](bold().and(color_text(RED))) "."];

TextEffect::and(self, other)

kis
pub const fn and(self, other: TextEffect) -> TextEffect
  • other TextEffect — the effect laid over this one.
  • Returns: TextEffect — a right-biased merge: fields set in other win, the others come from self.
  • Kind: const fn · Builtin: no

Constant: PLAIN

kis
pub const PLAIN: TextEffect = TextEffect {
color: None,
size: None,
weight: None,
italic: None,
font: None,
outline: None,
shadow: None,
emphasis: None,
reveal: None,
pause: None,
mark: None,
};

The effect that changes nothing: every field None.

Effect constructors

Each constructor is PLAIN with one field set. All are const fn, Builtin: no.

ConstructorSetsIn prelude
pub const fn color_text(color: Color) -> TextEffectcoloryes
pub const fn size(scale: Decimal) -> TextEffectsize: scale times the window’s text sizeno
pub const fn bold() -> TextEffectweight: Some(Bold)yes
pub const fn italic() -> TextEffectitalic: Some(true)no
pub const fn font(font: FontAsset) -> TextEffectfontno
pub const fn outline(color: Color, width: u32) -> TextEffectoutlineno
pub const fn shadow(color: Color, offset: Offset, blur: u32) -> TextEffectshadowno
pub const fn emphasis() -> TextEffectemphasis: Some(Styled)yes
pub const fn dots() -> TextEffectemphasis: Some(Dots)yes
pub const fn speed(per_char: Duration) -> TextEffectreveal: Some(PerChar(per_char))no
pub const fn speed_scale(scale: Decimal) -> TextEffectreveal: Some(Scaled(scale))no
pub const fn reveal_instant() -> TextEffectreveal: Some(Instant)no
pub const fn pause(duration: Duration) -> TextEffectpause: Some(Time(duration))yes
pub const fn click_wait() -> TextEffectpause: Some(Click)yes
pub const fn mark(n: u8) -> TextEffectmark: Some(Mark(n))yes

Styles

color_text(color), size(scale), bold(), italic(), font(font), outline(color, width), shadow(color, offset, blur), emphasis(), dots().

Style fields (color, size, weight, italic, font, outline, shadow, emphasis) apply to the effect’s base text.

  • emphasis() renders with the window’s TextStyle::emphasis.
  • dots() always draws emphasis dots, whatever the window’s style.
kix
const LINE: Text = t!["これは" ["数多"]("あまた") "の" !["赤い"](emphasis()) "花。"];

Reveal

speed(per_char), speed_scale(scale), reveal_instant().

reveal sets how fast the base appears; see Reveal. speed_scale needs a scale greater than 0.

kix
use std::narrative::text::speed;
const LINE: Text = t![!["Slowly, slowly…"](speed(ms(80))) " then all at once."];

Pauses

pause(duration), click_wait().

A pause stops the reveal before the effect’s base. The base is usually "".

  • pause(d) stops the reveal for d.
  • click_wait() stops the reveal until a click. That click continues the text; it does not complete it and is not a NextStep. It is not recorded in saves.
  • In auto mode a click pause continues after the auto_delay setting.
kix
const LINE: Text = t!["Wait" ![""](pause(ms(500))) "… " ![""](click_wait()) "there it is."];

Marks

mark(n).

A mark names a point of the reveal, so that a render can schedule animations there (see std::screen::anim).

  • mark(n) records the time the reveal reaches that point.
  • A duplicate mark in one text is a const-evaluation error (E4010).
  • A mark the step’s text does not contain resolves to the end of the reveal.
kix
use std::narrative::Mark;
const fn startled(mut screen: Screen) -> Screen {
screen.at_mark(Mark(1));
// changes scheduled here start when the reveal reaches mark 1
screen
}
#[scene]
pushdown fn Surprise() {
s!(render = startled, t!["Wait" ![""](pause(ms(500)).and(mark(1))) "—what?"]);
}

Here the render startled can call screen.at_mark(Mark(1)) and change a face at the moment the reveal reaches the dash.

Stability: Planned — syncing text and animation beyond marks: an animation that follows each revealed character, or a reveal that waits for an animation. Not designed yet.

Clicks and the backlog

  • A click during the reveal shows the full text at once, except that a click_wait() pause still waits for its own click.
  • Text in the backlog is shown without pauses or reveal. Interpolated values are recorded as they were shown, unless the step sets history.

Enum: TextAlign

kis
pub enum TextAlign {
Start,
Center,
End,
}

Horizontal text alignment.

  • Kind: — · Builtin: no

Enum: EmphasisStyle

kis
pub enum EmphasisStyle {
Dots,
Bold,
Italic,
}

How Emphasis::Styled text (from emphasis()) is drawn in a text box.

  • Kind: — · Builtin: no

Struct: TextStyle

kis
pub struct TextStyle {
pub font: Option<FontAsset>,
pub size: u32,
pub color: Color,
pub line_height: Decimal,
pub letter_spacing: i32,
pub align: TextAlign,
pub outline: Option<Outline>,
pub shadow: Option<Shadow>,
pub ruby_size: u32,
pub emphasis: EmphasisStyle,
pub hanging_indent: bool,
pub vertical: bool,
}

The style of a text box: the message window (ui::message), labels and text! in the UI, and label layers on the screen.

FieldMeaning
fontNone: System::font
size, ruby_sizepixels
colorthe text colour
line_heighta multiple of size
letter_spacingpixels between characters
alignhorizontal alignment
outline, shadowNone: none
emphasishow Emphasis::Styled text is drawn
hanging_indenta line that starts with an opening bracket (「『() indents its wrapped lines by the bracket’s width
verticalvertical writing
  • Kind: — · Builtin: no

Function: text_style(size, color)

kis
pub const fn text_style(size: u32, color: Color) -> TextStyle
  • size u32 — the text size in pixels.
  • color Color — the text colour.
  • Returns: TextStyle — a style with font None, line_height 1.5, letter_spacing 0, align Start, no outline or shadow, ruby_size = size / 2, emphasis Dots, hanging_indent false and vertical false.
  • Kind: const fn · Builtin: no

TextStyle builders

Each builder returns the style with one field replaced; builders of Option fields wrap the value in Some. All are const fn, Builtin: no.

kis
pub const fn font(mut self, font: FontAsset) -> TextStyle
pub const fn line_height(mut self, value: Decimal) -> TextStyle
pub const fn letter_spacing(mut self, value: i32) -> TextStyle
pub const fn align(mut self, value: TextAlign) -> TextStyle
pub const fn outline(mut self, value: Outline) -> TextStyle
pub const fn shadow(mut self, value: Shadow) -> TextStyle
pub const fn ruby_size(mut self, value: u32) -> TextStyle
pub const fn emphasis(mut self, value: EmphasisStyle) -> TextStyle
pub const fn hanging_indent(mut self, value: bool) -> TextStyle
pub const fn vertical(mut self, value: bool) -> TextStyle
BuilderSets
font(font)font: Some(font)
line_height(value)line_height: value times the size
letter_spacing(value)letter_spacing: pixels between characters
align(value)align
outline(value)outline: Some(value)
shadow(value)shadow: Some(value)
ruby_size(value)ruby_size: pixels
emphasis(value)emphasis: how Emphasis::Styled text is drawn
hanging_indent(value)hanging_indent
vertical(value)vertical: vertical or horizontal writing
kis
use std::narrative::text::{Outline, TextStyle, text_style};
const WINDOW_TEXT: TextStyle = text_style(26, WHITE)
.outline(Outline { color: BLACK, width: 2 })
.hanging_indent(true);

Last updated Oct 29, 2026