App & Runtime
App and Runtime are the layer underneath UiApp: the app describes what to run, the runtime owns the event loop, windows, native views, security checks, automation, tracing, and platform services. Most native-rendered apps never touch this layer directly — UiApp and the generated runner wire it for you. Reach for it when you need custom lifecycle callbacks, imperative window and view management, or a WebView-based frontend.
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 for compatibility startup windows; defaults to empty HTML |
source_fn | ?fn(*anyopaque) !WebViewSource | Dynamic source resolver (overrides source when set) |
scene_fn | ?fn(*anyopaque) !ShellConfig | Declarative native window and view tree; when set, startup uses the scene instead of the compatibility window list |
start_fn | ?fn(*anyopaque, *Runtime) !void | Called after the runtime starts, before startup scene or source loading |
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 and name; provide scene_fn when startup should build a declarative native shell, and source or source_fn only when the app has WebView content.
Startup shape
With scene_fn, the runtime materializes the returned ShellConfig as native shell windows and views — this is the native-first path, and the shape UiApp uses through its scene option. The first scene window adopts the startup native window; additional scene windows are created through the window service.
Scene windows and views are kept as resize layout bindings, so return slices backed by static or app-owned storage that lives as long as the window.
const shell_views = [_]native_sdk.ShellView{
.{ .label = "main-canvas", .kind = .gpu_surface, .fill = true, .gpu_backend = .metal },
.{ .label = "status", .kind = .statusbar, .edge = .bottom, .height = 28, .text = "Ready" },
};
const shell_windows = [_]native_sdk.ShellWindow{.{
.label = "main",
.title = "Acme",
.width = 1100,
.height = 760,
.views = &shell_views,
}};
const shell_scene: native_sdk.ShellConfig = .{ .windows = &shell_windows };
fn scene(context: *anyopaque) anyerror!native_sdk.ShellConfig {
_ = context;
return shell_scene;
}Without scene_fn, the runtime uses the WebView compatibility path: it loads source or source_fn into the configured startup window list.
WebViewSource
For apps that embed web content, three constructors specify what a 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 = native_sdk.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) |
See Frontend Projects for the dev-server/bundled-assets workflow.
Lifecycle events
The runtime dispatches LifecycleEvent values through your event_fn:
start-- the app runtime has started and startup scene or source loading is about to runactivate-- the app became the active foreground appdeactivate-- the app resigned active foreground statusframe-- a frame has been requested (for animations or state updates)stop-- the app is shutting down
Native file drops dispatch Event.files_dropped to event_fn. Apps with WebView content also receive app:activate, app:deactivate, and drop:files on each trusted window.zero instance:
window.zero.on("drop:files", (event) => {
console.log(event.paths);
});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 = native_sdk.Runtime.init(.{
.platform = my_platform,
.trace_sink = fanout.sink(),
.security = .{
.permissions = &app_permissions,
.navigation = .{ .allowed_origins = &.{ "zero://app" } },
},
.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 (WebView apps; see Bridge) |
builtin_bridge | BridgePolicy | . | Policy for built-in bridge 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 built-in window.zero helper namespaces for trusted app chrome. Command helpers require origin and command checks, view helpers require origin and view checks, and window, WebView, and platform helpers require origin and window checks. Dialog, OS, clipboard, and credential helpers still require explicit builtin_bridge policy. |
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 |
setGpuSurfaceInputLatencyBudget(window_id, label, budget_ns) | Set the input-to-frame latency budget reported by GPU surface diagnostics |
dispatchEvent(event) | Inject a synthetic event |
dispatchPlatformEvent(app, event) | Forward a platform event |
automationSnapshot() | Write state to automation directory |