A high-performance GPU UI framework for Zig. Signals, style recipes, flex / grid and DevTools feel like the web; Metal rendering and a complete text and IME path ship a native app. A ReleaseSmall Hello Button.app is 1.7 MB.

Start in 5 minutes
01 / SIGNALSSignals, not a virtual DOM.0:00 / 1:53
HELLO, ZENIT

One file.
One native window.

The complete source of examples/hello_button/main.zig, and the .app it compiles to. The window footage is recorded by the E2E harness, clicking the button three times in the real window.

main.zigexamples/hello_button/
const std = @import("std");const ui = @import("ui");const App = @import("zenit_app").App; /// 样式表:具名纯函数 + 应用层自定义 recipe,与业务逻辑分离。const S = @import("styles.zig"); const Counter = struct {    n: u32 = 0,    label: ?*ui.Node = null,    buf: [32]u8 = undefined,     pub fn increment(self: *Counter) void {        self.n += 1;        const node = self.label orelse return;        const content = std.fmt.bufPrint(&self.buf, "Clicked {d} times", .{self.n}) catch return;        if (node.getText()) |old| {            var t = old;            t.content = content;            node.setText(t);        }        node.markRenderDirty();    }}; fn mountUI(cx: *ui.Cx, scope: *ui.Scope) anyerror!*ui.Node {    const allocator = cx.allocator;     const counter = try cx.bindState(Counter, .{});    const click = cx.on(Counter, counter, Counter.increment);     const root = try ui.boxStyled(cx, S.root, .{});     try root.appendChild(allocator, try ui.textStyled(cx, S.title, "Hello, zenit!"));     try root.appendChild(allocator, try ui.widgets.Button(.{        .label = "Click me",        .variant = .primary,        .size = .md,        .on_click = click,    }).mount(scope, cx));     // 应用层自定义 recipe(styles.zig 的 PanelRecipe)包住计数文本    const panel = try ui.boxStyled(cx, S.panel(.highlight), .{});    const label = try ui.textStyled(cx, S.counterLabel, "Clicked 0 times");    try panel.appendChild(allocator, label);    try root.appendChild(allocator, panel);    counter.label = label;     return root;} pub fn main() !void {    var gpa = std.heap.GeneralPurposeAllocator(.{}){};    defer _ = gpa.deinit();     const app = try App.init(gpa.allocator(), .{        .window = .{ .width = 640, .height = 480, .title = "Hello Button" },    });    defer app.deinit();     try app.runWith(mountUI);}
Hello Button
Window
640 × 480 · Metal
.app
1.7 MB · ReleaseSmall
Recorded by
E2E harness
/01
1.7MB
Hello Button .app (ReleaseSmall)
/02
51
Recorded component stories
/03
2,026
Bundled Lucide icons
/04
60fps
Debug-build interaction target
AI SKILL · FOR CLAUDE CODE / ANY AGENT

Teach your agent
to write real zenit UI.

zenit-ui-dev is an Agent Skill distilled from the zenit framework and from the history of a production macOS editor built on it: component choice, the three styling layers, Signals, native integration, screenshot self-checks, and dozens of entries that each give a pitfall, its cause and the fix. Drop it in ~/.claude/skills and your agent loads it whenever it writes zenit code.

zenit-ui-dev/
SKILL.md9.6 KB
references/
app-architecture.md7.2 KB
components.md8.3 KB
macos-native.md8.2 KB
pencil-design.md7.8 KB
performance.md4.1 KB
pitfalls.md8.5 KB
project-setup.md8.0 KB
state-reactivity.md7.8 KB
styling.md5.8 KB
ui-tree-layout.md6.1 KB
verification.md5.7 KB
tools/
design_diff.ts20.6 KB
png.ts3.5 KB
shot.ts3.7 KB
Unzip into
~/.claude/skills/zenit-ui-dev/
Pencilpen.dev
RECOMMENDED WORKFLOW · PENCIL + SKILL
Pair it with Pencil: design, then build with AI

We recommend designing in Pencil and letting your agent build it with this Skill. Flex layout, spacing, radii, type sizes and lucide icons in a .pen file sit close to zenit’s model; the Skill includes a field mapping and a design_diff tool so the agent ports by the numbers rather than by eye.

  1. 01.penPencil design
  2. 02MCPAgent reads exact values
  3. 03zigzenit code from widgets + tokens
  4. 04diffNumeric diff against the design
01 / CAPABILITIES

Native from
window to pixel.

No WebView, no virtual DOM. The UI tree emits a flat DisplayItem list consumed directly by the Metal renderers.

Metal GPU rendering

render · gpu

Triple-buffered SDF, text and image renderers; GPU completion overlaps CPU layout.

LabelCount ← dirtyButtonBox

Fine-grained Signals

Signal · Memo · createEffect

No tree rebuilds, no diffing. A dependency reaches exactly the nodes that read it.

baselinex-height
Aa字ع

Text & IME

text · text_core

Unicode 17, UAX #9 bidi, UAX #29 grapheme boundaries, and end-to-end preedit / commit.

Click megetByRole("button")

Real-window E2E

ui.devtools · harness

Semantic locators, a virtual cursor, Retina screenshots and drawable-level MP4. DevTools included.

02 / COMPONENTS

51 components,
every pixel on the GPU.

Browse all components
zenit components: buttons, inputs, select, switches, checkboxes, radios, slider, progress, tabs, calendar, steps, table, alerts, tags, badges, chips, timeline, tree, accordion, rate
Not a mockup: this is the Component Wall story in Storybook, captured from a real window by the E2E harness. Every tile can be clicked, typed into and scrolled.
03 / ARCHITECTURE

Your app imports
two modules.

Platform, rendering and text live below. The boundary is enforced at build time: a forbidden import fails to compile.

error:import of 'render' is forbidden from L0
your appL0
ui + zenit_apppublic · L1
system_sdkrendergputext
text_coreicon_ir
NSWindow · CAMetalLayer · CoreTextmacOS
04 / PERFORMANCE
60fps
0 ms16.6 ms / frame1 s

The Debug-build target for basic interactions, including scrolling, cursor movement and typing in virtual lists with tens of thousands of rows. M-series Apple silicon.

01Triple-buffered instances; frame sync overlaps GPU with CPU layout
02Display list with subtree caching: static subtrees skip layout and render
03layout_isolation boundaries cut dirty cascades
04A deferred scheduler chunks heavy work across frames
From chapter 08 of the film: hover and a spinner dirty only their own subtree, the rest replays from cache; when nothing changes, zenit lowers the frame rate as far as it can. Measured on M4 Max · 5K · 60 Hz.
05 / QUICK START

Three steps to
your first window.

Get the template01
git clone https://github.com/version-next/zenit.git
cp -R zenit/templates/minimal-app ./myapp

Ships with build.zig, build.zig.zon and src/main.zig.

Wire the dependency02
zenit.attach(zenit_dep, exe);

One call wires ui, zenit_app, the native bridges and frameworks.

Build and run03
zig build run
zig build app

Run directly, or produce a double-clickable macOS .app.

06 / STATUS

Honestly, it is
not ready yet.

0.1.0 is the first public release, but the API can still change before 1.0. Pin an exact version; every breaking change is recorded in MIGRATION.

How zenit is built

Most of zenit’s code, docs and tests are written with AI coding agents. Architecture, review and acceptance are done by a person. Because of that we don’t take “it compiles and looks right” as evidence. CI runs about 2,700 deterministic tests, an allocation-failure campaign that fails every allocation in turn, tests on a real Metal device, real-window E2E with pixel comparison, and module-boundary checks. If you find a bug or a design problem, please open an issue: concrete reports are the most useful thing you can send.

macOS · Apple Silicon
NSWindow + Metal: the only continuously tested platform
Supported
Linux · Windows
Backends are stubbed; not yet usable
Planned
Accessibility
The a11y tree and NSAccessibility bridge exist, but 0 of 61 components have passed VoiceOver acceptance. Do not ship where accessibility is required.
Not supported
Public API
Breaking changes allowed before 1.0, each recorded in MIGRATION; frozen at v1.0.0
pre-1.0
07 / SHOWCASE

See it in
a real app.

Existing projects from the community, recorded in real windows.

Open the showcase
08 / BUILT WITH ZENIT

An open framework.
Your idea next.

Partners are already building an infinite-canvas design tool, a code editor IDE, a video downloader… One set of nodes, styles and native capabilities, carrying very different products.

In development by a partner
Infinite-canvas design tool

Zoom, drag and multi-select on the GPU, with liquid-glass chrome floating over the canvas.

GPU canvasGlassBoxmagnify
In development by a partner
Code editor IDE

Virtualized large files, a full IME path, multi-window palettes and native menus.

VirtualListIMEmulti-window
In development by a partner
Video downloader

Background jobs with live progress, and finished files dragged straight into Finder.

workersProgressdrag-out
Next
Your idea

The framework is open-ended. Start with one window and build the Mac app you have in mind.

Start building
OPEN SOURCE · NOW RECRUITING

Obsessed with UI
performance and motion? Join us.

Designer or developer: if a dropped frame, a caret one tick late or an easing curve that feels off bothers you, you are who we are looking for. Help us make zenit faster and nicer to use.

DesignersComponent visuals, motion curves, interaction details
DevelopersRendering, layout, the text engine and performance