You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
QtMeshEditor today supports playing skeletal animation, transforming the whole skeleton (SkeletonTransform::scaleSkeleton/translateSkeleton/rotateSkeleton), dragging bones with auto-key (BoneDragRelease), visualising weights as a heatmap (BoneWeightOverlay), debug-drawing bones (SkeletonDebug), and merging/renaming clips (AnimationMerger, SkeletonTransform::renameAnimation). Phase 5 added the dope sheet and curve editor.
What's not there: any way to actually edit the rig itself. No create/remove/reparent/rename bones. No skin weight painting. No IK authoring. No pose mirroring. No constraints. No envelopes. No rest-pose tools. No bone groups / display layers. No bone-shape customization. No FK/IK switch. None of the everyday tools a rigger reaches for.
This epic closes that gap: turn QtMeshEditor from a skeleton viewer/animator into a skeleton editor/rigger, with the standard rigging vocabulary that Blender, Maya, Houdini, Unity, and Unreal users already know.
GUI + CLI + MCP parity, undo through UndoManager, Sentry breadcrumbs (scene.skel.*), and the slice-PR cadence used by the recent UV (#458), HDR (#466), Lights (#482), Anim (#517), and Paint (#543) epics.
Why
Imported rigs are non-editable today. The user can only play what came in. Any tweak — add a tail bone, remove an unused IK target, rename mixamorig:Hips to Hips — requires bouncing through Blender.
Skin weights can't be edited or painted.BoneWeightOverlay shows the heatmap but the user can't fix it. AI-assist plans biharmonic auto-weights (AI: libigl bounded biharmonic skinning weights #402) — those will need manual cleanup, which we don't support.
No IK authoring means hand-animating arms/legs is the long way. Phase 5 added the curve editor; this slice adds the rigging tools that feed the curve editor with smarter source motion.
BoneDragRelease already drags bones with auto-key. This epic adds the surrounding rigging context so the drag-and-key flow becomes a proper authoring workflow rather than a single primitive.
Architecture
Builds directly on what's there. No replacements, only extensions:
SkeletonEditor singleton (src/SkeletonEditor.{h,cpp}) — owns bone-mutation operations: create, remove, reparent, rename, split, duplicate, mirror. Routes everything through Ogre's Skeleton API and the same revision counter EditableMesh uses so QML inspector + viewport gizmos refresh consistently.
SkinWeightController singleton — owns weight authoring (painting, normalizing, mirroring, smoothing, locking). Wraps Ogre::SubMesh::addBoneAssignment / getBoneAssignments. Pairs naturally with the Paint v2 epic's BrushEngine (Epic: Paint v2 — Gradients, textured brushes, layers, full PBR painting #543) — weight painting is "paint into a bone-index channel".
IKChainController — minimal viable IK authoring (CCD or analytical 2-bone), pole targets, FK/IK switch with bake-back.
BoneShapeLibrary — per-bone display shape (sphere / box / arrow / custom mesh) so riggers can distinguish handle bones, control bones, deformation bones at a glance.
Reused infrastructure: SkeletonTransform keeps doing skeleton-level TRS; BoneDragRelease keeps its drag-and-keyframe flow; BoneWeightOverlay extends to show active weight under the cursor for the new paint slice; SkeletonDebug becomes the renderer for the new bone shapes; MeshImporterExporter extends to round-trip the new rig metadata (bone groups, constraints where the format supports them, IK metadata into glTF extras).
Every operation is undoable through the existing UndoManager with mergeable commands for slider/drag interactions (mirror TranslateCommand::mergeWith). Every slice ships GUI + CLI + MCP coverage with Sentry breadcrumbs.
Child Issues
Slices A–D are the must-haves the user explicitly asked for (bone CRUD + reparent/attach + weight paint). E–H are the missing-feature must-haves any rigger expects. I is stretch. J brings everything to project conventions.
No regression in current animation playback, drag-with-auto-key, or weight-overlay paths.
CLAUDE.md "Skeletal Rigging" section under Architecture.
Dependencies & related issues
AI: libigl bounded biharmonic skinning weights #402 (AI: libigl biharmonic skinning weights) — generates initial weights for an unrigged mesh. Slice D in this epic provides the manual cleanup tools that always follow auto-weights.
Muscle / physics simulation rigs. Soft-body and dynamics out of scope.
Spline IK, stretchy chains, ribbon rigs. Future stretch; not in v1.
Character "metarig" wizards (Rigify-style auto-generation from a template). Future epic.
Cloth / hair / fur rigging. Different domain.
Procedural deformers (lattice, wave, bend modifiers). Out of scope.
Real-time mocap streaming. Different epic.
Notes for implementers
Ogre's Skeleton API has createBone, getBone, but no removeBone — bone deletion has to walk the bone list, rebuild handles, and rewrite affected VertexBoneAssignments in every submesh that references the deleted handle. Plan for this complexity in Slice A.
The drag-with-auto-key wiring in BoneDragRelease is the model — every new rig-authoring operation that produces motion should integrate with UndoManager the same way.
glTF skeleton round-trip is the bar for Slice A–C. FBX has more surface (constraints, IK metadata) but is lossy in the open-source toolchain.
Skin weight paint must reuse Paint v2's BrushEngine (Epic: Paint v2 — Gradients, textured brushes, layers, full PBR painting #543 Slice C blockers permitting). If Paint v2 hasn't shipped Slice C yet when Slice D here is ready, paint a layered prototype off TexturePaintController and migrate when Paint v2 catches up.
Constraints + IK evaluate per frame — wire them into the same animation-state evaluation that AnimationControlController drives; do not invent a parallel update loop.
Slice cadence + screenshots + Xvfb-safe tests per project convention.
Overview
QtMeshEditor today supports playing skeletal animation, transforming the whole skeleton (
SkeletonTransform::scaleSkeleton/translateSkeleton/rotateSkeleton), dragging bones with auto-key (BoneDragRelease), visualising weights as a heatmap (BoneWeightOverlay), debug-drawing bones (SkeletonDebug), and merging/renaming clips (AnimationMerger,SkeletonTransform::renameAnimation). Phase 5 added the dope sheet and curve editor.What's not there: any way to actually edit the rig itself. No create/remove/reparent/rename bones. No skin weight painting. No IK authoring. No pose mirroring. No constraints. No envelopes. No rest-pose tools. No bone groups / display layers. No bone-shape customization. No FK/IK switch. None of the everyday tools a rigger reaches for.
This epic closes that gap: turn QtMeshEditor from a skeleton viewer/animator into a skeleton editor/rigger, with the standard rigging vocabulary that Blender, Maya, Houdini, Unity, and Unreal users already know.
GUI + CLI + MCP parity, undo through
UndoManager, Sentry breadcrumbs (scene.skel.*), and the slice-PR cadence used by the recent UV (#458), HDR (#466), Lights (#482), Anim (#517), and Paint (#543) epics.Why
mixamorig:HipstoHips— requires bouncing through Blender.BoneWeightOverlayshows the heatmap but the user can't fix it. AI-assist plans biharmonic auto-weights (AI: libigl bounded biharmonic skinning weights #402) — those will need manual cleanup, which we don't support.BoneDragReleasealready drags bones with auto-key. This epic adds the surrounding rigging context so the drag-and-key flow becomes a proper authoring workflow rather than a single primitive.Architecture
Builds directly on what's there. No replacements, only extensions:
SkeletonEditorsingleton (src/SkeletonEditor.{h,cpp}) — owns bone-mutation operations: create, remove, reparent, rename, split, duplicate, mirror. Routes everything through Ogre'sSkeletonAPI and the same revision counterEditableMeshuses so QML inspector + viewport gizmos refresh consistently.SkinWeightControllersingleton — owns weight authoring (painting, normalizing, mirroring, smoothing, locking). WrapsOgre::SubMesh::addBoneAssignment/getBoneAssignments. Pairs naturally with the Paint v2 epic'sBrushEngine(Epic: Paint v2 — Gradients, textured brushes, layers, full PBR painting #543) — weight painting is "paint into a bone-index channel".IKChainController— minimal viable IK authoring (CCD or analytical 2-bone), pole targets, FK/IK switch with bake-back.BoneConstraintEngine— runtime evaluation of look-at, copy-rotation, parent-of, limit-rotation per bone (overlapping with Anim: Slice H — Constraints (look-at, IK targets, parent-of, copy-rotation) #525 in the Animation epic; this is the home for the rigging-side authoring while Anim: Slice H — Constraints (look-at, IK targets, parent-of, copy-rotation) #525 covers the animation-evaluation side).PoseMirror— left/right bone naming detection + mirror plane authoring; consumed by the Animation epic's pose library (Anim: Slice D — Pose library (named poses, blend, apply, export) #521).BoneShapeLibrary— per-bone display shape (sphere / box / arrow / custom mesh) so riggers can distinguish handle bones, control bones, deformation bones at a glance.Reused infrastructure:
SkeletonTransformkeeps doing skeleton-level TRS;BoneDragReleasekeeps its drag-and-keyframe flow;BoneWeightOverlayextends to show active weight under the cursor for the new paint slice;SkeletonDebugbecomes the renderer for the new bone shapes;MeshImporterExporterextends to round-trip the new rig metadata (bone groups, constraints where the format supports them, IK metadata into glTF extras).Every operation is undoable through the existing
UndoManagerwith mergeable commands for slider/drag interactions (mirrorTranslateCommand::mergeWith). Every slice ships GUI + CLI + MCP coverage with Sentry breadcrumbs.Child Issues
Slices A–D are the must-haves the user explicitly asked for (bone CRUD + reparent/attach + weight paint). E–H are the missing-feature must-haves any rigger expects. I is stretch. J brings everything to project conventions.
BrushEngine)Acceptance Criteria (epic-level)
_l/_r,Left*/Right*, and configurable naming conventions; consumed by the Animation epic's pose library (Anim: Slice D — Pose library (named poses, blend, apply, export) #521).qtmesh rig add-bone | remove-bone | reparent | rename-bone | paint-weight | mirror-weight | apply-ik.add_bone,remove_bone,reparent_bone,rename_bone,paint_skin_weight,mirror_skin_weight,create_ik_chain,bake_ik_to_fk,set_bone_constraint.scene.skel.*per action.CLAUDE.md"Skeletal Rigging" section under Architecture.Dependencies & related issues
BrushEnginefor the weight brush so radius/strength/falloff/pressure/symmetry/stabilizer come for free.Out of scope
Notes for implementers
SkeletonAPI hascreateBone,getBone, but noremoveBone— bone deletion has to walk the bone list, rebuild handles, and rewrite affectedVertexBoneAssignmentsin every submesh that references the deleted handle. Plan for this complexity in Slice A.BoneDragReleaseis the model — every new rig-authoring operation that produces motion should integrate withUndoManagerthe same way.BrushEngine(Epic: Paint v2 — Gradients, textured brushes, layers, full PBR painting #543 Slice C blockers permitting). If Paint v2 hasn't shipped Slice C yet when Slice D here is ready, paint a layered prototype offTexturePaintControllerand migrate when Paint v2 catches up.AnimationControlControllerdrives; do not invent a parallel update loop.