Expand description
Batteries-included runner: winit windows + wgpu renderers around one
kui_core::Core per window, driving the Elm-ish loop — input becomes
UiEvents routed to App::on_event (host) or extensions by origin, then
App::view rebuilds each window’s frame.
One event loop, any number of windows (docs/adr/0004-multi-window.md).
The launcher opens the main window; a frame that declares another
(Ui::window) has the core queue a WindowCommand::Open, and the runner
opens it as a [Pane] — a window, its surface, its Core and the
per-window input state — on the same Session and the same GPU device.
App::view runs once per pane per frame, with Ui::window_name saying
which; events carry the pane’s WindowId.
Re-exports§
pub use wgpu;
Modules§
- access
- Accessibility as data (see
docs/adr/0001-accessibility-as-data.md). - anim
- Transitions: retained tweens keyed by node identity. A node that declares
NodeSpec::transitionhas its animatable spec values (sizing amounts, colors, radius, opacity, shadow) eased from whatever they were last frame toward what the view declares this frame — the inputs to layout animate, so a subtree lays out consistently every frame instead of children snapping to a target size inside a still-moving parent. - atlas
- CPU-side glyph atlas: a single RGBA page with shelf packing. Renderers
mirror it to a texture;
dirty/epochtell them when to re-upload. - audio
- The audio device behind the core’s
AudioCommands. The core queues commands as data (Core::take_audio_commands); the shell hands them here after every input dispatch and every frame, and polls finished playbacks back into the core (Core::audio_ended) so tagged ones becomesoundevents. It answers the other way too: aStopwhose handle was still playing goes back asCore::audio_truncated, since whether a sound was still running is the one thing the core cannot see, and a play the device refuses goes back asCore::audio_refused: it never starts and so never ends, so the view has to hear about it or wait forever. - calc
- Size expressions (backlog F109): CSS’s
min(),max()andclamp()over lengths and percentages, resolved by layout against the parent’s content box — the same box aPercentsizing takes its cut of. - cells
- A cell grid: what a terminal draws (backlog C20). One node holds
rows × colscells — a character, a foreground, a background, a few attribute bits — and its emission is a table walk: a glyph is looked up by character and style variant in a cache that was filled by shaping that one character once, placed atcol × cell_w, and never shaped again. So a pane whose every cell is new every frame costs the same as one that never changes, which is the property the text runs a terminal could otherwise be built from do not have (seebenches/stream.rs). - color
- cursor
- Pointer shape as declared data. A view says what the pointer is over
a node with the
cursorprop — 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: anon_clicknode with nocursoris the plain arrow, as a native button is, and so is anon_dragnode. 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 declaresPointerfor itself, so<button>is a hand in every binding without the app saying so. - deco
- Decoration lines that are not a rect (backlog K4): the wavy and dotted
underlines a text, a span or a cell asks for. A solid line is one
Solidquad, as it always was; these are runs ofQuadKind::Segment— the capsule the backend already draws for alinenode (ADR 0010) — 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
- Diagnostics as data. The misconfigurations that fail silently — a grow
weight with nothing to split against, a transition on a positional key
under a sibling list that changes, two nodes sharing one key — all look
like “the feature is broken” from the outside. The core can see them,
so it reports them the way it reports everything else: as plain data a
driver drains (
crate::Core::take_warnings). The windowed runners print them; a headless test asserts on them, or on their absence. - dialog
- File dialogs as an ask (backlog C51): the app asks for an Open, a Save
or a folder, the host shows the platform’s own dialog, and the answer
comes back as one event —
{kind:"files", paths, tag}, the payload shape a drop zone’sdropcarries (ADR 0031),pathsempty for a dialog the user cancelled. - display
- The renderer boundary: a flat list of quads in physical pixels. A backend needs exactly two abilities — draw these quads, and mirror the glyph atlas to a texture. Everything else (layout, shaping, styling) happened already.
- edit
- Editable text: retained editor state keyed by widget
Key, built on cosmic-text’sEditorso cursor motion, selection, and click-to-position all come from the same shaping truth the rest of the text stack uses. Edits arrive as data (InputEvent::Text/InputEvent::Key) routed to the focused editor; hosts read text back withCore::edit_text. - enter
- Entrance transitions: where a node’s animatable slots start from the
first frame it is seen. A transition never animates in from nowhere —
a node’s first sight snaps, so a view that wants a slide-in used to draw
the node off screen for a frame and move it on the next.
NodeSpec::enterstates that starting point as data instead: on first sight the slots it names (dx/dyfor the laid-out position, plus width, height, bg and radius in the forms the props themselves take) start there and ease to what the view declares, on the node’stransition. - env
- Host environment facts pushed into the core by the frame driver — the inbound mirror of events-as-data. The core never touches a window; the driver (runner, FFI host) reports what it knows and views read it.
- event
- Typed readings of the core’s own event payloads (backlog DX7).
- fragment
- A fragment: WGSL an app registers, validated here so a frame never sees
a source that cannot compile
(
docs/adr/0015-a-fragment-element-and-the-painter-it-is-not.md). - geom
- input
- Input handling and event production. Hit regions come from the previous frame’s layout (the standard immediate-mode trade); events leave as plain data tagged with the origin that declared them, so the runner can route to the host app or an extension without knowing what either looks like.
- key
- Stable widget identity. Keys are content-addressed hashes of the path from the root (scope keys mixed with labels or sibling indices), so the same logical widget gets the same key every frame — and scripts can reproduce a key from strings alone, with no allocation event tying identity to a slot.
- keyframes
- Keyframes: CSS
@keyframesfor a node’s animatable slots. A node withNodeSpec::keyframescycles those slots through the stops over its transition’s duration, in the transition’srepeatdirection, held back by itsdelay_ms— CSS’sanimation-*family on a kui node. - layout
- Clay-style flex layout over the flat tree, five passes:
- line
- Strokes: what a
linenode draws (docs/adr/0010-a-segment-primitive.md). - menu
- Context menus as data: what an item is, what the window has open,
and what a host has to do about the items the core cannot finish on its
own (
docs/adr/0017-selection-as-a-scope.md, decision 5). - message
- Typed messages over the plain-data payload (backlog C50).
- metrics
- The sizes the stock widgets are built from, as one struct beside the palette (backlog T2, the axis ADR 0019 scoped itself out of).
- resources
- Long-lived, host-registered resources. Slotmap keys give typed handles
with generational use-after-free protection, and convert to/from
u64(KeyData::as_ffi) so they cross the scripting boundary as plain integers with the generation check intact on the way back. - runtime
- The
Core: one window. It owns everything that survives across frames and belongs to this window alone (interaction state, scroll and edit stores, focus) plus the reusable per-frame tree — and the frame-builder state itself. Builder state living here (not in a borrowing wrapper) is what lets flat C bindings drive a frame through one opaque pointer; the RustUiis a thin safe façade. - schema
- The prop schema: the single source of truth for the per-node surface
every frontend lowers into. One
PROPSrow declares a prop’s name, wire id, value kind, apply function, and doc — and every binding interprets that row instead of restating it: - scroll
- Retained scroll state: offsets keyed by widget
Key, surviving the per-frame tree rebuild. The layout pass clamps each offset to the current content overflow, so state stays valid as content changes — and, at the same moment, records the geometry it clamped against, which is the only copy of it that outlives the frame (Core::scroll_geometry). - select
- The window’s text selection outside an editor: what a
selectablenode scopes, what a press-drag across it produces, and what a copy reads (docs/adr/0017-selection-as-a-scope.md). - session
- What a window does not own alone.
- slider
- A slider’s arithmetic (
docs/adr/0034-stock-controls-over-the-roles.md, decision 4): what value a pointer position, an arrow, a Page key or Home / End means on a node whose role isSliderand that declaredon_change. Every slider that followed the pointer did the first half of this in the app and every one that answered the keyboard did the second; none in this repo did both. - slot
- Slots: the place a host declares in its own view for an extension to
fill, with parameters in and replies out
(
docs/adr/0014-slots-an-extension-fills-in-place.md). - slots
- The animatable slots an entrance or a keyframe stop may name — width,
height, bg, radius, opacity — as one value.
crate::enter::Enter(where a node starts on first sight) andcrate::keyframes::Keyframe(a stop in a cycle) are this plus one field each; before this module the five slots were two structs with the same builders and the same parse arms, and every consumer packed them into a tween’s four lanes by hand. A sixth animatable slot is one field here, one arm inparse_field, one case inlanes— and nothing in the two structs that carry it. - spec
- Node configuration: plain data, trivially constructible from any language.
- 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_graphrenders it with ordinary primitives. - testing
- A headless driver for an
App(backlog DX11). A headless driver for anApp: aCore, a viewport, the app’s extensions, and the inputs a test needs to press its keys, click its nodes and read what it drew — through the realviewandon_event, with no window (backlog DX11). - 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
- The named colours a view paints with, derived from what the OS said —
docs/adr/0019-a-theme-derived-from-appearance-and-accent.md. - tokens
- Tokens: named colours and lengths an app declares beside the theme and
the metrics, and references a colour or length prop by name
(
docs/adr/0027-tokens-beside-the-theme.md). - tree
- Per-frame UI tree: flat arrays rebuilt every frame, capacities retained. Nodes are stored in DFS preorder (a parent always precedes its children, and preorder equals paint order), linked via first_child/next_sibling.
- ui
- The Rust frame builder: a thin safe façade over
Core’s flat builder methods (which are also the FFI surface). It never captures user state, soview(&state)andupdate(&mut state)can’t conflict. - value
- Dynamic values: the payload type for events crossing the host/extension
boundary. Everything in the IR that scripts can produce or consume is
expressible as a
Value. - widgets
- Opinionated helpers composed purely from primitives — the pattern custom widgets should follow (composition over traits, state by key), which is what keeps them reachable from scripting frontends.
- window
- Windows as data. A node can declare a chrome role (drag handle,
close/minimize/maximize button); interacting with it produces
WindowCommands that the frame driver drains and applies to the real window. A frame can declare that a window exists (Core::declare_window,docs/adr/0004-multi-window.md): the core diffs the declared set and the same queue carries theWindowCommand::Open/WindowCommand::Closethe diff produces. A declared window is aWindowKind::Normalone or aWindowKind::Popup— borderless, owned, anchored, non-activating — and a driver reports a popup dismissed the way it reports one closed (DismissReason). Host window facts flow back in throughWindowEnvonEnv. The core never touches a window — headless drivers just never drain.
Structs§
- Accel
- A keyboard shortcut, parsed out of the string an item declares.
- Access
Node - One semantic node of a frame.
- Access
Request - A request from assistive technology, delivered as
crate::InputEvent::Access. - Access
Run - 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 thanRUN_CHARScharacters are split, so indices fit the platform’s byte-sized ones. - Access
Tree - 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::announceand drained byCore::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 (seedocs/adr/0008-live-regions-and-announcements.md). - Audio
Env - 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).
- Audio
Spec - What an
audionode declares each frame (Core::audio_node). - Audio
Store - Playback bookkeeping on the session: the command queue, the tagged
playbacks awaiting their
endedevent, and theaudionodes’ 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_framehands 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 bouncebis a damping ratio of1 - b(SwiftUI’sSpring(duration:bounce:)). - Button
Event - A
{kind:"button"}event: a non-primary button anonButtonnode claimed, captured by it from press to release (backlog F105). - Buttons
- Which of the non-primary buttons a node’s
on_buttonclaims (backlog F105):Buttons::SECONDARY,Buttons::MIDDLEandButtons::OTHER(every button past the named three), or-ed together. A node declaringon_buttonclaimsButtons::ALLunless 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 aSizingholding 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_lineplus 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 (ADR 0017, decision 4). - Cell
Grid - A grid to draw: the cells in row-major order (
rows × colsof them; fewer draw as blank), the style the glyphs are shaped in (size,line_heightas the cell height,family/font), and the cursor. - Cell
Selection - A selection inside one
cellsgrid. - Cell
Store - 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
viewis 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.
- Clipboard
Marks - What the pasteboard said about the text a paste brought back (backlog
F84): 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
- Core
- Depart
Store - The departing subtrees, bounded (see
MAX_NODES). - Display
List - Drag
- A
{kind:"drag"}event: anonDragnode’s pointer capture. - Edges
- Per-side lengths: padding, borders.
- Edit
Options - Endpoint
- Enter
- Where a node’s slots start on first sight. Every field is optional: a
slot
enterdoesn’t name simply snaps as it always did. Derefs to itsSlots, soenter.bgreads 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::HOSTand the extension at indexiisOriginId(i + 1), which is what an event’s origin indexes back into. - File
Dialog - An Open, Save or folder dialog, as an app asks for one.
- File
Filter - One entry of a dialog’s file-type menu:
Imagesoverpng,jpg. Extensions are without the dot. - Float
Config - Takes a node out of flex flow: it doesn’t consume space in its parent,
sizes Grow/Percent against its anchor, is positioned by attach points,
and escapes ancestor clips unless
FloatConfig::clipkeeps 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, under every one that opened after — and takes input in the same order (docs/adr/0023-layers-stack-in-the-order-they-open.md). - Font
Features - The OpenType features a style asks the shaper for (backlog C23): up to
FontFeatures::MAXfour-letter tags with a value each —liga0 to keep a coding font from joining->,tnum1 for tabular figures in a gutter,ss011 for a stylistic set. Plain data andCopy, since aTextStyleis; the spelling every binding shares isFontFeatures::parse’s. - FontId
- A registered font (
Core::add_font_data/add_system_font), used throughTextStyle::font. - Fragment
Draw - What a
QuadKind::Fragmentquad points at: which registered WGSL paints it, and the sixteen numbers that frame passes it. - Fragment
Draw Id - Where a node’s
Drawlives in the frame’sFragmentList. - Fragment
Id - A registered WGSL fragment function (
Core::add_fragment), drawn by afragmentnode (docs/adr/0015-a-fragment-element-and-the-painter-it-is-not.md). - Fragment
List - The frame’s fragment draws, one per
fragmentnode, indexed by theFragmentDrawIdthe node’sNodeContentcarries. - Fragment
Ref - What a
fragmentnode names: the function, and the image it reads throughkui_sampleif it declared one (backlog V1, ADR 0025 decision 7). Every fragment door takesimpl Into<FragmentRef>, so a bareFragmentIdis the no-image form andid.with_image(img)the other; nothing else about the node changes. - Frame
Cause - Why a frame was drawn: every reason that reached the window between
the start of the last frame and the start of this one (backlog F111).
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. - Frame
Holder - One thing that holds an owed frame, named for a person: see
OwedBy. - Frame
Request - Where a frame was asked for: a
Core::request_framecall, or one the core makes for itself. - Frame
Sample - One frame’s cost in milliseconds, split by phase.
- Frame
Stats - Fixed-size ring of recent frame samples, and the count of every frame ever pushed through it.
- Handles
- How a binding spells the handles inside a readback — a node key, a
resource id — when a shape crosses as a
Value(backlog AR1). The shape is the core’s; the spelling of a 64-bit handle is not, because a JS number cannot hold one and a Lua integer can: Node writes sixteen hex digits, the way itskey/font/soundarguments already read, and Lua writes the integer itskeyarguments already are. C reads the structs and never sees aValue. - Hover
- A
{kind:"hover"}event: anonHovernode entered or left. - ImageId
- Image
Opts - How an
imagenode meets the pixels it shows — the two per-node rows ADR 0025 decision 4 gives it. Carried on the node’s content rather than onNodeSpec, so a box pays nothing for a row only an image reads. - Key
- KeyLocks
- What the lock keys hold at a press: Caps Lock and Num Lock on or off.
Not a modifier held —
KeyModsis 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 (its1is 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 bindingCtrl-wneeds 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:
atresolves by position, and a slot a stop doesn’t name is left to its neighbours. Derefs to itsSlots, sostop.bgreads the slot. - Launcher
- Layout
- A
{kind:"layout"}event: anonLayoutnode’s placed rect. - LineId
- Index into the frame’s line list.
- Line
Store - The frame’s strokes, and the previous frame’s while an
exitneeds it. - Locale
- A language tag as the host reports it —
"en","en-US","zh-Hans-CN". Carried inline rather than as aStringsoEnvstaysCopy: a view readsui.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). - Menu
Item - One row of a menu.
- Metrics
- The sizes the stock widgets are built from. Plain data and
Copy: a view reads it offui.metrics()and may keep or change its own copy, andCore::set_metricsmakes 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 (
minWidth: "fit",Min::FIT).FITis what lets aGrowchild keep a content floor — CSS’sflex: 1 0 auto: the tabs of an i3-style bar split the 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 (layout::fit_widths/fit_heights), so every later clamp reads one; until then it clamps like no floor at all. - Mods
- Modifier state for editing keys.
wordis Alt/Option (word-wise motion),docis the platform primary modifier (line/document-wise motion). - Name
Refs - 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 (ADR 0027 decision 4, backlog AR14)
is written once: a
$namethat resolves to nothing, or to the other kind, isNone— 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 asunknown-tokenonce the lookup’s borrow of the core is handed back (Core::warn_unknown_token). - Node
Info - One node of the last finished frame.
- Node
Spec - Full per-node configuration. This — not any Rust trait — is the contract every frontend (Rust builders, Lua, serialized UI) lowers into.
- OpRange
- Where a derived token’s steps are in
Tokens’ chain: the table owns the ops, so the token staysCopy. - Origin
Id - 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 whatCore::animatinganswers;beyond_cycles()is the same with a keyframe cycle — which never ends — left out (backlog F64). - OwedBy
- Who holds the frame the last one left owed:
Core::owed, named (backlog F111). Each list is empty when its kind incrate::Owedis false, and names what made it true when it is. - PadShorthand
- The
padshorthand family as declared — any subset of the seven names, eachNonewhen the frontend did not see it.PadShorthand::resolvedecides what a missing edge falls back to; a binding only reports what it found. - Play
Options - How to start a playback (
Core::play). - Playback
Id - 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.
- Pump
Runner - A windowed runner driven from outside: same [
Shell] asLauncher::run(input mapping, IME, clipboard, chrome, caret blink), but the host callspumpon its own cadence instead of parking inrun_app. - Quad
- Range
End - 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
- Resources
- One session’s registry. The maps are secondary to 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 anonScrollnode. - Scroll
Geometry - 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_layoutreports. - Scroll
State - 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_activecolours, 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.
anchoris where the press landed andfocusis 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
Corejoins (Core::new_in(&session)). - Session
Id - Which
Sessiona 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 byspreadand its edge blurred overblur, painted incolorbehind the node. CSS’sbox-shadowwithout the inset and multi-shadow forms. - Shared
Audio - A window’s handle to the session’s audio store —
Core‘saudiofield. 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. Theaudionodes’ mounts are per window inside it (see the module doc), which is why the readers here take one. - Shared
Resources - A window’s handle to the session’s resource registry —
Core’sresourcesfield. 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 throughCore::play, anaudionode, orNodeSpec::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
lineis drawn: a width, a colour, and whether the points are the corners of a polyline or the knots of a curve through them. - System
Env - 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:
appearanceandaccentderive the theme (ADR 0019), 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. - System
Font - 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 (backlog F97).
What
Core::system_fontslists, 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.
byteis 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 aline.lineis the visual row within the node, 0-based, counted across every run the key covers by where the rows sit: alinerow 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, which is what it was until backlog AR30, and not the ordinalrole="line"node a pointer event’slinenames (that one counts rows of the editor, this one rows of the text asked about). - Text
Input - A
{kind:"text"}event: what a focused key sink or editor was given to insert. - Text
Metrics - 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 countis the end of the run). - Text
Style - 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 offui.theme()and may keep, mutate or replace its own copy. - Token
Lookup - 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_tokenswhole; each call replaces the caller’s table. - Transition
- How a node’s animatable values move when the view changes them.
- 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
- Vec2
Offset - Plain offset pair (kept separate from geometry to stay
Copy+ FFI-flat). - Waker
- A handle into the event loop that any thread may hold:
wakeasks 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). - Warning
- A silent misconfiguration the core noticed while finishing a frame.
- Window
Config - What a frame says about a window it declares (
Core::declare_window). Plain data by ADR 0004 decision 5 — no title, no callbacks — so aWindowCommandstaysCopyand equality is derived, which is how the diff tells two declarations of one name apart. - Window
Env - What the host knows about its window, pushed into
Envby 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. - Window
Id - Which OS window something belongs to: an opaque integer the core’s
declaration diff assigns when it opens a window, not a handle an app
builds.
WindowId::MAINis 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 the events refer to the surface that string opened.
Enums§
- Access
Action - What assistive technology can ask of a node. Each node advertises the
subset it supports (
AccessNode::actions), and a request for one arrives ascrate::InputEvent::Access. - Align
- Where children sit along an axis, and where a float attaches.
- Appearance
- The OS light/dark setting.
Unknownis 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 (backlog F48).
Listeningis “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 (ADR 0016 measures its cache from there).Noneis “the bridge is up and nobody has asked”;Unknownis “there is no bridge” — a headless core, a driver built without theaccesskitfeature, a C host that never called the setter. - Audio
Command - An audio intent for the frame driver. Durations are ms; volumes are linear amplitude. Drivers ignore playbacks they no longer hold.
- Audio
Device - The output device’s state.
Closedis the default and what a headless driver reports;Openingis the ~90 ms the open takes on its own thread;Failedis a device that refused to open, after which commands are dropped. - Bound
- What a
minWidth/maxWidth/minHeight/maxHeightdeclares: 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 (backlog F109). Until then a calc bound clamps like none, as a percentage clamp does in CSS’s intrinsic sizing. - Button
Phase - Which part of a held non-primary button an event reports (backlog F105).
- Cell
Cursor - 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 —
liftanddarkenareColor::mixtoward white and black,raiseisTheme::raise(toward the front of whichever base is in effect),alphaisColor::with_alpha,mixisColor::mixtoward another token, andreadableisColor::toward_contrasttoward black or white — whichever reads on the named colour — until it clears the ratio on it. - Color
Token - A colour token: one value per base, or a recipe over an earlier token
or a theme role (ADR 0028).
ColorToken::sameis the unthemed case, and what a declaration with one colour builds; a derived one is built byTokens::derive, since its source is an index into the table that holds it. - Content
- What a node opened through
Core::open_fromholds: a box (left open for its children), a fragment (likewise), acellsgrid or a stroke (leaves, closed by the door). - Copy
Request - What asking for a copy answered (
Core::request_copy). - Cursor
Shape - 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’scursor, GTK’s names) instead of interpreting it. - Devtools
Dock - Where the panel sits. The header has a button per placement, and
Ctrl+Shift+Dwalks them inDock::ALL’s order. - Dir
- Dismiss
Reason - Why a window was asked to go away (
Core::dismiss_window): the same two reasons ADR 0003 gave a modal node, one level up. - Drag
Phase - 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.
- File
Dialog Mode - What a dialog picks.
- Float
Anchor - What a floating node is positioned against.
- Font
Family - Fragment
Image - Where a fragment’s
imagerow 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 aQuadKind::Texturequad 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 (backlog DX20).
- Hover
Phase - Which half of a hover an event reports.
- Image
Backing - Where a registered image’s pixels are kept for drawing
(
docs/adr/0025-the-image-is-the-canvas.md, decision 2). 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. - Image
Fit - The
fitrow: 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. - Input
Event - KeyCode
- A physical key press: the full keyboard, decoupled from any windowing
library.
EditKeyis 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.codestays what the key is — the keypad’s1isChar('1'), its Enter isEnter— 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 matchesphase. - Layout
Script - Which alphabet the layout a press was typed on writes, as the platform answers it: what decides whose ASCII a keymap matches (backlog F115).
- Live
- How urgently a reader should read a change it was not asked to read:
ARIA’s
aria-live, AccessKit’sLive. Declared on the node holding the text (liveprop) and, for a one-off with no node behind it, the politeness of aAnnouncement. Seedocs/adr/0008-live-regions-and-announcements.md. - Menu
Action - What choosing an item leaves for the host to do, drained with
crate::runtime::Core::take_menu_actionsthe way window and audio commands are. - Menu
Role - What an item means, as far as anything outside the app is concerned.
- Message
Error - Why a payload is not the message it was read as.
- Motion
Pref - The OS reduce-motion setting:
Reducedis “the user asked for less animation”,Fullis “the user did not”,Unknownis “nobody asked the OS”. Spelled as what the user wants rather than as areduce_motionboolean because the third reading has no place in a boolean, and a missing answer is not the same as a “no”. - Mouse
Button - 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.
- Node
Kind - What kind of node a snapshot row is.
- Option
AsAlt - Which Option keys act as Alt on macOS (backlog F113) — 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 bindsnever 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’sOrientation). Derived from the container’sdirand 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 (seedocs/adr/0007-composite-keyboard-patterns.md, decision 7). 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 itsdircosts a less precise announcement rather than a dead keyboard. - Overscroll
- What a scroll gesture that starts over a scroller already at its limit
does (backlog F107) — CSS’s
overscroll-behavior, spelled by theoverscrollrow (crate::schema::OVERSCROLLS, in this order). - Quad
Kind - Render
Error - A frame that produced no image, mapped from
CurrentSurfaceTexture. - Repeat
- How keyframes cycle: CSS’s
animation-direction, always infinite. - Role
- What a node is to assistive technology. Most of these a view declares
(
roleprop;schema::ROLESis that list, and the wire order); the ones the core derives from a node’s content and behaviour instead areschema::DERIVED_ONLY, which says what derives each. Every variant is on one list or the other —schema’severy_role_is_declarable_or_derivedfails when a new one is on neither. - Sampling
- The
samplingrow: how a backend reads texels between pixel centres. - Scroll
Axes - Which axes an
on_scrollnode takes (backlog F107), spelled by thescrollAxesrow (crate::schema::SCROLL_AXES, in this order). - Scroll
Axis - Scrollbar
Mode - When a scrolling node’s bars are drawn. Spelled by the
scrollbarrow (crate::schema::SCROLLBARS, in this order). - Size
Expr - A parsed expression: lengths in logical px, percentages as fractions.
- Sizing
- TextAa
- How outline glyphs are antialiased.
- Text
Wrap - How a text node breaks lines at its width.
- Theme
Source - Where a
Core’s theme comes from, re-read at the start of every frame.Derivedis the default. - Token
Error - Why a name did not resolve.
- Token
Kind - What kind of value a token holds, and which prop slots it fits.
- Token
Ref - Where a name resolved to: a role, or an app token by index.
- Underline
Style - The shape of an underline (backlog K4): 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
- Why
- Why a one-shot playback was cut off — what
diag::TRUNCATED_PLAYBACKreports once the driver confirms the sound was still running. - Window
Button - Window
Command - A window-level intent for the frame driver, drained via
Core::take_window_commandsafter each input dispatch and each frame. Three things produce one: input on a chrome node, the declared set’s diff, and an app asking directly (Core::set_window_size,Core::focus_window,Core::push_window_command). A headless driver never drains, which is the whole of “the core never touches a window”. - Window
Kind - What kind of OS surface a declared window is
(
docs/adr/0004-multi-window.md, decision 9). - Window
Role - Role a node plays in window chrome (set via
NodeSpec::window_drag/NodeSpec::window_button). Chrome nodes never emitUiEvents — their interactions becomeWindowCommands for the driver instead.
Constants§
- ANY_
SLOT - Splits a full slot name at its last separator into (namespace, name);
a name with none has the empty namespace.
The one entry in
Extension::slotsthat means “every name the host declares under my namespace”: for an extension that learns its slots after it loads.fillmatches any declared name against it andfinishhas nothing to warn about for it (backlog K1). - DEFAULT_
TEXT_ CACHE_ BYTES - The default byte budget for the shaped-text cache (backlog C16). 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_budgetchanges 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 (backlog C19): 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 (backlog F26). A declared editor is never
evicted, however many there are: retention across absence is what the
<edit>row promises, so this is a ceiling, not a prune. - MAX_
UNDECLARED_ SCROLLS - How many undeclared scroll entries the store keeps before the longest undeclared one is dropped (backlog F26). An entry a layout resolved in the frame that just ended is never evicted, however many there are.
- 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::NONEin 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 overflowas bits: the C struct’s field, the binary wire’s payload and what theclip/scrollX/scrollYbooleans 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
- 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_withcarries one;Ui::slotcallsFill::fillat the position the host declared, andUi::finishcallsFill::finishonce the host’s view is done. - Message
Field - A type a message field can hold: to a
Valueand back. Implemented for the numbers,bool,String,Valueitself,Option(absent or null isNone) andVec;#[derive(Message)]implements it for the type it derives, so one message can carry another.
Functions§
- app
- Entry point:
kui_native::app("title").custom_titlebar().run(my_app). - full_
name namespace/name, ornamealone when the namespace is empty.- run
- split_
name
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::NONEscaled — and a backend that reads it needs no special case.
Derive Macros§
- Message
#[derive(Message)](backlog C50), with thederivefeature;kui-nativeturns it on. From a crate that depends on kui-core alone, say#[message(crate = "kui_core")]— the generated code reaches::kuiunless told otherwise.