{"record":{"id":"eb0218e2874b0b4b","repo":"moeru-ai/airi","slug":"no-hips-node-found-in-vrm-model","errorCode":null,"errorMessage":"No hips node found in VRM model.","messagePattern":"No hips node found in VRM model\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/stage-ui-three/src/composables/vrm/animation.ts","lineNumber":55,"sourceCode":"export async function clipFromVRMAnimation(vrm?: VRMCore, animation?: VRMAnimation) {\n  if (!vrm) {\n    console.warn('No VRM found')\n    return\n  }\n  if (!animation) {\n    return\n  }\n\n  // create animation clip\n  return createVRMAnimationClip(animation, vrm)\n}\n\n// Set initial positions for animation\nexport function reAnchorRootPositionTrack(clip: AnimationClip, _vrm: VRMCore) {\n// Get the hips node to re-anchor the root position track\n  const hipNode = _vrm.humanoid?.getNormalizedBoneNode('hips')\n  if (!hipNode) {\n    console.warn('No hips node found in VRM model.')\n    return\n  }\n  hipNode.updateMatrixWorld(true)\n  const defaultHipPos = new Vector3()\n  hipNode.getWorldPosition(defaultHipPos)\n\n  // Calculate the offset from the hips node to the hips's first frame position\n  const hipsTrack = clip.tracks.find(track =>\n    track instanceof VectorKeyframeTrack\n    && track.name === `${hipNode.name}.position`,\n  )\n  if (!(hipsTrack instanceof VectorKeyframeTrack)) {\n    console.warn('No Hips.position track of type VectorKeyframeTrack found in animation.')\n    return\n  }\n\n  const animeHipPos = new Vector3(\n    hipsTrack.values[0],","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-ui-three/src/composables/vrm/animation.ts#L37-L73","documentation":"reAnchorRootPositionTrack() re-centers a VRM animation by offsetting the root position track relative to the model's hips. It fetches the normalized hips node via _vrm.humanoid?.getNormalizedBoneNode('hips'); when the VRM has no humanoid rig (or no hips bone), it warns and returns without re-anchoring, so the animation may play at an offset position.","triggerScenarios":"Passing a VRM exported without the VRMC_vrm humanoid extension; a model whose humanoid bone map omits hips; calling the helper on a plain glTF/VRM0 model through the same code path.","commonSituations":"Non-humanoid props or creatures exported as VRM; broken VRM exporters that skip the humanoid block; testing with placeholder models.","solutions":["Check _vrm.humanoid is defined and getNormalizedBoneNode('hips') returns a node before calling reAnchorRootPositionTrack.","Re-export the model with a complete VRM humanoid mapping (hips is mandatory in the spec).","Skip re-anchoring for non-humanoid models — the clip still plays, only root offset correction is lost."],"exampleFix":"// before\nreAnchorRootPositionTrack(clip, vrm) // warns when humanoid is missing\n\n// after\nif (vrm.humanoid?.getNormalizedBoneNode('hips')) {\n  reAnchorRootPositionTrack(clip, vrm)\n}","handlingStrategy":"validation","validationCode":"if (!vrm.humanoid?.getNormalizedBoneNode('hips')) { /* skip re-anchor */ }","typeGuard":"function hasHips(vrm: VRMCore): boolean {\n  return !!vrm.humanoid?.getNormalizedBoneNode('hips')\n}","tryCatchPattern":null,"preventionTips":["Validate VRM imports in onboarding: require the humanoid extension with hips.","Branch on humanoid presence so non-humanoid VRM uses a separate code path.","Unit-test helpers with minimal mock VRMs lacking humanoid."],"tags":["vrm","humanoid","hips","animation","root-motion"],"backgroundTag":"missing-humanoid-bone","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}