{"openapi":"3.1.0","info":{"title":"Character Animation for Agents: rig and animate any 3D model (ZeroGPU)","description":"Send a 3D model (glb/gltf/obj/fbx) and a sentence; get back a rigged, animated GLB. SkinTokens (TokenRig, ACM TOG 2026) predicts the skeleton and skin weights, the rig becomes a UniMate asset on this Space (the upstream rig_preprocess pipeline: joint labels, facing, canonical T-pose), and UniMate (SIGGRAPH Asia 2026) generates 60-frame motions from text, with in-betweening, joint editing and multi-prompt expansion. One request does it all (POST /api/animate_mesh); every step is also its own call (POST /api/rig, POST /api/assets, POST /api/animate, /api/inbetween, /api/edit, /api/expand), and assets are reusable by id. Agent guide: /llms.txt. MCP: /gradio_api/mcp/.","version":"1.0"},"paths":{"/api":{"get":{"tags":["service"],"summary":"Service description: workflow, parameters, limits, provenance","operationId":"api_info_api_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Info Api Get"}}}}}}},"/api/health":{"get":{"tags":["service"],"summary":"Health","operationId":"health_api_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Health Api Health Get"}}}}}}},"/api/gpu_check":{"get":{"tags":["service"],"summary":"Run a 10 s ZeroGPU probe (billed to the caller) and report the GPU","operationId":"api_gpu_check_api_gpu_check_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Gpu Check Api Gpu Check Get"}}}}}}},"/api/identity":{"get":{"tags":["service"],"summary":"Who pays the GPU time of calls made with these headers","operationId":"api_identity_api_identity_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Identity Api Identity Get"}}}}}}},"/api/examples":{"get":{"tags":["service"],"summary":"Bundled meshes and skeletons, and real results generated by this Space with how to reproduce each","operationId":"api_examples_api_examples_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Examples Api Examples Get"}}}}}}},"/api/rig":{"post":{"tags":["rig"],"summary":"Rig a mesh with SkinTokens: skeleton + skin weights (synchronous, about 20-60 s)","description":"Send the mesh as the raw request body (`curl --data-binary @mesh.glb \"...?filename=mesh.glb\"`), as a multipart `file` field, or as JSON `{\"example\": \"giraffe\"}` / `{\"mesh_url\": \"https://...\"}`. Options (`num_beams`, `seed`, `keep_skeleton`, `preserve_original`, `postprocess`, `influences`, `top_k`, `top_p`, `temperature`, `repetition_penalty`, `preview`) go in the JSON body or as query parameters. Returns the r_ result with a URL per output file and the follow-up calls (make it an asset, animate it). GPU time is billed to the caller's ZeroGPU quota (send `Authorization: Bearer <HF token>`).","operationId":"api_rig_api_rig_post","parameters":[{"name":"filename","in":"query","required":false,"schema":{"type":"string","description":"name of the uploaded file (its extension selects the importer)","title":"Filename"},"description":"name of the uploaded file (its extension selects the importer)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Rig Api Rig Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/assets":{"get":{"tags":["assets"],"summary":"The skeletons that can be animated: bundled and prepared assets","operationId":"api_assets_api_assets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Assets Api Assets Get"}}}}}},"post":{"tags":["assets"],"summary":"Prepare an animatable asset: from a rig made here, a rigged file, or an asset to re-annotate (about 10-30 s)","description":"JSON `{\"rig_job_id\": \"r_...\"}` turns a SkinTokens result into a UniMate asset; `{\"mesh_url\": ...}`, the raw body (`?filename=rig.glb`) or a multipart `file` take any rigged glb/gltf/fbx (one armature with a skinned mesh; a zipped `data_process.rig_preprocess` output is accepted too); `{\"asset_id\": \"u_...\"}` re-annotates an earlier asset. Options: `labels` ({joint name: label}), `face_right` / `face_left` (joint names), `body_axis`, `rest_rotation` (\"x180\"), or a complete `annotation`. The upstream rig_preprocess pipeline runs on the CPU (Blender import, pruning, labels, facing, canonical T-pose, topology condition, canonical GLB). The id is derived from the file and the options, so the same request returns the same asset. Returns the asset with its annotation flags and a preview to check.","operationId":"api_prepare_asset_api_assets_post","parameters":[{"name":"filename","in":"query","required":false,"schema":{"type":"string","description":"name of the uploaded rigged file","title":"Filename"},"description":"name of the uploaded rigged file"}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Prepare Asset Api Assets Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/assets/{asset_id}":{"get":{"tags":["assets"],"summary":"One asset: joints, labels, facing pair, annotation flags, file URLs","operationId":"api_asset_api_assets__asset_id__get","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Asset Api Assets  Asset Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/assets/{asset_id}/rest.glb":{"get":{"tags":["assets"],"summary":"The canonical rest-pose GLB of an asset","operationId":"api_asset_glb_api_assets__asset_id__rest_glb_get","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/assets/{asset_id}/annotation":{"get":{"tags":["assets"],"summary":"The joint annotation of an asset (every joint with its label, the facing pair, the label vocabulary)","operationId":"api_asset_annotation_api_assets__asset_id__annotation_get","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/assets/{asset_id}/files/{name}":{"get":{"tags":["assets"],"summary":"A file of a prepared asset: preview.png, annotation_preview.png, annotation.json, source, rigprep.log","operationId":"api_asset_file_api_assets__asset_id__files__name__get","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}},{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/animate":{"post":{"tags":["animate"],"summary":"Generate a 60-frame motion for an asset from a prompt with UniMate (synchronous, about 10 s)","description":"Body: {\"asset\": \"u_... or unitree_go2\", \"prompt\": \"An object walks forward.\", \"num_samples\": 1, \"cfg_scale\": 3.0, \"seed\": 7, \"preview\": true}. Returns the a_ result with a URL per output file (animated GLB, motion .npy, joints JSON, skeleton MP4, contact sheet) and ready-made bodies for in-betweening, editing and expansion. GPU time is billed to the caller.","operationId":"api_animate_api_animate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Animate Api Animate Post"}}}}}}},"/api/inbetween":{"post":{"tags":["animate"],"summary":"In-betweening: keep some frames of an earlier motion, regenerate the rest from a prompt","description":"Body: {\"reference_job_id\": \"a_...\", \"reference_sample\": 0, \"reference_start\": 0, \"keep_frames\": \"0,-1\", \"prompt\": \"An object jumps in place.\", \"num_samples\": 1, \"cfg_scale\": 3.0, \"seed\": 7, \"preview\": true}. The kept frames (indices into the 60-frame window; negatives from the end; list or comma-separated string) come out identical to the reference, every other frame is regenerated under the prompt (upstream --inbetween --keep_frames).","operationId":"api_inbetween_api_inbetween_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Inbetween Api Inbetween Post"}}}}}}},"/api/edit":{"post":{"tags":["animate"],"summary":"Joint editing: keep some joints of an earlier motion, regenerate the others from a prompt","description":"Body: {\"reference_job_id\": \"a_...\", \"reference_sample\": 0, \"reference_start\": 0, \"keep_joints\": \"Left Thigh, Right Thigh, Left Shin, Right Shin\", \"prompt\": \"An object waves.\", \"num_samples\": 1, \"cfg_scale\": 3.0, \"seed\": 7, \"preview\": true}. keep_joints are joint names or anatomical labels of the asset (GET /api/assets/{id}), case-insensitive, list or comma-separated; a label selects every joint carrying it. Kept joints come out identical to the reference over all 60 frames, the other joints are regenerated under the prompt (upstream --motion_edit --keep_joints).","operationId":"api_edit_api_edit_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Edit Api Edit Post"}}}}}}},"/api/expand":{"post":{"tags":["animate"],"summary":"Motion expansion: chain several prompts into one long motion","description":"Body: {\"asset\": \"u_...\", \"prompts\": [\"An object walks forward.\", \"An object turns around.\", \"An object sits down.\"], \"overlap\": 10, \"num_samples\": 1, \"cfg_scale\": 3.0, \"seed\": 7, \"preview\": true}. One 60-frame segment per prompt (2-6); each segment after the first is generated with its first `overlap` frames pinned to the previous segment's last frames: 60 + (60 - overlap) x (prompts - 1) frames in one GLB / .npy / JSON (upstream --motion_expand --expand_overlap). num_samples x prompts is limited to 8 per call.","operationId":"api_expand_api_expand_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Expand Api Expand Post"}}}}}}},"/api/animate_mesh":{"post":{"tags":["animate_mesh"],"summary":"One request: mesh -> SkinTokens rig -> UniMate asset -> animated GLB (about 40-90 s)","description":"The mesh as the raw body (`?filename=model.glb&prompt=...`), a multipart `file`, or JSON with `\"example\"` / `\"mesh_url\"`; or skip stages with `\"rig_job_id\": \"r_...\"` (a rig made here) or `\"asset\": \"u_...\"` (a prepared asset). Required: `prompt` (one 60-frame motion) or `prompts` (2-6 captions, list or separated by |: a chained expansion). Rig options: `num_beams`, `rig_seed`, `keep_skeleton`, `preserve_original`, `postprocess`, `influences`; asset options: `labels`, `face_right`, `face_left`, `body_axis`, `rest_rotation`; animation options: `num_samples`, `cfg_scale`, `seed`, `overlap`, `preview`. Returns the p_ result with the three stages (rig, asset, animation), every file URL and the follow-up calls. Two ZeroGPU calls, billed to the caller.","operationId":"api_animate_mesh_api_animate_mesh_post","parameters":[{"name":"filename","in":"query","required":false,"schema":{"type":"string","description":"name of the uploaded file","title":"Filename"},"description":"name of the uploaded file"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Animate Mesh Api Animate Mesh Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}":{"get":{"tags":["jobs"],"summary":"A finished result again (r_ rig, a_ motion, p_ animate_mesh; kept 24 h)","operationId":"api_job_api_jobs__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Job Api Jobs  Job Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/files/{name}":{"get":{"tags":["jobs"],"summary":"Download an output file of a job","operationId":"api_job_file_api_jobs__job_id__files__name__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}},"servers":[{"url":"https://townbox-character-animation-for-agents.hf.space"}]}