var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var skinned_mesh_exports = {};
__export(skinned_mesh_exports, {
  buildEntitySkinnedMesh: () => buildEntitySkinnedMesh
});
module.exports = __toCommonJS(skinned_mesh_exports);
var import_context = require("./context.js");
var import_builders = require("./builders.js");
var import_texture_atlas = require("./texture-atlas.js");
function applyNodeTransforms(THREE, object, node) {
  object.position.set(node.position[0], node.position[1], node.position[2]);
  if (node.rotation) {
    object.rotation.set(THREE.MathUtils.degToRad(node.rotation[0]), THREE.MathUtils.degToRad(node.rotation[1]), THREE.MathUtils.degToRad(node.rotation[2]));
  }
  if (node.scale) {
    object.scale.set(node.scale[0], node.scale[1], node.scale[2]);
  }
}
function assignPrimitiveOwner(object, ownerId) {
  const stack = [object];
  while (stack.length > 0) {
    const current = stack.pop();
    current.userData = { ...current.userData ?? {}, primitiveOwnerId: ownerId };
    current.children.forEach((child) => stack.push(child));
  }
}
function buildNodeGraph(context, node, visitedPrimitives = /* @__PURE__ */ new Set()) {
  const object = new context.THREE.Object3D();
  object.name = node.id;
  object.userData = {
    ...object.userData ?? {},
    nodeId: node.id
  };
  applyNodeTransforms(context.THREE, object, node);
  const nodes = /* @__PURE__ */ new Map();
  nodes.set(node.id, object);
  if (node.mesh) {
    const primitive = context.primitivesById.get(node.mesh);
    if (primitive) {
      const primitiveObject = (0, import_builders.createPrimitiveObject)(context, primitive, "centered", visitedPrimitives);
      if (primitiveObject) {
        if (node.center) {
          primitiveObject.position.set(node.center[0], node.center[1], node.center[2]);
        }
        assignPrimitiveOwner(primitiveObject, node.id);
        object.add(primitiveObject);
      }
    }
  } else if (node.size) {
    const placeholder = (0, import_builders.createBoundingBoxMesh)(context, node.size);
    placeholder.userData = {
      ...placeholder.userData ?? {},
      primitiveOwnerId: node.id,
      size: [...node.size]
    };
    if (node.center) {
      placeholder.position.set(node.center[0], node.center[1], node.center[2]);
    }
    object.add(placeholder);
  }
  node.children.forEach((child) => {
    const childGraph = buildNodeGraph(context, child, new Set(visitedPrimitives));
    object.add(childGraph.object);
    childGraph.nodes.forEach((childObject, childId) => nodes.set(childId, childObject));
  });
  return { object, nodes };
}
function buildBoneHierarchy(THREE, node, parentBone, bones, boneMap, boneIndexMap) {
  const bone = new THREE.Bone();
  bone.name = node.id;
  bone.position.set(node.position[0], node.position[1], node.position[2]);
  if (node.rotation) {
    bone.rotation.set(THREE.MathUtils.degToRad(node.rotation[0]), THREE.MathUtils.degToRad(node.rotation[1]), THREE.MathUtils.degToRad(node.rotation[2]));
  }
  if (node.scale) {
    bone.scale.set(node.scale[0], node.scale[1], node.scale[2]);
  }
  if (parentBone) {
    parentBone.add(bone);
  }
  bones.push(bone);
  boneMap.set(node.id, bone);
  boneIndexMap.set(node.id, bones.length - 1);
  node.children.forEach((child) => {
    buildBoneHierarchy(THREE, child, bone, bones, boneMap, boneIndexMap);
  });
}
function materialToColor(THREE, material) {
  if ("color" in material && material.color instanceof THREE.Color) {
    return material.color.clone();
  }
  return new THREE.Color(0.5, 0.5, 0.5);
}
const CONNECT_FALLOFF_RATIO = 0.35;
const CONNECT_MIN_RADIUS = 0.25;
const CONNECT_SIGMA_MULTIPLIER = 0.55;
const CONNECT_WEIGHT_EPSILON = 1e-4;
function buildEntitySkinnedMesh(options) {
  const { THREE, entity } = options;
  const warnings = [];
  const builderContext = (0, import_context.createBuilderContext)({
    THREE,
    settings: { enableShadows: false }
  });
  (0, import_context.updateBuilderContext)(builderContext, { entity });
  const { object: nodeRootObject, nodes: nodeObjects } = buildNodeGraph(builderContext, entity.geometry.root);
  nodeRootObject.updateMatrixWorld(true);
  const nodeDefs = /* @__PURE__ */ new Map();
  const parentMap = /* @__PURE__ */ new Map();
  (function collect(node, parentId) {
    nodeDefs.set(node.id, node);
    parentMap.set(node.id, parentId);
    node.children.forEach((child) => collect(child, node.id));
  })(entity.geometry.root, null);
  const bones = [];
  const boneMap = /* @__PURE__ */ new Map();
  const boneIndexMap = /* @__PURE__ */ new Map();
  buildBoneHierarchy(THREE, entity.geometry.root, null, bones, boneMap, boneIndexMap);
  if (bones.length === 0) {
    throw new Error("entity_skinned_mesh_no_bones");
  }
  bones[0].updateMatrixWorld(true);
  const boneInverses = bones.map((bone) => bone.matrixWorld.clone().invert());
  const positions = [];
  const normals = [];
  const colors = [];
  const uvs = [];
  const skinIndices = [];
  const skinWeights = [];
  const blendStrengths = [];
  const tempColor = new THREE.Color(0.5, 0.5, 0.5);
  const tempWorldPos = new THREE.Vector3();
  const tempLocalPos = new THREE.Vector3();
  const computeSignedDistanceToBounds = (point, halfExtents) => {
    const dx = Math.abs(point.x) - halfExtents.x;
    const dy = Math.abs(point.y) - halfExtents.y;
    const dz = Math.abs(point.z) - halfExtents.z;
    const outsideX = Math.max(dx, 0);
    const outsideY = Math.max(dy, 0);
    const outsideZ = Math.max(dz, 0);
    const outsideDist = Math.sqrt(outsideX * outsideX + outsideY * outsideY + outsideZ * outsideZ);
    if (dx <= 0 && dy <= 0 && dz <= 0) {
      const insideX = halfExtents.x - Math.abs(point.x);
      const insideY = halfExtents.y - Math.abs(point.y);
      const insideZ = halfExtents.z - Math.abs(point.z);
      const minInside = Math.min(insideX, insideY, insideZ);
      return -minInside;
    }
    return outsideDist;
  };
  const evaluateInfluence = (bounds, worldPosition, scratch) => {
    scratch.copy(worldPosition).applyMatrix4(bounds.inverseMatrix).sub(bounds.center);
    const distance = computeSignedDistanceToBounds(scratch, bounds.halfExtents);
    if (distance <= 0) {
      return { inside: true, falloff: 1 };
    }
    const largestAxis = Math.max(bounds.halfExtents.x, bounds.halfExtents.y, bounds.halfExtents.z);
    const radius = Math.max(CONNECT_MIN_RADIUS, largestAxis * CONNECT_FALLOFF_RATIO);
    if (distance >= radius) {
      return { inside: false, falloff: 0 };
    }
    const sigma = radius * CONNECT_SIGMA_MULTIPLIER;
    const ratio = distance / sigma;
    return { inside: false, falloff: Math.exp(-(ratio * ratio)) };
  };
  const connectConfigs = /* @__PURE__ */ new Map();
  const parentBlendLookup = /* @__PURE__ */ new Map();
  const deriveBoundsFromObject = (object) => {
    const cache = object.userData?.__connectBounds;
    if (cache) {
      return cache;
    }
    const bounds = new THREE.Box3().setFromObject(object);
    if (!bounds || !Number.isFinite(bounds.min.x) || bounds.isEmpty()) {
      return null;
    }
    const inverse = object.matrixWorld.clone().invert();
    bounds.applyMatrix4(inverse);
    const sizeVec = new THREE.Vector3();
    const centerVec = new THREE.Vector3();
    bounds.getSize(sizeVec);
    bounds.getCenter(centerVec);
    const size = [sizeVec.x, sizeVec.y, sizeVec.z];
    const center = [centerVec.x, centerVec.y, centerVec.z];
    object.userData = {
      ...object.userData ?? {},
      __connectBounds: { size, center }
    };
    return { size, center };
  };
  const createBounds = (nodeDef, object) => {
    if (!object) {
      return null;
    }
    const sizeSource = nodeDef?.size ?? object.userData?.size ?? deriveBoundsFromObject(object)?.size;
    if (!sizeSource) {
      return null;
    }
    const derived = !nodeDef?.center ? deriveBoundsFromObject(object) : null;
    const centerSource = nodeDef?.center ?? object.userData?.center ?? derived?.center ?? [0, 0, 0];
    return {
      inverseMatrix: object.matrixWorld.clone().invert(),
      center: new THREE.Vector3(centerSource[0], centerSource[1], centerSource[2]),
      halfExtents: new THREE.Vector3(sizeSource[0] / 2, sizeSource[1] / 2, sizeSource[2] / 2)
    };
  };
  nodeDefs.forEach((node, nodeId) => {
    const mode = node.connect ?? "none";
    if (mode === "none") {
      return;
    }
    const parentId = parentMap.get(nodeId);
    if (!parentId) {
      warnings.push(`[skinned] node ${nodeId} connect ${mode} ignored (no parent)`);
      return;
    }
    const parentBoneIndex = boneIndexMap.get(parentId);
    if (parentBoneIndex === void 0) {
      warnings.push(`[skinned] node ${nodeId} connect ${mode} ignored (missing parent bone)`);
      return;
    }
    const childBoneIndex = boneIndexMap.get(nodeId);
    if (childBoneIndex === void 0) {
      warnings.push(`[skinned] node ${nodeId} connect ${mode} ignored (missing child bone)`);
      return;
    }
    const parentObject = nodeObjects.get(parentId);
    if (!parentObject) {
      warnings.push(`[skinned] node ${nodeId} connect ${mode} ignored (missing parent object)`);
      return;
    }
    const childObject = nodeObjects.get(nodeId);
    if (!childObject) {
      warnings.push(`[skinned] node ${nodeId} connect ${mode} ignored (missing child object)`);
      return;
    }
    const parentDef = nodeDefs.get(parentId);
    let childBlend;
    if (mode === "child" || mode === "both") {
      childBlend = createBounds(parentDef, parentObject) ?? void 0;
      if (!childBlend) {
        warnings.push(`[skinned] node ${nodeId} connect ${mode} ignored (parent ${parentId} missing size)`);
      }
    }
    let parentBlend;
    if (mode === "parent" || mode === "both") {
      parentBlend = createBounds(node, childObject) ?? void 0;
      if (!parentBlend) {
        warnings.push(`[skinned] node ${nodeId} connect ${mode} ignored (child ${nodeId} missing size)`);
      }
    }
    if (!childBlend && !parentBlend) {
      return;
    }
    const config = {
      mode,
      childId: nodeId,
      parentId,
      parentBoneIndex,
      childBoneIndex,
      childBlend,
      parentBlend,
      stats: { childVertices: 0, parentVertices: 0 }
    };
    connectConfigs.set(nodeId, config);
    if (config.parentBlend) {
      const existing = parentBlendLookup.get(parentId);
      if (existing) {
        existing.push(config);
      } else {
        parentBlendLookup.set(parentId, [config]);
      }
    }
  });
  const colorTextures = [];
  const textureSet = /* @__PURE__ */ new Set();
  const emissivePairs = /* @__PURE__ */ new Map();
  let needsAlphaTest = false;
  let needsDoubleSide = false;
  nodeObjects.forEach((nodeObject) => {
    nodeObject.traverse((child) => {
      if (!child.isMesh) {
        return;
      }
      const mesh2 = child;
      if (!mesh2.geometry) {
        return;
      }
      const material2 = mesh2.material;
      const materials = Array.isArray(material2) ? material2 : [material2];
      materials.forEach((entry) => {
        const std = entry;
        if (std.map instanceof THREE.DataTexture && std.map.image?.width && std.map.image?.height) {
          if (!textureSet.has(std.map.uuid)) {
            textureSet.add(std.map.uuid);
            colorTextures.push(std.map);
          }
        }
        if (std.map instanceof THREE.DataTexture && std.emissiveMap instanceof THREE.DataTexture) {
          emissivePairs.set(std.map, std.emissiveMap);
        }
        if (std.alphaTest > 0) {
          needsAlphaTest = true;
        }
        if (std.side === THREE.DoubleSide) {
          needsDoubleSide = true;
        }
      });
    });
  });
  const colorAtlas = (0, import_texture_atlas.buildTextureAtlas)(THREE, colorTextures);
  const transformLookup = colorAtlas?.transforms ?? null;
  const emissiveAtlas = colorAtlas ? (0, import_texture_atlas.buildEmissiveAtlas)(THREE, colorAtlas.width, colorAtlas.height, colorAtlas.transforms, emissivePairs) : null;
  const processPrimitiveObject = (object, ownerId) => {
    object.traverse((child) => {
      if (!child.isMesh) {
        return;
      }
      const mesh2 = child;
      if (!mesh2.geometry) {
        return;
      }
      const material2 = mesh2.material;
      const boneIndex = boneIndexMap.get(ownerId);
      if (boneIndex === void 0) {
        warnings.push(`No bone mapping found for node "${ownerId}".`);
        return;
      }
      const geometry2 = mesh2.geometry.clone();
      geometry2.applyMatrix4(mesh2.matrixWorld);
      const nonIndexed = geometry2.toNonIndexed();
      if (!nonIndexed.getAttribute("normal")) {
        nonIndexed.computeVertexNormals();
      }
      const positionAttr = nonIndexed.getAttribute("position");
      const normalAttr = nonIndexed.getAttribute("normal");
      const uvAttr = nonIndexed.getAttribute("uv");
      if (!positionAttr) {
        warnings.push(`Primitive "${ownerId}" produced geometry without positions.`);
        geometry2.dispose();
        nonIndexed.dispose();
        return;
      }
      const vertexCount = positionAttr.count;
      const materialArray = Array.isArray(material2) ? material2 : [material2];
      const materialIndexPerVertex = new Array(vertexCount).fill(0);
      const groups = nonIndexed.groups && nonIndexed.groups.length > 0 ? nonIndexed.groups : [{ start: 0, count: vertexCount, materialIndex: 0 }];
      groups.forEach((group) => {
        const start = Math.max(0, group.start);
        const end = Math.min(vertexCount, start + group.count);
        const materialIndex = group.materialIndex ?? 0;
        for (let i = start; i < end; i += 1) {
          materialIndexPerVertex[i] = Math.min(materialArray.length - 1, Math.max(0, materialIndex));
        }
      });
      const worldPos = tempWorldPos;
      const localPos = tempLocalPos;
      const hasUv = Boolean(uvAttr);
      const ownerConnect = connectConfigs.get(ownerId);
      const parentBlendEntries = parentBlendLookup.get(ownerId)?.filter((entry) => entry.parentBlend) ?? [];
      for (let i = 0; i < vertexCount; i += 1) {
        const px = positionAttr.getX(i);
        const py = positionAttr.getY(i);
        const pz = positionAttr.getZ(i);
        positions.push(px, py, pz);
        if (normalAttr) {
          normals.push(normalAttr.getX(i), normalAttr.getY(i), normalAttr.getZ(i));
        } else {
          normals.push(0, 1, 0);
        }
        worldPos.set(px, py, pz);
        const weights = /* @__PURE__ */ new Map();
        const setWeight = (index, weight) => {
          if (weight <= CONNECT_WEIGHT_EPSILON) {
            weights.delete(index);
          } else {
            weights.set(index, weight);
          }
        };
        setWeight(boneIndex, 1);
        if (ownerConnect?.childBlend) {
          const evaluation = evaluateInfluence(ownerConnect.childBlend, worldPos, localPos);
          if (ownerConnect.mode === "child") {
            if (evaluation.inside) {
              setWeight(boneIndex, 0);
              setWeight(ownerConnect.parentBoneIndex, 1);
              ownerConnect.stats.childVertices += 1;
            } else if (evaluation.falloff > CONNECT_WEIGHT_EPSILON) {
              const parentWeight = evaluation.falloff;
              setWeight(ownerConnect.parentBoneIndex, parentWeight);
              setWeight(boneIndex, Math.max(0, 1 - parentWeight));
              ownerConnect.stats.childVertices += 1;
            }
          } else if (ownerConnect.mode === "both") {
            if (evaluation.inside) {
              setWeight(boneIndex, 0.5);
              setWeight(ownerConnect.parentBoneIndex, 0.5);
              ownerConnect.stats.childVertices += 1;
            } else if (evaluation.falloff > CONNECT_WEIGHT_EPSILON) {
              const parentWeight = Math.min(0.5, evaluation.falloff * 0.5);
              if (parentWeight > CONNECT_WEIGHT_EPSILON) {
                setWeight(ownerConnect.parentBoneIndex, parentWeight);
                setWeight(boneIndex, Math.max(0, 1 - parentWeight));
                ownerConnect.stats.childVertices += 1;
              }
            }
          }
        }
        if (parentBlendEntries.length > 0) {
          parentBlendEntries.forEach((config) => {
            const bounds = config.parentBlend;
            if (!bounds)
              return;
            const evaluation = evaluateInfluence(bounds, worldPos, localPos);
            if (config.mode === "parent") {
              if (evaluation.inside) {
                setWeight(boneIndex, 0);
                setWeight(config.childBoneIndex, 1);
                config.stats.parentVertices += 1;
              } else if (evaluation.falloff > CONNECT_WEIGHT_EPSILON) {
                const childWeight = evaluation.falloff;
                setWeight(config.childBoneIndex, childWeight);
                setWeight(boneIndex, Math.max(0, 1 - childWeight));
                config.stats.parentVertices += 1;
              }
            } else if (config.mode === "both") {
              if (evaluation.inside) {
                setWeight(boneIndex, 0.5);
                setWeight(config.childBoneIndex, 0.5);
                config.stats.parentVertices += 1;
              } else if (evaluation.falloff > CONNECT_WEIGHT_EPSILON) {
                const childWeight = Math.min(0.5, evaluation.falloff * 0.5);
                if (childWeight > CONNECT_WEIGHT_EPSILON) {
                  setWeight(config.childBoneIndex, childWeight);
                  setWeight(boneIndex, Math.max(0, 1 - childWeight));
                  config.stats.parentVertices += 1;
                }
              }
            }
          });
        }
        let filtered = Array.from(weights.entries()).filter(([, value]) => value > CONNECT_WEIGHT_EPSILON);
        if (filtered.length === 0) {
          filtered = [[boneIndex, 1]];
        }
        const totalWeight = filtered.reduce((sum, [, value]) => sum + value, 0);
        if (totalWeight > 0) {
          const invTotal = 1 / totalWeight;
          filtered = filtered.map(([index, value]) => [index, value * invTotal]);
        } else {
          filtered = [[boneIndex, 1]];
        }
        filtered.sort((a, b) => b[1] - a[1]);
        const maxBlend = filtered.reduce((acc, [index, value]) => {
          if (index === boneIndex) {
            return acc;
          }
          return Math.max(acc, value);
        }, 0);
        blendStrengths.push(maxBlend);
        for (let slot = 0; slot < 4; slot += 1) {
          const influence = filtered[slot];
          if (influence) {
            skinIndices.push(influence[0]);
            skinWeights.push(influence[1]);
          } else {
            skinIndices.push(0);
            skinWeights.push(0);
          }
        }
        const materialIndex = materialIndexPerVertex[i];
        const mat = materialArray[materialIndex];
        const mapTexture = mat?.map;
        const transform = mapTexture && transformLookup ? transformLookup.get(mapTexture) : void 0;
        if (hasUv) {
          if (transform) {
            const u = uvAttr.getX(i) * transform.scale[0] + transform.offset[0];
            const v = uvAttr.getY(i) * transform.scale[1] + transform.offset[1];
            uvs.push(u, v);
          } else {
            uvs.push(uvAttr.getX(i), uvAttr.getY(i));
          }
        }
        if (transform) {
          colors.push(1, 1, 1);
        } else if (mat) {
          tempColor.copy(materialToColor(THREE, mat));
          colors.push(tempColor.r, tempColor.g, tempColor.b);
        } else {
          colors.push(0.5, 0.5, 0.5);
        }
      }
      geometry2.dispose();
      nonIndexed.dispose();
    });
  };
  const traverseNode = (node) => {
    const object = nodeObjects.get(node.id);
    if (object) {
      object.children.forEach((child) => {
        if (child.userData?.primitiveOwnerId === node.id) {
          processPrimitiveObject(child, node.id);
        }
      });
    }
    node.children.forEach(traverseNode);
  };
  traverseNode(entity.geometry.root);
  if (positions.length === 0) {
    throw new Error("entity_skinned_mesh_empty_geometry");
  }
  const geometry = new THREE.BufferGeometry();
  geometry.setAttribute("position", new THREE.Float32BufferAttribute(positions, 3));
  geometry.setAttribute("normal", new THREE.Float32BufferAttribute(normals, 3));
  geometry.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
  if (uvs.length > 0) {
    geometry.setAttribute("uv", new THREE.Float32BufferAttribute(uvs, 2));
  }
  geometry.setAttribute("skinIndex", new THREE.Uint16BufferAttribute(skinIndices, 4));
  geometry.setAttribute("skinWeight", new THREE.Float32BufferAttribute(skinWeights, 4));
  geometry.setAttribute("connectStrength", new THREE.Float32BufferAttribute(blendStrengths, 1));
  geometry.computeBoundingBox();
  geometry.computeBoundingSphere();
  const material = new THREE.MeshStandardMaterial({
    vertexColors: !colorAtlas,
    metalness: 0,
    roughness: 1
  });
  material.skinning = true;
  if (colorAtlas) {
    material.map = colorAtlas.texture;
  }
  if (emissiveAtlas) {
    material.emissiveMap = emissiveAtlas;
    material.emissive.setRGB(1, 1, 1);
    material.emissiveIntensity = 1;
  }
  if (needsAlphaTest) {
    material.alphaTest = 0.5;
    material.transparent = false;
    material.side = THREE.DoubleSide;
  } else if (needsDoubleSide) {
    material.side = THREE.DoubleSide;
  }
  const connectOverlayUniform = { value: 0 };
  material.onBeforeCompile = (shader) => {
    shader.uniforms.uConnectOverlay = connectOverlayUniform;
    shader.vertexShader = shader.vertexShader.replace("#include <common>", "#include <common>\nattribute float connectStrength;\nvarying float vConnectStrength;").replace("#include <begin_vertex>", "#include <begin_vertex>\n  vConnectStrength = connectStrength;");
    shader.fragmentShader = shader.fragmentShader.replace("#include <common>", "#include <common>\nuniform float uConnectOverlay;\nvarying float vConnectStrength;").replace("#include <output_fragment>", `#include <output_fragment>
        if (uConnectOverlay > 0.0) {
          float overlayStrength = clamp(vConnectStrength, 0.0, 1.0);
          vec3 overlayColor = mix(vec3(0.0, 0.2, 1.0), vec3(1.0, 0.0, 0.0), overlayStrength);
          gl_FragColor.rgb = overlayColor;
        }`);
  };
  material.userData.connectOverlayUniform = connectOverlayUniform;
  material.needsUpdate = true;
  const mesh = new THREE.SkinnedMesh(geometry, material);
  mesh.name = `${entity.id ?? "entity"}__skinned`;
  const skeleton = new THREE.Skeleton(bones, boneInverses);
  mesh.add(bones[0]);
  mesh.bind(skeleton);
  mesh.normalizeSkinWeights();
  let weldedVertices = 0;
  const weldedByNode = {};
  const connectBreakdown = {};
  connectConfigs.forEach((config, nodeId) => {
    const total = config.stats.childVertices + config.stats.parentVertices;
    if (total > 0) {
      weldedVertices += total;
      weldedByNode[nodeId] = total;
      connectBreakdown[nodeId] = {
        childVertices: config.stats.childVertices,
        parentVertices: config.stats.parentVertices
      };
    }
  });
  const dispose = () => {
    mesh.geometry.dispose();
    const mat = mesh.material;
    if (Array.isArray(mat)) {
      mat.forEach((entry) => entry.dispose?.());
    } else {
      mat.dispose?.();
    }
  };
  return {
    mesh,
    bones,
    skeleton,
    boneMap,
    stats: {
      vertices: positions.length / 3,
      triangles: positions.length / 9,
      weldedVertices,
      weldedByNode,
      connectBreakdown,
      atlas: colorAtlas ? { width: colorAtlas.width, height: colorAtlas.height } : null
    },
    warnings,
    dispose
  };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  buildEntitySkinnedMesh
});
