@crievo/omni 0.0.0-stage → 0.1.1

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 (708) hide show
  1. package/.env.example +41 -0
  2. package/README.md +2 -2
  3. package/bin/omni.mjs +18 -0
  4. package/docs/onboarding/clone-voice.png +0 -0
  5. package/docs/onboarding/getting-started.png +0 -0
  6. package/docs/onboarding/new-video.png +0 -0
  7. package/docs/onboarding/providers.png +0 -0
  8. package/docs/onboarding/publish.png +0 -0
  9. package/docs/onboarding/references.png +0 -0
  10. package/docs/onboarding.md +212 -0
  11. package/omnivideo.config.example.json +437 -0
  12. package/package.json +40 -4
  13. package/reference/captions.md +156 -0
  14. package/reference/carousel-contract.md +91 -0
  15. package/reference/cloud.md +96 -0
  16. package/reference/learnings.md +792 -0
  17. package/reference/omnichat.md +305 -0
  18. package/reference/premiere-mcp.md +91 -0
  19. package/reference/publish.md +305 -0
  20. package/reference/scenes-contract.md +109 -0
  21. package/reference/studio.md +666 -0
  22. package/reference/voicestudio.md +81 -0
  23. package/reference/writing-for-voice.md +67 -0
  24. package/requirements.txt +3 -0
  25. package/studio/api/app.ts +87 -0
  26. package/studio/api/lib/errors.ts +33 -0
  27. package/studio/api/lib/files.ts +41 -0
  28. package/studio/api/lib/hono.ts +9 -0
  29. package/studio/api/lib/result.ts +14 -0
  30. package/studio/api/lib/validate.ts +31 -0
  31. package/studio/api/lib/video.ts +10 -0
  32. package/studio/api/middleware/json-charset.ts +11 -0
  33. package/studio/api/middleware/local-only.ts +32 -0
  34. package/studio/api/middleware/no-timeout.ts +10 -0
  35. package/studio/api/routes/admin.ts +18 -0
  36. package/studio/api/routes/agent-cascade.ts +100 -0
  37. package/studio/api/routes/agent-history.ts +23 -0
  38. package/studio/api/routes/agent.ts +162 -0
  39. package/studio/api/routes/analytics.ts +31 -0
  40. package/studio/api/routes/approval.ts +60 -0
  41. package/studio/api/routes/archive.ts +12 -0
  42. package/studio/api/routes/captions.ts +28 -0
  43. package/studio/api/routes/carousel.ts +38 -0
  44. package/studio/api/routes/clone.ts +27 -0
  45. package/studio/api/routes/create.ts +19 -0
  46. package/studio/api/routes/events.ts +11 -0
  47. package/studio/api/routes/export.ts +14 -0
  48. package/studio/api/routes/media.ts +30 -0
  49. package/studio/api/routes/omnichat.ts +113 -0
  50. package/studio/api/routes/onboarding.ts +14 -0
  51. package/studio/api/routes/publish.ts +40 -0
  52. package/studio/api/routes/queue.ts +14 -0
  53. package/studio/api/routes/references.ts +40 -0
  54. package/studio/api/routes/runner.ts +17 -0
  55. package/studio/api/routes/schedule.ts +47 -0
  56. package/studio/api/routes/services.ts +11 -0
  57. package/studio/api/routes/sessions.ts +27 -0
  58. package/studio/api/routes/settings.ts +102 -0
  59. package/studio/api/routes/sound.ts +45 -0
  60. package/studio/api/routes/thumbnail.ts +18 -0
  61. package/studio/api/routes/usage.ts +13 -0
  62. package/studio/api/routes/videos.ts +41 -0
  63. package/studio/api/routes/voices.ts +71 -0
  64. package/studio/api/services/admin.ts +113 -0
  65. package/studio/api/services/agent-cascade.ts +975 -0
  66. package/studio/api/services/agent-claude.ts +47 -0
  67. package/studio/api/services/agent-history.ts +103 -0
  68. package/studio/api/services/agent-persona.ts +77 -0
  69. package/studio/api/services/agent-tools.ts +2237 -0
  70. package/studio/api/services/agent-ui-tools.ts +259 -0
  71. package/studio/api/services/agent-wait.ts +32 -0
  72. package/studio/api/services/agent.ts +553 -0
  73. package/studio/api/services/analytics.ts +92 -0
  74. package/studio/api/services/approval.ts +134 -0
  75. package/studio/api/services/archive.ts +38 -0
  76. package/studio/api/services/captions.ts +268 -0
  77. package/studio/api/services/carousel.ts +206 -0
  78. package/studio/api/services/classify.ts +196 -0
  79. package/studio/api/services/clone-phrases.ts +75 -0
  80. package/studio/api/services/clone.ts +722 -0
  81. package/studio/api/services/create.ts +421 -0
  82. package/studio/api/services/events.ts +215 -0
  83. package/studio/api/services/media.ts +32 -0
  84. package/studio/api/services/omnichat.ts +624 -0
  85. package/studio/api/services/onboarding.ts +77 -0
  86. package/studio/api/services/publish.ts +287 -0
  87. package/studio/api/services/queue.ts +150 -0
  88. package/studio/api/services/references.ts +269 -0
  89. package/studio/api/services/root.ts +60 -0
  90. package/studio/api/services/services.ts +114 -0
  91. package/studio/api/services/sessions.ts +1007 -0
  92. package/studio/api/services/settings.ts +983 -0
  93. package/studio/api/services/sound.ts +311 -0
  94. package/studio/api/services/thumbnail.ts +133 -0
  95. package/studio/api/services/usage.ts +27 -0
  96. package/studio/api/services/videos.ts +418 -0
  97. package/studio/api/services/voice-pause.ts +98 -0
  98. package/studio/api/services/voices.ts +324 -0
  99. package/studio/runner/runner.ts +244 -0
  100. package/studio/shared/omni-actions.ts +68 -0
  101. package/studio/shared/omni-admin.ts +52 -0
  102. package/studio/shared/omni-farewell.ts +48 -0
  103. package/studio/shared/omni-hotword.ts +20 -0
  104. package/studio/shared/omni-screens.ts +228 -0
  105. package/studio/shared/schemas/admin.ts +15 -0
  106. package/studio/shared/schemas/agent-cascade.ts +58 -0
  107. package/studio/shared/schemas/agent-history.ts +73 -0
  108. package/studio/shared/schemas/agent.ts +50 -0
  109. package/studio/shared/schemas/analytics.ts +6 -0
  110. package/studio/shared/schemas/approval.ts +22 -0
  111. package/studio/shared/schemas/captions.ts +19 -0
  112. package/studio/shared/schemas/carousel.ts +26 -0
  113. package/studio/shared/schemas/clone.ts +40 -0
  114. package/studio/shared/schemas/common.ts +16 -0
  115. package/studio/shared/schemas/omnichat.ts +54 -0
  116. package/studio/shared/schemas/onboarding.ts +5 -0
  117. package/studio/shared/schemas/publish.ts +45 -0
  118. package/studio/shared/schemas/references.ts +20 -0
  119. package/studio/shared/schemas/settings.ts +82 -0
  120. package/studio/shared/schemas/sound.ts +22 -0
  121. package/studio/shared/schemas/videos.ts +38 -0
  122. package/studio/shared/schemas/voices.ts +23 -0
  123. package/studio/shared/types/api.ts +1290 -0
  124. package/studio/studio.ts +148 -0
  125. package/studio/tsconfig.json +15 -0
  126. package/studio/web/assets/logos/cartesia.svg +4 -0
  127. package/studio/web/assets/logos/elevenlabs.svg +12 -0
  128. package/studio/web/assets/logos/fish.svg +24 -0
  129. package/studio/web/assets/logos/omni-black.png +0 -0
  130. package/studio/web/assets/logos/omni-white.png +0 -0
  131. package/studio/web/assets/logos/voicestudio.svg +21 -0
  132. package/studio/web/components/AgentMark.tsx +7 -0
  133. package/studio/web/components/AgentWalking.tsx +11 -0
  134. package/studio/web/components/ApiKeyField.tsx +104 -0
  135. package/studio/web/components/AppShell.tsx +64 -0
  136. package/studio/web/components/ApprovalNotice.tsx +65 -0
  137. package/studio/web/components/AvatarGroupIcon.tsx +22 -0
  138. package/studio/web/components/AvatarNameField.tsx +86 -0
  139. package/studio/web/components/AvatarPicker.tsx +84 -0
  140. package/studio/web/components/BrandLogo.tsx +16 -0
  141. package/studio/web/components/CartesiaPlanSetting.tsx +90 -0
  142. package/studio/web/components/ClaudeWalking.tsx +32 -0
  143. package/studio/web/components/CloneVoiceDialog/GuidedScript.tsx +39 -0
  144. package/studio/web/components/CloneVoiceDialog/LanguageBar.tsx +37 -0
  145. package/studio/web/components/CloneVoiceDialog/LevelMeter.tsx +31 -0
  146. package/studio/web/components/CloneVoiceDialog/ProviderChoice.tsx +81 -0
  147. package/studio/web/components/CloneVoiceDialog/QualityPanel.tsx +62 -0
  148. package/studio/web/components/CloneVoiceDialog/RecordStep.tsx +50 -0
  149. package/studio/web/components/CloneVoiceDialog/RecorderBar.tsx +79 -0
  150. package/studio/web/components/CloneVoiceDialog/RedoSummary.tsx +54 -0
  151. package/studio/web/components/CloneVoiceDialog/SaveStep.tsx +91 -0
  152. package/studio/web/components/CloneVoiceDialog/SourceBar.tsx +30 -0
  153. package/studio/web/components/CloneVoiceDialog/index.tsx +141 -0
  154. package/studio/web/components/CloneVoiceDialog/types.ts +28 -0
  155. package/studio/web/components/CloneVoiceDialog/useCloneVoice.ts +528 -0
  156. package/studio/web/components/ConnectionSignals.tsx +51 -0
  157. package/studio/web/components/EditVoiceDialog/EditVoiceFooter.tsx +72 -0
  158. package/studio/web/components/EditVoiceDialog/ProviderCards.tsx +81 -0
  159. package/studio/web/components/EditVoiceDialog/index.tsx +256 -0
  160. package/studio/web/components/ErrorBanner.tsx +115 -0
  161. package/studio/web/components/FinishedTask.tsx +41 -0
  162. package/studio/web/components/FishModelSetting.tsx +69 -0
  163. package/studio/web/components/FishPriceSetting.tsx +44 -0
  164. package/studio/web/components/HumanBanner.tsx +64 -0
  165. package/studio/web/components/Lightbox.tsx +41 -0
  166. package/studio/web/components/LogStream.tsx +42 -0
  167. package/studio/web/components/Markdown.tsx +21 -0
  168. package/studio/web/components/MissingDmsPanel/BatchSend.tsx +137 -0
  169. package/studio/web/components/MissingDmsPanel/CommentCard.tsx +168 -0
  170. package/studio/web/components/MissingDmsPanel/CommentFeed.tsx +45 -0
  171. package/studio/web/components/MissingDmsPanel/DmBubble.tsx +38 -0
  172. package/studio/web/components/MissingDmsPanel/ReplyComposer.tsx +63 -0
  173. package/studio/web/components/MissingDmsPanel/index.tsx +98 -0
  174. package/studio/web/components/NotFound.tsx +48 -0
  175. package/studio/web/components/Omni/OmniAvatarPicker.tsx +92 -0
  176. package/studio/web/components/Omni/OmniCards.tsx +202 -0
  177. package/studio/web/components/Omni/OmniGlow.tsx +183 -0
  178. package/studio/web/components/Omni/OmniHistory.tsx +119 -0
  179. package/studio/web/components/Omni/OmniHotword.tsx +40 -0
  180. package/studio/web/components/Omni/OmniMicSelect.tsx +92 -0
  181. package/studio/web/components/Omni/OmniVoiceSample.tsx +81 -0
  182. package/studio/web/components/Omni/OmniWidget.tsx +743 -0
  183. package/studio/web/components/Omni/PendingActions.tsx +200 -0
  184. package/studio/web/components/Omni/Transcript.tsx +127 -0
  185. package/studio/web/components/OmnichatAccountStatus.tsx +87 -0
  186. package/studio/web/components/OmnichatRulePanel/RuleConfig.tsx +150 -0
  187. package/studio/web/components/OmnichatRulePanel/RuleDryRun.tsx +15 -0
  188. package/studio/web/components/OmnichatRulePanel/RuleEnableConfirm.tsx +42 -0
  189. package/studio/web/components/OmnichatRulePanel/RuleSkeleton.tsx +18 -0
  190. package/studio/web/components/OmnichatRulePanel/RuleStatus.tsx +55 -0
  191. package/studio/web/components/OmnichatRulePanel/index.tsx +115 -0
  192. package/studio/web/components/OmnichatRulePanel/rule-steps.ts +67 -0
  193. package/studio/web/components/OmnichatRulePanel/steps/MessageStep.tsx +91 -0
  194. package/studio/web/components/OmnichatRulePanel/steps/RepliesStep.tsx +201 -0
  195. package/studio/web/components/OmnichatRulePanel/steps/TriggerStep.tsx +76 -0
  196. package/studio/web/components/OmnichatRulePanel/steps/types.ts +11 -0
  197. package/studio/web/components/Palette.tsx +17 -0
  198. package/studio/web/components/PlatformCard.tsx +109 -0
  199. package/studio/web/components/PlatformIcon.tsx +19 -0
  200. package/studio/web/components/ProviderCard.tsx +80 -0
  201. package/studio/web/components/ProviderDetail.tsx +367 -0
  202. package/studio/web/components/ProviderLogo.tsx +20 -0
  203. package/studio/web/components/QueuePanel.tsx +77 -0
  204. package/studio/web/components/ReferenceActions.tsx +89 -0
  205. package/studio/web/components/ReferencePicker.tsx +136 -0
  206. package/studio/web/components/ResultMessage.tsx +7 -0
  207. package/studio/web/components/RuleForm.tsx +138 -0
  208. package/studio/web/components/RuleLog.tsx +151 -0
  209. package/studio/web/components/RunningTask.tsx +23 -0
  210. package/studio/web/components/SampleList.tsx +55 -0
  211. package/studio/web/components/SessionPanel.tsx +352 -0
  212. package/studio/web/components/SettingRow.tsx +14 -0
  213. package/studio/web/components/SettingsCategorySkeleton.tsx +25 -0
  214. package/studio/web/components/SidePanel.tsx +77 -0
  215. package/studio/web/components/Sidebar.tsx +289 -0
  216. package/studio/web/components/StageStepper.tsx +87 -0
  217. package/studio/web/components/StudioOffline.tsx +80 -0
  218. package/studio/web/components/TaskName.tsx +17 -0
  219. package/studio/web/components/TopBanners.tsx +30 -0
  220. package/studio/web/components/VideoOmnichatPanel.tsx +287 -0
  221. package/studio/web/components/VoiceAvatar.tsx +33 -0
  222. package/studio/web/components/VoiceCarousel.tsx +196 -0
  223. package/studio/web/components/VoiceCategory.tsx +9 -0
  224. package/studio/web/components/VoiceModal.tsx +39 -0
  225. package/studio/web/components/VoiceProfileCard.tsx +75 -0
  226. package/studio/web/components/VoiceProfilePicker.tsx +107 -0
  227. package/studio/web/components/VoiceProfilesSettings.tsx +150 -0
  228. package/studio/web/components/VoiceProviderCard.tsx +118 -0
  229. package/studio/web/components/VoiceProvidersCard.tsx +26 -0
  230. package/studio/web/components/WaitList.tsx +21 -0
  231. package/studio/web/components/icons.tsx +247 -0
  232. package/studio/web/components/ui/accordion.tsx +47 -0
  233. package/studio/web/components/ui/badge.tsx +18 -0
  234. package/studio/web/components/ui/calendar.tsx +43 -0
  235. package/studio/web/components/ui/chart.tsx +229 -0
  236. package/studio/web/components/ui/checkbox.tsx +26 -0
  237. package/studio/web/components/ui/cx.ts +2 -0
  238. package/studio/web/components/ui/date-time-picker.tsx +84 -0
  239. package/studio/web/components/ui/panel.tsx +23 -0
  240. package/studio/web/components/ui/picker.tsx +58 -0
  241. package/studio/web/components/ui/popover.tsx +24 -0
  242. package/studio/web/components/ui/select.tsx +89 -0
  243. package/studio/web/components/ui/skeleton.tsx +10 -0
  244. package/studio/web/components/ui/slider.tsx +68 -0
  245. package/studio/web/components/ui/switch.tsx +13 -0
  246. package/studio/web/components/ui/tooltip.tsx +59 -0
  247. package/studio/web/hooks/useAccounts.ts +27 -0
  248. package/studio/web/hooks/useAdmin.ts +12 -0
  249. package/studio/web/hooks/useAnalytics.ts +21 -0
  250. package/studio/web/hooks/useAvatarAudioReactive.ts +87 -0
  251. package/studio/web/hooks/useBrowserConnect.ts +48 -0
  252. package/studio/web/hooks/useClonePlan.ts +14 -0
  253. package/studio/web/hooks/useConnected.ts +7 -0
  254. package/studio/web/hooks/useLiveQuery.ts +29 -0
  255. package/studio/web/hooks/useMenuCollapsed.ts +32 -0
  256. package/studio/web/hooks/useMicDevices.ts +53 -0
  257. package/studio/web/hooks/useMissingDms.ts +211 -0
  258. package/studio/web/hooks/useMissingSetupSteps.ts +26 -0
  259. package/studio/web/hooks/useNow.ts +11 -0
  260. package/studio/web/hooks/useOmniAgent.ts +278 -0
  261. package/studio/web/hooks/useOmniClaude.ts +124 -0
  262. package/studio/web/hooks/useOmniDock.ts +142 -0
  263. package/studio/web/hooks/useOmniGreeting.ts +60 -0
  264. package/studio/web/hooks/useOmniHotword.ts +128 -0
  265. package/studio/web/hooks/useOmnichat.ts +26 -0
  266. package/studio/web/hooks/useOnboarding.ts +27 -0
  267. package/studio/web/hooks/usePost.ts +23 -0
  268. package/studio/web/hooks/useQueue.ts +10 -0
  269. package/studio/web/hooks/useReferences.ts +20 -0
  270. package/studio/web/hooks/useRuleEditor.ts +101 -0
  271. package/studio/web/hooks/useRunner.ts +24 -0
  272. package/studio/web/hooks/useSaveAction.ts +23 -0
  273. package/studio/web/hooks/useSchedule.ts +11 -0
  274. package/studio/web/hooks/useServices.ts +10 -0
  275. package/studio/web/hooks/useSessions.ts +15 -0
  276. package/studio/web/hooks/useSettings.ts +11 -0
  277. package/studio/web/hooks/useSettingsSection.ts +30 -0
  278. package/studio/web/hooks/useSidePanel.ts +23 -0
  279. package/studio/web/hooks/useSound.ts +30 -0
  280. package/studio/web/hooks/useUsage.ts +11 -0
  281. package/studio/web/hooks/useVideoVoice.ts +36 -0
  282. package/studio/web/hooks/useVideos.ts +21 -0
  283. package/studio/web/hooks/useVoiceProfilePreview.ts +52 -0
  284. package/studio/web/hooks/useVoiceProfiles.ts +7 -0
  285. package/studio/web/hooks/useVoiceRunning.ts +10 -0
  286. package/studio/web/hooks/useVoiceStudioClosed.ts +8 -0
  287. package/studio/web/index.html +19 -0
  288. package/studio/web/lib/agent.ts +7 -0
  289. package/studio/web/lib/alerts.ts +210 -0
  290. package/studio/web/lib/analytics-metrics.ts +351 -0
  291. package/studio/web/lib/api.ts +70 -0
  292. package/studio/web/lib/audio.ts +39 -0
  293. package/studio/web/lib/avatars.ts +41 -0
  294. package/studio/web/lib/calendar.ts +218 -0
  295. package/studio/web/lib/caption-position.ts +249 -0
  296. package/studio/web/lib/carousel.ts +24 -0
  297. package/studio/web/lib/chime.ts +42 -0
  298. package/studio/web/lib/clone-voice.ts +55 -0
  299. package/studio/web/lib/export.ts +11 -0
  300. package/studio/web/lib/files.ts +8 -0
  301. package/studio/web/lib/format.ts +93 -0
  302. package/studio/web/lib/media.ts +29 -0
  303. package/studio/web/lib/mic-device.ts +72 -0
  304. package/studio/web/lib/missing-dms.ts +70 -0
  305. package/studio/web/lib/omni-cards.ts +42 -0
  306. package/studio/web/lib/omni-cascade.ts +1067 -0
  307. package/studio/web/lib/omni-greeting-audio.ts +24 -0
  308. package/studio/web/lib/omni-hotword.ts +231 -0
  309. package/studio/web/lib/omni-panel.ts +67 -0
  310. package/studio/web/lib/omni-realtime.ts +811 -0
  311. package/studio/web/lib/omni-ui.ts +402 -0
  312. package/studio/web/lib/omni-wait.ts +174 -0
  313. package/studio/web/lib/omnichat-api.ts +44 -0
  314. package/studio/web/lib/orb.ts +270 -0
  315. package/studio/web/lib/pcm-recorder.ts +115 -0
  316. package/studio/web/lib/platforms.ts +17 -0
  317. package/studio/web/lib/providers.ts +27 -0
  318. package/studio/web/lib/publish-draft.ts +52 -0
  319. package/studio/web/lib/publish-settings.ts +81 -0
  320. package/studio/web/lib/query-client.ts +122 -0
  321. package/studio/web/lib/references.ts +13 -0
  322. package/studio/web/lib/services.ts +40 -0
  323. package/studio/web/lib/sessions.ts +103 -0
  324. package/studio/web/lib/settings-categories.ts +58 -0
  325. package/studio/web/lib/sound-audio.ts +33 -0
  326. package/studio/web/lib/sound-timeline.ts +291 -0
  327. package/studio/web/lib/sse.ts +86 -0
  328. package/studio/web/lib/stage-history.ts +141 -0
  329. package/studio/web/lib/stages.ts +344 -0
  330. package/studio/web/lib/studio-offline.ts +60 -0
  331. package/studio/web/lib/upload.ts +24 -0
  332. package/studio/web/lib/video-tabs.ts +118 -0
  333. package/studio/web/lib/voice-profile-draft.ts +34 -0
  334. package/studio/web/lib/voice-profiles.ts +3 -0
  335. package/studio/web/main.tsx +14 -0
  336. package/studio/web/pages/AdminPage/index.tsx +123 -0
  337. package/studio/web/pages/AgentPage/components/Measurements.tsx +102 -0
  338. package/studio/web/pages/AgentPage/index.tsx +28 -0
  339. package/studio/web/pages/AnalyticsPage/components/About.tsx +52 -0
  340. package/studio/web/pages/AnalyticsPage/components/ChannelCards.tsx +106 -0
  341. package/studio/web/pages/AnalyticsPage/components/ChannelView.tsx +137 -0
  342. package/studio/web/pages/AnalyticsPage/components/CollectionStatus.tsx +46 -0
  343. package/studio/web/pages/AnalyticsPage/components/Comparison.tsx +68 -0
  344. package/studio/web/pages/AnalyticsPage/components/Diagnosis.tsx +50 -0
  345. package/studio/web/pages/AnalyticsPage/components/Highlights.tsx +49 -0
  346. package/studio/web/pages/AnalyticsPage/components/Hint.tsx +11 -0
  347. package/studio/web/pages/AnalyticsPage/components/HookVsBody.tsx +100 -0
  348. package/studio/web/pages/AnalyticsPage/components/HourlyWave.tsx +133 -0
  349. package/studio/web/pages/AnalyticsPage/components/Insights.tsx +70 -0
  350. package/studio/web/pages/AnalyticsPage/components/MetricCard.tsx +46 -0
  351. package/studio/web/pages/AnalyticsPage/components/PlanSection.tsx +40 -0
  352. package/studio/web/pages/AnalyticsPage/components/ProgressionChart.tsx +155 -0
  353. package/studio/web/pages/AnalyticsPage/components/ReelBarsChart.tsx +154 -0
  354. package/studio/web/pages/AnalyticsPage/components/ReelThumb.tsx +19 -0
  355. package/studio/web/pages/AnalyticsPage/components/ReelView.tsx +290 -0
  356. package/studio/web/pages/AnalyticsPage/components/ReelsTable.tsx +269 -0
  357. package/studio/web/pages/AnalyticsPage/components/RequestWithFocus.tsx +38 -0
  358. package/studio/web/pages/AnalyticsPage/components/SegmentedControl.tsx +35 -0
  359. package/studio/web/pages/AnalyticsPage/components/VsMedian.tsx +31 -0
  360. package/studio/web/pages/AnalyticsPage/index.tsx +17 -0
  361. package/studio/web/pages/GettingStartedPage/index.tsx +174 -0
  362. package/studio/web/pages/NewVideoPage/components/DeliverablesPicker.tsx +62 -0
  363. package/studio/web/pages/NewVideoPage/components/FormatPicker.tsx +33 -0
  364. package/studio/web/pages/NewVideoPage/index.tsx +133 -0
  365. package/studio/web/pages/NotFoundPage/index.tsx +9 -0
  366. package/studio/web/pages/OmnichatPage/components/NewFromLink.tsx +59 -0
  367. package/studio/web/pages/OmnichatPage/components/RuleListItem.tsx +64 -0
  368. package/studio/web/pages/OmnichatPage/components/RulePreview.tsx +14 -0
  369. package/studio/web/pages/OmnichatPage/components/RuleView.tsx +88 -0
  370. package/studio/web/pages/OmnichatPage/index.tsx +153 -0
  371. package/studio/web/pages/QueuePage/index.tsx +22 -0
  372. package/studio/web/pages/ReferencePage/components/ReferenceTexts.tsx +131 -0
  373. package/studio/web/pages/ReferencePage/index.tsx +216 -0
  374. package/studio/web/pages/ReferencesPage/components/NewReferenceForm.tsx +150 -0
  375. package/studio/web/pages/ReferencesPage/components/ReferenceCard.tsx +42 -0
  376. package/studio/web/pages/ReferencesPage/components/ReferenceGridSkeleton.tsx +31 -0
  377. package/studio/web/pages/ReferencesPage/index.tsx +67 -0
  378. package/studio/web/pages/SchedulePage/components/CalendarSkeleton.tsx +18 -0
  379. package/studio/web/pages/SchedulePage/components/DayView.tsx +177 -0
  380. package/studio/web/pages/SchedulePage/components/HourPicker.tsx +103 -0
  381. package/studio/web/pages/SchedulePage/components/MonthDayCell.tsx +111 -0
  382. package/studio/web/pages/SchedulePage/components/MonthView.tsx +47 -0
  383. package/studio/web/pages/SchedulePage/components/PlatformIcons.tsx +12 -0
  384. package/studio/web/pages/SchedulePage/components/PostThumb.tsx +15 -0
  385. package/studio/web/pages/SchedulePage/components/WeekColumn.tsx +75 -0
  386. package/studio/web/pages/SchedulePage/components/WeekView.tsx +35 -0
  387. package/studio/web/pages/SchedulePage/index.tsx +285 -0
  388. package/studio/web/pages/SettingsPage/components/AgentAccounts.tsx +263 -0
  389. package/studio/web/pages/SettingsPage/components/AgentCategory.tsx +20 -0
  390. package/studio/web/pages/SettingsPage/components/ModelPicker.tsx +49 -0
  391. package/studio/web/pages/SettingsPage/components/ModelsSettings.tsx +138 -0
  392. package/studio/web/pages/SettingsPage/components/PlatformsCategory.tsx +23 -0
  393. package/studio/web/pages/SettingsPage/components/PublishingCategory/AccountStatus.tsx +29 -0
  394. package/studio/web/pages/SettingsPage/components/PublishingCategory/AutoPublishPanel.tsx +90 -0
  395. package/studio/web/pages/SettingsPage/components/PublishingCategory/BrowserConnect.tsx +62 -0
  396. package/studio/web/pages/SettingsPage/components/PublishingCategory/CheckField.tsx +19 -0
  397. package/studio/web/pages/SettingsPage/components/PublishingCategory/InstagramPanel.tsx +113 -0
  398. package/studio/web/pages/SettingsPage/components/PublishingCategory/OmnichatSettingsPanel.tsx +146 -0
  399. package/studio/web/pages/SettingsPage/components/PublishingCategory/SaveBar.tsx +33 -0
  400. package/studio/web/pages/SettingsPage/components/PublishingCategory/SchedulePanel.tsx +132 -0
  401. package/studio/web/pages/SettingsPage/components/PublishingCategory/SettingsCard.tsx +47 -0
  402. package/studio/web/pages/SettingsPage/components/PublishingCategory/SettingsCardGroup.tsx +19 -0
  403. package/studio/web/pages/SettingsPage/components/PublishingCategory/TextPanel.tsx +55 -0
  404. package/studio/web/pages/SettingsPage/components/PublishingCategory/TiktokPanel.tsx +123 -0
  405. package/studio/web/pages/SettingsPage/components/PublishingCategory/YoutubePanel.tsx +100 -0
  406. package/studio/web/pages/SettingsPage/components/PublishingCategory/badges.tsx +15 -0
  407. package/studio/web/pages/SettingsPage/components/PublishingCategory/index.tsx +40 -0
  408. package/studio/web/pages/SettingsPage/components/PublishingCategory/types.ts +10 -0
  409. package/studio/web/pages/SettingsPage/components/UsageCategory.tsx +389 -0
  410. package/studio/web/pages/SettingsPage/components/VoiceProvidersCategory.tsx +97 -0
  411. package/studio/web/pages/SettingsPage/index.tsx +85 -0
  412. package/studio/web/pages/VideoPage/components/AudioPlayer.tsx +113 -0
  413. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/AxisField.tsx +50 -0
  414. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionList.tsx +56 -0
  415. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionListItem.tsx +92 -0
  416. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionMargins.tsx +57 -0
  417. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionStyleFields.tsx +70 -0
  418. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionTextForm.tsx +87 -0
  419. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/ColorField.tsx +37 -0
  420. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/MarginField.tsx +59 -0
  421. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/NumberField.tsx +57 -0
  422. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/PositionControls.tsx +140 -0
  423. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/captionEditor.ts +215 -0
  424. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/useCaptionPosition.ts +154 -0
  425. package/studio/web/pages/VideoPage/components/CarouselChangeRequest.tsx +72 -0
  426. package/studio/web/pages/VideoPage/components/CarouselCompositionStage.tsx +80 -0
  427. package/studio/web/pages/VideoPage/components/CarouselCreate.tsx +63 -0
  428. package/studio/web/pages/VideoPage/components/CarouselMissing.tsx +19 -0
  429. package/studio/web/pages/VideoPage/components/CarouselPublishStage.tsx +173 -0
  430. package/studio/web/pages/VideoPage/components/CarouselScriptStage.tsx +82 -0
  431. package/studio/web/pages/VideoPage/components/CarouselSlideCard.tsx +49 -0
  432. package/studio/web/pages/VideoPage/components/CarouselViewer.tsx +55 -0
  433. package/studio/web/pages/VideoPage/components/ChangedVoices.tsx +53 -0
  434. package/studio/web/pages/VideoPage/components/CompositionStage.tsx +78 -0
  435. package/studio/web/pages/VideoPage/components/CoverPicker.tsx +32 -0
  436. package/studio/web/pages/VideoPage/components/EditorStage.tsx +53 -0
  437. package/studio/web/pages/VideoPage/components/LineTakes.tsx +160 -0
  438. package/studio/web/pages/VideoPage/components/LineTextEditor.tsx +124 -0
  439. package/studio/web/pages/VideoPage/components/LineVoicePicker.tsx +37 -0
  440. package/studio/web/pages/VideoPage/components/MediaImage.tsx +25 -0
  441. package/studio/web/pages/VideoPage/components/MotionScriptStage.tsx +39 -0
  442. package/studio/web/pages/VideoPage/components/NarrationStage.tsx +70 -0
  443. package/studio/web/pages/VideoPage/components/PublishForm.tsx +387 -0
  444. package/studio/web/pages/VideoPage/components/PublishStage.tsx +76 -0
  445. package/studio/web/pages/VideoPage/components/PublishText.tsx +149 -0
  446. package/studio/web/pages/VideoPage/components/ScenesApprovalPanel.tsx +278 -0
  447. package/studio/web/pages/VideoPage/components/ScheduledInfo.tsx +72 -0
  448. package/studio/web/pages/VideoPage/components/ScriptApprovalPanel.tsx +189 -0
  449. package/studio/web/pages/VideoPage/components/ScriptStage.tsx +17 -0
  450. package/studio/web/pages/VideoPage/components/SequencePlayer.tsx +146 -0
  451. package/studio/web/pages/VideoPage/components/SoundTimeline/AddSound.tsx +117 -0
  452. package/studio/web/pages/VideoPage/components/SoundTimeline/AreaSelection.tsx +74 -0
  453. package/studio/web/pages/VideoPage/components/SoundTimeline/BedPanel.tsx +94 -0
  454. package/studio/web/pages/VideoPage/components/SoundTimeline/BedRow.tsx +45 -0
  455. package/studio/web/pages/VideoPage/components/SoundTimeline/CaptionOverlay.tsx +44 -0
  456. package/studio/web/pages/VideoPage/components/SoundTimeline/CaptionSaveBar.tsx +32 -0
  457. package/studio/web/pages/VideoPage/components/SoundTimeline/CaptionsPanel.tsx +22 -0
  458. package/studio/web/pages/VideoPage/components/SoundTimeline/ClipBlock.tsx +111 -0
  459. package/studio/web/pages/VideoPage/components/SoundTimeline/ClipPanel.tsx +76 -0
  460. package/studio/web/pages/VideoPage/components/SoundTimeline/CutsPanel.tsx +44 -0
  461. package/studio/web/pages/VideoPage/components/SoundTimeline/EditorTabBar.tsx +73 -0
  462. package/studio/web/pages/VideoPage/components/SoundTimeline/EffectChoice.tsx +46 -0
  463. package/studio/web/pages/VideoPage/components/SoundTimeline/EffectItem.tsx +89 -0
  464. package/studio/web/pages/VideoPage/components/SoundTimeline/EffectPanel.tsx +232 -0
  465. package/studio/web/pages/VideoPage/components/SoundTimeline/EffectsRow.tsx +21 -0
  466. package/studio/web/pages/VideoPage/components/SoundTimeline/Lane.tsx +39 -0
  467. package/studio/web/pages/VideoPage/components/SoundTimeline/MarkerRow.tsx +40 -0
  468. package/studio/web/pages/VideoPage/components/SoundTimeline/MuteButton.tsx +36 -0
  469. package/studio/web/pages/VideoPage/components/SoundTimeline/NumberInput.tsx +37 -0
  470. package/studio/web/pages/VideoPage/components/SoundTimeline/PlanWarnings.tsx +19 -0
  471. package/studio/web/pages/VideoPage/components/SoundTimeline/PlayerResizeHandle.tsx +50 -0
  472. package/studio/web/pages/VideoPage/components/SoundTimeline/PreviewControls.tsx +51 -0
  473. package/studio/web/pages/VideoPage/components/SoundTimeline/SceneRow.tsx +54 -0
  474. package/studio/web/pages/VideoPage/components/SoundTimeline/SettingsPanel.tsx +65 -0
  475. package/studio/web/pages/VideoPage/components/SoundTimeline/SoundLibrary.tsx +99 -0
  476. package/studio/web/pages/VideoPage/components/SoundTimeline/SoundPreview.tsx +82 -0
  477. package/studio/web/pages/VideoPage/components/SoundTimeline/SpeedPanel.tsx +128 -0
  478. package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineDock.tsx +56 -0
  479. package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineFooter.tsx +26 -0
  480. package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineSkeleton.tsx +21 -0
  481. package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineToolbar.tsx +160 -0
  482. package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineTracks.tsx +121 -0
  483. package/studio/web/pages/VideoPage/components/SoundTimeline/TrackSidebar.tsx +30 -0
  484. package/studio/web/pages/VideoPage/components/SoundTimeline/VoiceRow.tsx +53 -0
  485. package/studio/web/pages/VideoPage/components/SoundTimeline/Waveform.tsx +97 -0
  486. package/studio/web/pages/VideoPage/components/SoundTimeline/clipActions.ts +50 -0
  487. package/studio/web/pages/VideoPage/components/SoundTimeline/effectActions.ts +161 -0
  488. package/studio/web/pages/VideoPage/components/SoundTimeline/index.tsx +161 -0
  489. package/studio/web/pages/VideoPage/components/SoundTimeline/timelineGeometry.ts +45 -0
  490. package/studio/web/pages/VideoPage/components/SoundTimeline/types.ts +43 -0
  491. package/studio/web/pages/VideoPage/components/SoundTimeline/useAutosave.ts +107 -0
  492. package/studio/web/pages/VideoPage/components/SoundTimeline/useEditorShortcuts.ts +168 -0
  493. package/studio/web/pages/VideoPage/components/SoundTimeline/useFitHeight.ts +40 -0
  494. package/studio/web/pages/VideoPage/components/SoundTimeline/useFollowPlayhead.ts +21 -0
  495. package/studio/web/pages/VideoPage/components/SoundTimeline/useListenMix.ts +43 -0
  496. package/studio/web/pages/VideoPage/components/SoundTimeline/usePlayback.ts +231 -0
  497. package/studio/web/pages/VideoPage/components/SoundTimeline/usePlayerWidth.ts +27 -0
  498. package/studio/web/pages/VideoPage/components/SoundTimeline/useSoundData.ts +124 -0
  499. package/studio/web/pages/VideoPage/components/SoundTimeline/useSoundTimeline.ts +511 -0
  500. package/studio/web/pages/VideoPage/components/StageDrawer/CompareVersions.tsx +111 -0
  501. package/studio/web/pages/VideoPage/components/StageDrawer/VersionCard.tsx +81 -0
  502. package/studio/web/pages/VideoPage/components/StageDrawer/VersionMedia.tsx +24 -0
  503. package/studio/web/pages/VideoPage/components/StageDrawer/VersionText.tsx +15 -0
  504. package/studio/web/pages/VideoPage/components/StageDrawer/index.tsx +109 -0
  505. package/studio/web/pages/VideoPage/components/StageProcess.tsx +126 -0
  506. package/studio/web/pages/VideoPage/components/StageResult.tsx +69 -0
  507. package/studio/web/pages/VideoPage/components/SwapReference.tsx +92 -0
  508. package/studio/web/pages/VideoPage/components/ThumbnailPanel.tsx +252 -0
  509. package/studio/web/pages/VideoPage/components/TimingPanel.tsx +89 -0
  510. package/studio/web/pages/VideoPage/components/VideoPlayer.tsx +18 -0
  511. package/studio/web/pages/VideoPage/components/VideoSkeleton.tsx +50 -0
  512. package/studio/web/pages/VideoPage/components/VideoVoiceInfo.tsx +33 -0
  513. package/studio/web/pages/VideoPage/components/VideoVoicePicker.tsx +165 -0
  514. package/studio/web/pages/VideoPage/components/VoicePauseBanner.tsx +56 -0
  515. package/studio/web/pages/VideoPage/components/WithLogo.tsx +10 -0
  516. package/studio/web/pages/VideoPage/index.tsx +295 -0
  517. package/studio/web/pages/VideosPage/components/PublishedOn.tsx +85 -0
  518. package/studio/web/pages/VideosPage/components/ServicesPanel.tsx +81 -0
  519. package/studio/web/pages/VideosPage/components/SessionsPanel.tsx +62 -0
  520. package/studio/web/pages/VideosPage/components/VideoListSkeleton.tsx +25 -0
  521. package/studio/web/pages/VideosPage/components/VideoRow.tsx +122 -0
  522. package/studio/web/pages/VideosPage/index.tsx +134 -0
  523. package/studio/web/pages/VoicePage/index.tsx +28 -0
  524. package/studio/web/router.tsx +201 -0
  525. package/studio/web/styles/base/elements.css +55 -0
  526. package/studio/web/styles/base/utilities.css +25 -0
  527. package/studio/web/styles/components/badge.css +33 -0
  528. package/studio/web/styles/components/claude-running.css +27 -0
  529. package/studio/web/styles/components/claude-session.css +212 -0
  530. package/studio/web/styles/components/claude-walking.css +92 -0
  531. package/studio/web/styles/components/clone-voice-save.css +136 -0
  532. package/studio/web/styles/components/clone-voice.css +379 -0
  533. package/studio/web/styles/components/controls.css +70 -0
  534. package/studio/web/styles/components/data-and-image.css +54 -0
  535. package/studio/web/styles/components/forms.css +132 -0
  536. package/studio/web/styles/components/human-banner.css +99 -0
  537. package/studio/web/styles/components/lightbox.css +50 -0
  538. package/studio/web/styles/components/markdown.css +68 -0
  539. package/studio/web/styles/components/modal.css +70 -0
  540. package/studio/web/styles/components/omni-cards.css +105 -0
  541. package/studio/web/styles/components/omni.css +859 -0
  542. package/studio/web/styles/components/omnichat.css +538 -0
  543. package/studio/web/styles/components/panel.css +115 -0
  544. package/studio/web/styles/components/platform-card.css +140 -0
  545. package/studio/web/styles/components/provider-card.css +132 -0
  546. package/studio/web/styles/components/queue.css +185 -0
  547. package/studio/web/styles/components/reference-actions.css +133 -0
  548. package/studio/web/styles/components/reference-picker.css +146 -0
  549. package/studio/web/styles/components/results-drawer.css +224 -0
  550. package/studio/web/styles/components/segmented.css +115 -0
  551. package/studio/web/styles/components/side-panel-tab.css +23 -0
  552. package/studio/web/styles/components/status-signals.css +66 -0
  553. package/studio/web/styles/components/stepper.css +208 -0
  554. package/studio/web/styles/components/table.css +19 -0
  555. package/studio/web/styles/components/tabs.css +24 -0
  556. package/studio/web/styles/components/ui/accordion.css +71 -0
  557. package/studio/web/styles/components/ui/chart.css +162 -0
  558. package/studio/web/styles/components/ui/checkbox.css +37 -0
  559. package/studio/web/styles/components/ui/date-picker.css +153 -0
  560. package/studio/web/styles/components/ui/select.css +110 -0
  561. package/studio/web/styles/components/ui/skeleton.css +25 -0
  562. package/studio/web/styles/components/ui/slider.css +81 -0
  563. package/studio/web/styles/components/ui/switch.css +41 -0
  564. package/studio/web/styles/components/ui/tooltip.css +24 -0
  565. package/studio/web/styles/components/voice-carousel.css +255 -0
  566. package/studio/web/styles/components/voice-editor.css +179 -0
  567. package/studio/web/styles/components/voice-grid.css +56 -0
  568. package/studio/web/styles/components/voice-profiles.css +192 -0
  569. package/studio/web/styles/design-system.md +136 -0
  570. package/studio/web/styles/index.css +116 -0
  571. package/studio/web/styles/layout/page.css +41 -0
  572. package/studio/web/styles/layout/sidebar-groups.css +39 -0
  573. package/studio/web/styles/layout/sidebar.css +111 -0
  574. package/studio/web/styles/pages/agent.css +26 -0
  575. package/studio/web/styles/pages/analytics/dashboard.css +614 -0
  576. package/studio/web/styles/pages/analytics/insights.css +48 -0
  577. package/studio/web/styles/pages/getting-started.css +166 -0
  578. package/studio/web/styles/pages/new-video/form.css +32 -0
  579. package/studio/web/styles/pages/not-found.css +59 -0
  580. package/studio/web/styles/pages/references.css +204 -0
  581. package/studio/web/styles/pages/schedule/calendar.css +541 -0
  582. package/studio/web/styles/pages/schedule/chip-states.css +60 -0
  583. package/studio/web/styles/pages/settings/models.css +72 -0
  584. package/studio/web/styles/pages/settings/shell.css +361 -0
  585. package/studio/web/styles/pages/settings/usage.css +63 -0
  586. package/studio/web/styles/pages/studio-offline.css +105 -0
  587. package/studio/web/styles/pages/video/caption-controls.css +194 -0
  588. package/studio/web/styles/pages/video/captions-grid.css +70 -0
  589. package/studio/web/styles/pages/video/captions.css +79 -0
  590. package/studio/web/styles/pages/video/editor-chat.css +103 -0
  591. package/studio/web/styles/pages/video/export.css +50 -0
  592. package/studio/web/styles/pages/video/frames.css +29 -0
  593. package/studio/web/styles/pages/video/fullscreen-stage.css +400 -0
  594. package/studio/web/styles/pages/video/instagram-carousel.css +309 -0
  595. package/studio/web/styles/pages/video/layout.css +285 -0
  596. package/studio/web/styles/pages/video/narration.css +138 -0
  597. package/studio/web/styles/pages/video/preview-overview.css +11 -0
  598. package/studio/web/styles/pages/video/processing-notice.css +34 -0
  599. package/studio/web/styles/pages/video/publish-when.css +76 -0
  600. package/studio/web/styles/pages/video/publish.css +97 -0
  601. package/studio/web/styles/pages/video/result.css +96 -0
  602. package/studio/web/styles/pages/video/scenes.css +167 -0
  603. package/studio/web/styles/pages/video/sound-timeline.css +672 -0
  604. package/studio/web/styles/pages/video/sound-toolbar.css +149 -0
  605. package/studio/web/styles/pages/video/take-player.css +100 -0
  606. package/studio/web/styles/pages/video/thumbnail.css +157 -0
  607. package/studio/web/styles/pages/video/timeline.css +117 -0
  608. package/studio/web/styles/pages/video/voice-picker.css +14 -0
  609. package/studio/web/styles/pages/video-list/active-row.css +27 -0
  610. package/studio/web/styles/pages/video-list/card-link.css +49 -0
  611. package/studio/web/styles/pages/video-list/list.css +86 -0
  612. package/studio/web/styles/theme/identity/details.css +204 -0
  613. package/studio/web/styles/theme/identity/shell.css +249 -0
  614. package/studio/web/styles/theme/identity/surfaces.css +183 -0
  615. package/studio/web/styles/theme/identity/titles-and-buttons.css +120 -0
  616. package/studio/web/styles/theme/no-borders/blocks.css +208 -0
  617. package/studio/web/styles/theme/no-borders/controls.css +256 -0
  618. package/studio/web/styles/tokens.css +245 -0
  619. package/studio/web/types/api.ts +2 -0
  620. package/studio/web/types/assets.d.ts +9 -0
  621. package/templates/brief.md +27 -0
  622. package/templates/captions.html +204 -0
  623. package/templates/carousel-composition.md +47 -0
  624. package/templates/carousel-script.md +60 -0
  625. package/templates/components/voiceavatar/README.md +87 -0
  626. package/templates/components/voiceavatar/demo.html +50 -0
  627. package/templates/components/voiceavatar/voiceavatar.js +415 -0
  628. package/templates/motion.md +80 -0
  629. package/templates/playbook.md +43 -0
  630. package/templates/reference.md +123 -0
  631. package/templates/scene.html +112 -0
  632. package/templates/scenes.example.json +96 -0
  633. package/templates/script.md +63 -0
  634. package/templates/slide.html +71 -0
  635. package/templates/wireframe.html +91 -0
  636. package/tools/analysis.mjs +300 -0
  637. package/tools/approval.mjs +442 -0
  638. package/tools/assemble.mjs +942 -0
  639. package/tools/build-motion.mjs +437 -0
  640. package/tools/captions.mjs +246 -0
  641. package/tools/carousel.mjs +558 -0
  642. package/tools/compose.mjs +307 -0
  643. package/tools/cuts.mjs +74 -0
  644. package/tools/editor.mjs +419 -0
  645. package/tools/epidemic-capture.js +54 -0
  646. package/tools/fanout.mjs +69 -0
  647. package/tools/history.mjs +70 -0
  648. package/tools/history.py +61 -0
  649. package/tools/job-queue.mjs +180 -0
  650. package/tools/job_queue.py +430 -0
  651. package/tools/lib/agents.mjs +412 -0
  652. package/tools/lib/channel.mjs +399 -0
  653. package/tools/lib/claude-settings.mjs +67 -0
  654. package/tools/lib/cli.mjs +9 -0
  655. package/tools/lib/fanout.mjs +234 -0
  656. package/tools/lib/http.mjs +94 -0
  657. package/tools/lib/index.js +14 -0
  658. package/tools/lib/mcp-server.mjs +69 -0
  659. package/tools/lib/metrics/metrics.mjs +204 -0
  660. package/tools/lib/narration.mjs +15 -0
  661. package/tools/lib/oauth-client.mjs +295 -0
  662. package/tools/lib/omnichat/config.mjs +139 -0
  663. package/tools/lib/omnichat/errors.mjs +42 -0
  664. package/tools/lib/omnichat/extract.mjs +82 -0
  665. package/tools/lib/omnichat/gate.mjs +151 -0
  666. package/tools/lib/omnichat/manual.mjs +166 -0
  667. package/tools/lib/omnichat/match.mjs +78 -0
  668. package/tools/lib/omnichat/pass.mjs +393 -0
  669. package/tools/lib/omnichat/record.mjs +208 -0
  670. package/tools/lib/omnichat/text.mjs +315 -0
  671. package/tools/lib/omnichat/webhook.mjs +166 -0
  672. package/tools/lib/pairing.mjs +99 -0
  673. package/tools/lib/paths.mjs +41 -0
  674. package/tools/lib/platforms/instagram.mjs +469 -0
  675. package/tools/lib/platforms/tiktok.mjs +343 -0
  676. package/tools/lib/platforms/youtube.mjs +228 -0
  677. package/tools/lib/publish/publish.mjs +244 -0
  678. package/tools/lib/schedule/schedule.mjs +191 -0
  679. package/tools/lib/service.mjs +134 -0
  680. package/tools/lib/skill-client.mjs +126 -0
  681. package/tools/lib/skills-release.mjs +196 -0
  682. package/tools/lib/testing.mjs +52 -0
  683. package/tools/lib/up.mjs +187 -0
  684. package/tools/metrics.mjs +415 -0
  685. package/tools/models.mjs +134 -0
  686. package/tools/narrate.mjs +257 -0
  687. package/tools/omni.mjs +298 -0
  688. package/tools/omni_paths.py +12 -0
  689. package/tools/omnichat.mjs +1577 -0
  690. package/tools/omnivideo.py +1122 -0
  691. package/tools/package.mjs +130 -0
  692. package/tools/platforms.mjs +236 -0
  693. package/tools/premiere.mjs +533 -0
  694. package/tools/publish.mjs +1496 -0
  695. package/tools/reference.mjs +1408 -0
  696. package/tools/render.mjs +426 -0
  697. package/tools/runner.mjs +156 -0
  698. package/tools/setup.mjs +466 -0
  699. package/tools/skills-release.mjs +93 -0
  700. package/tools/sound.mjs +1323 -0
  701. package/tools/soundtrack.mjs +217 -0
  702. package/tools/thumbnail.mjs +271 -0
  703. package/tools/timing.mjs +108 -0
  704. package/tools/usage.py +628 -0
  705. package/tools/voice-envelope.mjs +185 -0
  706. package/tools/voice.py +448 -0
  707. package/tools/voice_sample.py +75 -0
  708. package/tools/wireframe.mjs +230 -0
@@ -0,0 +1,13 @@
1
+ import type { ReferenceSummary } from "../types/api";
2
+ import { formatSeconds } from "./format";
3
+
4
+ /* the short facts of a reference's measurements: duration, size, fps, shots, hold, BPM */
5
+ export function referenceFacts(m: ReferenceSummary["measurements"]) {
6
+ if (!m) return [];
7
+ return [
8
+ `${formatSeconds(m.duration)} · ${m.w}×${m.h} · ${m.fps} fps`,
9
+ m.shots != null && (m.shots === 1 ? "Um plano só" : `${m.shots} planos`),
10
+ m.hold_pct != null && `Segura ${m.hold_pct}%`,
11
+ m.bpm ? `${m.bpm} BPM` : null,
12
+ ].filter(Boolean) as string[];
13
+ }
@@ -0,0 +1,40 @@
1
+ /* Service health as the UI shows it (ServicesPanel on the Videos page, ConnectionSignals). */
2
+
3
+ import type { Services } from "../types/api";
4
+ import { formatElapsed } from "./format";
5
+
6
+ export type Health = { variant: "ok" | "warning" | "error"; text: string; hint?: string };
7
+
8
+ export function premiereStatus(p: Services["premiere"], exporting: boolean): Health {
9
+ if (p.ok) return { variant: "ok", text: "Ponte conectada" };
10
+ if (exporting) return { variant: "warning", text: "Exportando: o Premiere fica travado até terminar" };
11
+ if (p.age_ms == null) {
12
+ return {
13
+ variant: "error",
14
+ text: "Ponte não encontrada",
15
+ hint: "Abra o Premiere com um projeto e o painel Window → Extensions (Legacy) → MCP Bridge (CEP).",
16
+ };
17
+ }
18
+ if (!p.started)
19
+ return {
20
+ variant: "warning",
21
+ text: "Painel aberto, ponte parada",
22
+ hint: "Clique em Start Bridge no painel MCP Bridge.",
23
+ };
24
+ /* the panel delays the heartbeat while Premiere is busy; it only counts as gone after a while */
25
+ if (p.age_ms < 15_000)
26
+ return { variant: "warning", text: `Ponte lenta: sem batimento há ${formatElapsed(p.age_ms)}` };
27
+ return {
28
+ variant: "error",
29
+ text: `Sem batimento há ${formatElapsed(p.age_ms)}`,
30
+ hint: "Premiere fechado ou travado. Aberto e parado? Feche e reabra o painel MCP Bridge.",
31
+ };
32
+ }
33
+
34
+ export function swapStatus(m: Services["memory"]) {
35
+ const fraction = m.swap_total_mb ? m.swap_used_mb / m.swap_total_mb : 0;
36
+ return { fraction, variant: (fraction >= 0.9 ? "error" : fraction >= 0.75 ? "warning" : "ok") as Health["variant"] };
37
+ }
38
+
39
+ /* MB as GB with a decimal comma */
40
+ export const gb = (mb: number) => (mb / 1024).toLocaleString("pt-BR", { maximumFractionDigits: 1 });
@@ -0,0 +1,103 @@
1
+ /* Studio agent sessions as the UI shows them: state label, type name, where each lives on
2
+ screen, the chat route that resumes it and what an empty panel says. */
3
+
4
+ import type { Session, SessionState, SessionType } from "../types/api";
5
+ import { api, enc } from "./api";
6
+
7
+ export const SESSION_STATE: Record<SessionState, { text: string; variant: string }> = {
8
+ running: { text: "Agente trabalhando", variant: "running" },
9
+ stopped: { text: "Agente parou", variant: "warning" },
10
+ error: { text: "Agente parou com erro", variant: "error" },
11
+ interrupted: { text: "Sessão interrompida", variant: "error" },
12
+ };
13
+
14
+ export const costLabel = (s: Session) => (s.total_cost ? ` · US$ ${s.total_cost.toFixed(2)}` : "");
15
+
16
+ /* the chat request: resumes the last studio session or opens a new one */
17
+ export const chatRequest = (type: SessionType, target: string, message: string) => {
18
+ const json = { message };
19
+ if (type === "analysis") return api.analytics.claude.$post({ json });
20
+ if (type === "edit") return api.videos[":slug"].edit.claude.$post({ param: { slug: enc(target) }, json });
21
+ if (type === "video") return api.videos[":slug"].claude.$post({ param: { slug: enc(target) }, json });
22
+ return api.references[":name"].claude.$post({ param: { name: enc(target) }, json });
23
+ };
24
+
25
+ /* where the session lives on screen (href) */
26
+ export const sessionPagePath = (s: Session) =>
27
+ s.type === "video"
28
+ ? `/videos/${encodeURIComponent(s.target)}`
29
+ : s.type === "edit"
30
+ ? `/videos/${encodeURIComponent(s.target)}/render`
31
+ : s.type === "analysis"
32
+ ? "/"
33
+ : `/styles/${encodeURIComponent(s.target)}`;
34
+
35
+ /* the same, as TanStack <Link> props: <Link {...sessionPageLink(s)}> */
36
+ export type SessionPageLink =
37
+ | { to: "/videos/$slug"; params: { slug: string } }
38
+ | { to: "/videos/$slug/$stage"; params: { slug: string; stage: string } }
39
+ | { to: "/"; params?: undefined }
40
+ | { to: "/styles/$name"; params: { name: string } };
41
+ export const sessionPageLink = (s: Session): SessionPageLink =>
42
+ s.type === "video"
43
+ ? { to: "/videos/$slug", params: { slug: s.target } }
44
+ : s.type === "edit"
45
+ ? { to: "/videos/$slug/$stage", params: { slug: s.target, stage: "render" } }
46
+ : s.type === "analysis"
47
+ ? { to: "/" }
48
+ : { to: "/styles/$name", params: { name: s.target } };
49
+
50
+ /* how the session type reads in a list */
51
+ export const SESSION_TYPE_NAME: Record<SessionType, string> = {
52
+ video: "vídeo",
53
+ reference: "estilo visual",
54
+ analysis: "análise",
55
+ edit: "edição",
56
+ omni: "Omni",
57
+ };
58
+
59
+ /* what the empty box says for each session type: none (no session yet), label (send button), hint (placeholder) */
60
+ export const EMPTY_COPY: Record<SessionType, { none: string; label: string; hint: string }> = {
61
+ video: {
62
+ none: "Nenhuma sessão do studio neste vídeo: se ele está num chat, siga por lá",
63
+ label: "Continuar com o agente",
64
+ hint: "Opcional: o que fazer. Vazio, ele retoma da próxima etapa do status.",
65
+ },
66
+ reference: {
67
+ none: "Nenhuma sessão do studio neste estilo visual",
68
+ label: "Pedir ao agente",
69
+ hint: "O que fazer neste estilo visual: medir de novo, completar o guia, extrair tokens…",
70
+ },
71
+ analysis: {
72
+ none: "Nenhuma análise pedida pela tela ainda",
73
+ label: "Perguntar ao agente",
74
+ hint: "O que você quer saber das métricas: por que um Reel foi bem, o que testar no próximo…",
75
+ },
76
+ omni: {
77
+ none: "O Omni ainda não conversou por texto hoje",
78
+ label: "Perguntar ao Omni",
79
+ hint: "Pergunte sobre seus vídeos, métricas ou peça uma alteração",
80
+ },
81
+ edit: {
82
+ none: "Peça a edição em palavras: o agente mexe na timeline por você",
83
+ label: "Editar",
84
+ hint: "Ex.: corte as pausas maiores que meio segundo · atrase a animação da c03 meio segundo · tire o card da c02 · ponha o logo no canto no fim…",
85
+ },
86
+ };
87
+
88
+ /* what the user asked in a turn: the prompt the UI built carries the request after
89
+ "Pedido feito pel… :" (PT prompt prose); a first turn without a request is the session start */
90
+ export function turnRequest(prompt: string) {
91
+ const m = /Pedido feito pel[oa] [^:\n]*:\s*([\s\S]*)$/.exec(prompt);
92
+ if (m) return m[1].trim();
93
+ return prompt.trim().startsWith("/") ? null : prompt.trim();
94
+ }
95
+
96
+ /* one turn of GET /api/sessions/:id `history` */
97
+ export type TurnHistory = {
98
+ n: number;
99
+ origin: string;
100
+ prompt: string;
101
+ started_at: string;
102
+ result: { text: string; error: boolean; denied: string[] } | null;
103
+ };
@@ -0,0 +1,58 @@
1
+ /* The settings categories: one id in the URL (/settings/$category), a name and a sidebar group. */
2
+
3
+ export type SettingsCategoryId = "voice" | "providers" | "usage" | "agent" | "platforms" | "publishing";
4
+ export type SettingsCategory = { id: SettingsCategoryId; name: string; description: string };
5
+
6
+ export const CATEGORY_GROUPS: { name: string; categories: SettingsCategory[] }[] = [
7
+ {
8
+ name: "Produção",
9
+ categories: [
10
+ {
11
+ id: "voice",
12
+ name: "Voz",
13
+ description:
14
+ "O módulo de voz fala o texto de cada cena com a voz clonada do canal. Cada perfil guarda essa voz em um ou mais provedores (ElevenLabs, Fish Audio, Cartesia, VoiceStudio), na ordem de prioridade: se o primeiro falhar, a fala sai pelo próximo. O perfil ativo é o que vem marcado no vídeo novo.",
15
+ },
16
+ {
17
+ id: "usage",
18
+ name: "Uso das vozes",
19
+ description:
20
+ "O que sobra na Fish e na Cartesia e o que cada vídeo gastou. O plano e a cota ficam em Voz → Provedores de voz",
21
+ },
22
+ {
23
+ id: "agent",
24
+ name: "Agente de IA",
25
+ description: "Qual agente roda as sessões do studio, a conta dele e o modelo por etapa",
26
+ },
27
+ ],
28
+ },
29
+ {
30
+ name: "Distribuição",
31
+ categories: [
32
+ {
33
+ id: "platforms",
34
+ name: "Plataformas",
35
+ description: "YouTube, Instagram e TikTok: a conta e as chaves de cada uma",
36
+ },
37
+ {
38
+ id: "publishing",
39
+ name: "Publicação",
40
+ description: "O texto fixo, a publicação automática, a agenda e o omnichat",
41
+ },
42
+ ],
43
+ },
44
+ ];
45
+
46
+ /* outside the sidebar: opened by the "Configurar provedores" button of the Voice page, which stays marked in the menu */
47
+ export const PROVIDERS_CATEGORY: SettingsCategory = {
48
+ id: "providers",
49
+ name: "Provedores de voz",
50
+ description:
51
+ "As chaves e os modelos de cada provedor. Valem para todas as vozes dele; o Voice ID é de cada voz e fica no editor dela, em Voz.",
52
+ };
53
+
54
+ /* every category; the first (voice) is the default */
55
+ export const SETTINGS_CATEGORIES: SettingsCategory[] = [
56
+ ...CATEGORY_GROUPS.flatMap(g => g.categories),
57
+ PROVIDERS_CATEGORY,
58
+ ];
@@ -0,0 +1,33 @@
1
+ /* Web Audio of the sound timeline: one context for the page, decoded buffers kept by URL, and the
2
+ library's file preview (one at a time). */
3
+
4
+ let globalCtx: AudioContext | null = null;
5
+ export const audioCtx = () => (globalCtx ??= new AudioContext({ sampleRate: 48000 }));
6
+ const buffers = new Map<string, Promise<AudioBuffer>>();
7
+ export function loadBuffer(url: string): Promise<AudioBuffer> {
8
+ if (!buffers.has(url))
9
+ buffers.set(
10
+ url,
11
+ fetch(url)
12
+ .then(r => {
13
+ if (!r.ok) throw new Error(`${r.status} ${url}`);
14
+ return r.arrayBuffer();
15
+ })
16
+ .then(b => audioCtx().decodeAudioData(b)),
17
+ );
18
+ return buffers.get(url)!;
19
+ }
20
+
21
+ /* the library's ▶: plays the file; the same one again pauses it */
22
+ let listener: HTMLAudioElement | null = null;
23
+ export function previewFile(url: string | null) {
24
+ if (!url) return;
25
+ if (listener && listener.dataset.url === url && !listener.paused) {
26
+ listener.pause();
27
+ return;
28
+ }
29
+ listener?.pause();
30
+ listener = new Audio(url);
31
+ listener.dataset.url = url;
32
+ listener.play().catch(() => {});
33
+ }
@@ -0,0 +1,291 @@
1
+ /* Pure helpers of the sound timeline (VideoPage's SoundTimeline): formatting, media URLs, time ↔ px,
2
+ snapping, clip and cut edits and the playback windows. Two timelines, like tools/cuts.mjs:
3
+ "original" (scenes.json time) and "edited" (the timeline's, with the area cuts closed). */
4
+
5
+ import { normalizeCuts, removedDuration, keptSegments, toEdited, toOriginal } from "../../../tools/cuts.mjs";
6
+ import { animationStart, animationInstant, clipLength, clipSpeed } from "../../../tools/soundtrack.mjs";
7
+ import type {
8
+ SoundCatalog,
9
+ SoundClip,
10
+ SoundCut,
11
+ SoundData,
12
+ SoundEffectInfo,
13
+ SoundPlace,
14
+ SoundPlanItem,
15
+ } from "../types/api";
16
+
17
+ export const NO_CUTS: SoundCut[] = [];
18
+ export const NO_LINES: Record<string, SoundClip[]> = {};
19
+ export const PLAYER_WIDTH_KEY = "omnivideo.editor.player-width";
20
+ export const MERGE_MS = 500;
21
+ export const HISTORY_LIMIT = 200;
22
+ /* height of one effects lane, in px */
23
+ export const LANE_HEIGHT = 26;
24
+ export const SMALL_ROLES = new Set(["click", "tick", "pop", "typing"]);
25
+
26
+ export const clone = <T>(o: T): T => JSON.parse(JSON.stringify(o));
27
+ export const round2 = (n: number) => `${n.toFixed(2)}s`;
28
+ /* the timer and the timeline ruler: minute:second */
29
+ export const minSeconds = (n: number) => `${Math.floor(n / 60)}:${String(Math.floor(n % 60)).padStart(2, "0")}`;
30
+ export const placeKey = (l: { type: string; scene: string; element: string }) => `${l.type}:${l.scene}:${l.element}`;
31
+ export const mediaSrc = (slug: string, rel: string, v?: number) =>
32
+ `/media/${encodeURIComponent(slug)}/${rel.split("/").map(encodeURIComponent).join("/")}${v ? `?v=${v}` : ""}`;
33
+ export const effectSrc = (slug: string, e: SoundEffectInfo | undefined) =>
34
+ !e ? null : e.origin === "kit" ? `/kit/${encodeURIComponent(e.name)}` : mediaSrc(slug, `sfx/${e.name}`);
35
+ /* the kit's "bed" role shows as background music */
36
+ export const roleLabel = (p: string) => (p === "bed" ? "música de fundo" : p);
37
+ /* the voice volume control → gain: quadratic curve, so the middle of the control sounds like half */
38
+ export const gainOf = (pct: number) => (pct / 100) ** 2;
39
+
40
+ /* lanes: each effect on the first lane where it doesn't touch the previous one */
41
+ export function lanesOf(items: { id: string; start: number; duration: number }[]): Map<string, number> {
42
+ const end: number[] = [];
43
+ const m = new Map<string, number>();
44
+ for (const it of [...items].sort((a, b) => a.start - b.start)) {
45
+ let f = end.findIndex(x => x <= it.start + 0.01);
46
+ if (f < 0) {
47
+ f = end.length;
48
+ end.push(0);
49
+ }
50
+ end[f] = it.start + it.duration;
51
+ m.set(it.id, f);
52
+ }
53
+ return m;
54
+ }
55
+ /* how many lanes the effects row needs (at least one) */
56
+ export const laneCountOf = (lanes: Map<string, number>) => Math.max(1, ...[...lanes.values()].map(f => f + 1));
57
+
58
+ /* --- time ↔ px ------------------------------------------------------------------------- */
59
+
60
+ /* x: seconds → px at this zoom; E: original time → edited; boxOf: the box of an original span
61
+ (empty if it fell in a cut) */
62
+ export function timelineScale(zoom: number, cuts: SoundCut[]) {
63
+ const x = (s: number) => s * zoom;
64
+ const E = (o: number) => toEdited(o, cuts);
65
+ const boxOf = (a: number, b: number) => ({ left: x(E(a)), width: x(E(b) - E(a)) });
66
+ return { x, E, boxOf };
67
+ }
68
+ /* edited time → time of the export on screen (which may have other cuts, or none) */
69
+ export const toExportTime = (t: number, cuts: SoundCut[], exportCuts: SoundCut[]) =>
70
+ toEdited(toOriginal(t, cuts), exportCuts);
71
+ /* a point in original time shifted by dt seconds of the timeline (edited time) */
72
+ export const shiftOriginal = (base: number, dt: number, cuts: SoundCut[]) =>
73
+ toOriginal(toEdited(base, cuts) + dt, cuts);
74
+
75
+ /* --- snapping -------------------------------------------------------------------------- */
76
+
77
+ /* the pointer on the timeline (edited time): snaps to the nearest target within 7 px (unless Alt),
78
+ aligned to the frame and kept inside the video */
79
+ export function snapPointer(
80
+ raw: number,
81
+ o: { alt: boolean; zoom: number; fps: number; total: number; targets: number[] },
82
+ ) {
83
+ let best = raw;
84
+ if (!o.alt) {
85
+ let dmin = 7 / o.zoom;
86
+ for (const a of o.targets)
87
+ if (Math.abs(a - raw) < dmin) {
88
+ dmin = Math.abs(a - raw);
89
+ best = a;
90
+ }
91
+ }
92
+ return Math.max(0, Math.min(o.total, Math.round(best * o.fps) / o.fps));
93
+ }
94
+ /* the razor: snaps only to the playhead (unless Alt), on the frame */
95
+ export function snapRazor(raw: number, o: { alt: boolean; zoom: number; fps: number; total: number; t: number }) {
96
+ const s0 = !o.alt && Math.abs(raw - o.t) * o.zoom < 7 ? o.t : raw;
97
+ return Math.max(0, Math.min(o.total, Math.round(s0 * o.fps) / o.fps));
98
+ }
99
+ /* a dragged clip's start (edited time) snapped by either edge to the nearest anchor within 7 px;
100
+ anchors null (Alt) leaves it free */
101
+ export function snapClipStart(ed: number, length: number, anchors: number[] | null, zoom: number) {
102
+ if (!anchors) return ed;
103
+ let dmin = 7 / zoom,
104
+ shift = 0;
105
+ for (const al of anchors)
106
+ for (const edge of [0, length]) {
107
+ const d = al - (ed + edge);
108
+ if (Math.abs(d) < dmin) {
109
+ dmin = Math.abs(d);
110
+ shift = d;
111
+ }
112
+ }
113
+ return ed + shift;
114
+ }
115
+ /* the offset that puts a clip's start at edited time `ed`, on the clip's grid, within ±30 s */
116
+ export function dragOffsetAt(ed: number, o: { cuts: SoundCut[]; base: number; from: number; step: number }) {
117
+ const offset = Math.round((toOriginal(ed, o.cuts) - o.base - o.from) / o.step) * o.step;
118
+ return Math.max(-30, Math.min(30, offset));
119
+ }
120
+
121
+ /* --- clips ----------------------------------------------------------------------------- */
122
+
123
+ export const sameClips = (a: SoundClip[], b: SoundClip[]) =>
124
+ a.length === b.length &&
125
+ a.every(
126
+ (x, i) =>
127
+ Math.abs(x.from - b[i].from) < 1e-3 &&
128
+ Math.abs(x.to - b[i].to) < 1e-3 &&
129
+ Math.abs(x.offset - b[i].offset) < 1e-3 &&
130
+ Math.abs(clipSpeed(x) - clipSpeed(b[i])) < 1e-3,
131
+ );
132
+ /* the clips the export has (the old assembly.json kept only a number, the `video_em`) */
133
+ export function exportClipsOf(exp: SoundData["export"] | undefined, c: { id: string; duration: number }): SoundClip[] {
134
+ const v = exp?.scene_clips?.[c.id];
135
+ return Array.isArray(v) ? v : [{ from: 0, to: c.duration, offset: Number(v) || 0 }];
136
+ }
137
+ /* an offset on the clip's grid (seconds), within ±30 s */
138
+ export const quantizeOffset = (offset: number, step: number) =>
139
+ +(Math.round(Math.max(-30, Math.min(30, offset)) / step) * step).toFixed(4);
140
+ /* the razor: the clip's two halves at instant t (original time), each with the same `offset`;
141
+ null if a half would be shorter than one step */
142
+ export function splitClip(c: SoundClip, t: number, base: number, step: number): [SoundClip, SoundClip] | null {
143
+ /* a sped clip covers `speed` seconds of the file per second of video */
144
+ const local = Math.round((c.from + (t - (base + c.from + c.offset)) * clipSpeed(c)) / step) * step;
145
+ if (local - c.from < step || c.to - local < step) return null;
146
+ return [
147
+ { ...c, to: +local.toFixed(4) },
148
+ { ...c, from: +local.toFixed(4) },
149
+ ];
150
+ }
151
+ /* the edges of all clips (edited time), for the drag snap; without the clip itself */
152
+ export function clipEdgesOf(
153
+ kind: "video" | "voice",
154
+ id: string,
155
+ k: number,
156
+ o: {
157
+ scenes: { id: string; start: number; clips: SoundClip[] }[];
158
+ lines: { id: string; start: number; clips: SoundClip[] }[];
159
+ lineClips: Record<string, SoundClip[]>;
160
+ E: (o: number) => number;
161
+ },
162
+ ) {
163
+ const { E } = o;
164
+ return [
165
+ ...o.scenes.flatMap(c =>
166
+ c.clips.flatMap((cl, j) =>
167
+ kind === "video" && c.id === id && j === k
168
+ ? []
169
+ : [E(c.start + cl.from + cl.offset), E(c.start + cl.from + cl.offset + clipLength(cl))],
170
+ ),
171
+ ),
172
+ ...o.lines.flatMap(f =>
173
+ (o.lineClips[f.id] ?? f.clips).flatMap((cl, j) =>
174
+ kind === "voice" && f.id === id && j === k
175
+ ? []
176
+ : [E(f.start + cl.from + cl.offset), E(f.start + cl.from + cl.offset + clipLength(cl))],
177
+ ),
178
+ ),
179
+ ];
180
+ }
181
+
182
+ /* --- places and plan items ------------------------------------------------------------- */
183
+
184
+ /* where a beat or transition lands in the video: on the animation piece it falls in (null: in a
185
+ deleted piece) */
186
+ export function placeInstant(
187
+ l: SoundPlace,
188
+ scenes: { id: string; start: number; duration: number; clips: SoundClip[] }[],
189
+ ) {
190
+ if (l.instant == null) return null;
191
+ const c = scenes.find(x => x.id === l.scene);
192
+ if (!c) return l.instant;
193
+ return l.type === "transition" ? animationStart(c) : animationInstant(c, l.instant - c.start);
194
+ }
195
+ /* the place whose instant is nearest to `point` (original time); null if none has an instant */
196
+ export function nearestPlace(places: SoundPlace[], point: number, instantOf: (l: SoundPlace) => number | null) {
197
+ const nearest = places
198
+ .map((l, i) => ({ i, d: instantOf(l) == null ? Infinity : Math.abs(instantOf(l)! - point) }))
199
+ .sort((a, b) => a.d - b.d)[0];
200
+ return !nearest || !Number.isFinite(nearest.d) ? null : nearest.i;
201
+ }
202
+ /* the plan item of a place's layer */
203
+ export const findPlanItem = (items: SoundPlanItem[], place: SoundPlace, layer: number) =>
204
+ items.find(
205
+ it => it.type === place.type && it.scene === place.scene && it.element === place.element && it.layer === layer,
206
+ );
207
+ /* the place a plan item belongs to (-1: none) */
208
+ export const placeIndexOf = (places: SoundPlace[], it: SoundPlanItem) =>
209
+ places.findIndex(l => l.type === it.type && l.scene === it.scene && l.element === it.element);
210
+ export const findEffect = (catalog: SoundCatalog, name: string) =>
211
+ catalog.kit.find(e => e.name === name) ?? catalog.video.find(e => e.name === name);
212
+ /* the sound a new layer gets: the kit's transition or whoosh for a transition, pop or click for a beat */
213
+ export function defaultSoundName(catalog: SoundCatalog | undefined, type: SoundPlace["type"]): string {
214
+ const kit = catalog?.kit.filter(e => !e.music) ?? [];
215
+ const pref = type === "transition" ? ["transition", "whoosh"] : ["pop", "click"];
216
+ return (
217
+ (
218
+ kit.find(e => e.role === pref[0]) ??
219
+ kit.find(e => e.role === pref[1]) ??
220
+ kit[0] ??
221
+ catalog?.video.find(e => !e.music)
222
+ )?.name ?? ""
223
+ );
224
+ }
225
+ /* the background music "+ música de fundo" adds: the kit's texture or bed, or a music captured for the video */
226
+ export const defaultBedName = (catalog: SoundCatalog) =>
227
+ catalog.kit.find(e => e.role === "texture" || e.role === "bed")?.name ?? catalog.video.find(e => e.music)?.name;
228
+ /* "place:layer" keys → [place, layer] pairs, last first (so splicing one keeps the others' indices) */
229
+ export const layersInDeleteOrder = (keys: string[]) =>
230
+ keys.map(k => k.split(":").map(Number)).sort((a, b) => b[0] - a[0] || b[1] - a[1]);
231
+ /* the effects as the timeline shows them: in edited time, without what fell entirely in a cut */
232
+ export const editedItemsOf = (items: SoundPlanItem[], cuts: SoundCut[]) =>
233
+ items
234
+ .map(it => {
235
+ const ini = toEdited(it.start, cuts);
236
+ return {
237
+ ...it,
238
+ start: ini,
239
+ duration: toEdited(it.start + it.duration, cuts) - ini,
240
+ peak: toEdited(it.peak, cuts),
241
+ };
242
+ })
243
+ .filter(it => it.duration > 0.001);
244
+
245
+ /* --- area cuts ------------------------------------------------------------------------- */
246
+
247
+ /* the cuts with the marked area [a, b] (edited time) removed too, in original time; null if the
248
+ video would be left with less than half a second */
249
+ export function cutsWithArea(cuts: SoundCut[], area: [number, number], total: number, fps: number) {
250
+ const [a, b] = area;
251
+ const next: SoundCut[] = normalizeCuts([...cuts, { from: toOriginal(a, cuts), to: toOriginal(b, cuts) }], total, fps);
252
+ return total - removedDuration(next) < 0.5 ? null : next;
253
+ }
254
+
255
+ /* --- playback -------------------------------------------------------------------------- */
256
+
257
+ /* the kept spans (original time [a, b]) and where each starts in edited time (e) */
258
+ export const keptSpans = (cuts: SoundCut[], total: number) =>
259
+ (keptSegments(cuts, total) as [number, number][]).map(([a, b]) => ({ a, b, e: toEdited(a, cuts) }));
260
+ /* when (delay after `from`, edited time), from where (offset in the file) and for how long a file
261
+ placed at `start` (original time) plays: only inside the kept spans, joined in edited time.
262
+ `off`/`dur` play only that span of the file (a voice clip); `speed` plays it faster: `delay` stays
263
+ in video seconds, `offset` and `dur` are seconds of the file (what AudioBufferSourceNode.start takes,
264
+ with playbackRate = speed) */
265
+ export function playbackWindows(
266
+ f: { start: number; off?: number; dur?: number; speed?: number },
267
+ bufferDuration: number,
268
+ spans: { a: number; b: number; e: number }[],
269
+ from: number,
270
+ ) {
271
+ const out: { delay: number; offset: number; dur: number }[] = [];
272
+ const off = f.off ?? 0;
273
+ const v = f.speed ?? 1;
274
+ const end = f.start + Math.min(f.dur ?? Infinity, bufferDuration - off) / v;
275
+ for (const sp of spans) {
276
+ const ini = Math.max(f.start, sp.a),
277
+ upTo = Math.min(end, sp.b);
278
+ if (upTo <= ini) continue;
279
+ let delay = sp.e + (ini - sp.a) - from,
280
+ offset = off + (ini - f.start) * v,
281
+ dur = (upTo - ini) * v;
282
+ if (delay + dur / v <= 0) continue;
283
+ if (delay < 0) {
284
+ offset -= delay * v;
285
+ dur += delay * v;
286
+ delay = 0;
287
+ }
288
+ out.push({ delay, offset, dur });
289
+ }
290
+ return out;
291
+ }
@@ -0,0 +1,86 @@
1
+ /* One EventSource for the whole page (GET /api/events). Queue, services and sessions arrive
2
+ whole; video, reference, omnichat and analytics arrive as "changed" notices. lib/query-client.ts
3
+ turns both into TanStack Query cache updates; components only see the query hooks. */
4
+
5
+ export const SSE_EVENTS = [
6
+ "queue",
7
+ "services",
8
+ "video",
9
+ "sessions",
10
+ "reference",
11
+ "omnichat",
12
+ "analytics",
13
+ "agent",
14
+ ] as const;
15
+ export type SseEvent = (typeof SSE_EVENTS)[number];
16
+
17
+ export type Listener = (event: SseEvent, data: any) => void;
18
+
19
+ const listeners = new Set<Listener>();
20
+ const connectionListeners = new Set<() => void>();
21
+ let source: EventSource | null = null;
22
+ let connected = false;
23
+
24
+ function setConnected(c: boolean) {
25
+ connected = c;
26
+ connectionListeners.forEach(l => l());
27
+ }
28
+
29
+ const reconnectListeners = new Set<() => void>();
30
+ const RETRY_MS = 5000;
31
+ let everConnected = false;
32
+
33
+ export function openEventSource() {
34
+ if (source) return;
35
+ const es = new EventSource("/api/events");
36
+ source = es;
37
+ es.onopen = () => {
38
+ const back = everConnected && !connected;
39
+ everConnected = true;
40
+ setConnected(true);
41
+ /* events were missed while it was down: whoever shows data rereads it */
42
+ if (back) reconnectListeners.forEach(l => l());
43
+ };
44
+ es.onerror = () => {
45
+ setConnected(false);
46
+ /* a dropped stream retries by itself; a refused one (the hosted studio's 503 while the studio isn't
47
+ connected) is closed for good by the browser: open another one in a few seconds */
48
+ if (es.readyState === EventSource.CLOSED) {
49
+ source = null;
50
+ setTimeout(openEventSource, RETRY_MS);
51
+ }
52
+ };
53
+ for (const event of SSE_EVENTS) {
54
+ source.addEventListener(event, e => {
55
+ const data = JSON.parse((e as MessageEvent).data);
56
+ listeners.forEach(l => l(event, data));
57
+ });
58
+ }
59
+ }
60
+
61
+ /* listen to every event of the global stream; returns the unsubscribe */
62
+ export function subscribe(listener: Listener) {
63
+ openEventSource();
64
+ listeners.add(listener);
65
+ return () => {
66
+ listeners.delete(listener);
67
+ };
68
+ }
69
+
70
+ /* the stream came back after being down; returns the unsubscribe */
71
+ export function onReconnect(listener: () => void) {
72
+ reconnectListeners.add(listener);
73
+ return () => {
74
+ reconnectListeners.delete(listener);
75
+ };
76
+ }
77
+
78
+ /* connection state, for useSyncExternalStore (hooks/useConnected.ts) */
79
+ export function subscribeConnection(onChange: () => void) {
80
+ openEventSource();
81
+ connectionListeners.add(onChange);
82
+ return () => {
83
+ connectionListeners.delete(onChange);
84
+ };
85
+ }
86
+ export const isConnected = () => connected;