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
package/dist/index.d.ts CHANGED
@@ -1,5 +1,21 @@
1
- export type { TalkingHeadAccessory, TalkingHeadLoadingState, TalkingHeadLoadingStage, TalkingHeadMood, TalkingHeadProps, TalkingHeadRef, TalkingHeadViseme, TalkingHeadVisemeCue, TalkingHeadVisemeSchedule, } from './TalkingHead';
1
+ export type { EngineVisemeMappingArtifact, OculusViseme, OculusVisemeWeights, RhubarbViseme, ArkitBlendShape, AgentVisemePayload, VisemeCue } from './core/avatar/visemes';
2
+ export { ENGINE_VISEME_MAPPING, OCULUS_MORPH_TARGET_NAMES, OCULUS_VISEMES, RHUBARB_TO_OCULUS, RHUBARB_VISEMES, ARKIT_TO_OCULUS, oculusWeightsForRhubarbCue, remapArkitToOculus, getArkitWeightsForViseme } from './core/avatar/visemes';
3
+ export type { FaceControl, ExpressionState, HeadPose, EyeGaze, Viseme } from './core/avatar/faceControls';
4
+ export { createNeutralExpression, visemeToExpression, applyVisemeToExpression } from './core/avatar/faceControls';
5
+ export type { AvatarBackend, CalibrationProfile, AvatarRenderTarget } from './core/avatar/backend';
6
+ export { MorphTargetBackend } from './core/avatar/backends';
7
+ export { GaussianBackend } from './core/avatar/backends';
8
+ export type { GaussianBackendConfig } from './core/avatar/backends';
9
+ export { walkAvatarSchema } from './core/avatar/schema';
10
+ export type { AvatarSchemaReport, MorphCoverage, SkeletonInfo, MeshStats, VisemeTier, VísemeTier } from './core/avatar/schema';
11
+ export { inspectAvatarCapabilities, inspectAvatarGltf, inspectAvatarJsonChunk, parseGlbJson } from './core/avatar/avatarCapabilities';
12
+ export type { AvatarCapabilities, MotionCoverage } from './core/avatar/avatarCapabilities';
13
+ export { MOTION_DEFS, MOTION_KEYS, isMotionKey, TALKINGHEAD_GESTURES, TALKINGHEAD_POSES, } from './core/avatar/motion';
14
+ export type { MotionKey, MotionDef, MotionDefWithBones, MotionBoneKey, MotionOscillator, TalkingHeadGesture, TalkingHeadPose, } from './core/avatar/motion';
2
15
  export { TalkingHead } from './TalkingHead';
16
+ export type { TalkingHeadRef, TalkingHeadProps, TalkingHeadMood, TalkingHeadAccessory, TalkingHeadLoadingState, TalkingHeadLoadingStage, TalkingHeadViseme, TalkingHeadVisemeCue, TalkingHeadVisemeSchedule, AvatarPlayerProps, AvatarPlayerRef, } from './TalkingHead';
17
+ export { TalkingHeadVisualization } from './TalkingHeadVisualization';
18
+ export type { TalkingHeadVisualizationRef } from './TalkingHeadVisualization';
3
19
  export { applyAppearanceToObject3D } from './appearance/apply';
4
20
  export { pickTargetForMaterialName } from './appearance/matchers';
5
21
  export { normalizeAppearance } from './appearance/schema';
@@ -9,3 +25,5 @@ export * from './wardrobe';
9
25
  export { useDirectVisemeStream } from './tts/useDirectVisemeStream';
10
26
  export type { VisemeStreamPayload } from './tts/useDirectVisemeStream';
11
27
  export { useMotionMarkers } from './tts/useMotionMarkers';
28
+ export { useFaceControlsFromVisemes } from './voice/useFaceControls';
29
+ export type { AvatarGlbParams, AvatarPlatformApi } from './platform/api/types';
package/dist/index.js CHANGED
@@ -14,20 +14,59 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.useMotionMarkers = exports.useDirectVisemeStream = exports.normalizeAppearance = exports.pickTargetForMaterialName = exports.applyAppearanceToObject3D = exports.TalkingHead = void 0;
17
+ exports.useFaceControlsFromVisemes = exports.useMotionMarkers = exports.useDirectVisemeStream = exports.normalizeAppearance = exports.pickTargetForMaterialName = exports.applyAppearanceToObject3D = exports.TalkingHeadVisualization = exports.TalkingHead = exports.TALKINGHEAD_POSES = exports.TALKINGHEAD_GESTURES = exports.isMotionKey = exports.MOTION_KEYS = exports.MOTION_DEFS = exports.parseGlbJson = exports.inspectAvatarJsonChunk = exports.inspectAvatarGltf = exports.inspectAvatarCapabilities = exports.walkAvatarSchema = exports.GaussianBackend = exports.MorphTargetBackend = exports.applyVisemeToExpression = exports.visemeToExpression = exports.createNeutralExpression = exports.getArkitWeightsForViseme = exports.remapArkitToOculus = exports.oculusWeightsForRhubarbCue = exports.ARKIT_TO_OCULUS = exports.RHUBARB_VISEMES = exports.RHUBARB_TO_OCULUS = exports.OCULUS_VISEMES = exports.OCULUS_MORPH_TARGET_NAMES = exports.ENGINE_VISEME_MAPPING = void 0;
18
+ var visemes_1 = require("./core/avatar/visemes");
19
+ Object.defineProperty(exports, "ENGINE_VISEME_MAPPING", { enumerable: true, get: function () { return visemes_1.ENGINE_VISEME_MAPPING; } });
20
+ Object.defineProperty(exports, "OCULUS_MORPH_TARGET_NAMES", { enumerable: true, get: function () { return visemes_1.OCULUS_MORPH_TARGET_NAMES; } });
21
+ Object.defineProperty(exports, "OCULUS_VISEMES", { enumerable: true, get: function () { return visemes_1.OCULUS_VISEMES; } });
22
+ Object.defineProperty(exports, "RHUBARB_TO_OCULUS", { enumerable: true, get: function () { return visemes_1.RHUBARB_TO_OCULUS; } });
23
+ Object.defineProperty(exports, "RHUBARB_VISEMES", { enumerable: true, get: function () { return visemes_1.RHUBARB_VISEMES; } });
24
+ Object.defineProperty(exports, "ARKIT_TO_OCULUS", { enumerable: true, get: function () { return visemes_1.ARKIT_TO_OCULUS; } });
25
+ Object.defineProperty(exports, "oculusWeightsForRhubarbCue", { enumerable: true, get: function () { return visemes_1.oculusWeightsForRhubarbCue; } });
26
+ Object.defineProperty(exports, "remapArkitToOculus", { enumerable: true, get: function () { return visemes_1.remapArkitToOculus; } });
27
+ Object.defineProperty(exports, "getArkitWeightsForViseme", { enumerable: true, get: function () { return visemes_1.getArkitWeightsForViseme; } });
28
+ var faceControls_1 = require("./core/avatar/faceControls");
29
+ Object.defineProperty(exports, "createNeutralExpression", { enumerable: true, get: function () { return faceControls_1.createNeutralExpression; } });
30
+ Object.defineProperty(exports, "visemeToExpression", { enumerable: true, get: function () { return faceControls_1.visemeToExpression; } });
31
+ Object.defineProperty(exports, "applyVisemeToExpression", { enumerable: true, get: function () { return faceControls_1.applyVisemeToExpression; } });
32
+ var backends_1 = require("./core/avatar/backends");
33
+ Object.defineProperty(exports, "MorphTargetBackend", { enumerable: true, get: function () { return backends_1.MorphTargetBackend; } });
34
+ var backends_2 = require("./core/avatar/backends");
35
+ Object.defineProperty(exports, "GaussianBackend", { enumerable: true, get: function () { return backends_2.GaussianBackend; } });
36
+ var schema_1 = require("./core/avatar/schema");
37
+ Object.defineProperty(exports, "walkAvatarSchema", { enumerable: true, get: function () { return schema_1.walkAvatarSchema; } });
38
+ var avatarCapabilities_1 = require("./core/avatar/avatarCapabilities");
39
+ Object.defineProperty(exports, "inspectAvatarCapabilities", { enumerable: true, get: function () { return avatarCapabilities_1.inspectAvatarCapabilities; } });
40
+ Object.defineProperty(exports, "inspectAvatarGltf", { enumerable: true, get: function () { return avatarCapabilities_1.inspectAvatarGltf; } });
41
+ Object.defineProperty(exports, "inspectAvatarJsonChunk", { enumerable: true, get: function () { return avatarCapabilities_1.inspectAvatarJsonChunk; } });
42
+ Object.defineProperty(exports, "parseGlbJson", { enumerable: true, get: function () { return avatarCapabilities_1.parseGlbJson; } });
43
+ var motion_1 = require("./core/avatar/motion");
44
+ Object.defineProperty(exports, "MOTION_DEFS", { enumerable: true, get: function () { return motion_1.MOTION_DEFS; } });
45
+ Object.defineProperty(exports, "MOTION_KEYS", { enumerable: true, get: function () { return motion_1.MOTION_KEYS; } });
46
+ Object.defineProperty(exports, "isMotionKey", { enumerable: true, get: function () { return motion_1.isMotionKey; } });
47
+ Object.defineProperty(exports, "TALKINGHEAD_GESTURES", { enumerable: true, get: function () { return motion_1.TALKINGHEAD_GESTURES; } });
48
+ Object.defineProperty(exports, "TALKINGHEAD_POSES", { enumerable: true, get: function () { return motion_1.TALKINGHEAD_POSES; } });
49
+ // TalkingHead component + legacy type re-exports
18
50
  var TalkingHead_1 = require("./TalkingHead");
19
51
  Object.defineProperty(exports, "TalkingHead", { enumerable: true, get: function () { return TalkingHead_1.TalkingHead; } });
20
- // Export appearance utilities, but exclude AvatarAppearance — the canonical
21
- // AvatarAppearance (with equippedAccessories) comes from ./api below.
52
+ var TalkingHeadVisualization_1 = require("./TalkingHeadVisualization");
53
+ Object.defineProperty(exports, "TalkingHeadVisualization", { enumerable: true, get: function () { return TalkingHeadVisualization_1.TalkingHeadVisualization; } });
54
+ // Appearance
22
55
  var apply_1 = require("./appearance/apply");
23
56
  Object.defineProperty(exports, "applyAppearanceToObject3D", { enumerable: true, get: function () { return apply_1.applyAppearanceToObject3D; } });
24
57
  var matchers_1 = require("./appearance/matchers");
25
58
  Object.defineProperty(exports, "pickTargetForMaterialName", { enumerable: true, get: function () { return matchers_1.pickTargetForMaterialName; } });
26
- var schema_1 = require("./appearance/schema");
27
- Object.defineProperty(exports, "normalizeAppearance", { enumerable: true, get: function () { return schema_1.normalizeAppearance; } });
59
+ var schema_2 = require("./appearance/schema");
60
+ Object.defineProperty(exports, "normalizeAppearance", { enumerable: true, get: function () { return schema_2.normalizeAppearance; } });
61
+ // API
28
62
  __exportStar(require("./api"), exports);
63
+ // Wardrobe
29
64
  __exportStar(require("./wardrobe"), exports);
65
+ // TTS / Visemes
30
66
  var useDirectVisemeStream_1 = require("./tts/useDirectVisemeStream");
31
67
  Object.defineProperty(exports, "useDirectVisemeStream", { enumerable: true, get: function () { return useDirectVisemeStream_1.useDirectVisemeStream; } });
32
68
  var useMotionMarkers_1 = require("./tts/useMotionMarkers");
33
69
  Object.defineProperty(exports, "useMotionMarkers", { enumerable: true, get: function () { return useMotionMarkers_1.useMotionMarkers; } });
70
+ // Face controls hook
71
+ var useFaceControls_1 = require("./voice/useFaceControls");
72
+ Object.defineProperty(exports, "useFaceControlsFromVisemes", { enumerable: true, get: function () { return useFaceControls_1.useFaceControlsFromVisemes; } });
@@ -1,5 +1,19 @@
1
- export type { TalkingHeadAccessory, TalkingHeadLoadingState, TalkingHeadMood, TalkingHeadProps, TalkingHeadRef, } from './TalkingHead.web';
1
+ export type { AvatarPlayerProps, AvatarPlayerRef, TalkingHeadAccessory, TalkingHeadLoadingStage, TalkingHeadLoadingState, TalkingHeadMood, TalkingHeadProps, TalkingHeadRef, TalkingHeadViseme, TalkingHeadVisemeCue, TalkingHeadVisemeSchedule, } from './TalkingHead.web';
2
2
  export { TalkingHead } from './TalkingHead.web';
3
+ export { buildAvatarHtml } from './html';
4
+ export type { AvatarConfig } from './html';
5
+ export type { EngineVisemeMappingArtifact, OculusViseme, OculusVisemeWeights, RhubarbViseme, ArkitBlendShape, AgentVisemePayload, VisemeCue } from './core/avatar/visemes';
6
+ export { ENGINE_VISEME_MAPPING, OCULUS_MORPH_TARGET_NAMES, OCULUS_VISEMES, RHUBARB_TO_OCULUS, RHUBARB_VISEMES, ARKIT_TO_OCULUS, oculusWeightsForRhubarbCue, remapArkitToOculus, getArkitWeightsForViseme } from './core/avatar/visemes';
7
+ export type { FaceControl, ExpressionState, HeadPose, EyeGaze, Viseme } from './core/avatar/faceControls';
8
+ export { createNeutralExpression, visemeToExpression, applyVisemeToExpression } from './core/avatar/faceControls';
9
+ export type { AvatarBackend, CalibrationProfile, AvatarRenderTarget } from './core/avatar/backend';
10
+ export { MorphTargetBackend } from './core/avatar/backends';
11
+ export { GaussianBackend } from './core/avatar/backends';
12
+ export type { GaussianBackendConfig } from './core/avatar/backends';
13
+ export { walkAvatarSchema } from './core/avatar/schema';
14
+ export type { AvatarSchemaReport, MorphCoverage, SkeletonInfo, MeshStats, VisemeTier, VísemeTier } from './core/avatar/schema';
15
+ export { MOTION_DEFS, MOTION_KEYS, isMotionKey, TALKINGHEAD_GESTURES, TALKINGHEAD_POSES, } from './core/avatar/motion';
16
+ export type { MotionKey, MotionDef, MotionDefWithBones, MotionBoneKey, MotionOscillator, TalkingHeadGesture, TalkingHeadPose, } from './core/avatar/motion';
3
17
  export { applyAppearanceToObject3D } from './appearance/apply';
4
18
  export { pickTargetForMaterialName } from './appearance/matchers';
5
19
  export { normalizeAppearance } from './appearance/schema';
@@ -7,3 +21,6 @@ export type { AppearanceTarget } from './appearance/matchers';
7
21
  export * from './api';
8
22
  export { useDirectVisemeStream } from './tts/useDirectVisemeStream';
9
23
  export type { VisemeStreamPayload } from './tts/useDirectVisemeStream';
24
+ export { useMotionMarkers } from './tts/useMotionMarkers';
25
+ export { useFaceControlsFromVisemes } from './voice/useFaceControls';
26
+ export type { AvatarGlbParams, AvatarPlatformApi } from './platform/api/types';
package/dist/index.web.js CHANGED
@@ -14,17 +14,50 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.useDirectVisemeStream = exports.normalizeAppearance = exports.pickTargetForMaterialName = exports.applyAppearanceToObject3D = exports.TalkingHead = void 0;
17
+ exports.useFaceControlsFromVisemes = exports.useMotionMarkers = exports.useDirectVisemeStream = exports.normalizeAppearance = exports.pickTargetForMaterialName = exports.applyAppearanceToObject3D = exports.TALKINGHEAD_POSES = exports.TALKINGHEAD_GESTURES = exports.isMotionKey = exports.MOTION_KEYS = exports.MOTION_DEFS = exports.walkAvatarSchema = exports.GaussianBackend = exports.MorphTargetBackend = exports.applyVisemeToExpression = exports.visemeToExpression = exports.createNeutralExpression = exports.getArkitWeightsForViseme = exports.remapArkitToOculus = exports.oculusWeightsForRhubarbCue = exports.ARKIT_TO_OCULUS = exports.RHUBARB_VISEMES = exports.RHUBARB_TO_OCULUS = exports.OCULUS_VISEMES = exports.OCULUS_MORPH_TARGET_NAMES = exports.ENGINE_VISEME_MAPPING = exports.buildAvatarHtml = exports.TalkingHead = void 0;
18
18
  var TalkingHead_web_1 = require("./TalkingHead.web");
19
19
  Object.defineProperty(exports, "TalkingHead", { enumerable: true, get: function () { return TalkingHead_web_1.TalkingHead; } });
20
+ var html_1 = require("./html");
21
+ Object.defineProperty(exports, "buildAvatarHtml", { enumerable: true, get: function () { return html_1.buildAvatarHtml; } });
22
+ var visemes_1 = require("./core/avatar/visemes");
23
+ Object.defineProperty(exports, "ENGINE_VISEME_MAPPING", { enumerable: true, get: function () { return visemes_1.ENGINE_VISEME_MAPPING; } });
24
+ Object.defineProperty(exports, "OCULUS_MORPH_TARGET_NAMES", { enumerable: true, get: function () { return visemes_1.OCULUS_MORPH_TARGET_NAMES; } });
25
+ Object.defineProperty(exports, "OCULUS_VISEMES", { enumerable: true, get: function () { return visemes_1.OCULUS_VISEMES; } });
26
+ Object.defineProperty(exports, "RHUBARB_TO_OCULUS", { enumerable: true, get: function () { return visemes_1.RHUBARB_TO_OCULUS; } });
27
+ Object.defineProperty(exports, "RHUBARB_VISEMES", { enumerable: true, get: function () { return visemes_1.RHUBARB_VISEMES; } });
28
+ Object.defineProperty(exports, "ARKIT_TO_OCULUS", { enumerable: true, get: function () { return visemes_1.ARKIT_TO_OCULUS; } });
29
+ Object.defineProperty(exports, "oculusWeightsForRhubarbCue", { enumerable: true, get: function () { return visemes_1.oculusWeightsForRhubarbCue; } });
30
+ Object.defineProperty(exports, "remapArkitToOculus", { enumerable: true, get: function () { return visemes_1.remapArkitToOculus; } });
31
+ Object.defineProperty(exports, "getArkitWeightsForViseme", { enumerable: true, get: function () { return visemes_1.getArkitWeightsForViseme; } });
32
+ var faceControls_1 = require("./core/avatar/faceControls");
33
+ Object.defineProperty(exports, "createNeutralExpression", { enumerable: true, get: function () { return faceControls_1.createNeutralExpression; } });
34
+ Object.defineProperty(exports, "visemeToExpression", { enumerable: true, get: function () { return faceControls_1.visemeToExpression; } });
35
+ Object.defineProperty(exports, "applyVisemeToExpression", { enumerable: true, get: function () { return faceControls_1.applyVisemeToExpression; } });
36
+ var backends_1 = require("./core/avatar/backends");
37
+ Object.defineProperty(exports, "MorphTargetBackend", { enumerable: true, get: function () { return backends_1.MorphTargetBackend; } });
38
+ var backends_2 = require("./core/avatar/backends");
39
+ Object.defineProperty(exports, "GaussianBackend", { enumerable: true, get: function () { return backends_2.GaussianBackend; } });
40
+ var schema_1 = require("./core/avatar/schema");
41
+ Object.defineProperty(exports, "walkAvatarSchema", { enumerable: true, get: function () { return schema_1.walkAvatarSchema; } });
42
+ var motion_1 = require("./core/avatar/motion");
43
+ Object.defineProperty(exports, "MOTION_DEFS", { enumerable: true, get: function () { return motion_1.MOTION_DEFS; } });
44
+ Object.defineProperty(exports, "MOTION_KEYS", { enumerable: true, get: function () { return motion_1.MOTION_KEYS; } });
45
+ Object.defineProperty(exports, "isMotionKey", { enumerable: true, get: function () { return motion_1.isMotionKey; } });
46
+ Object.defineProperty(exports, "TALKINGHEAD_GESTURES", { enumerable: true, get: function () { return motion_1.TALKINGHEAD_GESTURES; } });
47
+ Object.defineProperty(exports, "TALKINGHEAD_POSES", { enumerable: true, get: function () { return motion_1.TALKINGHEAD_POSES; } });
20
48
  // Export appearance utilities, but exclude AvatarAppearance — the canonical
21
49
  // AvatarAppearance (with equippedAccessories) comes from ./api below.
22
50
  var apply_1 = require("./appearance/apply");
23
51
  Object.defineProperty(exports, "applyAppearanceToObject3D", { enumerable: true, get: function () { return apply_1.applyAppearanceToObject3D; } });
24
52
  var matchers_1 = require("./appearance/matchers");
25
53
  Object.defineProperty(exports, "pickTargetForMaterialName", { enumerable: true, get: function () { return matchers_1.pickTargetForMaterialName; } });
26
- var schema_1 = require("./appearance/schema");
27
- Object.defineProperty(exports, "normalizeAppearance", { enumerable: true, get: function () { return schema_1.normalizeAppearance; } });
54
+ var schema_2 = require("./appearance/schema");
55
+ Object.defineProperty(exports, "normalizeAppearance", { enumerable: true, get: function () { return schema_2.normalizeAppearance; } });
28
56
  __exportStar(require("./api"), exports);
29
57
  var useDirectVisemeStream_1 = require("./tts/useDirectVisemeStream");
30
58
  Object.defineProperty(exports, "useDirectVisemeStream", { enumerable: true, get: function () { return useDirectVisemeStream_1.useDirectVisemeStream; } });
59
+ var useMotionMarkers_1 = require("./tts/useMotionMarkers");
60
+ Object.defineProperty(exports, "useMotionMarkers", { enumerable: true, get: function () { return useMotionMarkers_1.useMotionMarkers; } });
61
+ // Face controls hook
62
+ var useFaceControls_1 = require("./voice/useFaceControls");
63
+ Object.defineProperty(exports, "useFaceControlsFromVisemes", { enumerable: true, get: function () { return useFaceControls_1.useFaceControlsFromVisemes; } });
@@ -0,0 +1,10 @@
1
+ export interface AvatarGlbParams {
2
+ quality?: 'low' | 'medium' | 'high';
3
+ textureSize?: 256 | 512 | 1024 | 2048;
4
+ morphGroups?: ('oculus' | 'arkit' | 'expressions')[];
5
+ compression?: 'draco' | 'meshopt' | 'none';
6
+ textureFormat?: 'webp' | 'jpeg' | 'png';
7
+ }
8
+ export interface AvatarPlatformApi {
9
+ getAvatarUrl(id: string, params?: AvatarGlbParams): string;
10
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Rarity tiers for catalog items — determines availability and pricing.
3
+ */
4
+ export type RarityLevel = 'common' | 'uncommon' | 'rare' | 'legendary';
5
+ /**
6
+ * A single item in the avatar catalog (clothing, hair, accessory, etc.).
7
+ */
8
+ export interface CatalogItem {
9
+ id: string;
10
+ name: string;
11
+ /** Category tag, e.g. "hair", "outfit", "accessory", "body" */
12
+ category: string;
13
+ /** GLB asset URL */
14
+ glbUrl: string;
15
+ /** Preview image URL (2D thumbnail) */
16
+ thumbnailUrl?: string;
17
+ rarity: RarityLevel;
18
+ /** If set, item is only available to specific body types */
19
+ bodyTypeFilter?: string[];
20
+ /** Brand or collection tag */
21
+ collection?: string;
22
+ /** Price in platform credits; 0 = free */
23
+ price: number;
24
+ }
25
+ /**
26
+ * An avatar asset owned by a user (purchased or equipped).
27
+ */
28
+ export interface AvatarAsset {
29
+ catalogItemId: string;
30
+ /** When the user acquired this item */
31
+ acquiredAt: string;
32
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,27 @@
1
+ import type { AvatarGlbParams } from '../api/types';
2
+ /**
3
+ * Configuration passed to the Unity SDK AvatarLoader.
4
+ * Maps to the C# AvatarSDKConfig struct in the Unity plugin.
5
+ */
6
+ export interface UnitySdkConfig {
7
+ /** Base URL of the avatar platform API, e.g. "https://api.yourplatform.com" */
8
+ apiBaseUrl: string;
9
+ /** OAuth2 / API key for authenticated avatar downloads. */
10
+ apiKey?: string;
11
+ /** Default GLB quality params applied unless overridden per-avatar. */
12
+ defaultParams?: AvatarGlbParams;
13
+ }
14
+ /**
15
+ * Avatar metadata returned when a GLB is resolved for Unity.
16
+ * Mirrors the fields Unity's SkinnedMeshRenderer setup expects.
17
+ */
18
+ export interface UnityAvatarManifest {
19
+ id: string;
20
+ glbUrl: string;
21
+ /** Morph target names present in the GLB, ordered as they appear. */
22
+ morphTargets: string[];
23
+ /** Whether Oculus viseme morph targets are present. */
24
+ hasOculusVisemes: boolean;
25
+ /** Whether ARKit blendshape morph targets are present. */
26
+ hasArkit: boolean;
27
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,23 @@
1
+ import type { AvatarGlbParams } from '../api/types';
2
+ /**
3
+ * Configuration for the Unreal Engine plugin.
4
+ * Maps to the UE5 UAvatarSDKSettings data asset.
5
+ */
6
+ export interface UnrealSdkConfig {
7
+ /** Base URL of the avatar platform API. */
8
+ apiBaseUrl: string;
9
+ /** API key for authenticated requests. */
10
+ apiKey?: string;
11
+ /** Default GLB quality params. */
12
+ defaultParams?: AvatarGlbParams;
13
+ }
14
+ /**
15
+ * Blueprint-friendly avatar descriptor.
16
+ * Exposed as a UStruct in the Unreal plugin.
17
+ */
18
+ export interface UnrealAvatarDescriptor {
19
+ id: string;
20
+ glbUrl: string;
21
+ /** Morph target names for Blueprint binding. */
22
+ morphTargets: string[];
23
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,16 @@
1
+ import type { AvatarGlbParams } from '../api/types';
2
+ import type { AgentVisemePayload } from '../../core/avatar/visemes';
3
+ /**
4
+ * Minimal contract for the web SDK — fetch a GLB and drive morph targets.
5
+ * Implemented by any engine integration (Three.js, Babylon.js, etc.)
6
+ */
7
+ export interface AvatarWebSDK {
8
+ /** Build the GLB download URL for a given avatar id and quality params. */
9
+ getAvatarUrl(id: string, params?: AvatarGlbParams): string;
10
+ /** Schedule viseme morph-target animation from a TTS payload. */
11
+ scheduleVisemes(payload: AgentVisemePayload): void;
12
+ /** Drive jaw open/close from raw audio amplitude (0–1). */
13
+ sendAmplitude(amplitude: number): void;
14
+ /** Release GPU/memory resources. */
15
+ dispose(): void;
16
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getBestThumbnail = exports.downloadModel = exports.getDownloadUrl = exports.searchSketchfab = void 0;
3
+ exports.searchSketchfab = searchSketchfab;
4
+ exports.getDownloadUrl = getDownloadUrl;
5
+ exports.downloadModel = downloadModel;
6
+ exports.getBestThumbnail = getBestThumbnail;
4
7
  const SKETCHFAB_API_BASE = 'https://api.sketchfab.com/v3';
5
8
  const PAGE_SIZE = 24;
6
9
  async function searchSketchfab(options) {
@@ -8,6 +11,7 @@ async function searchSketchfab(options) {
8
11
  const params = new URLSearchParams({
9
12
  type: 'models',
10
13
  downloadable: 'true',
14
+ rigged: 'true',
11
15
  count: String(count),
12
16
  sort_by: '-likeCount',
13
17
  q: query,
@@ -23,7 +27,6 @@ async function searchSketchfab(options) {
23
27
  }
24
28
  return response.json();
25
29
  }
26
- exports.searchSketchfab = searchSketchfab;
27
30
  async function getDownloadUrl(uid, apiKey) {
28
31
  const response = await fetch(`${SKETCHFAB_API_BASE}/models/${uid}/download`, {
29
32
  headers: { Authorization: `Token ${apiKey}` },
@@ -34,7 +37,6 @@ async function getDownloadUrl(uid, apiKey) {
34
37
  const data = (await response.json());
35
38
  return data?.glb?.url ?? data?.gltf?.url ?? null;
36
39
  }
37
- exports.getDownloadUrl = getDownloadUrl;
38
40
  async function downloadModel(uid, name, apiKey) {
39
41
  const url = await getDownloadUrl(uid, apiKey);
40
42
  if (!url) {
@@ -48,7 +50,6 @@ async function downloadModel(uid, name, apiKey) {
48
50
  const cleanName = name.replace(/[^\w\s-]/g, '').trim() || 'model';
49
51
  return new File([blob], `${cleanName}.glb`, { type: 'model/gltf-binary' });
50
52
  }
51
- exports.downloadModel = downloadModel;
52
53
  function getBestThumbnail(thumbnails, targetWidth = 280) {
53
54
  if (!thumbnails?.images?.length) {
54
55
  return '';
@@ -56,4 +57,3 @@ function getBestThumbnail(thumbnails, targetWidth = 280) {
56
57
  const sorted = [...thumbnails.images].sort((left, right) => Math.abs(left.width - targetWidth) - Math.abs(right.width - targetWidth));
57
58
  return sorted[0].url;
58
59
  }
59
- exports.getBestThumbnail = getBestThumbnail;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Lightweight GLB inspection — reads the JSON chunk header only, no geometry.
3
+ *
4
+ * Used to detect whether a downloaded model has morph targets (blend shapes)
5
+ * before importing it. Models without morph targets can't do real lipsync;
6
+ * we fall back to jaw-bone animation, which is much worse.
7
+ */
8
+ /** Byte length of the GLB JSON chunk, or null if not a valid GLB header. */
9
+ export declare function glbJsonChunkLength(header: Uint8Array): number | null;
10
+ export interface GlbMorphInfo {
11
+ /** Total morph targets across all mesh primitives. */
12
+ morphTargetCount: number;
13
+ /** Names from mesh.extras.targetNames where present (lowercased). */
14
+ targetNames: string[];
15
+ }
16
+ /**
17
+ * Inspect a glTF JSON document (the parsed JSON chunk of a GLB) for morph
18
+ * targets. Returns counts and any declared target names.
19
+ */
20
+ export declare function inspectGltfMorphs(gltf: unknown): GlbMorphInfo;
21
+ /** Parse the JSON chunk bytes of a GLB and inspect morph targets. */
22
+ export declare function inspectGlbJsonChunk(jsonBytes: Uint8Array): GlbMorphInfo;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ /**
3
+ * Lightweight GLB inspection — reads the JSON chunk header only, no geometry.
4
+ *
5
+ * Used to detect whether a downloaded model has morph targets (blend shapes)
6
+ * before importing it. Models without morph targets can't do real lipsync;
7
+ * we fall back to jaw-bone animation, which is much worse.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.glbJsonChunkLength = glbJsonChunkLength;
11
+ exports.inspectGltfMorphs = inspectGltfMorphs;
12
+ exports.inspectGlbJsonChunk = inspectGlbJsonChunk;
13
+ const GLB_MAGIC = 0x46546c67; // 'glTF'
14
+ const CHUNK_JSON = 0x4e4f534a; // 'JSON'
15
+ /** Byte length of the GLB JSON chunk, or null if not a valid GLB header. */
16
+ function glbJsonChunkLength(header) {
17
+ if (header.length < 20)
18
+ return null;
19
+ const view = new DataView(header.buffer, header.byteOffset, header.byteLength);
20
+ if (view.getUint32(0, true) !== GLB_MAGIC)
21
+ return null;
22
+ if (view.getUint32(16, true) !== CHUNK_JSON)
23
+ return null;
24
+ return view.getUint32(12, true);
25
+ }
26
+ /**
27
+ * Inspect a glTF JSON document (the parsed JSON chunk of a GLB) for morph
28
+ * targets. Returns counts and any declared target names.
29
+ */
30
+ function inspectGltfMorphs(gltf) {
31
+ const info = { morphTargetCount: 0, targetNames: [] };
32
+ const meshes = gltf?.meshes;
33
+ if (!Array.isArray(meshes))
34
+ return info;
35
+ for (const mesh of meshes) {
36
+ const primitives = mesh?.primitives;
37
+ if (Array.isArray(primitives)) {
38
+ for (const prim of primitives) {
39
+ const targets = prim?.targets;
40
+ if (Array.isArray(targets))
41
+ info.morphTargetCount += targets.length;
42
+ }
43
+ }
44
+ const names = mesh?.extras?.targetNames;
45
+ if (Array.isArray(names)) {
46
+ for (const n of names) {
47
+ if (typeof n === 'string')
48
+ info.targetNames.push(n.toLowerCase());
49
+ }
50
+ }
51
+ }
52
+ return info;
53
+ }
54
+ /** Parse the JSON chunk bytes of a GLB and inspect morph targets. */
55
+ function inspectGlbJsonChunk(jsonBytes) {
56
+ const text = new TextDecoder().decode(jsonBytes);
57
+ return inspectGltfMorphs(JSON.parse(text));
58
+ }
@@ -2,5 +2,8 @@ export { searchSketchfab, getDownloadUrl, downloadModel, getBestThumbnail } from
2
2
  export type { SketchfabSearchOptions } from './api';
3
3
  export { useSketchfabSearch } from './useSketchfabSearch';
4
4
  export type { UseSketchfabSearchOptions, UseSketchfabSearchResult } from './useSketchfabSearch';
5
+ export { glbJsonChunkLength, inspectGlbJsonChunk, inspectGltfMorphs } from './glbInspect';
6
+ export type { GlbMorphInfo } from './glbInspect';
7
+ export { inspectAvatarFromUrl, fetchSketchfabCapabilities } from './inspectRemote';
5
8
  export { ACCESSORY_CATEGORIES, HUMANOID_TAGS } from './categories';
6
9
  export type { SketchfabModel, SketchfabResponse, AccessoryCategory } from './types';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HUMANOID_TAGS = exports.ACCESSORY_CATEGORIES = exports.useSketchfabSearch = exports.getBestThumbnail = exports.downloadModel = exports.getDownloadUrl = exports.searchSketchfab = void 0;
3
+ exports.HUMANOID_TAGS = exports.ACCESSORY_CATEGORIES = exports.fetchSketchfabCapabilities = exports.inspectAvatarFromUrl = exports.inspectGltfMorphs = exports.inspectGlbJsonChunk = exports.glbJsonChunkLength = exports.useSketchfabSearch = exports.getBestThumbnail = exports.downloadModel = exports.getDownloadUrl = exports.searchSketchfab = void 0;
4
4
  var api_1 = require("./api");
5
5
  Object.defineProperty(exports, "searchSketchfab", { enumerable: true, get: function () { return api_1.searchSketchfab; } });
6
6
  Object.defineProperty(exports, "getDownloadUrl", { enumerable: true, get: function () { return api_1.getDownloadUrl; } });
@@ -8,6 +8,13 @@ Object.defineProperty(exports, "downloadModel", { enumerable: true, get: functio
8
8
  Object.defineProperty(exports, "getBestThumbnail", { enumerable: true, get: function () { return api_1.getBestThumbnail; } });
9
9
  var useSketchfabSearch_1 = require("./useSketchfabSearch");
10
10
  Object.defineProperty(exports, "useSketchfabSearch", { enumerable: true, get: function () { return useSketchfabSearch_1.useSketchfabSearch; } });
11
+ var glbInspect_1 = require("./glbInspect");
12
+ Object.defineProperty(exports, "glbJsonChunkLength", { enumerable: true, get: function () { return glbInspect_1.glbJsonChunkLength; } });
13
+ Object.defineProperty(exports, "inspectGlbJsonChunk", { enumerable: true, get: function () { return glbInspect_1.inspectGlbJsonChunk; } });
14
+ Object.defineProperty(exports, "inspectGltfMorphs", { enumerable: true, get: function () { return glbInspect_1.inspectGltfMorphs; } });
15
+ var inspectRemote_1 = require("./inspectRemote");
16
+ Object.defineProperty(exports, "inspectAvatarFromUrl", { enumerable: true, get: function () { return inspectRemote_1.inspectAvatarFromUrl; } });
17
+ Object.defineProperty(exports, "fetchSketchfabCapabilities", { enumerable: true, get: function () { return inspectRemote_1.fetchSketchfabCapabilities; } });
11
18
  var categories_1 = require("./categories");
12
19
  Object.defineProperty(exports, "ACCESSORY_CATEGORIES", { enumerable: true, get: function () { return categories_1.ACCESSORY_CATEGORIES; } });
13
20
  Object.defineProperty(exports, "HUMANOID_TAGS", { enumerable: true, get: function () { return categories_1.HUMANOID_TAGS; } });
@@ -0,0 +1,13 @@
1
+ import { type AvatarCapabilities } from '../core/avatar/avatarCapabilities';
2
+ /**
3
+ * Capability report for a GLB at `glbUrl`, read via two small Range requests
4
+ * (header, then JSON chunk). Returns null when the model can't be cheaply
5
+ * inspected (no Range support, bad header, oversized/short JSON chunk, network
6
+ * error or abort) — callers treat null as "unknown", never as "bad".
7
+ */
8
+ export declare function inspectAvatarFromUrl(glbUrl: string, signal?: AbortSignal): Promise<AvatarCapabilities | null>;
9
+ /**
10
+ * Resolve a Sketchfab model's signed GLB URL and inspect its capabilities
11
+ * without a full download. Returns null on any failure ("unknown").
12
+ */
13
+ export declare function fetchSketchfabCapabilities(uid: string, apiKey: string, signal?: AbortSignal): Promise<AvatarCapabilities | null>;
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.inspectAvatarFromUrl = inspectAvatarFromUrl;
4
+ exports.fetchSketchfabCapabilities = fetchSketchfabCapabilities;
5
+ /**
6
+ * Remote (pre-download) avatar capability inspection for Sketchfab results.
7
+ *
8
+ * Reads only the GLB header + JSON chunk via HTTP Range requests so we can tell
9
+ * whether a search result can lip-sync + move BEFORE the user commits to a full
10
+ * download/import. This is what lets the picker float "good-first" avatars to
11
+ * the top and badge them.
12
+ *
13
+ * Safety: a host that ignores Range and replies 200 would stream the whole file
14
+ * (models go up to 50MB), so we bail unless the response is a 206 Partial
15
+ * Content. The JSON chunk holds only metadata (nodes/meshes/skins/accessors),
16
+ * not geometry, so it stays small even for dense rigs.
17
+ */
18
+ const glbInspect_1 = require("./glbInspect");
19
+ const api_1 = require("./api");
20
+ const avatarCapabilities_1 = require("../core/avatar/avatarCapabilities");
21
+ /** Sanity cap on the JSON chunk we'll pull before giving up (treated as
22
+ * "unknown"). Real avatar JSON chunks are well under this. */
23
+ const MAX_JSON_CHUNK_BYTES = 8 * 1024 * 1024;
24
+ async function rangeBytes(url, start, endInclusive, signal) {
25
+ const res = await fetch(url, {
26
+ headers: { Range: `bytes=${start}-${endInclusive}` },
27
+ signal,
28
+ });
29
+ // Require a partial response. A 200 means the host ignored Range and is about
30
+ // to hand us the entire file — abandon the body so we never pull 50MB.
31
+ if (res.status !== 206) {
32
+ const body = res.body;
33
+ if (body?.cancel) {
34
+ try {
35
+ await body.cancel();
36
+ }
37
+ catch {
38
+ /* best effort */
39
+ }
40
+ }
41
+ return null;
42
+ }
43
+ return new Uint8Array(await res.arrayBuffer());
44
+ }
45
+ /**
46
+ * Capability report for a GLB at `glbUrl`, read via two small Range requests
47
+ * (header, then JSON chunk). Returns null when the model can't be cheaply
48
+ * inspected (no Range support, bad header, oversized/short JSON chunk, network
49
+ * error or abort) — callers treat null as "unknown", never as "bad".
50
+ */
51
+ async function inspectAvatarFromUrl(glbUrl, signal) {
52
+ try {
53
+ const header = await rangeBytes(glbUrl, 0, 19, signal);
54
+ if (!header)
55
+ return null;
56
+ const jsonLen = (0, glbInspect_1.glbJsonChunkLength)(header);
57
+ if (jsonLen === null || jsonLen <= 0 || jsonLen > MAX_JSON_CHUNK_BYTES)
58
+ return null;
59
+ const jsonBytes = await rangeBytes(glbUrl, 20, 20 + jsonLen - 1, signal);
60
+ if (!jsonBytes || jsonBytes.length < jsonLen)
61
+ return null;
62
+ return (0, avatarCapabilities_1.inspectAvatarJsonChunk)(jsonBytes);
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ }
68
+ /**
69
+ * Resolve a Sketchfab model's signed GLB URL and inspect its capabilities
70
+ * without a full download. Returns null on any failure ("unknown").
71
+ */
72
+ async function fetchSketchfabCapabilities(uid, apiKey, signal) {
73
+ const url = await (0, api_1.getDownloadUrl)(uid, apiKey);
74
+ if (!url)
75
+ return null;
76
+ return inspectAvatarFromUrl(url, signal);
77
+ }
@@ -29,6 +29,16 @@ export interface SketchfabModel {
29
29
  label: string;
30
30
  } | null;
31
31
  isDownloadable: boolean;
32
+ archives?: {
33
+ glb?: {
34
+ size: number;
35
+ url?: string;
36
+ };
37
+ gltf?: {
38
+ size: number;
39
+ url?: string;
40
+ };
41
+ };
32
42
  }
33
43
  export interface SketchfabResponse {
34
44
  results: SketchfabModel[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useSketchfabSearch = void 0;
3
+ exports.useSketchfabSearch = useSketchfabSearch;
4
4
  const react_1 = require("react");
5
5
  const api_1 = require("./api");
6
6
  function useSketchfabSearch({ apiKey, initialQuery = 'character humanoid avatar', debounceMs = 400, }) {
@@ -79,4 +79,3 @@ function useSketchfabSearch({ apiKey, initialQuery = 'character humanoid avatar'
79
79
  prevPage,
80
80
  };
81
81
  }
82
- exports.useSketchfabSearch = useSketchfabSearch;
@@ -0,0 +1,6 @@
1
+ export interface AccessoryBrowserScreenProps {
2
+ avatarId?: string;
3
+ sketchfabApiKey: string;
4
+ onDone?: () => void;
5
+ }
6
+ export declare function AccessoryBrowserScreen({ avatarId, sketchfabApiKey, onDone, }: AccessoryBrowserScreenProps): import("react/jsx-runtime").JSX.Element;