talking-head-studio 0.4.9 → 0.4.11

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 (69) hide show
  1. package/README.md +227 -351
  2. package/dist/TalkingHead.d.ts +16 -25
  3. package/dist/TalkingHead.web.d.ts +6 -0
  4. package/dist/TalkingHead.web.js +18 -8
  5. package/dist/api/studioApi.js +25 -26
  6. package/dist/appearance/apply.js +2 -3
  7. package/dist/appearance/matchers.js +1 -2
  8. package/dist/appearance/schema.js +1 -2
  9. package/dist/core/avatar/backend.d.ts +130 -0
  10. package/dist/core/avatar/backend.js +4 -0
  11. package/dist/core/avatar/backends/gaussian.d.ts +49 -0
  12. package/dist/core/avatar/backends/gaussian.js +291 -0
  13. package/dist/core/avatar/backends/index.d.ts +3 -0
  14. package/dist/core/avatar/backends/index.js +7 -0
  15. package/dist/core/avatar/backends/morphTarget.d.ts +39 -0
  16. package/dist/core/avatar/backends/morphTarget.js +179 -0
  17. package/dist/core/avatar/faceControls.d.ts +40 -0
  18. package/dist/core/avatar/faceControls.js +138 -0
  19. package/dist/core/avatar/schema.d.ts +50 -0
  20. package/dist/core/avatar/schema.js +134 -0
  21. package/dist/core/avatar/visemes.d.ts +64 -0
  22. package/dist/core/avatar/visemes.js +72 -0
  23. package/dist/editor/AvatarCanvas.js +1 -2
  24. package/dist/editor/AvatarEditor.native.js +18 -9
  25. package/dist/editor/AvatarModel.js +1 -2
  26. package/dist/editor/FaceSqueezeEditor.js +19 -9
  27. package/dist/editor/FaceSqueezeEditor.web.js +2 -2
  28. package/dist/editor/RigidAccessory.js +1 -2
  29. package/dist/editor/SkinnedClothing.js +18 -9
  30. package/dist/editor/boneSnap.js +22 -12
  31. package/dist/editor/studioTheme.js +2 -2
  32. package/dist/html.js +1 -2
  33. package/dist/index.d.ts +15 -1
  34. package/dist/index.js +28 -5
  35. package/dist/platform/api/types.d.ts +10 -0
  36. package/dist/platform/api/types.js +2 -0
  37. package/dist/platform/marketplace/types.d.ts +32 -0
  38. package/dist/platform/marketplace/types.js +2 -0
  39. package/dist/platform/sdk/unity.d.ts +27 -0
  40. package/dist/platform/sdk/unity.js +2 -0
  41. package/dist/platform/sdk/unreal.d.ts +23 -0
  42. package/dist/platform/sdk/unreal.js +2 -0
  43. package/dist/platform/sdk/web.d.ts +16 -0
  44. package/dist/platform/sdk/web.js +2 -0
  45. package/dist/sketchfab/api.js +4 -5
  46. package/dist/sketchfab/useSketchfabSearch.js +1 -2
  47. package/dist/tts/useDirectVisemeStream.d.ts +2 -6
  48. package/dist/tts/useDirectVisemeStream.js +1 -2
  49. package/dist/tts/useMotionMarkers.d.ts +0 -1
  50. package/dist/tts/useMotionMarkers.js +1 -2
  51. package/dist/utils/avatarUtils.js +2 -3
  52. package/dist/utils/faceLandmarkerToShapeWeights.js +19 -10
  53. package/dist/voice/convertToWav.js +1 -2
  54. package/dist/voice/index.d.ts +3 -0
  55. package/dist/voice/index.js +6 -1
  56. package/dist/voice/useAudioPlayer.js +1 -2
  57. package/dist/voice/useAudioRecording.js +1 -2
  58. package/dist/voice/useFaceControls.d.ts +14 -0
  59. package/dist/voice/useFaceControls.js +81 -0
  60. package/dist/voice/useVoicePreview.d.ts +7 -0
  61. package/dist/voice/useVoicePreview.js +81 -0
  62. package/dist/wardrobe/index.d.ts +2 -0
  63. package/dist/wardrobe/index.js +3 -1
  64. package/dist/wardrobe/useAvatarWardrobeHydration.js +1 -2
  65. package/dist/wardrobe/useStudioAvatar.d.ts +29 -0
  66. package/dist/wardrobe/useStudioAvatar.js +177 -0
  67. package/dist/wgpu/WgpuAvatar.js +17 -7
  68. package/dist/wgpu/useAuthedModelUri.js +18 -9
  69. package/package.json +8 -4
@@ -0,0 +1,7 @@
1
+ export declare function configureVoicePreviewBaseUrl(url: string): void;
2
+ export declare function useVoicePreview(): {
3
+ activeVoiceId: string | null;
4
+ loadingVoiceId: string | null;
5
+ previewVoice: (voiceId: string) => Promise<void>;
6
+ stopPreview: () => void;
7
+ };
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configureVoicePreviewBaseUrl = configureVoicePreviewBaseUrl;
4
+ exports.useVoicePreview = useVoicePreview;
5
+ const react_1 = require("react");
6
+ const expo_audio_1 = require("expo-audio");
7
+ const studioApi_1 = require("../api/studioApi");
8
+ let _baseUrl = process.env.EXPO_PUBLIC_BACKEND_URL ?? '';
9
+ function configureVoicePreviewBaseUrl(url) {
10
+ _baseUrl = url;
11
+ }
12
+ async function fetchFirstSampleUrl(voiceId) {
13
+ const samples = await (0, studioApi_1.getVoiceProfileSamples)(voiceId);
14
+ if (!samples || samples.length === 0)
15
+ return null;
16
+ return `${_baseUrl}/samples/${samples[0].id}`;
17
+ }
18
+ function useVoicePreview() {
19
+ const playerRef = (0, react_1.useRef)(null);
20
+ const [player, setPlayer] = (0, react_1.useState)(null);
21
+ const [activeVoiceId, setActiveVoiceId] = (0, react_1.useState)(null);
22
+ const [loadingVoiceId, setLoadingVoiceId] = (0, react_1.useState)(null);
23
+ const status = (0, expo_audio_1.useAudioPlayerStatus)(player);
24
+ (0, react_1.useEffect)(() => {
25
+ if (status?.didJustFinish) {
26
+ setActiveVoiceId(null);
27
+ }
28
+ }, [status?.didJustFinish]);
29
+ const stopPreview = (0, react_1.useCallback)(() => {
30
+ if (playerRef.current) {
31
+ playerRef.current.pause();
32
+ playerRef.current.remove();
33
+ playerRef.current = null;
34
+ }
35
+ setPlayer(null);
36
+ setActiveVoiceId(null);
37
+ setLoadingVoiceId(null);
38
+ }, []);
39
+ const previewVoice = (0, react_1.useCallback)(async (voiceId) => {
40
+ if (!voiceId || loadingVoiceId === voiceId)
41
+ return;
42
+ if (activeVoiceId === voiceId) {
43
+ stopPreview();
44
+ return;
45
+ }
46
+ setLoadingVoiceId(voiceId);
47
+ stopPreview();
48
+ try {
49
+ const sampleUrl = await fetchFirstSampleUrl(voiceId);
50
+ if (!sampleUrl) {
51
+ setLoadingVoiceId(null);
52
+ return;
53
+ }
54
+ await (0, expo_audio_1.setAudioModeAsync)({
55
+ playsInSilentMode: true,
56
+ allowsRecording: false,
57
+ shouldPlayInBackground: false,
58
+ interruptionMode: 'mixWithOthers',
59
+ });
60
+ const newPlayer = (0, expo_audio_1.createAudioPlayer)(sampleUrl);
61
+ playerRef.current = newPlayer;
62
+ setPlayer(newPlayer);
63
+ newPlayer.play();
64
+ setLoadingVoiceId(null);
65
+ setActiveVoiceId(voiceId);
66
+ }
67
+ catch (err) {
68
+ console.error('[useVoicePreview] Failed to play sample:', err);
69
+ setLoadingVoiceId(null);
70
+ setActiveVoiceId(null);
71
+ }
72
+ }, [activeVoiceId, loadingVoiceId, stopPreview]);
73
+ (0, react_1.useEffect)(() => {
74
+ return () => {
75
+ playerRef.current?.pause();
76
+ playerRef.current?.remove();
77
+ playerRef.current = null;
78
+ };
79
+ }, []);
80
+ return { activeVoiceId, loadingVoiceId, previewVoice, stopPreview };
81
+ }
@@ -1,2 +1,4 @@
1
1
  export * from './wardrobeStore';
2
2
  export { useAvatarWardrobeHydration } from './useAvatarWardrobeHydration';
3
+ export { useStudioAvatar } from './useStudioAvatar';
4
+ export type { UseStudioAvatarOptions, UseStudioAvatarResult } from './useStudioAvatar';
@@ -14,7 +14,9 @@ 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.useAvatarWardrobeHydration = void 0;
17
+ exports.useStudioAvatar = exports.useAvatarWardrobeHydration = void 0;
18
18
  __exportStar(require("./wardrobeStore"), exports);
19
19
  var useAvatarWardrobeHydration_1 = require("./useAvatarWardrobeHydration");
20
20
  Object.defineProperty(exports, "useAvatarWardrobeHydration", { enumerable: true, get: function () { return useAvatarWardrobeHydration_1.useAvatarWardrobeHydration; } });
21
+ var useStudioAvatar_1 = require("./useStudioAvatar");
22
+ Object.defineProperty(exports, "useStudioAvatar", { enumerable: true, get: function () { return useStudioAvatar_1.useStudioAvatar; } });
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useAvatarWardrobeHydration = void 0;
3
+ exports.useAvatarWardrobeHydration = useAvatarWardrobeHydration;
4
4
  const react_1 = require("react");
5
5
  const studioApi_1 = require("../api/studioApi");
6
6
  const wardrobeStore_1 = require("./wardrobeStore");
@@ -32,4 +32,3 @@ function useAvatarWardrobeHydration({ avatarId, accessories, }) {
32
32
  };
33
33
  }, [accessorySignature, avatarId, hydrateFromApi, accessories]);
34
34
  }
35
- exports.useAvatarWardrobeHydration = useAvatarWardrobeHydration;
@@ -0,0 +1,29 @@
1
+ import type { Avatar } from '../api/types';
2
+ export interface UseStudioAvatarOptions {
3
+ avatarId: string;
4
+ }
5
+ export interface UseStudioAvatarResult {
6
+ avatar: Avatar | null;
7
+ loading: boolean;
8
+ error: string | null;
9
+ name: string;
10
+ setName: (name: string) => void;
11
+ description: string;
12
+ setDescription: (desc: string) => void;
13
+ isPublic: boolean;
14
+ setIsPublic: (v: boolean) => void;
15
+ hairColor: string;
16
+ setHairColor: (color: string) => void;
17
+ skinColor: string;
18
+ setSkinColor: (color: string) => void;
19
+ eyeColor: string;
20
+ setEyeColor: (color: string) => void;
21
+ voiceProfileId: string | null;
22
+ setVoiceProfileId: (id: string | null) => void;
23
+ isDirty: boolean;
24
+ saving: boolean;
25
+ save: () => Promise<void>;
26
+ revert: () => void;
27
+ reload: () => Promise<void>;
28
+ }
29
+ export declare function useStudioAvatar({ avatarId }: UseStudioAvatarOptions): UseStudioAvatarResult;
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useStudioAvatar = useStudioAvatar;
4
+ const react_1 = require("react");
5
+ const studioApi_1 = require("../api/studioApi");
6
+ const wardrobeStore_1 = require("./wardrobeStore");
7
+ const DEFAULT_HAIR_COLOR = '#4a3728';
8
+ const DEFAULT_SKIN_COLOR = '#f5d0b0';
9
+ const DEFAULT_EYE_COLOR = '#5b7553';
10
+ function extractHairColor(a) {
11
+ return a?.appearance?.hairColor ?? DEFAULT_HAIR_COLOR;
12
+ }
13
+ function extractSkinColor(a) {
14
+ return a?.appearance?.skinColor ?? DEFAULT_SKIN_COLOR;
15
+ }
16
+ function extractEyeColor(a) {
17
+ return a?.appearance?.eyeColor ?? DEFAULT_EYE_COLOR;
18
+ }
19
+ function useStudioAvatar({ avatarId }) {
20
+ const [avatar, setAvatar] = (0, react_1.useState)(null);
21
+ const [loading, setLoading] = (0, react_1.useState)(true);
22
+ const [error, setError] = (0, react_1.useState)(null);
23
+ const [saving, setSaving] = (0, react_1.useState)(false);
24
+ const [name, setName] = (0, react_1.useState)('');
25
+ const [description, setDescription] = (0, react_1.useState)('');
26
+ const [isPublic, setIsPublic] = (0, react_1.useState)(false);
27
+ const [hairColor, setHairColor] = (0, react_1.useState)(DEFAULT_HAIR_COLOR);
28
+ const [skinColor, setSkinColor] = (0, react_1.useState)(DEFAULT_SKIN_COLOR);
29
+ const [eyeColor, setEyeColor] = (0, react_1.useState)(DEFAULT_EYE_COLOR);
30
+ const [voiceProfileId, setVoiceProfileId] = (0, react_1.useState)(null);
31
+ const populateFromAvatar = (0, react_1.useCallback)((a) => {
32
+ setName(a.name);
33
+ setDescription(a.description ?? '');
34
+ setIsPublic(a.is_public);
35
+ setHairColor(extractHairColor(a));
36
+ setSkinColor(extractSkinColor(a));
37
+ setEyeColor(extractEyeColor(a));
38
+ setVoiceProfileId(a.default_voice_profile_id);
39
+ }, []);
40
+ const fetchAvatar = (0, react_1.useCallback)(async () => {
41
+ setLoading(true);
42
+ setError(null);
43
+ try {
44
+ const a = await (0, studioApi_1.getAvatar)(avatarId);
45
+ setAvatar(a);
46
+ populateFromAvatar(a);
47
+ }
48
+ catch (err) {
49
+ setError(err instanceof Error ? err.message : 'Failed to load avatar');
50
+ }
51
+ finally {
52
+ setLoading(false);
53
+ }
54
+ }, [avatarId, populateFromAvatar]);
55
+ (0, react_1.useEffect)(() => {
56
+ fetchAvatar();
57
+ }, [fetchAvatar]);
58
+ const equipped = (0, wardrobeStore_1.useWardrobeStore)((s) => s.equipped);
59
+ const placements = (0, wardrobeStore_1.useWardrobeStore)((s) => s.placements);
60
+ const isDirty = (0, react_1.useMemo)(() => {
61
+ if (!avatar)
62
+ return false;
63
+ if (name !== avatar.name)
64
+ return true;
65
+ if (description !== (avatar.description ?? ''))
66
+ return true;
67
+ if (isPublic !== avatar.is_public)
68
+ return true;
69
+ if (hairColor !== extractHairColor(avatar))
70
+ return true;
71
+ if (skinColor !== extractSkinColor(avatar))
72
+ return true;
73
+ if (eyeColor !== extractEyeColor(avatar))
74
+ return true;
75
+ if (voiceProfileId !== avatar.default_voice_profile_id)
76
+ return true;
77
+ const serialized = wardrobeStore_1.useWardrobeStore.getState().serializeForApi();
78
+ const serverAccs = avatar.appearance?.equippedAccessories ?? [];
79
+ if (serialized.length !== serverAccs.length)
80
+ return true;
81
+ for (const acc of serialized) {
82
+ const serverMatch = serverAccs.find((sa) => sa.asset_id === acc.asset_id);
83
+ if (!serverMatch)
84
+ return true;
85
+ if (serverMatch.bone !== acc.bone)
86
+ return true;
87
+ if (serverMatch.scale !== acc.scale)
88
+ return true;
89
+ if (serverMatch.position?.join(',') !== acc.position?.join(','))
90
+ return true;
91
+ if (serverMatch.rotation?.join(',') !== acc.rotation?.join(','))
92
+ return true;
93
+ }
94
+ return false;
95
+ }, [avatar, name, description, isPublic, hairColor, skinColor, eyeColor, voiceProfileId, equipped, placements]);
96
+ const save = (0, react_1.useCallback)(async () => {
97
+ if (!avatar)
98
+ return;
99
+ setSaving(true);
100
+ setError(null);
101
+ try {
102
+ const update = {};
103
+ if (name !== avatar.name)
104
+ update.name = name;
105
+ if (description !== (avatar.description ?? ''))
106
+ update.description = description;
107
+ if (isPublic !== avatar.is_public)
108
+ update.is_public = isPublic;
109
+ const equippedAccessories = wardrobeStore_1.useWardrobeStore.getState().serializeForApi();
110
+ const serverAccs = avatar.appearance?.equippedAccessories ?? [];
111
+ const accessoriesChanged = equippedAccessories.length !== serverAccs.length ||
112
+ equippedAccessories.some((acc) => {
113
+ const serverMatch = serverAccs.find((sa) => sa.asset_id === acc.asset_id);
114
+ if (!serverMatch)
115
+ return true;
116
+ if (serverMatch.bone !== acc.bone)
117
+ return true;
118
+ if (serverMatch.scale !== acc.scale)
119
+ return true;
120
+ if (serverMatch.position?.join(',') !== acc.position?.join(','))
121
+ return true;
122
+ if (serverMatch.rotation?.join(',') !== acc.rotation?.join(','))
123
+ return true;
124
+ return false;
125
+ });
126
+ if (hairColor !== extractHairColor(avatar) ||
127
+ skinColor !== extractSkinColor(avatar) ||
128
+ eyeColor !== extractEyeColor(avatar) ||
129
+ accessoriesChanged) {
130
+ const appearance = {
131
+ version: 1,
132
+ ...(hairColor ? { hairColor } : {}),
133
+ ...(skinColor ? { skinColor } : {}),
134
+ ...(eyeColor ? { eyeColor } : {}),
135
+ equippedAccessories,
136
+ };
137
+ update.appearance = appearance;
138
+ }
139
+ if (Object.keys(update).length > 0) {
140
+ await (0, studioApi_1.updateAvatar)(avatarId, update);
141
+ }
142
+ const serverVoice = avatar.default_voice_profile_id;
143
+ if (voiceProfileId !== serverVoice) {
144
+ if (voiceProfileId) {
145
+ await (0, studioApi_1.setDefaultVoice)(avatarId, voiceProfileId);
146
+ }
147
+ else {
148
+ await (0, studioApi_1.removeDefaultVoice)(avatarId);
149
+ }
150
+ }
151
+ await fetchAvatar();
152
+ }
153
+ catch (err) {
154
+ setError(err instanceof Error ? err.message : 'Failed to save avatar');
155
+ }
156
+ finally {
157
+ setSaving(false);
158
+ }
159
+ }, [avatar, avatarId, name, description, isPublic, hairColor, skinColor, eyeColor, voiceProfileId, fetchAvatar]);
160
+ const revert = (0, react_1.useCallback)(() => {
161
+ if (avatar)
162
+ populateFromAvatar(avatar);
163
+ }, [avatar, populateFromAvatar]);
164
+ return {
165
+ avatar, loading, error,
166
+ name, setName,
167
+ description, setDescription,
168
+ isPublic, setIsPublic,
169
+ hairColor, setHairColor,
170
+ skinColor, setSkinColor,
171
+ eyeColor, setEyeColor,
172
+ voiceProfileId, setVoiceProfileId,
173
+ isDirty, saving,
174
+ save, revert,
175
+ reload: fetchAvatar,
176
+ };
177
+ }
@@ -15,13 +15,23 @@ 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
36
  exports.WgpuAvatar = void 0;
27
37
  const jsx_runtime_1 = require("react/jsx-runtime");
@@ -15,15 +15,25 @@ 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.useAuthedModelUri = void 0;
36
+ exports.useAuthedModelUri = useAuthedModelUri;
27
37
  const react_1 = require("react");
28
38
  const FileSystem = __importStar(require("expo-file-system/legacy"));
29
39
  const studioApi_1 = require("../api/studioApi");
@@ -114,4 +124,3 @@ function useAuthedModelUri(remoteUrl) {
114
124
  }, [remoteUrl]);
115
125
  return result;
116
126
  }
117
- exports.useAuthedModelUri = useAuthedModelUri;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "talking-head-studio",
3
- "version": "0.4.9",
3
+ "version": "0.4.11",
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",
@@ -55,7 +55,7 @@
55
55
  "format": "prettier --write 'src/**/*.{ts,tsx}'",
56
56
  "test": "jest",
57
57
  "prepublishOnly": "npm run lint && npm run typecheck && npm test -- --runInBand && npm run build",
58
- "build:creator": "vite build --config creator-app/vite.config.ts"
58
+ "build:creator": "vite build --config packages/avatar-creator/vite.config.ts"
59
59
  },
60
60
  "keywords": [
61
61
  "react-native",
@@ -92,6 +92,9 @@
92
92
  "bugs": {
93
93
  "url": "https://github.com/sitebay/talking-head-studio/issues"
94
94
  },
95
+ "workspaces": [
96
+ "packages/*"
97
+ ],
95
98
  "sideEffects": false,
96
99
  "dependencies": {
97
100
  "@mediapipe/tasks-vision": "^0.10.34",
@@ -154,7 +157,7 @@
154
157
  "@testing-library/react-native": "^13.3.3",
155
158
  "@types/jest": "^30.0.0",
156
159
  "@types/react": "^19.2.14",
157
- "@types/react-dom": "^18.3.7",
160
+ "@types/react-dom": "^19.0.0",
158
161
  "@types/react-native": "^0.73.0",
159
162
  "@types/three": "^0.180.0",
160
163
  "@typescript-eslint/eslint-plugin": "^8.56.1",
@@ -166,6 +169,7 @@
166
169
  "eslint-plugin-react": "^7.37.5",
167
170
  "eslint-plugin-react-hooks": "^7.0.1",
168
171
  "eslint-plugin-react-native": "^5.0.0",
172
+ "expo-audio": "^55.0.9",
169
173
  "expo-haptics": "^55.0.9",
170
174
  "express": "^5.2.1",
171
175
  "jest": "^30.2.0",
@@ -183,6 +187,6 @@
183
187
  "three": "^0.180.0",
184
188
  "ts-jest": "^29.4.6",
185
189
  "typescript": "^5.3.3",
186
- "vite": "^5.4.21"
190
+ "vite": "^8.0.3"
187
191
  }
188
192
  }