Skip to main content

Crate kui_native

Crate kui_native 

Source
Expand description

The windowed kui runner: a winit window and a wgpu renderer around kui_core, with the App trait an application implements.

kui is a Rust UI library whose view is a plain data tree rebuilt every frame. kui_core holds the model, the layout and the widgets, kui_wgpu draws them, and this crate puts a window around both; it is the crate most apps depend on. It re-exports all of kui-core, so kui_native:: reaches everything, and adds the App trait, the app launcher builder, multiple windows, the clipboard, file dialogs, audio, AccessKit and a headless testing driver. kui-derive supplies #[derive(Message)]; kui-lua, kui-ffi and kui-node are bindings over the same core.

§Quick start

use kui_native::{App, TextStyle, Ui};

struct Hello;

impl App for Hello {
    // Called once per frame. Everything on screen is declared here,
    // from scratch, every time.
    fn view(&mut self, ui: &mut Ui<'_>) {
        let theme = ui.theme();
        ui.text("Hello, kui", TextStyle::new(24.0).color(theme.fg));
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    kui_native::app("Hello").size(360.0, 200.0).run(Hello)
}

§State and events

A button carries a message. After the frame, each event it produced reaches App::on_event, and UiEvent::message reads the message back as the app’s own enum.

use kui_native::widgets;
use kui_native::{App, Message, NodeSpec, TextStyle, Ui, UiEvent};

// `derive(Message)` turns each variant into plain data on the way out
// and back into `Msg` on the way in.
#[derive(Message, Clone, Debug, PartialEq)]
enum Msg {
    Inc,
    Dec,
}

#[derive(Default)]
struct Counter {
    count: i64,
}

impl App for Counter {
    fn view(&mut self, ui: &mut Ui<'_>) {
        let t = ui.theme();
        ui.with(NodeSpec::column().fill().center().gap(16.0).bg(t.bg), |ui| {
            ui.text(&self.count.to_string(), TextStyle::new(56.0).color(t.fg));
            ui.with(NodeSpec::row().gap(8.0), |ui| {
                widgets::button(ui, "-1", Msg::Dec);
                widgets::button(ui, "+1", Msg::Inc);
            });
        });
    }

    fn on_event(&mut self, ev: UiEvent) {
        match ev.message::<Msg>() {
            Some(Msg::Inc) => self.count += 1,
            Some(Msg::Dec) => self.count -= 1,
            // Not ours: a resize, a focus change, a window event.
            None => {}
        }
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    kui_native::app("Counter").size(360.0, 240.0).run(Counter::default())
}

The book walks from here through controls, lists, the keyboard, floating windows, motion, effects and tests, one step per chapter.

§Where to look

  • App: the trait an app implements; view, on_event, setup, teardown.
  • app and Launcher: title, size, chrome, icon, extensions, then Launcher::run; Launcher::open gives a host that owns the loop a PumpRunner instead.
  • Ui: what view is given; Ui::with, Ui::text, Ui::window.
  • NodeSpec and TextStyle: a box’s layout, look and handlers; a text’s size, font and colour.
  • widgets: buttons, checkboxes, text inputs, selects, sliders, lists, tables and menus.
  • UiEvent: what on_event receives, with the readers on it.
  • testing: a headless driver for an App, for cargo test.
  • From kui-core: theme, anim (transitions and springs), window (several windows), message and Value (the payload behind a message), Core (one window’s runtime, for hosts and tests).

§Windows

One event loop, any number of windows. The launcher opens the main window; a frame that declares another with Ui::window opens it on the same session and GPU device, and a frame that stops declaring it closes it. view runs once per open window per frame, Ui::window_name says which ("main" for the launcher’s), and every event carries its window’s WindowId.

§Features

  • audio (default): plays sounds through kira and cpal. Off, audio commands are dropped and no audio library is linked (ALSA on Linux).
  • accesskit (default): exposes the access tree to screen readers through AccessKit. Off, the tree is still built and nothing reaches the OS.
  • derive (default): #[derive(Message)]. Off, messages are built and matched as Values by hand.
  • dialogs (default): the platform’s file dialogs through rfd (the XDG portal on Linux). Off, every dialog answers at once as cancelled.
  • smoke: honours KUI_SMOKE_FRAMES=n, which closes the window after n frames, in a release build. A debug build honours it regardless.

§Linux

Building needs pkg-config and ALSA’s headers (libasound2-dev on Debian and Ubuntu). A window loads the rest at run time: libxkbcommon (and libxkbcommon-x11 on X11); libX11, libXcursor, libXrandr and libXi on X11 or libwayland-client on Wayland; libvulkan with a driver, or libEGL. A missing one fails when the window opens, naming the library. macOS and Windows need only a Rust toolchain.

The book: https://kui-book.qxuken.dev. Repository and design records (under docs/adr): https://github.com/qxuken/kui.

Re-exports§

pub use wgpu;

Modules§

access
Accessibility as data: the semantic tree of a frame, derived from what nodes do and from the role and label props a view declares.
anim
Transitions: retained tweens keyed by node identity.
atlas
CPU-side glyph atlas: a single RGBA page with shelf packing. Renderers mirror it to a texture; dirty/epoch tell them when to re-upload.
audio
The audio device behind the core’s AudioCommands, used by the runner and by hosts that drive a Core themselves.
calc
Size expressions: CSS’s min(), max() and clamp() over lengths and percentages, resolved by layout against the parent’s content box (the same box a Percent sizing takes its cut of).
cells
A cell grid: a terminal’s screen as one node, rows × cols cells each with a character, a foreground, a background and attribute bits.
color
Color: straight-alpha sRGB with f32 channels, plus the small amount of colour arithmetic a palette needs (mixing, luminance, WCAG contrast).
cursor
Pointer shape as declared data. A view says what the pointer is over a node with the cursor prop — a button is a hand because it declared one, a handle a grab because it declared one — and the core resolves which declaration is under the pointer per frame (crate::runtime::Core::cursor_shape), which the frame driver hands to the real window. Nothing is inferred from what a node does: an on_click node with no cursor is the plain arrow, as a native button is, and so is an on_drag node. The one shape the core implies is the I-beam over an editor or a selection scope, the way every desktop marks text that can be taken. The stock button declares Pointer for itself, so <button> is a hand in every binding without the app saying so.
deco
Decoration lines that are not a rect: the wavy and dotted underlines a text, a span or a cell asks for. A solid line is one Solid quad, as it always was; these are runs of QuadKind::Segment — the capsule the backend already draws for a line node — so no backend, header or protocol learns a kind. A wave is a zigzag of short pieces whose round caps soften the corners; a dotted line is a row of zero-length pieces, which the capsule SDF draws as dots. Both are sized from the stroke the face recommends, so they scale with the text and the display.
depart
Exit transitions: a subtree the view stopped declaring, kept as a picture and played out.
diag
Warnings as data: misconfigurations the core notices, drained through crate::Core::take_warnings.
dialog
File dialogs as an ask: the app describes an Open, Save or folder dialog, the host shows the platform’s own, and the answer comes back as one {kind:"files", paths, tag} event (paths empty when cancelled).
display
The renderer boundary: a flat list of quads in physical pixels.
edit
Editable text: the retained state of every text_edit node, keyed by node Key, built on cosmic-text’s editor.
enter
Entrance transitions: where a node’s animatable slots start on the first frame it is seen.
env
Env: the host facts a frame driver pushes into the core, which a view reads back with ui.env().
event
Typed readings of the core’s own event payloads: drags, buttons, scrolls, hovers, layouts, key presses and text input.
fragment
A fragment: WGSL an app registers, validated here so a frame never sees a source that cannot compile.
geom
Plain geometry in logical pixels: Vec2, Size, Rect and Edges.
gradient
Gradients: what a box’s gradient row paints (docs/adr/0042-a-gradient-is-an-image-the-core-paints.md).
input
Input in, events out.
key
Key: stable node identity across frames.
keyframes
Keyframes: CSS @keyframes for a node’s animatable slots.
layout
The flex solver: clay-style layout over the flat tree, run by compute once per frame.
line
Strokes: what a line node draws.
menu
Menus as data: the rows of a context menu or the application menu bar, what the window has open, and what a host still has to do after a row is chosen.
message
Typed messages over the plain-data payload.
metrics
Metrics: the sizes the stock widgets are built from, one struct beside the palette.
path
Paths: what a path node draws (docs/adr/0040-a-path-is-a-mask-in-the-atlas.md).
resources
Long-lived, host-registered resources: fonts, images, sounds and fragment shaders, behind typed handles.
runtime
Core: one window’s runtime, the state machine a runner drives frame by frame.
schema
The prop schema: the one table of node props, elements, events and readings that every kui binding is generated from or checked against.
scroll
Retained scroll state: the offset of every scroll container, keyed by node Key, and the geometry the last layout resolved for it.
select
The window’s text selection outside an editor: what a selectable node scopes, what a press-drag across it produces, and what a copy reads.
session
Session: what a set of windows shares.
slider
A slider’s arithmetic: what value a pointer position, an arrow, a Page key or Home / End means on a node whose role is Slider and that declared on_change.
slot
Slots: the places a host declares in its own view for an extension to fill, with parameters in and replies out.
slots
The animatable slots an entrance or a keyframe stop may name (width, height, bg, radius, opacity) as one value.
spec
NodeSpec and TextStyle: everything a node and a text declare, as plain data with a builder.
stats
Frame timing samples for the latency graph. The core only stores data — whoever drives the frame loop (the runner, an FFI host) measures and pushes; widgets::latency_graph renders it with ordinary primitives.
testing
A headless driver for an App: clicks, keys, typed text and drags through the real view and on_event, with no window and no GPU.
text
Core-owned text stack. Shaping and line layout run through cosmic-text and are cached across frames keyed by (content, style, scale) — the layout pass measures through this cache, so shaping survives resizes and static text costs a hash lookup per frame. Rasterization feeds the shared glyph atlas; renderers only ever see positioned atlas quads.
theme
Theme: the named colours a view and the stock widgets paint with, derived from the OS’s appearance and accent.
tokens
Tokens: named colours and lengths an app declares beside the theme and references by name ($peach, $sidebar) in any colour or length prop.
tree
Tree: the per-frame flat tree the core builds, lays out and emits.
ui
Ui: the frame builder a Rust view declares its tree through.
value
Value: the plain-data payload type for everything that crosses an event or binding boundary.
widgets
Stock widgets built from the primitives: buttons, toggles, text input, select, slider, splitter, tooltips, menus, a titlebar and virtual lists.
window
Windows as data: what a frame declares about the OS windows it wants, and the commands a frame driver applies to the real ones.

Structs§

Accel
A keyboard shortcut, parsed out of the string an item declares.
AccessNode
One semantic node of a frame.
AccessRequest
A request from assistive technology, delivered as crate::InputEvent::Access.
AccessRun
One visual line (or a piece of one) of an editor’s text, with what a screen reader needs to read it by character and word and to place a caret: every character’s byte length, x position and width. A line that continues into another ends with its "\n", counted as a character of zero width. Runs longer than RUN_CHARS characters are split, so indices fit the platform’s byte-sized ones.
AccessTree
The semantic nodes of a finished frame, in tree order (a parent always precedes its descendants; the root comes first).
Announcement
One thing to say once, with no node behind it: “Saved”, “3 results”. Queued by Core::announce and drained by Core::take_announcements, the way window commands, audio commands and warnings are: an announcement is an event on a timeline, and the frame’s tree has no place to keep one.
AudioEnv
What the driver’s audio output is doing, for views to read. A fact, not a verb: nothing here lets a view close the device, which stays the driver’s decision (it closes an idle one itself, after a while).
AudioSpec
What an audio node declares each frame (Core::audio_node).
AudioStore
Playback bookkeeping on the session: the command queue, the tagged playbacks awaiting their ended event, and the audio nodes’ retained playbacks. The queue and the ids are the session’s, because the process has one device; the mounts are keyed by window as well as by node, because each is reconciled against one window’s frame (finish_frame hands in the window it finished, and only that window’s slice is diffed).
BarMenu
One menu of the bar: what the bar reads, and what drops out of it.
Bounce
How far a spring overshoots, 0 (glides in, no overshoot) to MAX_BOUNCE (rings a while): the one number that shapes a spring besides its duration. A bounce b is a damping ratio of 1 - b (SwiftUI’s Spring(duration:bounce:)).
ButtonEvent
A {kind:"button"} event: a non-primary button an onButton node claimed, captured by it from press to release.
Buttons
Which of the non-primary buttons a node’s on_button claims: Buttons::SECONDARY, Buttons::MIDDLE and Buttons::OTHER (every button past the named three), or-ed together. A node declaring on_button claims Buttons::ALL unless it says otherwise. The primary button is never in it: that one presses, drags and clicks for every node.
Calc
An expression that depends on the room, by its place in the table. Copy, so a Sizing holding one still is.
Cell
One cell: a character, its colours as 0xRRGGBBAA (a background of 0 is none, an underline colour of 0 the foreground’s), and attribute bits. Sixteen bytes, so a 200×50 pane is a 160 KB slice a frame.
CellEnd
One end of a selection in a cell grid: an absolute line (the grid’s origin_line plus the row) and a column. Absolute because a grid is one screenful of an app’s own history, so a row number means a different line after every scroll.
CellGrid
A grid to draw: the cells in row-major order (rows × cols of them; fewer draw as blank), the style the glyphs are shaped in (size, line_height as the cell height, family / font), and the cursor.
CellSelection
A selection inside one cells grid.
CellStore
The frame’s grids and the glyph tables they draw from. The frame before it is kept too, the way the text store keeps its places: a host that reads the selection from inside its own view is asking about a frame that has not been built yet.
CellsId
Index into the frame’s grid list.
Clip
The clip a node inherits: a rect, and the radii to round its corners by.
ClipboardMarks
What the pasteboard said about the text a paste brought back: the markers password managers set on a copied secret, after the convention at nspasteboard.org that 1Password, Bitwarden, KeePassXC and the macOS clipboard managers follow. Read by the driver, which owns the clipboard, and handed over with the text as InputEvent::Paste.
Color
A straight-alpha sRGB colour with f32 channels in 0.0..=1.0.
Core
One window’s runtime: the state a runner drives frame by frame.
Dash
A stroke’s dash pattern (backlog V2): a mark, a gap, a second mark and a second gap, repeated along the stroke’s length from its first point.
DepartStore
The departing subtrees, bounded (see MAX_NODES).
DisplayList
Drag
A {kind:"drag"} event: an onDrag node’s pointer capture.
Edges
Per-side lengths: padding, borders.
EditOptions
How a text_edit node behaves: its text style, whether it is a single-line field or a multiline document, and how it takes focus and paints its selection. Build one with struct update syntax from Default.
Endpoint
One end of a selection: the node whose text it lands in, and a byte offset into that node’s content (not into the scope’s).
Enter
Where a node’s slots start on first sight. Every field is optional: a slot enter doesn’t name simply snaps as it always did. Derefs to its Slots, so enter.bg reads the slot.
Env
What the host knows about the display/window. Defaults are safe for headless drivers (tests, benches) that never set anything.
Extensions
The runner’s extensions, each under the namespace the host gave it. Origins are positions here: the host is OriginId::HOST and the extension at index i is OriginId(i + 1), which is what an event’s origin indexes back into.
FileDialog
An Open, Save or folder dialog, as an app asks for one.
FileFilter
One entry of a dialog’s file-type menu: Images over png, jpg. Extensions are without the dot.
FloatConfig
Takes a node out of flex flow: it does not consume space in its parent, sizes Grow/Percent against its anchor, is positioned by attach points, and escapes ancestor clips unless FloatConfig::clip keeps it in its parent’s. It paints as a layer of its own, above the in-flow tree and every float that opened before it and under every one that opened after, and takes input in the same order.
FontFeatures
The OpenType features a style asks the shaper for: up to FontFeatures::MAX four-letter tags with a value each. liga 0 keeps a coding font from joining ->, tnum 1 gives tabular figures, ss01 1 turns on a stylistic set. Plain data and Copy, since a TextStyle is; the spelling every binding shares is FontFeatures::parse’s.
FontId
A registered font (Core::add_font_data / add_system_font), used through TextStyle::font.
FragmentDraw
What a QuadKind::Fragment quad points at: which registered WGSL paints it, and the sixteen numbers that frame passes it.
FragmentDrawId
Where a node’s Draw lives in the frame’s FragmentList.
FragmentId
A registered WGSL fragment function (Core::add_fragment), drawn by a fragment node.
FragmentList
The frame’s fragment draws, one per fragment node, indexed by the FragmentDrawId the node’s NodeContent carries.
FragmentRef
What a fragment node names: the function, and the image it reads through kui_sample if it declared one. Every fragment door takes impl Into<FragmentRef>, so a bare FragmentId is the no-image form and id.with_image(img) the other; nothing else about the node changes.
FrameCause
Why a frame was drawn: every reason that reached the window between the start of the last frame and the start of this one. Read from a view as Core::frame_cause. A set, because a frame answers everything that asked since the last one — a keystroke and the caret’s blink, a wheel and the transition it started.
FrameHolder
One thing that holds an owed frame, named for a person: see OwedBy.
FrameRequest
Where a frame was asked for: a Core::request_frame call, or one the core makes for itself.
FrameSample
One frame’s cost in milliseconds, split by phase.
FrameStats
Fixed-size ring of recent frame samples, and the count of every frame ever pushed through it.
Gradient
A box’s gradient: see the module’s notes. Built by Gradient::to, Gradient::angle or Gradient::radial, or read from plain data by parse_with.
GradientStop
One stop: a colour, and where along the gradient it sits, 0 to 1. A stop with no position is spaced evenly between its neighbours that have one, the first defaulting to 0 and the last to 1, as CSS spaces them.
Handles
How a binding spells the handles inside a readback (a node key, a resource id) when a shape crosses as a Value. A JS number cannot hold a 64-bit handle and a Lua integer can, so Node writes sixteen hex digits (Handles::HEX) and Lua the integer itself (Handles::INT).
Hover
A {kind:"hover"} event: an onHover node entered or left.
ImageId
ImageOpts
How an image node meets the pixels it shows: its two per-node rows. Carried on the node’s content rather than on NodeSpec, so a box pays nothing for a row only an image reads.
Key
A node’s identity: the hash of its path from the root. Key::ROOT is the tree’s root; Key::str and Key::index derive children.
KeyLocks
What the lock keys hold at a press: Caps Lock and Num Lock on or off. Not a modifier held — KeyMods is only what is down, which accelerators and chords compare exactly — but state a press was made under, which a terminal speaking kitty’s keyboard protocol reports and a keypad reading needs (its 1 is an End with Num Lock off).
KeyMods
Physical modifier state. Unlike Mods — which abstracts platform conventions for the input widget (word, doc) — nothing here is normalized: an app binding Ctrl-w needs to know it was Control and not Command.
KeyPress
One key press, delivered to whatever holds key focus. Carries both the binding view (code + mods) and the typing view (text), so an app can serve a modal keymap and an insert mode from the same event.
Keyframe
One stop. Every field is optional: at resolves by position, and a slot a stop doesn’t name is left to its neighbours. Derefs to its Slots, so stop.bg reads the slot.
Launcher
The windowed runner’s builder, made by app.
Layout
A {kind:"layout"} event: an onLayout node’s placed rect.
LineId
Index into the frame’s line list.
LineStore
The frame’s strokes, and the previous frame’s while an exit needs it.
Locale
A language tag as the host reports it — "en", "en-US", "zh-Hans-CN". Carried inline rather than as a String so Env stays Copy: a view reads ui.env() every frame, and a tag that allocated would allocate on every one of them.
Menu
The menu a window has open: its items, where it opened, and what it is about. One per window — opening a second closes the first, the way one selection closes the last.
MenuBar
The application menu: what a frame declares, in order (Core::declare_menu_bar).
MenuItem
One row of a menu.
Metrics
The sizes the stock widgets are built from. Plain data and Copy: a view reads it off ui.metrics() and may keep or change its own copy, and Core::set_metrics makes one the frame’s.
Min
A lower clamp on one axis: a number of logical px, or the node’s own fit size on that axis (Min::FIT, minWidth: "fit" in the bindings). FIT is what lets a Grow child keep a content floor, like CSS’s flex: 1 0 auto: tabs split a bar evenly while they fit and sit at their label’s width, scrolling, once they do not. Layout resolves it to a number in the fit pass of its axis, so every later clamp reads one; until then it clamps like no floor at all.
Mods
Modifier state for editing keys. word is Alt/Option (word-wise motion), doc is the platform primary modifier (line/document-wise motion).
NameRefs
A lookup plus the names it could not answer — the shape every by-name lowering wants (Lua’s props, a keyframe stop or an entrance in any binding, since those cross as plain data with the name still in them), so the one miss policy is written once: a $name that resolves to nothing, or to the other kind, is None — the slot is left at the row’s default, the way the prop would be if it were not declared — and the miss is remembered for the caller to raise as unknown-token once the lookup’s borrow of the core is handed back (Core::warn_unknown_token).
NodeInfo
One node of the last finished frame.
NodeSpec
Everything one node declares. This, not any Rust trait, is the contract every frontend (Rust builders, Lua, JSX, C) lowers into. Start from NodeSpec::row, NodeSpec::column or NodeSpec::table and chain builders; see the module docs for an example.
OpRange
Where a derived token’s steps are in Tokens’ chain: the table owns the ops, so the token stays Copy.
OriginId
Which frontend produced a node: 0 is the host app, extensions get 1+.
Owed
What a frame left owed, by kind: Core::owed. any() is what Core::animating answers; beyond_cycles() is the same with a keyframe cycle — which never ends — left out.
OwedBy
Who holds the frame the last one left owed: Core::owed, named. Each list is empty when its kind in crate::Owed is false, and names what made it true when it is.
PadShorthand
The pad shorthand family as declared — any subset of the seven names, each None when the frontend did not see it. PadShorthand::resolve decides what a missing edge falls back to; a binding only reports what it found.
Path
A path as an app builds one: the ops, the fill rule, and an optional stroke. The fill colour is the node’s bg; the stroke’s width and colour are the crate::line::Stroke’s (curve is ignored).
PathError
Where a d string went wrong: the byte offset and what was expected.
PathId
Index into the frame’s path list.
PathStore
The frame’s paths, and the previous frame’s while an exit needs it.
PlayOptions
How to start a playback (Core::play).
PlaybackId
One playback instance. Allocated by the core when the play command is queued, so callers get it synchronously without a driver round trip; 0 is never issued.
PumpRunner
A windowed runner driven from outside, from Launcher::open: the same runner as Launcher::run (input mapping, IME, clipboard, chrome, caret blink), but the host calls pump or pump_until on its own cadence instead of parking in the event loop.
Quad
RangeEnd
One end of the range an app is asked to fill in (Core::selection_range): the data index of the row it is in, and the byte inside that row’s own text. An end outside every virtualised row has no index — it is text the core built and can answer for itself.
Rect
Renderer
One window’s renderer: its surface, the pipelines and a GPU copy of the core’s glyph atlas.
Resources
One session’s registry. The maps are secondary to the process-wide the process-wide mint (see the module doc), so a lookup that misses is a handle this session never registered or has since removed — never somebody else’s entry.
Scroll
A {kind:"scroll"} event: the wheel over an onScroll node.
ScrollGeometry
What the last layout resolved for a scroll container: where the container landed, how big its content came out, and the offset it clamped. All logical px, in the same viewport coordinates on_layout reports.
ScrollState
A scroll view’s offsets and range (logical px).
Scrollbar
A scrolling node’s bars, per node. Every field’s default is the stock bar — the theme’s scrollbar / scrollbar_active colours, 4 px at rest and 6 px under the pointer, always drawn while the content overflows — so a binding that sets none of the four rows gets exactly what it always had. The bars are overlays and take no layout space whatever their width; the grabbable track is at least as wide as the active thumb plus its inset.
Selection
The window’s selection: a scope and two ends of it. anchor is where the press landed and focus is where the pointer is now, so the pair is directed — dragging back past the anchor selects the other way without the two swapping, which is what keeps a drag from feeling like it jumps when it crosses its own start.
Session
The font database, registries and audio store a set of windows share. Cloning one clones the handle, not the contents: that is how a second Core joins (Core::new_in(&session)).
SessionId
Which Session a registry — and so every handle it minted — belongs to. Process-wide unique, from a counter; never serialized, so the number means nothing across runs and is only ever compared or printed.
Shadow
One outer drop shadow: the node’s rounded rect, moved by dx/dy, grown by spread and its edge blurred over blur, painted in color behind the node. CSS’s box-shadow without the inset and multi-shadow forms.
SharedAudio
A window’s handle to the session’s audio store — Core‘s audio field. The process has one audio device, so the playbacks and the command queue are the session’s and not this window’s: whichever window’s driver drains the queue applies every window’s sounds. The audio nodes’ mounts are per window inside it (see the module doc), which is why the readers here take one.
SharedResources
A window’s handle to the session’s resource registry — Core’s resources field. A font, image or sound registered through one is registered for every window in the session, and draws in all of them.
Size
Slot
Which slot an extension is filling, handed to Extension::view.
SoundId
A registered sound (Core::add_sound): encoded file bytes the driver’s audio backend decodes. Played through Core::play, an audio node, or NodeSpec::click_sound / hover_sound.
Span
One styled run inside a rich-text paragraph. Spans are shaped and wrapped together as a single flow; plain data, so every frontend can build them.
Stroke
How a line is drawn: a width, a colour, and whether the points are the corners of a polyline or the knots of a curve through them.
SystemEnv
The user’s OS settings, as the host reports them. Not window facts and not display facts: things the person chose once, in a settings app, that a view is expected to honour. The core acts on two of them in one way: appearance and accent derive the theme, so the stock widgets and a <text> with no colour follow the OS — and nothing else moves. Reduced motion does not shorten an animation and a dark appearance repaints none of the app’s own colours: the view decides, because only it knows which of its colours is the background and which of its animations carries meaning.
SystemFont
One family of the font database — installed or loaded — as its faces describe it, from what the database read off each face’s tables when it was scanned: nothing is loaded or shaped to answer. What Core::system_fonts lists, one per family.
TextHit
Where a point landed in the text a keyed node drew: a byte offset and the visual row it is on. byte is a caret position: between two characters, past the last one at the end, and cosmic-text’s rule for which side of a glyph the point fell on. For a node holding several text runs the offset runs across them in tree order, the way the access tree reads a line. line is the visual row within the node, 0-based, counted across every run the key covers by where the rows sit: a line row of three inline runs is one row, a run that wrapped is as many as it wrapped to, and two runs stacked are two — not the wrapped line within one run’s buffer, and not the ordinal role="line" node a pointer event’s line names (that one counts rows of the editor, this one rows of the text asked about).
TextInput
A {kind:"text"} event: what a focused key sink or editor was given to insert.
TextMetrics
What a piece of text measures, in logical px at the current scale — the same numbers layout uses for a text node with that content and style, so a view can size a column to its widest label or pick a tier that fits without hand-tuned magic numbers.
TextPos
A position in an editor’s text: a run and a character index into it (character == char count is the end of the run).
TextStyle
How a run of text is shaped and painted: size, line height, colour, family, wrapping, line limits, OpenType features and decorations.
Theme
Every colour the stock widgets and the core’s own chrome paint with, as roles rather than values. Plain data and Copy: a view reads it off ui.theme() and may keep, mutate or replace its own copy.
TokenLookup
A frame’s view of the tokens a lowering can reference: the running origin’s table over the host’s, and the roles in front of both. Borrowed from the core for the length of a lowering (crate::Core::token_lookup).
Tokens
One origin’s declared tokens, in declaration order. Built with the chaining constructors and handed to crate::Core::set_tokens whole; each call replaces the caller’s table.
Transition
How a node’s animatable values move when the view changes them: a duration, an easing (a timed curve or a spring), and for keyframes a repeat direction and a delay. Built with Transition::ms and the builders, or through the NodeSpec shorthands (transition, easing, bounce, repeat, delay).
Turn
A path’s turn (docs/adr/0041-a-mask-turns-about-its-centre.md): how far it is turned, in turns — clockwise with y down, as Path::sector counts them — and the point it turns about, in the path’s own coordinates; None is the centre of the outline’s box. A path with a turn is boxed by the square the turn sweeps, so its mask is one mask at every angle and the quad that draws it carries the angle.
Ui
UiEvent
An event produced by the UI, ready for routing.
Unresolved
Why a derived token was dropped at declaration: the name it was given and the source or operand that resolved to no colour token declared before it and no theme role.
Vec2
A point or offset in logical pixels.
Vec2Offset
Plain offset pair (kept separate from geometry to stay Copy + FFI-flat).
Waker
A handle into the event loop that any thread may hold; Waker::wake asks for a frame from wherever the app’s data arrived. Cheap to clone, and harmless after the loop has ended (a wake nobody hears is dropped). An app gets one in App::setup, a host from PumpRunner::waker.
Warning
A silent misconfiguration the core noticed while finishing a frame.
WindowConfig
What a frame says about a window it declares (Ui::window, Core::declare_window). Plain data, no title and no callbacks, so a WindowCommand stays Copy and two declarations of one name compare by value.
WindowEnv
What the host knows about its window, pushed into Env by the frame driver. Views (e.g. widgets::titlebar) read this to adapt: reserve space for native controls, pick the maximize/restore glyph, or render nothing at all under native decorations.
WindowId
Which OS window something belongs to: an opaque integer the core assigns when it opens a window, not a handle an app builds. WindowId::MAIN is 0, the window the launcher opens, which is always live. Apps name windows with a stable string (Core::declare_window); the id is how the driver and UiEvent::window refer to the surface that string opened.

Enums§

AccessAction
What assistive technology can ask of a node. Each node advertises the subset it supports (AccessNode::actions), and a request for one arrives as crate::InputEvent::Access.
Align
Where children sit along an axis, and where a float attaches.
Appearance
The OS light/dark setting. Unknown is a real answer — a host with no way to ask says it, and a view that has one palette per appearance picks its own default for it rather than being handed a guess.
Assistive
Whether assistive technology is listening: the difference between an alert that blinks and one that announces. Listening is “an accessibility client has asked this window for its tree”, which is the one signal the platform adapters give and the moment the runner starts deriving trees. None is “the bridge is up and nobody has asked”; Unknown is “there is no bridge” — a headless core, a driver built without the accesskit feature, a C host that never called the setter.
AudioCommand
An audio intent for the frame driver. Durations are ms; volumes are linear amplitude. Drivers ignore playbacks they no longer hold.
AudioDevice
The output device’s state. Closed is the default and what a headless driver reports; Opening is the ~90 ms the open takes on its own thread; Failed is a device that refused to open, after which commands are dropped.
Bound
What a min_width / max_width / min_height / max_height declares: px, the node’s own fit size (a min only), or a size expression that layout resolves against the parent’s content box when it sizes the node. Until then a calc bound clamps like none, as a percentage clamp does in CSS’s intrinsic sizing.
ButtonPhase
Which part of a held non-primary button an event reports.
CellCursor
How the grid’s cursor is drawn, in the colour given with it.
Chrome
Who draws the window chrome.
ColorOp
One step of a derived token’s recipe, as declared: a verb and its operands, a colour named by its token or role. Each is a method the core already paints with — lift and darken are Color::mix toward white and black, raise is Theme::raise (toward the front of whichever base is in effect), alpha is Color::with_alpha, mix is Color::mix toward another token, and readable is Color::toward_contrast toward black or white — whichever reads on the named colour — until it clears the ratio on it.
ColorToken
A colour token: one value per base, or a recipe over an earlier token or a theme role. ColorToken::same is the unthemed case, and what a declaration with one colour builds; a derived one is built by Tokens::derive, since its source is an index into the table that holds it.
Content
What a node opened through Core::open_from holds: a box (left open for its children), a fragment (likewise), a cells grid or a stroke (leaves, closed by the door).
CopyRequest
What asking for a copy answered (Core::request_copy).
CursorShape
The shape the pointer takes. Spelled the way CSS and the platform toolkits do, so a driver maps it one-to-one (winit’s CursorIcon, the Web’s cursor, GTK’s names) instead of interpreting it.
DevtoolsDock
Where the panel sits. The header has a button per placement, and Ctrl+Shift+D walks them in Dock::ALL’s order.
Dir
Which way a container stacks its children.
DismissReason
Why a window was asked to go away (Core::dismiss_window): the same two reasons a modal node has, one level up.
DragPhase
Which part of a drag an event reports.
Easing
Easing curve for a Transition.
EditKey
Editing keys, decoupled from any windowing library’s key codes.
FileDialogMode
What a dialog picks.
FillRule
How a path’s inside is decided: SVG’s default, or the polygon’s rule.
FloatAnchor
What a floating node is positioned against.
FontFamily
Which face a text shapes with: one of the three stock families, or a font registered with the core.
FragmentImage
Where a fragment’s image row lands for one frame: nowhere, in the glyph atlas the fragment pipeline already has bound, or in a texture of the image’s own that the backend binds in the atlas’s place for that one quad — the same swap a QuadKind::Texture quad asks for. The core decides between the last two on the image’s backing, so a backend meets the same two cases it already draws.
Grain
What a drag-select moves by. A press sets it from the click count the driver counted, the way every text UI does: one click drags by characters, two by words, three by whole runs.
HoverBy
What moved to change the hover.
HoverPhase
Which half of a hover an event reports.
ImageBacking
Where a registered image’s pixels are kept for drawing. The core decides on the two facts that matter — whether the image fits an atlas page, and whether its pixels were ever replaced — and the app never chooses.
ImageFit
The fit row: how the pixels meet the node’s box. The box itself — its layout, its hit region, its access rect — is the same in every mode; only what is painted inside it moves.
InputEvent
KeyCode
A physical key press: the full keyboard, decoupled from any windowing library. EditKey is the input widget’s closed navigation vocabulary; this is what apps that own their own text model bind against — an editor with modal keymaps, a game, a scripted panel.
KeyLocation
Where on the keyboard a key sits, for the keys that have twins: the left or right Shift, Ctrl, Alt or Super, and the keypad’s digits, operators, Enter and (with Num Lock off) arrows beside the main block’s. Everything else is Standard. code stays what the key is — the keypad’s 1 is Char('1'), its Enter is Enter — so a keymap that does not care reads nothing new, and one that does (a terminal speaking kitty’s keyboard protocol, a game) reads this.
KeyPhase
Which half of a key’s life an event reports. Both halves arrive as one {kind="key"} payload — the way a drag’s three phases and a hover’s two do — so an app binds one handler and matches phase.
LayoutScript
Which alphabet the layout a press was typed on writes, as the platform answers it: what decides whose ASCII a keymap matches.
Live
How urgently a reader should read a change it was not asked to read: ARIA’s aria-live, AccessKit’s Live. Declared on the node holding the text (live prop) and, for a one-off with no node behind it, the politeness of an Announcement.
MenuAction
What choosing an item leaves for the host to do, drained with crate::runtime::Core::take_menu_actions the way window and audio commands are.
MenuRole
What an item means, as far as anything outside the app is concerned.
MessageError
Why a payload is not the message it was read as.
MotionPref
The OS reduce-motion setting: Reduced is “the user asked for less animation”, Full is “the user did not”, Unknown is “nobody asked the OS”. Spelled as what the user wants rather than as a reduce_motion boolean because the third reading has no place in a boolean, and a missing answer is not the same as a “no”.
MouseButton
Which button a press came from — driver-facing rather than shaped after any one windowing library, so every driver maps its own vocabulary onto this one.
NodeKind
What kind of node a snapshot row is.
OptionAsAlt
Which Option keys act as Alt on macOS — what a frame declares with crate::Ui::option_as_alt. On a Mac, Option composes: ⌥m types “µ”, and ⌥u, ⌥e, ⌥i, ⌥n and ⌥` are dead keys that start an accent and wait for the next key, so the press never arrives as a key at all and a keymap that binds <A-u> never hears it. An Option key named here is Alt instead: it composes nothing, types nothing, and every key under it arrives as a chord of the key the layout prints unmodified — what a terminal’s “Option as Meta” and an editor’s Alt bindings want. None, the default, is the Mac’s own behaviour; one side leaves the other composing, so a user keeps ü on the right Option while the left one is Alt. Other platforms have no such composition on Alt and read nothing here.
Orientation
How a container arranges its items, for the platform to announce (AXOrientation, UIA’s Orientation). Derived from the container’s dir and never declared: the layout is what arranges the items, so a row that says it is a column would be a fact with two owners. It is an announcement and not a gate — the arrows move both ways whatever this says — so a container whose visual arrangement does not match its dir costs a less precise announcement rather than a dead keyboard.
Overscroll
What a scroll gesture that starts over a scroller already at its limit does: CSS’s overscroll-behavior, spelled by the overscroll row.
PathOp
One drawing command, every coordinate absolute, in the space the path was declared in.
QuadKind
RenderError
A frame that produced no image, and what to do about it.
Repeat
How keyframes cycle: CSS’s animation-direction, always infinite.
Role
What a node is to assistive technology. Most of these a view declares (role prop; schema::ROLES is that list, and the wire order); the ones the core derives from a node’s content and behaviour instead are schema::DERIVED_ONLY, which says what derives each. Every variant is on one list or the other — schema’s every_role_is_declarable_or_derived fails when a new one is on neither.
Sampling
The sampling row: how a backend reads texels between pixel centres.
ScrollAxes
Which axes an on_scroll node takes, spelled by the scrollAxes row.
ScrollAxis
ScrollbarMode
When a scrolling node’s bars are drawn. Spelled by the scrollbar row (crate::schema::SCROLLBARS, in this order).
Side
Where a linear gradient runs to: a side or a corner of the box.
SizeExpr
A parsed expression: lengths in logical px, percentages as fractions.
Sizing
How a node sizes one axis. A plain number converts to Fixed, so .width(120.0) and .width(Sizing::Fixed(120.0)) are the same.
TextAa
How outline glyphs are antialiased.
TextWrap
How a text node breaks lines at its width.
ThemeSource
Where a Core’s theme comes from, re-read at the start of every frame. Derived is the default.
TokenError
Why a name did not resolve.
TokenKind
What kind of value a token holds, and which prop slots it fits.
TokenRef
Where a name resolved to: a role, or an app token by index.
UnderlineStyle
The shape of an underline: the face’s line, a wave under a diagnostic, dots. Where it goes and how thick it is are the face’s recommendation either way; a wave is three strokes tall around the line’s centre with a six-stroke period, dots two strokes across and four apart (crate::deco).
Value
A dynamically typed value: null, bool, int, float, string, list or an ordered string-keyed map. See the module docs for an example.
Why
Why a one-shot playback was cut off — what diag::TRUNCATED_PLAYBACK reports once the driver confirms the sound was still running.
WindowButton
WindowCommand
A window-level intent for the frame driver, drained with Core::take_window_commands after each input dispatch and each frame. Three things produce one: input on a chrome node, the diff of the declared window set, and an app asking directly (Core::set_window_size, Core::focus_window, Core::push_window_command). A headless driver never drains.
WindowKind
What kind of OS surface a declared window is.
WindowRole
Role a node plays in window chrome (set via NodeSpec::window_drag / NodeSpec::window_button). Chrome nodes never emit UiEvents — their interactions become WindowCommands for the driver instead.

Constants§

ANY_SLOT
The one entry in Extension::slots that means “every name the host declares under my namespace”: for an extension that learns its slots after it loads. fill matches any declared name against it and finish has nothing to warn about for it.
DEFAULT_TEXT_CACHE_BYTES
The default byte budget for the shaped-text cache. Sized so a screenful of code never meets it — two panes of 55 highlighted lines are ~900 short entries, a few megabytes — and a pane streaming new text meets it within seconds, which is when the clock alone let the cache reach gigabytes. Core::set_text_cache_budget changes it.
FLOAT_PRESETS
The float preset names, in wire order: the index of a name here is what the binary protocol writes for it and what KUI_FLOAT_* counts from.
LONG_LINE_BYTES
A non-wrapping text at least this long is shaped in chunks: a minified bundle, a log line with a blob in it, a base64 field. Shorter text takes the path it always took, so nothing below the line moves. Bytes, not characters, for the same reason a step line carries integers: every binding can count them.
MAX_BOUNCE
The most bounce a spring takes: at 1 it would never settle, and past 0.9 it rings for seconds.
MAX_UNDECLARED_EDITS
How many undeclared editors the store keeps before the longest undeclared one is dropped. A declared editor is never evicted, however many there are: retention across absence is what text_edit promises, so this is a ceiling, not a prune. An editor holding a short line is a few KB and one holding a long line about 22 KB, so a full budget is a few MB.
MAX_UNDECLARED_SCROLLS
How many undeclared scroll entries the store keeps before the longest undeclared one is dropped. An entry a layout resolved in the frame that just ended is never evicted, however many there are. An entry is about 64 bytes, so a full budget is about 64 KB.
NAMESPACE_SEPARATOR
What separates a namespace from a slot name in a full name. A namespace may contain it (the host chooses namespaces, and "left/fs" is a fine one); a slot name an extension lists may not, so a full name splits at its last one.
NO_CLIP
A clip that clips nothing.
NO_CLIP_ID
The entry every frame’s clip table starts with: Clip::NONE in physical pixels. Emission seeds it before any quad is made, so a quad that is clipped by nothing — most quads of most frames — names this without interning anything.
OVERFLOW_CLIP
overflow as bits: the C struct’s field, the binary wire’s payload and what the clip / scrollX / scrollY booleans OR together. One set of values so a binding cannot invent its own numbering.
OVERFLOW_SCROLL_X
OVERFLOW_SCROLL_Y
ROOT_SLOT
The reserved slot name an extension listing none fills.

Traits§

App
What a kui application implements: a view that declares each frame and an on_event that answers what the frame produced.
Extension
A frontend that draws into the shared tree each frame — the trait the runner uses to host Lua (or any other) extensions without knowing what they are. Origins are assigned by the runner.
Fill
What fills slots: the runner’s extension list, or a test’s stand-in. A frame begun with Core::frame_with carries one; Ui::slot calls Fill::fill at the position the host declared, and Ui::finish calls Fill::finish once the host’s view is done.
MessageField
A type a message field can hold: to a Value and back. Implemented for the numbers, bool, String, Value itself, Option (absent or null is None) and Vec; #[derive(Message)] implements it for the type it derives, so one message can carry another.

Functions§

app
Starts a Launcher for a window titled title.
full_name
namespace/name, or name alone when the namespace is empty.
run
app(title).extensions(extensions).run(application) in one call.
split_name
Splits a full slot name at its last separator into (namespace, name); a name with none has the empty namespace.

Type Aliases§

ClipId
An index into DisplayList::clips. Every quad has one; there is no “no clip” value, because a frame that clips nothing still names an entry — Clip::NONE scaled — and a backend that reads it needs no special case.

Derive Macros§

Message
#[derive(Message)], with the derive feature (kui-native turns it on). The generated code reaches ::kui_native unless told otherwise, so a crate that depends on kui-core alone adds #[message(crate = "kui_core")] to the enum. Derives From<Self> for Value, TryFrom<&Value>, TryFrom<Value> and MessageField for an enum or a struct; see the crate docs.