Bone rotation changes correctly in memory but mesh never updates visually (skinned mesh from Blender glTF export)

Hi,
I’m stuck on a skinning issue I can’t resolve despite extensive debugging. I have a character rig exported from Blender 5.0.1 to GLB, loaded via SceneLoader.ImportMesh. The skeleton has 100 bones, properly linked to the mesh (confirmed via Weight Paint in Blender — vertex groups exist and have correct non-zero weights for the bones I’m testing).

The problem: when I rotate a bone in JavaScript (e.g. Spine_01), the rotation value changes correctly in memory (confirmed via console.log every frame, values oscillate as expected), but the mesh never visually deforms. The skeleton lines (via SkeletonViewer) also stay frozen in rest pose.

What I’ve already ruled out:

  • The bone uses rotationQuaternion (not Euler rotation) — I update the quaternion correctly each frame, confirmed by logging it changes.
  • squelette.prepare() called every frame — no effect.
  • No animations or Animatables running that could override it (scene.animatables.length === 0, getAnimationRanges() empty).
  • Tried registerBeforeRender and registerAfterRender — same result.
  • numBoneInfluencers is 4 (default), needInitialSkinMatrix is false.
  • Tested on a manually-built mesh + skeleton (cylinder, 2 bones, manual MatricesIndicesKind/MatricesWeightsKind) in the same project — this one animates perfectly with the exact same quaternion code.
  • Tested the exact same minimal skinning code in the official Playground — works perfectly.
  • Tested with a second, completely different GLB export (older Sketchfab rig, different bone names) — same frozen behavior.
  • Weight Paint in Blender confirms gradient weights exist on the relevant bone for the relevant mesh.

So the manual skinning approach works fine in this exact environment, but imported GLB skinned meshes stay frozen no matter what I do to the bones in code, even though the bone data updates correctly in memory.

Babylon.js version: 9.12.1, WebGL2.

I’d really appreciate help inspecting the GLB file itself if anyone has bandwidth — I suspect something in the Blender glTF export (inverse bind matrices? duplicate bone indices?) but I can’t pinpoint it from the JS side alone. I can provide the .glb file directly.

Playground reproducing the working manual-skinning case (for comparison).

Playground reproducing the issue with the imported GLB:

Playground showing the same quaternion bone rotation code working with a manually created skeleton (cylinder test):

For a GLTF skeleton you have to use the TransformNode that is linked to the bone. See here: https://playground.babylonjs.com/#FDL8IN#1

Thank you so much, this fixed it! I had tried .getTransformNode() before but apparently wasn’t connecting it correctly with the rest of the animation logic. Really appreciate you taking the time to look into this — saved me hours of further debugging!