Zgui is a retained user interface framework for native Rust applications. It provides components, fine-grained reactive state, CSS styling, text layout, accessibility, and GPU rendering. It does not embed a browser and does not use HTML or JavaScript.
Zgui is under active development. Its API is not yet stable.
Caution
This project is very experimental and very AI-sloppy. You should probably not use it.
Zgui aims to combine the application model of a modern web UI with a native rendering pipeline:
- Write reusable components with declarative view syntax.
- Update only the view data that depends on changed signals.
- Use selectors, the cascade, flexbox, grid, and other CSS features for layout and appearance.
- Keep the document, layout tree, paint data, and GPU resources between frames.
- Redraw only damaged content.
- Keep the platform, text, and rendering backends replaceable.
The framework is intended for native application interfaces. It does not try to implement the web platform.
use zgui::prelude::*;
#[component]
fn Counter() -> impl IntoView {
let count = RwSignal::new(0);
view! {
column(class = "counter") {
text(class = "value") {{move || count.get().to_string()}}
control(on:click = move |_| count.update(|value| *value += 1)) {
"Increment"
}
}
}
}
const STYLE: &str = css!(
":root {
background: #111318;
color: #f2f4f8;
font-family: sans-serif;
display: flex;
align-items: center;
justify-content: center;
}
.counter { gap: 12px; align-items: center; }
.value { font-size: 48px; font-weight: 700; }
control {
padding: 8px 16px;
border-radius: 8px;
background: #356df3;
}"
);
fn main() -> Result<(), zgui::Error> {
app()
.with_title("Counter")
.with_size(360.0, 240.0)
.with_stylesheet(STYLE)
.run(|| view! { Counter() })
}Run the complete counter example from this repository:
cargo run -p zgui-examples --example counter| Guide | What it answers |
|---|---|
| Architecture | what the framework is made of, and what one frame does |
| The layering rules | what may depend on what, and what the published surface promises |
| The styling model | sheets, the cascade, and what a style change costs |
| The reactive model | signals, owners, the flush, and the three Send escapes |
Writing a Renderer |
the renderer contract, damage, and vector rasterisation |
| Building a browser on zgui | every extension point a document language needs |
Measurements rather than claims: CSS parity and performance are both generated by the test suite.
Zgui uses one retained pipeline:
components and signals
|
v
retained document
|
v
style cascade -> box tree -> layout and text
|
v
fragments, hit testing, and damage
|
v
retained paint operations -> GPU scene -> persistent render target
The view layer creates and updates a persistent document. Reactive closures update the document; they do not rebuild the full application tree on each frame. The style engine applies CSS and translates changed properties into layout or paint damage.
The layout stage uses cached box and text measurements. It rebuilds affected subtrees and produces fragments for painting and hit testing. The paint stage replays unchanged fragment operations and emits typed scene primitives for changed content.
The wgpu renderer batches those primitives. It keeps glyphs and images in atlases and composes into a persistent texture. This design permits partial redraw because pixels outside the damage region remain valid. The platform layer supplies native windows, input, clipboard access, and accessibility integration.
The main public crate is zgui. Lower-level crates define the document, style, layout, text,
scene, renderer, and platform interfaces. Applications can replace these backends without changing
their component code.
The application API takes its main inspiration from Leptos and SolidJS. Components create the view once. Signals then run small reactive closures that update the affected data instead of rerunning each component and reconciling a virtual tree.
The rendering and backend design takes its main inspiration from GPUI and Vello. Zgui owns the native window, retained scene, damage tracking, and GPU submission path. It uses Vello for vector work inside a larger renderer of its own.
Zgui also uses browser-engine components where they are useful: Stylo for CSS, Taffy for layout, and Parley for text. These are implementation libraries, not embedded runtimes.
This table compares the main data flow. It does not compare feature completeness or maturity.
| Project | Application update model | UI tree and styling | Rendering boundary |
|---|---|---|---|
| Zgui | Components initialize once; fine-grained signals update their dependents. | Retained native document; CSS with Stylo; layout with Taffy. | Own damage, scene, text, and wgpu pipeline; Vello handles vector work; no webview. |
| GPUI | Entity and context state; notified views render again; hybrid immediate/retained model. | Rust element tree with programmatic styling and layout. | Own native, GPU-accelerated renderer; no webview. |
| Iced | Elm model: state, messages, update, and view. | The view produces a widget hierarchy from current state; styling uses Rust theme/widget APIs. | Renderer-agnostic native runtime with GPU and software backends; no webview. |
| Tauri | Any web frontend; Rust commands and application state live in the core process. | Browser DOM, HTML, and CSS in an operating-system webview. | The webview renders the UI and communicates with the Rust core through IPC. |
| Leptos | Components initialize once; fine-grained signals update DOM bindings. | Browser DOM with HTML and CSS; supports client rendering, server rendering, and hydration. | The browser engine owns layout, paint, composition, and presentation. |
| Dioxus Native | Components produce a virtual DOM; dependency-aware rerenders are reconciled into mutations. | HTML/CSS document rendered by Blitz, with Stylo and Taffy. | Experimental native wgpu renderer with Vello; no webview. |
Apache-2.0