talking-head-studio 0.4.10 → 0.4.12

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.
Files changed (178) hide show
  1. package/README.md +299 -337
  2. package/dist/TalkingHead.d.ts +44 -28
  3. package/dist/TalkingHead.js +21 -2
  4. package/dist/TalkingHead.web.d.ts +37 -4
  5. package/dist/TalkingHead.web.js +28 -8
  6. package/dist/TalkingHeadVisualization.d.ts +22 -0
  7. package/dist/TalkingHeadVisualization.js +30 -10
  8. package/dist/api/studioApi.d.ts +12 -1
  9. package/dist/api/studioApi.js +41 -28
  10. package/dist/appearance/apply.js +2 -3
  11. package/dist/appearance/matchers.js +1 -2
  12. package/dist/appearance/schema.js +1 -2
  13. package/dist/contract.d.ts +14 -0
  14. package/dist/contract.js +30 -0
  15. package/dist/core/avatar/avatarCapabilities.d.ts +60 -0
  16. package/dist/core/avatar/avatarCapabilities.js +100 -0
  17. package/dist/core/avatar/backend.d.ts +130 -0
  18. package/dist/core/avatar/backend.js +4 -0
  19. package/dist/core/avatar/backends/gaussian.d.ts +49 -0
  20. package/dist/core/avatar/backends/gaussian.js +293 -0
  21. package/dist/core/avatar/backends/index.d.ts +3 -0
  22. package/dist/core/avatar/backends/index.js +7 -0
  23. package/dist/core/avatar/backends/morphTarget.d.ts +39 -0
  24. package/dist/core/avatar/backends/morphTarget.js +179 -0
  25. package/dist/core/avatar/faceControls.d.ts +40 -0
  26. package/dist/core/avatar/faceControls.js +138 -0
  27. package/dist/core/avatar/motion.d.ts +1713 -0
  28. package/dist/core/avatar/motion.js +550 -0
  29. package/dist/core/avatar/motionRuntime.d.ts +46 -0
  30. package/dist/core/avatar/motionRuntime.js +84 -0
  31. package/dist/core/avatar/schema.d.ts +78 -0
  32. package/dist/core/avatar/schema.js +134 -0
  33. package/dist/core/avatar/visemes.d.ts +47 -1
  34. package/dist/core/avatar/visemes.js +114 -1
  35. package/dist/editor/AvatarCanvas.js +93 -3
  36. package/dist/editor/AvatarEditor.native.js +19 -9
  37. package/dist/editor/AvatarModel.js +2 -2
  38. package/dist/editor/FaceSqueezeEditor.d.ts +3 -1
  39. package/dist/editor/FaceSqueezeEditor.js +195 -121
  40. package/dist/editor/FaceSqueezeEditor.web.d.ts +3 -1
  41. package/dist/editor/FaceSqueezeEditor.web.js +32 -30
  42. package/dist/editor/RigidAccessory.js +18 -4
  43. package/dist/editor/SkinnedClothing.js +19 -9
  44. package/dist/editor/boneLockedDrag.d.ts +11 -0
  45. package/dist/editor/boneLockedDrag.js +68 -0
  46. package/dist/editor/boneSnap.js +22 -12
  47. package/dist/editor/boneSnap.web.d.ts +27 -0
  48. package/dist/editor/boneSnap.web.js +99 -0
  49. package/dist/editor/index.web.d.ts +10 -0
  50. package/dist/editor/index.web.js +26 -0
  51. package/dist/editor/sounds/haha.wav +0 -0
  52. package/dist/editor/sounds/owie.wav +0 -0
  53. package/dist/editor/sounds/stop.wav +0 -0
  54. package/dist/editor/studioTheme.d.ts +14 -14
  55. package/dist/editor/studioTheme.js +19 -16
  56. package/dist/editor/types.d.ts +1 -0
  57. package/dist/html/accessories.d.ts +7 -0
  58. package/dist/html/accessories.js +149 -0
  59. package/dist/html/motion.d.ts +1 -0
  60. package/dist/html/motion.js +189 -0
  61. package/dist/html/visemes.d.ts +7 -0
  62. package/dist/html/visemes.js +348 -0
  63. package/dist/html.d.ts +1 -1
  64. package/dist/html.js +56 -734
  65. package/dist/index.d.ts +19 -1
  66. package/dist/index.js +44 -5
  67. package/dist/index.web.d.ts +18 -1
  68. package/dist/index.web.js +36 -3
  69. package/dist/platform/api/types.d.ts +10 -0
  70. package/dist/platform/api/types.js +2 -0
  71. package/dist/platform/marketplace/types.d.ts +32 -0
  72. package/dist/platform/marketplace/types.js +2 -0
  73. package/dist/platform/sdk/unity.d.ts +27 -0
  74. package/dist/platform/sdk/unity.js +2 -0
  75. package/dist/platform/sdk/unreal.d.ts +23 -0
  76. package/dist/platform/sdk/unreal.js +2 -0
  77. package/dist/platform/sdk/web.d.ts +16 -0
  78. package/dist/platform/sdk/web.js +2 -0
  79. package/dist/sketchfab/api.js +5 -5
  80. package/dist/sketchfab/glbInspect.d.ts +22 -0
  81. package/dist/sketchfab/glbInspect.js +58 -0
  82. package/dist/sketchfab/index.d.ts +3 -0
  83. package/dist/sketchfab/index.js +8 -1
  84. package/dist/sketchfab/inspectRemote.d.ts +13 -0
  85. package/dist/sketchfab/inspectRemote.js +77 -0
  86. package/dist/sketchfab/types.d.ts +10 -0
  87. package/dist/sketchfab/useSketchfabSearch.js +1 -2
  88. package/dist/studio/AccessoryBrowserScreen.d.ts +6 -0
  89. package/dist/studio/AccessoryBrowserScreen.js +626 -0
  90. package/dist/studio/AccessoryPanel.d.ts +10 -0
  91. package/dist/studio/AccessoryPanel.js +396 -0
  92. package/dist/studio/AppearancePanel.d.ts +9 -0
  93. package/dist/studio/AppearancePanel.js +77 -0
  94. package/dist/studio/AvatarCreatorScreen.d.ts +5 -0
  95. package/dist/studio/AvatarCreatorScreen.js +806 -0
  96. package/dist/studio/AvatarEditorScreen.d.ts +14 -0
  97. package/dist/studio/AvatarEditorScreen.js +510 -0
  98. package/dist/studio/AvatarGrid.d.ts +23 -0
  99. package/dist/studio/AvatarGrid.js +257 -0
  100. package/dist/studio/ColorSwatch.d.ts +8 -0
  101. package/dist/studio/ColorSwatch.js +100 -0
  102. package/dist/studio/CreateVoiceProfileSheet.d.ts +8 -0
  103. package/dist/studio/CreateVoiceProfileSheet.js +242 -0
  104. package/dist/studio/DetailsPanel.d.ts +15 -0
  105. package/dist/studio/DetailsPanel.js +239 -0
  106. package/dist/studio/FilamentEditor.d.ts +2 -0
  107. package/dist/studio/FilamentEditor.js +6 -0
  108. package/dist/studio/PrecisionPanel.d.ts +2 -0
  109. package/dist/studio/PrecisionPanel.js +7 -0
  110. package/dist/studio/PublicGalleryScreen.d.ts +5 -0
  111. package/dist/studio/PublicGalleryScreen.js +358 -0
  112. package/dist/studio/SketchfabModelCard.d.ts +20 -0
  113. package/dist/studio/SketchfabModelCard.js +104 -0
  114. package/dist/studio/StudioBrowseHeader.d.ts +9 -0
  115. package/dist/studio/StudioBrowseHeader.js +28 -0
  116. package/dist/studio/StudioEmptyState.d.ts +8 -0
  117. package/dist/studio/StudioEmptyState.js +29 -0
  118. package/dist/studio/StudioFloatingAction.d.ts +13 -0
  119. package/dist/studio/StudioFloatingAction.js +42 -0
  120. package/dist/studio/StudioSectionHeader.d.ts +7 -0
  121. package/dist/studio/StudioSectionHeader.js +27 -0
  122. package/dist/studio/StudioSurfaceCard.d.ts +8 -0
  123. package/dist/studio/StudioSurfaceCard.js +20 -0
  124. package/dist/studio/VoicePanel.d.ts +15 -0
  125. package/dist/studio/VoicePanel.js +305 -0
  126. package/dist/studio/constants.d.ts +3 -0
  127. package/dist/studio/constants.js +6 -0
  128. package/dist/studio/index.d.ts +29 -0
  129. package/dist/studio/index.js +54 -0
  130. package/dist/studio/useSketchfabCapabilities.d.ts +31 -0
  131. package/dist/studio/useSketchfabCapabilities.js +82 -0
  132. package/dist/tts/useDirectVisemeStream.d.ts +2 -6
  133. package/dist/tts/useDirectVisemeStream.js +16 -12
  134. package/dist/tts/useMotionMarkers.d.ts +0 -1
  135. package/dist/tts/useMotionMarkers.js +1 -2
  136. package/dist/utils/avatarUtils.js +94 -8
  137. package/dist/utils/faceLandmarkerToShapeWeights.js +21 -14
  138. package/dist/voice/convertToWav.js +1 -2
  139. package/dist/voice/index.d.ts +3 -0
  140. package/dist/voice/index.js +6 -1
  141. package/dist/voice/useAudioPlayer.js +18 -6
  142. package/dist/voice/useAudioRecording.js +1 -2
  143. package/dist/voice/useFaceControls.d.ts +14 -0
  144. package/dist/voice/useFaceControls.js +81 -0
  145. package/dist/voice/useVoicePreview.d.ts +7 -0
  146. package/dist/voice/useVoicePreview.js +83 -0
  147. package/dist/wardrobe/index.d.ts +3 -0
  148. package/dist/wardrobe/index.js +8 -1
  149. package/dist/wardrobe/useAccessoryGestures.d.ts +20 -0
  150. package/dist/wardrobe/useAccessoryGestures.js +94 -0
  151. package/dist/wardrobe/useAvatarWardrobeHydration.js +9 -4
  152. package/dist/wardrobe/useStudioAvatar.d.ts +29 -0
  153. package/dist/wardrobe/useStudioAvatar.js +186 -0
  154. package/dist/wardrobe/wardrobeStore.d.ts +2 -0
  155. package/dist/wardrobe/wardrobeStore.js +12 -2
  156. package/dist/wgpu/R3FWebGpuCanvas.d.ts +15 -0
  157. package/dist/wgpu/R3FWebGpuCanvas.js +176 -0
  158. package/dist/wgpu/WgpuAvatar.d.ts +26 -2
  159. package/dist/wgpu/WgpuAvatar.js +313 -46
  160. package/dist/wgpu/accessoryDefaults.d.ts +12 -0
  161. package/dist/wgpu/accessoryDefaults.js +19 -0
  162. package/dist/wgpu/blobShim.d.ts +2 -0
  163. package/dist/wgpu/blobShim.js +191 -0
  164. package/dist/wgpu/index.d.ts +1 -0
  165. package/dist/wgpu/index.js +4 -1
  166. package/dist/wgpu/loadGLTFFromUri.d.ts +2 -0
  167. package/dist/wgpu/loadGLTFFromUri.js +75 -0
  168. package/dist/wgpu/morphTables.js +21 -10
  169. package/dist/wgpu/motionState.d.ts +20 -0
  170. package/dist/wgpu/motionState.js +31 -0
  171. package/dist/wgpu/patchThreeForRN.d.ts +28 -0
  172. package/dist/wgpu/patchThreeForRN.js +292 -0
  173. package/dist/wgpu/scenePlacement.d.ts +5 -0
  174. package/dist/wgpu/scenePlacement.js +50 -0
  175. package/dist/wgpu/useAuthedModelUri.js +22 -11
  176. package/dist/wgpu/useNativeGLTF.d.ts +7 -0
  177. package/dist/wgpu/useNativeGLTF.js +36 -0
  178. package/package.json +102 -32
@@ -0,0 +1,11 @@
1
+ import * as THREE from 'three';
2
+ /**
3
+ * Converts a screen-space drag delta into a world-space translation delta,
4
+ * keeping the accessory in a plane facing the camera (bone-locked plane).
5
+ */
6
+ export declare function screenDeltaToWorldDelta(camera: THREE.PerspectiveCamera, objectWorldPos: THREE.Vector3, dx: number, dy: number, viewportWidth: number, viewportHeight: number): THREE.Vector3;
7
+ /**
8
+ * Computes the rotation angle delta between two pointer-pair angles.
9
+ * Returns delta in radians, normalized to [-π, π].
10
+ */
11
+ export declare function twoPointerAngleDelta(startAngle: number, currentAngle: number): number;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.screenDeltaToWorldDelta = screenDeltaToWorldDelta;
37
+ exports.twoPointerAngleDelta = twoPointerAngleDelta;
38
+ const THREE = __importStar(require("three"));
39
+ /**
40
+ * Converts a screen-space drag delta into a world-space translation delta,
41
+ * keeping the accessory in a plane facing the camera (bone-locked plane).
42
+ */
43
+ function screenDeltaToWorldDelta(camera, objectWorldPos, dx, dy, viewportWidth, viewportHeight) {
44
+ const distance = objectWorldPos.distanceTo(camera.position);
45
+ const fovY = (camera.fov * Math.PI) / 180;
46
+ const worldHeight = 2 * distance * Math.tan(fovY / 2);
47
+ const worldWidth = worldHeight * (viewportWidth / viewportHeight);
48
+ const right = new THREE.Vector3();
49
+ const up = new THREE.Vector3();
50
+ camera.getWorldDirection(new THREE.Vector3()); // ensure matrix is fresh
51
+ right.setFromMatrixColumn(camera.matrixWorld, 0).normalize();
52
+ up.setFromMatrixColumn(camera.matrixWorld, 1).normalize();
53
+ return right
54
+ .multiplyScalar((dx / viewportWidth) * worldWidth)
55
+ .add(up.multiplyScalar((-dy / viewportHeight) * worldHeight));
56
+ }
57
+ /**
58
+ * Computes the rotation angle delta between two pointer-pair angles.
59
+ * Returns delta in radians, normalized to [-π, π].
60
+ */
61
+ function twoPointerAngleDelta(startAngle, currentAngle) {
62
+ let delta = currentAngle - startAngle;
63
+ while (delta > Math.PI)
64
+ delta -= 2 * Math.PI;
65
+ while (delta < -Math.PI)
66
+ delta += 2 * Math.PI;
67
+ return delta;
68
+ }
@@ -15,15 +15,29 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.useBoneSnap = exports.snapPlacementToNearestBone = exports.getWorldPositionForPlacement = exports.getWorldPositionForBone = exports.findNearestBone = exports.HUMANOID_BONES = void 0;
36
+ exports.getWorldPositionForPlacement = exports.HUMANOID_BONES = void 0;
37
+ exports.findNearestBone = findNearestBone;
38
+ exports.getWorldPositionForBone = getWorldPositionForBone;
39
+ exports.snapPlacementToNearestBone = snapPlacementToNearestBone;
40
+ exports.useBoneSnap = useBoneSnap;
27
41
  const react_1 = require("react");
28
42
  const Haptics = __importStar(require("expo-haptics"));
29
43
  const THREE = __importStar(require("three"));
@@ -54,7 +68,6 @@ function findNearestBone(avatarScene, worldPos, maxDistance = 0.35) {
54
68
  });
55
69
  return best;
56
70
  }
57
- exports.findNearestBone = findNearestBone;
58
71
  /**
59
72
  * Returns the world-space position of a named bone in the avatar scene.
60
73
  * Returns the scene origin if the bone is not found.
@@ -68,13 +81,11 @@ function getWorldPositionForBone(avatarScene, boneName) {
68
81
  });
69
82
  return result;
70
83
  }
71
- exports.getWorldPositionForBone = getWorldPositionForBone;
72
84
  // Legacy alias kept for call-site compatibility
73
85
  exports.getWorldPositionForPlacement = getWorldPositionForBone;
74
86
  function snapPlacementToNearestBone(avatarScene, worldPos) {
75
87
  return findNearestBone(avatarScene, worldPos);
76
88
  }
77
- exports.snapPlacementToNearestBone = snapPlacementToNearestBone;
78
89
  /**
79
90
  * Hook that returns a snap function. Fires haptic feedback when a new bone
80
91
  * is snapped to.
@@ -90,4 +101,3 @@ function useBoneSnap(avatarScene) {
90
101
  return result;
91
102
  }, [avatarScene]);
92
103
  }
93
- exports.useBoneSnap = useBoneSnap;
@@ -0,0 +1,27 @@
1
+ import * as THREE from 'three';
2
+ export declare const HUMANOID_BONES: readonly ["Hips", "Spine", "Spine1", "Spine2", "Neck", "Head", "LeftShoulder", "LeftArm", "LeftForeArm", "LeftHand", "RightShoulder", "RightArm", "RightForeArm", "RightHand", "LeftUpLeg", "LeftLeg", "LeftFoot", "LeftToeBase", "RightUpLeg", "RightLeg", "RightFoot", "RightToeBase"];
3
+ export type HumanoidBone = (typeof HUMANOID_BONES)[number];
4
+ export interface BoneSnapResult {
5
+ bone: string;
6
+ position: THREE.Vector3;
7
+ distance: number;
8
+ }
9
+ /**
10
+ * Given an avatar scene and a world-space position, finds the nearest skeleton
11
+ * bone whose name matches a known humanoid bone name.
12
+ */
13
+ export declare function findNearestBone(avatarScene: THREE.Object3D, worldPos: THREE.Vector3, maxDistance?: number): BoneSnapResult | null;
14
+ /**
15
+ * Returns the world-space position of a named bone in the avatar scene.
16
+ * Returns the scene origin if the bone is not found.
17
+ */
18
+ export declare function getWorldPositionForBone(avatarScene: THREE.Object3D, boneName: string): THREE.Vector3;
19
+ export declare const getWorldPositionForPlacement: typeof getWorldPositionForBone;
20
+ /**
21
+ * Returns the nearest known humanoid bone to a placement point.
22
+ */
23
+ export declare function snapPlacementToNearestBone(avatarScene: THREE.Object3D, worldPos: THREE.Vector3): BoneSnapResult | null;
24
+ /**
25
+ * Web-safe snap hook. Native builds use the haptic version from boneSnap.ts.
26
+ */
27
+ export declare function useBoneSnap(avatarScene: THREE.Object3D | null): (worldPos: THREE.Vector3) => BoneSnapResult | null;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getWorldPositionForPlacement = exports.HUMANOID_BONES = void 0;
37
+ exports.findNearestBone = findNearestBone;
38
+ exports.getWorldPositionForBone = getWorldPositionForBone;
39
+ exports.snapPlacementToNearestBone = snapPlacementToNearestBone;
40
+ exports.useBoneSnap = useBoneSnap;
41
+ const react_1 = require("react");
42
+ const THREE = __importStar(require("three"));
43
+ exports.HUMANOID_BONES = [
44
+ 'Hips', 'Spine', 'Spine1', 'Spine2', 'Neck', 'Head',
45
+ 'LeftShoulder', 'LeftArm', 'LeftForeArm', 'LeftHand',
46
+ 'RightShoulder', 'RightArm', 'RightForeArm', 'RightHand',
47
+ 'LeftUpLeg', 'LeftLeg', 'LeftFoot', 'LeftToeBase',
48
+ 'RightUpLeg', 'RightLeg', 'RightFoot', 'RightToeBase',
49
+ ];
50
+ /**
51
+ * Given an avatar scene and a world-space position, finds the nearest skeleton
52
+ * bone whose name matches a known humanoid bone name.
53
+ */
54
+ function findNearestBone(avatarScene, worldPos, maxDistance = 0.35) {
55
+ let best = null;
56
+ const boneWorldPos = new THREE.Vector3();
57
+ avatarScene.traverse((obj) => {
58
+ if (!(obj instanceof THREE.Bone))
59
+ return;
60
+ if (!exports.HUMANOID_BONES.includes(obj.name))
61
+ return;
62
+ obj.getWorldPosition(boneWorldPos);
63
+ const dist = worldPos.distanceTo(boneWorldPos);
64
+ if (dist < maxDistance && (!best || dist < best.distance)) {
65
+ best = { bone: obj.name, position: boneWorldPos.clone(), distance: dist };
66
+ }
67
+ });
68
+ return best;
69
+ }
70
+ /**
71
+ * Returns the world-space position of a named bone in the avatar scene.
72
+ * Returns the scene origin if the bone is not found.
73
+ */
74
+ function getWorldPositionForBone(avatarScene, boneName) {
75
+ const result = new THREE.Vector3();
76
+ avatarScene.traverse((obj) => {
77
+ if (obj instanceof THREE.Bone && obj.name === boneName) {
78
+ obj.getWorldPosition(result);
79
+ }
80
+ });
81
+ return result;
82
+ }
83
+ exports.getWorldPositionForPlacement = getWorldPositionForBone;
84
+ /**
85
+ * Returns the nearest known humanoid bone to a placement point.
86
+ */
87
+ function snapPlacementToNearestBone(avatarScene, worldPos) {
88
+ return findNearestBone(avatarScene, worldPos);
89
+ }
90
+ /**
91
+ * Web-safe snap hook. Native builds use the haptic version from boneSnap.ts.
92
+ */
93
+ function useBoneSnap(avatarScene) {
94
+ return (0, react_1.useCallback)((worldPos) => {
95
+ if (!avatarScene)
96
+ return null;
97
+ return findNearestBone(avatarScene, worldPos);
98
+ }, [avatarScene]);
99
+ }
@@ -0,0 +1,10 @@
1
+ export { AvatarCanvas } from './AvatarCanvas';
2
+ export { AvatarEditor } from './AvatarEditor';
3
+ export { AvatarModel } from './AvatarModel';
4
+ export { RigidAccessory } from './RigidAccessory';
5
+ export { SkinnedClothing } from './SkinnedClothing';
6
+ export { FaceSqueezeEditor, FACE_SQUEEZE_LOCAL_MODULE } from './FaceSqueezeEditor.web';
7
+ export { studioTheme, withAlpha } from './studioTheme';
8
+ export { useBoneSnap, findNearestBone, getWorldPositionForBone, getWorldPositionForPlacement, snapPlacementToNearestBone, HUMANOID_BONES, } from './boneSnap.web';
9
+ export type { AvatarEditorProps, AssetPlacement, EquippedAsset, FaceSqueezeEditorProps } from './types';
10
+ export type { BoneSnapResult, HumanoidBone } from './boneSnap.web';
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HUMANOID_BONES = exports.snapPlacementToNearestBone = exports.getWorldPositionForPlacement = exports.getWorldPositionForBone = exports.findNearestBone = exports.useBoneSnap = exports.withAlpha = exports.studioTheme = exports.FACE_SQUEEZE_LOCAL_MODULE = exports.FaceSqueezeEditor = exports.SkinnedClothing = exports.RigidAccessory = exports.AvatarModel = exports.AvatarEditor = exports.AvatarCanvas = void 0;
4
+ var AvatarCanvas_1 = require("./AvatarCanvas");
5
+ Object.defineProperty(exports, "AvatarCanvas", { enumerable: true, get: function () { return AvatarCanvas_1.AvatarCanvas; } });
6
+ var AvatarEditor_1 = require("./AvatarEditor");
7
+ Object.defineProperty(exports, "AvatarEditor", { enumerable: true, get: function () { return AvatarEditor_1.AvatarEditor; } });
8
+ var AvatarModel_1 = require("./AvatarModel");
9
+ Object.defineProperty(exports, "AvatarModel", { enumerable: true, get: function () { return AvatarModel_1.AvatarModel; } });
10
+ var RigidAccessory_1 = require("./RigidAccessory");
11
+ Object.defineProperty(exports, "RigidAccessory", { enumerable: true, get: function () { return RigidAccessory_1.RigidAccessory; } });
12
+ var SkinnedClothing_1 = require("./SkinnedClothing");
13
+ Object.defineProperty(exports, "SkinnedClothing", { enumerable: true, get: function () { return SkinnedClothing_1.SkinnedClothing; } });
14
+ var FaceSqueezeEditor_web_1 = require("./FaceSqueezeEditor.web");
15
+ Object.defineProperty(exports, "FaceSqueezeEditor", { enumerable: true, get: function () { return FaceSqueezeEditor_web_1.FaceSqueezeEditor; } });
16
+ Object.defineProperty(exports, "FACE_SQUEEZE_LOCAL_MODULE", { enumerable: true, get: function () { return FaceSqueezeEditor_web_1.FACE_SQUEEZE_LOCAL_MODULE; } });
17
+ var studioTheme_1 = require("./studioTheme");
18
+ Object.defineProperty(exports, "studioTheme", { enumerable: true, get: function () { return studioTheme_1.studioTheme; } });
19
+ Object.defineProperty(exports, "withAlpha", { enumerable: true, get: function () { return studioTheme_1.withAlpha; } });
20
+ var boneSnap_web_1 = require("./boneSnap.web");
21
+ Object.defineProperty(exports, "useBoneSnap", { enumerable: true, get: function () { return boneSnap_web_1.useBoneSnap; } });
22
+ Object.defineProperty(exports, "findNearestBone", { enumerable: true, get: function () { return boneSnap_web_1.findNearestBone; } });
23
+ Object.defineProperty(exports, "getWorldPositionForBone", { enumerable: true, get: function () { return boneSnap_web_1.getWorldPositionForBone; } });
24
+ Object.defineProperty(exports, "getWorldPositionForPlacement", { enumerable: true, get: function () { return boneSnap_web_1.getWorldPositionForPlacement; } });
25
+ Object.defineProperty(exports, "snapPlacementToNearestBone", { enumerable: true, get: function () { return boneSnap_web_1.snapPlacementToNearestBone; } });
26
+ Object.defineProperty(exports, "HUMANOID_BONES", { enumerable: true, get: function () { return boneSnap_web_1.HUMANOID_BONES; } });
Binary file
Binary file
Binary file
@@ -1,20 +1,20 @@
1
1
  export declare const studioTheme: {
2
2
  readonly colors: {
3
- readonly background: "#111315";
4
- readonly backgroundAlt: "#191d20";
5
- readonly surface: "#1c2125";
6
- readonly surfaceRaised: "#252b30";
7
- readonly surfaceSoft: "#2b3238";
8
- readonly border: "#394249";
9
- readonly borderStrong: "#53606a";
10
- readonly textPrimary: "#f6efe4";
11
- readonly textSecondary: "#cabfaa";
12
- readonly textMuted: "#8b847a";
13
- readonly accent: "#ff7a59";
14
- readonly accentStrong: "#ff9c72";
15
- readonly accentMuted: "rgba(255, 122, 89, 0.16)";
3
+ readonly background: "#0d1018";
4
+ readonly backgroundAlt: "#13151C";
5
+ readonly surface: "#1a1e29";
6
+ readonly surfaceRaised: "#222a3a";
7
+ readonly surfaceSoft: "#282B36";
8
+ readonly border: "#363b4a";
9
+ readonly borderStrong: "#424655";
10
+ readonly textPrimary: "#FAF7F0";
11
+ readonly textSecondary: "#C8CCD9";
12
+ readonly textMuted: "#6B7080";
13
+ readonly accent: "#4F5BD5";
14
+ readonly accentStrong: "#6673D6";
15
+ readonly accentMuted: "rgba(79, 91, 213, 0.16)";
16
16
  readonly success: "#69c08a";
17
- readonly danger: "#f07a7a";
17
+ readonly danger: "#E85C48";
18
18
  readonly shadow: "rgba(0, 0, 0, 0.32)";
19
19
  readonly haze: "rgba(255, 255, 255, 0.05)";
20
20
  };
@@ -1,23 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.withAlpha = exports.studioTheme = void 0;
3
+ exports.studioTheme = void 0;
4
+ exports.withAlpha = withAlpha;
5
+ // Self-contained theme. Palette is inspired by @sitebay/theme (slate dark
6
+ // surfaces + indigo accent + parchment text) but intentionally NOT a hard
7
+ // dependency — keeps this package standalone/publishable.
4
8
  exports.studioTheme = {
5
9
  colors: {
6
- background: '#111315',
7
- backgroundAlt: '#191d20',
8
- surface: '#1c2125',
9
- surfaceRaised: '#252b30',
10
- surfaceSoft: '#2b3238',
11
- border: '#394249',
12
- borderStrong: '#53606a',
13
- textPrimary: '#f6efe4',
14
- textSecondary: '#cabfaa',
15
- textMuted: '#8b847a',
16
- accent: '#ff7a59',
17
- accentStrong: '#ff9c72',
18
- accentMuted: 'rgba(255, 122, 89, 0.16)',
10
+ background: '#0d1018',
11
+ backgroundAlt: '#13151C',
12
+ surface: '#1a1e29',
13
+ surfaceRaised: '#222a3a',
14
+ surfaceSoft: '#282B36',
15
+ border: '#363b4a',
16
+ borderStrong: '#424655',
17
+ textPrimary: '#FAF7F0',
18
+ textSecondary: '#C8CCD9',
19
+ textMuted: '#6B7080',
20
+ accent: '#4F5BD5',
21
+ accentStrong: '#6673D6',
22
+ accentMuted: 'rgba(79, 91, 213, 0.16)',
19
23
  success: '#69c08a',
20
- danger: '#f07a7a',
24
+ danger: '#E85C48',
21
25
  shadow: 'rgba(0, 0, 0, 0.32)',
22
26
  haze: 'rgba(255, 255, 255, 0.05)',
23
27
  },
@@ -86,4 +90,3 @@ function withAlpha(hexOrRgb, alphaHex) {
86
90
  }
87
91
  return hexOrRgb;
88
92
  }
89
- exports.withAlpha = withAlpha;
@@ -41,4 +41,5 @@ export interface AvatarEditorProps {
41
41
  }
42
42
  export interface FaceSqueezeEditorProps {
43
43
  onClose: () => void;
44
+ avatarModule?: unknown;
44
45
  }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Generated avatar WebView accessories script section.
3
+ *
4
+ * Kept as a string builder so html.ts can compose the final document without
5
+ * owning every browser-side subsystem inline.
6
+ */
7
+ export declare function buildAccessoriesScript(): string;
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildAccessoriesScript = buildAccessoriesScript;
4
+ /**
5
+ * Generated avatar WebView accessories script section.
6
+ *
7
+ * Kept as a string builder so html.ts can compose the final document without
8
+ * owning every browser-side subsystem inline.
9
+ */
10
+ function buildAccessoriesScript() {
11
+ return `let THREE_REF = null;
12
+ let gltfLoaderInstance = null;
13
+ const currentAccessories = {};
14
+ let pendingAccessoriesList = [];
15
+
16
+ function disposeHierarchy(node) {
17
+ if (!node) return;
18
+ node.traverse((child) => {
19
+ if (child.isMesh) {
20
+ if (child.geometry) child.geometry.dispose();
21
+ if (child.material) {
22
+ const materials = Array.isArray(child.material) ? child.material : [child.material];
23
+ materials.forEach(mat => {
24
+ if (mat.map) mat.map.dispose();
25
+ if (mat.lightMap) mat.lightMap.dispose();
26
+ if (mat.bumpMap) mat.bumpMap.dispose();
27
+ if (mat.normalMap) mat.normalMap.dispose();
28
+ if (mat.specularMap) mat.specularMap.dispose();
29
+ if (mat.envMap) mat.envMap.dispose();
30
+ mat.dispose();
31
+ });
32
+ }
33
+ }
34
+ });
35
+ }
36
+
37
+ async function ensureThree() {
38
+ if (!THREE_REF) {
39
+ THREE_REF = await import('three');
40
+ const { GLTFLoader } = await import('three/addons/loaders/GLTFLoader.js');
41
+ const { DRACOLoader } = await import('three/addons/loaders/DRACOLoader.js');
42
+ gltfLoaderInstance = new GLTFLoader();
43
+ const dracoLoader = new DRACOLoader();
44
+ dracoLoader.setDecoderPath(DRACO_URL);
45
+ gltfLoaderInstance.setDRACOLoader(dracoLoader);
46
+ }
47
+ }
48
+
49
+ async function applyAccessories(accessoriesList) {
50
+ log('[ACC] applyAccessories called with ' + accessoriesList.length + ' items');
51
+ pendingAccessoriesList = accessoriesList;
52
+ await ensureThree();
53
+ const root = (head && head.armature) ? head.armature : staticModel;
54
+ log('[ACC] root=' + (root ? root.constructor.name + '/' + root.name : 'NULL') + ' head=' + !!head + ' head.armature=' + !!(head && head.armature) + ' staticModel=' + !!staticModel);
55
+ if (!root) { log('[ACC] ABORT: no root'); return; }
56
+
57
+ const boneNames = [];
58
+ root.traverse((child) => { if (child.isBone) boneNames.push(child.name); });
59
+ log('[ACC] Bones found: ' + boneNames.join(', '));
60
+
61
+ const newAccessoryIds = new Set(accessoriesList.map(a => a.id));
62
+ for (const id in currentAccessories) {
63
+ if (!newAccessoryIds.has(id)) {
64
+ const acc = currentAccessories[id];
65
+ if (acc.model) {
66
+ if (acc.model.parent) acc.model.parent.remove(acc.model);
67
+ disposeHierarchy(acc.model);
68
+ }
69
+ delete currentAccessories[id];
70
+ log('[ACC] Removed old accessory: ' + id);
71
+ }
72
+ }
73
+
74
+ for (const accData of accessoriesList) {
75
+ log('[ACC] Processing: id=' + accData.id + ' url=' + accData.url + ' bone=' + accData.bone);
76
+ const existing = currentAccessories[accData.id];
77
+
78
+ if (!existing || existing.url !== accData.url) {
79
+ if (existing && existing.model) {
80
+ if (existing.model.parent) existing.model.parent.remove(existing.model);
81
+ disposeHierarchy(existing.model);
82
+ }
83
+ currentAccessories[accData.id] = { ...accData, model: null, isLoading: true, latestData: accData };
84
+ log('[ACC] Starting GLB load: ' + accData.url);
85
+ (async () => {
86
+ try {
87
+ const loadedUrl = await loadWithAuth(accData.url);
88
+ gltfLoaderInstance.load(loadedUrl, (gltf) => {
89
+ if (loadedUrl.startsWith('blob:')) URL.revokeObjectURL(loadedUrl);
90
+ log('[ACC] GLB loaded OK for ' + accData.id);
91
+ const model = gltf.scene;
92
+ const latestData = (currentAccessories[accData.id] && currentAccessories[accData.id].latestData) || accData;
93
+ let targetBone = null;
94
+ let prefixCandidate = null;
95
+ root.traverse((child) => {
96
+ if (child.isBone && child.name === latestData.bone) targetBone = child;
97
+ else if (!prefixCandidate && child.name.replace(/_\\d+$/, '') === latestData.bone) prefixCandidate = child;
98
+ });
99
+ if (!targetBone && prefixCandidate) {
100
+ targetBone = prefixCandidate;
101
+ log('[ACC] Prefix match bone: ' + targetBone.name);
102
+ }
103
+ model.traverse((child) => { if (child.isMesh) child.frustumCulled = false; });
104
+ if (!targetBone) { log('[ACC] Bone not found: ' + latestData.bone + '. Using root.'); targetBone = root; }
105
+ else log('[ACC] Found bone: ' + targetBone.name);
106
+ const modelScale = latestData.scale !== undefined ? latestData.scale : 1.0;
107
+ model.scale.set(modelScale, modelScale, modelScale);
108
+ model.position.set(
109
+ latestData.position ? latestData.position[0] : 0,
110
+ latestData.position ? latestData.position[1] : 0,
111
+ latestData.position ? latestData.position[2] : 0
112
+ );
113
+ if (latestData.rotation) model.rotation.set(...latestData.rotation);
114
+ if (!currentAccessories[accData.id] || currentAccessories[accData.id].url !== accData.url) {
115
+ log('[ACC] Aborting: ' + accData.id + ' changed while loading.');
116
+ return;
117
+ }
118
+ targetBone.add(model);
119
+ log('[ACC] Attached to ' + targetBone.name);
120
+ currentAccessories[accData.id].model = model;
121
+ currentAccessories[accData.id].isLoading = false;
122
+ }, () => {}, (err) => {
123
+ if (loadedUrl.startsWith('blob:')) URL.revokeObjectURL(loadedUrl);
124
+ log('[ACC] FAILED: ' + accData.id + ': ' + err.message);
125
+ if (currentAccessories[accData.id]) currentAccessories[accData.id].isLoading = false;
126
+ });
127
+ } catch (authErr) {
128
+ log('[ACC] Auth fetch failed ' + accData.id + ': ' + authErr.message);
129
+ if (currentAccessories[accData.id]) currentAccessories[accData.id].isLoading = false;
130
+ }
131
+ })();
132
+ } else if (existing && existing.isLoading) {
133
+ existing.latestData = accData;
134
+ } else if (existing && existing.model) {
135
+ const model = existing.model;
136
+ const accScale = accData.scale !== undefined ? accData.scale : 1.0;
137
+ model.scale.set(accScale, accScale, accScale);
138
+ model.position.set(
139
+ accData.position ? accData.position[0] : 0,
140
+ accData.position ? accData.position[1] : 0,
141
+ accData.position ? accData.position[2] : 0
142
+ );
143
+ if (accData.rotation) model.rotation.set(...accData.rotation);
144
+ }
145
+ }
146
+ }
147
+
148
+ `;
149
+ }
@@ -0,0 +1 @@
1
+ export declare function buildMotionScript(): string;