GLB model appears deformed (crushed) in Three.js, but animations and skeleton load correctly

I’m working on a Three.js game using Electron, and I’m running into a strange issue when importing a GLB model exported from Blender. When I load my model in Three.js, the mesh appears crushed on itself as shown on the image while its skeleton (using SkeletonHelper) seems correct and is correctly animated.

  • The model includes baked animations, and there are no constraints left in the armature.
  • The hierarchy is clean and correct.
  • When I load the model in the Don McCurdy glTF Viewer and the Babylon.js sandbox, everything works fine — mesh, skeleton, and animations. No warning.
  • When I load the same GLB in my Three.js app without animations, the mesh displays correctly.

But when I load it with animations included, the mesh appears completely deformed, although the skeleton still loads properly and plays animations.

I checked:

  • The model uses a single SkinnedMesh
  • The skeleton structure seems correct
  • The model passes the Khronos glTF validator — only warning is an unused TEXCOORD_0

I’m applying the animations to gltf.scene using AnimationMixer

Do you have any idea of ​​the origin of the problem?

After a lot of trial and error, I unintentionally fixed the issue by using SkeletonUtils.clone() to clone the loaded gltf.scene before adding it to my scene and applying animations.

To be honest, I’m not entirely sure what the root cause was. My best guess is that there was some kind of mismatch or internal reference issue between the original SkinnedMesh and its Skeleton when applying animations directly to the unmodified gltf scene. Perhaps cloning with SkeletonUtils forces a proper rebinding of the mesh to the skeleton.

If someone has a more technical explanation for why this happens, I’d love to hear it — but in the meantime, if anyone runs into a similar issue with animated GLB models looking crushed in Three.js: try SkeletonUtils.clone()! It solved it for me.

Perhaps cloning with SkeletonUtils forces a proper rebinding of the mesh to the skeleton.

Exactly right. That’s why SkeletonUtils.clone() was created.

Normal .clone() ing of skinnedmeshes doesn’t properly clone the Skeleton object, since it doesn’t technically live inside the scene graph, but rather is a separate object that refers to components inside the graph, so SkeletonUtils.clone() knows to locate this “skeleton” object and copy it properly, including binding to the clones() bones, instead of it staying bound to the original object.
It’s not ideal, but it’s an actual architectural quirk that has to be worked around to still stay flexible.

1 Like