UniRig Extract Skeleton ⚡
Where Does the Skeleton Actually Go? UniRig Guesses
- mesh
- skeleton_model
- mesh
- skeleton
- skeleton_info
Feed it a mesh, get a skeleton. That's the pitch, and it works better than you'd expect on humanoids - the paper is SIGGRAPH 2025 for a reason, and the ComfyUI wrapper's release thread drew a genuinely excited crowd. It's also the node in this pack with the most knobs worth understanding, because the skeleton is the one part of an auto-rig you can't fix afterwards with a slider.
The pipeline inside the node
- Decimate if needed. Anything above
max_facesgets simplified first - 50,000 by default, which is the POC and upstream value. Withfast-simplificationinstalled you get the POC's exact decimation; without it core's QEM decimator steps in and you get a slightly different mesh. Important: the rig binds to the decimated mesh, and that decimated mesh is the one this node outputs. - Normalize into a [-1, 1] cube.
- Sample the surface -
num_samplespoints, default 2048, seeded. The seed also feeds the beam sampler below, so a re-run with the same seed gives the same rig. That's not a small thing when you're comparing two templates. - Encode through Michelangelo, then decode bone tokens autoregressively with OPT-350m.
- Beam-sample the token sequence: 15 beams, temperature 1.5, top-k 5, top-p 0.95, repetition penalty 3.0. This is where the skeleton's plausibility comes from - a greedy decode gives you bones in nonsense order, beam search gives you a leg.
- Name it to the chosen template.
Three outputs: mesh (the decimated mesh the rig will bind to - save this, not the original), skeleton, and skeleton_info, a plain STRING listing the bones, which is the only way to see what the model decided without opening the GLB.
The template dropdown, which is the real decision
mixamo(default) - a 52-bone humanoid namedmixamorig:*. This is the one to pick if you ever want to apply a Mixamo animation, because the names line up and retargeting works. Internally it generates the vroid skeleton and renames.vroid- the same bones underJ_Bip_*names, for VRoid/VRM pipelines.articulationxl- a free-form skeleton, no naming convention, for creatures, props, and anything not human-shaped. UniRig's actual generality lives here; the humanoid templates are it being helpful.
If your subject is a quadruped, a robot arm, or a chair, mixamo will try to force 52 human bones onto it and the result will be funny. articulationxl is the honest option.
The optional knobs
num_beams (15), temperature (1.5), num_samples (2048) - you can leave all three alone. If you're getting skeletons with a missing limb, raising num_beams to 20-24 gives the search more candidates; it also costs more time and about 2 GB of working memory beyond the weights, which the node asks ComfyUI for explicitly. Lowering temperature makes it more conservative and more likely to produce the anatomically boring answer, which is usually what you want.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/ChrisColeTech/ComfyUI-GGUF-Loader
pip install -r ComfyUI/custom_nodes/ComfyUI-GGUF-Loader/requirements.txt
Manager → "ComfyUI-GGUF-Loader" → restart. Needs skeleton.safetensors (1.4 GB) in models/unirig/, trimesh/addict/einops for the family, and optionally fast-simplification. No Blender, no spconv, no flash-attn - the whole point of this port.
Where it bites
Multiple meshes in the batch. The node logs a warning and rigs batch item 0. If your GLB had a body plus accessories as separate objects, you rig one of them.
Decimation you didn't intend. max_faces defaults to 50k. Feed it a 400k-face TripoSG mesh and you're rigging a simplified version - which is usually correct, but the mesh socket output is the one to save, and people wire the original by mistake and wonder why the rig doesn't match. Set max_faces to 0 to never decimate.
A skeleton that exists but is anatomically silly. That's the model, not the node. Try temperature lower, num_beams higher, or a different seed - the seed genuinely changes the answer. And if the mesh has no discernible limbs (a rock, a blob), no template will rescue you.
And the expectation to set before you invest an evening: auto-rigging is the step after retopology, not a replacement for it. Community feedback on the ComfyUI wrapper is consistent about this - the tool is a genuine leap for a last-mile step, but a marching-cubes mesh still deforms like rubber, and the fix for that is edge loops in Blender, not a bigger beam width.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| mesh | MESH | — | |
| skeleton_model | CCTECH_UNIRIG_SKELETON_MODEL | — | |
| seed | INT | 420–4294967295 | Seeds surface sampling and beam sampling. |
| skeleton_template | COMBO | mixamo | mixamo: 52-bone humanoid named mixamorig:* (vroid generation + rename); vroid: same bones, J_Bip_* names; articulationxl: generic skeleton for any creature/object. |
| max_faces | INT | 500000–1000000 | Decimate above this face count first (POC/upstream: 50000; 0 = never). The rig binds to the decimated mesh. |
| num_beamsopt | INT | 151–32 | Beam-sampling width (POC: 15). |
| temperatureopt | FLOAT | 1.500.1–3 | Sampling temperature (POC: 1.5). |
| num_samplesopt | INT | 2048512–16384 | Surface points fed to the encoder (POC: 2048). |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| mesh | MESH | — |
| skeleton | CCTECH_UNIRIG_SKELETON | — |
| skeleton_info | STRING | — |