simvx.core.scripted_demo

Scripted demo playback — automated input sequences with narration and assertions.

Drive a game/UI scene with pre-recorded steps: move cursor, click, type text, press keys, wait, assert state, and show narration overlays. Useful for creating self-playing demos, tutorials, and integration tests.

Usage: from simvx.core.scripted_demo import DemoRunner, MoveTo, Click, Narrate, Assert

steps = [
    Narrate("Welcome to the demo!", duration=2.0),
    MoveTo(200, 150, duration=0.5),
    Click(200, 150),
    Assert(lambda g: g.board[0][0] == "X", "Cell should be X"),
]
runner = DemoRunner(steps, speed=2.0)
game.add_child(runner)

Module Contents

Classes

MoveTo

Smoothly move the virtual cursor to a screen position.

Click

Move to position then click (press + release).

TypeText

Type a string character by character.

PressKey

Press and hold a key for a duration.

Wait

Pause playback for a duration.

Assert

Run a check function against the game node (parent of DemoRunner).

Do

Execute an action against the game node (parent of DemoRunner).

Narrate

Display narration text at the bottom of the screen.

DemoRunner

Plays a scripted sequence of demo steps, injecting input and drawing overlays.

Data

API

simvx.core.scripted_demo.log

‘getLogger(…)’

simvx.core.scripted_demo.__all__

[‘MoveTo’, ‘Click’, ‘TypeText’, ‘PressKey’, ‘Wait’, ‘Assert’, ‘Do’, ‘Narrate’, ‘DemoRunner’]

class simvx.core.scripted_demo.MoveTo

Smoothly move the virtual cursor to a screen position.

x: float

None

y: float

None

duration: float

0.5

class simvx.core.scripted_demo.Click

Move to position then click (press + release).

x: float

None

y: float

None

button: int

1

class simvx.core.scripted_demo.TypeText

Type a string character by character.

text: str

None

delay_per_char: float

0.05

class simvx.core.scripted_demo.PressKey

Press and hold a key for a duration.

key: int

None

hold_duration: float

0.1

class simvx.core.scripted_demo.Wait

Pause playback for a duration.

duration: float

None

class simvx.core.scripted_demo.Assert

Run a check function against the game node (parent of DemoRunner).

check_fn: Any

None

message: str = <Multiline-String>
actual_fn: Any

None

class simvx.core.scripted_demo.Do

Execute an action against the game node (parent of DemoRunner).

Like Assert but semantically different — never fails on return value. In test_mode, exceptions propagate; in interactive mode, they’re logged.

action: Any

None

message: str = <Multiline-String>
class simvx.core.scripted_demo.Narrate

Display narration text at the bottom of the screen.

text: str

None

duration: float

2.0

class simvx.core.scripted_demo.DemoRunner(steps: list, test_mode: bool = False, on_complete: collections.abc.Callable | None = None, speed: float | None = None, speed_mode: int = 0, delay_between_steps: float = 0.15, **kwargs)

Bases: simvx.core.engine.Node

Plays a scripted sequence of demo steps, injecting input and drawing overlays.

Add as a child of the game/scene root. In test_mode, hotkeys are disabled and assertions raise on failure.

Args: steps: List of step dataclasses to execute in order. test_mode: If True, skip hotkeys and raise on assertion failure. on_complete: Optional callback invoked when all steps finish. speed: Explicit speed override. If set, takes precedence over speed_mode. speed_mode: Speed preset index (0=slow 0.5x, 1=fast 3x, 2=instant 50x). Default 1. delay_between_steps: Natural pause (seconds) between steps. Default 0.15.

Initialization

classmethod register_step_handler(step_type: type, handler: collections.abc.Callable)

Register a handler for a custom step type.

Handler signature: (runner: DemoRunner, step, dt: float) -> None. The handler must call runner._advance() when the step is complete.

property current_step_index: int
property total_steps: int
property is_done: bool
property failures: list[str]
process(dt: float)
draw(renderer)
classmethod run_headless(scene: simvx.core.engine.Node, steps: list, *, speed: float = 50.0, screen_size: tuple[int, int] = (800, 600), max_frames: int = 20000, delay_between_steps: float = 0.0) bool

Run a demo headlessly and return True if all steps pass.

Creates a DemoRunner in test_mode, adds it to scene, and advances frames via SceneRunner until completion or max_frames is reached.

classmethod run_visual(scene: simvx.core.engine.Node, steps: list, *, speed: float | None = None, speed_mode: int = 0, title: str = 'Demo', width: int = 800, height: int = 600)

Run a demo visually with the Vulkan App.

Lazily imports simvx.graphics.App to keep core free of graphics deps.

script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
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
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
enter_tree() None
exit_tree() None
physics_process(dt: float) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()