# Skeleton SimVX provides skeletal animation support through the `Bone` dataclass and `Skeleton` class. Together they define a bone hierarchy and compute joint matrices for GPU vertex skinning. ## Bone A `Bone` represents a single bone in the hierarchy: | Field | Type | Description | |-------|------|-------------| | `name` | `str` | Human-readable bone name | | `parent_index` | `int` | Index of parent bone (-1 for root) | | `inverse_bind_matrix` | `np.ndarray (4x4)` | Transforms from mesh space to bone-local space | | `local_transform` | `np.ndarray (4x4)` | Default local-space transform relative to parent | ## Skeleton `Skeleton` holds an ordered list of bones and computes the final joint matrices used by the GPU skinning shader. ### Creating a Skeleton Bones must be ordered so that every parent appears before its children: ```python import numpy as np from simvx.core import Bone, Skeleton # Build a simple arm: root -> upper_arm -> forearm -> hand bones = [ Bone(name="root", parent_index=-1), Bone(name="upper_arm", parent_index=0, local_transform=translate(0, 2, 0)), Bone(name="forearm", parent_index=1, local_transform=translate(0, 1.5, 0)), Bone(name="hand", parent_index=2, local_transform=translate(0, 1.0, 0)), ] skeleton = Skeleton(bones) print(skeleton.bone_count) # 4 ``` ### Computing a Pose Call `compute_pose()` to walk the hierarchy and produce joint matrices. Optionally override individual bone transforms: ```python # Default pose (uses each bone's local_transform) skeleton.compute_pose() # Animated pose — override forearm rotation import math animated = { 2: rotate((1, 0, 0), math.radians(45)) @ translate((0, 1.5, 0)), # forearm rotated 45 deg } skeleton.compute_pose(bone_transforms=animated) ``` ### Joint Matrices After `compute_pose()`, the `joint_matrices` property returns a `(bone_count, 4, 4)` NumPy array. Each matrix is `world_transform @ inverse_bind_matrix` -- ready to upload to an SSBO. ```python matrices = skeleton.joint_matrices # shape (4, 4, 4) for 4 bones ``` The vertex shader applies skinning by blending up to 4 joint matrices per vertex using bone weights: ```glsl vec4 skinned = vec4(0.0); for (int i = 0; i < 4; i++) { skinned += joint_matrices[bone_ids[i]] * vec4(position, 1.0) * bone_weights[i]; } ``` ### Finding Bones Look up a bone index by name: ```python idx = skeleton.find_bone("forearm") # 2 idx = skeleton.find_bone("missing") # -1 ``` ## API Reference See {py:mod}`simvx.core.skeleton` for the complete skeleton API.