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
Metadata
Release files for hand-tracking-sdk 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| hand_tracking_sdk-1.1.0.tar.gz | 17.2 MB | With provenance | Details for hand_tracking_sdk-1.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| hand_tracking_sdk-1.1.0-py3-none-any.whl | Python 3 | none | any | Details for hand_tracking_sdk-1.1.0-py3-none-any.whl |
Total release size: 17.3 MB
Release files / hand_tracking_sdk-1.1.0.tar.gz
| Download URL | hand_tracking_sdk-1.1.0.tar.gz |
|---|---|
| Size | 17.2 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c3b2ff1c7edba941c629c54c91a8b1142eecffa61ca7c79d8080080db10ca60c
|
|
BLAKE2b-256 checksum How to use checksums |
8ea6deef547513eeb9ef9e08a1e56e653d781a3ec66b91d9feb876863b45087a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 11, 2026.
Transparency logRelease files / hand_tracking_sdk-1.1.0-py3-none-any.whl
| Download URL | hand_tracking_sdk-1.1.0-py3-none-any.whl |
|---|---|
| Size | 49.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2f0118023c964b7f2b650956bb1b4881145363bc28e9fc4d48a9bbe63eb3c364
|
|
BLAKE2b-256 checksum How to use checksums |
84865c3d23152e1cf9adb78f99fdba0ce4cda2d8db600f47e11243d7314de956
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 11, 2026.
Transparency logSecurity for hand-tracking-sdk 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for hand_tracking_sdk-1.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 11, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.