Fitting skeleton to mesh after using shape keys?

hello, i have this human model from makehuman addon in blender. i imported using gltfloader, and the shape keys and the rest works great. The problem is that when adjust the mesh with shape keys, the skeleton stays at the same position.

chatgpt suggests calculating the offset between base position and morphed positions of vertices, and move each bone by that offset. there are a lot of shape keys and the skeleton has over 900 bones, so i thought maybe there’s a more efficient way of doing this. What kind of approach do you recommend?

i was able to fix it by using reference points on the mesh.

class SkeletonAlignment {
  constructor(mesh, skeletonDataUrl, vertexDataUrl) {
    this.mesh = mesh;
    this.skeletonDataUrl = skeletonDataUrl; //rig data you generate in blender
    this.vertexDataUrl = vertexDataUrl; //vertex group data found in makehuman directory
    this.skeletonData = null;
    this.vertexData = null;
  }

  async loadJSONFiles() {
    try {
      const [skeletonResponse, vertexResponse] = await Promise.all([
        fetch(this.skeletonDataUrl),
        fetch(this.vertexDataUrl),
      ]);

      this.skeletonData = await skeletonResponse.json();
      this.vertexData = await vertexResponse.json();
    } catch (error) {
      console.error("Error loading JSON files:", error.message);
    }
  }
  // put single values in array, flatten those retrieved from vertex data file
  toArray(value) {
    return Array.isArray(value) ? value : [value];
  }

  flattenArray(value) {
    return Array.isArray(value) && Array.isArray(value[0]) ? value.flat() : this.toArray(value);
  }

  getJointPositions(boneName) {
    const boneData = this.skeletonData.bones[boneName];

    if (!boneData) {
      console.warn(`Bone data not found for: ${boneName}`);
      return null;
    }
    // three strategies for each bone: cube, mean, or vertex.
    const headVertices = boneData.head.cube_name
      ? this.flattenArray(this.vertexData[boneData.head.cube_name])
      : this.toArray(boneData.head.vertex_indices || boneData.head.vertex_index);

    const tailVertices = boneData.tail.cube_name
      ? this.flattenArray(this.vertexData[boneData.tail.cube_name])
      : this.toArray(boneData.tail?.vertex_indices || boneData.tail?.vertex_index);

    return {
      bone: boneName,
      head: boneData.head.cube_name || boneData.head.strategy,
      tail: boneData.tail.cube_name || boneData.tail.strategy,
      headVertices,
      tailVertices,
      headPosition: this.calculateAveragePosition(headVertices),
      tailPosition: this.calculateAveragePosition(tailVertices), 
    };
    
  }

  calculateAveragePosition(vertices) {
    if (!vertices[0]) {
      console.warn("invalid or empty vertices array", vertices);
      return null;
    }

    if (vertices.length === 1) {
      const tempVec = new THREE.Vector3();
      this.mesh.getVertexPosition(vertices[0], tempVec);
      return tempVec;
    }
    const [start, end] = vertices;

    const tempVec = new THREE.Vector3();
    let sum = new THREE.Vector3();
    let count = 0;

    for (let i = start; i <= end; i++) {
      this.mesh.getVertexPosition(i, tempVec);
      sum.add(tempVec);
      count++;
    }

    return sum.divideScalar(count);
    
  }

  updateJointPositions() {
    const skeleton = this.mesh.skeleton;
  
    const jointPos = skeleton.bones.map((bone) => {
      if (bone.userData.name === "neutral_bone") {
        //console.warn(`Skipping neutral bone`);
        return null;
      }

      const position = this.getJointPositions(bone.userData.name);
      if (!position) {
        console.error(`Invalid joint position for bone: ${bone.userData.name}`);
      }
      return position;
    });

    skeleton.bones.forEach((bone, i) => {
      if (bone.userData.name === "neutral_bone" || !jointPos[i].headPosition) {
        return;
      }
      const localVec = new THREE.Vector3();
      const parentBone = bone.parent;
      const parentMatrixWorld = parentBone.matrixWorld.clone().invert();
      if (!jointPos[i].headPosition) return;
      localVec.copy(jointPos[i].headPosition).applyMatrix4(parentMatrixWorld);
      bone.position.copy(localVec);
      bone.updateMatrixWorld();
    });
    skeleton.calculateInverses();
    this.mesh.updateMatrixWorld();
  }
}

when i call the updateJointPositions function with dat gui’s onChange function all bones move to their reference positions on the mesh.