🦴 Poser Template Bind (1:1 skin_standard.npz — joints+mesh)
The 1:1 rest pose, and why it isn't an A-pose
- joints
- mesh
Most rigging tutorials tell you a character should be modelled in a T-pose or an A-pose. That advice is about your workflow convenience. It is not a law of the universe, and it is very much not what the SOMAX weight-transfer template looks like.
Poser Template Bind exists because of that gap. It loads the canonical SOMAX rest pose - the exact same skin_standard.npz the pack's weight transfer uses - and emits both the joints and the mesh in it. No engine, no statistical mean, no synthetic A-pose computed by rotating a T-pose 45°. The template's real pose is roughly a 51° arm drop with a ~25° elbow bend, which is a natural resting posture, not a textbook one.
Why you'd want that
Because alignment stops being a problem. If your ControlNet conditioning and your eventual weight transfer are both built on the same template data, the generated character comes out standing like the mesh it will be skinned to. The pack's own framing is that this makes "the weight transfer alignment trivially correct" - and if you've ever spent an afternoon nudging a rendered depth map until a rig matched it, that's not a small claim.
It's also the sanity-check node. If something in your poser chain is wrong, wire this in, render it, and you have the ground truth pose to compare against.
How it works
It reads skin_standard.npz, unpacks the bind_rig_transform (77 × 4×4 matrices) and bind_vertices/faces, and does the unit conversion: the NPZ is in metres, the JOINTS and MESH contracts in this pack are centimetres. Joint rotations are sliced out of the bind matrices and copied, positions come from the translation column, and everything is cast to float32.
The load is wrapped in an LRU cache with a max size of one, so the 531KB read and its array decoding happen once per ComfyUI process, not once per node. Multi-angle workflows that call it eight times pay for it once. Caveat from the source: callers must not mutate the returned arrays, and the npz is a vendored read-only asset - if it ever changes, restart ComfyUI, which you'd be doing anyway for a code change.
Inputs and outputs
No inputs. That's the whole node - add it, and it has data.
Two outputs:
joints-(positions, rotations), positions(1, 77, 3)in centimetres (the leading 1 is one frame), rotations(1, 77, 3, 3)world-space. Same wire formatPoserBindPoseemits, so it's a drop-in swap.mesh-(vertices, faces), vertices in centimetres.
Because both formats match the rest of the pack, this node slots in wherever PoserBindPose + PoserDeformSoma would go: PoserRender for a depth pass, PoserRenderOpenPose for a matching skeleton, both at once for the full conditioning pair.
Install
cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/JayDataEngineer/melite-poser-nodes.git
Restart, or install melite-poser-nodes from ComfyUI Manager. The pack's declared deps are py-soma-x[anny], trimesh and xatlas - but this node deliberately doesn't touch any of them. It's numpy and a vendored NPZ. That makes it the one node in the poser half you can use on a box where the parametric identity layer is fighting you.
And here's the catch you need to know before you queue: the NPZ path is a hard-coded absolute path, /opt/kimodo/kimodo/assets/skeletons/somaskel77/skin_standard.npz, matching the estate's weight-transfer tool constant. If that file doesn't exist on your machine, this node cannot work, and no environment variable overrides it. The file is small and read-only; getting hold of a SOMA-77 skeleton set and placing it at that path is the fix, and PoserRenderOpenPose (with no joints input) wants the same file.
Where people get burned
Don't treat the template pose as "wrong". People see the arm drop and the elbow bend and assume the exporter failed or that they should re-pose it to an A-pose before conditioning. The whole point is that this is the pose the weight transfer expects. Re-posing it defeats the node.
Units again, and this time there's a conversion in the middle. The NPZ is metres, the output is centimetres. If you're comparing these joints against something you loaded yourself with numpy, check what units you loaded.
The rotations have no translation in them. Positions are a separate array. Pull the joint location from positions, not from the bottom row of a rotation matrix that isn't there.
No identity_coeffs, no shaping. This is one fixed body. For a shaped body use PoserBindPose and accept that you're now in engine territory with the py-soma-x dependency.
The pack is MIT, published from a private inference-estate repo in September 2026, and there is no public discussion of it anywhere - so when the template path bites, the answer is in the source and in your filesystem, not on a forum.
Inputs (0)
No inputs
Outputs (2)
| Name | Type | Description |
|---|---|---|
| joints | JOINTS | — |
| mesh | MESH | — |