@mml-io/3d-web-avatar 0.0.0-experimental-c32c620-20250626 → 0.0.0-experimental-3a2278c-20250715
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/build/character/MMLCharacter.d.ts +3 -2
- package/build/index.js +66 -49
- package/build/index.js.map +2 -2
- package/package.json +11 -10
- package/LICENSE +0 -19
@@ -2,13 +2,14 @@ import { ModelLoadResult } from "@mml-io/model-loader";
|
|
2
2
|
import { Object3D } from "three";
|
3
3
|
import { MMLCharacterDescriptionPart } from "../helpers/parseMMLDescription";
|
4
4
|
type MMLCharacterModelLoader = {
|
5
|
-
load: (url: string) => Promise<ModelLoadResult>;
|
5
|
+
load: (url: string, abortController?: AbortController) => Promise<ModelLoadResult | null>;
|
6
6
|
};
|
7
7
|
export declare class MMLCharacter {
|
8
8
|
private modelLoader;
|
9
9
|
constructor(modelLoader: MMLCharacterModelLoader);
|
10
|
+
static load(fullBodyURL: string, bodyParts: Array<MMLCharacterDescriptionPart>, modelLoader: MMLCharacterModelLoader, abortController?: AbortController): Promise<Object3D | null>;
|
10
11
|
private createBoneIndexMap;
|
11
12
|
private remapBoneIndices;
|
12
|
-
|
13
|
+
load(fullBodyURL: string, bodyParts: Array<MMLCharacterDescriptionPart>, abortController?: AbortController): Promise<Object3D | null>;
|
13
14
|
}
|
14
15
|
export {};
|
package/build/index.js
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
// src/character/MMLCharacter.ts
|
2
|
-
import {
|
3
|
-
|
4
|
-
MathUtils
|
5
|
-
} from "three";
|
6
|
-
var MMLCharacter = class {
|
2
|
+
import { Group, MathUtils, Sphere, Vector3 } from "three";
|
3
|
+
var MMLCharacter = class _MMLCharacter {
|
7
4
|
constructor(modelLoader) {
|
8
5
|
this.modelLoader = modelLoader;
|
9
6
|
}
|
7
|
+
static load(fullBodyURL, bodyParts, modelLoader, abortController) {
|
8
|
+
const mmlCharacter = new _MMLCharacter(modelLoader);
|
9
|
+
return mmlCharacter.load(fullBodyURL, bodyParts, abortController);
|
10
|
+
}
|
10
11
|
createBoneIndexMap(originSkeleton, targetSkeleton) {
|
11
12
|
const boneIndexMap = /* @__PURE__ */ new Map();
|
12
13
|
for (let i = 0; i < originSkeleton.bones.length; i++) {
|
@@ -22,7 +23,6 @@ var MMLCharacter = class {
|
|
22
23
|
const originSkeleton = skinnedMesh.skeleton;
|
23
24
|
const originGeometry = skinnedMesh.geometry;
|
24
25
|
const boneIndexMap = this.createBoneIndexMap(originSkeleton, targetSkeleton);
|
25
|
-
const newSkinIndexArray = [];
|
26
26
|
const missingBoneIndices = /* @__PURE__ */ new Set();
|
27
27
|
const skinIndexAttribute = originGeometry.attributes.skinIndex;
|
28
28
|
for (let i = 0; i < skinIndexAttribute.count; i++) {
|
@@ -40,18 +40,31 @@ var MMLCharacter = class {
|
|
40
40
|
);
|
41
41
|
}
|
42
42
|
}
|
43
|
-
async
|
43
|
+
async load(fullBodyURL, bodyParts, abortController) {
|
44
44
|
const group = new Group();
|
45
|
-
const fullBodyAssetPromise = this.modelLoader.load(fullBodyURL);
|
45
|
+
const fullBodyAssetPromise = this.modelLoader.load(fullBodyURL, abortController);
|
46
46
|
const assetPromises = bodyParts.map((part) => {
|
47
47
|
return new Promise((resolve) => {
|
48
|
-
this.modelLoader.load(part.url).then((asset) => {
|
48
|
+
this.modelLoader.load(part.url, abortController).then((asset) => {
|
49
|
+
if (!asset) {
|
50
|
+
resolve(null);
|
51
|
+
return;
|
52
|
+
}
|
49
53
|
resolve({ asset, part });
|
50
54
|
});
|
51
55
|
});
|
52
56
|
});
|
53
57
|
const fullBodyAsset = await fullBodyAssetPromise;
|
58
|
+
if (abortController == null ? void 0 : abortController.signal.aborted) {
|
59
|
+
return null;
|
60
|
+
}
|
61
|
+
if (!fullBodyAsset) {
|
62
|
+
return null;
|
63
|
+
}
|
54
64
|
const assets = await Promise.all(assetPromises);
|
65
|
+
if (abortController == null ? void 0 : abortController.signal.aborted) {
|
66
|
+
return null;
|
67
|
+
}
|
55
68
|
const rawBodyGltf = fullBodyAsset.group;
|
56
69
|
const availableBones = /* @__PURE__ */ new Map();
|
57
70
|
rawBodyGltf.traverse((child) => {
|
@@ -70,6 +83,7 @@ var MMLCharacter = class {
|
|
70
83
|
const asSkinnedMesh = child;
|
71
84
|
if (asSkinnedMesh.isSkinnedMesh) {
|
72
85
|
foundSkinnedMeshes.push(asSkinnedMesh);
|
86
|
+
asSkinnedMesh.boundingSphere = new Sphere(new Vector3(), 3);
|
73
87
|
}
|
74
88
|
});
|
75
89
|
if (foundSkinnedMeshes.length === 0) {
|
@@ -86,48 +100,51 @@ var MMLCharacter = class {
|
|
86
100
|
group.add(skinnedMesh.skeleton.bones[0]);
|
87
101
|
const sharedMatrixWorld = skinnedMesh.matrixWorld;
|
88
102
|
for (const loadingAsset of assets) {
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
103
|
+
if (loadingAsset) {
|
104
|
+
const part = loadingAsset.part;
|
105
|
+
const rawGltf = loadingAsset.asset;
|
106
|
+
const modelGroup = rawGltf.group;
|
107
|
+
if (part.socket) {
|
108
|
+
const socketName = part.socket.socket;
|
109
|
+
let bone = availableBones.get("root");
|
110
|
+
if (availableBones.has(socketName)) {
|
111
|
+
bone = availableBones.get(socketName);
|
112
|
+
} else {
|
113
|
+
console.warn(
|
114
|
+
`WARNING: no bone found for [${socketName}] socket. Attatching to Root bone`
|
115
|
+
);
|
116
|
+
}
|
117
|
+
if (bone) {
|
118
|
+
bone.add(modelGroup);
|
119
|
+
modelGroup.position.set(
|
120
|
+
part.socket.position.x,
|
121
|
+
part.socket.position.y,
|
122
|
+
part.socket.position.z
|
123
|
+
);
|
124
|
+
modelGroup.rotation.set(
|
125
|
+
MathUtils.degToRad(part.socket.rotation.x),
|
126
|
+
MathUtils.degToRad(part.socket.rotation.y),
|
127
|
+
MathUtils.degToRad(part.socket.rotation.z)
|
128
|
+
);
|
129
|
+
modelGroup.scale.set(part.socket.scale.x, part.socket.scale.y, part.socket.scale.z);
|
130
|
+
}
|
97
131
|
} else {
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
);
|
114
|
-
modelGroup.scale.set(part.socket.scale.x, part.socket.scale.y, part.socket.scale.z);
|
115
|
-
}
|
116
|
-
} else {
|
117
|
-
const skinnedMeshes = [];
|
118
|
-
modelGroup.traverse((child) => {
|
119
|
-
const asSkinnedMesh = child;
|
120
|
-
if (asSkinnedMesh.isSkinnedMesh) {
|
121
|
-
skinnedMeshes.push(asSkinnedMesh);
|
132
|
+
const skinnedMeshes = [];
|
133
|
+
modelGroup.traverse((child) => {
|
134
|
+
const asSkinnedMesh = child;
|
135
|
+
if (asSkinnedMesh.isSkinnedMesh) {
|
136
|
+
skinnedMeshes.push(asSkinnedMesh);
|
137
|
+
asSkinnedMesh.boundingSphere = new Sphere(new Vector3(), 3);
|
138
|
+
}
|
139
|
+
});
|
140
|
+
for (const skinnedMeshPart of skinnedMeshes) {
|
141
|
+
this.remapBoneIndices(skinnedMeshPart, sharedSkeleton);
|
142
|
+
skinnedMeshPart.castShadow = true;
|
143
|
+
skinnedMeshPart.receiveShadow = true;
|
144
|
+
skinnedMeshPart.bind(sharedSkeleton, sharedMatrixWorld);
|
145
|
+
skinnedMeshPart.children = [];
|
146
|
+
group.add(skinnedMeshPart);
|
122
147
|
}
|
123
|
-
});
|
124
|
-
for (const skinnedMeshPart of skinnedMeshes) {
|
125
|
-
this.remapBoneIndices(skinnedMeshPart, sharedSkeleton);
|
126
|
-
skinnedMeshPart.castShadow = true;
|
127
|
-
skinnedMeshPart.receiveShadow = true;
|
128
|
-
skinnedMeshPart.bind(sharedSkeleton, sharedMatrixWorld);
|
129
|
-
skinnedMeshPart.children = [];
|
130
|
-
group.add(skinnedMeshPart);
|
131
148
|
}
|
132
149
|
}
|
133
150
|
}
|
package/build/index.js.map
CHANGED
@@ -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 {\n Bone,\n BufferAttribute,\n Group,\n InterleavedBufferAttribute,\n MathUtils,\n Object3D,\n Skeleton,\n SkinnedMesh,\n} from \"three\";\n\nimport { MMLCharacterDescriptionPart } from \"../helpers/parseMMLDescription\";\n\ntype MMLCharacterModelLoader = {\n load: (url: string) => Promise<ModelLoadResult>;\n};\n\nexport class MMLCharacter {\n constructor(private modelLoader: MMLCharacterModelLoader) {}\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 newSkinIndexArray = [];\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 mergeBodyParts(\n fullBodyURL: string,\n bodyParts: Array<MMLCharacterDescriptionPart>,\n ): Promise<Object3D> {\n const group = new Group();\n\n const fullBodyAssetPromise = this.modelLoader.load(fullBodyURL);\n\n const assetPromises: Array<\n Promise<{ asset: ModelLoadResult; part: MMLCharacterDescriptionPart }>\n > = bodyParts.map((part) => {\n return new Promise((resolve) => {\n this.modelLoader.load(part.url).then((asset) => {\n resolve({ asset, part });\n });\n });\n });\n\n const fullBodyAsset = await fullBodyAssetPromise;\n const assets = await Promise.all(assetPromises);\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 }\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 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 }\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 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": ";AACA
|
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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",
|
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-
|
3
|
+
"version": "0.0.0-experimental-3a2278c-20250715",
|
4
4
|
"publishConfig": {
|
5
5
|
"access": "public"
|
6
6
|
},
|
@@ -11,6 +11,7 @@
|
|
11
11
|
"/build"
|
12
12
|
],
|
13
13
|
"scripts": {
|
14
|
+
"depcheck": "depcheck --quiet",
|
14
15
|
"build": "tsx ./build.ts --build",
|
15
16
|
"iterate": "tsx ./build.ts --watch",
|
16
17
|
"start": "cross-env NODE_ENV=production node build/index.js 2>error.log",
|
@@ -20,17 +21,17 @@
|
|
20
21
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
|
21
22
|
},
|
22
23
|
"dependencies": {
|
23
|
-
"@mml-io/model-loader": "0.
|
24
|
+
"@mml-io/model-loader": "0.0.0-experimental-b41f621-20250714",
|
24
25
|
"react": "^19.0.0",
|
25
|
-
"
|
26
|
-
"three": "0.163.0"
|
26
|
+
"three": "0.178.0"
|
27
27
|
},
|
28
28
|
"devDependencies": {
|
29
|
+
"@types/jest": "^29.5.12",
|
29
30
|
"@types/node": "^22.13.1",
|
30
|
-
"@types/
|
31
|
-
"
|
32
|
-
"
|
33
|
-
"
|
34
|
-
|
35
|
-
|
31
|
+
"@types/three": "0.178.0",
|
32
|
+
"esbuild-css-modules-plugin": "3.1.4",
|
33
|
+
"jest-environment-jsdom": "29.7.0",
|
34
|
+
"jest-junit": "16.0.0",
|
35
|
+
"ts-jest": "^29.1.5"
|
36
|
+
}
|
36
37
|
}
|
package/LICENSE
DELETED
@@ -1,19 +0,0 @@
|
|
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.
|