Python SDK for Hand Tracking Streamer telemetry
Project description
Python SDK for consuming telemetry from Hand Tracking Streamer (HTS)
Hand Tracking SDK is a Python package for consuming HTS hand-tracking telemetry (UDP/TCP), parsing wrist/landmark data into typed frames, and providing conversion, visualization, and integration-ready APIs.
This SDK is hosted on PyPI, with API documentation Here
Installation
pip install hand-tracking-sdk
Optional visualization support with Rerun:
pip install "hand-tracking-sdk[visualization]"
Quickstart
from hand_tracking_sdk import HTSClient, HTSClientConfig, StreamOutput
client = HTSClient(
HTSClientConfig(
output=StreamOutput.BOTH, # packets + assembled frames
)
)
for event in client.iter_events():
print(event)
What HTS Sends
HTS emits UTF-8 CSV lines:
- wrist packet: 7 floats (
x, y, z, qx, qy, qz, qw) - landmarks packet: 63 floats (
21 x [x, y, z])
The SDK validates packet labels, hand side, and exact value counts.
Streaming Client
HTSClient provides a high-level sync stream with filtering and error policy controls.
- Transport: UDP, TCP server, TCP client
- Output: raw packets, assembled frames, or both
- Hand filter: left, right, or both
- Error policy: strict (raise) or tolerant (skip malformed)
- Observability:
get_stats()counters,log_hookfor structured events
Frame Assembly
HandFrameAssembler correlates wrist + landmark packets into per-hand HandFrame
objects. Head pose packets produce HeadFrame events. Stale out-of-order updates
are discarded.
A HandFrame includes:
side: Left or Rightwrist:WristPose(x, y, z, qx, qy, qz, qw)landmarks.points: 21 MediaPipe-style(x, y, z)joints- Per-joint access:
frame.get_joint(JointName.INDEX_TIP) - Per-finger access:
frame.get_finger("index") - Timing metadata:
recv_ts_ns,source_ts_ns,sequence_id
Coordinate Conversion
Explicit Unity left-handed to right-handed converters:
from hand_tracking_sdk.convert import (
convert_hand_frame_unity_left_to_right,
unity_left_to_rfu_position, # right-forward-up
unity_left_to_rfu_rotation_matrix,
)
Joint & Finger Access
To get telemetry for a specific joint from a frame, use get_joint(...).
Joint names and order follow the HTS streamed contract (wrist is JointName.WRIST).
from hand_tracking_sdk import HTSClient, HTSClientConfig, JointName, StreamOutput
client = HTSClient(HTSClientConfig(output=StreamOutput.FRAMES))
for frame in client.iter_events():
x, y, z = frame.get_joint(JointName.INDEX_TIP)
print(
f"side={frame.side.value} joint={JointName.INDEX_TIP.value} "
f"xyz=({x:.5f}, {y:.5f}, {z:.5f}) recv_ts_ns={frame.recv_ts_ns}"
)
You can also query by finger group:
index_points = frame.get_finger("index")
# returns dict[JointName, tuple[float, float, float]]
# keys include JointName.INDEX_PROXIMAL, JointName.INDEX_TIP, ...
Examples
Telemetry
| Script | Description |
|---|---|
examples/visualize_rerun.py |
Rerun 3D visualization with coordinate frames and jitter metrics |
examples/stream_frames.py |
Print assembled frames to console |
examples/log_to_jsonl.py |
JSONL capture for replay and analysis |
examples/jitter_report.py |
Timing jitter report |
uv run python examples/visualize_rerun.py --transport tcp_server --host 0.0.0.0 --port 8000
Video Host (WebRTC)
Host-side scripts that stream video back to the Quest headset over WebRTC.
See examples/video/README.md for details.
| Script | Source | Description |
|---|---|---|
test_pattern_video_host.py |
Test pattern | Colour bars — no hardware needed |
webcam_video_host.py |
USB webcam | Streams a local camera feed |
inspire_hand_video_host.py |
MuJoCo | Bimanual Inspire Hand with vector retargeting |
shadow_hand_video_host.py |
MuJoCo | Bimanual Shadow Hand E3M5 with vector retargeting |
aloha_video_host.py |
MuJoCo | ALOHA 2 bimanual arms with IK |
# Test pattern — no extra dependencies:
uv run examples/video/test_pattern_video_host.py
# Shadow Hand bimanual retargeting:
uv run examples/video/shadow_hand_video_host.py --mocap-tcp-port 5555
Simulation Teleop
The MuJoCo video hosts close a full teleoperation loop: Quest sends hand + head mocap over TCP, Python drives a MuJoCo simulation, and the rendered camera view streams back to the headset over WebRTC.
Quest 3/3S ──TCP──► HTSClient ──► MuJoCo pre_step + mj_step + render
│
Quest 3/3S ◄────────────── WebRTC H.264 ◄────────────┘
Protocol and Docs
- HTS protocol: hand-tracking-streamer README
- SDK API docs: hand-tracking-sdk.readthedocs.io
License
Apache-2.0
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hand_tracking_sdk-1.1.0.tar.gz.
File metadata
- Download URL: hand_tracking_sdk-1.1.0.tar.gz
- Upload date:
- Size: 17.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c3b2ff1c7edba941c629c54c91a8b1142eecffa61ca7c79d8080080db10ca60c
|
|
| MD5 |
34a32b62786cffaf6c825ac7ed4a3205
|
|
| BLAKE2b-256 |
8ea6deef547513eeb9ef9e08a1e56e653d781a3ec66b91d9feb876863b45087a
|
Provenance
The following attestation bundles were made for hand_tracking_sdk-1.1.0.tar.gz:
Publisher:
release.yml on wengmister/hand-tracking-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hand_tracking_sdk-1.1.0.tar.gz -
Subject digest:
c3b2ff1c7edba941c629c54c91a8b1142eecffa61ca7c79d8080080db10ca60c - Sigstore transparency entry: 1079078171
- Sigstore integration time:
-
Permalink:
wengmister/hand-tracking-sdk@6ca05d1d5b00dfd89535aef74f698d6765bf1229 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/wengmister
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ca05d1d5b00dfd89535aef74f698d6765bf1229 -
Trigger Event:
push
-
Statement type:
File details
Details for the file hand_tracking_sdk-1.1.0-py3-none-any.whl.
File metadata
- Download URL: hand_tracking_sdk-1.1.0-py3-none-any.whl
- Upload date:
- Size: 49.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2f0118023c964b7f2b650956bb1b4881145363bc28e9fc4d48a9bbe63eb3c364
|
|
| MD5 |
79215d930ac9b18ee16c92762c9d79e7
|
|
| BLAKE2b-256 |
84865c3d23152e1cf9adb78f99fdba0ce4cda2d8db600f47e11243d7314de956
|
Provenance
The following attestation bundles were made for hand_tracking_sdk-1.1.0-py3-none-any.whl:
Publisher:
release.yml on wengmister/hand-tracking-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hand_tracking_sdk-1.1.0-py3-none-any.whl -
Subject digest:
2f0118023c964b7f2b650956bb1b4881145363bc28e9fc4d48a9bbe63eb3c364 - Sigstore transparency entry: 1079078181
- Sigstore integration time:
-
Permalink:
wengmister/hand-tracking-sdk@6ca05d1d5b00dfd89535aef74f698d6765bf1229 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/wengmister
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ca05d1d5b00dfd89535aef74f698d6765bf1229 -
Trigger Event:
push
-
Statement type: