simvx.graphics.app

Graphics application layer: engine wrapper with node tree support.

Module Contents

Classes

App

Graphics application wrapper. Supports both raw callbacks and node tree scenes.

Data

API

simvx.graphics.app.log

‘getLogger(…)’

simvx.graphics.app.__all__

[‘App’, ‘AVAILABLE_BACKENDS’]

class simvx.graphics.app.App(title: str = 'SimVX', width: int = 1280, height: int = 720, backend: str | None = None, physics_fps: int = 60, target_fps: int | None = None, visible: bool = True, vsync: bool = True, bg_colour: tuple[float, float, float, float] | str | None = None, audio_sample_rate: int = 48000, audio_channels: int = 2, **_kwargs)[source]

Graphics application wrapper. Supports both raw callbacks and node tree scenes.

Args: title: Window title string. width: Window width in pixels (must be >= 1). height: Window height in pixels (must be >= 1). backend: Windowing backend name. One of "glfw" (desktop), "sdl3" (touch/mobile), "qt" (embedding). None auto-detects. physics_fps: Fixed-timestep physics simulation rate (Hz). Independent of the display rate; the run loop drives physics via an accumulator so changing this never affects render cadence. target_fps: Maximum display frame rate. None (default) means uncapped (vsync-gated only). Mirrors Godot’s Engine.max_fps, Unity’s Application.targetFrameRate, and Bevy’s FrameRateLimit::Limit. Combine with vsync=False to make the cap dominant on high-refresh displays. visible: Open a visible window. Set False for headless tests. vsync: Enable vertical sync at present time. bg_colour: Background clear colour. "transparent", an RGBA tuple, or None to use the theme background.

Usage with node tree (recommended)::

app = App(title="My Game", width=1280, height=720)
app.run(MyGameScene())  # Node subclass with ready()/process()

Usage with raw callbacks::

app = App(title="My Game")
app.run(update=my_update, render=my_render)

After run() has created the window, window_title, window_size, and active_backend reflect the live state.

Initialization

classmethod current() simvx.graphics.app.App | None[source]

Return the running App instance, or None if no App is alive.

Prefer node.app from inside Node subclasses (after on_enter_tree); use this from non-Node helpers like audio callbacks, utility modules, or tools that don’t have a node handle.

toggle_fullscreen() None[source]

Toggle fullscreen mode.

property is_fullscreen: bool[source]
property engine: simvx.graphics.engine.Engine | None[source]

Access the graphics engine (available after run() starts).

property texture_manager[source]

The renderer’s :class:TextureManager (available after run() starts).

Convenience accessor: forwards to app.engine.texture_manager so scenes that upload runtime-generated pixels (e.g. rasterised text) don’t need to reach into _engine.

property scene_adapter[source]

Scene adapter bridging SceneTree to the renderer (available after run() starts).

property active_backend: str | None[source]

Return the resolved backend name (e.g. "glfw"), or None if the engine has not yet initialised a window.

property window_title: str[source]

Current window title. Writable once the window exists.

property window_size: tuple[int, int][source]

Current window (width, height). Writable once the window exists.

property cursor_pos: tuple[float, float][source]

Current cursor position in screen coordinates, (0.0, 0.0) before run().

property vsync: bool[source]

Whether vertical sync is currently enabled.

set_vsync(value: bool) None[source]

Toggle vsync at runtime.

Before run() this just stores the boot-time value. After run(), the engine recreates the swapchain with the new present mode (FIFO when on, MAILBOX/IMMEDIATE when off).

property time_scale: float[source]

Global time-scale multiplier for the scene-tree tick.

Applied to dt before delivery to tree.process() and tree.physics_process(). 1.0 is real-time, 0.3 is 30% speed (slow-motion / hitstop), 2.0 is double speed, 0.0 is paused (still ticks, with zero dt). Default 1.0.

Scope is intentionally narrow: only the scene-tree dt is scaled. Audio playback rate, coroutine pacing, and the wall-clock physics accumulator are NOT touched: slowing audio + coroutines requires a separate design pass. Read :attr:simvx.core.SceneTree.now for the scaled scene clock.

property last_draw2d_draw_count: int | None[source]

Draw2DPass.last_frame_draw_count from the most recent run_headless call’s final rendered frame.

None if no run has happened yet or the renderer reported no Draw2D pass for this scene.

run(root_or_update: Any = None, *, update: collections.abc.Callable[[], None] | None = None, render: collections.abc.Callable[[object, tuple[int, int]], None] | None = None) None[source]

Run the graphics engine.

Args: root_or_update: Either a Node (scene root) or a per-frame update callback. When a Node is passed, SceneTree and input are set up automatically. update: Per-frame callback (alternative to the positional arg). render: Custom render callback (cmd, extent). Only used in callback mode.

quit() None[source]

Request a clean shutdown of the running app.

Safe to call from process/physics_process or input handlers. The main loop exits at the end of the current frame; audio and Vulkan resources are torn down in the usual finally-paths. Prefer this over sys.exit which can leave background threads (e.g. miniaudio) alive and stall process exit.

run_headless(root_node: Any, *, frames: int = 1, on_frame: collections.abc.Callable[[int, float], bool | None] | None = None, capture_frames: list[int] | None = (), capture_fn: collections.abc.Callable[[int], bool] | None = None) list[source]

Run the engine headlessly for frames frames and return captured pixels.

Args: root_node: Scene root node. frames: Total number of frames to simulate. on_frame: Optional callback invoked with (frame_index, time) before each frame. Return False to stop early. capture_frames: Which frame indices to capture. Defaults to (): no capture. Per-frame swapchain readback costs ~4 ms/frame (vkQueueWaitIdle + vkDeviceWaitIdle + host copy), so the default is no-capture so that tests/CI/benchmarks measure real frame work, not host-side readback. Pass an explicit list of frame indices (e.g. [frames - 1] for the final frame) to opt in, or None to capture every frame. capture_fn: Dynamic capture predicate: called with frame index, captures if True. Takes precedence over capture_frames when provided.

Returns: List of (H, W, 4) uint8 RGBA numpy arrays, one per captured frame (empty when the default capture_frames=() is used).

run_streaming(root_node: Any, server: Any) None[source]

Run the engine headlessly and stream frames to browsers over WebSocket.

Args: root_node: Scene root node. server: A StreamingServer instance (from simvx.graphics.streaming).