Rezi
Rezi is a code-first terminal UI framework for Node.js and Bun. It uses a declarative widget API, deterministic input routing, and native-backed rendering through the Zireael C engine.
Rezi is a code-first terminal UI framework for Node.js and Bun. It uses a declarative widget API, deterministic input routing, and native-backed rendering through the Zireael C engine.
Status: pre-alpha. Rezi is under active development. Public APIs, ABI details, and behavior may change between releases. It is not yet recommended for production workloads.
Focus
ui.*widget factories as the canonical API- deterministic rendering and event routing
- native-backed layout and framebuffer diffing
- explicit focus, forms, routing, and theme control
- optional JSX support through
@rezi-ui/jsx
Architecture
| Layer | Purpose |
|---|---|
@rezi-ui/core | Runtime-agnostic widget API, layout, routing, focus, forms, themes, testing hooks |
@rezi-ui/node | Node.js/Bun backend, terminal I/O, scheduling, native engine integration |
@rezi-ui/native | N-API binding to the Zireael engine |
@rezi-ui/jsx | Optional JSX runtime over the core widget API |
Getting Started
-
Install
Install Rezi and set up your first project.
-
Quickstart
Build a minimal Rezi application.
-
Widgets
Browse the widget catalog and stability tiers.
-
Templates
Review the public starter set:
minimal,cli-tool, andstarship. -
Examples
Review the curated public examples and the reference app split.
-
Benchmarks
Review the benchmark methodology and results.
Public Templates
minimal- single-screen utility startercli-tool- routed multi-screen workflow starterstarship- advanced console starter with tabs, charts, overlays, and broad widget coverage
Example Surfaces
- Repository examples:
examples/hello-counter,examples/raw-draw-demo,examples/gallery - Validation app:
examples/regression-dashboard
Core Concepts
State-Driven Rendering
Rezi applications are state-driven. You define a view function that returns a widget tree based on application state:
type State = { items: string[]; selected: number };
app.view((state) =>
ui.column({ gap: 1 },
state.items.map((item, i) =>
ui.text(i === state.selected ? `> ${item}` : ` ${item}`, {
key: String(i),
})
)
)
);State Updates
Update state with app.update(). Updates are batched and coalesced for efficiency:
app.update((prev) => ({ ...prev, selected: prev.selected + 1 }));