App Model
A zero-native app provides a name, a WebView source, and optional lifecycle callbacks. The runtime owns the event loop, windows, and native services; the platform owns the web engine.
The App struct
| Field | Type | Description |
|---|---|---|
context | *anyopaque | Pointer to your app state (required) |
name | []const u8 | App name used in traces and automation snapshots (required) |
source | WebViewSource | Initial WebView content (required) |
source_fn | ?fn(*anyopaque) !WebViewSource | Dynamic source resolver (overrides source when set) |
start_fn | ?fn(*anyopaque, *Runtime) !void | Called after the runtime starts and the first window is loaded |
event_fn | ?fn(*anyopaque, *Runtime, Event) !void | Called on every runtime event (lifecycle + commands) |
stop_fn | ?fn(*anyopaque, *Runtime) !void | Called before the runtime shuts down |
All callback fields are optional. A minimal app only needs context, name, and source.
WebViewSource
Three constructors for specifying what the WebView loads:
.html(content)-- inline HTML string, served aszero://inline.url(address)-- load a remote or local URL.assets(options)-- serve a local file tree through a custom origin
The assets constructor takes a WebViewAssetSource:
.source = zero_native.WebViewSource.assets(.{
.root_path = "dist",
.entry = "index.html", // default
.origin = "zero://app", // default
.spa_fallback = true, // default
}),| Field | Default | Description |
|---|---|---|
root_path | required | Path to the directory containing frontend assets |
entry | "index.html" | HTML entry point within the root path |
origin | "zero://app" | Origin used for asset URLs |
spa_fallback | true | Serve entry for unknown routes (SPA mode) |
Lifecycle events
The runtime dispatches LifecycleEvent values through your event_fn:
start-- the app has started and the initial source is loadedframe-- a frame has been requested (for animations or state updates)stop-- the app is shutting down
The runner pattern
The generated src/runner.zig wires the runtime with platform services:
- Selects the platform (macOS, Linux, or null for headless tests)
- Sets up trace sinks (stdout + file) via
FanoutTraceSink - Installs panic capture so crashes write
last-panic.txt - Initializes window state persistence from
windows.zon - Creates the
Runtimewith all options and callsruntime.run(app)
var runtime = zero_native.Runtime.init(.{
.platform = my_platform,
.trace_sink = fanout.sink(),
.bridge = my_app.bridge(),
.builtin_bridge = .{ .enabled = true, .commands = &builtin_policies },
.security = .{
.permissions = &app_permissions,
.navigation = .{ .allowed_origins = &.{ "zero://app" } },
},
.js_window_api = true,
.window_state_store = state_store,
.automation = if (build_options.automation) automation_server else null,
});
try runtime.run(my_app.app());RuntimeOptions
| Field | Type | Default | Description |
|---|---|---|---|
platform | Platform | required | Platform abstraction (macOS, Linux, or NullPlatform) |
trace_sink | ?trace.Sink | null | Destination for structured trace records |
log_path | ?[]const u8 | null | Path for persistent log file |
extensions | ?ModuleRegistry | null | Extension modules with lifecycle hooks |
bridge | ?BridgeDispatcher | null | App-defined bridge commands and handlers |
builtin_bridge | BridgePolicy | . | Policy for built-in commands (dialogs, windows) |
security | SecurityPolicy | . | Navigation allowlist, external links, permissions |
automation | ?automation.Server | null | File-based automation server for testing |
window_state_store | ?window_state.Store | null | Persistent window geometry and state |
js_window_api | bool | false | Expose window.zero.windows.*; origin and window permission checks still apply |
Runtime methods
| Method | Description |
|---|---|
init(options) Runtime | Create a runtime |
run(app) !void | Enter the platform event loop |
createWindow(options) !WindowInfo | Open a new window |
listWindows() []WindowInfo | List open windows |
focusWindow(id) !void | Bring a window to front |
closeWindow(id) !void | Close a window |
invalidate() | Request a redraw |
invalidateFor(reason, dirty_region) | Request a redraw with reason and optional dirty region |
frameDiagnostics() FrameDiagnostics | Return stats from the last frame |
dispatchEvent(event) | Inject a synthetic event |
dispatchPlatformEvent(app, event) | Forward a platform event |
automationSnapshot() | Write state to automation directory |