zaxis 0.1.0

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:

SettingValue
Native titlezaxis
Native inner size860 × 560 logical pixels
PresentationPresentationMode::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

MethodBehavior
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::windows lists 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_window or Windows::open returns OpenOutcome; 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, or from_attributes). A child closes with its parent.
  • Exit: ExitPolicy::MainWindow (default) ends the app with the main window; ExitPolicy::LastWindow runs until the last window closes.
  • Data across windows: a window repaints on its own input; call Windows::request_repaint(key) or request_repaint_all() after changing shared data.
  • Failures: a window that cannot be created reaches window_failed and WindowStatus::Failed; the others keep running and the key can be requested again.
  • Shortcuts: keys go to the focused window; global_shortcut can take one first.
  • Browser: a page has one canvas. Windows::open returns OpenOutcome::Unsupported for a second key, its status is Failed, and window_failed receives WindowError::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.

OptionEffect
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

EventRunner action
Initial resumeCreate 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
InputForward to Context; request redraw when its response requires it
Resize or DPI changeRefresh viewport from actual native size and scale, resize renderer
Occlusion or zero native sizeStop rendering and wait for events
UnocclusionRequest redraw
Surface timeout, lost, or outdatedRetry after 16 ms; renderer handles surface recovery
GPU device lossRecreate renderer with the current presentation mode, request redraw (in a browser, in the background; nothing is drawn meanwhile)
SuspendDrop native window/renderer, clear focus and held input
Resume after suspendRecreate 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:

VariantFailure
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.

Edit on GitHub

On this page