Download a motion
Download generated motions in FBX or GLB format using the motion download endpoints.
Step 1: Identify your character and motion IDs
You need both the characterId and motionId to download files.
Note: The filename in the URL is customizable for /motion/file/ and /motion/animation/ endpoints. You can use any filename you want (e.g., motion.fbx, walking-animation.glb). The /motion/bundle/ endpoint requires the fixed filename character.glb or character.fbx.
Retargeting: When you download a motion with a specific character ID, retargeting happens automatically—the motion is adapted to work with that character's skeleton and proportions.
Step 2: Download the motion file
- Shell
- Python
- TypeScript
- C#
API_KEY="{{apiKey}}"
CHARACTER_ID="cXi2eAP19XwQ"
MOTION_ID="your-motion-id"
# FBX (includes character mesh)
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/motion.fbx" \
-u $API_KEY: \
-o motion.fbx
# GLB (includes character mesh)
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/motion.glb" \
-u $API_KEY: \
-o motion.glb
import requests
API_KEY = "{{apiKey}}"
CHARACTER_ID = "cXi2eAP19XwQ"
MOTION_ID = "your-motion-id"
fbx_url = f"https://uthana.com/motion/file/motion_viewer/{CHARACTER_ID}/{MOTION_ID}/motion.fbx"
response = requests.get(fbx_url, auth=(API_KEY, ""))
with open("motion.fbx", "wb") as f:
f.write(response.content)
const API_KEY = "{{apiKey}}";
const CHARACTER_ID = "cXi2eAP19XwQ";
const MOTION_ID = "your-motion-id";
const authString = btoa(`${API_KEY}:`);
const fbxUrl = `https://uthana.com/motion/file/motion_viewer/${CHARACTER_ID}/${MOTION_ID}/motion.fbx`;
const response = await fetch(fbxUrl, {
headers: {
Authorization: `Basic ${authString}`,
},
});
const data = await response.blob();
var apiKey = "{{apiKey}}";
var characterId = "cXi2eAP19XwQ";
var motionId = "your-motion-id";
var downloadUrl = $"https://uthana.com/motion/file/motion_viewer/{characterId}/{motionId}/motion.fbx";
var authValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{apiKey}:"));
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authValue);
var bytes = await _httpClient.GetByteArrayAsync(downloadUrl);
Download options
Frame rate (FPS)
You can specify the frame rate for downloaded motions using the fps query parameter. Supported values are 24, 30, and 60.
- Shell
- Python
- TypeScript
- C#
# Download at 30 FPS
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/motion.fbx?fps=30" \
-u $API_KEY: \
-o motion-30fps.fbx
# Download at 60 FPS
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/motion.fbx?fps=60" \
-u $API_KEY: \
-o motion-60fps.fbx
# Download at 30 FPS
fbx_url = f"https://uthana.com/motion/file/motion_viewer/{CHARACTER_ID}/{MOTION_ID}/motion.fbx?fps=30"
response = requests.get(fbx_url, auth=(API_KEY, ""))
with open("motion-30fps.fbx", "wb") as f:
f.write(response.content)
async function downloadMotionAtFps(
characterId: string,
motionId: string,
format: "fbx" | "glb",
fps: 24 | 30 | 60,
filename: string = "motion",
) {
const url = `https://uthana.com/motion/file/motion_viewer/${characterId}/${motionId}/${filename}.${format}?fps=${fps}`;
const response = await fetch(url, {
headers: {
Authorization: `Basic ${authString}`,
},
});
return await response.blob();
}
// Usage
const motion30fps = await downloadMotionAtFps(CHARACTER_ID, MOTION_ID, "fbx", 30);
public async Task<byte[]> DownloadMotionAtFpsAsync(string motionId, string format, int fps, string filename = "motion")
{
var downloadUrl = $"https://uthana.com/motion/file/motion_viewer/{CHARACTER_ID}/{motionId}/{filename}.{format}?fps={fps}";
var response = await _httpClient.GetAsync(downloadUrl);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsByteArrayAsync();
}
// Usage
var motion30fps = await DownloadMotionAtFpsAsync(motionId, "fbx", 30);
Exclude character mesh
Use the no_mesh query parameter to download animation data without the character mesh. Set no_mesh=true to exclude the mesh, or no_mesh=false to include it (default).
- Shell
- Python
- TypeScript
- C#
# Download FBX without character mesh
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/motion.fbx?no_mesh=true" \
-u $API_KEY: \
-o motion-no-mesh.fbx
# Download FBX without character mesh
fbx_url = f"https://uthana.com/motion/file/motion_viewer/{CHARACTER_ID}/{MOTION_ID}/motion.fbx?no_mesh=true"
response = requests.get(fbx_url, auth=(API_KEY, ""))
with open("motion-no-mesh.fbx", "wb") as f:
f.write(response.content)
async function downloadMotionNoMesh(
characterId: string,
motionId: string,
format: "fbx" | "glb",
filename: string = "motion",
) {
const url = `https://uthana.com/motion/file/motion_viewer/${characterId}/${motionId}/${filename}.${format}?no_mesh=true`;
const response = await fetch(url, {
headers: {
Authorization: `Basic ${authString}`,
},
});
return await response.blob();
}
public async Task<byte[]> DownloadMotionNoMeshAsync(string motionId, string format, string filename = "motion")
{
var downloadUrl = $"https://uthana.com/motion/file/motion_viewer/{CHARACTER_ID}/{motionId}/{filename}.{format}?no_mesh=true";
var response = await _httpClient.GetAsync(downloadUrl);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsByteArrayAsync();
}
Combining options
You can combine fps and no_mesh parameters:
# Download at 30 FPS without character mesh
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/motion.fbx?fps=30&no_mesh=true" \
-u $API_KEY: \
-o motion-30fps-no-mesh.fbx
Motion-only GLB
To download only animation data without the character mesh, you can use the motion-only endpoint or the no_mesh=true parameter:
- Shell
- Python
- TypeScript
- C#
# Using the motion-only endpoint
curl -L "https://uthana.com/motion/animation/motion_viewer/$CHARACTER_ID/$MOTION_ID/motion.glb" \
-u $API_KEY: \
-o motion-only.glb
# Or using no_mesh parameter
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/motion.glb?no_mesh=true" \
-u $API_KEY: \
-o motion-only.glb
# Using the motion-only endpoint
motion_only_url = f"https://uthana.com/motion/animation/motion_viewer/{CHARACTER_ID}/{MOTION_ID}/motion.glb"
response = requests.get(motion_only_url, auth=(API_KEY, ""))
with open("motion-only.glb", "wb") as f:
f.write(response.content)
const motionOnlyUrl = `https://uthana.com/motion/animation/motion_viewer/${CHARACTER_ID}/${MOTION_ID}/motion.glb`;
const response = await fetch(motionOnlyUrl, {
headers: {
Authorization: `Basic ${authString}`,
},
});
const blob = await response.blob();
var motionOnlyUrl = $"https://uthana.com/motion/animation/motion_viewer/{CHARACTER_ID}/{motionId}/motion.glb";
var response = await _httpClient.GetAsync(motionOnlyUrl);
response.EnsureSuccessStatusCode();
var bytes = await response.Content.ReadAsByteArrayAsync();
Error handling
If you provide invalid parameter values, you'll receive an error response:
- Invalid FPS: If
fpsis not24,30, or60, you'll receive:"Malformed - fps parameter must be in [24, 30, 60]" - Invalid no_mesh: If
no_meshis not"true"or"false", you'll receive:"Malformed - no_mesh parameter must be a boolean"
Related docs
- Asset management for listing motions and metadata