v0.1.0-alpha
官网Home
docs/guide/getting-started
开始 · 5 分钟Get started · 5 min

快速开始Quick start

创建一个独立于 zenit 仓库、可以构建和运行的原生 macOS 应用。Create a native macOS app that lives outside the zenit repo and builds and runs on its own.

预计阅读 8 分钟8 min read
用 Claude Code 或其他 Agent 开发?先装上 zenit UI dev Skill。Building with Claude Code or another agent? Install the zenit UI dev Skill first.

它把这份手册、组件选型表和真实项目踩过的坑打包成 Agent 能按需加载的说明,写出的代码直接符合 zenit 的约定。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.

准备环境Prerequisites

当前版本面向 macOS,Apple Silicon 是持续验证的平台。开始前确认系统具有 Zig 0.15.2 与 Xcode Command Line Tools;只有运行端到端测试时才需要 Bun。This release targets macOS, with Apple Silicon continuously verified. Make sure you have Zig 0.15.2 and the Xcode Command Line Tools; Bun is only needed for end-to-end tests.

Terminal
zig version
xcode-select -p

创建项目Create a project

从仓库里的 templates/minimal-app 开始。它是一个完整的下游项目:Start from templates/minimal-app in the repo. It is a complete downstream project:

templates/minimal-app
minimal-app/
├── README.md
├── build.zig          # zenit.attach() + run / app steps
├── build.zig.zon      # declares the zenit dependency
├── e2e/
│   └── record-demo.ts # drives and records the app through the Harness
└── src/
    └── main.zig       # counter-button app
  1. 1
    复制模板Copy the template

    把 templates/minimal-app 复制到 zenit 仓库之外的新目录。Copy templates/minimal-app to a new directory outside the zenit repo.

  2. 2
    调整依赖路径Fix the dependency path

    模板默认 .path = "../../",只在仓库内部有效。复制后改成新项目到 zenit checkout 的相对路径(相对 build.zig.zon 所在目录),或用 zig fetch --save=zenit <url> 固定到某个发布版本。The template defaults to .path = "../../", which only resolves inside the repo. After copying, point it at your zenit checkout relative to build.zig.zon, or pin a published revision with zig fetch --save=zenit <url>.

  3. 3
    生成唯一指纹Generate a fingerprint

    不要沿用模板的 .fingerprint,否则两个项目会在 Zig 包缓存里冲突。删除这一行并运行一次 zig build,按错误提示填回生成值。顺手把 .name = .myapp 改成你的包名。Don’t keep the template’s .fingerprint — two projects sharing it collide in Zig’s package cache. Delete the line, run zig build once, and paste back the value from the error. Rename .name = .myapp while you’re there.

Terminal
git clone https://github.com/version-next/zenit.git
cp -R zenit/templates/minimal-app ./myapp
cd myapp   # then set .zenit = .{ .path = "../zenit" } in build.zig.zon
zig build

连接 zenitWire up zenit

build.zig.zon 声明依赖;build.zig 用 @import("zenit") 拿到 zenit 自己的构建 API。build.zig.zon declares the dependency; build.zig gets zenit’s own build API through @import("zenit").

build.zig.zon
.{
    .name = .myapp,
    .version = "0.1.0",
    .fingerprint = 0x8798022a7f8e220e, // replace: delete this line, run zig build once
    .minimum_zig_version = "0.15.2",

    .dependencies = .{
        // Relative to this file. Absolute paths are rejected by Zig 0.15.2.
        .zenit = .{ .path = "../zenit" },
    },

    .paths = .{
        "README.md",
        "build.zig",
        "build.zig.zon",
        "e2e",
        "src",
    },
}

下面是模板里的 build.zig 原文。它不只是 attach 一行,还包含测试开关转发、Harness 客户端安装、run 步骤与 .app 打包:Here is the template’s build.zig verbatim. It’s more than one attach call: it forwards the test switches, installs the Harness client, and defines the run step and .app packaging:

调用Call作用What it does
zenit.attach(zenit_dep, exe)给 exe 加上 ui 与 zenit_app 两个模块导入,编译 5 个 macOS ObjC 桥接,链接 Cocoa、Metal、CoreText 等系统框架Adds the ui and zenit_app module imports, compiles the five macOS ObjC bridges and links Cocoa, Metal, CoreText and the other frameworks
.@"test-mode" / .@"e2e-port"Zig 的依赖选项是隔离的,必须显式转发,zig build -Dtest-mode=true 才能到达 zenitDependency options are isolated in Zig; forward them explicitly so zig build -Dtest-mode=true reaches zenit
zenit.installHarnessClient(b, zenit_dep)把类型化的 Harness 客户端装到 zig-out/share/zenit/harness/client.ts,供 e2e/record-demo.ts 使用Installs the typed Harness client to zig-out/share/zenit/harness/client.ts for e2e/record-demo.ts
zenit.bundleApp(b, .{ ... })生成可双击的 zig-out/<display_name>.app,示例使用 ad-hoc 签名Produces a double-clickable zig-out/<display_name>.app, ad-hoc signed here

挂载第一棵 UI 树Mount your first UI tree

App.runWith 创建根 Scope、调用一次挂载函数并接管事件循环。挂载函数的签名必须是 fn (cx: *ui.Cx, scope: *ui.Scope) anyerror!*ui.Node,应用只负责返回根节点。App.runWith creates the root Scope, calls your mount function once and takes over the event loop. The mount function must have the signature fn (cx: *ui.Cx, scope: *ui.Scope) anyerror!*ui.Node; your app only returns the root node.

cx.bindState 让 Cx 持有 Counter,cx.on 把它的方法变成按钮回调;test_id 让 E2E 脚本可以按语义找到按钮。cx.bindState hands Counter to the Cx, and cx.on turns one of its methods into the button callback; test_id lets E2E scripts find the button by meaning.

构建与运行Build and run

Terminal
zig build run   # build and run the unbundled executable
zig build app   # package zig-out/My App.app (macOS)
从构建产物启动的真实 Hello Button.app(examples/hello_button,与模板同一个计数按钮):Harness 用 hand 光标连续点击三次,文本更新为 Clicked 3 times。窗口、组件和响应都来自上面的公开 API。The real Hello Button.app launched from build output (examples/hello_button, the same counter button as the template): the harness clicks three times with the hand cursor and the label reads “Clicked 3 times”. Window, widget and response all come from the public API above.

模板还自带一段录制脚本:zig build -Dtest-mode=true 后启动应用,再运行 e2e/record-demo.ts 就能得到同样的录像,详见 E2E 自动化。The template also ships a recording script: build with zig build -Dtest-mode=true, start the app, then run e2e/record-demo.ts to get the same kind of clip — see E2E harness.

zenit · 双授权Dual-licensed开源项目可按 GPL-3.0-only 免费使用;闭源或商业产品需要商业授权。Free for open-source projects under GPL-3.0-only; closed-source or commercial products need a commercial license.可联系作者:Contact the author: zongyi.xzy#gmail.com(# 换成 @) (replace # with @)zenit 5f9add5+wip 2026-09-30