Retarget to any character
Apply motions generated with Uthana to your custom 3D characters. Retargeting automatically adapts animations to work with different character skeletons and proportions.
Overview
When you generate a motion with Uthana, it's created for a specific character skeleton. Retargeting allows you to apply that same motion to any character you've uploaded, automatically adapting the animation to match different bone structures and proportions.
Learn more about Retargeting.
How retargeting works
- Generate or select a motion: Create a motion using text-to-motion or video-to-motion, or use an existing motion
- Choose your character: Select the character you want to apply the motion to
- Download the retargeted motion: The motion is automatically retargeted when you download it with a specific character ID
Step-by-step tutorial
Step 1: Upload your character
First, upload your custom character model. Uthana will automatically rig it if needed.
See the Auto-rig / add a character guide for detailed instructions on uploading characters, including supported formats, auto-rigging options, and code examples for all languages.
After uploading, save the character ID from the response. You'll need it for retargeting motions.
Step 2: Generate a motion
Generate a motion using Text to motion or Video to motion. Save the motion ID from the response—you'll need it for downloading the retargeted motion.
Step 3: Download retargeted motion
When you download a motion with a specific character ID, Uthana automatically retargets it to that character's skeleton.
- Shell
- Python
- TypeScript
- C#
# Download retargeted motion as FBX (filename is customizable)
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/fbx/motion.fbx" \
-u $API_KEY: \
-o retargeted-motion.fbx
# Download retargeted motion as GLB (filename is customizable)
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/glb/motion.glb" \
-u $API_KEY: \
-o retargeted-motion.glb
# Download retargeted motion as FBX (filename is customizable)
fbx_url = f'https://uthana.com/motion/file/motion_viewer/{CHARACTER_ID}/{MOTION_ID}/fbx/motion.fbx'
response = requests.get(fbx_url, auth=(API_KEY, ''))
with open('retargeted-motion.fbx', 'wb') as f:
f.write(response.content)
# Download retargeted motion as GLB (filename is customizable)
glb_url = f'https://uthana.com/motion/file/motion_viewer/{CHARACTER_ID}/{MOTION_ID}/glb/motion.glb'
response = requests.get(glb_url, auth=(API_KEY, ''))
with open('retargeted-motion.glb', 'wb') as f:
f.write(response.content)
async function downloadRetargetedMotion(
characterId: string,
motionId: string,
format: "fbx" | "glb",
filename: string = "motion",
) {
const url = `https://uthana.com/motion/file/motion_viewer/${characterId}/${motionId}/${format}/${filename}.${format}`;
const response = await fetch(url, {
headers: {
Authorization: `Basic ${btoa(`${API_KEY}:`)}`,
},
});
if (!response.ok) {
throw new Error(`Failed to download motion: ${response.statusText}`);
}
const blob = await response.blob();
return blob;
}
// Usage
const fbxBlob = await downloadRetargetedMotion(CHARACTER_ID, MOTION_ID, "fbx");
const glbBlob = await downloadRetargetedMotion(CHARACTER_ID, MOTION_ID, "glb");
public async Task<byte[]> DownloadRetargetedMotionAsync(string characterId, string motionId, string format = "fbx", string filename = "motion")
{
var downloadUrl = $"https://uthana.com/motion/file/motion_viewer/{characterId}/{motionId}/{format}/{filename}.{format}";
var response = await _httpClient.GetAsync(downloadUrl);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsByteArrayAsync();
}
// Usage
var fbxData = await DownloadRetargetedMotionAsync(characterId, motionId, "fbx");
var glbData = await DownloadRetargetedMotionAsync(characterId, motionId, "glb");
Downloading motion-only files
For animation data without the character mesh (useful for applying to characters in your game engine), download the motion-only GLB:
- Shell
- Python
- TypeScript
- C#
# Download motion-only GLB (animation data without character mesh, filename is customizable)
curl -L "https://uthana.com/motion/animation/motion_viewer/$CHARACTER_ID/$MOTION_ID/glb/motion.glb" \
-u $API_KEY: \
-o motion-only.glb
# Download motion-only GLB (filename is customizable)
motion_only_url = f'https://uthana.com/motion/animation/motion_viewer/{CHARACTER_ID}/{MOTION_ID}/glb/motion.glb'
response = requests.get(motion_only_url, auth=(API_KEY, ''))
with open('motion-only.glb', 'wb') as f:
f.write(response.content)
async function downloadMotionOnlyGlb(characterId: string, motionId: string) {
const url = `https://uthana.com/motion/animation/motion_viewer/${characterId}/${motionId}/glb/${characterId}-${motionId}.glb`;
const response = await fetch(url, {
headers: {
Authorization: `Basic ${btoa(`${API_KEY}:`)}`,
},
});
if (!response.ok) {
throw new Error(`Failed to download motion-only GLB: ${response.statusText}`);
}
const blob = await response.blob();
return blob;
}
// Usage
const motionOnlyBlob = await downloadMotionOnlyGlb(CHARACTER_ID, MOTION_ID);
public async Task<byte[]> DownloadMotionOnlyGlbAsync(string characterId, string motionId, string filename = "motion")
{
var downloadUrl = $"https://uthana.com/motion/animation/motion_viewer/{characterId}/{motionId}/glb/{filename}.glb";
var response = await _httpClient.GetAsync(downloadUrl);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsByteArrayAsync();
}
// Usage
var motionOnlyData = await DownloadMotionOnlyGlbAsync(characterId, motionId);
Next steps
- Learn about Text to motion for generating animations
- Explore Asset management for managing your characters and motions
- Check the API reference for complete schema documentation