A Python client for Uthana: generate lifelike human motion from text or 2D video, create and auto-rig characters, and manage your motions.
Project description
uthana-python-client
A Python client for Uthana: generate lifelike human motion from text or 2D video, create and auto-rig characters, and manage your motions.
📖 Full API documentation · 🤖 Context7 page
Install
pip install uthana
API key
You need an Uthana account and API key. Sign up for free, then get your API key from account settings once logged in. For full setup, verification, and capabilities, see the Uthana API docs.
Quick start
Context7
Context7 helps LLMs and AI code editors pull up-to-date documentation instead of relying on stale training data. Use it in prompts, e.g.: "How do I create a text-to-motion animation with the Uthana API? use context7 library /websites/uthana_api". Add Uthana as a source: context7.com/websites/uthana_api, then install Context7 in your IDE.
Async by default
All methods are async and return coroutines. Use await inside an async function and asyncio.run() to execute. Async calls are non-blocking: the event loop can run other tasks while waiting on I/O, which is ideal for concurrent requests or UI applications.
Sync variants exist for every method, suffixed with _sync. These block until the request completes and are simpler for scripts or when you don't need concurrency.
import asyncio
from uthana import Uthana
uthana_client = Uthana("your-api-key")
# Async (non-blocking)
async def async_example():
output = await uthana_client.ttm.create("a person walking")
data = await uthana_client.motions.download(output.character_id, output.motion_id, output_format="glb")
return data
data = asyncio.run(async_example())
# Sync (blocking)
def sync_example():
output = uthana_client.ttm.create_sync("a person walking")
data = uthana_client.motions.download_sync(output.character_id, output.motion_id, output_format="glb")
return data
data = sync_example()
Text to motion (ttm)
Generate 3D character animations from natural language prompts.
import asyncio
from uthana import Uthana, UthanaCharacters
uthana_client = Uthana("your-api-key")
async def text_to_motion():
# Basic usage (model defaults from models.toml)
output = await uthana_client.ttm.create("a person walking forward")
print(output.character_id, output.motion_id)
# Use a specific character (default is Tar)
output = await uthana_client.ttm.create(
"a person dancing",
character_id=UthanaCharacters.ava,
)
# Explicit model and advanced options
output = await uthana_client.ttm.create(
"a person waving hello",
model="diffusion-v2",
character_id=UthanaCharacters.manny,
length=5.0,
cfg_scale=2.5,
seed=42,
)
# Download the motion
data = await uthana_client.motions.download(
output.character_id,
output.motion_id,
output_format="glb",
fps=30,
)
asyncio.run(text_to_motion())
Locomotion
Generate controllable, loopable travel motion for a character (stride count, speed, style, direction).
import asyncio
from uthana import Uthana, UthanaCharacters
uthana_client = Uthana("your-api-key")
async def locomotion_example():
styles = await uthana_client.motions.list_locomotion_styles()
print("Available style_id values:", styles)
output = await uthana_client.motions.create_locomotion(
UthanaCharacters.tar,
strides=2,
move_speed=1.3,
style_id="neutral_male_a",
travel_angle=0,
)
print(output.character_id, output.motion_id)
asyncio.run(locomotion_example())
Video to motion (vtm)
Extract motion capture from video files. Returns a job to poll until complete.
import asyncio
from uthana import Uthana, UthanaCharacters
uthana_client = Uthana("your-api-key")
async def video_to_motion():
job = await uthana_client.vtm.create("path/to/dance.mp4", motion_name="my_dance")
while job["status"] not in ("FINISHED", "FAILED"):
await asyncio.sleep(5) # Non-blocking; other tasks can run while waiting
job = await uthana_client.jobs.get(job["id"])
if job["status"] == "FINISHED":
motion_id = job["result"]["result"]["id"]
data = await uthana_client.motions.download(
UthanaCharacters.tar, motion_id, output_format="glb", fps=30
)
with open("dance.glb", "wb") as f:
f.write(data)
asyncio.run(video_to_motion())
Characters
Docs: Auto-rig / add a character · Download a character
Upload, list, and download characters. Supports auto-rigging for humanoid meshes, and generation from text prompts or image files.
import asyncio
from uthana import Uthana
uthana_client = Uthana("your-api-key")
async def manage_characters():
# Upload and auto-rig a character from a file
output = await uthana_client.characters.create_from_file("path/to/character.glb")
print(output.character_id)
print(output.auto_rig_confidence) # 0–1.0, higher is better
# Download the rigged character
data = await uthana_client.characters.download(output.character_id, output_format="glb")
with open("character_rigged.glb", "wb") as f:
f.write(data)
# List all characters
for c in await uthana_client.characters.list():
print(c.get("id"), c.get("name"))
# Text-to-character: one-shot with callback
result = await uthana_client.characters.create_from_prompt(
prompt="a knight in shining armor",
name="Knight",
on_previews_ready=lambda previews: previews[0]["key"],
)
print(result.character.get("id"))
# Text-to-character: async callback (e.g. show a UI and return the chosen key)
result = await uthana_client.characters.create_from_prompt(
prompt="a futuristic soldier",
on_previews_ready=lambda previews: show_picker_ui(previews),
)
# Text-to-character: two-step (inspect previews before confirming)
pending = await uthana_client.characters.create_from_prompt(prompt="a futuristic soldier")
# pending.previews is a list of {"key": ..., "url": ...} — show them to the user
result = await uthana_client.characters.generate_from_image(pending, pending.previews[0]["key"])
# Image-to-character: upload an image file (always one-shot)
result = await uthana_client.characters.create_from_image("path/to/reference.png")
# Rename or delete
await uthana_client.characters.rename(result.character["id"], "New name")
await uthana_client.characters.delete(result.character["id"])
asyncio.run(manage_characters())
Motions
Docs: Asset management · Retargeting
List, download, preview, delete, rename, favorite, and bake motions.
import asyncio
from uthana import Uthana, UthanaCharacters
uthana_client = Uthana("your-api-key")
async def manage_motions():
# List all motions
for m in await uthana_client.motions.list():
print(m.get("id"), m.get("name"))
# Download a motion
data = await uthana_client.motions.download(
UthanaCharacters.tar,
"motion-id",
output_format="glb",
fps=30,
no_mesh=False,
)
# Download motion preview WebM (does not charge download seconds)
preview_bytes = await uthana_client.motions.preview(character_id, motion_id)
with open("preview.webm", "wb") as f:
f.write(preview_bytes)
# Rename a motion
await uthana_client.motions.rename("motion-id", "New name")
# Delete a motion (soft delete)
await uthana_client.motions.delete("motion-id")
# Favorite / unfavorite
await uthana_client.motions.favorite("motion-id", True)
# Bake custom GLTF animation data as a new motion for an existing character
result = await uthana_client.motions.bake_with_changes(
gltf_content, "My motion", character_id=character_id
)
print(result.motion_id, result.character_id)
asyncio.run(manage_motions())
Organization and user (org)
Docs: Account and organization
Get user and organization info, including quota.
import asyncio
from uthana import Uthana
uthana_client = Uthana("your-api-key")
async def get_org_info():
user = await uthana_client.org.get_user()
print(user.get("id"), user.get("name"), user.get("email"))
org = await uthana_client.org.get_org()
print(org.get("name"))
print(org.get("motion_download_secs_per_month_remaining"), "seconds remaining")
asyncio.run(get_org_info())
Jobs
Docs: Video to motion (job polling)
Poll async jobs (e.g. video to motion).
import asyncio
from uthana import Uthana
uthana_client = Uthana("your-api-key")
async def poll_job():
job = await uthana_client.jobs.get("job-id")
print(job["status"]) # RESERVED, READY, FINISHED, FAILED
print(job["result"]) # Result payload when FINISHED
asyncio.run(poll_job())
Uthana characters
Docs: Auto-rig / add a character
Pre-built characters you can use without uploading your own:
| Attribute | Character ID |
|---|---|
UthanaCharacters.tar |
cXi2eAP19XwQ |
UthanaCharacters.ava |
cmEE2fT4aSaC |
UthanaCharacters.manny |
c43tbGks3crJ |
UthanaCharacters.quinn |
czCjWEMtWxt8 |
UthanaCharacters.y_bot |
cJM4ngRqXg83 |
Testing
Integration tests (tests/test_client.py) require UTHANA_API_KEY. Use .env.local (gitignored) or env vars:
# .env.local
UTHANA_API_KEY=your_key
UTHANA_DOMAIN=custom.uthana.com # optional, for non-production
Releasing and PyPI
Maintainers publish to PyPI from GitHub Actions.
Release flow
Prepare the version/tag, push it, then verify GitHub can see the tag:
uv run python scripts/release.py prepare --version 1.2.3
uv run python scripts/release.py push
uv run python scripts/release.py verify
Shorthands: make release-prepare VERSION=…, make release-push, make release-verify.
Checks and dry-runs
verifycheckspyproject.toml, the localv*tag atHEAD, and the tag onorigin. Use--skip-remote-checkbefore pushing, orSKIP_RELEASE_TAG_CHECK=1to bypass.uv run python scripts/release.py push --dry-runpreviews the branch/tag push.publishdeletesdist/beforeuv buildso leftover wheels (e.g. an old 0.2.0) are not uploaded next to the current version.uv run python scripts/release.py publish --dry-runbuilds and validates a PyPI upload without uploading. Add--index testpypifor TestPyPI.
Auth and TestPyPI
The release workflow uses PyPI Trusted Publishing (OIDC). Add this repo as a trusted publisher on both PyPI and TestPyPI if you use both. For TestPyPI, run Actions → Release → Run workflow and enable Upload to TestPyPI.
For local uploads, set UV_PUBLISH_TOKEN from the target index, then run:
UV_PUBLISH_TOKEN=your_token uv run python scripts/release.py publish --index testpypi
Production is the default (--index pypi), but routine production releases should use tag push → CI.
Type hints
The package ships an empty py.typed marker (PEP 561) so type checkers treat uthana as providing inline types. Keep src/uthana/py.typed in the repo and in package data (pyproject.toml).
Custom domain
Use a different API host by passing domain=:
uthana_client = Uthana("your-api-key", domain="custom.example.com")
Support
- Discord for community support
- support@uthana.com or Slack for priority support
License
Apache 2.0
Project details
Release history Release notifications | RSS feed
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 uthana-0.3.1.tar.gz.
File metadata
- Download URL: uthana-0.3.1.tar.gz
- Upload date:
- Size: 27.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
92050e6c10160434ea1e4dfea1e9324426af153df27730bfeb335801bec9a15c
|
|
| MD5 |
ca0822f3ad3ef6094c1e0e4cde3f0c6e
|
|
| BLAKE2b-256 |
ad325dd9e06ac9d0e266ac270a0dd4eacb7c4362d19fc927857c4a1bc6654263
|
Provenance
The following attestation bundles were made for uthana-0.3.1.tar.gz:
Publisher:
release.yml on Uthana/uthana-python-client
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
uthana-0.3.1.tar.gz -
Subject digest:
92050e6c10160434ea1e4dfea1e9324426af153df27730bfeb335801bec9a15c - Sigstore transparency entry: 1697491914
- Sigstore integration time:
-
Permalink:
Uthana/uthana-python-client@1253141e491f704efe5e54edf9cfacbc1978318d -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/Uthana
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1253141e491f704efe5e54edf9cfacbc1978318d -
Trigger Event:
push
-
Statement type:
File details
Details for the file uthana-0.3.1-py3-none-any.whl.
File metadata
- Download URL: uthana-0.3.1-py3-none-any.whl
- Upload date:
- Size: 23.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1503e37bb072399ef1c1e35cf0d4b4bbd35592537ab5142db2f0c1632ca70671
|
|
| MD5 |
71edb97b4a91d1873e41ff56504a09a2
|
|
| BLAKE2b-256 |
b495240475236db27b33c4ba987f8035de92fbcf277f8894d2878d57a1e25be3
|
Provenance
The following attestation bundles were made for uthana-0.3.1-py3-none-any.whl:
Publisher:
release.yml on Uthana/uthana-python-client
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
uthana-0.3.1-py3-none-any.whl -
Subject digest:
1503e37bb072399ef1c1e35cf0d4b4bbd35592537ab5142db2f0c1632ca70671 - Sigstore transparency entry: 1697491994
- Sigstore integration time:
-
Permalink:
Uthana/uthana-python-client@1253141e491f704efe5e54edf9cfacbc1978318d -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/Uthana
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1253141e491f704efe5e54edf9cfacbc1978318d -
Trigger Event:
push
-
Statement type: