Auto-rig / add a character
Upload a 3D character model in FBX or GLB format to use with generated motions.
Step 1: Prepare your character file
- Supported formats:
.fbx,.glb,.gltf - File size must be less than 20MB (100MB for some organizations)
- Keep the file size reasonable to speed up auto-rigging
Step 2: Upload via GraphQL
Use a multipart GraphQL request with the create_character mutation.
- Shell
- Python
- TypeScript
- C#
API_KEY="{{apiKey}}"
CHARACTER_FILE="/path/to/character.fbx"
CHARACTER_NAME="My Character"
curl -X POST https://uthana.com/graphql \
-u $API_KEY: \
-F 'operations={
"query": "mutation ($file: Upload!, $name: String!, $auto_rig: Boolean, $auto_rig_front_facing: Boolean) { create_character(file: $file, name: $name, auto_rig: $auto_rig, auto_rig_front_facing: $auto_rig_front_facing) { character { id name } auto_rig_confidence } }",
"variables": { "file": null, "name": "'"$CHARACTER_NAME"'", "auto_rig": true, "auto_rig_front_facing": true }
}' \
-F 'map={ "0": ["variables.file"] }' \
-F '0=@'"$CHARACTER_FILE"
import json
import requests
API_URL = "https://uthana.com/graphql"
API_KEY = "{{apiKey}}"
CHARACTER_FILE = "/path/to/character.fbx"
CHARACTER_NAME = "My Character"
operations = {
"query": """
mutation ($file: Upload!, $name: String!, $auto_rig: Boolean, $auto_rig_front_facing: Boolean) {
create_character(file: $file, name: $name, auto_rig: $auto_rig, auto_rig_front_facing: $auto_rig_front_facing) {
character { id name }
auto_rig_confidence
}
}
""",
"variables": {"file": None, "name": CHARACTER_NAME, "auto_rig": True, "auto_rig_front_facing": True}
}
files = {
"operations": (None, json.dumps(operations)),
"map": (None, json.dumps({"0": ["variables.file"]})),
"0": open(CHARACTER_FILE, "rb"),
}
response = requests.post(API_URL, auth=(API_KEY, ""), files=files)
print(response.json())
const API_URL = "https://uthana.com/graphql";
const API_KEY = "{{apiKey}}";
const CHARACTER_NAME = "My Character";
// Example markup: <input type="file" id="characterFile" accept=".fbx,.glb,.gltf" />
const characterInput = document.querySelector<HTMLInputElement>("#characterFile");
const characterFile = characterInput?.files?.[0];
if (!characterFile) {
throw new Error("Select a character file before uploading.");
}
const formData = new FormData();
formData.append(
"operations",
JSON.stringify({
query: `
mutation ($file: Upload!, $name: String!, $auto_rig: Boolean, $auto_rig_front_facing: Boolean) {
create_character(file: $file, name: $name, auto_rig: $auto_rig, auto_rig_front_facing: $auto_rig_front_facing) {
character { id name }
auto_rig_confidence
}
}
`,
variables: { file: null, name: CHARACTER_NAME, auto_rig: true, auto_rig_front_facing: true },
}),
);
formData.append("map", JSON.stringify({ 0: ["variables.file"] }));
formData.append("0", characterFile, characterFile.name);
const authString = btoa(`${API_KEY}:`);
const response = await fetch(API_URL, {
method: "POST",
headers: {
Authorization: `Basic ${authString}`,
},
body: formData,
});
console.log(await response.json());
var operations = new
{
query = @"
mutation ($file: Upload!, $name: String!, $auto_rig: Boolean, $auto_rig_front_facing: Boolean) {
create_character(file: $file, name: $name, auto_rig: $auto_rig, auto_rig_front_facing: $auto_rig_front_facing) {
character { id name }
auto_rig_confidence
}
}",
variables = new { file = (object)null, name = "My Character", auto_rig = true, auto_rig_front_facing = true }
};
var map = new { ["0"] = new[] { "variables.file" } };
using var content = new MultipartFormDataContent();
content.Add(new StringContent(JsonSerializer.Serialize(operations), Encoding.UTF8, "application/json"), "operations");
content.Add(new StringContent(JsonSerializer.Serialize(map), Encoding.UTF8, "application/json"), "map");
content.Add(new StreamContent(File.OpenRead("/path/to/character.fbx")), "0", "character.fbx");
var authValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{_apiKey}:"));
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authValue);
var response = await _httpClient.PostAsync("https://uthana.com/graphql", content);
response.EnsureSuccessStatusCode();
Step 3: Save the character ID
The response includes the character id. Keep it for generating motions and downloads.
Auto-rigging
By default, Uthana automatically attempts to rig characters that don't have a skeleton. Auto-rigging allows you to use characters that weren't originally rigged for animation. However, there are some cases where the auto-rigging has difficulty:
- Non humanoid: Missing clearly defined head, torso, two arms, or two legs. The character must have a recognizable bipedal humanoid structure.
- Extreme proportions: Head or other body parts so oversized they would interfere with standard humanoid skeletal mapping (slight stylization like cartoon characters is acceptable).
- Limb intersections: Arms, legs, or other body parts visibly intersecting, overlapping, or clipping through the body or each other.
- Flowing clothing: Long skirts, robes, capes, or dresses that obscure or merge the legs into a single volume.
- Large extra appendages: long tails, large wings, large extra limbs, long horns, or any large appendages beyond standard human anatomy. Small appendages are OK, such as cat ears.
The result of the gql mutation will return auto_rig_confidence score. 1.0 indicates high confidence in the result, lower scores indicate less confidence.
This confidence score can be used to filter out characters with one or more of the above difficulties.
Default behavior
auto_rig:true(default) - Automatically rig the character if no skeleton is foundauto_rig_front_facing:true(default) - Make the auto-rigged character face forward
Timing
- Auto-rigging typically takes 30-60 seconds to complete
- The upload job has a timeout of 5 minutes (300 seconds)
- If your character already has a skeleton, no auto-rigging occurs and the upload is faster
Disabling auto-rigging
If your character already has a skeleton rig, you can disable auto-rigging to speed up the upload:
- Shell
- Python
- TypeScript
- C#
curl -X POST https://uthana.com/graphql \
-u $API_KEY: \
-F 'operations={
"query": "mutation ($file: Upload!, $name: String!, $auto_rig: Boolean) { create_character(file: $file, name: $name, auto_rig: $auto_rig) { character { id name } } }",
"variables": { "file": null, "name": "'"$CHARACTER_NAME"'", "auto_rig": false }
}' \
-F 'map={ "0": ["variables.file"] }' \
-F '0=@'"$CHARACTER_FILE"
operations = {
"query": """
mutation ($file: Upload!, $name: String!, $auto_rig: Boolean) {
create_character(file: $file, name: $name, auto_rig: $auto_rig) {
character { id name }
}
}
""",
"variables": {"file": None, "name": CHARACTER_NAME, "auto_rig": False}
}
variables: { file: null, name: CHARACTER_NAME, auto_rig: false, auto_rig_front_facing: true },
variables = new { file = (object)null, name = "My Character", auto_rig = false, auto_rig_front_facing = true }
Character requirements
Your character must have essential joints for retargeting to work:
- Pelvis
- Left and right hips
- Left and right shoulders
If these joints are missing, the upload will fail with an error.
Known errors
Common errors you may encounter:
- "Only FBX and GLB files are supported" - Your file format is not supported. Use
.fbxor.glbfiles only. - "The provided file is too large, it must be less than [size]MiB" - File size exceeds the limit (default 20MB, 100MB for some organizations). The error message will include the actual size limit.
- "Maximum number of characters reached" - Your organization has reached its character limit. Upgrade your plan or delete unused characters.
- "Essential joints missing. Please ensure your character has a basic bone structure (pelvis, shoulders, hips)." - Your character model lacks required skeleton joints.
- "Auto-rigging failed: [error]" - Auto-rigging encountered an error. The character may not be suitable for automatic rigging (e.g., non-humanoid structure, extreme proportions, or other compatibility issues). The error message will include specific details about what went wrong.
- "Auto-rigging job not done after [timeout] seconds" - Auto-rigging exceeded the timeout. Try uploading a smaller or simpler character model. The error message will include the actual timeout value.
- "No rig found in scene. Please upload a rigged character." - No skeleton was found and auto-rigging was disabled or failed.
Related docs
- Asset management for full character and motion workflows