Quick Start

1. A Colored Rectangle (2D)

The simplest SimVX program: a blue rectangle that moves with arrow keys.

from simvx.core import Node, Node2D, InputMap, Key, Input, Property
from simvx.graphics import App


class BlueRect(Node2D):
    speed = Property(200.0, hint="Pixels per second")

    def ready(self):
        InputMap.add_action("move_left", [Key.A, Key.LEFT])
        InputMap.add_action("move_right", [Key.D, Key.RIGHT])
        InputMap.add_action("move_up", [Key.W, Key.UP])
        InputMap.add_action("move_down", [Key.S, Key.DOWN])

    def process(self, dt):
        direction = Input.get_vector(
            "move_left", "move_right", "move_up", "move_down"
        )
        self.position += direction * self.speed * dt

    def draw(self, canvas):
        canvas.rect(self.position.x, self.position.y, 60, 60, color=(0.2, 0.4, 1.0))


app = App(width=800, height=600, title="Blue Rectangle")
app.run(BlueRect())

Property declares editor-visible, serializable values. InputMap.add_action binds named actions to typed Key enums – query them with Input.get_vector() or Input.is_action_pressed().

2. Spinning 3D Cube

Build a minimal 3D scene with a camera and a red cube:

from simvx.core import Node, Camera3D, MeshInstance3D, Mesh, Material
from simvx.graphics import App


class SpinningCube(Node):
    def ready(self):
        cam = Camera3D(position=(0, 3, 8))
        cam.look_at((0, 0, 0))
        self.add_child(cam)

        self.cube = MeshInstance3D(
            name="Cube",
            mesh=Mesh.cube(),
            material=Material(color=(1, 0, 0)),
        )
        self.add_child(self.cube)

    def process(self, dt):
        self.cube.rotate((0, 1, 0), 90 * dt)  # degrees per second


app = App(width=1280, height=720, title="Spinning Cube")
app.run(SpinningCube())

All rotation APIs use degrees. Access children by path with self["Cube"].

3. Handle Input

Use InputMap with typed keys for all input bindings:

from simvx.core import InputMap, Key, Input, Node3D, Property


class Player(Node3D):
    speed = Property(10.0, range=(0, 50))

    def ready(self):
        InputMap.add_action("move_left", [Key.A, Key.LEFT])
        InputMap.add_action("move_right", [Key.D, Key.RIGHT])
        InputMap.add_action("move_forward", [Key.W, Key.UP])
        InputMap.add_action("move_back", [Key.S, Key.DOWN])

    def process(self, dt):
        direction = Input.get_vector(
            "move_left", "move_right", "move_forward", "move_back"
        )
        self.translate((direction.x * self.speed * dt, 0,
                        direction.y * self.speed * dt))

4. Signals and Timers

Signals provide decoupled event communication. connect() returns a Connection handle:

from simvx.core import Node, Timer, Signal, MeshInstance3D, Mesh, Material


class Spawner(Node):
    def ready(self):
        timer = Timer(duration=2.0, one_shot=False, autostart=True)
        conn = timer.timeout.connect(self.spawn_enemy)
        self.add_child(timer)

        # One-shot connection: auto-disconnects after first call
        self.tree.root_changed.connect(self.on_first_root, once=True)

    def spawn_enemy(self):
        enemy = MeshInstance3D(mesh=Mesh.sphere(), material=Material(color=(0, 1, 0)))
        self.add_child(enemy)

5. Animate Properties

Use coroutine-based tweens to animate any property:

from simvx.core import tween, Node3D
from simvx.core.animation import ease_out_elastic


class AnimatedNode(Node3D):
    def ready(self):
        self.start_coroutine(
            tween(self, "position", (5, 0, 0), duration=1.0,
                  easing=ease_out_elastic)
        )

6. Collision

Attach collision shapes for overlap detection:

from simvx.core import CharacterBody3D


class Bullet(CharacterBody3D):
    def __init__(self):
        super().__init__(collision=0.5)  # sphere radius
        self.velocity = (0, 0, -20)

    def physics_process(self, dt):
        self.move_and_slide(dt)
        for enemy in self.get_overlapping(group="enemies"):
            enemy.destroy()

7. Context Manager

App supports with for clean resource management:

with App(width=1280, height=720, title="My Game") as app:
    app.run(SpinningCube())

Full Import Reference

from simvx.core import (
    Node, Node2D, Node3D, Camera3D, MeshInstance3D,
    SceneTree, Signal, Connection, Property,
    InputMap, Key, MouseButton, Input,
    Vec2, Vec3, Quat, Rect2, AABB, Transform2D, Transform3D,
    Mesh, Material, Shader,
    Timer, Child, OnReady,
    tween, wait, parallel,
    SceneRunner, InputSimulator, scene_diff,
    save_scene, load_scene,
)
from simvx.graphics import App

Next Steps