Kagari
Type to search documentation.

Modules

std::screen

Stability: Stable — the screen a render transforms: entities and their components, the Hud, the choice menu, the camera, the screen filter and the audio channels.

A render is a const fn from the screen before a step to the screen after it. It changes the screen in place through projections, one chain per statement, and every change states its animation:

kis
const fn azusa_smiles(mut screen: Screen) -> Screen {
screen.entity(AZUSA).image().change(AZUSA::CLOSE_EYE_SMILE).apply_animation(cut());
screen.entity(HANAKO).apply_animation(jump(20, ms(300)));
screen
}

Every item of this module is const fn or plain data, so renders are evaluated at compile time and the compiler can compare screens. The timeline methods of Screen are described here; the animation values they schedule are in std::screen::anim, the audio values in std::screen::audio, and the shader effects (filters, mixes, masks, paints and shader motions) in std::screen::shader, with ready-made shaders in std::shaders. Character helpers built on this module are in std::stage; complete examples are in Staging Recipes.

The prelude re-exports Screen, Render, EntityId, Part, Point, Offset, Size, Anchor, Color, Plane, Visibility, point, offset, rgb, hex, BLACK, WHITE and TRANSPARENT. Every other item needs a use std::screen::….

Overview

ItemKindSummary
Rendertypeconst fn(Screen) -> Screen
EntityId, BACKGROUNDstruct, constantentity identity
Part, MAINstruct, constantimage layer key
Point, Offset, Size, Insets, Anchor, Angle, Posestructs + constructorsgeometry
Color and constantsstruct + constructorssRGB colour
Plane, Visibility, Flip, VAlignenumslayout options
Screenbuiltin structthe screen and the step’s timeline
Entitybuiltin structa thing on the screen
Prop, Changebuiltin structsinterpolated properties
ImageLayer, LabelLayer, Movie, MovieLayer, Swapstructslayers
Hudbuiltin structthe game view’s chrome
ChoiceMenubuiltin structpresentation of the step’s choice
Camerabuiltin structthe camera over the lower planes

The logical screen

The logical screen of a step is the persistent state after its render:

  • the entities with their components;
  • the Hud, the camera and the screen filter;
  • the audio channels.

Snapshots, screen equality and the consistency check use the logical screen only. The timeline, scheduled animations, one-shot sounds and the ChoiceMenu belong to the step and are not part of it.

Animations never change the start or end state: a tween or transition runs from the old value to the value set by change, a motion ends at identity, and a shader motion changes only how an entity is drawn. So a click, skip, or the animations setting being off can never change the logical screen.

Step entry

Before the step’s render runs, the engine resets the step-only state:

  • the timeline cursor goes to (entry, 0 ms);
  • scheduled animations are completed;
  • one-shot cues are dropped unless they are already playing;
  • the ChoiceMenu is emptied and set to Middle;
  • the text start goes to (entry, 0).

A step without render gets the same reset.

Type: Render

kis
pub type Render = const fn(Screen) -> Screen;

A render: the screen before a step to the screen after it. A step’s render = field takes a Render, either a named const fn or a closure:

kix
s!(render = |mut screen| {
screen.hud().text_window().change(Visibility::Hidden).apply_animation(instant());
screen
});

A render whose output does not depend on its input is a keyframe; see Screen::empty().

Geometry

Positions and lengths are pixels in the design resolution System::resolution. Entity ids are studio constants.

Struct: EntityId

kis
pub struct EntityId(pub u32);

The identity of an entity. Studios declare ids as constants: const HANAKO: EntityId = EntityId(1);. Ids also order entities that share a plane and z; see Drawing order.

Constant: BACKGROUND

kis
pub const BACKGROUND: EntityId = EntityId(0);

Reserved for the background entity of Screen::empty(); studio ids start at 1. Screen::background() is its main image.

Struct: Part

kis
pub struct Part(pub u8);

An image layer of an entity. Parts draw in ascending order, so one entity can stack a body, a face and an overlay.

Constant: MAIN

kis
pub const MAIN: Part = Part(0);

The main part, which gives the entity its size. Entity::image() is part(MAIN).

Struct: Point

kis
pub struct Point {
pub x: i32,
pub y: i32,
}
pub const fn point(x: i32, y: i32) -> Point

A point in design-resolution pixels; point(x, y) builds one. Kind: const fn · Builtin: no.

Struct: Offset

kis
pub struct Offset {
pub dx: i32,
pub dy: i32,
}
pub const fn offset(dx: i32, dy: i32) -> Offset

A displacement in pixels; offset(dx, dy) builds one. Used by the camera and by motion keys. Kind: const fn · Builtin: no.

Struct: Size

kis
pub struct Size {
pub w: u32,
pub h: u32,
}
pub const fn size(w: u32, h: u32) -> Size

A size in pixels; size(w, h) is w × h. Used by Entity::set_fill_size. Kind: const fn · Builtin: no.

Struct: Insets

kis
pub struct Insets {
pub top: i32,
pub right: i32,
pub bottom: i32,
pub left: i32,
}
pub const fn insets(top: i32, right: i32, bottom: i32, left: i32) -> Insets
pub const fn uniform(n: i32) -> Insets

Distances from the four edges of a box, in pixels. insets takes CSS order: top, right, bottom, left. uniform(n) is n on every edge. Kind: const fn · Builtin: no.

Struct: Anchor

kis
pub struct Anchor {
pub x: Decimal,
pub y: Decimal,
}
pub const TOP_LEFT: Anchor = Anchor { x: 0.0, y: 0.0 };
pub const CENTER: Anchor = Anchor { x: 0.5, y: 0.5 };
pub const BOTTOM_CENTER: Anchor = Anchor { x: 0.5, y: 1.0 };

The point of an entity that sits at its position, as fractions of the entity’s own size, 0.0..=1.0. TOP_LEFT is the top-left corner (the spawn default), CENTER the centre, BOTTOM_CENTER the middle of the bottom edge (usual for character sprites). Scale and rotation pivot on the anchor.

Struct: Angle

kis
pub struct Angle {
pub degrees: Decimal,
}
pub const fn degrees(d: Decimal) -> Angle

A rotation, clockwise; degrees(d) is a rotation of d degrees. Kind: const fn · Builtin: no.

Struct: Pose

kis
pub struct Pose {
pub position: Point,
pub scale: Decimal,
pub rotation: Angle,
}
pub const fn pose(position: Point, scale: Decimal, rotation: Angle) -> Pose

Where an entity is: its position, scale and rotation, as the entity’s properties hold them; pose(position, scale, rotation) builds one. Used by Entity::travel. Kind: const fn · Builtin: no.

Colour

Struct: Color

kis
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}

An sRGB colour with alpha.

rgb(r, g, b), rgba(r, g, b, a), hex(rgb)

kis
pub const fn rgb(r: u8, g: u8, b: u8) -> Color
pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Color
pub const fn hex(rgb: u32) -> Color
  • rgb returns an opaque colour (alpha 255); rgba takes alpha explicitly.
  • hex(0xRRGGBB) returns the opaque colour; bits above 0xFFFFFF are ignored. hex(0x382000) is rgb(0x38, 0x20, 0x00).
  • Kind: const fn · Builtin: no.

Constants: BLACK, WHITE, TRANSPARENT

kis
pub const BLACK: Color = Color { r: 0, g: 0, b: 0, a: 255 };
pub const WHITE: Color = Color { r: 255, g: 255, b: 255, a: 255 };
pub const TRANSPARENT: Color = Color { r: 0, g: 0, b: 0, a: 0 };

Opaque black, opaque white, and fully transparent.

Planes and flips

Enum: Plane

kis
pub enum Plane {
Background,
Stage,
Front,
OverWindow,
}

A drawing plane. The text window is drawn by the game view between Front and OverWindow. The camera and the screen filter apply to Background, Stage and Front only.

Enum: Visibility

kis
pub enum Visibility {
Shown,
Hidden,
}

Whether a Hud part is shown. A Prop<Visibility> change interpolates as a fade.

Enum: Flip

kis
pub enum Flip {
None,
Horizontal,
Vertical,
Both,
}

A mirror of an entity’s drawing; set with Entity::set_flip.

Enum: VAlign

kis
pub enum VAlign {
Top,
Middle,
Bottom,
}

Vertical placement; used by ChoiceMenu::set_align.

Shader effects

Shaders are WGSL files run by the renderer. The screen holds them as effect values that pair a shader with its arguments; std::screen::shader declares them, and std::shaders has ready-made ones. Every effect slot is optional; None is no effect.

SlotValueEffect
Screen::filterProp<Option<Filter>>recolours the Background, Stage and Front planes
Entity::filterProp<Option<Filter>>recolours the entity
Entity::mixProp<Option<Mix>>composites the entity over what is below it; None is normal source-over
Entity::maskProp<Option<Mask>>multiplies the entity’s alpha over its box
Entity::local_motionProp<Option<LocalMotion>>moves the entity around its pose, for drawing only
Entity::travela callmoves the entity to a new pose along a shader path
ImageLayer::painta layer swapgenerated content in place of an image

Tweening an effect. An effect slot is a Prop, so its change takes a tween. When the old and the new value use the same shader (and, for a local motion, the same behaviour), the tween interpolates the arguments: decimals, colours, points, sizes, angles and durations move with the tween’s easing; integers, bool and enums switch at the start. Any other change, including from or to None, switches at the start of the tween.

kis
use std::shaders::color::blur;
screen.filter().change(Some(blur(0.0))).apply_animation(instant());
screen.wait(ms(500));
screen.filter().change(Some(blur(6.0))).apply_animation(tween(ms(1500)));

Effect time. A shader sees the time in seconds since its effect started, and the time keeps running across steps while the slot keeps the same shader. See Effect time. With the animations setting off, every effect time is 0.

When a shader cannot run. kagari build checks every shader the game uses, so a broken shader does not build. A GPU that cannot run shaders of a role draws the slot as if it were None (a travel moves in a straight line, a masked transition crossfades, a paint draws nothing) and logs a warning. The logical screen is the same either way.

Struct: Screen

kis
#[builtin] pub struct Screen;

The screen a step shows, and the step’s timeline. Screen is an opaque builtin handle: a render reaches its state only through the methods below. Screens compare with == (they implement Eq); equality uses the logical screen only.

Screen::empty()

kis
#[builtin] pub const fn empty() -> Screen;
  • Returns: a screen with only the opaque BACKGROUND entity (plane Background, opacity 1.0, no image).
  • The Hud has the text window and quick menu Shown and no side image.
  • The camera has offset 0, zoom 1.0 and rotation 0.
  • The screen filter is None.
  • Every audio channel is silent with volume 1.0.
  • Kind: const fn · Builtin: yes.

A render whose output does not depend on its input is a keyframe; Screen::empty() is the usual way to write one:

kis
const fn roof_evening(_screen: Screen) -> Screen {
let mut screen = Screen::empty();
screen.background().change(BG::ROOF_EVENING).apply_animation(fade(ms(500)));
screen
}

screen.entity(id)

kis
#[builtin] pub const fn entity(&mut self, id: EntityId) -> &mut Entity;
  • id EntityId — the entity.
  • Returns: &mut Entity — the entity, spawned with default components if it is absent.
  • Kind: const fn · Builtin: yes.

Spawning

entity(id) creates the entity if it is absent, with these defaults:

ComponentDefault
plane, zStage, 0
position, anchor(0, 0), TOP_LEFT
scale, rotation1.0, 0°
opacity0.0
filter, mix, mask, local motionNone
fill, fill sizeTRANSPARENT, None (whole screen)
layersno parts, no label, no movie
flip, gateFlip::None, None

A spawned entity is invisible, so every appearance states its animation:

kis
screen.entity(HANAKO).image().change(HANAKO::SMILE).apply_animation(cut());
screen.entity(HANAKO).opacity().change(1.0).apply_animation(tween(ms(300)));

entity(id) on an id with a pending despawn cancels the despawn; the entity keeps its current values.

screen.contains(id)

kis
#[builtin] pub const fn contains(&self, id: EntityId) -> bool;
  • Returns: bool — whether entity id is on the logical screen. A despawned entity that is still fading out is not.
  • Kind: const fn · Builtin: yes.

screen.entities(plane)

kis
#[builtin] pub const fn entities(&self, plane: Plane) -> Vec<EntityId>;
  • Returns: Vec<EntityId> — the ids of the logical screen on plane, ascending.
  • Kind: const fn · Builtin: yes.

screen.despawn(id)

kis
#[builtin] pub const fn despawn(&mut self, id: EntityId);

Removes entity id from the logical screen immediately. It is still drawn until its scheduled animations end, and then removed. So a fade-out followed by despawn fades out, and the next step does not inherit the entity. Kind: const fn · Builtin: yes.

kis
screen.entity(CARD).opacity().change(0.0).apply_animation(tween(ms(500)));
screen.despawn(CARD);

screen.background()

kis
pub const fn background(&mut self) -> &mut ImageLayer {
self.entity(BACKGROUND).image()
}

The main image of the BACKGROUND entity. Kind: const fn · Builtin: no.

kis
screen.background().change(BG::ROOF).apply_animation(fade(ms(500)));

screen.hud()

kis
#[builtin] pub const fn hud(&mut self) -> &mut Hud;

The Hud the game view draws. Kind: const fn · Builtin: yes.

screen.choice_menu()

kis
#[builtin] pub const fn choice_menu(&mut self) -> &mut ChoiceMenu;

The choice menu of this step. Kind: const fn · Builtin: yes.

screen.camera()

kis
#[builtin] pub const fn camera(&mut self) -> &mut Camera;

The camera over the Background, Stage and Front planes. Kind: const fn · Builtin: yes.

screen.filter()

kis
#[builtin] pub const fn filter(&mut self) -> &mut Prop<Option<shader::Filter>>;

The colour filter over the Background, Stage and Front planes, applied after the camera; None is no filter. See Shader effects. Kind: const fn · Builtin: yes.

screen.music(), screen.ambience(channel)

kis
#[builtin] pub const fn music(&mut self) -> &mut audio::Channel;
#[builtin] pub const fn ambience(&mut self, channel: Int<0, 3>) -> &mut audio::Channel;

The music channel and the four ambience channels ambience(0) to ambience(3). See Channels. Kind: const fn · Builtin: yes.

screen.play(sound), screen.stop_sounds(fade_out)

kis
#[builtin] pub const fn play(&mut self, sound: audio::Sound);
#[builtin] pub const fn stop_sounds(&mut self, fade_out: Duration);

play plays a one-shot sound at the cursor plus its delay. stop_sounds fades out, over fade_out, every one-shot sound playing at the cursor. See Sound. Kind: const fn · Builtin: yes.

screen.replay_bgm()

kis
#[builtin] pub const fn replay_bgm(&mut self);

Restarts the music channel’s track from its start at the cursor. Without it, a track that is already playing carries over to later steps without restarting. See The same-track rule. Kind: const fn · Builtin: yes.

Timeline methods

kis
#[builtin] pub const fn wait(&mut self, duration: Duration);
#[builtin] pub const fn barrier(&mut self);
#[builtin] pub const fn at_mark(&mut self, mark: Mark);
#[builtin] pub const fn at_entry(&mut self);
#[builtin] pub const fn begin_text(&mut self);
MethodEffect
wait(d)advances the cursor by d
barrier()moves the cursor to the end of everything scheduled so far
at_mark(m)moves the cursor to the time the text reaches m
at_entry()moves the cursor back to the step entry
begin_text()starts the text reveal and the voice at the cursor

The cursor model is described in The timeline. Kind: const fn · Builtin: yes.

Struct: Entity

kis
#[builtin] pub struct Entity;

A thing on the screen: a transform, an opacity, a colour filter, a mix, a mask, a local motion, a fill and layers. The component set is fixed; studios add no components.

Kind of memberMembersChanged with
Interpolated propertiesposition, scale, rotation, opacity, filter, mix, mask, local_motion, fillchange(v).apply_animation(Tween)
Layerspart(p), image(), label(), movie()change(x) or paint(p), then apply_animation(Transition)
Layout settingsset_plane, set_z, set_anchor, set_flip, set_fill_size, gatedirect setters, not interpolable
Relative motionapply_animation(Motion)see Motion
Shader pathtravel(to, motion)see travel

Interpolated properties

kis
#[builtin] pub const fn position(&mut self) -> &mut Prop<Point>;
#[builtin] pub const fn scale(&mut self) -> &mut Prop<Decimal>;
#[builtin] pub const fn rotation(&mut self) -> &mut Prop<Angle>;
#[builtin] pub const fn opacity(&mut self) -> &mut Prop<Decimal>;
  • position is where the anchor point sits.
  • scale is a factor around the anchor; rotation is clockwise around the anchor.
  • opacity is a fraction 0.0..=1.0; spawned entities start at 0.0.
  • Kind: const fn · Builtin: yes.

entity.filter()

kis
#[builtin] pub const fn filter(&mut self) -> &mut Prop<Option<shader::Filter>>;

The colour filter over this entity; None is no filter. The filter covers everything the entity draws, after its mask and motion, in screen space. See Shader effects. Kind: const fn · Builtin: yes.

entity.mix()

kis
#[builtin] pub const fn mix(&mut self) -> &mut Prop<Option<shader::Mix>>;

How the entity composites over what is below it; None is normal source-over. Blend modes such as multiply or screen are mixes (std::shaders::mix). The entity’s opacity applies before the mix. Kind: const fn · Builtin: yes.

kis
screen.entity(TINT).mix().change(Some(std::shaders::mix::color())).apply_animation(instant());

entity.mask()

kis
#[builtin] pub const fn mask(&mut self) -> &mut Prop<Option<shader::Mask>>;

The alpha over the entity’s box: everything the entity draws in its box is multiplied by the mask, which moves, scales and rotates with the entity. A fill without a fill size covers the whole screen and is not masked. None is no mask. Kind: const fn · Builtin: yes.

entity.local_motion()

kis
#[builtin] pub const fn local_motion(&mut self) -> &mut Prop<Option<shader::LocalMotion>>;

A motion around the entity’s pose that only changes how it is drawn; None is no motion. The shader starts from the pose the entity has at each frame, tweens and Motions included, so a bobbing character can still walk. The logical position, scale and rotation do not change. A fill without a fill size is not moved. Kind: const fn · Builtin: yes.

kis
screen.entity(HANAKO).local_motion().change(Some(std::shaders::motion::bob(20.0, ms(1000)))).apply_animation(instant());

entity.travel(to, motion)

kis
#[builtin] pub const fn travel(&mut self, to: Pose, motion: shader::TransitionalMotion);

Moves the entity to to along the path of motion. Kind: const fn · Builtin: yes.

  • The logical pose becomes to at once: a later position().get() in the same render sees to.position.
  • travel schedules a tween of position, scale and rotation each, with the motion’s duration, easing and delay, plus the shader path. While the travel runs, the shader decides the drawn pose from the start pose, to and the eased progress. When it ends, the entity is at to.
  • Where the shader cannot run, the entity moves along the plain tweens: in a straight line.
  • A local motion of the entity runs on top of the travel.
  • An invalid easing is a const-evaluation error, as for a tween.
kis
use std::screen::{degrees, pose};
screen.entity(BIRD).travel(pose(point(900, 400), 1.0, degrees(0.0)), std::shaders::motion::arc(200.0, ms(1200)));

entity.fill()

kis
#[builtin] pub const fn fill(&mut self) -> &mut Prop<Color>;

A colour drawn below the parts, over the fill size. With the default fill size (None, the whole screen), an entity with only a fill is a full-screen colour plate. Kind: const fn · Builtin: yes.

entity.part(part), entity.image()

kis
#[builtin] pub const fn part(&mut self, part: Part) -> &mut ImageLayer;
pub const fn image(&mut self) -> &mut ImageLayer {
self.part(MAIN)
}

The image layer part; image() is the MAIN layer. Parts draw in ascending Part order. Kind: const fn · Builtin: part yes, image no.

Stability: Planned — auto-blink and lip sync on layered character sprites (parts that animate on their own, and lip sync driven by the voice) are not designed yet.

entity.label()

kis
#[builtin] pub const fn label(&mut self) -> &mut LabelLayer;

The text layer, drawn above the parts and the movie. Kind: const fn · Builtin: yes.

entity.movie()

kis
#[builtin] pub const fn movie(&mut self) -> &mut MovieLayer;

The movie layer, drawn above the parts. Kind: const fn · Builtin: yes · Profile: native_v0 rejects video assets at build, so only clear() builds; the native renderer draws no movies.

Layout setters

kis
#[builtin] pub const fn set_plane(&mut self, plane: Plane);
#[builtin] pub const fn set_z(&mut self, z: i32);
#[builtin] pub const fn set_anchor(&mut self, anchor: Anchor);
#[builtin] pub const fn set_flip(&mut self, flip: Flip);
#[builtin] pub const fn set_fill_size(&mut self, size: Option<Size>);
SetterEffect
set_plane(p)moves the entity to plane p
set_z(z)sets the order inside the plane; higher draws later
set_anchor(a)sets the point of the entity that sits at its position
set_flip(f)mirrors the drawing
set_fill_size(s)sets the fill’s size; None covers the whole screen

Setters take effect at once; they are not animated. Kind: const fn · Builtin: yes.

entity.gate(setting)

kis
#[builtin] pub const fn gate(&mut self, setting: Option<Setting<bool>>);

gate(Some(s)) draws the entity only while setting s is true; gate(None) always draws it. Kind: const fn · Builtin: yes.

  • The handle is part of the logical screen and compares by identity, not by value. A render cannot read the setting, so the logical screen does not depend on it.
  • The engine reads the value at draw time (a deferred reference).
kis
static SHOW_CLOCK: Setting<bool> = setting(true);
const CLOCK: EntityId = EntityId(40);
const CLOCK_FACE: ImageAsset = asset("clock.png");
const fn clock_overlay(mut screen: Screen) -> Screen {
screen.entity(CLOCK).set_plane(Plane::OverWindow);
screen.entity(CLOCK).gate(Some(SHOW_CLOCK));
screen.entity(CLOCK).image().change(CLOCK_FACE).apply_animation(cut());
screen.entity(CLOCK).opacity().change(1.0).apply_animation(tween(ms(200)));
screen
}

entity.apply_animation(motion)

kis
#[builtin] pub const fn apply_animation(&mut self, motion: anim::Motion);

Plays a relative motion that ends where it started. The entity’s logical state does not change. Kind: const fn · Builtin: yes.

Drawing order

  • Planes are drawn in the order Background < Stage < Front < (text window, drawn by the game view) < OverWindow. Inside a plane, z ascends, then EntityId ascends: z is the analog of CSS z-index.
  • Inside an entity, the order is fill, parts by ascending Part (images and paints), movie, label.
  • The anchor point sits at position. The entity size is the size of the MAIN part’s image or paint, else the fill size, else the label box. Scale and rotation pivot on the anchor.
  • An entity’s effects nest, innermost first: the mask over the entity’s box, then the local motion (and travel), then the filter, then the mix with the opacity. A fill without a fill size is drawn inside the filter and the mix but is neither moved nor masked.
  • The camera applies to Background, Stage and Front only: offset translates, zoom and rotation pivot on the screen centre.
  • The screen filter applies to the same three planes, after the camera.

Struct: Prop

kis
#[builtin] pub struct Prop<T>;
impl<T> Prop<T> {
#[builtin] pub const fn get(&self) -> T;
#[builtin] pub const fn change(&mut self, value: T) -> &mut Change<T>;
}

An interpolated property. get() returns the logical value. change(v) sets the logical value at once and returns a pending Change; the change happens once it is given a tween. Kind: const fn · Builtin: yes.

prop.change(v).apply_animation(t):

  • The logical value becomes v at once, so a later get in the same render sees v.
  • The engine interpolates from the value the property has at cursor + t.delay to v, over t.duration with t.easing.
  • A later animation of the same property that starts while an earlier one is still running cuts the earlier one to its end.
  • Prop<Visibility> interpolates as a fade.
kis
screen.entity(HANAKO).position().change(point(400, 80)).apply_animation(tween(ms(1000)).ease(Easing::InOutQuad));

Struct: Change

kis
#[must_use] #[builtin] pub struct Change<T>;
impl<T> Change<T> {
#[builtin] pub const fn apply_animation(&mut self, tween: anim::Tween);
}

A pending property change; it happens only through apply_animation, which interpolates from the value at the cursor plus the delay to the new value. Change<T> is #[must_use]: a change with no apply_animation does not happen, and the statement is a warning. A change that should be immediate says so with instant(). Kind: const fn · Builtin: yes.

Layers and Swap

A layer swap behaves like a property change, with a Transition instead of a Tween: the logical content changes at once, and the transition runs from the old content to the new one at cursor + delay. clear() swaps to nothing.

Struct: ImageLayer

kis
#[builtin] pub struct ImageLayer;
impl ImageLayer {
#[builtin] pub const fn get(&self) -> Option<ImageAsset>;
#[builtin] pub const fn change(&mut self, image: ImageAsset) -> &mut Swap;
#[builtin] pub const fn paint(&mut self, paint: shader::Paint) -> &mut Swap;
#[builtin] pub const fn clear(&mut self) -> &mut Swap;
}

An image layer of an entity. Kind: const fn · Builtin: yes.

  • get() is the image shown, if any; None also when the layer shows a paint.
  • change(image) swaps the content for image.
  • paint(p) swaps the content for the generated Paint p: content of p’s size that a texture shader draws, such as a gradient or rain. It is placed, flipped and swapped like an image of that size, and as the MAIN part it gives the entity its size.
  • clear() swaps the content for nothing.
kis
use std::screen::{degrees, rgba, size};
screen.entity(RAIN).image().paint(std::shaders::texture::rain(rgba(200, 210, 255, 160), 30, 900.0, degrees(10.0), size(1920, 1080))).apply_animation(fade(ms(500)));

Struct: LabelLayer

kis
#[builtin] pub struct LabelLayer;
impl LabelLayer {
#[builtin] pub const fn change(&mut self, text: Text) -> &mut Swap;
#[builtin] pub const fn clear(&mut self) -> &mut Swap;
#[builtin] pub const fn set_style(&mut self, style: TextStyle);
#[builtin] pub const fn set_width(&mut self, width: Option<u32>);
}

The text layer of an entity. It shows a Text with its own TextStyle. change(text) and clear() swap the text; set_style sets the style; set_width(Some(w)) wraps at w pixels, None does not wrap. Kind: const fn · Builtin: yes.

Struct: Movie

kis
pub struct Movie {
pub video: VideoAsset,
pub looping: bool,
}
pub const fn movie(video: VideoAsset) -> Movie
impl Movie {
pub const fn looping(mut self) -> Movie
}

A movie and whether it loops. movie(v) plays v once; movie(v).looping() loops it. Kind: const fn · Builtin: no · Profile: native_v0 rejects video assets at build, so movies and std::system::watched cannot be used; the native renderer draws no movies and never fills the seen-movie set.

Struct: MovieLayer

kis
#[builtin] pub struct MovieLayer;
impl MovieLayer {
#[builtin] pub const fn change(&mut self, movie: Movie) -> &mut Swap;
#[builtin] pub const fn clear(&mut self) -> &mut Swap;
}

The movie layer of an entity. change(movie) swaps the movie for movie; clear() swaps it for nothing. Kind: const fn · Builtin: yes.

Struct: Swap

kis
#[must_use] #[builtin] pub struct Swap;
impl Swap {
#[builtin] pub const fn apply_animation(&mut self, transition: anim::Transition);
}

A pending layer swap; it happens only through apply_animation, which swaps from the old content to the new one with transition. Swap is #[must_use]. Kind: const fn · Builtin: yes.

kis
screen.background().change(BG::ROOF).apply_animation(fade(ms(500)));

Struct: Hud

kis
#[builtin] pub struct Hud;
impl Hud {
#[builtin] pub const fn text_window(&mut self) -> &mut Prop<Visibility>;
#[builtin] pub const fn quick_menu(&mut self) -> &mut Prop<Visibility>;
#[builtin] pub const fn side_image(&mut self) -> &mut ImageLayer;
}

What the story asks of the game view’s chrome: whether the text window and the quick menu are shown, and the side image next to the text window. The Hud is part of the logical screen. The game view reads it through Narrative::hud(); the story never reads it. Kind: const fn · Builtin: yes.

kix
s!(render = |mut screen| {
screen.hud().text_window().change(Visibility::Hidden).apply_animation(instant());
screen
});

Struct: ChoiceMenu

kis
#[builtin] pub struct ChoiceMenu;
impl ChoiceMenu {
#[builtin] pub const fn disabled_arm(&mut self, at: u32, text: Text);
#[builtin] pub const fn set_align(&mut self, align: VAlign);
}

The presentation of the choice a step shows. Kind: const fn · Builtin: yes.

  • The choice menu is step-only: it is emptied and set to Middle at every step entry, and is not part of the logical screen.
  • disabled_arm(at, text) adds a display-only arm, shown disabled at position at of the shown list (clamped). It has no value, cannot be selected and is not part of choice!, so no analysis sees it. Story code picks the render that adds it; see std::narrative.
  • set_align(align) places the menu vertically.

Struct: Camera

kis
#[builtin] pub struct Camera;
impl Camera {
#[builtin] pub const fn offset(&mut self) -> &mut Prop<Offset>;
#[builtin] pub const fn zoom(&mut self) -> &mut Prop<Decimal>;
#[builtin] pub const fn rotation(&mut self) -> &mut Prop<Angle>;
#[builtin] pub const fn apply_animation(&mut self, motion: anim::Motion);
}

The camera over the Background, Stage and Front planes, so the text window and OverWindow stay still. offset translates; zoom and rotation pivot on the screen centre. apply_animation plays a relative motion that ends where it started; it is the usual way to shake the whole scene. Kind: const fn · Builtin: yes.

kis
screen.camera().apply_animation(quake(8, 4, ms(600)));

Last updated Oct 29, 2026