Downloads · 30 days
0
cgb/unirig-skeleton-onnx-webgpu
unirig-skeleton-onnx-webgpu is a other model from cgb. Use it for the other task on the model card, and read the license before you ship it in a product. It is set up for onnx. The card lists the license as mit.
UniRig ("One Model to Rig Them All", SIGGRAPH 2025, VAST-AI-Research) predicts a skeleton from raw mesh geometry, no template and no markers. This is the skeleton stage quantized to int8 so it runs entirely inside a w…
Downloads · 30 days
0
Access
Public
Updated Sep 4, 2026
Repo size
811 MB
Likes
1
Public
Click a slice to open those files.
.data454 MB · 100%
From the Hugging Face model README
UniRig ("One Model to Rig Them All", SIGGRAPH 2025, VAST-AI-Research) predicts a skeleton from raw mesh geometry, no template and no markers. This is the skeleton stage quantized to int8 so it runs entirely inside a web browser on WebGPU.
1.44 GB down to 455 MB, with the same skeleton coming out.
| File | Precision | Size |
|---|---|---|
encoder_q8.onnx + .data | int8 weight-only, block 32 | 61 MB |
decoder_q8.onnx + .data | int8 weight-only, block 16 | 393 MB |
embed.onnx | float32 | 1.1 MB |
vertices [1,N,3], normals [1,N,3] float32, N up to 65536,
surface-sampled, centred, and scaled so the longest side spans -1 to 1,
with +Y up, to latents [1,1024,1024].input_ids [1,S] int64 to token_embeds [1,S,1024].inputs_embeds [1,S,1024] and past.{0..23}.{key,value} [1,16,P,64] to logits [1,S,267] and present.{0..23}.{key,value}.latents = encoder(points, normals)
inputs_embeds = concat([latents, embed([bos=257, cls=266])])
loop:
logits, present = decoder(inputs_embeds, past)
token = argmax over ONLY the tokens the grammar allows
inputs_embeds = embed([token]); past = present
The class token is easy to miss and is not optional.
"A centred unit box" is ambiguous and the wrong reading does not give a scaled rig, it gives no rig. At -0.5 to 0.5 the decode never emits its end token and runs to the safety cap, producing a hundred bones in a line. The same cloud scaled to -1 to 1 terminates normally at twenty two. Measured both ways on the same points.
256 coordinate bins over [-1,1], undiscretize(t) = (t+0.5)/256*2-1; vocab 267
with branch=256, bos=257, eos=258, cls=266. Bones are
[branch?, parent xyz, joint xyz], so six coordinates each; eos and branch
are legal only on a six-coordinate boundary.
This is not defensive. On the first step of a real decode the unmasked argmax is token 260, an unused slot in the vocabulary. An unconstrained greedy decode produces garbage immediately.
Match a parent to the nearest earlier joint rather than to an exact bin; real decodes routinely miss the bin the parent was written to.
Gemm nodes, which
MatMulNBitsQuantizer does not touch. Without this the decoder only gets to
933 MB. Only the exact form these graphs use is rewritten (alpha=beta=1,
no transA, transB set, initializer weight).scripts/unirig-verify.py runs the whole chain on a real reconstruction rather
than on noise, and compares the quantized pack against the original on the only
thing that matters: 111 of 112 tokens identical, diverging only on the last,
the same 18 bones, the hierarchy identical, and joints within 1.00 quantisation
bins (one bin is the finest distance the model can express). A different
hierarchy, or joints moving more than a bin and a half, fails the build.
The excellent export this is derived from is by
fernandotonon for
QtMeshEditor. If you go looking
for it: the graphs that match the documented contract are in
fernandotonon/QtMeshEditor-models under unirig/. The standalone
QtMeshEditor-unirig-onnx repository currently mirrors a generic input_ids
export of the decoder, which cannot be conditioned on a mesh at all.
MIT, from the upstream code and weights. Trained on Articulation-XL2.0 (CC-BY-4.0) — credit VAST-AI-Research. Permits commercial use.