kui is a UI library for Rust. You describe what is on screen as a tree of
boxes and text; kui lays it out, draws it, and hands back what the user did
as plain data. Underneath is a clay-style flat-array layout solver, on top
an iced-style view / on_event loop, and text shaping is part of the
core. Because a frame is data all the way down, Lua, C and Node bind to
the same contract the Rust builders use.
Kit also supports native presentations as code
in Lua/Teal and TSX: interactive content, reveals, private presenter views
and PNG export. Theme presets accept the project's fonts, colors and sizes.
Try kui run addons/kit/samples/presentations -- --presenter.
| crate | role | |
|---|---|---|
kui-native |
The crate most apps use: a window (winit), the GPU renderer, the stock widgets and the App trait |
crates.io · docs.rs |
kui-core |
The bindable contract: the flat per-frame tree, the flex solver, the text stack (cosmic-text + a glyph atlas), events as data, resources, the quad display list | crates.io · docs.rs |
kui-wgpu |
The wgpu backend: one instanced pipeline (rounded rects, borders, glyphs), one draw call per frame | crates.io · docs.rs |
kui-value |
Plain data on no kui core: Value, its JSON reader, the message conversions, Lua conversions behind lua; re-exported by kui-core |
crates.io · docs.rs |
kui-channel |
The data channel: named, typed columns one handle names, read from any thread, filtered, sorted and laid on lanes in Rust; re-exported by kui-core |
crates.io · docs.rs |
kui-trace |
The recording format: its reader and writer, the kui-trace tool (dump, stats, convert, diff, synth) and, behind lua, a recording as channels |
crates.io · docs.rs |
kui-derive |
#[derive(Message)]: an enum that travels through the frame as data and comes back typed |
crates.io · docs.rs |
kui-lua |
Lua extensions via mlua: scripts return table trees and receive events as tables | crates.io · docs.rs |
kui-ffi |
The C API (a cdylib, a staticlib on request, plus include/kui.h): flat builder calls, opaque KuiValue payloads, repr(C) draw data, a windowed runner via callbacks, and CExtension, a C shared library as a guest in another host's frame |
crates.io · docs.rs |
kui-node |
The Node.js addon (napi-rs) behind the @qxuken/kui npm package: JSX views lowered into the IR in one call per frame, Elm-style messages as data. Ships through npm, not crates.io |
packages/kui |
cargo add kui-nativewhich writes the one line a project needs:
[dependencies]
kui-native = "0.1.0-alpha.79"Every release so far is an alpha. A requirement like "0.1.0-alpha.34"
is a floor that admits every later alpha; Cargo.lock keeps the version
you tested, and "=0.1.0-alpha.34" pins it in the manifest.
macOS and Windows need nothing beyond a Rust toolchain. On Linux the build
wants pkg-config and ALSA's headers (libasound2-dev on Debian and
Ubuntu). A window loads the rest at run time: libxkbcommon (plus
libxkbcommon-x11 on X11), the X11 client libraries (libX11,
libXcursor, libXrandr, libXi) or libwayland-client, and
libvulkan with a driver or libEGL. A missing one fails when the window
opens, with the library's name in the error. File dialogs go through the
XDG desktop portal; without one on the session bus, every dialog answers
as if cancelled.
The first build takes a few minutes: it compiles a GPU renderer.
From C or Odin there is nothing to build: each release on
GitHub carries, for each of
linux-x64, linux-arm64, darwin-arm64 and win32-x64,
kui-ffi-<version>-<platform>.tar.gz, that platform's libkui_ffi with
the windowed runner, shared and static, and
kui-ffi-core-<version>-<platform>.tar.gz, the library without it for a
host that brings its own window, shared only (.zip for win32-x64).
Each carries kui.h, the Odin package and a README.md with the link lines.
The whole of kui in one program. An app is a type with a view that
declares the frame from scratch, and a launcher opens a window around it.
use kui_native::{App, TextStyle, Ui};
/// The app is any type. It holds the state; this one has none yet.
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)
}Put that in src/main.rs and cargo run. From a checkout of this
repository it is cargo run -p kui-native --example tutorial_01_hello.
That program is step one of the kui book:
ten short chapters, each the last plus one concept (layout, messages,
controls, lists, keys, floats, motion, effects, a test), and each a
program under examples/rust/tutorial. Read it
first.
The checkout pins Node in .node-version, Rust in rust-toolchain.toml
and the fuzz nightly in fuzz/rust-toolchain.toml. mise reads those files;
the remaining build and release tools are in mise.toml, with downloads
and checksums for the four supported platforms in mise.lock.
mise install --locked
mise run bindings-setup
mise run test
mise run release-prepUse mise exec -- <command> without shell activation. The C compiler,
platform SDK and system libraries still come from the machine; see
releasing for the native verification prerequisites.
To change a tool, update its version file and run
mise lock --platform linux-x64,linux-arm64,macos-arm64,windows-x64.
CI uses the same files in locked mode.
- The kui book: the path in, one concept a chapter, every code block pulled from a runnable program. Its source is docs/book.
- API reference on docs.rs: kui-native, kui-core, kui-wgpu, kui-derive, kui-lua, kui-ffi.
- docs/howto.md: "How do I…", about twenty questions a developer arrives with, two sentences each and a pointer.
- docs/props.md: every prop, element, event, warning, theme role and metric, with its JSX, Lua, C and Odin spelling in the same row. Generated from the schema, so it cannot drift.
- examples/README.md: the map of every example in Rust, C, Lua, Node and Odin, what each shows and how to run it.
- docs/guide.md: testing without a window, the devtools panel, the same app from Node, Lua and C, and the reference documents in detail.
- docs/design.md: the design notes (one schema for every binding, events, focus, modals, transitions, text, windows, audio, the C ABI) and the layout solver pass by pass.
- docs/performance.md: the benchmark table and what it says, editing latency, frame pacing.
- docs/releasing.md: the registries, how a release is cut, CI, the smoke rounds and the audits.
- docs/status.md: what v0 does not do, by area.
- docs/adr: design records, the decisions that are hard to reverse and would look arbitrary without their context.
- CHANGELOG.md: per release, what was added and, separately, what an app can delete.
- packages/kui: the Node package,
@qxuken/kui: JSX views, an Elm-styleupdate, a headlesscreateAppand the same devtools.
MIT, see LICENSE.