talking-head-studio 0.3.5 → 0.3.7

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 (47) hide show
  1. package/dist/TalkingHead.web.js +7 -17
  2. package/dist/api/studioApi.js +26 -25
  3. package/dist/appearance/apply.d.ts +6 -0
  4. package/dist/appearance/apply.js +72 -7
  5. package/dist/appearance/index.d.ts +1 -1
  6. package/dist/appearance/index.js +2 -1
  7. package/dist/appearance/matchers.js +2 -1
  8. package/dist/appearance/schema.d.ts +1 -0
  9. package/dist/appearance/schema.js +3 -1
  10. package/dist/appearance/sharedState.d.ts +11 -0
  11. package/dist/appearance/sharedState.js +13 -0
  12. package/dist/editor/AvatarCanvas.d.ts +1 -0
  13. package/dist/editor/AvatarCanvas.js +3 -2
  14. package/dist/editor/AvatarModel.d.ts +1 -3
  15. package/dist/editor/AvatarModel.js +13 -5
  16. package/dist/editor/RigidAccessory.js +2 -1
  17. package/dist/editor/SkinnedClothing.js +9 -18
  18. package/dist/filament/FilamentAvatar.js +20 -42
  19. package/dist/filament/editor/FilamentEditor.d.ts +16 -0
  20. package/dist/filament/editor/FilamentEditor.js +880 -0
  21. package/dist/filament/editor/FilamentEditor.web.d.ts +19 -0
  22. package/dist/filament/editor/FilamentEditor.web.js +58 -0
  23. package/dist/filament/editor/PrecisionPanel.d.ts +1 -0
  24. package/dist/filament/editor/PrecisionPanel.js +252 -0
  25. package/dist/filament/editor/boneSnap.d.ts +10 -0
  26. package/dist/filament/editor/boneSnap.js +97 -0
  27. package/dist/filament/editor/index.d.ts +5 -0
  28. package/dist/filament/editor/index.js +19 -0
  29. package/dist/filament/editor/studioTheme.d.ts +86 -0
  30. package/dist/filament/editor/studioTheme.js +89 -0
  31. package/dist/filament/useAuthedFilamentUri.js +9 -18
  32. package/dist/html.js +2 -1
  33. package/dist/index.d.ts +0 -2
  34. package/dist/index.js +1 -3
  35. package/dist/sketchfab/api.js +5 -4
  36. package/dist/sketchfab/useSketchfabSearch.js +2 -1
  37. package/dist/tts/useDirectVisemeStream.js +2 -1
  38. package/dist/tts/useMotionMarkers.d.ts +1 -0
  39. package/dist/tts/useMotionMarkers.js +2 -1
  40. package/dist/utils/avatarUtils.js +3 -2
  41. package/dist/utils/faceLandmarkerToShapeWeights.d.ts +44 -0
  42. package/dist/utils/faceLandmarkerToShapeWeights.js +112 -0
  43. package/dist/voice/convertToWav.js +2 -1
  44. package/dist/voice/useAudioPlayer.js +2 -1
  45. package/dist/voice/useAudioRecording.js +2 -1
  46. package/dist/wardrobe/useAvatarWardrobeHydration.js +2 -1
  47. package/package.json +25 -3
@@ -15,25 +15,15 @@ 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 () {
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
- })();
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
+ };
35
25
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.useAuthedFilamentUri = useAuthedFilamentUri;
26
+ exports.useAuthedFilamentUri = void 0;
37
27
  const react_1 = require("react");
38
28
  const FileSystem = __importStar(require("expo-file-system/legacy"));
39
29
  const studioApi_1 = require("../api/studioApi");
@@ -124,3 +114,4 @@ function useAuthedFilamentUri(remoteUrl) {
124
114
  }, [remoteUrl]);
125
115
  return result;
126
116
  }
117
+ exports.useAuthedFilamentUri = useAuthedFilamentUri;
package/dist/html.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.buildAvatarHtml = buildAvatarHtml;
3
+ exports.buildAvatarHtml = void 0;
4
4
  const UPSTREAM_SAFE_MOOD_MAP = {
5
5
  neutral: 'neutral',
6
6
  happy: 'happy',
@@ -1138,3 +1138,4 @@ await init();
1138
1138
  </html>
1139
1139
  `;
1140
1140
  }
1141
+ exports.buildAvatarHtml = buildAvatarHtml;
package/dist/index.d.ts CHANGED
@@ -6,8 +6,6 @@ export { normalizeAppearance } from './appearance/schema';
6
6
  export type { AppearanceTarget } from './appearance/matchers';
7
7
  export * from './api';
8
8
  export * from './wardrobe';
9
- export { TalkingHeadVisualization } from './TalkingHeadVisualization';
10
- export type { TalkingHeadVisualizationRef } from './TalkingHeadVisualization';
11
9
  export { useDirectVisemeStream } from './tts/useDirectVisemeStream';
12
10
  export type { VisemeStreamPayload } from './tts/useDirectVisemeStream';
13
11
  export { useMotionMarkers } from './tts/useMotionMarkers';
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ 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.TalkingHeadVisualization = exports.normalizeAppearance = exports.pickTargetForMaterialName = exports.applyAppearanceToObject3D = exports.TalkingHead = void 0;
17
+ exports.useMotionMarkers = exports.useDirectVisemeStream = exports.normalizeAppearance = exports.pickTargetForMaterialName = exports.applyAppearanceToObject3D = exports.TalkingHead = void 0;
18
18
  var TalkingHead_1 = require("./TalkingHead");
19
19
  Object.defineProperty(exports, "TalkingHead", { enumerable: true, get: function () { return TalkingHead_1.TalkingHead; } });
20
20
  // Export appearance utilities, but exclude AvatarAppearance — the canonical
@@ -27,8 +27,6 @@ var schema_1 = require("./appearance/schema");
27
27
  Object.defineProperty(exports, "normalizeAppearance", { enumerable: true, get: function () { return schema_1.normalizeAppearance; } });
28
28
  __exportStar(require("./api"), exports);
29
29
  __exportStar(require("./wardrobe"), exports);
30
- var TalkingHeadVisualization_1 = require("./TalkingHeadVisualization");
31
- Object.defineProperty(exports, "TalkingHeadVisualization", { enumerable: true, get: function () { return TalkingHeadVisualization_1.TalkingHeadVisualization; } });
32
30
  var useDirectVisemeStream_1 = require("./tts/useDirectVisemeStream");
33
31
  Object.defineProperty(exports, "useDirectVisemeStream", { enumerable: true, get: function () { return useDirectVisemeStream_1.useDirectVisemeStream; } });
34
32
  var useMotionMarkers_1 = require("./tts/useMotionMarkers");
@@ -1,9 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.searchSketchfab = searchSketchfab;
4
- exports.getDownloadUrl = getDownloadUrl;
5
- exports.downloadModel = downloadModel;
6
- exports.getBestThumbnail = getBestThumbnail;
3
+ exports.getBestThumbnail = exports.downloadModel = exports.getDownloadUrl = exports.searchSketchfab = void 0;
7
4
  const SKETCHFAB_API_BASE = 'https://api.sketchfab.com/v3';
8
5
  const PAGE_SIZE = 24;
9
6
  async function searchSketchfab(options) {
@@ -26,6 +23,7 @@ async function searchSketchfab(options) {
26
23
  }
27
24
  return response.json();
28
25
  }
26
+ exports.searchSketchfab = searchSketchfab;
29
27
  async function getDownloadUrl(uid, apiKey) {
30
28
  const response = await fetch(`${SKETCHFAB_API_BASE}/models/${uid}/download`, {
31
29
  headers: { Authorization: `Token ${apiKey}` },
@@ -36,6 +34,7 @@ async function getDownloadUrl(uid, apiKey) {
36
34
  const data = (await response.json());
37
35
  return data?.glb?.url ?? data?.gltf?.url ?? null;
38
36
  }
37
+ exports.getDownloadUrl = getDownloadUrl;
39
38
  async function downloadModel(uid, name, apiKey) {
40
39
  const url = await getDownloadUrl(uid, apiKey);
41
40
  if (!url) {
@@ -49,6 +48,7 @@ async function downloadModel(uid, name, apiKey) {
49
48
  const cleanName = name.replace(/[^\w\s-]/g, '').trim() || 'model';
50
49
  return new File([blob], `${cleanName}.glb`, { type: 'model/gltf-binary' });
51
50
  }
51
+ exports.downloadModel = downloadModel;
52
52
  function getBestThumbnail(thumbnails, targetWidth = 280) {
53
53
  if (!thumbnails?.images?.length) {
54
54
  return '';
@@ -56,3 +56,4 @@ function getBestThumbnail(thumbnails, targetWidth = 280) {
56
56
  const sorted = [...thumbnails.images].sort((left, right) => Math.abs(left.width - targetWidth) - Math.abs(right.width - targetWidth));
57
57
  return sorted[0].url;
58
58
  }
59
+ exports.getBestThumbnail = getBestThumbnail;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useSketchfabSearch = useSketchfabSearch;
3
+ exports.useSketchfabSearch = void 0;
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,3 +79,4 @@ function useSketchfabSearch({ apiKey, initialQuery = 'character humanoid avatar'
79
79
  prevPage,
80
80
  };
81
81
  }
82
+ exports.useSketchfabSearch = useSketchfabSearch;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useDirectVisemeStream = useDirectVisemeStream;
3
+ exports.useDirectVisemeStream = void 0;
4
4
  const react_1 = require("react");
5
5
  const fetch_1 = require("expo/fetch");
6
6
  // How long to keep retrying a stream before giving up (ms).
@@ -100,6 +100,7 @@ function useDirectVisemeStream(onVisemes) {
100
100
  }, []);
101
101
  return { openStream };
102
102
  }
103
+ exports.useDirectVisemeStream = useDirectVisemeStream;
103
104
  // ─── SSE parser ──────────────────────────────────────────────────────────────
104
105
  /**
105
106
  * Reads an SSE stream to completion, dispatching `event: visemes` messages.
@@ -1,2 +1,3 @@
1
+ /// <reference types="react" />
1
2
  import type { TalkingHeadRef } from '../TalkingHead';
2
3
  export declare function useMotionMarkers(ref: React.RefObject<TalkingHeadRef | null>): (text: string) => string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useMotionMarkers = useMotionMarkers;
3
+ exports.useMotionMarkers = void 0;
4
4
  const react_1 = require("react");
5
5
  /**
6
6
  * Parses ::marker_name:: tokens out of LLM transcript text, fires the
@@ -22,3 +22,4 @@ function useMotionMarkers(ref) {
22
22
  return '';
23
23
  }), [ref]);
24
24
  }
25
+ exports.useMotionMarkers = useMotionMarkers;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveFilamentAssetUri = resolveFilamentAssetUri;
4
- exports.resolveLocalAssetUrl = resolveLocalAssetUrl;
3
+ exports.resolveLocalAssetUrl = exports.resolveFilamentAssetUri = void 0;
5
4
  const expo_asset_1 = require("expo-asset");
6
5
  const react_native_1 = require("react-native");
7
6
  const expo_file_system_1 = require("expo-file-system");
@@ -22,6 +21,7 @@ async function resolveFilamentAssetUri(module) {
22
21
  return null;
23
22
  }
24
23
  }
24
+ exports.resolveFilamentAssetUri = resolveFilamentAssetUri;
25
25
  /**
26
26
  * Resolves a local Expo asset module (from require()) into a usable URL string.
27
27
  * On web, returns an absolute URL.
@@ -54,3 +54,4 @@ async function resolveLocalAssetUrl(module) {
54
54
  return null;
55
55
  }
56
56
  }
57
+ exports.resolveLocalAssetUrl = resolveLocalAssetUrl;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * faceLandmarkerToShapeWeights
3
+ *
4
+ * Runs MediaPipe FaceLandmarker on a photo and returns a
5
+ * faceShapeWeights Record<string, number> ready to store in
6
+ * AvatarAppearance. Works with any GLB that has ARKit morph
7
+ * target names — mesh-agnostic, pure named floats.
8
+ *
9
+ * Lazy-loads @mediapipe/tasks-vision on first call (~3MB WASM).
10
+ * Subsequent calls reuse the same FaceLandmarker instance.
11
+ *
12
+ * Apache 2.0 — no API key, no license restrictions.
13
+ */
14
+ type ImageSource = HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | ImageBitmap;
15
+ export type FaceShapeWeights = Record<string, number>;
16
+ export interface FaceLandmarkerOptions {
17
+ /**
18
+ * Minimum score threshold to include a blendshape weight.
19
+ * Shapes below this are omitted to keep the dict lean.
20
+ * Default: 0.01
21
+ */
22
+ minScore?: number;
23
+ /**
24
+ * If true, also includes near-zero weights (useful for
25
+ * resetting a previously shaped face to neutral).
26
+ * Default: false
27
+ */
28
+ includeNeutral?: boolean;
29
+ }
30
+ /**
31
+ * Detect face blendshapes from a photo and return a faceShapeWeights
32
+ * dict compatible with AvatarAppearance.
33
+ *
34
+ * @param source Any image/video/canvas/bitmap element
35
+ * @param options Optional thresholds
36
+ * @returns faceShapeWeights Record<string, number>, or null if no face detected
37
+ */
38
+ export declare function faceLandmarkerToShapeWeights(source: ImageSource, options?: FaceLandmarkerOptions): Promise<FaceShapeWeights | null>;
39
+ /**
40
+ * Load the FaceLandmarker WASM bundle eagerly — call this on app start
41
+ * to avoid a cold-start delay when the user first uploads a photo.
42
+ */
43
+ export declare function prefetchFaceLandmarker(): void;
44
+ export {};
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ /**
3
+ * faceLandmarkerToShapeWeights
4
+ *
5
+ * Runs MediaPipe FaceLandmarker on a photo and returns a
6
+ * faceShapeWeights Record<string, number> ready to store in
7
+ * AvatarAppearance. Works with any GLB that has ARKit morph
8
+ * target names — mesh-agnostic, pure named floats.
9
+ *
10
+ * Lazy-loads @mediapipe/tasks-vision on first call (~3MB WASM).
11
+ * Subsequent calls reuse the same FaceLandmarker instance.
12
+ *
13
+ * Apache 2.0 — no API key, no license restrictions.
14
+ */
15
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ var desc = Object.getOwnPropertyDescriptor(m, k);
18
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
19
+ desc = { enumerable: true, get: function() { return m[k]; } };
20
+ }
21
+ Object.defineProperty(o, k2, desc);
22
+ }) : (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ o[k2] = m[k];
25
+ }));
26
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
27
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
28
+ }) : function(o, v) {
29
+ o["default"] = v;
30
+ });
31
+ var __importStar = (this && this.__importStar) || function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.prefetchFaceLandmarker = exports.faceLandmarkerToShapeWeights = void 0;
40
+ const MEDIAPIPE_CDN = 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm';
41
+ // ---------------------------------------------------------------------------
42
+ // Singleton — built once, reused across calls
43
+ // ---------------------------------------------------------------------------
44
+ let _landmarkerPromise = null;
45
+ async function getLandmarker() {
46
+ if (_landmarkerPromise)
47
+ return _landmarkerPromise;
48
+ _landmarkerPromise = (async () => {
49
+ // Dynamic import so this module is tree-shaken when unused
50
+ // @mediapipe/tasks-vision is loaded at runtime from CDN — not in node_modules.
51
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
52
+ // @ts-ignore
53
+ const vision = await Promise.resolve().then(() => __importStar(require(
54
+ /* webpackChunkName: "mediapipe-tasks-vision" */
55
+ '@mediapipe/tasks-vision')));
56
+ const { FaceLandmarker, FilesetResolver } = vision;
57
+ const filesetResolver = await FilesetResolver.forVisionTasks(MEDIAPIPE_CDN);
58
+ const landmarker = await FaceLandmarker.createFromOptions(filesetResolver, {
59
+ baseOptions: {
60
+ modelAssetPath: 'https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task',
61
+ delegate: 'GPU',
62
+ },
63
+ outputFaceBlendshapes: true,
64
+ runningMode: 'IMAGE',
65
+ numFaces: 1,
66
+ });
67
+ return landmarker;
68
+ })();
69
+ // Reset on failure so next call retries
70
+ _landmarkerPromise.catch(() => {
71
+ _landmarkerPromise = null;
72
+ });
73
+ return _landmarkerPromise;
74
+ }
75
+ /**
76
+ * Detect face blendshapes from a photo and return a faceShapeWeights
77
+ * dict compatible with AvatarAppearance.
78
+ *
79
+ * @param source Any image/video/canvas/bitmap element
80
+ * @param options Optional thresholds
81
+ * @returns faceShapeWeights Record<string, number>, or null if no face detected
82
+ */
83
+ async function faceLandmarkerToShapeWeights(source, options = {}) {
84
+ const { minScore = 0.01, includeNeutral = false } = options;
85
+ const landmarker = await getLandmarker();
86
+ const result = landmarker.detect(source);
87
+ const blendshapes = result.faceBlendshapes?.[0]?.categories;
88
+ if (!blendshapes || blendshapes.length === 0) {
89
+ return null; // No face detected
90
+ }
91
+ const weights = {};
92
+ for (const { categoryName, score } of blendshapes) {
93
+ // MediaPipe includes '_neutral' as a catch-all — skip unless requested
94
+ if (!includeNeutral && categoryName === '_neutral')
95
+ continue;
96
+ if (score < minScore)
97
+ continue;
98
+ weights[categoryName] = Math.round(score * 1000) / 1000; // 3 dp is plenty
99
+ }
100
+ return weights;
101
+ }
102
+ exports.faceLandmarkerToShapeWeights = faceLandmarkerToShapeWeights;
103
+ /**
104
+ * Load the FaceLandmarker WASM bundle eagerly — call this on app start
105
+ * to avoid a cold-start delay when the user first uploads a photo.
106
+ */
107
+ function prefetchFaceLandmarker() {
108
+ getLandmarker().catch(() => {
109
+ // Silently ignore prefetch failures — will retry on actual use
110
+ });
111
+ }
112
+ exports.prefetchFaceLandmarker = prefetchFaceLandmarker;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.convertToWav = convertToWav;
3
+ exports.convertToWav = void 0;
4
4
  /**
5
5
  * Convert any audio blob to WAV format using the Web Audio API.
6
6
  * Handles WebM/opus output from MediaRecorder without requiring ffmpeg.
@@ -19,6 +19,7 @@ async function convertToWav(audioBlob) {
19
19
  await audioContext.close();
20
20
  }
21
21
  }
22
+ exports.convertToWav = convertToWav;
22
23
  /**
23
24
  * Encode an AudioBuffer as a 16-bit PCM WAV blob.
24
25
  */
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useAudioPlayer = useAudioPlayer;
3
+ exports.useAudioPlayer = void 0;
4
4
  const react_1 = require("react");
5
5
  function useAudioPlayer({ onError, } = {}) {
6
6
  const [isPlaying, setIsPlaying] = (0, react_1.useState)(false);
@@ -62,3 +62,4 @@ function useAudioPlayer({ onError, } = {}) {
62
62
  cleanup,
63
63
  };
64
64
  }
65
+ exports.useAudioPlayer = useAudioPlayer;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useAudioRecording = useAudioRecording;
3
+ exports.useAudioRecording = void 0;
4
4
  const react_1 = require("react");
5
5
  const convertToWav_1 = require("./convertToWav");
6
6
  function useAudioRecording({ maxDurationSeconds = 29, onRecordingComplete, } = {}) {
@@ -163,3 +163,4 @@ function useAudioRecording({ maxDurationSeconds = 29, onRecordingComplete, } = {
163
163
  cancelRecording,
164
164
  };
165
165
  }
166
+ exports.useAudioRecording = useAudioRecording;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useAvatarWardrobeHydration = useAvatarWardrobeHydration;
3
+ exports.useAvatarWardrobeHydration = void 0;
4
4
  const react_1 = require("react");
5
5
  const studioApi_1 = require("../api/studioApi");
6
6
  const wardrobeStore_1 = require("./wardrobeStore");
@@ -32,3 +32,4 @@ function useAvatarWardrobeHydration({ avatarId, accessories, }) {
32
32
  };
33
33
  }, [accessorySignature, avatarId, hydrateFromApi]);
34
34
  }
35
+ exports.useAvatarWardrobeHydration = useAvatarWardrobeHydration;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "talking-head-studio",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "Cross-platform 3D avatar component for React Native & web — lip-sync, gestures, accessories, and LLM integration. Powered by TalkingHead + Three.js.",
5
5
  "main": "dist/index.web.js",
6
6
  "browser": "dist/index.web.js",
@@ -41,6 +41,11 @@
41
41
  "react-native": "./dist/filament/index.js",
42
42
  "types": "./dist/filament/index.d.ts",
43
43
  "default": "./dist/filament/index.js"
44
+ },
45
+ "./filament/editor": {
46
+ "react-native": "./dist/filament/editor/index.js",
47
+ "types": "./dist/filament/editor/index.d.ts",
48
+ "default": "./dist/filament/editor/index.js"
44
49
  }
45
50
  },
46
51
  "files": [
@@ -53,7 +58,8 @@
53
58
  "lint": "eslint 'src/**/*.{ts,tsx}'",
54
59
  "format": "prettier --write 'src/**/*.{ts,tsx}'",
55
60
  "test": "jest",
56
- "prepublishOnly": "npm run lint && npm run typecheck && npm test -- --runInBand && npm run build"
61
+ "prepublishOnly": "npm run lint && npm run typecheck && npm test -- --runInBand && npm run build",
62
+ "build:creator": "vite build --config creator-app/vite.config.ts"
57
63
  },
58
64
  "keywords": [
59
65
  "react-native",
@@ -92,6 +98,7 @@
92
98
  },
93
99
  "sideEffects": false,
94
100
  "dependencies": {
101
+ "@mediapipe/tasks-vision": "^0.10.34",
95
102
  "zustand": "^5.0.12"
96
103
  },
97
104
  "peerDependencies": {
@@ -139,27 +146,42 @@
139
146
  "@babel/core": "^7.29.0",
140
147
  "@babel/preset-env": "^7.29.0",
141
148
  "@babel/preset-typescript": "^7.28.5",
149
+ "@expo/vector-icons": "^15.1.1",
142
150
  "@react-native/babel-preset": "^0.84.1",
151
+ "@react-three/drei": "^9.122.0",
152
+ "@react-three/fiber": "^8.18.0",
143
153
  "@testing-library/react-native": "^13.3.3",
144
154
  "@types/jest": "^30.0.0",
145
155
  "@types/react": "^19.2.14",
156
+ "@types/react-dom": "^18.3.7",
146
157
  "@types/react-native": "^0.73.0",
158
+ "@types/three": "^0.180.0",
147
159
  "@typescript-eslint/eslint-plugin": "^8.56.1",
148
160
  "@typescript-eslint/parser": "^8.56.1",
161
+ "@vitejs/plugin-react": "^4.7.0",
149
162
  "babel-jest": "^30.2.0",
150
163
  "eslint": "^9.39.3",
151
164
  "eslint-config-prettier": "^10.1.8",
152
165
  "eslint-plugin-react": "^7.37.5",
153
166
  "eslint-plugin-react-hooks": "^7.0.1",
154
167
  "eslint-plugin-react-native": "^5.0.0",
168
+ "expo-haptics": "^55.0.9",
155
169
  "express": "^5.2.1",
156
170
  "jest": "^30.2.0",
157
171
  "jest-environment-jsdom": "^30.2.0",
158
172
  "metro-react-native-babel-preset": "^0.77.0",
173
+ "moti": "^0.30.0",
159
174
  "multer": "^2.1.0",
160
175
  "prettier": "^3.8.1",
176
+ "react": "^18.3.1",
177
+ "react-dom": "^18.3.1",
178
+ "react-native-gesture-handler": "^2.30.0",
179
+ "react-native-reanimated": "^4.2.3",
161
180
  "react-native-webview": "^13.16.0",
162
181
  "react-test-renderer": "^19.2.4",
163
- "ts-jest": "^29.4.6"
182
+ "three": "^0.180.0",
183
+ "ts-jest": "^29.4.6",
184
+ "typescript": "^5.3.3",
185
+ "vite": "^5.4.21"
164
186
  }
165
187
  }