simvx.core.skeleton

Skeleton and bone hierarchy for skeletal animation.

Skeleton is a Node3D that manages a flat array of Bone data. Each frame it walks the parent chain, computes world transforms, and produces GPU-ready joint matrices (world * inverse_bind) suitable for SSBO upload.

SkeletonProfile provides a standard naming convention so retargeting, animation libraries, and humanoid IK can agree on bone names.

Module Contents

Classes

Bone

Single bone in a skeleton hierarchy.

Skeleton

Bone hierarchy with GPU-ready joint matrix computation.

SkeletonProfile

Standard bone naming convention for retargeting and humanoid IK.

Data

API

simvx.core.skeleton.log[source]

‘getLogger(…)’

simvx.core.skeleton.__all__

[‘Bone’, ‘Skeleton’, ‘SkeletonProfile’, ‘PROFILE_HUMANOID’]

class simvx.core.skeleton.Bone[source]

Single bone in a skeleton hierarchy.

name: str = <Multiline-String>
parent_index: int

None

inverse_bind_matrix: numpy.ndarray

‘field(…)’

local_transform: numpy.ndarray

‘field(…)’

class simvx.core.skeleton.Skeleton(bones: list[simvx.core.skeleton.Bone] | None = None, **kwargs)[source]

Bases: simvx.core.nodes_3d.node3d.Node3D

Bone hierarchy with GPU-ready joint matrix computation.

Joint matrices = parent_world * local_transform * inverse_bind_matrix These are uploaded to an SSBO for vertex skinning in the shader.

As a Node3D it participates in the scene tree, inherits a 3D transform, and can be animated/parented like any other spatial node.

Signals: bone_pose_changed: Emitted after compute_pose updates joint matrices. Connected MeshInstance3D nodes (via skin) can listen to know when to re-upload skinning data.

Initialization

property bone_count: int
property joint_matrices: numpy.ndarray

Get computed joint matrices (bone_count, 4, 4). Call compute_pose() first.

set_bone_pose(bone_index: int, transform: numpy.ndarray) None[source]

Override a single bone’s local transform for the current pose.

The override persists until cleared via clear_bone_pose or another set_bone_pose call. Call compute_pose() afterwards (or let process() do it) to propagate the change.

get_bone_pose(bone_index: int) numpy.ndarray[source]

Return the current local transform for a bone (override or default).

clear_bone_pose(bone_index: int) None[source]

Remove the per-bone pose override, reverting to the bone’s default local_transform.

clear_all_bone_poses() None[source]

Remove all per-bone pose overrides.

get_bone_global_transform(bone_index: int) numpy.ndarray[source]

Return the world-space transform of a bone after the last compute_pose.

This is not the joint matrix (which includes inverse-bind); it is the raw world transform useful for attachment points, IK targets, etc.

compute_pose(bone_transforms: dict[int, numpy.ndarray] | None = None) None[source]

Compute final joint matrices from bone-local transforms.

Args: bone_transforms: Optional additional overrides for bone-local transforms (merged on top of set_bone_pose overrides). Maps bone_index -> 4x4 local transform matrix. Bones not in any override use their default local_transform.

process(dt: float) None[source]

Auto-recompute pose each frame if there are any overrides.

find_bone(name: str) int[source]

Find bone index by name. Returns -1 if not found.

add_bone(bone: simvx.core.skeleton.Bone) int[source]

Append a bone and return its index.

render_layer

‘Property(…)’

property position
property rotation: simvx.core.math.types.Quat
property scale
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)
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)
strict_errors: ClassVar[bool]

True

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, recursive: bool = True) 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
draw(renderer) 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)
clear_children()
destroy()
property app
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]
__repr__()
class simvx.core.skeleton.SkeletonProfile[source]

Standard bone naming convention for retargeting and humanoid IK.

A profile defines an ordered list of bone names, optional parent relationships (by name), and bone groups for logical grouping.

Usage::

profile = PROFILE_HUMANOID
idx = skel.find_bone(profile.bone_names[0])  # "Hips"

# Validate a skeleton against the profile
missing = profile.validate(skel)
name: str

None

bone_names: list[str]

‘field(…)’

bone_parents: dict[str, str]

‘field(…)’

bone_groups: dict[str, list[str]]

‘field(…)’

validate(skeleton: simvx.core.skeleton.Skeleton) list[str][source]

Return a list of profile bone names missing from skeleton.

find_in_skeleton(skeleton: simvx.core.skeleton.Skeleton, profile_bone_name: str) int[source]

Look up a profile bone name in a skeleton. Returns -1 if not found.

get_parent(bone_name: str) str | None[source]

Return the profile-defined parent bone name, or None for root bones.

get_group(group_name: str) list[str][source]

Return bone names belonging to a group, or empty list.

simvx.core.skeleton.PROFILE_HUMANOID

‘SkeletonProfile(…)’