@mml-io/3d-web-avatar 0.0.0-experimental-4fa4c42-20250715 → 0.0.0-experimental-1111b42-20250721

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2023 Improbable MV Limited
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -25,4 +25,4 @@ export type MMLCharacterDescription = {
25
25
  parts: MMLCharacterDescriptionPart[];
26
26
  };
27
27
  export type LoadingErrors = string[];
28
- export declare const parseMMLDescription: (mmlDescription: string) => [MMLCharacterDescription, LoadingErrors];
28
+ export declare const parseMMLDescription: (mmlDescription: string, mmlCharacterUrl: string | null) => [MMLCharacterDescription, LoadingErrors];
package/build/index.js CHANGED
@@ -159,7 +159,7 @@ function cloneSkinnedMesh(model) {
159
159
  }
160
160
 
161
161
  // src/helpers/parseMMLDescription.ts
162
- var parseMMLDescription = (mmlDescription) => {
162
+ var parseMMLDescription = (mmlDescription, mmlCharacterUrl) => {
163
163
  const parser = new DOMParser();
164
164
  const doc = parser.parseFromString(mmlDescription, "text/html");
165
165
  const tag = (count) => {
@@ -199,13 +199,19 @@ var parseMMLDescription = (mmlDescription) => {
199
199
  let base = { url: "" };
200
200
  let parts = [];
201
201
  if (validCharacter) {
202
- const baseSrc = validCharacter.getAttribute("src") ?? "";
202
+ let baseSrc = validCharacter.getAttribute("src") ?? "";
203
+ if (mmlCharacterUrl) {
204
+ baseSrc = new URL(baseSrc, mmlCharacterUrl).toString();
205
+ }
203
206
  base = { url: baseSrc };
204
207
  const directModelChildren = Array.from(validCharacter.children).filter(
205
208
  (child) => child.tagName.toLowerCase() === "m-model"
206
209
  );
207
210
  parts = directModelChildren.map((model) => {
208
- const partSrc = model.getAttribute("src") ?? "";
211
+ let partSrc = model.getAttribute("src") ?? "";
212
+ if (mmlCharacterUrl) {
213
+ partSrc = new URL(partSrc, mmlCharacterUrl).toString();
214
+ }
209
215
  const socketAttr = model.getAttribute("socket");
210
216
  const position = {
211
217
  x: parseFloat(model.getAttribute("x") ?? "0") || 0,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/character/MMLCharacter.ts", "../src/helpers/cloneSkinnedMesh.ts", "../src/helpers/parseMMLDescription.ts", "../src/helpers/createMMLCharacterString.ts"],
4
- "sourcesContent": ["import { ModelLoadResult } from \"@mml-io/model-loader\";\nimport { Bone, Group, MathUtils, Object3D, Skeleton, SkinnedMesh, Sphere, Vector3 } from \"three\";\n\nimport { MMLCharacterDescriptionPart } from \"../helpers/parseMMLDescription\";\n\ntype MMLCharacterModelLoader = {\n load: (url: string, abortController?: AbortController) => Promise<ModelLoadResult | null>;\n};\n\nexport class MMLCharacter {\n constructor(private modelLoader: MMLCharacterModelLoader) {}\n\n public static load(\n fullBodyURL: string,\n bodyParts: Array<MMLCharacterDescriptionPart>,\n modelLoader: MMLCharacterModelLoader,\n abortController?: AbortController,\n ): Promise<Object3D | null> {\n const mmlCharacter = new MMLCharacter(modelLoader);\n return mmlCharacter.load(fullBodyURL, bodyParts, abortController);\n }\n\n private createBoneIndexMap(\n originSkeleton: Skeleton,\n targetSkeleton: Skeleton,\n ): Map<number, number> {\n const boneIndexMap = new Map<number, number>();\n\n for (let i = 0; i < originSkeleton.bones.length; i++) {\n const originBone = originSkeleton.bones[i];\n const targetBone = targetSkeleton.bones.find((bone) => bone.name === originBone.name);\n if (targetBone) {\n boneIndexMap.set(i, targetSkeleton.bones.indexOf(targetBone));\n }\n }\n return boneIndexMap;\n }\n\n private remapBoneIndices(skinnedMesh: SkinnedMesh, targetSkeleton: Skeleton): void {\n const originSkeleton = skinnedMesh.skeleton;\n const originGeometry = skinnedMesh.geometry;\n\n const boneIndexMap = this.createBoneIndexMap(originSkeleton, targetSkeleton);\n\n const missingBoneIndices = new Set();\n\n const skinIndexAttribute = originGeometry.attributes.skinIndex;\n for (let i = 0; i < skinIndexAttribute.count; i++) {\n const originIndex = skinIndexAttribute.getComponent(i, 0);\n const targetIndex = boneIndexMap.get(originIndex);\n if (targetIndex !== undefined) {\n skinIndexAttribute.setComponent(i, 0, targetIndex);\n } else {\n missingBoneIndices.add(originIndex);\n }\n }\n\n if (missingBoneIndices.size > 0) {\n console.warn(\n `Missing bone indices in skinIndex attribute: ${Array.from(missingBoneIndices).join(\", \")}`,\n );\n }\n }\n\n public async load(\n fullBodyURL: string,\n bodyParts: Array<MMLCharacterDescriptionPart>,\n abortController?: AbortController,\n ): Promise<Object3D | null> {\n const group = new Group();\n\n const fullBodyAssetPromise = this.modelLoader.load(fullBodyURL, abortController);\n\n const assetPromises: Array<\n Promise<{ asset: ModelLoadResult; part: MMLCharacterDescriptionPart } | null>\n > = bodyParts.map((part) => {\n return new Promise((resolve) => {\n this.modelLoader.load(part.url, abortController).then((asset: ModelLoadResult | null) => {\n if (!asset) {\n resolve(null);\n return;\n }\n resolve({ asset, part });\n });\n });\n });\n\n const fullBodyAsset = await fullBodyAssetPromise;\n if (abortController?.signal.aborted) {\n return null;\n }\n if (!fullBodyAsset) {\n return null;\n }\n const assets = await Promise.all(assetPromises);\n if (abortController?.signal.aborted) {\n return null;\n }\n\n const rawBodyGltf = fullBodyAsset.group;\n const availableBones = new Map<string, Bone>();\n rawBodyGltf.traverse((child) => {\n const asBone = child as Bone;\n if (asBone.isBone) {\n availableBones.set(child.name, asBone);\n }\n\n const asSkinnedMesh = child as SkinnedMesh;\n if (asSkinnedMesh.isSkinnedMesh) {\n asSkinnedMesh.castShadow = true;\n asSkinnedMesh.receiveShadow = true;\n }\n });\n const foundSkinnedMeshes: Array<SkinnedMesh> = [];\n rawBodyGltf.traverse((child) => {\n const asSkinnedMesh = child as SkinnedMesh;\n if (asSkinnedMesh.isSkinnedMesh) {\n foundSkinnedMeshes.push(asSkinnedMesh);\n // Set a default bounding sphere for skinned meshes to avoid costly calculations for frustrum culling\n asSkinnedMesh.boundingSphere = new Sphere(new Vector3(), 3);\n }\n });\n\n if (foundSkinnedMeshes.length === 0) {\n throw new Error(\"No skinned mesh in base model file\");\n }\n if (foundSkinnedMeshes.length > 1) {\n console.warn(\n \"Multiple skinned meshes in base model file. Expected 1. Using first for skeleton.\",\n );\n }\n const skinnedMesh = foundSkinnedMeshes[0];\n group.add(...foundSkinnedMeshes);\n const sharedSkeleton = skinnedMesh.skeleton;\n group.add(skinnedMesh.skeleton.bones[0]);\n const sharedMatrixWorld = skinnedMesh.matrixWorld;\n\n for (const loadingAsset of assets) {\n if (loadingAsset) {\n const part = loadingAsset.part;\n const rawGltf = loadingAsset.asset;\n\n const modelGroup = rawGltf.group;\n if (part.socket) {\n const socketName = part.socket.socket;\n let bone = availableBones.get(\"root\");\n if (availableBones.has(socketName)) {\n bone = availableBones.get(socketName);\n } else {\n console.warn(\n `WARNING: no bone found for [${socketName}] socket. Attatching to Root bone`,\n );\n }\n if (bone) {\n bone.add(modelGroup);\n\n modelGroup.position.set(\n part.socket.position.x,\n part.socket.position.y,\n part.socket.position.z,\n );\n\n modelGroup.rotation.set(\n MathUtils.degToRad(part.socket.rotation.x),\n MathUtils.degToRad(part.socket.rotation.y),\n MathUtils.degToRad(part.socket.rotation.z),\n );\n\n modelGroup.scale.set(part.socket.scale.x, part.socket.scale.y, part.socket.scale.z);\n }\n } else {\n const skinnedMeshes: Array<SkinnedMesh> = [];\n modelGroup.traverse((child) => {\n const asSkinnedMesh = child as SkinnedMesh;\n if (asSkinnedMesh.isSkinnedMesh) {\n skinnedMeshes.push(asSkinnedMesh);\n // Set a default bounding sphere for skinned meshes to avoid costly calculations for frustrum culling\n asSkinnedMesh.boundingSphere = new Sphere(new Vector3(), 3);\n }\n });\n for (const skinnedMeshPart of skinnedMeshes) {\n this.remapBoneIndices(skinnedMeshPart, sharedSkeleton);\n skinnedMeshPart.castShadow = true;\n skinnedMeshPart.receiveShadow = true;\n skinnedMeshPart.bind(sharedSkeleton, sharedMatrixWorld!);\n skinnedMeshPart.children = [];\n group.add(skinnedMeshPart);\n }\n }\n }\n }\n return group;\n }\n}\n", "import { Group } from \"three\";\nimport * as SkeletonUtils from \"three/examples/jsm/utils/SkeletonUtils.js\";\n\nexport function cloneSkinnedMesh(model: Group) {\n return SkeletonUtils.clone(model);\n}\n", "export type MMLCharacterDescriptionPart = {\n url: string;\n type?: string;\n socket?: {\n socket: string;\n position: { x: number; y: number; z: number };\n scale: { x: number; y: number; z: number };\n rotation: { x: number; y: number; z: number };\n };\n};\n\nexport type MMLCharacterDescription = {\n base: MMLCharacterDescriptionPart;\n parts: MMLCharacterDescriptionPart[];\n};\n\nexport type LoadingErrors = string[];\n\nexport const parseMMLDescription = (\n mmlDescription: string,\n): [MMLCharacterDescription, LoadingErrors] => {\n const parser: DOMParser = new DOMParser();\n const doc = parser.parseFromString(mmlDescription, \"text/html\");\n\n const tag = (count: number) => {\n return count > 1 ? \"tags\" : \"tag\";\n };\n\n const errors: string[] = [];\n\n const warn = (errorMessage: string) => {\n errors.push(errorMessage);\n console.warn(errorMessage);\n };\n\n const characters = Array.from(doc.body.children).filter(\n (child) => child.tagName.toLowerCase() === \"m-character\",\n );\n const validCharacter = characters.shift();\n\n if (characters.length > 0) {\n const tagStr = tag(characters.length);\n warn(\n `ignoring ${characters.length} extra <m-character> ${tagStr} found in the root of the document (only the first one is valid).`,\n );\n }\n\n const nestedCharacters = doc.querySelectorAll(\"body * m-character\");\n if (nestedCharacters.length > 0) {\n const tagStr = tag(nestedCharacters.length);\n warn(\n `ignoring ${nestedCharacters.length} nested <m-character> ${tagStr} found within other tags. A valid <m-character> tag must be at the root of the document.`,\n );\n }\n\n const rootModels = Array.from(doc.body.children).filter(\n (child) => child.tagName.toLowerCase() === \"m-model\",\n );\n if (rootModels.length > 0) {\n const tagStr = tag(rootModels.length);\n warn(\n `ignoring ${rootModels.length} <m-model> ${tagStr} were found at the root of the document (<m-model> tags must be children of a valid <m-character> tag).`,\n );\n }\n\n let base: MMLCharacterDescriptionPart = { url: \"\" };\n let parts: MMLCharacterDescriptionPart[] = [];\n\n if (validCharacter) {\n const baseSrc = validCharacter.getAttribute(\"src\") ?? \"\";\n base = { url: baseSrc };\n\n const directModelChildren = Array.from(validCharacter.children).filter(\n (child) => child.tagName.toLowerCase() === \"m-model\",\n );\n parts = directModelChildren.map((model) => {\n const partSrc = model.getAttribute(\"src\") ?? \"\";\n\n const socketAttr = model.getAttribute(\"socket\");\n const position = {\n x: parseFloat(model.getAttribute(\"x\") ?? \"0\") || 0,\n y: parseFloat(model.getAttribute(\"y\") ?? \"0\") || 0,\n z: parseFloat(model.getAttribute(\"z\") ?? \"0\") || 0,\n };\n const scale = {\n x: parseFloat(model.getAttribute(\"sx\") ?? \"1\") || 1,\n y: parseFloat(model.getAttribute(\"sy\") ?? \"1\") || 1,\n z: parseFloat(model.getAttribute(\"sz\") ?? \"1\") || 1,\n };\n const rotation = {\n x: parseFloat(model.getAttribute(\"rx\") ?? \"0\") || 0,\n y: parseFloat(model.getAttribute(\"ry\") ?? \"0\") || 0,\n z: parseFloat(model.getAttribute(\"rz\") ?? \"0\") || 0,\n };\n\n const socketObj = socketAttr ? { socket: socketAttr, position, scale, rotation } : undefined;\n\n return { url: partSrc, socket: socketObj };\n });\n\n const wrappedModelTags = Array.from(doc.querySelectorAll(\"m-character m-model\")).filter(\n (model) => !directModelChildren.includes(model),\n );\n if (wrappedModelTags.length > 0) {\n const tagStr = tag(wrappedModelTags.length);\n warn(\n `ignoring ${wrappedModelTags.length} <m-model> ${tagStr} that were found wrapped inside tags other than a valid <m-character> tag.`,\n );\n }\n } else {\n warn(`No valid <m-character> tag was found in the provided document.`);\n }\n\n const characterDescription: MMLCharacterDescription = {\n base: base,\n parts: parts,\n };\n\n return [characterDescription, errors];\n};\n", "import { MMLCharacterDescription } from \"./parseMMLDescription\";\n\nexport const createMMLCharacterString = (characterDescription: MMLCharacterDescription): string => {\n const base = characterDescription.base.url;\n\n const partsTags = characterDescription.parts.map(\n (part) => `<m-model src=\"${part.url}\"${part.type ? ` type=\"${part.type}\"` : \"\"}></m-model>`,\n );\n\n return `<m-character src=\"${base}\">\n ${partsTags.join(\"\\n \")}\n</m-character>`;\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { ModelLoadResult } from \"@mml-io/model-loader\";\nimport { Bone, Group, MathUtils, Object3D, Skeleton, SkinnedMesh, Sphere, Vector3 } from \"three\";\n\nimport { MMLCharacterDescriptionPart } from \"../helpers/parseMMLDescription\";\n\ntype MMLCharacterModelLoader = {\n load: (url: string, abortController?: AbortController) => Promise<ModelLoadResult | null>;\n};\n\nexport class MMLCharacter {\n constructor(private modelLoader: MMLCharacterModelLoader) {}\n\n public static load(\n fullBodyURL: string,\n bodyParts: Array<MMLCharacterDescriptionPart>,\n modelLoader: MMLCharacterModelLoader,\n abortController?: AbortController,\n ): Promise<Object3D | null> {\n const mmlCharacter = new MMLCharacter(modelLoader);\n return mmlCharacter.load(fullBodyURL, bodyParts, abortController);\n }\n\n private createBoneIndexMap(\n originSkeleton: Skeleton,\n targetSkeleton: Skeleton,\n ): Map<number, number> {\n const boneIndexMap = new Map<number, number>();\n\n for (let i = 0; i < originSkeleton.bones.length; i++) {\n const originBone = originSkeleton.bones[i];\n const targetBone = targetSkeleton.bones.find((bone) => bone.name === originBone.name);\n if (targetBone) {\n boneIndexMap.set(i, targetSkeleton.bones.indexOf(targetBone));\n }\n }\n return boneIndexMap;\n }\n\n private remapBoneIndices(skinnedMesh: SkinnedMesh, targetSkeleton: Skeleton): void {\n const originSkeleton = skinnedMesh.skeleton;\n const originGeometry = skinnedMesh.geometry;\n\n const boneIndexMap = this.createBoneIndexMap(originSkeleton, targetSkeleton);\n\n const missingBoneIndices = new Set();\n\n const skinIndexAttribute = originGeometry.attributes.skinIndex;\n for (let i = 0; i < skinIndexAttribute.count; i++) {\n const originIndex = skinIndexAttribute.getComponent(i, 0);\n const targetIndex = boneIndexMap.get(originIndex);\n if (targetIndex !== undefined) {\n skinIndexAttribute.setComponent(i, 0, targetIndex);\n } else {\n missingBoneIndices.add(originIndex);\n }\n }\n\n if (missingBoneIndices.size > 0) {\n console.warn(\n `Missing bone indices in skinIndex attribute: ${Array.from(missingBoneIndices).join(\", \")}`,\n );\n }\n }\n\n public async load(\n fullBodyURL: string,\n bodyParts: Array<MMLCharacterDescriptionPart>,\n abortController?: AbortController,\n ): Promise<Object3D | null> {\n const group = new Group();\n\n const fullBodyAssetPromise = this.modelLoader.load(fullBodyURL, abortController);\n\n const assetPromises: Array<\n Promise<{ asset: ModelLoadResult; part: MMLCharacterDescriptionPart } | null>\n > = bodyParts.map((part) => {\n return new Promise((resolve) => {\n this.modelLoader.load(part.url, abortController).then((asset: ModelLoadResult | null) => {\n if (!asset) {\n resolve(null);\n return;\n }\n resolve({ asset, part });\n });\n });\n });\n\n const fullBodyAsset = await fullBodyAssetPromise;\n if (abortController?.signal.aborted) {\n return null;\n }\n if (!fullBodyAsset) {\n return null;\n }\n const assets = await Promise.all(assetPromises);\n if (abortController?.signal.aborted) {\n return null;\n }\n\n const rawBodyGltf = fullBodyAsset.group;\n const availableBones = new Map<string, Bone>();\n rawBodyGltf.traverse((child) => {\n const asBone = child as Bone;\n if (asBone.isBone) {\n availableBones.set(child.name, asBone);\n }\n\n const asSkinnedMesh = child as SkinnedMesh;\n if (asSkinnedMesh.isSkinnedMesh) {\n asSkinnedMesh.castShadow = true;\n asSkinnedMesh.receiveShadow = true;\n }\n });\n const foundSkinnedMeshes: Array<SkinnedMesh> = [];\n rawBodyGltf.traverse((child) => {\n const asSkinnedMesh = child as SkinnedMesh;\n if (asSkinnedMesh.isSkinnedMesh) {\n foundSkinnedMeshes.push(asSkinnedMesh);\n // Set a default bounding sphere for skinned meshes to avoid costly calculations for frustum culling\n asSkinnedMesh.boundingSphere = new Sphere(new Vector3(), 3);\n }\n });\n\n if (foundSkinnedMeshes.length === 0) {\n throw new Error(\"No skinned mesh in base model file\");\n }\n if (foundSkinnedMeshes.length > 1) {\n console.warn(\n \"Multiple skinned meshes in base model file. Expected 1. Using first for skeleton.\",\n );\n }\n const skinnedMesh = foundSkinnedMeshes[0];\n group.add(...foundSkinnedMeshes);\n const sharedSkeleton = skinnedMesh.skeleton;\n group.add(skinnedMesh.skeleton.bones[0]);\n const sharedMatrixWorld = skinnedMesh.matrixWorld;\n\n for (const loadingAsset of assets) {\n if (loadingAsset) {\n const part = loadingAsset.part;\n const rawGltf = loadingAsset.asset;\n\n const modelGroup = rawGltf.group;\n if (part.socket) {\n const socketName = part.socket.socket;\n let bone = availableBones.get(\"root\");\n if (availableBones.has(socketName)) {\n bone = availableBones.get(socketName);\n } else {\n console.warn(\n `WARNING: no bone found for [${socketName}] socket. Attatching to Root bone`,\n );\n }\n if (bone) {\n bone.add(modelGroup);\n\n modelGroup.position.set(\n part.socket.position.x,\n part.socket.position.y,\n part.socket.position.z,\n );\n\n modelGroup.rotation.set(\n MathUtils.degToRad(part.socket.rotation.x),\n MathUtils.degToRad(part.socket.rotation.y),\n MathUtils.degToRad(part.socket.rotation.z),\n );\n\n modelGroup.scale.set(part.socket.scale.x, part.socket.scale.y, part.socket.scale.z);\n }\n } else {\n const skinnedMeshes: Array<SkinnedMesh> = [];\n modelGroup.traverse((child) => {\n const asSkinnedMesh = child as SkinnedMesh;\n if (asSkinnedMesh.isSkinnedMesh) {\n skinnedMeshes.push(asSkinnedMesh);\n // Set a default bounding sphere for skinned meshes to avoid costly calculations for frustum culling\n asSkinnedMesh.boundingSphere = new Sphere(new Vector3(), 3);\n }\n });\n for (const skinnedMeshPart of skinnedMeshes) {\n this.remapBoneIndices(skinnedMeshPart, sharedSkeleton);\n skinnedMeshPart.castShadow = true;\n skinnedMeshPart.receiveShadow = true;\n skinnedMeshPart.bind(sharedSkeleton, sharedMatrixWorld!);\n skinnedMeshPart.children = [];\n group.add(skinnedMeshPart);\n }\n }\n }\n }\n return group;\n }\n}\n", "import { Group } from \"three\";\nimport * as SkeletonUtils from \"three/examples/jsm/utils/SkeletonUtils.js\";\n\nexport function cloneSkinnedMesh(model: Group) {\n return SkeletonUtils.clone(model);\n}\n", "export type MMLCharacterDescriptionPart = {\n url: string;\n type?: string;\n socket?: {\n socket: string;\n position: { x: number; y: number; z: number };\n scale: { x: number; y: number; z: number };\n rotation: { x: number; y: number; z: number };\n };\n};\n\nexport type MMLCharacterDescription = {\n base: MMLCharacterDescriptionPart;\n parts: MMLCharacterDescriptionPart[];\n};\n\nexport type LoadingErrors = string[];\n\nexport const parseMMLDescription = (\n mmlDescription: string,\n mmlCharacterUrl: string | null,\n): [MMLCharacterDescription, LoadingErrors] => {\n const parser: DOMParser = new DOMParser();\n const doc = parser.parseFromString(mmlDescription, \"text/html\");\n\n const tag = (count: number) => {\n return count > 1 ? \"tags\" : \"tag\";\n };\n\n const errors: string[] = [];\n\n const warn = (errorMessage: string) => {\n errors.push(errorMessage);\n console.warn(errorMessage);\n };\n\n const characters = Array.from(doc.body.children).filter(\n (child) => child.tagName.toLowerCase() === \"m-character\",\n );\n const validCharacter = characters.shift();\n\n if (characters.length > 0) {\n const tagStr = tag(characters.length);\n warn(\n `ignoring ${characters.length} extra <m-character> ${tagStr} found in the root of the document (only the first one is valid).`,\n );\n }\n\n const nestedCharacters = doc.querySelectorAll(\"body * m-character\");\n if (nestedCharacters.length > 0) {\n const tagStr = tag(nestedCharacters.length);\n warn(\n `ignoring ${nestedCharacters.length} nested <m-character> ${tagStr} found within other tags. A valid <m-character> tag must be at the root of the document.`,\n );\n }\n\n const rootModels = Array.from(doc.body.children).filter(\n (child) => child.tagName.toLowerCase() === \"m-model\",\n );\n if (rootModels.length > 0) {\n const tagStr = tag(rootModels.length);\n warn(\n `ignoring ${rootModels.length} <m-model> ${tagStr} were found at the root of the document (<m-model> tags must be children of a valid <m-character> tag).`,\n );\n }\n\n let base: MMLCharacterDescriptionPart = { url: \"\" };\n let parts: MMLCharacterDescriptionPart[] = [];\n\n if (validCharacter) {\n let baseSrc = validCharacter.getAttribute(\"src\") ?? \"\";\n if (mmlCharacterUrl) {\n // Make the baseSrc relative to the mmlCharacterUrl if it's a relative URL\n baseSrc = new URL(baseSrc, mmlCharacterUrl).toString();\n }\n base = { url: baseSrc };\n\n const directModelChildren = Array.from(validCharacter.children).filter(\n (child) => child.tagName.toLowerCase() === \"m-model\",\n );\n parts = directModelChildren.map((model) => {\n let partSrc = model.getAttribute(\"src\") ?? \"\";\n if (mmlCharacterUrl) {\n // Make the partSrc relative to the mmlCharacterUrl if it's a relative URL\n partSrc = new URL(partSrc, mmlCharacterUrl).toString();\n }\n\n const socketAttr = model.getAttribute(\"socket\");\n const position = {\n x: parseFloat(model.getAttribute(\"x\") ?? \"0\") || 0,\n y: parseFloat(model.getAttribute(\"y\") ?? \"0\") || 0,\n z: parseFloat(model.getAttribute(\"z\") ?? \"0\") || 0,\n };\n const scale = {\n x: parseFloat(model.getAttribute(\"sx\") ?? \"1\") || 1,\n y: parseFloat(model.getAttribute(\"sy\") ?? \"1\") || 1,\n z: parseFloat(model.getAttribute(\"sz\") ?? \"1\") || 1,\n };\n const rotation = {\n x: parseFloat(model.getAttribute(\"rx\") ?? \"0\") || 0,\n y: parseFloat(model.getAttribute(\"ry\") ?? \"0\") || 0,\n z: parseFloat(model.getAttribute(\"rz\") ?? \"0\") || 0,\n };\n\n const socketObj = socketAttr ? { socket: socketAttr, position, scale, rotation } : undefined;\n\n return { url: partSrc, socket: socketObj };\n });\n\n const wrappedModelTags = Array.from(doc.querySelectorAll(\"m-character m-model\")).filter(\n (model) => !directModelChildren.includes(model),\n );\n if (wrappedModelTags.length > 0) {\n const tagStr = tag(wrappedModelTags.length);\n warn(\n `ignoring ${wrappedModelTags.length} <m-model> ${tagStr} that were found wrapped inside tags other than a valid <m-character> tag.`,\n );\n }\n } else {\n warn(`No valid <m-character> tag was found in the provided document.`);\n }\n\n const characterDescription: MMLCharacterDescription = {\n base: base,\n parts: parts,\n };\n\n return [characterDescription, errors];\n};\n", "import { MMLCharacterDescription } from \"./parseMMLDescription\";\n\nexport const createMMLCharacterString = (characterDescription: MMLCharacterDescription): string => {\n const base = characterDescription.base.url;\n\n const partsTags = characterDescription.parts.map(\n (part) => `<m-model src=\"${part.url}\"${part.type ? ` type=\"${part.type}\"` : \"\"}></m-model>`,\n );\n\n return `<m-character src=\"${base}\">\n ${partsTags.join(\"\\n \")}\n</m-character>`;\n};\n"],
5
+ "mappings": ";AACA,SAAe,OAAO,WAA4C,QAAQ,eAAe;AAQlF,IAAM,eAAN,MAAM,cAAa;AAAA,EACxB,YAAoB,aAAsC;AAAtC;AAAA,EAAuC;AAAA,EAE3D,OAAc,KACZ,aACA,WACA,aACA,iBAC0B;AAC1B,UAAM,eAAe,IAAI,cAAa,WAAW;AACjD,WAAO,aAAa,KAAK,aAAa,WAAW,eAAe;AAAA,EAClE;AAAA,EAEQ,mBACN,gBACA,gBACqB;AACrB,UAAM,eAAe,oBAAI,IAAoB;AAE7C,aAAS,IAAI,GAAG,IAAI,eAAe,MAAM,QAAQ,KAAK;AACpD,YAAM,aAAa,eAAe,MAAM,CAAC;AACzC,YAAM,aAAa,eAAe,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,WAAW,IAAI;AACpF,UAAI,YAAY;AACd,qBAAa,IAAI,GAAG,eAAe,MAAM,QAAQ,UAAU,CAAC;AAAA,MAC9D;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,iBAAiB,aAA0B,gBAAgC;AACjF,UAAM,iBAAiB,YAAY;AACnC,UAAM,iBAAiB,YAAY;AAEnC,UAAM,eAAe,KAAK,mBAAmB,gBAAgB,cAAc;AAE3E,UAAM,qBAAqB,oBAAI,IAAI;AAEnC,UAAM,qBAAqB,eAAe,WAAW;AACrD,aAAS,IAAI,GAAG,IAAI,mBAAmB,OAAO,KAAK;AACjD,YAAM,cAAc,mBAAmB,aAAa,GAAG,CAAC;AACxD,YAAM,cAAc,aAAa,IAAI,WAAW;AAChD,UAAI,gBAAgB,QAAW;AAC7B,2BAAmB,aAAa,GAAG,GAAG,WAAW;AAAA,MACnD,OAAO;AACL,2BAAmB,IAAI,WAAW;AAAA,MACpC;AAAA,IACF;AAEA,QAAI,mBAAmB,OAAO,GAAG;AAC/B,cAAQ;AAAA,QACN,gDAAgD,MAAM,KAAK,kBAAkB,EAAE,KAAK,IAAI,CAAC;AAAA,MAC3F;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAa,KACX,aACA,WACA,iBAC0B;AAC1B,UAAM,QAAQ,IAAI,MAAM;AAExB,UAAM,uBAAuB,KAAK,YAAY,KAAK,aAAa,eAAe;AAE/E,UAAM,gBAEF,UAAU,IAAI,CAAC,SAAS;AAC1B,aAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,aAAK,YAAY,KAAK,KAAK,KAAK,eAAe,EAAE,KAAK,CAAC,UAAkC;AACvF,cAAI,CAAC,OAAO;AACV,oBAAQ,IAAI;AACZ;AAAA,UACF;AACA,kBAAQ,EAAE,OAAO,KAAK,CAAC;AAAA,QACzB,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAED,UAAM,gBAAgB,MAAM;AAC5B,QAAI,mDAAiB,OAAO,SAAS;AACnC,aAAO;AAAA,IACT;AACA,QAAI,CAAC,eAAe;AAClB,aAAO;AAAA,IACT;AACA,UAAM,SAAS,MAAM,QAAQ,IAAI,aAAa;AAC9C,QAAI,mDAAiB,OAAO,SAAS;AACnC,aAAO;AAAA,IACT;AAEA,UAAM,cAAc,cAAc;AAClC,UAAM,iBAAiB,oBAAI,IAAkB;AAC7C,gBAAY,SAAS,CAAC,UAAU;AAC9B,YAAM,SAAS;AACf,UAAI,OAAO,QAAQ;AACjB,uBAAe,IAAI,MAAM,MAAM,MAAM;AAAA,MACvC;AAEA,YAAM,gBAAgB;AACtB,UAAI,cAAc,eAAe;AAC/B,sBAAc,aAAa;AAC3B,sBAAc,gBAAgB;AAAA,MAChC;AAAA,IACF,CAAC;AACD,UAAM,qBAAyC,CAAC;AAChD,gBAAY,SAAS,CAAC,UAAU;AAC9B,YAAM,gBAAgB;AACtB,UAAI,cAAc,eAAe;AAC/B,2BAAmB,KAAK,aAAa;AAErC,sBAAc,iBAAiB,IAAI,OAAO,IAAI,QAAQ,GAAG,CAAC;AAAA,MAC5D;AAAA,IACF,CAAC;AAED,QAAI,mBAAmB,WAAW,GAAG;AACnC,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,QAAI,mBAAmB,SAAS,GAAG;AACjC,cAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF;AACA,UAAM,cAAc,mBAAmB,CAAC;AACxC,UAAM,IAAI,GAAG,kBAAkB;AAC/B,UAAM,iBAAiB,YAAY;AACnC,UAAM,IAAI,YAAY,SAAS,MAAM,CAAC,CAAC;AACvC,UAAM,oBAAoB,YAAY;AAEtC,eAAW,gBAAgB,QAAQ;AACjC,UAAI,cAAc;AAChB,cAAM,OAAO,aAAa;AAC1B,cAAM,UAAU,aAAa;AAE7B,cAAM,aAAa,QAAQ;AAC3B,YAAI,KAAK,QAAQ;AACf,gBAAM,aAAa,KAAK,OAAO;AAC/B,cAAI,OAAO,eAAe,IAAI,MAAM;AACpC,cAAI,eAAe,IAAI,UAAU,GAAG;AAClC,mBAAO,eAAe,IAAI,UAAU;AAAA,UACtC,OAAO;AACL,oBAAQ;AAAA,cACN,+BAA+B,UAAU;AAAA,YAC3C;AAAA,UACF;AACA,cAAI,MAAM;AACR,iBAAK,IAAI,UAAU;AAEnB,uBAAW,SAAS;AAAA,cAClB,KAAK,OAAO,SAAS;AAAA,cACrB,KAAK,OAAO,SAAS;AAAA,cACrB,KAAK,OAAO,SAAS;AAAA,YACvB;AAEA,uBAAW,SAAS;AAAA,cAClB,UAAU,SAAS,KAAK,OAAO,SAAS,CAAC;AAAA,cACzC,UAAU,SAAS,KAAK,OAAO,SAAS,CAAC;AAAA,cACzC,UAAU,SAAS,KAAK,OAAO,SAAS,CAAC;AAAA,YAC3C;AAEA,uBAAW,MAAM,IAAI,KAAK,OAAO,MAAM,GAAG,KAAK,OAAO,MAAM,GAAG,KAAK,OAAO,MAAM,CAAC;AAAA,UACpF;AAAA,QACF,OAAO;AACL,gBAAM,gBAAoC,CAAC;AAC3C,qBAAW,SAAS,CAAC,UAAU;AAC7B,kBAAM,gBAAgB;AACtB,gBAAI,cAAc,eAAe;AAC/B,4BAAc,KAAK,aAAa;AAEhC,4BAAc,iBAAiB,IAAI,OAAO,IAAI,QAAQ,GAAG,CAAC;AAAA,YAC5D;AAAA,UACF,CAAC;AACD,qBAAW,mBAAmB,eAAe;AAC3C,iBAAK,iBAAiB,iBAAiB,cAAc;AACrD,4BAAgB,aAAa;AAC7B,4BAAgB,gBAAgB;AAChC,4BAAgB,KAAK,gBAAgB,iBAAkB;AACvD,4BAAgB,WAAW,CAAC;AAC5B,kBAAM,IAAI,eAAe;AAAA,UAC3B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;;;AChMA,YAAY,mBAAmB;AAExB,SAAS,iBAAiB,OAAc;AAC7C,SAAqB,oBAAM,KAAK;AAClC;;;ACaO,IAAM,sBAAsB,CACjC,gBACA,oBAC6C;AAC7C,QAAM,SAAoB,IAAI,UAAU;AACxC,QAAM,MAAM,OAAO,gBAAgB,gBAAgB,WAAW;AAE9D,QAAM,MAAM,CAAC,UAAkB;AAC7B,WAAO,QAAQ,IAAI,SAAS;AAAA,EAC9B;AAEA,QAAM,SAAmB,CAAC;AAE1B,QAAM,OAAO,CAAC,iBAAyB;AACrC,WAAO,KAAK,YAAY;AACxB,YAAQ,KAAK,YAAY;AAAA,EAC3B;AAEA,QAAM,aAAa,MAAM,KAAK,IAAI,KAAK,QAAQ,EAAE;AAAA,IAC/C,CAAC,UAAU,MAAM,QAAQ,YAAY,MAAM;AAAA,EAC7C;AACA,QAAM,iBAAiB,WAAW,MAAM;AAExC,MAAI,WAAW,SAAS,GAAG;AACzB,UAAM,SAAS,IAAI,WAAW,MAAM;AACpC;AAAA,MACE,YAAY,WAAW,MAAM,wBAAwB,MAAM;AAAA,IAC7D;AAAA,EACF;AAEA,QAAM,mBAAmB,IAAI,iBAAiB,oBAAoB;AAClE,MAAI,iBAAiB,SAAS,GAAG;AAC/B,UAAM,SAAS,IAAI,iBAAiB,MAAM;AAC1C;AAAA,MACE,YAAY,iBAAiB,MAAM,yBAAyB,MAAM;AAAA,IACpE;AAAA,EACF;AAEA,QAAM,aAAa,MAAM,KAAK,IAAI,KAAK,QAAQ,EAAE;AAAA,IAC/C,CAAC,UAAU,MAAM,QAAQ,YAAY,MAAM;AAAA,EAC7C;AACA,MAAI,WAAW,SAAS,GAAG;AACzB,UAAM,SAAS,IAAI,WAAW,MAAM;AACpC;AAAA,MACE,YAAY,WAAW,MAAM,cAAc,MAAM;AAAA,IACnD;AAAA,EACF;AAEA,MAAI,OAAoC,EAAE,KAAK,GAAG;AAClD,MAAI,QAAuC,CAAC;AAE5C,MAAI,gBAAgB;AAClB,QAAI,UAAU,eAAe,aAAa,KAAK,KAAK;AACpD,QAAI,iBAAiB;AAEnB,gBAAU,IAAI,IAAI,SAAS,eAAe,EAAE,SAAS;AAAA,IACvD;AACA,WAAO,EAAE,KAAK,QAAQ;AAEtB,UAAM,sBAAsB,MAAM,KAAK,eAAe,QAAQ,EAAE;AAAA,MAC9D,CAAC,UAAU,MAAM,QAAQ,YAAY,MAAM;AAAA,IAC7C;AACA,YAAQ,oBAAoB,IAAI,CAAC,UAAU;AACzC,UAAI,UAAU,MAAM,aAAa,KAAK,KAAK;AAC3C,UAAI,iBAAiB;AAEnB,kBAAU,IAAI,IAAI,SAAS,eAAe,EAAE,SAAS;AAAA,MACvD;AAEA,YAAM,aAAa,MAAM,aAAa,QAAQ;AAC9C,YAAM,WAAW;AAAA,QACf,GAAG,WAAW,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK;AAAA,QACjD,GAAG,WAAW,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK;AAAA,QACjD,GAAG,WAAW,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK;AAAA,MACnD;AACA,YAAM,QAAQ;AAAA,QACZ,GAAG,WAAW,MAAM,aAAa,IAAI,KAAK,GAAG,KAAK;AAAA,QAClD,GAAG,WAAW,MAAM,aAAa,IAAI,KAAK,GAAG,KAAK;AAAA,QAClD,GAAG,WAAW,MAAM,aAAa,IAAI,KAAK,GAAG,KAAK;AAAA,MACpD;AACA,YAAM,WAAW;AAAA,QACf,GAAG,WAAW,MAAM,aAAa,IAAI,KAAK,GAAG,KAAK;AAAA,QAClD,GAAG,WAAW,MAAM,aAAa,IAAI,KAAK,GAAG,KAAK;AAAA,QAClD,GAAG,WAAW,MAAM,aAAa,IAAI,KAAK,GAAG,KAAK;AAAA,MACpD;AAEA,YAAM,YAAY,aAAa,EAAE,QAAQ,YAAY,UAAU,OAAO,SAAS,IAAI;AAEnF,aAAO,EAAE,KAAK,SAAS,QAAQ,UAAU;AAAA,IAC3C,CAAC;AAED,UAAM,mBAAmB,MAAM,KAAK,IAAI,iBAAiB,qBAAqB,CAAC,EAAE;AAAA,MAC/E,CAAC,UAAU,CAAC,oBAAoB,SAAS,KAAK;AAAA,IAChD;AACA,QAAI,iBAAiB,SAAS,GAAG;AAC/B,YAAM,SAAS,IAAI,iBAAiB,MAAM;AAC1C;AAAA,QACE,YAAY,iBAAiB,MAAM,cAAc,MAAM;AAAA,MACzD;AAAA,IACF;AAAA,EACF,OAAO;AACL,SAAK,gEAAgE;AAAA,EACvE;AAEA,QAAM,uBAAgD;AAAA,IACpD;AAAA,IACA;AAAA,EACF;AAEA,SAAO,CAAC,sBAAsB,MAAM;AACtC;;;AC9HO,IAAM,2BAA2B,CAAC,yBAA0D;AACjG,QAAM,OAAO,qBAAqB,KAAK;AAEvC,QAAM,YAAY,qBAAqB,MAAM;AAAA,IAC3C,CAAC,SAAS,iBAAiB,KAAK,GAAG,IAAI,KAAK,OAAO,UAAU,KAAK,IAAI,MAAM,EAAE;AAAA,EAChF;AAEA,SAAO,qBAAqB,IAAI;AAAA,IAC9B,UAAU,KAAK,MAAM,CAAC;AAAA;AAE1B;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mml-io/3d-web-avatar",
3
- "version": "0.0.0-experimental-4fa4c42-20250715",
3
+ "version": "0.0.0-experimental-1111b42-20250721",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -21,7 +21,7 @@
21
21
  "test": "NODE_OPTIONS=--experimental-vm-modules jest"
22
22
  },
23
23
  "dependencies": {
24
- "@mml-io/model-loader": "0.0.0-experimental-b41f621-20250714",
24
+ "@mml-io/model-loader": "0.20.0",
25
25
  "react": "^19.0.0",
26
26
  "three": "0.178.0"
27
27
  },
@@ -33,5 +33,6 @@
33
33
  "jest-environment-jsdom": "29.7.0",
34
34
  "jest-junit": "16.0.0",
35
35
  "ts-jest": "^29.1.5"
36
- }
36
+ },
37
+ "gitHead": "6715c1d4febf4efa299fb472060b1d1855306302"
37
38
  }