talking-head-studio 0.4.10 → 0.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/README.md +299 -337
  2. package/dist/TalkingHead.d.ts +44 -28
  3. package/dist/TalkingHead.js +21 -2
  4. package/dist/TalkingHead.web.d.ts +37 -4
  5. package/dist/TalkingHead.web.js +28 -8
  6. package/dist/TalkingHeadVisualization.d.ts +22 -0
  7. package/dist/TalkingHeadVisualization.js +30 -10
  8. package/dist/api/studioApi.d.ts +12 -1
  9. package/dist/api/studioApi.js +41 -28
  10. package/dist/appearance/apply.js +2 -3
  11. package/dist/appearance/matchers.js +1 -2
  12. package/dist/appearance/schema.js +1 -2
  13. package/dist/contract.d.ts +14 -0
  14. package/dist/contract.js +30 -0
  15. package/dist/core/avatar/avatarCapabilities.d.ts +60 -0
  16. package/dist/core/avatar/avatarCapabilities.js +100 -0
  17. package/dist/core/avatar/backend.d.ts +130 -0
  18. package/dist/core/avatar/backend.js +4 -0
  19. package/dist/core/avatar/backends/gaussian.d.ts +49 -0
  20. package/dist/core/avatar/backends/gaussian.js +293 -0
  21. package/dist/core/avatar/backends/index.d.ts +3 -0
  22. package/dist/core/avatar/backends/index.js +7 -0
  23. package/dist/core/avatar/backends/morphTarget.d.ts +39 -0
  24. package/dist/core/avatar/backends/morphTarget.js +179 -0
  25. package/dist/core/avatar/faceControls.d.ts +40 -0
  26. package/dist/core/avatar/faceControls.js +138 -0
  27. package/dist/core/avatar/motion.d.ts +1713 -0
  28. package/dist/core/avatar/motion.js +550 -0
  29. package/dist/core/avatar/motionRuntime.d.ts +46 -0
  30. package/dist/core/avatar/motionRuntime.js +84 -0
  31. package/dist/core/avatar/schema.d.ts +78 -0
  32. package/dist/core/avatar/schema.js +134 -0
  33. package/dist/core/avatar/visemes.d.ts +47 -1
  34. package/dist/core/avatar/visemes.js +114 -1
  35. package/dist/editor/AvatarCanvas.js +93 -3
  36. package/dist/editor/AvatarEditor.native.js +19 -9
  37. package/dist/editor/AvatarModel.js +2 -2
  38. package/dist/editor/FaceSqueezeEditor.d.ts +3 -1
  39. package/dist/editor/FaceSqueezeEditor.js +195 -121
  40. package/dist/editor/FaceSqueezeEditor.web.d.ts +3 -1
  41. package/dist/editor/FaceSqueezeEditor.web.js +32 -30
  42. package/dist/editor/RigidAccessory.js +18 -4
  43. package/dist/editor/SkinnedClothing.js +19 -9
  44. package/dist/editor/boneLockedDrag.d.ts +11 -0
  45. package/dist/editor/boneLockedDrag.js +68 -0
  46. package/dist/editor/boneSnap.js +22 -12
  47. package/dist/editor/boneSnap.web.d.ts +27 -0
  48. package/dist/editor/boneSnap.web.js +99 -0
  49. package/dist/editor/index.web.d.ts +10 -0
  50. package/dist/editor/index.web.js +26 -0
  51. package/dist/editor/sounds/haha.wav +0 -0
  52. package/dist/editor/sounds/owie.wav +0 -0
  53. package/dist/editor/sounds/stop.wav +0 -0
  54. package/dist/editor/studioTheme.d.ts +14 -14
  55. package/dist/editor/studioTheme.js +19 -16
  56. package/dist/editor/types.d.ts +1 -0
  57. package/dist/html/accessories.d.ts +7 -0
  58. package/dist/html/accessories.js +149 -0
  59. package/dist/html/motion.d.ts +1 -0
  60. package/dist/html/motion.js +189 -0
  61. package/dist/html/visemes.d.ts +7 -0
  62. package/dist/html/visemes.js +348 -0
  63. package/dist/html.d.ts +1 -1
  64. package/dist/html.js +56 -734
  65. package/dist/index.d.ts +19 -1
  66. package/dist/index.js +44 -5
  67. package/dist/index.web.d.ts +18 -1
  68. package/dist/index.web.js +36 -3
  69. package/dist/platform/api/types.d.ts +10 -0
  70. package/dist/platform/api/types.js +2 -0
  71. package/dist/platform/marketplace/types.d.ts +32 -0
  72. package/dist/platform/marketplace/types.js +2 -0
  73. package/dist/platform/sdk/unity.d.ts +27 -0
  74. package/dist/platform/sdk/unity.js +2 -0
  75. package/dist/platform/sdk/unreal.d.ts +23 -0
  76. package/dist/platform/sdk/unreal.js +2 -0
  77. package/dist/platform/sdk/web.d.ts +16 -0
  78. package/dist/platform/sdk/web.js +2 -0
  79. package/dist/sketchfab/api.js +5 -5
  80. package/dist/sketchfab/glbInspect.d.ts +22 -0
  81. package/dist/sketchfab/glbInspect.js +58 -0
  82. package/dist/sketchfab/index.d.ts +3 -0
  83. package/dist/sketchfab/index.js +8 -1
  84. package/dist/sketchfab/inspectRemote.d.ts +13 -0
  85. package/dist/sketchfab/inspectRemote.js +77 -0
  86. package/dist/sketchfab/types.d.ts +10 -0
  87. package/dist/sketchfab/useSketchfabSearch.js +1 -2
  88. package/dist/studio/AccessoryBrowserScreen.d.ts +6 -0
  89. package/dist/studio/AccessoryBrowserScreen.js +626 -0
  90. package/dist/studio/AccessoryPanel.d.ts +10 -0
  91. package/dist/studio/AccessoryPanel.js +396 -0
  92. package/dist/studio/AppearancePanel.d.ts +9 -0
  93. package/dist/studio/AppearancePanel.js +77 -0
  94. package/dist/studio/AvatarCreatorScreen.d.ts +5 -0
  95. package/dist/studio/AvatarCreatorScreen.js +806 -0
  96. package/dist/studio/AvatarEditorScreen.d.ts +14 -0
  97. package/dist/studio/AvatarEditorScreen.js +510 -0
  98. package/dist/studio/AvatarGrid.d.ts +23 -0
  99. package/dist/studio/AvatarGrid.js +257 -0
  100. package/dist/studio/ColorSwatch.d.ts +8 -0
  101. package/dist/studio/ColorSwatch.js +100 -0
  102. package/dist/studio/CreateVoiceProfileSheet.d.ts +8 -0
  103. package/dist/studio/CreateVoiceProfileSheet.js +242 -0
  104. package/dist/studio/DetailsPanel.d.ts +15 -0
  105. package/dist/studio/DetailsPanel.js +239 -0
  106. package/dist/studio/FilamentEditor.d.ts +2 -0
  107. package/dist/studio/FilamentEditor.js +6 -0
  108. package/dist/studio/PrecisionPanel.d.ts +2 -0
  109. package/dist/studio/PrecisionPanel.js +7 -0
  110. package/dist/studio/PublicGalleryScreen.d.ts +5 -0
  111. package/dist/studio/PublicGalleryScreen.js +358 -0
  112. package/dist/studio/SketchfabModelCard.d.ts +20 -0
  113. package/dist/studio/SketchfabModelCard.js +104 -0
  114. package/dist/studio/StudioBrowseHeader.d.ts +9 -0
  115. package/dist/studio/StudioBrowseHeader.js +28 -0
  116. package/dist/studio/StudioEmptyState.d.ts +8 -0
  117. package/dist/studio/StudioEmptyState.js +29 -0
  118. package/dist/studio/StudioFloatingAction.d.ts +13 -0
  119. package/dist/studio/StudioFloatingAction.js +42 -0
  120. package/dist/studio/StudioSectionHeader.d.ts +7 -0
  121. package/dist/studio/StudioSectionHeader.js +27 -0
  122. package/dist/studio/StudioSurfaceCard.d.ts +8 -0
  123. package/dist/studio/StudioSurfaceCard.js +20 -0
  124. package/dist/studio/VoicePanel.d.ts +15 -0
  125. package/dist/studio/VoicePanel.js +305 -0
  126. package/dist/studio/constants.d.ts +3 -0
  127. package/dist/studio/constants.js +6 -0
  128. package/dist/studio/index.d.ts +29 -0
  129. package/dist/studio/index.js +54 -0
  130. package/dist/studio/useSketchfabCapabilities.d.ts +31 -0
  131. package/dist/studio/useSketchfabCapabilities.js +82 -0
  132. package/dist/tts/useDirectVisemeStream.d.ts +2 -6
  133. package/dist/tts/useDirectVisemeStream.js +16 -12
  134. package/dist/tts/useMotionMarkers.d.ts +0 -1
  135. package/dist/tts/useMotionMarkers.js +1 -2
  136. package/dist/utils/avatarUtils.js +94 -8
  137. package/dist/utils/faceLandmarkerToShapeWeights.js +21 -14
  138. package/dist/voice/convertToWav.js +1 -2
  139. package/dist/voice/index.d.ts +3 -0
  140. package/dist/voice/index.js +6 -1
  141. package/dist/voice/useAudioPlayer.js +18 -6
  142. package/dist/voice/useAudioRecording.js +1 -2
  143. package/dist/voice/useFaceControls.d.ts +14 -0
  144. package/dist/voice/useFaceControls.js +81 -0
  145. package/dist/voice/useVoicePreview.d.ts +7 -0
  146. package/dist/voice/useVoicePreview.js +83 -0
  147. package/dist/wardrobe/index.d.ts +3 -0
  148. package/dist/wardrobe/index.js +8 -1
  149. package/dist/wardrobe/useAccessoryGestures.d.ts +20 -0
  150. package/dist/wardrobe/useAccessoryGestures.js +94 -0
  151. package/dist/wardrobe/useAvatarWardrobeHydration.js +9 -4
  152. package/dist/wardrobe/useStudioAvatar.d.ts +29 -0
  153. package/dist/wardrobe/useStudioAvatar.js +186 -0
  154. package/dist/wardrobe/wardrobeStore.d.ts +2 -0
  155. package/dist/wardrobe/wardrobeStore.js +12 -2
  156. package/dist/wgpu/R3FWebGpuCanvas.d.ts +15 -0
  157. package/dist/wgpu/R3FWebGpuCanvas.js +176 -0
  158. package/dist/wgpu/WgpuAvatar.d.ts +26 -2
  159. package/dist/wgpu/WgpuAvatar.js +313 -46
  160. package/dist/wgpu/accessoryDefaults.d.ts +12 -0
  161. package/dist/wgpu/accessoryDefaults.js +19 -0
  162. package/dist/wgpu/blobShim.d.ts +2 -0
  163. package/dist/wgpu/blobShim.js +191 -0
  164. package/dist/wgpu/index.d.ts +1 -0
  165. package/dist/wgpu/index.js +4 -1
  166. package/dist/wgpu/loadGLTFFromUri.d.ts +2 -0
  167. package/dist/wgpu/loadGLTFFromUri.js +75 -0
  168. package/dist/wgpu/morphTables.js +21 -10
  169. package/dist/wgpu/motionState.d.ts +20 -0
  170. package/dist/wgpu/motionState.js +31 -0
  171. package/dist/wgpu/patchThreeForRN.d.ts +28 -0
  172. package/dist/wgpu/patchThreeForRN.js +292 -0
  173. package/dist/wgpu/scenePlacement.d.ts +5 -0
  174. package/dist/wgpu/scenePlacement.js +50 -0
  175. package/dist/wgpu/useAuthedModelUri.js +22 -11
  176. package/dist/wgpu/useNativeGLTF.d.ts +7 -0
  177. package/dist/wgpu/useNativeGLTF.js +36 -0
  178. package/package.json +102 -32
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SketchfabModelCard = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const react_1 = __importDefault(require("react"));
9
+ const react_native_1 = require("react-native");
10
+ const expo_image_1 = require("expo-image");
11
+ const vector_icons_1 = require("@expo/vector-icons");
12
+ const moti_1 = require("moti");
13
+ const sketchfab_1 = require("../sketchfab");
14
+ const constants_1 = require("./constants");
15
+ const editor_1 = require("../editor");
16
+ const COLORS = editor_1.studioTheme.colors;
17
+ function formatCount(n) {
18
+ if (n >= 1000000)
19
+ return `${(n / 1000000).toFixed(1)}M`;
20
+ if (n >= 1000)
21
+ return `${(n / 1000).toFixed(1)}k`;
22
+ return String(n);
23
+ }
24
+ const HUMANOID_TAGS = [
25
+ 'character', 'humanoid', 'human', 'anime', 'avatar',
26
+ 'person', 'figure', 'girl', 'boy', 'woman', 'man',
27
+ ];
28
+ function isHumanoidModel(model) {
29
+ return model.tags.some((t) => HUMANOID_TAGS.includes(t.slug.toLowerCase()));
30
+ }
31
+ exports.SketchfabModelCard = react_1.default.memo(function SketchfabModelCard({ model, index, onPress, showHumanoidBadge = false, capability = null, }) {
32
+ const thumbnailUrl = (0, sketchfab_1.getBestThumbnail)(model.thumbnails, 280) || undefined;
33
+ const delay = Math.min(index * 60, 600);
34
+ return ((0, jsx_runtime_1.jsx)(moti_1.MotiView, { from: { opacity: 0, translateY: 20 }, animate: { opacity: 1, translateY: 0 }, transition: { type: 'timing', duration: 400, delay }, style: styles.cardOuter, children: (0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { activeOpacity: 0.7, onPress: () => onPress(model), style: styles.card, children: [thumbnailUrl ? ((0, jsx_runtime_1.jsx)(expo_image_1.Image, { source: { uri: thumbnailUrl }, style: styles.thumbnail, contentFit: "cover", placeholder: { blurhash: constants_1.BLURHASH }, transition: 250, cachePolicy: "memory-disk", recyclingKey: model.uid })) : ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.thumbnailPlaceholder, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.placeholderText, children: "3D" }) })), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.badgeRow, children: [capability === 'ready' && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [styles.badge, styles.readyBadge], children: [(0, jsx_runtime_1.jsx)(vector_icons_1.Ionicons, { name: "checkmark-circle", size: 10, color: "#48c98a" }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.badgeText, styles.readyBadgeText], children: "Ready" })] })), capability === 'lipsync' && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [styles.badge, styles.verifiedBadge], children: [(0, jsx_runtime_1.jsx)(vector_icons_1.Ionicons, { name: "checkmark-circle", size: 10, color: "#4da3ff" }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.badgeText, styles.verifiedBadgeText], children: "Lipsync" })] })), capability === 'limited' && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [styles.badge, styles.limitedBadge], children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.badgeText, styles.limitedBadgeText], children: "Limited" }) })), capability === 'checking' && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [styles.badge, styles.checkingBadge], children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.badgeText, styles.checkingBadgeText], children: "Checking\u2026" }) })), showHumanoidBadge && isHumanoidModel(model) && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.badge, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.badgeText, children: "Humanoid" }) })), model.animationCount > 0 && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [styles.badge, styles.animatedBadge], children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.badgeText, children: "Animated" }) }))] }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.cardName, numberOfLines: 1, children: model.name }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.cardStats, children: [(0, jsx_runtime_1.jsx)(vector_icons_1.Ionicons, { name: "heart", size: 11, color: COLORS.textMuted }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.cardStatText, children: formatCount(model.likeCount) }), (0, jsx_runtime_1.jsx)(vector_icons_1.Ionicons, { name: "eye", size: 11, color: COLORS.textMuted, style: { marginLeft: 6 } }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.cardStatText, children: formatCount(model.viewCount) })] }), (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: styles.cardCreator, numberOfLines: 1, children: ["by ", model.user.displayName || model.user.username] })] }) }));
35
+ });
36
+ const styles = react_native_1.StyleSheet.create({
37
+ cardOuter: { flex: 1, marginHorizontal: 6, marginBottom: 12 },
38
+ card: {
39
+ borderRadius: 16,
40
+ borderWidth: 1,
41
+ borderColor: COLORS.border,
42
+ backgroundColor: COLORS.surfaceRaised,
43
+ overflow: 'hidden',
44
+ padding: 10,
45
+ gap: 6,
46
+ shadowColor: '#000',
47
+ shadowOffset: { width: 0, height: 2 },
48
+ shadowOpacity: 0.25,
49
+ shadowRadius: 4,
50
+ elevation: 4,
51
+ },
52
+ thumbnail: {
53
+ width: '100%',
54
+ aspectRatio: 1,
55
+ borderRadius: 12,
56
+ backgroundColor: COLORS.backgroundAlt,
57
+ },
58
+ thumbnailPlaceholder: {
59
+ width: '100%',
60
+ aspectRatio: 1,
61
+ borderRadius: 12,
62
+ backgroundColor: COLORS.backgroundAlt,
63
+ alignItems: 'center',
64
+ justifyContent: 'center',
65
+ },
66
+ placeholderText: {
67
+ color: COLORS.textMuted,
68
+ fontSize: 22,
69
+ fontWeight: '700',
70
+ letterSpacing: 2,
71
+ },
72
+ badgeRow: { flexDirection: 'row', flexWrap: 'wrap', gap: 4 },
73
+ badge: {
74
+ paddingHorizontal: 6,
75
+ paddingVertical: 2,
76
+ borderRadius: 6,
77
+ backgroundColor: 'rgba(255, 122, 89, 0.14)',
78
+ },
79
+ animatedBadge: { backgroundColor: 'rgba(100, 200, 100, 0.14)' },
80
+ verifiedBadge: {
81
+ backgroundColor: 'rgba(77, 163, 255, 0.14)',
82
+ flexDirection: 'row',
83
+ alignItems: 'center',
84
+ gap: 3,
85
+ },
86
+ verifiedBadgeText: { color: '#4da3ff' },
87
+ readyBadge: {
88
+ backgroundColor: 'rgba(72, 201, 138, 0.16)',
89
+ flexDirection: 'row',
90
+ alignItems: 'center',
91
+ gap: 3,
92
+ },
93
+ readyBadgeText: { color: '#48c98a' },
94
+ limitedBadge: { backgroundColor: 'rgba(255, 255, 255, 0.08)' },
95
+ limitedBadgeText: { color: COLORS.textMuted },
96
+ checkingBadge: { backgroundColor: 'rgba(255, 255, 255, 0.06)' },
97
+ checkingBadgeText: { color: COLORS.textMuted },
98
+ badgeText: { color: COLORS.accent, fontSize: 9, fontWeight: '700' },
99
+ cardName: { color: COLORS.textPrimary, fontSize: 13, fontWeight: '600', textAlign: 'center', marginTop: 2 },
100
+ cardStats: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center' },
101
+ cardStatText: { color: COLORS.textMuted, fontSize: 11, marginLeft: 3 },
102
+ cardCreator: { color: COLORS.textMuted, fontSize: 10, textAlign: 'center' },
103
+ });
104
+ exports.default = exports.SketchfabModelCard;
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ interface StudioBrowseHeaderProps {
3
+ eyebrow?: string;
4
+ title: string;
5
+ subtitle?: string;
6
+ children?: React.ReactNode;
7
+ }
8
+ export declare function StudioBrowseHeader({ eyebrow, title, subtitle, children, }: StudioBrowseHeaderProps): import("react/jsx-runtime").JSX.Element;
9
+ export default StudioBrowseHeader;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StudioBrowseHeader = StudioBrowseHeader;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_native_1 = require("react-native");
6
+ const StudioSectionHeader_1 = require("./StudioSectionHeader");
7
+ const StudioSurfaceCard_1 = require("./StudioSurfaceCard");
8
+ const editor_1 = require("../editor");
9
+ function StudioBrowseHeader({ eyebrow, title, subtitle, children, }) {
10
+ return ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.shell, children: (0, jsx_runtime_1.jsxs)(StudioSurfaceCard_1.StudioSurfaceCard, { style: styles.card, children: [(0, jsx_runtime_1.jsx)(StudioSectionHeader_1.StudioSectionHeader, { eyebrow: eyebrow, title: title, subtitle: subtitle }), children ? (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.content, children: children }) : null] }) }));
11
+ }
12
+ const styles = react_native_1.StyleSheet.create({
13
+ shell: {
14
+ paddingHorizontal: editor_1.studioTheme.spacing.md,
15
+ paddingTop: editor_1.studioTheme.spacing.sm,
16
+ paddingBottom: editor_1.studioTheme.spacing.md,
17
+ },
18
+ card: {
19
+ backgroundColor: editor_1.studioTheme.colors.surfaceRaised,
20
+ borderColor: editor_1.studioTheme.colors.borderStrong,
21
+ gap: editor_1.studioTheme.spacing.md,
22
+ overflow: 'hidden',
23
+ },
24
+ content: {
25
+ gap: editor_1.studioTheme.spacing.md,
26
+ },
27
+ });
28
+ exports.default = StudioBrowseHeader;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ interface StudioEmptyStateProps {
3
+ icon?: React.ReactNode;
4
+ title: string;
5
+ subtitle?: string;
6
+ }
7
+ export declare function StudioEmptyState({ icon, title, subtitle, }: StudioEmptyStateProps): import("react/jsx-runtime").JSX.Element;
8
+ export default StudioEmptyState;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StudioEmptyState = StudioEmptyState;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_native_1 = require("react-native");
6
+ const editor_1 = require("../editor");
7
+ function StudioEmptyState({ icon, title, subtitle, }) {
8
+ return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.container, children: [icon, (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.title, children: title }), subtitle ? (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.subtitle, children: subtitle }) : null] }));
9
+ }
10
+ const styles = react_native_1.StyleSheet.create({
11
+ container: {
12
+ alignItems: 'center',
13
+ justifyContent: 'center',
14
+ paddingHorizontal: editor_1.studioTheme.spacing.xl,
15
+ paddingVertical: editor_1.studioTheme.spacing.xxl,
16
+ gap: editor_1.studioTheme.spacing.sm,
17
+ },
18
+ title: {
19
+ color: editor_1.studioTheme.colors.textPrimary,
20
+ textAlign: 'center',
21
+ ...editor_1.studioTheme.type.sectionTitle,
22
+ },
23
+ subtitle: {
24
+ color: editor_1.studioTheme.colors.textSecondary,
25
+ textAlign: 'center',
26
+ ...editor_1.studioTheme.type.body,
27
+ },
28
+ });
29
+ exports.default = StudioEmptyState;
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { type StyleProp, type ViewStyle } from 'react-native';
3
+ interface StudioFloatingActionProps {
4
+ children: React.ReactNode;
5
+ onPress?: () => void;
6
+ disabled?: boolean;
7
+ bottomInset?: number;
8
+ clearance?: number;
9
+ style?: StyleProp<ViewStyle>;
10
+ testID?: string;
11
+ }
12
+ export declare function StudioFloatingAction({ children, onPress, disabled, bottomInset, clearance, style, testID, }: StudioFloatingActionProps): import("react/jsx-runtime").JSX.Element;
13
+ export default StudioFloatingAction;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StudioFloatingAction = StudioFloatingAction;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_native_1 = require("react-native");
6
+ const editor_1 = require("../editor");
7
+ function StudioFloatingAction({ children, onPress, disabled = false, bottomInset = 0, clearance = 28, style, testID, }) {
8
+ return ((0, jsx_runtime_1.jsx)(react_native_1.View, { pointerEvents: "box-none", testID: "studio-floating-action-shell", style: [styles.shell, { paddingBottom: bottomInset + clearance }], children: (0, jsx_runtime_1.jsx)(react_native_1.Pressable, { accessibilityRole: "button", disabled: disabled, onPress: onPress, testID: testID, style: ({ pressed }) => [
9
+ styles.button,
10
+ disabled && styles.buttonDisabled,
11
+ pressed && !disabled && styles.buttonPressed,
12
+ style,
13
+ ], children: children }) }));
14
+ }
15
+ const styles = react_native_1.StyleSheet.create({
16
+ shell: {
17
+ position: 'absolute',
18
+ left: editor_1.studioTheme.spacing.lg,
19
+ right: editor_1.studioTheme.spacing.lg,
20
+ bottom: 0,
21
+ alignItems: 'flex-end',
22
+ pointerEvents: 'box-none',
23
+ },
24
+ button: {
25
+ minHeight: 60,
26
+ minWidth: 60,
27
+ borderRadius: editor_1.studioTheme.radius.pill,
28
+ backgroundColor: editor_1.studioTheme.colors.accent,
29
+ justifyContent: 'center',
30
+ alignItems: 'center',
31
+ paddingHorizontal: editor_1.studioTheme.spacing.lg,
32
+ ...editor_1.studioTheme.shadow.glow,
33
+ },
34
+ buttonPressed: {
35
+ transform: [{ scale: 0.97 }],
36
+ backgroundColor: editor_1.studioTheme.colors.accentStrong,
37
+ },
38
+ buttonDisabled: {
39
+ opacity: 0.45,
40
+ },
41
+ });
42
+ exports.default = StudioFloatingAction;
@@ -0,0 +1,7 @@
1
+ interface StudioSectionHeaderProps {
2
+ eyebrow?: string;
3
+ title: string;
4
+ subtitle?: string;
5
+ }
6
+ export declare function StudioSectionHeader({ eyebrow, title, subtitle, }: StudioSectionHeaderProps): import("react/jsx-runtime").JSX.Element;
7
+ export default StudioSectionHeader;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StudioSectionHeader = StudioSectionHeader;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_native_1 = require("react-native");
6
+ const editor_1 = require("../editor");
7
+ function StudioSectionHeader({ eyebrow, title, subtitle, }) {
8
+ return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.container, children: [eyebrow ? (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.eyebrow, children: eyebrow }) : null, (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.title, children: title }), subtitle ? (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.subtitle, children: subtitle }) : null] }));
9
+ }
10
+ const styles = react_native_1.StyleSheet.create({
11
+ container: {
12
+ gap: editor_1.studioTheme.spacing.xs,
13
+ },
14
+ eyebrow: {
15
+ color: editor_1.studioTheme.colors.textSecondary,
16
+ ...editor_1.studioTheme.type.eyebrow,
17
+ },
18
+ title: {
19
+ color: editor_1.studioTheme.colors.textPrimary,
20
+ ...editor_1.studioTheme.type.sectionTitle,
21
+ },
22
+ subtitle: {
23
+ color: editor_1.studioTheme.colors.textSecondary,
24
+ ...editor_1.studioTheme.type.body,
25
+ },
26
+ });
27
+ exports.default = StudioSectionHeader;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { type StyleProp, type ViewStyle } from 'react-native';
3
+ interface StudioSurfaceCardProps {
4
+ children: React.ReactNode;
5
+ style?: StyleProp<ViewStyle>;
6
+ }
7
+ export declare function StudioSurfaceCard({ children, style }: StudioSurfaceCardProps): import("react/jsx-runtime").JSX.Element;
8
+ export default StudioSurfaceCard;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StudioSurfaceCard = StudioSurfaceCard;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_native_1 = require("react-native");
6
+ const editor_1 = require("../editor");
7
+ function StudioSurfaceCard({ children, style }) {
8
+ return (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [styles.card, style], children: children });
9
+ }
10
+ const styles = react_native_1.StyleSheet.create({
11
+ card: {
12
+ borderRadius: editor_1.studioTheme.radius.md,
13
+ borderWidth: 1,
14
+ borderColor: editor_1.studioTheme.colors.border,
15
+ backgroundColor: editor_1.studioTheme.colors.surface,
16
+ padding: editor_1.studioTheme.spacing.md,
17
+ ...editor_1.studioTheme.shadow.card,
18
+ },
19
+ });
20
+ exports.default = StudioSurfaceCard;
@@ -0,0 +1,15 @@
1
+ interface VoicePanelProps {
2
+ activeVoiceId: string | null;
3
+ onSelectVoice: (id: string | null) => void;
4
+ /**
5
+ * Optional preview override. When provided, tapping a voice's preview calls
6
+ * this instead of the built-in audio-only sample player — letting a host
7
+ * route the preview through a live avatar for real lip-sync. Receives the
8
+ * voice profile id; should return a promise that resolves when started.
9
+ */
10
+ onPreviewVoice?: (voiceId: string) => Promise<void> | void;
11
+ /** Voice id currently previewing, when the host owns preview state. */
12
+ previewingVoiceId?: string | null;
13
+ }
14
+ export default function VoicePanel({ activeVoiceId, onSelectVoice, onPreviewVoice, previewingVoiceId }: VoicePanelProps): import("react/jsx-runtime").JSX.Element;
15
+ export {};
@@ -0,0 +1,305 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.default = VoicePanel;
40
+ const jsx_runtime_1 = require("react/jsx-runtime");
41
+ const vector_icons_1 = require("@expo/vector-icons");
42
+ const Haptics = __importStar(require("expo-haptics"));
43
+ const react_1 = require("react");
44
+ const react_native_1 = require("react-native");
45
+ const react_native_reanimated_1 = __importStar(require("react-native-reanimated"));
46
+ const api_1 = require("../api");
47
+ const useVoicePreview_1 = require("../voice/useVoicePreview");
48
+ const CreateVoiceProfileSheet_1 = __importDefault(require("./CreateVoiceProfileSheet"));
49
+ const editor_1 = require("../editor");
50
+ const AnimatedPressable = react_native_reanimated_1.default.createAnimatedComponent(react_native_1.Pressable);
51
+ const VoiceCard = ({ profile, isActive, onPress, previewState, onPreview, }) => {
52
+ const scale = (0, react_native_reanimated_1.useSharedValue)(1);
53
+ const isNoVoice = profile === null;
54
+ const isPreviewLoading = previewState === 'loading';
55
+ const isPreviewActive = previewState === 'playing';
56
+ const animatedStyle = (0, react_native_reanimated_1.useAnimatedStyle)(() => {
57
+ return {
58
+ transform: [{ scale: scale.value }],
59
+ borderColor: (0, react_native_reanimated_1.withTiming)(isPreviewActive || isActive ? editor_1.studioTheme.colors.accent : editor_1.studioTheme.colors.border, { duration: 250 }),
60
+ backgroundColor: (0, react_native_reanimated_1.withTiming)(isPreviewActive || isActive
61
+ ? editor_1.studioTheme.colors.accentMuted
62
+ : editor_1.studioTheme.colors.surfaceRaised, { duration: 250 }),
63
+ };
64
+ });
65
+ const handlePressIn = () => {
66
+ scale.value = (0, react_native_reanimated_1.withSpring)(0.97, { damping: 15, stiffness: 200 });
67
+ };
68
+ const handlePressOut = () => {
69
+ scale.value = (0, react_native_reanimated_1.withSpring)(1, { damping: 15, stiffness: 200 });
70
+ };
71
+ return ((0, jsx_runtime_1.jsxs)(AnimatedPressable, { onPress: () => {
72
+ void Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
73
+ onPress();
74
+ }, onPressIn: handlePressIn, onPressOut: handlePressOut, style: [styles.card, animatedStyle], children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.cardHeader, children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.cardTitleRow, children: [isNoVoice ? ((0, jsx_runtime_1.jsx)(vector_icons_1.Ionicons, { name: "mic-off", size: 20, color: isActive ? editor_1.studioTheme.colors.accent : editor_1.studioTheme.colors.textMuted, style: styles.icon })) : ((0, jsx_runtime_1.jsx)(vector_icons_1.Ionicons, { name: "mic", size: 20, color: isPreviewActive || isActive
75
+ ? editor_1.studioTheme.colors.accent
76
+ : editor_1.studioTheme.colors.textPrimary, style: styles.icon })), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.name, isNoVoice && styles.mutedText, isActive && styles.activeText], children: isNoVoice ? 'No Default Voice' : profile.name })] }), !isNoVoice && ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: (e) => {
77
+ e.stopPropagation();
78
+ void Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
79
+ onPreview();
80
+ }, style: [
81
+ styles.playButton,
82
+ isPreviewActive && styles.playButtonActive,
83
+ isPreviewLoading && styles.playButtonLoading,
84
+ ], children: isPreviewLoading ? ((0, jsx_runtime_1.jsx)(react_native_1.ActivityIndicator, { size: "small", color: editor_1.studioTheme.colors.textPrimary })) : ((0, jsx_runtime_1.jsx)(vector_icons_1.Ionicons, { name: isPreviewActive ? 'stop-circle-outline' : 'play-circle-outline', size: 24, color: isPreviewActive || isActive
85
+ ? editor_1.studioTheme.colors.textPrimary
86
+ : editor_1.studioTheme.colors.textSecondary })) })), isActive && ((0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.View, { entering: react_native_reanimated_1.FadeIn.duration(200), exiting: react_native_reanimated_1.FadeOut.duration(200), children: (0, jsx_runtime_1.jsx)(vector_icons_1.Ionicons, { name: "checkmark-circle", size: 22, color: editor_1.studioTheme.colors.accent }) }))] }), !isNoVoice && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.detailsRow, children: [profile.language && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [styles.badge, isActive && styles.activeBadge], children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.badgeText, isActive && styles.activeBadgeText], children: profile.language.toUpperCase() }) })), isPreviewLoading ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.previewStateText, children: "Loading sample..." })) : isPreviewActive ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.previewStateText, children: "Previewing sample..." })) : null, profile.description && ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.description, isActive && styles.activeDescription], numberOfLines: 2, children: profile.description }))] }))] }));
87
+ };
88
+ function VoicePanel({ activeVoiceId, onSelectVoice, onPreviewVoice, previewingVoiceId }) {
89
+ const [voices, setVoices] = (0, react_1.useState)([]);
90
+ const [isLoading, setIsLoading] = (0, react_1.useState)(true);
91
+ const [error, setError] = (0, react_1.useState)(null);
92
+ const sheetRef = (0, react_1.useRef)(null);
93
+ const { activeVoiceId: builtinPreviewVoiceId, loadingVoiceId, previewVoice } = (0, useVoicePreview_1.useVoicePreview)();
94
+ // When the host supplies onPreviewVoice it owns preview playback (and the
95
+ // "playing" state via previewingVoiceId); otherwise fall back to the built-in
96
+ // audio-only sample preview.
97
+ const previewVoiceId = onPreviewVoice ? (previewingVoiceId ?? null) : builtinPreviewVoiceId;
98
+ const refreshVoices = (0, react_1.useCallback)(async (signal) => {
99
+ const data = await (0, api_1.getVoiceProfiles)();
100
+ if (!signal?.aborted) {
101
+ setVoices(data || []);
102
+ }
103
+ }, []);
104
+ const loadVoices = (0, react_1.useCallback)(async (signal) => {
105
+ try {
106
+ setIsLoading(true);
107
+ setError(null);
108
+ await refreshVoices(signal);
109
+ }
110
+ catch (err) {
111
+ if (!signal?.aborted) {
112
+ console.error('Failed to load voice profiles', err);
113
+ setError('Failed to fetch voices. Please try again later.');
114
+ }
115
+ }
116
+ finally {
117
+ if (!signal?.aborted)
118
+ setIsLoading(false);
119
+ }
120
+ }, [refreshVoices]);
121
+ (0, react_1.useEffect)(() => {
122
+ const controller = new AbortController();
123
+ void loadVoices(controller.signal);
124
+ return () => controller.abort();
125
+ }, [loadVoices]);
126
+ const renderItem = ({ item }) => {
127
+ const isActive = item === null ? activeVoiceId === null : item.id === activeVoiceId;
128
+ const previewState = !item?.id
129
+ ? 'idle'
130
+ : loadingVoiceId === item.id
131
+ ? 'loading'
132
+ : previewVoiceId === item.id
133
+ ? 'playing'
134
+ : 'idle';
135
+ return ((0, jsx_runtime_1.jsx)(VoiceCard, { profile: item, isActive: isActive, onPress: () => onSelectVoice(item ? item.id : null), previewState: previewState, onPreview: () => {
136
+ if (!item?.id)
137
+ return;
138
+ const run = onPreviewVoice ? onPreviewVoice(item.id) : previewVoice(item.id);
139
+ Promise.resolve(run).catch((err) => console.warn('[VoicePanel] Preview failed:', err));
140
+ } }));
141
+ };
142
+ const listData = [null, ...voices];
143
+ if (isLoading) {
144
+ return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.centerContainer, children: [(0, jsx_runtime_1.jsx)(react_native_1.ActivityIndicator, { size: "large", color: editor_1.studioTheme.colors.accent }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.loadingText, children: "Synthesizing voices..." })] }));
145
+ }
146
+ if (error) {
147
+ return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.centerContainer, children: [(0, jsx_runtime_1.jsx)(vector_icons_1.Ionicons, { name: "alert-circle-outline", size: 36, color: editor_1.studioTheme.colors.danger, style: { marginBottom: 12 } }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.errorText, children: error }), (0, jsx_runtime_1.jsx)(react_native_1.Pressable, { style: styles.retryButton, onPress: () => loadVoices(), children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.retryButtonText, children: "Retry" }) })] }));
148
+ }
149
+ return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.container, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.sectionTitle, children: "DEFAULT VOICE" }), voices.length === 0 && ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.emptyStateText, children: "You don't have any voice profiles yet." })), (0, jsx_runtime_1.jsx)(react_native_1.FlatList, { data: listData, keyExtractor: (item) => (item ? item.id : 'no-voice'), renderItem: renderItem, contentContainerStyle: styles.listContent, showsVerticalScrollIndicator: false }), (0, jsx_runtime_1.jsxs)(react_native_1.Pressable, { style: styles.cloneButton, onPress: () => sheetRef.current?.expand(), children: [(0, jsx_runtime_1.jsx)(vector_icons_1.Ionicons, { name: "add-circle", size: 20, color: "#fff" }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.cloneButtonText, children: "Clone Voice Profile" })] }), (0, jsx_runtime_1.jsx)(CreateVoiceProfileSheet_1.default, { sheetRef: sheetRef, onSuccess: () => refreshVoices().catch((err) => console.warn('[VoicePanel] Refresh failed:', err)) })] }));
150
+ }
151
+ const styles = react_native_1.StyleSheet.create({
152
+ container: {
153
+ flex: 1,
154
+ paddingVertical: 16,
155
+ },
156
+ centerContainer: {
157
+ flex: 1,
158
+ justifyContent: 'center',
159
+ alignItems: 'center',
160
+ padding: 24,
161
+ },
162
+ sectionTitle: {
163
+ color: editor_1.studioTheme.colors.textSecondary,
164
+ fontSize: 12,
165
+ fontWeight: '700',
166
+ letterSpacing: 1.2,
167
+ textTransform: 'uppercase',
168
+ paddingHorizontal: 16,
169
+ marginBottom: 8,
170
+ },
171
+ emptyStateText: {
172
+ paddingHorizontal: 16,
173
+ paddingTop: 8,
174
+ color: editor_1.studioTheme.colors.textMuted,
175
+ fontSize: 14,
176
+ fontStyle: 'italic',
177
+ },
178
+ listContent: {
179
+ paddingVertical: 8,
180
+ paddingHorizontal: 16,
181
+ gap: 12,
182
+ },
183
+ card: {
184
+ borderRadius: 16,
185
+ borderWidth: 1,
186
+ padding: 18,
187
+ marginBottom: 12,
188
+ },
189
+ cardHeader: {
190
+ flexDirection: 'row',
191
+ justifyContent: 'space-between',
192
+ alignItems: 'center',
193
+ },
194
+ playButton: { marginLeft: 'auto', marginRight: 12, padding: 4 },
195
+ playButtonActive: {
196
+ borderRadius: 999,
197
+ backgroundColor: editor_1.studioTheme.colors.accent,
198
+ },
199
+ playButtonLoading: {
200
+ borderRadius: 999,
201
+ backgroundColor: editor_1.studioTheme.colors.surfaceSoft,
202
+ },
203
+ cardTitleRow: {
204
+ flexDirection: 'row',
205
+ alignItems: 'center',
206
+ },
207
+ icon: {
208
+ marginRight: 12,
209
+ },
210
+ name: {
211
+ fontSize: 16,
212
+ fontWeight: '600',
213
+ color: editor_1.studioTheme.colors.textPrimary,
214
+ letterSpacing: 0.3,
215
+ },
216
+ activeText: {
217
+ color: editor_1.studioTheme.colors.textPrimary,
218
+ },
219
+ mutedText: {
220
+ color: editor_1.studioTheme.colors.textMuted,
221
+ fontStyle: 'italic',
222
+ fontWeight: '500',
223
+ },
224
+ detailsRow: {
225
+ marginTop: 12,
226
+ flexDirection: 'row',
227
+ alignItems: 'center',
228
+ paddingLeft: 32,
229
+ },
230
+ badge: {
231
+ backgroundColor: editor_1.studioTheme.colors.surfaceSoft,
232
+ paddingHorizontal: 8,
233
+ paddingVertical: 4,
234
+ borderRadius: 6,
235
+ marginRight: 12,
236
+ },
237
+ activeBadge: {
238
+ backgroundColor: editor_1.studioTheme.colors.accentMuted,
239
+ },
240
+ badgeText: {
241
+ fontSize: 10,
242
+ fontWeight: '700',
243
+ color: editor_1.studioTheme.colors.textSecondary,
244
+ letterSpacing: 0.5,
245
+ },
246
+ activeBadgeText: {
247
+ color: editor_1.studioTheme.colors.accent,
248
+ },
249
+ previewStateText: {
250
+ color: editor_1.studioTheme.colors.accent,
251
+ fontSize: 12,
252
+ fontWeight: '700',
253
+ marginRight: 12,
254
+ },
255
+ description: {
256
+ flex: 1,
257
+ fontSize: 13,
258
+ color: editor_1.studioTheme.colors.textMuted,
259
+ lineHeight: 18,
260
+ },
261
+ activeDescription: {
262
+ color: editor_1.studioTheme.colors.textSecondary,
263
+ },
264
+ loadingText: {
265
+ marginTop: 16,
266
+ color: editor_1.studioTheme.colors.textSecondary,
267
+ fontSize: 15,
268
+ fontWeight: '500',
269
+ letterSpacing: 0.5,
270
+ },
271
+ errorText: {
272
+ color: editor_1.studioTheme.colors.danger,
273
+ fontSize: 15,
274
+ textAlign: 'center',
275
+ marginBottom: 20,
276
+ lineHeight: 22,
277
+ },
278
+ retryButton: {
279
+ backgroundColor: editor_1.studioTheme.colors.surfaceSoft,
280
+ paddingHorizontal: 24,
281
+ paddingVertical: 12,
282
+ borderRadius: 999,
283
+ },
284
+ retryButtonText: {
285
+ color: editor_1.studioTheme.colors.textPrimary,
286
+ fontWeight: '600',
287
+ fontSize: 14,
288
+ },
289
+ cloneButton: {
290
+ backgroundColor: editor_1.studioTheme.colors.accent,
291
+ flexDirection: 'row',
292
+ alignItems: 'center',
293
+ justifyContent: 'center',
294
+ padding: 16,
295
+ borderRadius: 16,
296
+ marginHorizontal: 16,
297
+ marginTop: 12,
298
+ gap: 8,
299
+ },
300
+ cloneButtonText: {
301
+ color: '#fff',
302
+ fontWeight: 'bold',
303
+ fontSize: 16,
304
+ },
305
+ });
@@ -0,0 +1,3 @@
1
+ export declare const BLURHASH = "L6PZfSi_.AyE_3t7t7R**0o#DgR4";
2
+ export declare const MAX_ASSET_SIZE: number;
3
+ export declare const RESULTS_PER_PAGE = 24;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RESULTS_PER_PAGE = exports.MAX_ASSET_SIZE = exports.BLURHASH = void 0;
4
+ exports.BLURHASH = 'L6PZfSi_.AyE_3t7t7R**0o#DgR4';
5
+ exports.MAX_ASSET_SIZE = 50 * 1024 * 1024; // 50 MB
6
+ exports.RESULTS_PER_PAGE = 24;