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

FieldTypeDescription
context*anyopaquePointer to your app state (required)
name[]const u8App name used in traces and automation snapshots (required)
sourceWebViewSourceInitial WebView content (required)
source_fn?fn(*anyopaque) !WebViewSourceDynamic source resolver (overrides source when set)
start_fn?fn(*anyopaque, *Runtime) !voidCalled after the runtime starts and the first window is loaded
event_fn?fn(*anyopaque, *Runtime, Event) !voidCalled on every runtime event (lifecycle + commands)
stop_fn?fn(*anyopaque, *Runtime) !voidCalled 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 as zero://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
}),
FieldDefaultDescription
root_pathrequiredPath 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_fallbacktrueServe 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 loaded
  • frame -- 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:

  1. Selects the platform (macOS, Linux, or null for headless tests)
  2. Sets up trace sinks (stdout + file) via FanoutTraceSink
  3. Installs panic capture so crashes write last-panic.txt
  4. Initializes window state persistence from windows.zon
  5. Creates the Runtime with all options and calls runtime.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

FieldTypeDefaultDescription
platformPlatformrequiredPlatform abstraction (macOS, Linux, or NullPlatform)
trace_sink?trace.SinknullDestination for structured trace records
log_path?[]const u8nullPath for persistent log file
extensions?ModuleRegistrynullExtension modules with lifecycle hooks
bridge?BridgeDispatchernullApp-defined bridge commands and handlers
builtin_bridgeBridgePolicy.Policy for built-in commands (dialogs, windows)
securitySecurityPolicy.Navigation allowlist, external links, permissions
automation?automation.ServernullFile-based automation server for testing
window_state_store?window_state.StorenullPersistent window geometry and state
js_window_apiboolfalseExpose window.zero.windows.*; origin and window permission checks still apply

Runtime methods

MethodDescription
init(options) RuntimeCreate a runtime
run(app) !voidEnter the platform event loop
createWindow(options) !WindowInfoOpen a new window
listWindows() []WindowInfoList open windows
focusWindow(id) !voidBring a window to front
closeWindow(id) !voidClose a window
invalidate()Request a redraw
invalidateFor(reason, dirty_region)Request a redraw with reason and optional dirty region
frameDiagnostics() FrameDiagnosticsReturn stats from the last frame
dispatchEvent(event)Inject a synthetic event
dispatchPlatformEvent(app, event)Forward a platform event
automationSnapshot()Write state to automation directory