Stability: Stable — the program description, settings, mode types, seen sets and input bindings.
std::system describes the game system: everything around the story, such as the title page,
the save and load pages, the settings page, the backlog and the in-game UI. A game’s main
function returns a System value, and the engine runs the program it describes.
System code is fn code. Constructors (setting, volume, bind, default_bindings) are
const fn, so they may appear in static and const initializers.
The module has two submodules:
std::system::navchanges the mode stack.std::system::savesreads and deletes save slots.
pub mod nav;pub mod saves;The prelude imports nav, Setting, setting, System, Settings, Volume, volume,
RootPage, Overlay, GameOverlay and Dialog. Import the other items by path, for example
use std::system::{seen_image, default_bindings};.
Overview
| Item | Kind | Summary |
|---|---|---|
Setting<T> | builtin struct | A persistent global setting, stored outside saves |
setting(init) | const fn | Declares a setting |
Volume, volume(level) | struct, const fn | A bus volume |
Settings | struct | The setting handles the engine reads |
RootPage, Overlay, GameOverlay, Dialog | structs | The mode types |
System | struct | The program, returned by main |
seen_image, heard, watched | fn | The seen sets |
set_music | fn | The system music channel |
Key, MouseButton, PadButton, Input | enums | Bindable inputs |
Action | enum | What a binding does |
Binding, bind, default_bindings | struct, const fn | Input bindings |
Struct: Setting<T>
#[builtin] pub struct Setting<T>;A handle to a persistent, global setting. Its value is stored in the config file, never in a save, so loading a save or rewinding never changes it.
An immutable static whose initializer is setting(init) declares a setting:
static TEXT_SPEED: Setting<Duration> = setting(ms(30));static MUSIC: Setting<Volume> = setting(volume(60));static WINDOW_OPACITY: Setting<Int<0, 100>> = setting(80);static PETALS_ON: Setting<bool> = setting(true);- The engine reads the handles listed in
Settings. A studio may declare any further settings for its own UI and renders, such asPETALS_ONabove. - In
fncode, callgetandset. - In a
const fn(a render), a handle is only a value: it may be passed toEntity::gate(seestd::screen), which draws an entity only while aSetting<bool>istrue.getandsetarefnand cannot be called there. See Compiler Rules. - Settings never reach the story’s control flow, so every story analysis holds for every value of
every setting. Compare
Meta<T>, which the story may write.
setting(init)
#[builtin] pub const fn setting<T>(init: T) -> Setting<T>;initT— the value used when the config file has no value for this setting, for example on first boot or after an update adds the setting.- Returns:
Setting<T>— the handle. - Kind:
const fn· Builtin: yes
Setting::get()
#[builtin] pub fn get(&self) -> T;- Returns:
T— the current value. - Kind:
fn· Builtin: yes
get is a reactive source: a reactive attribute or effect that calls it
re-runs when the value changes.
Setting::set(value)
#[builtin] pub fn set(&self, value: T);valueT— the new value. It is written to the config file.- Kind:
fn· Builtin: yes
button!{on_click = || FULLSCREEN.set(!FULLSCREEN.get()), t!["Fullscreen"]}Struct: Volume
pub struct Volume { pub level: Int<0, 100>, pub muted: bool,}The value of a volume setting.
level— the volume in percent. Because it is anInt<0, 100>, aslider!bound to it runs from 0 to 100 without any range attributes.muted—truesilences the bus without losinglevel.
volume(level)
pub const fn volume(level: Int<0, 100>) -> Volume { Volume { level, muted: false }}levelInt<0, 100>— the level in percent.- Returns:
Volume— an unmuted volume atlevel. - Kind:
const fn· Builtin: no
Struct: Settings
pub struct Settings { /// Per character; `ZERO` is instant. pub text_speed: Setting<Duration>, /// The wait after a line in auto mode. pub auto_delay: Setting<Duration>, /// Added to `auto_delay` per character of the line. pub auto_delay_per_char: Setting<Duration>, /// Whether skip mode also skips unread text. pub skip_unread: Setting<bool>, pub master: Setting<Volume>, pub music: Setting<Volume>, pub sound: Setting<Volume>, pub voice: Setting<Volume>, /// Whether a voice keeps playing into the next step. pub voice_sustain: Setting<bool>, /// Whether auto mode waits for the voice. pub wait_for_voice: Setting<bool>, pub window_opacity: Setting<Int<0, 100>>, pub fullscreen: Setting<bool>, /// `false`: every duration counts as 0. pub animations: Setting<bool>,}The setting handles the engine itself reads, given in System::settings. Each field
is a handle declared with setting; the struct only tells the engine which
handle plays which role.
| Field | Meaning |
|---|---|
text_speed | The reveal time per character; ZERO reveals a line at once |
auto_delay, auto_delay_per_char | In auto mode, the wait after a line: auto_delay plus auto_delay_per_char per character of the line. Also the wait of a click pause in auto mode |
skip_unread | Whether skip mode also skips text the player has not read |
master, music, sound, voice | The bus volumes; see std::screen::audio |
voice_sustain | Whether a voice keeps playing into the next step |
wait_for_voice | Whether auto mode waits for the voice to end |
window_opacity | The opacity of the text window, in percent |
fullscreen | Fullscreen (true) or windowed |
animations | false: every duration counts as 0, so animations and transitions end at once |
Mode types
The system is a stack of modes. The kind of a mode is the return type of its component, a
fn that builds its UI. Each mode type wraps an Element, as in
Overlay(column![…]).
| Mode | Component signature | Examples | On the stack |
|---|---|---|---|
| root page | fn() -> RootPage | Title, Gallery, Credits | Only as the base; never together with a game |
| game mode | fn(Narrative) -> Element (System::game) | The game view | Only as the base |
| overlay | fn() -> Overlay | Config, Load | Pushed over any mode |
| game overlay | fn(Narrative) -> GameOverlay | Save, Backlog | Pushed only over a game base, through Narrative::call |
| dialog | fn() -> Dialog | Confirmations | Pushed over any mode; drawn over a still image of the modes below |
- Input goes to the top mode only.
- While an overlay or dialog is on top of the game mode, the story is paused and the screen’s running animations are completed, so the modes below are still.
- Only the game view and game overlays receive a
Narrativehandle, so an operation that needs a running game (saving, opening the backlog) cannot be written in a root page: it does not type-check. std::system::navlists the operations that change the stack. The compiler checks the graph of modes these operations build (unreachable modes, modes that cannot be left, an unbounded stack); see the game system diagnostics.
Struct: RootPage
pub struct RootPage(pub Element);A base page of the mode stack, such as a title page, a gallery or the credits. The
System::start page and the targets of nav::goto are root
pages.
Struct: Overlay
pub struct Overlay(pub Element);A mode pushed over any mode by nav::call or
Action::Open, such as a config or load page.
Struct: GameOverlay
pub struct GameOverlay(pub Element);A mode pushed over the game by Narrative::call or Action::OpenInGame. Its
component receives the running game’s Narrative handle, so it can save, read the backlog or
rewind. Save pages, backlogs and in-game menus are game overlays.
Struct: Dialog
pub struct Dialog(pub Element);A modal mode pushed by nav::dialog, such as a confirmation. It is
drawn over a still image of the modes below.
Struct: System
pub struct System { pub title: Text, /// The design resolution every pixel value refers to. pub resolution: Size, pub start: fn() -> RootPage, pub game: fn(Narrative) -> Element, pub save_slots: u32, pub auto_slots: u32, /// The maximum number of backlog entries. pub backlog: u32, /// The default font: the font of text whose style and effects name none. pub font: FontAsset, /// The default style of `ui::label` and `text!`. pub text: TextStyle, pub settings: Settings, pub bindings: Vec<Binding>,}The program. main is a fn in the root module that returns a System; the engine runs it once
at boot. Every field is required.
| Field | Meaning |
|---|---|
title | The window title |
resolution | The design resolution. Every position and length in renders and UI is in pixels of it |
start | The root page the system starts on |
game | The view of the game mode. It receives the Narrative handle and usually draws game_screen! and the message window |
save_slots | The number of manual slots: SaveSlot::Manual(0) … Manual(save_slots - 1) |
auto_slots | The number of autosave slots: SaveSlot::Auto(0) … Auto(auto_slots - 1) |
backlog | The maximum number of Narrative::history entries |
font | The default font: the font of any text whose TextStyle and text effects name no font. Required |
text | The default TextStyle of ui::label and text! outside buttons and toggles |
settings | The setting handles the engine reads |
bindings | The input bindings |
main runs as ordinary code, so its calls count toward the recursion depth like any other call.
use std::narrative::text::text_style;use std::screen::size;use std::system::default_bindings;
static TEXT_SPEED: Setting<Duration> = setting(ms(30));static AUTO_DELAY: Setting<Duration> = setting(ms(1300));static AUTO_DELAY_PER_CHAR: Setting<Duration> = setting(ms(60));static SKIP_UNREAD: Setting<bool> = setting(false);static MASTER: Setting<Volume> = setting(volume(100));static MUSIC: Setting<Volume> = setting(volume(60));static SOUND: Setting<Volume> = setting(volume(100));static VOICE: Setting<Volume> = setting(volume(100));static VOICE_SUSTAIN: Setting<bool> = setting(false);static WAIT_FOR_VOICE: Setting<bool> = setting(true);static WINDOW_OPACITY: Setting<Int<0, 100>> = setting(80);static FULLSCREEN: Setting<bool> = setting(false);static ANIMATIONS: Setting<bool> = setting(true);const FONT: FontAsset = asset("fonts/default.otf");
fn main() -> System { System { title: "Example", resolution: size(1280, 720), start: Title, game: GameView, save_slots: 20, auto_slots: 3, backlog: 200, font: FONT, text: text_style(26, WHITE), settings: Settings { text_speed: TEXT_SPEED, auto_delay: AUTO_DELAY, auto_delay_per_char: AUTO_DELAY_PER_CHAR, skip_unread: SKIP_UNREAD, master: MASTER, music: MUSIC, sound: SOUND, voice: VOICE, voice_sustain: VOICE_SUSTAIN, wait_for_voice: WAIT_FOR_VOICE, window_opacity: WINDOW_OPACITY, fullscreen: FULLSCREEN, animations: ANIMATIONS, }, bindings: default_bindings(), }}
fn GameView(game: Narrative) -> Element { game_screen!(game = game)}
fn Title() -> RootPage { RootPage(button!{on_click = || nav::quit(), t!["Quit"]})}A complete title page, game view and settings page are in System Recipes.
Seen sets
The seen sets are meta values the engine keeps by itself. They record what the player has ever seen, heard or watched, across all plays. Like read-text flags they are never reverted by load or rewind. They are reactive sources. They back a CG gallery, a music room and a movie room without any studio bookkeeping.
Function: seen_image(image)
#[builtin] pub fn seen_image(image: ImageAsset) -> bool;imageImageAsset— the image.- Returns:
bool— whetherimagehas ever been on a step’s logical screen, on any image layer. - Kind:
fn· Builtin: yes
Function: heard(audio)
#[builtin] pub fn heard(audio: AudioAsset) -> bool;audioAudioAsset— the track or sound.- Returns:
bool— whetheraudiohas ever played: aLoopstarted in a channel, or a one-shot sound played. - Kind:
fn· Builtin: yes
Function: watched(video)
#[builtin] pub fn watched(video: VideoAsset) -> bool;videoVideoAsset— the movie.- Returns:
bool— whethervideohas ever played. - Kind:
fn· Builtin: yes
Function: set_music(track, fade)
#[builtin] pub fn set_music(track: Option<crate::screen::audio::Loop>, fade: crate::screen::audio::AudioFade);trackOption<Loop>— the track to play;Nonestops the system music.fadeAudioFade— how the channel goes from the old track to the new one, for examplecrossfade(ms(500)).- Kind:
fn· Builtin: yes
Sets the system music channel. It is heard while no game runs on the mode stack, for example
on the title page or in a music room. While a game runs, the game screen’s music channel plays
instead. Only system code can call it, because it is a fn. See
std::screen::audio for Loop, looped and AudioFade.
Stability: Planned — reading what is currently playing (the current track, and a music room’s playback state such as position or pause) is not designed yet.
Bindings
System::bindings maps inputs to actions. It is a Vec<Binding>, so a studio starts
from default_bindings() and adds or replaces entries.
Focus keys are built in and not bindable. The arrow keys, the D-pad, Tab and Shift+Tab
move focus between controls; Enter and PadButton::South activate the focused control (see
Focus).
Enum: Key
pub enum Key { Enter, Escape, Space, Backspace, Tab, Up, Down, Left, Right, PageUp, PageDown, Home, End, Shift, Control, Alt, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, Digit0, Digit1, Digit2, Digit3, Digit4, Digit5, Digit6, Digit7, Digit8, Digit9,}A keyboard key: Enter, Escape, Space, Backspace, Tab, the arrow keys, PageUp/PageDown, Home/End,
the modifiers Shift, Control and Alt, F1–F12, the letters A–Z and the digits Digit0–Digit9.
Modifiers are keys of their own; there are no key combinations.
Enum: MouseButton
pub enum MouseButton { Left, Right, Middle, Back, Forward, WheelUp, WheelDown,}A mouse button or a wheel direction. Back and Forward are the side buttons.
Enum: PadButton
pub enum PadButton { South, East, West, North, LeftShoulder, RightShoulder, LeftTrigger, RightTrigger, Start, Select, LeftStick, RightStick, DpadUp, DpadDown, DpadLeft, DpadRight,}A gamepad button, named by position, not by label: South, East, West and North are the
bottom, right, left and top face buttons. LeftStick and RightStick are the stick presses.
PadButton::South and the D-pad also drive focus (see Focus).
Enum: Input
pub enum Input { Key(Key), Mouse(MouseButton), Pad(PadButton),}An input that can be bound.
Enum: Action
pub enum Action { Advance, HoldSkip, ToggleSkip, ToggleAuto, HideWindow, QuickSave, QuickLoad, Back, Open(fn() -> Overlay), OpenInGame(fn(Narrative) -> GameOverlay),}What a binding does.
| Action | Effect | Applies when |
|---|---|---|
Advance | Sends NextStep, or first completes the step’s running timeline | The game mode is on top |
HoldSkip | Skip mode while the input is held | The game mode is on top |
ToggleSkip, ToggleAuto | Switches skip mode or auto mode on or off | The game mode is on top |
HideWindow | Hides the text window | The game mode is on top |
QuickSave, QuickLoad | Writes or loads SaveSlot::Quick | The game mode is on top |
OpenInGame(o) | Pushes the game overlay o | The game mode is on top |
Back | nav::back(); ignored on a base | Always |
Open(o) | Pushes the overlay o | Always |
A binding with Action::Back also counts as a way out of every mode for the
E6003 check.
Struct: Binding
pub struct Binding { pub input: Input, pub action: Action,}An input bound to an action.
Function: bind(input, action)
pub const fn bind(input: Input, action: Action) -> Binding { Binding { input, action }}inputInput— the input.actionAction— what it does.- Returns:
Binding—inputbound toaction. - Kind:
const fn· Builtin: no
Function: default_bindings()
pub const fn default_bindings() -> Vec<Binding> { let mut bindings = Vec::new(); bindings.push(bind(Input::Key(Key::Enter), Action::Advance)); bindings.push(bind(Input::Key(Key::Space), Action::Advance)); bindings.push(bind(Input::Mouse(MouseButton::Left), Action::Advance)); bindings.push(bind(Input::Mouse(MouseButton::WheelDown), Action::Advance)); bindings.push(bind(Input::Pad(PadButton::South), Action::Advance)); bindings.push(bind(Input::Key(Key::Control), Action::HoldSkip)); bindings.push(bind(Input::Pad(PadButton::RightTrigger), Action::HoldSkip)); bindings.push(bind(Input::Mouse(MouseButton::Right), Action::HideWindow)); bindings.push(bind(Input::Pad(PadButton::North), Action::HideWindow)); bindings.push(bind(Input::Key(Key::Escape), Action::Back)); bindings.push(bind(Input::Pad(PadButton::East), Action::Back)); bindings}- Returns:
Vec<Binding>— the default bindings below. - Kind:
const fn· Builtin: no
| Input | Action |
|---|---|
Key::Enter, Key::Space, MouseButton::Left, MouseButton::WheelDown, PadButton::South | Advance |
Key::Control, PadButton::RightTrigger | HoldSkip |
MouseButton::Right, PadButton::North | HideWindow |
Key::Escape, PadButton::East | Back |
Extend the defaults in a const fn:
use std::system::{Action, Binding, Input, Key, MouseButton, bind, default_bindings};
const fn bindings() -> Vec<Binding> { let mut list = default_bindings(); list.push(bind(Input::Key(Key::A), Action::ToggleAuto)); list.push(bind(Input::Key(Key::L), Action::OpenInGame(Backlog))); list.push(bind(Input::Mouse(MouseButton::WheelUp), Action::OpenInGame(Backlog))); list}Stability: Planned — binding an input to an arbitrary
fn(for example a fullscreen toggle) and touch input are not supported yet.
Last updated Oct 29, 2026