Runtime rig layer
The "load and drive a rig at runtime" foundation — renderer-agnostic, the basis for a VR spectator
view. It spans several crates and is validated by a renderer-free rest-pose reproduction invariant. Full
text: docs/reference/rig-runtime.md.
The crates
avatar render --avatar model.fbx --pose Avatar.prefab -o posed.png # the rig layer, driven from a prefab's pose
avatar render --avatar model.fbx --stretch 'Skirt_*:1.5' -o out.pngavatar-mesh— PODRawMesh/ skin interchange, noglam.avatar-fbx::meshes()+avatar-gltf— FBX / glTF →RawMesh+ skin/bind.avatar-pose—PosedSkeleton→ world matrices, GPU bone-matrix palette, CPU skinning,pose::iktwo-bone IK.avatar-input—TrackerState/TrackerSource;MockSource+ anosc-feature backend; OpenXR planned.
Bind & the rest-pose invariant
Bind comes from TransformLink / inverse-bind — never recomposed from
Lcl + PreRotation. The load → pose → skin pipeline is validated by a
renderer-free rest-pose reproduction invariant: posing the skeleton at its rest pose and
skinning must reproduce the original mesh.
When the per-cluster bind Transforms can't be trusted (converted/MMD→FBX avatars), a
pose can still be applied to the raw control points as a per-bone delta
(G⁻¹ · world(pose) · world(rest)⁻¹ · G) that never
involves the cluster binds — identity for every untouched bone. avatar render --pose
<prefab> / --stretch are built on it (see render).
Using it from Rust
use std::path::Path;
let scene = avatar_fbx::FbxScene::load(Path::new("model.fbx"))?;
let meshes = avatar_fbx::FbxDocument::load(Path::new("model.fbx"))?.meshes()?; // RawMesh + skin per mesh
let skeleton = avatar_armature::Skeleton::from_scene(&scene);
let skel = avatar_pose::PosedSkeleton::from_fbx(&skeleton, &scene, &meshes[0]);
let mut pose = skel.rest_pose(); // identity palette at rest
pose.set_local(skel.index_of(bone_id).unwrap(), local_matrix);
let palette = skel.palette(&pose); // world ยท inverse_bind per bone
// GPU: upload `palette`; CPU: avatar_pose::cpu_skin(&mesh, &vertex_skin, &palette)
Signatures as of this docs pass; the crate READMEs are authoritative.
glam (f32) is confined to pose/input/gltf — it never reaches the lint/cli graph, which is verified by cargo tree.