FrameState & PlayerPose
FrameState, PlayerPose, and H36M_JOINT_NAMES define the instantaneous per-frame kinematic and scoreboard contract used across MatchTimeline, PadelVisualizer, and the Universal Match Format (.parquet).
FrameState
Represents the complete state of the court, 9D ball, 4 players, and match scoreboard at a single timestamp timestamp.
- Name
timestamp- Type
- float
- Description
Elapsed time in seconds.
- Name
ball_position- Type
- tuple[float, float, float]
- Description
3D ball coordinates
(x, y, z)in meters (CENTEREDcourt frame).
- Name
ball_velocity- Type
- tuple[float, float, float]
- Description
3D linear ball velocity
(vx, vy, vz)inm/s.
- Name
ball_spin- Type
- tuple[float, float, float]
- Description
3D angular ball velocity
(wx, wy, wz)inrad/s.
- Name
ball_speed_mps / ball_speed_kmh- Type
- float
- Description
Computed scalar linear ball speed in
m/sandkm/h.
- Name
ball_spin_rpm- Type
- float
- Description
Computed total ball spin rate in revolutions per minute (
RPM).
- Name
players- Type
- dict[str, PlayerPose]
- Description
Mapping of player IDs (
"P1".."P4") to theirPlayerPoseinstances.
- Name
score- Type
- str
- Description
Formatted scoreboard string displayed on the 3D HUD.
- Name
sets_a / sets_b- Type
- int
- Description
Completed sets won by Team A and Team B at this frame.
- Name
games_a / games_b- Type
- int
- Description
Games won in the active set by Team A and Team B.
- Name
points_a / points_b- Type
- str
- Description
Point call in the active game (
"0","15","30","40","Ad", or tiebreak integer string).
- Name
server_team- Type
- str
- Description
Serving team identifier (
"A"or"B").
- Name
server_player- Type
- str
- Description
Serving player identifier (
"P1".."P4"or player name).
- Name
point_index- Type
- int
- Description
0-based rally/point index in the match progression.
- Name
in_tiebreak- Type
- bool
- Description
Truewhen the active game is a tiebreak or super-tiebreak.
- Name
is_gold_point- Type
- bool
- Description
Trueon a deciding deuce point (40-40with golden point enabled).
- Name
event- Type
- str | None
- Description
Optional discrete event label at this frame (
"serve","bounce_floor_sliding","shot_smash", etc.).
Stamp Score from MatchScore
Returns a copy of the FrameState with all structured score fields (score, sets_a, sets_b, games_a, games_b, points_a, points_b, in_tiebreak, is_gold_point, point_index, server_team, server_player) populated directly from a MatchScore snapshot.
Arguments
- Name
match_score- Type
- MatchScore
- Description
Immutable
MatchScoresnapshot (e.g.match.current_score).
- Name
point_index- Type
- int
- Description
0-based rally index.
- Name
server_team- Type
- str
- Description
Serving team label (
"A"or"B").
- Name
server_player- Type
- str
- Description
Serving player label.
- Name
golden_point_enabled- Type
- bool
- Description
If
True, setsis_gold_point=Truewhenpoints_a == "40"andpoints_b == "40".
Stamp MatchScore
from padelkit import FrameState, Match, TeamId
match = Match(advantage_method="gold_point")
match.history.add_point(TeamId.A)
frame = FrameState(
timestamp=0.5,
ball_position=(0.0, 2.0, 1.4),
).with_match_score(
match.history.get_current_score(),
point_index=1,
server_team="A",
server_player="P1",
)
print(frame.score, "| points:", frame.points_a, "-", frame.points_b)
PlayerPose
Represents the 3D position, heading, stroke animation state, and optional 17-joint H36M 3D skeletal pose of a single player at a single timestamp.
- Name
player_id- Type
- str
- Description
Player slot identifier (
"P1","P2","P3", or"P4").
- Name
x / y / z- Type
- float
- Description
Root position
(x, y, z)in court meters (CENTEREDcoordinate system).
- Name
yaw_deg- Type
- float
- Description
Facing heading in degrees (
0.0= facing+Y,180.0= facing-Y).
- Name
animation- Type
- str
- Description
Active locomotion or stroke clip ID (
"idle","run","forehand_drive","forehand_serve", etc.).
- Name
team- Type
- str
- Description
Team identifier (
"A"forP1/P2,"B"forP3/P4).
- Name
swing_phase- Type
- float
- Description
Normalized stroke progress in
[0.0, 1.0].
- Name
keypoints_3d- Type
- tuple[tuple[float, float, float], ...] | None
- Description
Optional 17-tuple of
(jx, jy, jz)coordinates in the player's local frame (PelvisXY at(0, 0),Zheight above floor0.0, facing+Y) followingH36M_JOINT_NAMES.
- Name
world_keypoints_3d- Type
- tuple[tuple[float, float, float], ...] | None
- Description
Computed 17-tuple of
(X, Y, Z)joints transformed into absolute 3D court coordinates, orNoneifkeypoints_3dis not set.
Classmethods & Methods
- Name
from_world_keypoints_3d(player_id, world_keypoints_3d, ...)- Type
- PlayerPose
- Description
Constructs a
PlayerPosedirectly from a(17, 3)array or sequence of absolute 3D world joints (e.g. from multi-camera triangulation orMotionBERT), automatically anchoring(x, y)atPelvis (joint 0),zat the lowest ankle, and computing localkeypoints_3d.
- Name
to_dict()- Type
- dict[str, Any]
- Description
Serializes the pose for the Three.js visualizer (including
kp3dwhenkeypoints_3dis populated).
Construct from World 3D Joints
import numpy as np
from padelkit import H36M_JOINT_NAMES, PlayerPose
print("17 H36M joints:", H36M_JOINT_NAMES)
# Example (17, 3) absolute world coordinates in court meters
world_j3d = np.zeros((17, 3), dtype=np.float32)
world_j3d[:, 0] = 1.85 # X = +1.85m
world_j3d[:, 1] = -7.20 # Y = -7.20m
world_j3d[0, 2] = 0.88 # Pelvis Z = 0.88m
world_j3d[10, 2] = 1.66 # Head Z = 1.66m
pose = PlayerPose.from_world_keypoints_3d(
player_id="P1",
world_keypoints_3d=world_j3d,
yaw_deg=10.0,
animation="forehand_drive",
team="A",
swing_phase=0.5,
)
print("Root (x, y, z):", (pose.x, pose.y, pose.z))
print("Pelvis offset:", pose.keypoints_3d[0])
print("World Head Z:", pose.world_keypoints_3d[10][2])