simvx.core.nodes_3d.sprite

Sprite3D, SpriteAnimation3D, AnimatedSprite3D – billboarded sprites in 3D.

Module Contents

Classes

Sprite3D

Billboarded textured quad in 3D space.

SpriteAnimation3D

Named sprite animation with frame indices and playback settings.

AnimatedSprite3D

Animated billboarded sprite in 3D space.

API

class simvx.core.nodes_3d.sprite.Sprite3D(texture=None, **kwargs)[source]

Bases: simvx.core.graphics.texture_slot.TextureSlot, simvx.core.nodes_3d.node3d.Node3D

Billboarded textured quad in 3D space.

Like Text3D but for images. Renders a textured quad positioned in the 3D world, optionally billboarded to always face the camera. Used for health bars, retro-3D sprites, vegetation cards, and particle-like effects.

The texture property takes a file path, encoded bytes, an RGBA ndarray or a :class:~simvx.core.graphics.Texture; the graphics backend resolves it and publishes the handle through

Meth:

~simvx.core.graphics.TextureSlot.publish_texture_slot, along with the image’s pixel dimensions. Reassigning texture re-resolves, and the quad resizes to the new image. The pixel_size property controls how many world units each pixel occupies.

Example::

sprite = Sprite3D(texture="tree.png", position=(0, 1, -5))
sprite.pixel_size = 0.01
sprite.billboard = True

Initialization

texture

‘Property(…)’

pixel_size

‘Property(…)’

billboard

‘Property(…)’

flip_h

‘Property(…)’

flip_v

‘Property(…)’

modulate

‘Colour(…)’

centered

‘Property(…)’

offset

‘Property(…)’

alpha_cut

‘Property(…)’

render_priority

‘Property(…)’

region_enabled

‘Property(…)’

region_rect

‘Property(…)’

publish_texture_size(width: int, height: int) None[source]

Record the resolved image’s pixel dimensions (drives :attr:quad_size).

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

Native texture size in pixels (width, height). Set by the graphics backend.

property quad_size: simvx.core.math.types.Vec2[source]

Quad’s world-space size based on pixel_size and the texture/region dimensions.

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

(u0, v0, u1, v1) UV coordinates, accounting for region and flip.

get_aabb()[source]

Return axis-aligned bounding box for frustum culling.

Returns: AABB centred on the node’s global position, sized by the quad dimensions.

on_draw(renderer) None[source]

Emit a depth-tested billboard quad for the 3D renderer.

on_draw is invoked by both the 2D Draw2D tree walk and the 3D scene adapter; only the latter passes a renderer exposing draw_sprite_3d (Billboard2DPass), so the 2D walk is a safe no-op here.

property texture_slot: int
publish_texture_slot(slot: int) None
publish_overlay_slot(slot: int) None
strict_errors: ClassVar[bool]

True

dev_checks: ClassVar[bool]

None

script_error_raised

‘Signal(…)’

dynamic: bool

False

visible

‘Property(…)’

update_mode

‘Property(…)’

__properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]

None

classmethod __init_subclass__(**kwargs)
property name: str
property visible_in_tree: bool
reset_error() None
add_child(node: simvx.core.node.T) simvx.core.node.T
remove_child(node: simvx.core.node.Node) None
reparent(new_parent: simvx.core.node.Node)
node_at(path, default=_NO_DEFAULT)
find(target, *, direct: bool = False)
find_all(target, *, direct: bool = False)
expect(target, *, direct: bool = False)
ancestor(target)
walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]
property path: str
property is_scene_root: bool
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
on_ready() None
on_enter_tree() 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)
queue_redraw() None
property render_dirty: bool
clear_children()
destroy()
property destroying: bool
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__()
position

‘_SpatialVecProperty(…)’

rotation

‘Property(…)’

scale

‘_SpatialVecProperty(…)’

render_layer

‘Property(…)’

property rotation_degrees: simvx.core.math.types.Vec3
property world_position: simvx.core.math.types.Vec3
property world_rotation: simvx.core.math.types.Quat
property world_scale: simvx.core.math.types.Vec3
property forward: simvx.core.math.types.Vec3
property right: simvx.core.math.types.Vec3
property up: simvx.core.math.types.Vec3
translate(offset: tuple[float, float, float] | numpy.ndarray)
translate_global(offset: tuple[float, float, float] | numpy.ndarray)
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)
rotate_x(angle: float)
rotate_y(angle: float)
rotate_z(angle: float)
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)
face_along(forward: tuple[float, float, float] | numpy.ndarray, up: tuple[float, float, float] | numpy.ndarray | None = None) None
set_render_layer(index: int, enabled: bool = True) None
is_on_render_layer(index: int) bool
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)
class simvx.core.nodes_3d.sprite.SpriteAnimation3D[source]

Named sprite animation with frame indices and playback settings.

name: str

None

frames: list[int]

None

fps: float

10.0

loop: bool

True

class simvx.core.nodes_3d.sprite.AnimatedSprite3D(**kwargs)[source]

Bases: simvx.core.nodes_3d.sprite.Sprite3D

Animated billboarded sprite in 3D space.

Plays frame-based animations from a sprite sheet, mirroring AnimatedSprite2D but positioned in 3D world space with billboard support.

The sheet grid, the registered animations and whether playback runs are authoring state, so they are Properties and a saved scene carries them. The playback position (frame, and the private frame timer) is not: a reloaded scene is the sprite that was set up, not the instant a save happened to catch.

Example::

sprite = AnimatedSprite3D(
    texture="enemy_sheet.png",
    frames_h=4,
    frames_v=2,
    position=(0, 1, -5),
)
sprite.add_animation("walk", frames=[0, 1, 2, 3], fps=10, loop=True)
sprite.add_animation("die", frames=[4, 5, 6, 7], fps=8, loop=False)
sprite.play("walk")

Initialization

speed_scale

‘Property(…)’

frames_h

‘Property(…)’

frames_v

‘Property(…)’

animations

‘Property(…)’

current_animation

‘Property(…)’

playing

‘Property(…)’

__transient__

‘frozenset(…)’

frame_changed

‘Signal(…)’

animation_finished

‘Signal(…)’

add_animation(name: str, frames: list[int], fps: float = 10.0, loop: bool = True)[source]

Register a named animation.

Args: name: Animation identifier. frames: List of frame indices into the sprite sheet. fps: Playback speed in frames per second. loop: Whether the animation loops.

play(animation_name: str = 'default')[source]

Start playing a named animation.

If the animation name is not registered, a default animation covering all frames in the sheet is created automatically.

stop()[source]

Stop animation and reset to the start of the current animation.

playing becomes False and the frame counter resets so a subsequent play() or resume() begins from frame 0.

pause()[source]

Pause animation, preserving the current frame and frame time.

playing becomes False but no state is reset; resume() continues from where playback left off.

resume()[source]

Resume animation from the current frame.

on_update(dt: float)[source]

Advance animation by dt seconds, respecting speed_scale.

property current_frame_index: int[source]

Absolute frame index in the sprite sheet.

property frame_uv: tuple[simvx.core.math.types.Vec2, simvx.core.math.types.Vec2][source]

UV coordinates for the current frame (top-left, bottom-right) as Vec2 with flip applied.

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

Override to use sprite-sheet frame UVs instead of region_rect.

property quad_size: simvx.core.math.types.Vec2[source]

Frame size is the texture size divided by sheet grid dimensions.

texture

‘Property(…)’

pixel_size

‘Property(…)’

billboard

‘Property(…)’

flip_h

‘Property(…)’

flip_v

‘Property(…)’

modulate

‘Colour(…)’

centered

‘Property(…)’

offset

‘Property(…)’

alpha_cut

‘Property(…)’

render_priority

‘Property(…)’

region_enabled

‘Property(…)’

region_rect

‘Property(…)’

publish_texture_size(width: int, height: int) None
property texture_size: tuple[int, int]
get_aabb()
on_draw(renderer) None
property texture_slot: int
publish_texture_slot(slot: int) None
publish_overlay_slot(slot: int) None
strict_errors: ClassVar[bool]

True

dev_checks: ClassVar[bool]

None

script_error_raised

‘Signal(…)’

dynamic: bool

False

visible

‘Property(…)’

update_mode

‘Property(…)’

__properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]

None

classmethod __init_subclass__(**kwargs)
property name: str
property visible_in_tree: bool
reset_error() None
add_child(node: simvx.core.node.T) simvx.core.node.T
remove_child(node: simvx.core.node.Node) None
reparent(new_parent: simvx.core.node.Node)
node_at(path, default=_NO_DEFAULT)
find(target, *, direct: bool = False)
find_all(target, *, direct: bool = False)
expect(target, *, direct: bool = False)
ancestor(target)
walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]
property path: str
property is_scene_root: bool
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
on_ready() None
on_enter_tree() None
on_exit_tree() 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)
queue_redraw() None
property render_dirty: bool
clear_children()
destroy()
property destroying: bool
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__()
position

‘_SpatialVecProperty(…)’

rotation

‘Property(…)’

scale

‘_SpatialVecProperty(…)’

render_layer

‘Property(…)’

property rotation_degrees: simvx.core.math.types.Vec3
property world_position: simvx.core.math.types.Vec3
property world_rotation: simvx.core.math.types.Quat
property world_scale: simvx.core.math.types.Vec3
property forward: simvx.core.math.types.Vec3
property right: simvx.core.math.types.Vec3
property up: simvx.core.math.types.Vec3
translate(offset: tuple[float, float, float] | numpy.ndarray)
translate_global(offset: tuple[float, float, float] | numpy.ndarray)
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)
rotate_x(angle: float)
rotate_y(angle: float)
rotate_z(angle: float)
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)
face_along(forward: tuple[float, float, float] | numpy.ndarray, up: tuple[float, float, float] | numpy.ndarray | None = None) None
set_render_layer(index: int, enabled: bool = True) None
is_on_render_layer(index: int) bool
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)