simvx.core.ui.splash

Boot / loading splash screen (design/splash_screen_design.md).

class:

SplashScreen is a full-screen anchored Control drawn through the normal 2D UI pass, so it renders identically on the desktop (Vulkan) and web (WebGPU) backends and in the headless test harness. The desktop FrameLoop presents it across the first-frame pipeline compile; games reuse the same control for heavy scene transitions by binding progress to an asset BatchHandle.

Sequence (the user-approved boot look): the whole splash fades in from black, holds while loading with a segmented gradient progress bar, fades back to black once loading is complete and the minimum display time has elapsed, then the black backdrop itself fades out to reveal the scene. Fade phases advance on frame dt (smooth at any frame rate); the minimum-display floor is measured in wall-clock time so a synchronous load stall (desktop pipeline compile, no frames presented) still counts toward it.

The branded face (wordmark, gradient, credit) comes from

mod:

simvx.core.branding; whether it appears at all is the branding gate’s decision, resolved by the driving app, not here.

Module Contents

Classes

SplashScreen

Full-screen boot/loading splash, drawn via the 2D UI pass on every backend.

AttributionWatermark

The persistent “Made with SimVX” corner watermark (LICENSE-EXCEPTION.md #3).

Data

API

simvx.core.ui.splash.__all__

[‘SplashScreen’, ‘AttributionWatermark’]

class simvx.core.ui.splash.SplashScreen(*, logo: str | int | None = None, logo_size: tuple[float, float] | None = None, progress: collections.abc.Callable[[], float] | Any | None = None, min_display_time: float = 1.0, fade_in_time: float = 0.25, fade_out_time: float = 0.25, skippable: bool = False, attribution: bool = True, **kwargs)[source]

Bases: simvx.core.ui.splash._FullscreenOverlay

Full-screen boot/loading splash, drawn via the 2D UI pass on every backend.

States: fade_in (content fades up from black) -> loading (hold, bar advances) -> fade_out (content fades back to black) -> reveal (the black backdrop fades off the scene) -> done (:attr:finished emitted).

Dismissal is max(load complete, min_display_time): the splash leaves as soon as loading is done once the floor is met, and never flashes sub-second on fast hardware. notify_loaded() marks loading complete; a progress source reaching 1.0 does the same automatically.

Example (scene transition)::

batch = assets.load_batch([...])
splash = SplashScreen(progress=batch, min_display_time=0.5)
root.add_child(splash)
splash.finished.connect(splash.destroy)

Initialization

Create a splash screen.

Args: logo: None draws the branded SimVX wordmark. A str image path (pkg:// or filesystem) or an int bindless texture id replaces it with a game logo (the SimVX credit then falls back to the persistent watermark, enforced by the driving app). logo_size: Pixel size for a custom logo; None fits a box of 35% of the screen’s short side. progress: A () -> float callable or any object with a progress attribute in [0, 1] (e.g. an asset BatchHandle). None renders an indeterminate shimmer until :meth:set_progress or :meth:notify_loaded is called. min_display_time: Minimum total on-screen time in seconds, fades included (anti-flicker floor). 0 dismisses as soon as loaded. fade_in_time / fade_out_time: Fade-from-black / fade-to-black durations in seconds. The reveal (backdrop off the scene) reuses fade_out_time. skippable: When True, any key/click after loading completes skips the remaining hold (never before loading is done). attribution: Render the “Made with SimVX” credit line (the branding gate may rely on it; see LICENSE-EXCEPTION.md).

BACKGROUND: tuple[float, float, float, float]

(0.0035, 0.0055, 0.0045, 1.0)

property state: str[source]

Current phase: fade_in / loading / fade_out / reveal / done.

property loaded: bool[source]

Whether loading has been reported complete.

set_progress(fraction: float, caption: str | None = None) None[source]

Advance the milestone-driven bar to fraction in [0, 1].

The bar becomes determinate on first call and only ever moves forward. caption (when given) replaces the stage line under the bar. Reaching 1.0 marks loading complete.

notify_loaded() None[source]

Mark loading complete: the splash dismisses once the min-display floor is met.

skip() None[source]

Skip the remaining hold (honoured only after loading is complete).

on_ready() None[source]
on_update(dt: float) None[source]
on_unhandled_input(event) None[source]
on_draw(renderer) None[source]
on_enter_tree() None
get_rect() tuple[float, float, float, float]
get_global_rect() tuple[float, float, float, float]
size_x

‘Property(…)’

size_y

‘Property(…)’

anchor_left

‘Property(…)’

anchor_top

‘Property(…)’

anchor_right

‘Property(…)’

anchor_bottom

‘Property(…)’

margin_left

‘Property(…)’

margin_top

‘Property(…)’

margin_right

‘Property(…)’

margin_bottom

‘Property(…)’

dismiss_on_outside_click

‘Property(…)’

property size: simvx.core.math.types.Vec2
touch_mode: str

‘mouse’

property theme: simvx.core.ui.types.Theme | None
property mouse_over: bool
property focused: bool
property disabled: bool
get_theme() simvx.core.ui.types.Theme
queue_redraw()
get_minimum_size() simvx.core.math.types.Vec2
is_point_inside(point) bool
place_bottom_strip(height: float) None
place_top_strip(height: float) None
set_anchor_preset(preset: simvx.core.ui.enums.AnchorPreset)
set_focus()
grab_focus()
release_focus()
has_focus() bool
focus_next_control()
focus_previous_control()
grab_mouse()
release_mouse()
set_drag_preview(control: simvx.core.ui.core.Control)
property is_overlay_open: bool
show_overlay(modality: str = 'light', *, dim: bool | None = None, dismiss: bool | None = None, inert: bool | None = None, owner: simvx.core.ui.core.Control | None = None, initial_focus: simvx.core.ui.core.Control | None = None) None
close_overlay() None
position

‘_SpatialVecProperty(…)’

rotation

‘Property(…)’

scale

‘_SpatialVecProperty(…)’

z_index

‘Property(…)’

z_as_relative

‘Property(…)’

render_layer

‘Property(…)’

set_render_layer(index: int, enabled: bool = True) None
is_on_render_layer(index: int) bool
property absolute_z_index: int
property rotation_degrees: float
property world_position: simvx.core.math.types.Vec2
property world_rotation: float
property world_scale: simvx.core.math.types.Vec2
property world_transform: tuple[simvx.core.math.types.Vec2, simvx.core.math.types.Vec2, float]
property forward: simvx.core.math.types.Vec2
property right: simvx.core.math.types.Vec2
translate(offset: tuple[float, float] | numpy.ndarray)
rotate(radians: float)
rotate_deg(degrees: float)
look_at(target: tuple[float, float] | numpy.ndarray)
transform_points(points: list[simvx.core.math.types.Vec2]) list[simvx.core.math.types.Vec2]
draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, colour=None)
wrap_screen(margin: float = 20)
hdr

‘Property(…)’

property transform_render_dirty: bool
strict_errors: ClassVar[bool]

True

script_error_raised

‘Signal(…)’

dynamic: bool

False

classmethod __init_subclass__(**kwargs)
property name: str
property update_mode: simvx.core.descriptors.UpdateMode
property visible: bool
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
get_node_or_none(path: str) simvx.core.node.Node | None
find(target, *, direct: bool = False)
find_all(target, *, direct: bool = False)
walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
on_exit_tree() None
on_fixed_update(dt: float) None
on_picked(event: simvx.core.events.InputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
property render_dirty: bool
clear_children()
destroy()
call_deferred(method: collections.abc.Callable[..., Any], *args: Any) None
property app
property tree: simvx.core.scene_tree.SceneTree
property physics
property physics_2d
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
__repr__()
class simvx.core.ui.splash.AttributionWatermark(**kwargs)[source]

Bases: simvx.core.ui.splash._FullscreenOverlay

The persistent “Made with SimVX” corner watermark (LICENSE-EXCEPTION.md #3).

The fallback branding form when a game replaces the default splash face (or suppresses the splash) on a branded build: small, unobtrusive, bottom-right, never intercepts input. Removal goes through the two-step unbranded gate (:func:simvx.core.branding.unbranded_allowed), not through this class.

Initialization

on_draw(renderer) None[source]
on_enter_tree() None
get_rect() tuple[float, float, float, float]
get_global_rect() tuple[float, float, float, float]
size_x

‘Property(…)’

size_y

‘Property(…)’

anchor_left

‘Property(…)’

anchor_top

‘Property(…)’

anchor_right

‘Property(…)’

anchor_bottom

‘Property(…)’

margin_left

‘Property(…)’

margin_top

‘Property(…)’

margin_right

‘Property(…)’

margin_bottom

‘Property(…)’

dismiss_on_outside_click

‘Property(…)’

property size: simvx.core.math.types.Vec2
touch_mode: str

‘mouse’

property theme: simvx.core.ui.types.Theme | None
property mouse_over: bool
property focused: bool
property disabled: bool
get_theme() simvx.core.ui.types.Theme
queue_redraw()
get_minimum_size() simvx.core.math.types.Vec2
is_point_inside(point) bool
place_bottom_strip(height: float) None
place_top_strip(height: float) None
set_anchor_preset(preset: simvx.core.ui.enums.AnchorPreset)
set_focus()
grab_focus()
release_focus()
has_focus() bool
focus_next_control()
focus_previous_control()
grab_mouse()
release_mouse()
set_drag_preview(control: simvx.core.ui.core.Control)
property is_overlay_open: bool
show_overlay(modality: str = 'light', *, dim: bool | None = None, dismiss: bool | None = None, inert: bool | None = None, owner: simvx.core.ui.core.Control | None = None, initial_focus: simvx.core.ui.core.Control | None = None) None
close_overlay() None
position

‘_SpatialVecProperty(…)’

rotation

‘Property(…)’

scale

‘_SpatialVecProperty(…)’

z_index

‘Property(…)’

z_as_relative

‘Property(…)’

render_layer

‘Property(…)’

set_render_layer(index: int, enabled: bool = True) None
is_on_render_layer(index: int) bool
property absolute_z_index: int
property rotation_degrees: float
property world_position: simvx.core.math.types.Vec2
property world_rotation: float
property world_scale: simvx.core.math.types.Vec2
property world_transform: tuple[simvx.core.math.types.Vec2, simvx.core.math.types.Vec2, float]
property forward: simvx.core.math.types.Vec2
property right: simvx.core.math.types.Vec2
translate(offset: tuple[float, float] | numpy.ndarray)
rotate(radians: float)
rotate_deg(degrees: float)
look_at(target: tuple[float, float] | numpy.ndarray)
transform_points(points: list[simvx.core.math.types.Vec2]) list[simvx.core.math.types.Vec2]
draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, colour=None)
wrap_screen(margin: float = 20)
hdr

‘Property(…)’

property transform_render_dirty: bool
strict_errors: ClassVar[bool]

True

script_error_raised

‘Signal(…)’

dynamic: bool

False

classmethod __init_subclass__(**kwargs)
property name: str
property update_mode: simvx.core.descriptors.UpdateMode
property visible: bool
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
get_node_or_none(path: str) simvx.core.node.Node | None
find(target, *, direct: bool = False)
find_all(target, *, direct: bool = False)
walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
on_ready() None
on_exit_tree() None
on_update(dt: float) None
on_fixed_update(dt: float) None
on_picked(event: simvx.core.events.InputEvent) None
on_unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
property render_dirty: bool
clear_children()
destroy()
call_deferred(method: collections.abc.Callable[..., Any], *args: Any) None
property app
property tree: simvx.core.scene_tree.SceneTree
property physics
property physics_2d
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
__repr__()