---
title: "Overview | zenit Zig UI Docs"
description: "Build truly native macOS desktop UI in Zig. zenit folds windows, GPU rendering, text, input methods and accessibility into one clear UI model; this manual…"
url: https://ui.surf/zenit/docs
language: en
alternate_zh: https://ui.surf/zenit/zh/docs.md
alternate_es: https://ui.surf/zenit/es/docs.md
alternate_ja: https://ui.surf/zenit/ja/docs.md
alternate_ko: https://ui.surf/zenit/ko/docs.md
alternate_fr: https://ui.surf/zenit/fr/docs.md
alternate_de: https://ui.surf/zenit/de/docs.md
project: zenit v0.1.0-alpha (Zig 0.15.2, macOS)
source: https://github.com/version-next/zenit
---

# The zenit manual

Build truly native macOS desktop UI in Zig. zenit folds windows, GPU rendering, text, input methods and accessibility into one clear UI model; this manual takes you from your first window to a maintainable production app.

[Start in 5 minutes](https://ui.surf/zenit/docs/guide/getting-started)

$zig build run

**0.15.2**Zig version

**Metal**Current GPU backend

**2 tiers**Public API: ui.X and ui.<group>.X

`src/main.zig`

```zig
const std = @import("std");
const ui = @import("ui");
const App = @import("zenit_app").App;

fn mountUi(cx: *ui.Cx, _: *ui.Scope) anyerror!*ui.Node {
    return ui.text(cx, "Hello, zenit!", .{
        .font_size = cx.tokens.font_size.xxxl,
        .color = cx.tokens.color.fg_primary,
    });
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    const app = try App.init(gpa.allocator(), .{
        .window = .{ .title = "Hello" },
    });
    defer app.deinit();
    try app.runWith(mountUi);
}
```

Building with Claude Code or another agent? Install the zenit UI dev Skill first.

It packs this manual, the component decision table and real-project pitfalls into instructions your agent loads on demand, so the code it writes follows zenit conventions.

[Download the Skill.zip · 54 KB](https://ui.surf/zenit/downloads/zenit-ui-dev.zip)[Install guide](https://ui.surf/zenit/docs/guide/ai-skill)

## Learning path

Work through it once, in order (about 45 minutes), and you’ll have the whole mental model for building zenit apps on your own.

[01Run your first windowWire the dep, mount UI, build and run.10 min →](https://ui.surf/zenit/docs/guide/getting-started)[02Nodes and layoutCompose with box, stack and text.12 min →](https://ui.surf/zenit/docs/guide/ui-tree)[03Data-driven UISignal, Memo and Effect together.12 min →](https://ui.surf/zenit/docs/guide/reactivity)[04A styling systemTokens, named styles and recipes.11 min →](https://ui.surf/zenit/docs/guide/styling)

## The architecture you use

Apps depend only on the stable public layer; zenit owns platform and rendering.

LAYERS

`zenit.attach(dep, exe)` adds exactly two module imports to your executable (`ui` and `zenit_app`), then compiles the native bridges and links the system frameworks. Internal modules aren’t in your build graph at all: not “please don’t”, but “can’t”.

## More than a set of APIs

These three run through the runtime, the text stack and the tooling. Each is backed by a runnable demo and real-window evidence.

[DATA FLOWPrecise Signal updatesNo virtual-tree rebuild, no whole-tree diff. A dependency goes straight to the node that subscribed.See the animation →](https://ui.surf/zenit/docs/guide/reactivity#signal-not-diffing)[TEXT ENGINEUnicode 17 + IMEUAX #9 bidi, UAX #29 grapheme boundaries, and an end-to-end preedit / commit input path.See the conformance data →](https://ui.surf/zenit/docs/guide/text-engine)[TOOLINGReal-window E2E you can watchSemantic node lookup, a virtual cursor, Retina PNG captures and MP4s recorded straight from the drawable.See the recordings →](https://ui.surf/zenit/docs/advanced/e2e)

## Three principles

Follow them and your code stays clear while zenit is still moving fast.

**Import only from the public layer**

Use `ui.*`, `ui.<group>.*` and `zenit_app.App`. Never reach into internal directories.

**Let data drive the UI**

Persistent state lives in Signals or bound state; derive with Memo, side-effect with Effect.

**Tokens first**

Color, type, spacing and radii come from the theme; when you must go off-scale, say so with `ui.arb`.
