moeru-ai/airi · warning
No Hips.position track of type VectorKeyframeTrack found in
Error message
No Hips.position track of type VectorKeyframeTrack found in animation.
What it means
After finding the hips node, reAnchorRootPositionTrack() searches clip.tracks for a VectorKeyframeTrack whose name is exactly `${hipNode.name}.position`. If no such track exists — the animation contains only rotations, or the position track uses a different PropertyBinding name/path — it warns and returns, leaving the root position uncorrected.
Source
Thrown at packages/stage-ui-three/src/composables/vrm/animation.ts:68
// Set initial positions for animation
export function reAnchorRootPositionTrack(clip: AnimationClip, _vrm: VRMCore) {
// Get the hips node to re-anchor the root position track
const hipNode = _vrm.humanoid?.getNormalizedBoneNode('hips')
if (!hipNode) {
console.warn('No hips node found in VRM model.')
return
}
hipNode.updateMatrixWorld(true)
const defaultHipPos = new Vector3()
hipNode.getWorldPosition(defaultHipPos)
// Calculate the offset from the hips node to the hips's first frame position
const hipsTrack = clip.tracks.find(track =>
track instanceof VectorKeyframeTrack
&& track.name === `${hipNode.name}.position`,
)
if (!(hipsTrack instanceof VectorKeyframeTrack)) {
console.warn('No Hips.position track of type VectorKeyframeTrack found in animation.')
return
}
const animeHipPos = new Vector3(
hipsTrack.values[0],
hipsTrack.values[1],
hipsTrack.values[2],
)
const animeDelta = new Vector3().subVectors(animeHipPos, defaultHipPos)
clip.tracks.forEach((track) => {
if (track.name.endsWith('.position') && track instanceof VectorKeyframeTrack) {
for (let i = 0; i < track.values.length; i += 3) {
track.values[i] -= animeDelta.x
track.values[i + 1] -= animeDelta.y
track.values[i + 2] -= animeDelta.z
}
}View on GitHub (pinned to 677329427f)
Solutions
- Log clip.tracks.map(t => t.name) and compare with the expected `${hipNode.name}.position` binding.
- Use a .vrma that actually keyframes hips translation (full-body animations do).
- If the track is optional for your clip type, guard with the same check and skip re-anchoring intentionally.
Example fix
// before
reAnchorRootPositionTrack(clip, vrm) // warns: no hips position track
// after
const hips = vrm.humanoid?.getNormalizedBoneNode('hips')
const hasHipsPos = !!hips && clip.tracks.some(t => t.name === `${hips.name}.position`)
if (hasHipsPos) reAnchorRootPositionTrack(clip, vrm) Defensive patterns
Strategy: validation
Validate before calling
const hips = vrm.humanoid?.getNormalizedBoneNode('hips')
const hasHipsPosTrack = !!hips && clip.tracks.some(t => t.name === `${hips.name}.position`)
if (!hasHipsPosTrack) { /* rotation-only clip: skip re-anchor */ } Prevention
- Classify clips (full-body vs upper-body) before applying root re-anchoring.
- Log track names when integrating new .vrma assets to confirm binding format.
- Remember re-anchoring is an enhancement; design playback to be correct without it.
When it happens
Trigger: Playing an upper-body or idle .vrma that animates only bone quaternion tracks; a clip whose hips position track is bound to the raw (non-normalized) bone name so the normalized hipNode.name does not match; hand-built AnimationClips without a hips position track.
Common situations: Mix-and-match of clips from different rigs; three.js track-name formats (node.position vs bones[name].position) after retargeting; upper-body-only animations.
Related errors
- [mmd] playAction skipped: "${name}" is not registered
- [mmd] setIdleMotion skipped: "${name}" is not registered
- No VRM found
- No hips node found in VRM model.
- No VRM animation loaded
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/ff500c36eb7f5cce.
Report an issue: GitHub.