Pipe your capture volume into your code.
Zendo runs the capture; the SDK is the client. While Zendo is running, connect to its live stream and read typed joint orientations, landmarks and joint angles — in a handful of lines, in Python or Rust.
How it works#
Zendo does the perception work — capturing from your cameras, tracking pose, and reconstructing a 3D skeleton on your machine. While a capture session is running, Zendo exposes that skeleton as a live WebSocket stream on your local network.
The SDK is a thin client for that stream. It handles port discovery, the connection lifecycle, optional reconnection, and decoding, so you get typed events — body orientations, landmarks, hands and joint angles — instead of raw bytes. It does not start or manage Zendo itself: Zendo must already be running for the SDK to connect.
Install#
The Python package is a thin layer over the Rust crate, so both decode the same wire protocol. Install whichever fits your stack.
pip install zendo-sdkConnecting#
Connecting comes down to one question: is your code running on the same machine as Zendo, or a different one? On the same machine, the SDK finds Zendo for you. Across machines, you point it at the address Zendo displays.
The connection address
With Zendo running, open Settings → Connection. Zendo shows two addresses for the live stream — copy whichever matches where your client runs:
- Localhost
- ws://localhost:5432 — for a client on the same machine as Zendo.
- Network IP
- ws://192.168.1.42:5432 — Zendo's address on your local network, for a client on a different machine. Your IP and port will differ.
Zendo binds ports 5432–5435 and uses the first one free, so the port shown in Settings is the source of truth. The stream is plain ws:// — unencrypted and unauthenticated.
Same machine
If your code runs on the same computer as Zendo, you don't need to look the address up at all. Call connect() and the SDK scans 127.0.0.1 across the port range and attaches to the first Zendo it finds.
Another machine
To stream to a different computer — your code on a laptop, Zendo on a capture rig — pass the Network IP from Zendo's Settings to connect_url. Both machines must be on the same local network, connected over WiFi or ethernet, and able to reach each other (no client isolation or firewall blocking the port).
import zendo
# Same machine as Zendo? Auto-discover it on ports 5432-5435.client = zendo.connect()
# Or name localhost explicitly.client = zendo.connect_url("ws://localhost:5432")
# Different machine? Use the Network IP shown in Zendo's Settings.client = zendo.connect_url("ws://192.168.1.42:5432")Both clients also expose connect_at(port) if you want to skip discovery and target an explicit port on localhost.
Streaming motion data#
Once connected, iterate the client. Each iteration yields the next frame as a typed event. The Python client is synchronous and blocking — iterating waits for the next frame — which keeps it ergonomic in notebooks and scripts. The Rust client is async on Tokio.
import zendo
# The client is synchronous and blocking: iterating waits for the next frame.with zendo.connect() as client: print(f"connected on port {client.port}") for event in client: match event: case zendo.BodyQuaternions(frame): print("hips:", frame.hips.w, frame.hips.x, frame.hips.y, frame.hips.z) case zendo.BodyLandmarks(frame): print("nose:", frame.nose.x, frame.nose.y, frame.nose.z) case zendo.HandQuaternions(side, frame): print(side, "wrist:", frame.wrist.w) case zendo.BodyIsbAngles(frame): print("right elbow flexion:", frame.right_elbow_flexion)What you get
The stream carries several event types. You'll typically match on the ones you care about and ignore the rest.
- Body quaternions
- Orientation of 13 body joints — hips, spine, arms, legs — each as a (w, x, y, z) quaternion.
- Body landmarks
- 19 body keypoints (nose, shoulders, wrists, ankles, …), each with x, y, z and a confidence value.
- Hand quaternions / landmarks
- Per-hand finger tracking, tagged with side (left or right) — 16 joint orientations or 21 landmarks per hand.
- Body ISB angles
- 21 clinical joint angles in radians (e.g. right_elbow_flexion, neck_flexion), following ISB conventions.
Frames expose one attribute per joint or landmark and are iterable, so you can also loop over every joint by name rather than reaching for them individually.
Reconnection#
By default, a dropped connection ends the stream. Opt into automatic reconnection to ride out a Zendo restart or a brief network blip — the client re-establishes the connection with exponential backoff and keeps yielding events transparently.
import zendo
# Re-establishes a dropped connection with exponential backoff.client = zendo.connect(reconnect=True, base_delay_ms=250, max_retries=10)Full API on the package registries.
Builder options, the stream interface, every frame type and the wire protocol live alongside each package.