Runner
App, Frame, native window configuration, lifecycle, startup errors, and the browser runner.
Entry points
pub fn run(app: impl App) -> Result<(), RunError>;
pub fn run_with_options(app: impl App, options: RunOptions) -> Result<(), RunError>;On the desktop, call either entry point on the main thread. winit generally permits one event loop per process. The call blocks until the loop exits.
In a browser (wasm32-unknown-unknown) the same functions draw on a canvas, but the call
returns immediately after registering the event loop with winit's spawn_app: the page
drives the loop from then on, and the renderer is created asynchronously. The application
must be 'static. Errors after the return are written to the console. The page has one
window; see Web.
App requires one method; the other four are optional and serve several native windows:
fn update(&mut self, context: &mut Context, frame: &mut Frame<'_>);
fn windows(&mut self, plan: &mut WindowPlan) {}
fn close_requested(&mut self, request: &mut CloseRequested<'_>) {}
fn window_failed(&mut self, key: &WindowKey, error: &WindowError) {}
fn global_shortcut(&mut self, shortcut: &GlobalShortcut<'_>, windows: &mut Windows<'_>) -> bool { false }The runner owns the native windows, renderer, and one context per window. It invokes update inside
Context::run on each visible RedrawRequested. Build the UI directly in update.
Configure the native window
use zaxis::{App, PresentationMode, RunError, RunOptions};
use zaxis::winit::{dpi::LogicalSize, window::Window};
fn open(app: impl App) -> Result<(), RunError> {
zaxis::run_with_options(app, RunOptions {
window_attributes: Window::default_attributes()
.with_title("Inspector")
.with_inner_size(LogicalSize::new(1024.0, 720.0))
.with_min_inner_size(LogicalSize::new(640.0, 480.0)),
presentation_mode: PresentationMode::Immediate,
..Default::default()
})
}RunOptions contains window_attributes: winit::window::WindowAttributes,
presentation_mode: PresentationMode, font_family: Option<FontFamily>
(RunOptions::with_font_family; None uses the bundled Inter), monospace_family
(with_monospace_family; None uses the bundled JetBrains Mono), main_window: WindowKey
(with_main_window), exit_policy: ExitPolicy (with_exit_policy) and web: WebOptions
(with_canvas_id, with_container_id, with_web_backend; read only by the browser runner).
The attributes and presentation mode describe the main window. Defaults:
| Setting | Value |
|---|---|
| Native title | zaxis |
| Native inner size | 860 × 560 logical pixels |
| Presentation | PresentationMode::Vsync |
accessibility: bool (with_accessibility) is described in Accessibility.
Native WindowAttributes can use logical or physical dimensions. The zaxis panel
builder Window controls panels inside the native window; its dimensions are always
logical pixels. See Window.
Frame
| Method | Behavior |
|---|---|
frame.window() -> &Arc<winit::window::Window> | Access the native window being drawn, change its title, request redraw, or clone its handle |
frame.window_key() / is_main() / info() | Which window this frame builds, and its size, scale and state (WindowInfo) |
frame.windows() | Open, close, focus, resize and inspect other windows (Windows) |
frame.open_window(key, options) | Ask for a secondary window |
frame.close_window(key) / close_this_window() | Close a window now, without asking |
frame.request_close() | Close this window as the user would, so close_requested decides |
frame.window_status(&key) / stats() | WindowStatus of a key; AppStats over all windows |
frame.device_resets() / last_device_loss() | GPU recovery counters, shared by every window |
frame.close() | End the application after the current frame is successfully presented, closing every window |
An OS close request goes to App::close_requested; the window closes unless it calls
reject(). A single-window application that implements nothing else exits as before.
frame.close() waits for RenderStatus::Presented; a transient retry can delay shutdown.
Multiple windows
Each native window is named by a WindowKey and has its own Context, so update runs once
per redraw of one window; branch on frame.window_key(). Windows share one glyph atlas,
image cache and appearance (SharedResources, Windows::set_theme), and closing a window
drops only its UI state. Application data stays in your App.
const INSPECTOR: &str = "inspector";
fn windows(&mut self, plan: &mut WindowPlan) {
plan.window_if(self.show_inspector, INSPECTOR, || {
WindowOptions::new("Inspector").with_inner_size(320.0, 360.0)
});
}
fn close_requested(&mut self, request: &mut CloseRequested<'_>) {
if request.is_main() && self.unsaved {
request.reject(); // show a Modal, then frame.close_this_window()
}
}- Declarative:
App::windowslists the secondary windows that should exist; the runner opens new keys and closes keys no longer declared. A window the user closed stays closed until you stop declaring it once. - Imperative:
Frame::open_windoworWindows::openreturnsOpenOutcome; an open or pending key is never duplicated. Both styles can be mixed. - Options:
WindowOptions(title, size, position, min/max size, decorations, resizable, always on top, transparent, icon, visible, maximized, parent, presentation mode, rounded corners, orfrom_attributes). A child closes with itsparent. - Exit:
ExitPolicy::MainWindow(default) ends the app with the main window;ExitPolicy::LastWindowruns until the last window closes. - Data across windows: a window repaints on its own input; call
Windows::request_repaint(key)orrequest_repaint_all()after changing shared data. - Failures: a window that cannot be created reaches
window_failedandWindowStatus::Failed; the others keep running and the key can be requested again. - Shortcuts: keys go to the focused window;
global_shortcutcan take one first. - Browser: a page has one canvas.
Windows::openreturnsOpenOutcome::Unsupportedfor a second key, its status isFailed, andwindow_failedreceivesWindowError::Unsupported; the main window is unaffected.
Run cargo run --example multi_window (add -- --smoke-test for the scripted lifecycle).
The runner does not expose its Renderer through Frame. Runtime presentation
switching uses a custom host.
Accessibility
With the default accesskit feature every native window serves an accessibility tree
to screen readers. Nothing is built until assistive technology connects, so leaving it
on costs nothing without one.
| Option | Effect |
|---|---|
RunOptions::with_accessibility(false) | No window serves a tree |
WindowOptions::with_accessibility(false) | That window serves none; it is invisible to assistive technology |
Both default to true; a window serves a tree only when both are on. The options have
no effect without the accesskit feature or in a browser. The runner names the tree
after the native window title. See Accessibility.
Lifecycle
| Event | Runner action |
|---|---|
| Initial resume | Create the main native window and renderer, set viewport, request redraw; open declared windows. In a browser the renderer arrives from a task, and the window gets its context and first frame then |
| Input | Forward to Context; request redraw when its response requires it |
| Resize or DPI change | Refresh viewport from actual native size and scale, resize renderer |
| Occlusion or zero native size | Stop rendering and wait for events |
| Unocclusion | Request redraw |
| Surface timeout, lost, or outdated | Retry after 16 ms; renderer handles surface recovery |
| GPU device loss | Recreate renderer with the current presentation mode, request redraw (in a browser, in the background; nothing is drawn meanwhile) |
| Suspend | Drop native window/renderer, clear focus and held input |
| Resume after suspend | Recreate native resources; retain application and UI state |
The event loop uses ControlFlow::Wait while idle and WaitUntil for repaint
deadlines; on the web winit maps them to requestAnimationFrame and timers, so a settled
page and a background tab do no work. Surface retry backoff takes precedence over immediate
UI repaint requests.
Repaint deadlines are zaxis::Instant values: std::time::Instant on native targets,
web_time::Instant on wasm32, where std's clock panics.
Errors
RunError implements Display and std::error::Error:
| Variant | Failure |
|---|---|
EventLoop(EventLoopError) | Create or run the winit event loop |
Window(OsError) | Create the main native window (secondary windows report WindowError to window_failed) |
Web(String) | The page lacks what the browser runner needs, such as the canvas_id element |
Render(RenderError) | Initialize the renderer or handle an unrecoverable rendering failure |
Return this error from main, or handle it in your application launcher. Renderer
error variants are described in Renderer.
File dialogs
With the file-dialogs feature the runner shows the dialogs a frame opens with
Context::open_dialog, modal for their window only, and answers Cancelled when that window
closes. See File dialogs and file drop.