simvx.core.skeleton2d

2D skeletal animation: Skeleton2D, Bone2D, and IK modifications.

Spine/DragonBones-style 2D skeletal animation built on the Node2D hierarchy. Bones are Node2D nodes that add rest-pose semantics; a Skeleton2D groups them and provides batch operations (reset, enumerate, IK).

Module Contents

Classes

Bone2D

A bone in a 2D skeleton hierarchy.

Skeleton2D

Container node for a 2D bone hierarchy.

SkeletonModification2D

Base class for 2D skeleton modifications (IK, constraints, etc.).

SkeletonModification2DCCDIK

Cyclic Coordinate Descent IK for 2D bone chains.

SkeletonModification2DTwoBoneIK

Analytical two-bone IK solver.

Data

API

simvx.core.skeleton2d.log[source]

‘getLogger(…)’

simvx.core.skeleton2d.__all__

[‘Bone2D’, ‘Skeleton2D’, ‘SkeletonModification2D’, ‘SkeletonModification2DCCDIK’, ‘SkeletonModificat…

class simvx.core.skeleton2d.Bone2D(bone_length: float = 0.0, rest_transform: simvx.core.math_types.Transform2D | None = None, **kwargs)[source]

Bases: simvx.core.nodes_2d.node2d.Node2D

A bone in a 2D skeleton hierarchy.

Extends Node2D with a rest transform — the bone’s default pose. Skeletal animation works by offsetting the bone from its rest pose.

Attributes: rest_transform: Default pose (Transform2D). bone_length: Visual length of the bone (pixels). bone_angle: Additional angle applied on top of the rest rotation (radians).

Initialization

bone_length

‘Property(…)’

property rest_transform: simvx.core.math_types.Transform2D

The bone’s rest (bind) pose.

property bone_angle: float

Pose angle offset from rest rotation (radians).

apply_pose(angle: float, length: float | None = None) None[source]

Set the bone to a specific pose.

Args: angle: Rotation offset from rest pose (radians). length: Optional override for bone_length.

reset_to_rest() None[source]

Reset this bone to its rest transform.

set_as_rest() None[source]

Capture current local transform as the new rest pose.

get_skeleton() simvx.core.skeleton2d.Skeleton2D | None[source]

Walk up the tree to find the parent Skeleton2D.

property bone_tip: simvx.core.math.types.Vec2

Global position of the bone tip (end point), computed from length and rotation.

z_index

‘Property(…)’

z_as_relative

‘Property(…)’

render_layer

‘Property(…)’

set_render_layer(index: int, enabled: bool = True) None
is_on_render_layer(index: int) bool
property absolute_z_index: int
property position: simvx.core.math.types.Vec2
property rotation: float
property rotation_degrees: float
property scale: simvx.core.math.types.Vec2
property world_position: simvx.core.math.types.Vec2
property world_rotation: float
property world_scale: simvx.core.math.types.Vec2
property forward: simvx.core.math.types.Vec2
property right: simvx.core.math.types.Vec2
translate(offset: tuple[float, float] | numpy.ndarray)
rotate(radians: float)
rotate_deg(degrees: float)
look_at(target: tuple[float, float] | numpy.ndarray)
transform_points(points: list[simvx.core.math.types.Vec2]) list[simvx.core.math.types.Vec2]
draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, colour=None)
wrap_screen(margin: float = 20)
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
process(dt: float) 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.skeleton2d.Skeleton2D(**kwargs)[source]

Bases: simvx.core.nodes_2d.node2d.Node2D

Container node for a 2D bone hierarchy.

Holds Bone2D children (which may themselves have Bone2D children) and provides batch operations and IK modification support.

Signals: bones_changed: Emitted when the bone hierarchy changes.

Initialization

bones_changed

‘Signal(…)’

get_bones() list[simvx.core.skeleton2d.Bone2D][source]

Return all Bone2D nodes in hierarchy order (cached).

property bone_count: int

Number of Bone2D nodes in the hierarchy.

get_bone(index: int) simvx.core.skeleton2d.Bone2D[source]

Get Bone2D by index in hierarchy order.

Raises: IndexError: If index is out of range.

find_bone(name: str) simvx.core.skeleton2d.Bone2D | None[source]

Find a bone by name. Returns None if not found.

find_bone_index(name: str) int[source]

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

set_bone_rest(index: int, transform: simvx.core.math_types.Transform2D) None[source]

Set the rest pose for the bone at index.

reset_to_rest() None[source]

Reset every bone in the skeleton to its rest pose.

capture_rest() None[source]

Capture the current pose of all bones as the rest pose.

add_modification(mod: simvx.core.skeleton2d.SkeletonModification2D) None[source]

Register a skeleton modification (e.g. IK solver).

remove_modification(mod: simvx.core.skeleton2d.SkeletonModification2D) None[source]

Remove a previously registered modification.

execute_modifications(delta: float) None[source]

Run all registered modifications (call from process or manually).

add_child(child, **kwargs)[source]
remove_child(child)[source]
process(dt: float)[source]

Execute IK modifications each frame.

z_index

‘Property(…)’

z_as_relative

‘Property(…)’

render_layer

‘Property(…)’

set_render_layer(index: int, enabled: bool = True) None
is_on_render_layer(index: int) bool
property absolute_z_index: int
property position: simvx.core.math.types.Vec2
property rotation: float
property rotation_degrees: float
property scale: simvx.core.math.types.Vec2
property world_position: simvx.core.math.types.Vec2
property world_rotation: float
property world_scale: simvx.core.math.types.Vec2
property forward: simvx.core.math.types.Vec2
property right: simvx.core.math.types.Vec2
translate(offset: tuple[float, float] | numpy.ndarray)
rotate(radians: float)
rotate_deg(degrees: float)
look_at(target: tuple[float, float] | numpy.ndarray)
transform_points(points: list[simvx.core.math.types.Vec2]) list[simvx.core.math.types.Vec2]
draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, colour=None)
wrap_screen(margin: float = 20)
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
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.skeleton2d.SkeletonModification2D[source]

Base class for 2D skeleton modifications (IK, constraints, etc.).

Initialization

property skeleton: simvx.core.skeleton2d.Skeleton2D | None
abstractmethod execute(delta: float) None[source]

Override in subclasses to apply the modification.

class simvx.core.skeleton2d.SkeletonModification2DCCDIK(tip_bone_index: int = 0, chain_length: int = 2, max_iterations: int = 10, tolerance: float = 1.0)[source]

Bases: simvx.core.skeleton2d.SkeletonModification2D

Cyclic Coordinate Descent IK for 2D bone chains.

Iteratively rotates each bone in the chain (from tip to root) to point toward the target. Converges quickly for simple chains.

Attributes: target: World-space target position (Vec2). tip_bone_index: Index of the end-effector bone. chain_length: Number of bones in the chain (walking up from tip). max_iterations: CCD iterations per execute call. tolerance: Distance threshold to consider the target reached.

Initialization

execute(delta: float) None[source]

Run CCD IK iterations.

property skeleton: simvx.core.skeleton2d.Skeleton2D | None
class simvx.core.skeleton2d.SkeletonModification2DTwoBoneIK(upper_bone_index: int = 0, lower_bone_index: int = 1, flip: bool = False)[source]

Bases: simvx.core.skeleton2d.SkeletonModification2D

Analytical two-bone IK solver.

Given a two-bone chain (upper + lower), computes exact joint angles using the law of cosines. Faster and more stable than CCD for exactly two bones.

Attributes: target: World-space target position (Vec2). upper_bone_index: Index of the upper (root-side) bone. lower_bone_index: Index of the lower (tip-side) bone. flip: Mirror the elbow direction.

Initialization

execute(delta: float) None[source]

Solve two-bone IK analytically.

property skeleton: simvx.core.skeleton2d.Skeleton2D | None