@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,792 @@
1
+ # Learnings
2
+
3
+ One entry per problem: symptom, cause, what fixed it. Newest on top.
4
+ Before debugging something odd, look here.
5
+
6
+ ## 2026-10-13 · A scene rule loses to `_common.html` at the same specificity
7
+
8
+ **Symptom:** in c10 of video 2026-10-13-esse-e-o-roteiro-sua, the chips with
9
+ `class="card chip"` came out with the gray border of `.card`, not the orange
10
+ one of `.chip` written in the scene's `<style>`.
11
+ **Cause:** the build pastes `_common.html` at the start of `<body>`, after the
12
+ scene's `<head>` `<style>`. At equal specificity (`.card` × `.chip`) the rule
13
+ that comes last wins: the common one.
14
+ **Fixed:** in the scene, raise the specificity (`.card.chip`, or an `#id`) for
15
+ everything that changes a property the common file also sets.
16
+
17
+ ## 2026-10-13 · `min_duration` ignored: composition scenes at 0.8 s
18
+
19
+ **Symptom:** in video 2026-10-12-uma-das-maiores-limitacoes-de, after writing
20
+ `min_duration` 3.6 on c02, `build-motion.mjs --scene c02` kept reporting
21
+ "0.80s" and "⚠ pouco tempo até o fim da cena" for every beat.
22
+ **Cause:** the `timing` run during the preview wrote `duration: 0.8` and
23
+ `start` on every scene that had no line yet (default hold). `loadVideo()` in
24
+ `tools/timing.mjs` only estimates the duration when `scene.duration == null`,
25
+ so the stale value beats the new `min_duration`.
26
+ **Fixed:** in composition, delete `duration` and `start` from scenes without
27
+ lines (and `total_duration`); the build goes back to estimating from
28
+ `min_duration`. The timing stage (`omnivideo.py timing`) rewrites both after
29
+ the voice.
30
+
31
+ ## 2026-10-13 · Composition coming out with 0.8 s scenes
32
+
33
+ **Symptom:** in video 2026-10-13-eu-dei-mais-contexto-para, when composing
34
+ c02–c09 after the preview, `scenes.json` had `duration: 0.8` and `start` on
35
+ every scene without lines; `build-motion.mjs` would use 0.8 s instead of
36
+ `min_duration`.
37
+ **Cause:** `omnivideo.py timing` ran during the preview, when only c01 had
38
+ voice, and wrote `duration` (the hold alone) and `start` on the others.
39
+ `loadVideo()` in `timing.mjs` only estimates the duration when
40
+ `scene.duration` is missing.
41
+ **Fixed:** delete `duration` and `start` from scenes still without voice (and
42
+ `total_duration`) before composing; stage 5's `timing` writes them again.
43
+ Real fix: `timing` should not write a duration for a scene without lines.
44
+
45
+ ## 2026-10-12 · `enters_with` does not accept a hyphenated word
46
+
47
+ **Symptom:** `build-motion.mjs` stopped with "referência de tempo inválida:
48
+ c01f1:código-fonte" (video 2026-10-12-hook-e-se-voce-pudesse).
49
+ **Cause:** the regex of `resolveTime()` in `tools/timing.mjs` reads `-` as the
50
+ start of the offset (`-0.3`), so the word cannot contain a hyphen.
51
+ **Fixed (workaround):** point at the previous word with an offset
52
+ (`c01f1:ao+0.25`, which lands on the start of "código-fonte"). If the voice is
53
+ redone, check the offset. Real fix: accept a hyphen followed by a letter in the
54
+ regex.
55
+
56
+ ## 2026-10-12 · Child of a card that dropped stays on screen
57
+
58
+ **Symptom:** in video 2026-10-12-criaram-uma-ferramenta-para-a, the dark card
59
+ dropped out in c06, but the two tracks inside it stayed on screen until the end
60
+ (c06, c07 and c08), on top of everything else.
61
+ **Cause:** the continuous composition's `pose()` hides with
62
+ `visibility:hidden`, and each track wrote its own `visibility:visible`. In CSS
63
+ a `visible` child shows even when its parent is `hidden` (opacity multiplies,
64
+ visibility does not).
65
+ **Fixed:** the children are only visible if the parent is (`cardOn`). When you
66
+ put a node inside another one that hides with `visibility`, the child must not
67
+ write `visible` on its own.
68
+
69
+ ## 2026-10-12 · Two stills at the same `t` with different hashes
70
+
71
+ **Symptom:** in c07 of video 2026-10-12-roteiro-nem-toda-decisao-precisa, two
72
+ `--still --at 2.37` runs gave different hashes (PSNR 48.7 dB, nothing visible
73
+ even at 40× contrast). The same showed up comparing the last frame of c07 with
74
+ frame 0 of c01 (loop).
75
+ **Cause:** not the scene. PSNR per strip: all `inf` down to y 1600, the
76
+ difference only in the bottom 320 px, the strip headless Chrome fills with
77
+ garbage from the top (entry "The bottom ~140 px of the frame repeat the top",
78
+ still unfixed in `render.mjs` at the time).
79
+ **Fixed:** to check determinism or a seam, compare per strip:
80
+ `ffmpeg -i a.png -i b.png -filter_complex "[0:v]crop=1080:320:0:${y}[a];[1:v]crop=1080:320:0:${y}[b];[a][b]psnr"`
81
+ (in zsh, `${y}` needs the braces: `$y[a]` becomes an array subscript).
82
+
83
+ ## 2026-10-12 · Burned-in caption on top of the big number
84
+
85
+ **Symptom:** in the export of video 2026-10-12-https-x-com-0xcodila-status, the
86
+ caption (pill, safe area `all`) landed at y ≈ 1160–1248, on top of the data
87
+ block (500 DÓLARES at 1140–1252). A `y: -160` override on c02–c04 only moved
88
+ the pill on top of the phone. The assembly sheet did not show the problem in
89
+ c01, c05 and c06 because it takes one frame per scene, at the first caption,
90
+ before the number comes in.
91
+ **Cause:** the scene was designed with the old rule of `templates/scene.html`
92
+ (caption in the bottom 19 %, y > 1555). In the ffmpeg assembly, the `all` safe
93
+ area ends 35 % above the bottom: the caption never goes below y 1248 in 9:16,
94
+ and a 47 px pill is ~88 px tall.
95
+ **Fixed:** in composition, reserve a ~90 px band for the caption above y 1248
96
+ and set the same `captions.y` for the whole video (here the data block moved
97
+ down from 1112 to 1160, and `y: -108` puts the pill at 1052–1140). Check with
98
+ frames from the MP4 at the moments the content is full
99
+ (`ffmpeg … select='eq(n\,N)+…',tile=6x1`), not only with the assembly sheet.
100
+
101
+ ## 2026-10-12 · `frame` and `excerpt` refuse `apura-motion`
102
+
103
+ **Symptom:** `node tools/reference.mjs frame apura-motion 4.5` exits with
104
+ "não tem vídeo na raiz"; `list` shows "sem measurements.json · vídeo fora da
105
+ raiz".
106
+ **Cause:** that reference keeps its two reels in `reels/` and its guide in
107
+ `MOTION-SVG.md`; `reference.mjs` only looks for the video at the folder root.
108
+ **Fixed:** measure with ffmpeg directly, which the studio session allows:
109
+ `ffmpeg -ss <t> -i <dir>/reels/<reel>.mp4 -frames:v 1 <out>.png` for a full
110
+ frame, and `-vf "fps=1,scale=360:-1,tile=5x3"` for a sheet. The frames go in
111
+ `videos/<slug>/source/ref/`. Typography and zones came from there (video
112
+ 2026-10-12-https-x-com-0xcodila-status).
113
+
114
+ ## 2026-10-12 · `measure` sees 1 shot in an 11-scene piece
115
+
116
+ **Symptom:** on the `dark-vibrant-elements` reference (near-black background,
117
+ 74 % of the area at `#010102`), `measure` reported "1 plano, sem corte" and did
118
+ not generate `sheets/cuts.png`. Reading the `excerpt` sheets, the piece has 11
119
+ hard cuts.
120
+ **Cause:** the detector compares the whole image, and between two mostly black
121
+ frames the difference stays under the threshold, even when the hero changes.
122
+ The color flip of the whole scene (green → red) also almost went unnoticed
123
+ (energy 0.75).
124
+ **Fixed:** on a dark reference, do not trust `shots` or `cuts`. Lay out the
125
+ whole piece with `excerpt` at 10 fps in 4 s sheets and count the scenes by
126
+ reading them. The `rhythm.changes` list in `measurements.json` still works as a
127
+ map: every real cut fell inside one of its windows. For the exact frame, pick a
128
+ point that changes from one scene to the next (a corner of the canvas, a
129
+ spotlight) and run `color` at t = n/30 on both sides. Reading at 10 fps got 3
130
+ of the 10 cuts wrong by 1–3 frames (2.07 → 2.133, 13.95 → 14.033, 28.40 →
131
+ 28.367).
132
+ **Update 2026-10-14:** the cut detector in `reference.mjs` now also marks a cut
133
+ on a local peak (≥ 0.06 and 5× the median of the ±0.5 s around it), besides the
134
+ fixed 0.3 jump. On dark-vibrant-elements it finds 7 of the 10 cuts, on the
135
+ exact frame (before: 0); on pure-dark, 3 of 3 (before: 0); ascii and
136
+ samuel-rizzon still have no cut at all, as they should. 4.667, 16.667 and
137
+ 28.367 s still slip through: on a dark piece, counting from the sheet still
138
+ wins when it disagrees with the shots.
139
+
140
+ ## 2026-10-12 · Reference color read by eye in a studio session
141
+
142
+ **Symptom:** while filling the GUIDE.md of the `motion` reference in a session
143
+ opened by the studio, the colors that are not in `measure`'s palette
144
+ (background ink, brand, violet, card border) were left as `≈`, read by eye from
145
+ the PNG.
146
+ **Cause:** the tool had no way to read a pixel, and ad-hoc Python
147
+ (`python -c` with PIL) falls outside the allow list: a studio session has no
148
+ one to approve, so the denial is immediate and lasts for the whole session.
149
+ **Fixed:** `node tools/reference.mjs color <name> <t> <x>,<y> …` returns the
150
+ pixel and the 5×5 average at each point, in hex and OKLCH. On thin strokes
151
+ (letters, 1 px borders) use the pixel; on flat areas, the average. For the
152
+ exact time of a flip, sample the background frame by frame with `color`
153
+ instead of reading the `excerpt` sheet: the 30 fps sheet showed a gray at
154
+ 3.367 s that the exact frame already gave as black (one frame off).
155
+
156
+ ## 2026-10-12 · `status` skipping the preview, the narration and the voice
157
+
158
+ **Symptom:** on a video stopped at stage P (only the preview scene had lines,
159
+ already voiced, and the other scenes had `lines: []`), `status` dropped the
160
+ preview row, marked ✓ narration and ✓ voice and said "próxima etapa: tempo". A
161
+ chat resuming the video would go straight past the approval and the narration
162
+ of the other scenes. Found while reviewing the studio, which showed the
163
+ preview as "anterior à etapa" and hid the approve button.
164
+ **Cause:** the three checks only looked at the lines that exist. With all of
165
+ them voiced and no `preview` in `scenes.json`, the video fell into the "video
166
+ made before the preview existed" rule.
167
+ **Fixed:** narration requires a line in every scene; voice requires narration
168
+ and audio for every line; legacy requires the voice ready for the whole video.
169
+ A complete video (like roteador-de-decisoes) comes out the same as before.
170
+
171
+ ## 2026-10-12 · Checking the Premiere bridge opened Premiere
172
+
173
+ **Symptom:** a risk found while building the studio's services panel, before it
174
+ happened: checking the bridge every few seconds with `premiere.mjs status`.
175
+ **Cause:** `verify_premiere_connection` has `launchIfNeeded` on by default:
176
+ with Premiere closed, it opens the app. And each check is a script on the
177
+ bridge, which runs one at a time; in the middle of a `premiere.mjs assemble`
178
+ it queues behind it.
179
+ **Fixed:** the studio reads the heartbeat the panel writes to
180
+ `/tmp/premiere-mcp-bridge/bridge-heartbeat.json` every ~1 s (stale for more
181
+ than 2.5 s means the bridge is down, the same limit the server uses). To check
182
+ by hand without opening anything: `node tools/premiere.mjs call
183
+ verify_premiere_connection '{"launchIfNeeded": false}'`.
184
+
185
+ ## 2026-10-12 · Ctrl-C that does not interrupt the task
186
+
187
+ **Symptom:** in the queue test, `kill -INT` on the group of an `omnivideo.py`
188
+ launched with `&` by a script stopped nothing; the task went on and kept the
189
+ turn.
190
+ **Cause:** a shell without a terminal launches background processes with
191
+ SIGINT ignored, and Python keeps the ignored signal it inherited. In a
192
+ terminal, Ctrl-C works and the queue releases the turn.
193
+ **Fixed:** in the test, restore the signal
194
+ (`perl -e '$SIG{INT}="DEFAULT"; exec @ARGV' …`). To stop a task launched that
195
+ way, `kill <pid>` (the pid is in `tools/job_queue.py`); the kernel releases
196
+ the lock and the ticket becomes `interrupted`.
197
+
198
+ ## 2026-10-12 · `RuntimeWarning: divide by zero encountered in matmul` in captions
199
+
200
+ **Symptom:** `omnivideo.py captions` prints three `RuntimeWarning`s from
201
+ `faster_whisper/feature_extractor.py` (divide by zero, overflow, invalid value).
202
+ **Cause:** numpy in the spectrogram computation. It shows up the same with the
203
+ previous version of the tool.
204
+ **Fixed:** nothing to do: the words and the similarity come out identical to
205
+ before. Ignore the warning; what matters is the `⚠` line for a line that
206
+ differs from its text.
207
+
208
+ ## 2026-10-12 · Blank sheets in the full-page screenshot of the studio
209
+
210
+ **Symptom:** a full-page screenshot of the studio (windowless Chrome,
211
+ `captureBeyondViewport`) with the sheets and the last scene's still blank.
212
+ **Cause:** the images have `loading="lazy"`, and capturing beyond the visible
213
+ area does not scroll the page: they never request the file.
214
+ **Fixed:** to check the screen, scroll to the section and capture the visible
215
+ area. In a real browser they load on scroll.
216
+
217
+ ## 2026-10-12 · The bottom ~140 px of the frame repeat the top
218
+
219
+ **Symptom:** on a 1920×1080 board, the bottom strip of the PNG showed the start
220
+ of the page again. A page of numbered strips confirmed it: at 1080×1920 and at
221
+ 1920×1080, the bottom ~140 px of every frame are the top ~140 px.
222
+ **Cause:** headless Chrome opens the `--window-size` window with a usable area
223
+ ~140 px shorter. `setDeviceMetricsOverride` takes the viewport to W×H, but the
224
+ captured surface ends earlier, and the rest is filled with the top. It goes
225
+ unnoticed when top and bottom share the same flat background, as in 9:16 with
226
+ the empty Reels zones.
227
+ **Fix:** a window taller than the frame, `--window-size=${W},${H + 400}`. The
228
+ strips come out right up to the edge in both formats. Applied in
229
+ `tools/render.mjs` on 2026-10-12, when the caption became allowed outside the
230
+ safe area (a pill at y > 1794 came out clipped).
231
+
232
+ ## 2026-10-12 · Wide comma and missing space in Schibsted Grotesk numbers
233
+
234
+ **Symptom:** the timer came out "0 , 108 s", with the comma as wide as a digit;
235
+ once that was fixed, it came out "0,108s", without the space.
236
+ **Cause:** Schibsted's `tabular-nums` also makes the punctuation tabular. The
237
+ space disappeared because the number sat loose inside a `display:flex` parent:
238
+ loose text becomes a flex item and loses its trailing space.
239
+ **Fixed:** tnum only on the digits
240
+ (`<span class="tn">0</span>,<span class="tn">108</span> s`) and the whole
241
+ number inside a span.
242
+
243
+ ## 2026-10-12 · "Adobe Media Encoder is not installed" with AME installed
244
+
245
+ **Symptom:** `premiere.mjs export` failed with `MEDIA_ENCODER_NOT_INSTALLED`,
246
+ without reaching Premiere.
247
+ **Cause:** a bug in `adobe-premiere-pro-mcp` 1.2.8: on macOS it looks for the
248
+ `.app` directly in `/Applications`, and Adobe installs it inside a folder.
249
+ **Fixed:** a symlink `/Applications/Adobe Media Encoder 2026.app` pointing to
250
+ the real app (details in `premiere-mcp.md`).
251
+
252
+ ## 2026-10-12 · A2 with one clip too many
253
+
254
+ **Symptom:** `premiere.mjs assemble` reported "A2 tem 8 clips, esperado 7" and
255
+ an effect out of place.
256
+ **Cause:** a swoosh with a late peak started 0.4 s before the click of the next
257
+ beat; on the same track, `add_to_timeline` in overwrite mode cut the swoosh in
258
+ two.
259
+ **Fixed:** `sound.mjs` merges overlapping effects into one mixed clip (`clips`
260
+ in `sound/plan.json`), and `premiere.mjs assemble` places clips. The faulty
261
+ sequence stayed in the project; the good one is `v2`.
262
+
263
+ ## 2026-10-12 · "Ritmo estranho" on a correct line
264
+
265
+ **Symptom:** `omnivideo.py voice` flagged 2.1 words/s twice on the same line.
266
+ **Cause:** a sentence of long words ("especializados", "resolvidas"): 35
267
+ syllables in 6.4 s, a normal rate when measured in syllables.
268
+ **Fixed:** nothing to regenerate. The captions gave similarity 1.0, and that
269
+ is what tells whether the voice got it wrong.
270
+
271
+ ## 2026-10-12 · 1.2 s of silence in the middle of a sentence
272
+
273
+ **Symptom:** the hook sentence continues into the next scene ("…é relevante, /
274
+ você está pagando caro…"), and the default timing put 0.8 s of stillness at the
275
+ end of one scene and 0.4 s of lead-in at the start of the other.
276
+ **Cause:** lead-in and hold were the same for every scene.
277
+ **Fixed:** each scene can have its own `lead_in` and `hold` (`hold: 0` on the
278
+ one that cuts the sentence, `lead_in: 0.25` on the one that finishes it).
279
+
280
+ ## 2026-10-12 · Composition pasted inside a CSS comment
281
+
282
+ **Symptom:** `_common.html` landed in the middle of the scene's `<style>`.
283
+ **Cause:** the base scene quoted the marker `<!-- omnivideo:common -->` in a CSS
284
+ comment, and the build replaced the first occurrence.
285
+ **Fixed:** the build only accepts the marker alone on a line, and the base no
286
+ longer quotes the literal marker.
287
+
288
+ ## 2026-10-12 · Hard cut opening on an empty frame
289
+
290
+ **Symptom:** in the c03 → c04 transition sheet, all three panels empty.
291
+ **Cause:** the trace disappears at the cut, and the first node only came in on
292
+ its own beat, which falls at the start of the line (the lead-in after the cut).
293
+ **Fixed:** after a hard cut, the first element is already in the frame of the
294
+ cut. The hard-cut sheet now shows the last frame of the outgoing scene
295
+ (`duration − 1 frame`), not the instant of the cut, which in a continuous
296
+ composition is already the next scene.
297
+
298
+ ## 2026-10-12 · Sound effect peak off the beat
299
+
300
+ **Symptom:** a short click landed 23 ms before the beat, and a trimmed riser
301
+ 42 ms after.
302
+ **Cause:** the peak was measured on a mono 8 kHz decode. Without the highs, the
303
+ click's transient disappears and the maximum becomes the body of the sound.
304
+ **Fixed:** `sound.mjs` measures in the same format as the WAV that goes to the
305
+ timeline (48 kHz, two channels) and trims with `atrim`. Measured error: under
306
+ 0.5 ms.
307
+
308
+ ## 2026-10-12 · Background jumping at the cut between scenes
309
+
310
+ **Symptom:** the animated background restarted in every scene; in the
311
+ transition sheet, the overlap came out with a ghost.
312
+ **Cause:** the scene only knew its own time (`--t` starts at 0 in each one).
313
+ **Fixed:** the build injects `--scene-start`, and whatever crosses the cut runs
314
+ on video time. Side effect: changing a scene's duration forces rendering the
315
+ following ones; `motion/<id>.render.json` records the start used and `status`
316
+ flags it.
317
+
318
+ ## 2026-10-12 · `No such filter: 'drawtext'`
319
+
320
+ **Symptom:** the transition sheet broke when labeling the panels.
321
+ **Cause:** this machine's Homebrew ffmpeg has no freetype.
322
+ **Fixed:** sheets without text, with a fixed and documented panel order.
323
+
324
+ ## 2026-10-12 · Video without lines treated as final timing
325
+
326
+ **Symptom:** before narration, the build did not mark the video
327
+ `provisional` and allowed `--render`.
328
+ **Cause:** `timing.mjs` only marked it provisional when estimating a line;
329
+ without lines, nothing was estimated.
330
+ **Fixed:** an estimated duration or start also marks the video as
331
+ provisional.
332
+
333
+ ## 2026-10-12 · Generic voice with no error at all
334
+
335
+ **Symptom:** the lines came out too fast and in a voice that was not Pedro's.
336
+ **Cause:** the config pointed to a `profile_id` that had been deleted.
337
+ VoiceStudio's `POST /generate` does not validate the id and generates without
338
+ a clone.
339
+ **Fixed:** the profile is chosen by name ("Pedro") and `omnivideo.py voice`
340
+ fails unless it finds exactly one.
341
+
342
+ ## 2026-10-12 · `import av` loading the wrong file
343
+
344
+ **Symptom:** `module 'av' has no attribute 'audio'` while transcribing.
345
+ **Cause:** the tool was called `tools/av.py`; `faster-whisper` imports the PyAV
346
+ library as `av` and Python found the local file first.
347
+ **Fixed:** renamed to `tools/omnivideo.py`. Do not create a file in `tools/`
348
+ named after a library.
349
+
350
+ ## 2026-10-12 · Contact sheet breaking in ffmpeg
351
+
352
+ **Symptom:** `vstack: Input 1 width 1280 does not match input 0 width 1920`.
353
+ **Cause:** the `--sheet` of the old renderer (from the `soft-spatial-motion`
354
+ skill, since deleted) built rows of 3; with 4 or 5 times the last row came out
355
+ narrow.
356
+ **Fixed:** the rewritten `tools/render.mjs` builds the grid with ffmpeg's
357
+ `tile` filter, which pads the last row.
358
+
359
+ ## 2026-10-12 · Card clipped in 9:16
360
+
361
+ **Symptom:** a scene rendered at 1080×1920 with the card clipped on the right
362
+ and an empty background below.
363
+ **Cause:** the old base scene (`scene.html` from the deleted skill) fixed the
364
+ canvas at 1920×1080.
365
+ **Fixed:** `templates/scene.html` sizes the canvas from the viewport; the same
366
+ file works for 9:16 and 16:9.
367
+
368
+ ## 2026-10-12 · Premiere: response without `sequenceId`
369
+
370
+ **Symptom:** `add_to_timeline: expected string, received undefined` right after
371
+ creating the sequence.
372
+ **Cause:** tools from the expanded catalog return their data inside `data`.
373
+ **Fixed:** the client flattens `data` into the response.
374
+
375
+ ## 2026-10-11 · Whisper skipping the start of the audio
376
+
377
+ **Symptom:** transcription starting at second 4.3; the first sentence was gone.
378
+ **Cause:** the sentence had been passed as `initial_prompt`; Whisper skips a
379
+ span identical to the hint.
380
+ **Fixed:** no hint. The spelling comes from the known text, by alignment.
381
+
382
+ ## 2026-10-11 · Generation abandoned after 305 s
383
+
384
+ **Symptom:** "TTS generate ran for more than 305s… abandoned".
385
+ **Cause:** a 59 s reference without a transcript (VoiceStudio transcribed it 4
386
+ times before each generation) plus 11.9 of 12 GB of swap.
387
+ **Fixed:** a short reference with a transcript, and memory freed. Short lines
388
+ (one sentence) also keep each generation far from the limit.
389
+
390
+ ## 2026-10-12 · Studio `claude -p` session denying commands
391
+
392
+ **Symptom:** in the session opened from the studio, even `echo` and
393
+ `$PY tools/…` came back "Permission … denied … no approval surface".
394
+ **Cause:** without a terminal, nobody approves. `auto` mode denies whatever
395
+ would need approval, and a Bash rule does not match a command that expands a
396
+ shell variable.
397
+ **Fixed:** `acceptEdits` + `studio.claude.allow` in the config, with
398
+ VoiceStudio's Python by its full path (`{python}`), and a system prompt asking
399
+ for full paths, one command per call and no `curl`.
400
+ **Update (12/10/2026, Claude Code 2.1.284):** `auto` now works in
401
+ `claude -p --permission-prompts none`: chained commands, shell variables, `~`
402
+ and writes outside the project ran without denial; the classifier only denies
403
+ what is risky. `studio.claude.permission_mode` became `auto`; the allowlist
404
+ stayed, as pre-approval.
405
+
406
+ ## 2026-10-12 · Premiere out of the way; burned-in captions without libass
407
+
408
+ **Symptom:** stage 8 depended on Premiere being open, on the bridge panel, on
409
+ Media Encoder (with a symlink because of an MCP bug) and on ExtendScript
410
+ approval; the caption track came out in the default style, unreadable on a
411
+ light background.
412
+ **Cause:** Premiere only repeated an assembly whose timings `scenes.json`
413
+ already had; the MCP does not apply caption styles. And Homebrew's ffmpeg
414
+ (9.0.1) came without libass, `subtitles` and `drawtext`.
415
+ **Fixed:** `tools/assemble.mjs` assembles and exports with ffmpeg. The
416
+ captions are drawn in HTML (`templates/captions.html`), one transparent PNG per
417
+ caption (`render.mjs --frames --alpha`), overlaid by a concat slideshow with
418
+ the timings snapped to the fps grid and converted to bt709 before the overlay
419
+ (in bt601 the pill's white shifts tone). Two-pass loudnorm to −14 LUFS.
420
+
421
+ ## 2026-10-12 · `model:` in a skill without fork does not change the model in `claude -p`
422
+
423
+ **Symptom:** a skill with `model: haiku` in its frontmatter, called from a
424
+ `claude -p --model sonnet` session: its work ran on Sonnet (`modelUsage` only
425
+ had Sonnet). The docs say the override applies while the skill is active.
426
+ **Cause:** not investigated; measured on Claude Code 2.1.284.
427
+ **Fixed:** `context: fork` on the skill. With fork it runs in a subagent with
428
+ its own `model` and `effort` (Haiku in `modelUsage`, permissions inherited,
429
+ `$ARGUMENTS` arrives, and a fork can call another forked skill). Every stage
430
+ skill runs this way; `tools/models.mjs apply` writes the three fields.
431
+
432
+
433
+ ## 2026-10-12 · Epidemic effect: the MP3 URL does not show in the Network tab
434
+
435
+ **Symptom:** when capturing effects in the Epidemic Sound search through Claude
436
+ in Chrome, `read_network_requests` and `performance.getEntriesByType` showed no
437
+ `audiocdn.epidemicsound.com/lqmp3/…` after play (only the
438
+ `waveform/<id>.json`, whose id is a different one and gives 404 on `lqmp3/`).
439
+ In a freshly loaded tab, `javascript_tool` hung for 45 s and the list had zero
440
+ rows.
441
+ **Cause:** the player plays through an `<audio>` created outside the page; the
442
+ media request shows up neither in the extension's log nor in resource timing.
443
+ And the results list only renders while the tab is painted: in the background
444
+ React does not render.
445
+ **Fixed:** `tools/epidemic-capture.js` intercepts the
446
+ `HTMLMediaElement.prototype.src` setter and clicks the "Play <title>" buttons of
447
+ the `[data-testid=track-row]` rows, one at a time (`sound.mjs capture` prints
448
+ the code). Take a screenshot of the tab before running it. The CDN serves the
449
+ MP3 without login, so `sound.mjs download` downloads straight into the video's
450
+ `sfx/`. A studio session needs `--chrome` on `claude -p` to get the Chrome
451
+ tools.
452
+
453
+ ## 2026-10-12 · Studio session "running" forever: zombie process
454
+
455
+ **Symptom:** turn 4 of session 7d3fc032 (av-motion in a fork composing c02–c08)
456
+ stayed "running" in the studio with no new event. The `claude -p` had already
457
+ exited (≈ 16:36, `cost-state` written and no `result`) and showed up as
458
+ `<defunct>`.
459
+ **Cause:** the studio runs with `bun --watch`; a reload (an edit to the
460
+ sessions server module at 16:34, now `studio/api/services/sessions.ts`) replaces the
461
+ process image, and a child that exits afterwards is no longer reaped: it
462
+ becomes a zombie. `kill(pid, 0)` answers for a zombie, so the liveness check
463
+ said it was alive. The reload did not kill the turn (the heartbeats went on
464
+ until 16:36:38); what ended it was not recorded.
465
+ **Fixed:** the liveness check (`isAlive()` in `studio/api/services/queue.ts`, and its
466
+ twins in `tools/job-queue.mjs` and `tools/job_queue.py`) checks the state in
467
+ `ps` and treats `Z` as dead: the session shows as interrupted and can be
468
+ resumed from the studio, and a queue ticket stuck on a zombie no longer blocks
469
+ the machine. Avoid editing the studio while a session is running.
470
+
471
+ ## 2026-10-12 · TikTok connected in the terminal, "não conectado" in the studio
472
+
473
+ **Symptom:** `publish.mjs auth tiktok` ended with "TikTok conectado:
474
+ @galdinoai" and `status` showed ✓, but the studio's card and panel still said
475
+ "não conectado" (not connected). Before that, the first login (authorized in
476
+ Dia) never came back to `127.0.0.1`: two `auth tiktok` were waiting at the same
477
+ time (one from the terminal, one from the studio's Conectar button), each on a
478
+ different port and with a different `state`.
479
+ **Cause:** the studio caches `status --json` for 5 min and only drops it when
480
+ the login goes through the studio; a login from the terminal writes `.env`
481
+ without telling it. The failure in Dia has no confirmed cause; with a single
482
+ login, through Chrome, it worked.
483
+ **Fixed:** `getAccounts()` in `studio/api/services/publish.ts` rereads when `.env` is
484
+ newer than the cached read. To connect, one login at a time: through the
485
+ studio's button or through the terminal, not both.
486
+
487
+ ## 2026-10-12 · Instagram asks for video_url; TikTok refuses a public account
488
+
489
+ **Symptom:** on the first publish, `Instagram (criar container): 400 The
490
+ parameter video_url is required` and `TikTok (abrir envio): 403 Please review
491
+ our integration guidelines`.
492
+ **Cause:** resumable upload (`upload_type=resumable` + rupload.facebook.com)
493
+ only exists for apps with Facebook login; with Instagram login, Meta only
494
+ downloads from a public `video_url`. On TikTok, the generic message was the
495
+ code `unaudited_client_can_only_post_to_private_accounts`: an unaudited app can
496
+ only post directly to a private account.
497
+ **Fixed:** `publish.mjs` serves the MP4 through a cloudflared quick tunnel only
498
+ while publishing to Instagram (and checks the URL through the 1.1.1.1 DNS:
499
+ macOS DNS caches the "does not exist" of a new name for more than a minute). On
500
+ TikTok, that code becomes a draft in the app's inbox. Errors now show the
501
+ platform's code, not just the message.
502
+
503
+ ## 2026-10-12 · A .json file in .queue/ takes the studio down
504
+
505
+ **Symptom:** the studio crashed at startup with `undefined is not an object
506
+ (evaluating '(b.fim ?? b.chegada).localeCompare')` in the studio's queue module
507
+ (now `api/services/queue.ts`; the message quotes the old ticket keys, now `ended_at`
508
+ and `arrived_at`).
509
+ **Cause:** the first version of the scheduler wrote its index as a `.json` in
510
+ the queue folder (now `.queue/`). The queue (`queue.ts` and `job_queue.py`)
511
+ reads every `.json` in `.queue/` as a ticket, and that one had no
512
+ `arrived_at`.
513
+ **Fixed:** the scheduler has its own folder, `.schedule/`. Nothing but tickets
514
+ goes in `.queue/` with a `.json` extension.
515
+
516
+ ## 2026-10-12 · Loud and uneven effects: leveled by peak
517
+
518
+ **Symptom:** effects too loud, uneven among themselves (a click disappears, a
519
+ whoosh blows up), fighting the voice and at a different level in each video.
520
+ **Cause:** `sound.mjs` brought every effect to the same peak (−16 dBFS). Peak
521
+ is not what you hear: a dense riser or whoosh sounds much louder than a click
522
+ with the same peak. Measured on the 2026-10-12 videos, the effects sat between
523
+ −5 and +7.7 dB relative to the voice (max loudness over 200 ms against the
524
+ voice's integrated loudness), with ~13 dB of spread inside a single video. The
525
+ voice of the lines comes out at ~−29 LUFS and loudnorm raises everything by
526
+ ~15 dB, effects included.
527
+ **Fixed:** `sound.mjs` measures each effect, already trimmed and processed, by
528
+ perceived loudness (BS.1770 K-weighting, window `sound.window_s`, checked
529
+ against ffmpeg's `ebur128`) and places it `sound.level_db` below the video's
530
+ integrated voice loudness. While the voice speaks, the effect drops by
531
+ `sound.ducking.db`, along a curve computed from the speech segments (words,
532
+ when aligned). Since the assembly normalizes the mix by the voice, the final
533
+ effect level is the same from one video to the next. The assembly's loudnorm
534
+ stays in "dynamic" mode (quiet voice at the source + −1 dBTP ceiling), as it
535
+ was in every earlier export.
536
+
537
+ ## 2026-10-12 · Still or sheet with a frame from another video
538
+
539
+ **Symptom:** in the composition of `2026-10-12-e-se-em-vez-de`, the c07 sheet
540
+ came out with frames from another video ("MODELO DE RACIOCÍNIO", "Opus 5.5",
541
+ R$), and the c05 → c06 transition came out with c06 all white. The still of the
542
+ same scene, in the same build, was right.
543
+ **Cause:** `render.mjs` picks Chrome's debugging port from the pid
544
+ (`9300 + (pid·7 + n·31) % 600`) and does not check whether it is free. With
545
+ another render running on the machine (another session, or outside the queue),
546
+ both instances can land on the same port: `/json/list` answers with the other
547
+ Chrome and the capture comes from its page.
548
+ **Fixed (for now):** run the scene's build again; and **read every PNG**, which
549
+ is what catches the error. Real fix, pending: in `render.mjs`, open Chrome with
550
+ `--remote-debugging-port=0` and read the port from
551
+ `<profile>/DevToolsActivePort`, or test the port before using it.
552
+
553
+ ## 2026-10-13 · Fixed-duration alarm runs past the cut when the voice delays the beat
554
+
555
+ **Symptom:** in c04 of `hook-um-agente-de-ia`, `SPAM` blinked until 4.03 s in a
556
+ 3.80 s scene: the last frame came out dark, and the alarm sound leaked over the
557
+ c05 transition.
558
+ **Cause:** the beat was planned at 1.2 s, but with the voice "spam" landed at
559
+ 2.73 s. `SR.alarme` had a fixed 0.3 s × 3 (+0.4 after the beat), and the
560
+ composition does not check what still runs after the last beat. The build warns
561
+ "pouco tempo até o fim da cena", but does not say by how much it overruns.
562
+ **Fixed:** `SR.alarme(t, t0, per)` takes the period (default 0.3); c04 uses
563
+ 0.2 s starting at +0.26 and the alarm sound with `dur` 0.6. For a beat near the
564
+ end, add beat + everything it triggers and compare with the scene's real
565
+ duration.
566
+
567
+ ## 2026-10-13 · Cartesia clone never got created, and nobody saw the error
568
+
569
+ **Symptom:** when cloning the voice with Fish and Cartesia checked, only Fish
570
+ created it; the profile came out without a Cartesia Voice ID and the edit
571
+ dialog had no way to create it there.
572
+ **Cause:** Cartesia answers `402 plan_upgrade_required` to
573
+ `POST /voices/clone` on the free plan (cloning through the API is paid only).
574
+ `clone.ts` kept the error as a warning, but the screen closed the modal on
575
+ partial success and the warning was lost.
576
+ **Fixed:** the 402 becomes a clear message; a clone that fails on one provider
577
+ opens the voice in the edit dialog with the warning; "Editar voz" → Fish/Cartesia
578
+ → "Configurar" (Edit voice → Configure) has "Criar voz" (Create voice)
579
+ (`/api/settings/clone/recreate`, also on ElevenLabs), which uses the recording
580
+ kept in `.clones/` or asks for audio when the voice has no recording. The
581
+ Cartesia plan can be detected without creating anything: an empty
582
+ `POST /voices/clone` returns 402 on free and 400 on paid
583
+ (`/api/settings/clone/plan`). ElevenLabs validates the form before the plan, so
584
+ its error only shows on the click.
585
+
586
+ ## 2026-10-14 · A wireframe came out as Chrome's empty page
587
+
588
+ **Symptom:** on the first pass of `wireframe.mjs` (12 scenes, 4 Chromes in
589
+ parallel), `c08.png` came out light and empty, with the gradient of the
590
+ browser's blank page, and the sheet showed that frame blank. The other 11 came
591
+ out right, and the c08 HTML had no error.
592
+ **Cause:** a transient failure of one of the parallel Chromes (did not
593
+ reproduce).
594
+ **Fixed:** `node tools/wireframe.mjs videos/<slug> --only c08` redid just that
595
+ one, correctly, and rewrote the sheet. Whole frame blank in the sheet: run
596
+ `--only` before touching the HTML.
597
+
598
+ ## 2026-10-14 · Narration and voice took minutes
599
+
600
+ **Symptom:** narration took 2 to 5.4 min and voice up to 3.7 min, with the
601
+ voice command itself taking 2–14 s.
602
+ **Cause:** subagent detours, not a slow tool. Narration opened the scenes' HTML
603
+ (`motion/src/`) looking for the beats and thought for 1 min on each read, while
604
+ the beat table in `motion.md` already says what each one shows. Voice, after
605
+ generating, transcribed the audio with `faster_whisper` to check pronunciation
606
+ (2.5 min), work the captions stage does right after. Both ran on Sonnet/Opus
607
+ at the time.
608
+ **Fixed:** the `av-narration` and `av-voice` skills now say what the stage does
609
+ not do (do not open `motion/src/`; do not transcribe). On Haiku, narration
610
+ reads only `motion.md`.
611
+
612
+ ## 2026-10-14 · Captions stopped transcribing
613
+
614
+ **Symptom:** captions took ~2.5 min per video running Whisper large-v3 on the
615
+ CPU, and held the queue all that time.
616
+ **Cause:** Whisper was only there to give each word's timing (the text is
617
+ already known: the narration wrote it) and to check pronunciation.
618
+ **Fixed:** `omnivideo.py captions` measures in the audio where the voice
619
+ starts and ends and splits the span among the words by letter count, anchored
620
+ on the real pauses. It takes seconds. Against Whisper, 0.15 s median (and
621
+ Whisper puts word starts about 0.1 to 0.2 s early). The pronunciation check was
622
+ lost: the signal of a bad line is now only the voice's `← ritmo estranho`.
623
+
624
+ ## 2026-10-14 · The render came out with voices the user had swapped
625
+
626
+ **Symptom:** in the studio, the user picked Fish versions for 5 lines of a
627
+ video in Cartesia; after render and assembly, the lines had gone back to
628
+ Cartesia. They picked again and Claude undid it again.
629
+ **Cause:** three failures together. `voice --use` saved the chosen version as
630
+ a fallback (provider ≠ the video's, without `provider_pinned`);
631
+ `--regenerate-fallback` ignored even `provider_pinned`; and the "vozes
632
+ misturadas" (mixed voices) warning counted those lines, and `av-voice` said to
633
+ unify before render, so Claude ran `--regenerate-fallback` and regenerated the
634
+ choices on Cartesia.
635
+ **Fixed:** `--use` sets `provider_pinned` when the version is from another
636
+ provider; `provider_pinned` is never redone on its own nor counted in the
637
+ warning; `av-voice` says that line is the user's choice. And swapping a voice
638
+ in the studio now pauses what comes after it (`voice-pause.json`,
639
+ `studio/api/services/voice-pause.ts`) until "Seguir com estas vozes" (Proceed with
640
+ these voices).
641
+
642
+ ## Omnichat: comments come back empty with the app in development mode (2026-10-14)
643
+
644
+ - **Symptom:** `GET /{media}/comments` answered 200 with `data: []` and a
645
+ `next`, even with `comments_count` 23 and the new token with
646
+ `instagram_business_manage_comments`.
647
+ - **Cause:** a Meta app in development mode only returns data from people with
648
+ a role in the app; a follower's comment disappears from the page, with no
649
+ error.
650
+ - **Fixed:** publish the app (Live), with the privacy policy URL in App
651
+ settings → Basic. For your own account, no App Review is needed.
652
+ - **Also:** the account's manual replies come as a standalone comment with
653
+ `@someone`, not nested under the comment: `omnichat.mjs` reads both forms.
654
+ - **And:** with Instagram login, the `/{media}/comments` listing already brings
655
+ the nested replies together with the comments (the account's one has
656
+ `@someone` in the text), and the `replies{…}` field comes back empty; to see a
657
+ comment's replies, use `/{comment}/replies`. Deleting an account comment:
658
+ `DELETE /{comment-id}`.
659
+
660
+ ## Screenshot of reddit.com through Claude in Chrome (14/10/2026)
661
+
662
+ **Symptom:** `navigate` to a Reddit thread returns "This site is not allowed due to safety restrictions".
663
+ **Cause:** the Claude in Chrome extension blocks reddit.com; it has nothing to do with omnivideo.
664
+ **What fixed it:** nothing to work around. The scene carries the screenshot as a pending asset (`source/sources.json`, field `missing`) and the report asks the user to take the capture by hand. The Codex logo also only exists as a PNG on openai.com: check the origin of every logo before calling it official.
665
+
666
+ ## Version "5.5" read as "cinco ponto cinco" (14/10/2026)
667
+
668
+ **Symptom:** Cartesia said "Haiku cinco ponto cinco"; the user does not want the word "ponto" in the voice, and the caption stays "5.5".
669
+ **Cause:** `line.text` is both voice and caption, and only VoiceStudio had a pronunciation dictionary.
670
+ **What fixed it:** `voice.pronunciation` in the config (term → how it is spoken), applied by `tools/voice.py` (`spoken_text()`) to the text sent to any provider and to the hash; `text` and the captions do not change. Lines without the term keep the same hash. Today: "Haiku 5.5" → "Haiku cinco cinco", "Haiku 4.5" → "Haiku quatro cinco". A new term goes there, not in the line's text.
671
+
672
+ ## Omnichat: the post link became the DM link (14/10/2026)
673
+
674
+ **Symptom:** the rule created by pasting the Reel into "Post que já está no ar" (Post already live; Omnichat page) came out with `link` = the Reel itself, and the DM sent the Reel's link at the end. The user also had to paste the link by hand after publishing to enable omnichat.
675
+ **Cause:** the studio's `createRuleFromLink()` passed the whole body, the post's `{ link }`, to `ruleFields()`, which reads `link` as what the DM delivers. And nothing enabled the rule when the Reel went up.
676
+ **What fixed it:** the body's `link` is only the post's (the DM's lives in the rule panel). `publish.mjs` calls `omnichat.mjs published` after Instagram and, with `omnichat.instagram.enable_on_publish`, the rule enables itself (if there is no rule, from the narration's "comenta X que eu te mando"). An omnivideo video does not need the post link: the id is in `publication.json`.
677
+
678
+ ## Videos came out long: a budget of 3.0 words per second (15/10/2026)
679
+
680
+ **Symptom:** scripts planned for 35–60 s came out at 55 to 118 s with the voice, and people stayed 13 to 25 s on average on the Reels (`metrics.mjs show`).
681
+ **Cause:** `av-script` and `av-narration` counted 3.0 words per second; the cloned voice speaks 2.2 (1.9 to 2.5, measured on the 14 videos from 12 to 14/10). A "45 s" script came out at about 61 s. And a finished script coming from another AI was kept whole, with no cuts.
682
+ **What fixed it:** budget = seconds × 2.2 × publishing speed (the exports go up at 1.15–1.2×), with a ceiling of 60 s published unless asked, in `av-script` (Budget) and in `av-narration`'s gate. The script the user sends is a draft: the facts and the opinion stay, the structure and the cut are redone, and the script approval shows them the result.
683
+
684
+ ## Hook: the first frame came out black or blurred (15/10/2026)
685
+
686
+ **Symptom:** 35% to 55% of people skipped in the first 3 seconds (the API's `reels_skip_rate`). The sheet of frames from 0 to 3 s showed the best performer opening on a black screen and the worst (55%) blurred until 3 s.
687
+ **Cause:** c01 started like the other scenes, with the hero coming in from nothing (opacity 0, blur). In the feed, frame 0 is what decides whether the person stops.
688
+ **What fixed it:** the script specifies the hook in three layers (line, frame 0, on-screen text), and `av-motion` treats c01 as a visual hook: hero and text already visible at t=0, entrance from a visible state, sheet `c01-opening.png` (0; 0.5; 1; 2 s) read at the gate. The effect is measured by the 3 s skip rate of the next videos (`channel/playbook.md`, learning 1).
689
+
690
+ ## A new studio page gives "não encontrado" on reload (15/10/2026)
691
+
692
+ **Symptom:** opening Analytics "sometimes crashed": the screen went white with "não encontrado" (not found) in the corner.
693
+ **Cause:** the `/analytics` route existed only in the web app's router (then `rota.tsx`); `studio.ts`'s `Bun.serve` did not serve it. Clicking in the menu worked, but reloading, opening the direct link or the `bun --watch` reload (which restarts on every saved file) fell into the server's 404.
694
+ **What fixed it:** `"/analytics"` and `"/analytics/:slug"` in `studio.ts`'s `routes`, like the other pages. A new page in the web app = a new route on the server, always both.
695
+
696
+ ## Bitmap style read as solid UI and the bottom of the frame was blank (15/10/2026)
697
+
698
+ **Symptom:** in the c01 preview of the Cloudflare skill video, the user rejected it: "os elementos estão muito sólidos" (window, bar, alert and title box were `cheio` rectangles, smooth 1-pixel outline, flat data lines) and "o fundo está sem textura na parte de baixo" (the dot grid stopped at y = 1555, and the bottom was plain paper).
699
+ **Cause:** the `bitmap` reference itself said so: `cheio` for box and bar, "ali só papel" in the caption zone. Only the cross/x and the S had visible pixels; the rest was flat design with square corners.
700
+ **What fixed it:** `F.chapa` in the engine (`referencias/bitmap/motor/bitmap.js`): a large shape is a dotted `bayer8` gradient, with a pixel halo and a solid band under the text (the 6 px pixel is larger than the mono label's stroke). Background: grid over the full height and a texture floor (0 → 0.12 in `cruz`) at the bottom. Guide, `proof/style.html` and the video's `_common.html` updated. A new video in the bitmap style: do not use `cheio` on anything larger than a badge.
701
+
702
+ ## First frame (and captions) with content from another video — colliding Chrome debugging port
703
+
704
+ - **Symptom:** the first frame of a scene (or the caption PNGs, opaque) came out with the screen of another video ("POR QUE IMPORTA?", "MILHARES DE LEADS"); the export showed that frame for the whole scene or for the first frames.
705
+ - **Cause:** `tools/render.mjs` derived Chrome's port from the PID. With two sessions rendering at the same time, the same port was used, and the render connected to the other session's Chrome and captured its page.
706
+ - **Fixed:** the render checks whether the port is free before opening Chrome (otherwise it draws another) and only accepts the page whose URL is its own file. If it shows up again, re-render the scene and read the first frame.
707
+
708
+ ## 8-bit kit effects played twice or came out stretched above 4× (15/10/2026)
709
+
710
+ - **Symptom:** in the render of the Cloudflare skill video, `sound.mjs` warned "velocidade 7× fora de 0,25–4×" on `passo-8bit` and `digitacao-rapida`, and "tocam juntos" on several pairs. Listening to the plan, every `select-8bit` gave a second blip 1 s later, which landed on top of the next effect (c01 `selo` × `vaza`, c03 `varre` × 3rd tick, c05 `agente` × `falha`).
711
+ - **Cause:** `select-8bit.mp3` has two blips (0 s and 1.0 s) and `passo-8bit.mp3` has four steps (0, 1, 2 and 3 s): they are variation files, and the kit measures the "useful" part up to the end. With a short `dur`, `sound.mjs` squeezed the four steps into 0.45 s; without `trim`, the select played both. The typing (9.4 s) was stretched to fit 1.2 s and 0.9 s.
712
+ - **Fixed:** `trim: [0, 0.15]` on every `select-8bit` and `passo-8bit` (one blip, no `dur`), and the typing as a trim the length of the movement, at its original speed, instead of `dur`. Before using a kit effect for the first time, look at its envelope (`ffmpeg … astats`) to see whether the file has more than one hit.
713
+
714
+ ## Carousel: slide with `01/01`, slide style ignored (16/10/2026)
715
+
716
+ - **Symptom:** in the first carousel (`2026-10-15-use-o-roteiro-voce-usa/carousel`), the cover came out with the counter `01/01` and the bleed stuck to the left edge; then s02's `justify-content` did not apply; and an edit by regex left three slides with no frame and no style.
717
+ - **Cause:** three: the comment at the top of `templates/slide.html` quoted a literal `</head>`, and the `carousel.mjs` injection landed inside the comment (no `OMNICAROUSEL` and no `--slide-i`); the `_common.html` `<style>` went into the body, after the slide's `<style>`, and beat it at equal specificity; the same comment quoted `<style>`, and a `re.sub` of `<style>.*?</style>` ate the end of the comment.
718
+ - **Fixed:** the injection goes at the last `</head>`; the common `<style>`s go up to the start of the head (base) and the slide's overrides; the template comment no longer has a literal tag. Write template comments without a literal `<tag>`, and edit slides with Edit or Write, not with a regex over the whole file.
719
+
720
+ ## `omnichat.mjs post <link>` rewrote the live rule of a published video (16/10/2026)
721
+
722
+ - **Symptom:** testing the button gate on a Reel, `post <link> --keyword TESTEBOTAO --link … --button` printed "Reel … → videos/2026-10-13-esse-e-o-roteiro-sua" and the video's enabled rule (204 DMs sent) came out with the test keyword, link, no public reply and the gate. For a few minutes nobody commenting `REA` would have been answered.
723
+ - **Cause:** `post` resolves a link that belongs to an omnivideo video to that video's own folder and applies the rule options on top of its rule, with no check that the rule already exists and is enabled.
724
+ - **Fixed:** the rule was rebuilt from `omnichat-record.json` (the keyword in 193 of the 204 comments answered, the only public reply used, the link in the video's `source/`) and confirmed with `test` and `run --dry-run` (0 sent). Before running `post`, `rule` or `enable` for a test, check what the link resolves to (`status`) and test on a post that has no rule; never reuse a post that is answering real comments.
725
+
726
+ ## Omnichat button: a follower tapped and got nothing (16/10/2026)
727
+
728
+ - **Symptom:** on the CLEF Reel, the comment got the DM with the "Receber link" button, but tapping it (as a follower) sent nothing; the record stayed `awaiting_tap`.
729
+ - **Cause:** the tap never left Meta. The app had no callback URL with the `messages` / `messaging_postbacks` fields subscribed, the account was not subscribed (`subscribed_apps`), and `webhook serve` was not running. Meta does not keep or resend taps made before the webhook exists.
730
+ - **Fixed:** callback URL and fields in the panel (Instagram → API setup with Instagram login → Configure webhooks → Webhook fields), `omnichat.mjs webhook subscribe`, server and tunnel up; the old button worked on the next tap, because its payload carries the post and the comment. Before turning on `button` / `require_follow`, `webhook status` must show the account subscribed and the server must answer through the public URL.
731
+
732
+ ## The composition cost more than all the other stages together (17/10/2026)
733
+
734
+ - **Symptom:** in `2026-10-16-https-x-ai-news-grok` (1 min, 9 scenes) the stage 3 fork (`av-motion`, opus) took ~60 % of the video's cost: 140 turns, 26 M cache-read tokens. The stages on haiku added up to ~1 %. Then a second opus fork was opened only to move a sound 0.4 s (c07 `confirma-leve` × c08 transition).
735
+ - **Cause:** one fork composed c02–c09 in sequence and its context grew from 47 k to 290 k tokens: every turn of c09 re-read the HTML of c02–c08. Output was a small part; what cost was re-reading. The sound overlap was a mechanical rule handed to a model.
736
+ - **Fixed:** the composition is one `av-motion` call per scene (`compor cNN`) plus a close (`fechar composição`), each reading only the style, `_common.html`, the preview's scene and the previous one (skills `av-motion` and `omnivideo`). `sound.mjs` resolves overlaps between beats by itself, keeping both peaks (`↔` in the output, `adjusted` in `sound/plan.json`). Before lowering a stage's model, measure where the tokens go: context size × turns weighs more than the model.
737
+
738
+ ## A WebGL scene never signalled `__ready` and a script inlined by the build printed as text (17/10/2026)
739
+
740
+ - **Symptom:** the VoiceAvatar demo rendered a blank frame after "a cena não sinalizou window.__ready = true em 20 s"; `getContext("webgl2")` was `null`. Later, once the build pasted the component in, the sheet showed the component's source as text on the page.
741
+ - **Cause:** `render.mjs` launches Chrome with `--disable-gpu`, which leaves no WebGL backend at all, so the component threw before `__ready`. For the text: the component's header comment had a literal closing script tag in its usage example, and a `<script>` pasted inline ends at the first closing tag, comments included.
742
+ - **Fixed:** `render.mjs` swaps in `--use-angle=swiftshader --enable-unsafe-swiftshader --ignore-gpu-blocklist` when the scene source mentions `webgl` or `VoiceAvatar` (`--gl` forces it); frames stay identical across seek order (checked by hash). `build-motion.mjs` refuses a component containing a closing script tag. Write component comments without literal tags, and give every WebGL scene a `try`/`catch` path or at least check `getContext` early. Also: a palette texture painted with radial gradients to `rgba(0,0,0,0)` gets a dark fringe (the canvas interpolates to transparent black), and mipmaps on a texture sampled through warped coordinates draw a fine hatch.
743
+
744
+ ## A component's window global overwrote the studio's React component of the same name (17/10/2026)
745
+
746
+ - **Symptom:** in a test bundle of the studio, `VoiceAvatar` (the React component) failed with "Element type is invalid … got: object", though it was a function in the source and rendered fine with `bun` on the server.
747
+ - **Cause:** `templates/components/voiceavatar/voiceavatar.js` ended with `window.VoiceAvatar = {…}` (what a scene needs). Bundled as a classic script, the studio's own top-level `function VoiceAvatar` is a global too, and the component's assignment replaced it with the plain object. The real studio loads its bundle as a module and was not hit, which is why only the test bundle showed it.
748
+ - **Fixed:** the component now exports through `module.exports` when a module system exists (the studio imports it) and only assigns `window.VoiceAvatar` as a plain script (a scene); `globalThis` stands in for `window`, so importing it on the server no longer throws. Before a script file leaves a global behind, check that no bundle that imports it declares the same name at top level, and render a real bundle (not just the typecheck) once.
749
+
750
+ ## Omni's cascade: a slow brain, a wrong count and a fake microphone that heard nothing (17/10/2026)
751
+
752
+ - **Symptom:** in the cascade, a question that needed one tool took 6 s to the first word, and with reasoning off the models said 8 or 9 videos published this week (there were 10). Fish over WebSocket was expected to be faster than HTTP and wasn't. The headless test's microphone (`--use-file-for-fake-audio-capture`) delivered pure silence.
753
+ - **Cause:** Haiku 5.5 reasons by default and, after a tool result, spent its 500 output tokens comparing dates before writing a word. Without reasoning it guessed the count. The Fish WebSocket buffers text before synthesizing: ~0.95 s to the first audio with the socket already open, against ~0.76 s for one HTTP request per sentence. This Chromium build ignores the fake audio file.
754
+ - **Fixed:** `reasoning: { effort: "none" }` in the cascade (tool choice still 18/18 on the bench) and `list_videos` returns `published_counts` (today, this week, last 7 days, this month) so nobody counts dates. Fish stays HTTP per sentence with `latency: "low"`. In the headless test, `navigator.mediaDevices.getUserMedia` is replaced by a stream that plays a decoded WAV. Before putting an LLM on a voice path, measure the time after a tool result, not only the first token; and precompute in the tool's output anything that takes reasoning.
755
+
756
+ ## Omni didn't stop when the user spoke over it (17/10/2026)
757
+
758
+ - **Symptom:** in the cascade's Trechos mode, the user started talking while Omni spoke and it went on to the end.
759
+ - **Cause:** to keep Omni's own voice from interrupting it, speaking over it took a fixed RMS of 0.07 for 300 ms; after the browser's echo cancellation a real voice stayed under that.
760
+ - **Fixed:** the page follows the level of the echo left under Omni's voice and interrupts at 2.5 times it for 200 ms (`ECHO_RATIO` in `studio/web/lib/omni-cascade.ts`). A fixed threshold can't fit every microphone and speaker: tune the ratio, not an absolute level.
761
+
762
+
763
+ ## A unit test wrote to the real project's config and Omni log (17/10/2026)
764
+
765
+ - **Symptom:** after a new `api/test/agent-cascade.test.ts`, five other API tests failed in the full run (the video list showed the real videos) and the real `omnivideo.config.json` ended with `agent.avatar: "h200-abc123"` and `gender: "male"`; `.agent/log.jsonl` got 20 fake sessions.
766
+ - **Cause:** the test imported `./fixture` and then the services with static imports. The fixture sets `OMNIVIDEO_ROOT` behind a top-level await, and a sibling static import can be evaluated before that await finishes, so `services/root.ts` resolved the real project. The module cache then served that root to every later test file, and `agent-avatar.test.ts` posted to the real config.
767
+ - **Fixed:** the test loads the services with `await import()` after the fixture and throws if `ROOT` is not the fixture's. The config values and the log were restored. In API tests, take services only through the fixture or a dynamic import after it, never with a static `import` next to `./fixture`.
768
+
769
+
770
+ ## Duplicate scene forks left plans that didn't match the source (17/10/2026)
771
+
772
+ - **Symptom:** at the composition close of `2026-10-16-https-x-ai-news-grok`, `plan/c03.*`, `c06.json` and `c10.*` described another version of the scene (another size, other beats); the source of c03 read a beat `troca` that wasn't in `scenes.json`, c08's read `titulo`/`codigo` while its plan had `passo`. Running `compose.mjs apply` on the stale `c06.json` rewrote the good beats in `scenes.json`.
773
+ - **Cause:** the same scene was launched in two forks; each wrote its `motion/plan/<id>.*` and `src/<id>.html` at different moments, so the last plan and the last source came from different forks.
774
+ - **Fixed:** the close call takes the source (`src/<id>.html`) as the truth, compares the beats it reads (`beats["x"]`, `b("x")`, `--b-x`) with `scenes.json` and the plan before any `apply`, and rewrites the plan from the source. Never launch two forks for the same scene; before `apply` in a close call, diff the plan against `scenes.json`.
775
+
776
+ ## The composition ran twice in parallel (17/10/2026)
777
+
778
+ - **Symptom:** in `2026-10-16-https-x-ai-news-grok`, the scenes c02–c10 were composed by two sets of 8 forks at the same time (18 forks, ~US$ 22, half of it wasted), writing the same `motion/plan/<id>.*` and `src/<id>.html` (the entry above).
779
+ - **Cause:** the orchestrator called `av-motion` with "composição (etapa 3) das cenas c02 a c11"; that fork, with no scene named, ran `compose.mjs plan` and launched its own 8 Agent forks in the background and returned. The orchestrator, seeing the stage "done" in seconds, ran `plan` itself and launched another 8. Nothing in the tools stopped a second launch: `plan` printed the same scenes to anyone who asked.
780
+ - **Fixed:** each scene is handed out once (`tools/lib/fanout.mjs`): `plan` records the run, a second `plan` lists the scenes still running as busy and hands out nothing, and each fork starts with `fanout.mjs claim … --run R`, which refuses (exit 3) a scene already started or from another run. The same guard covers the wireframes and the narration, which now fan out too. `av-motion` and `av-narration` refuse a call without a scene and never launch forks. Rules don't stop a duplicate; a claim does.
781
+
782
+ ## The hosted studio broke with "Cannot read properties of undefined (reading 'state')" (17/10/2026)
783
+
784
+ - **Symptom:** the hosted studio threw `Cannot read properties of undefined (reading 'state')`.
785
+ - **Cause:** `wrangler deploy` in `cloud/studio` ships whatever is in `studio/dist`, and nobody rebuilt it: the bundle was from 05:18, before `preview` left the video summary (06:23), so the old bundle read `video.preview.state` on a list from the current API, without `preview`.
786
+ - **Fixed:** `[build] command` in `cloud/studio/wrangler.toml` runs `bun run build` in `studio/` before every `wrangler deploy` (and `dev`), so the web that goes up is always the one that matches the API.
787
+
788
+ ## The omnichat Worker hit Cloudflare's daily request limit (17/10/2026)
789
+
790
+ - **Symptom:** the cloud answered `429 error code: 1027` (the Workers Free plan's 100k requests a day), and the studio said "A cloud do omnichat não responde". The Worker had 140k requests that day, ~5k an hour since the evening before and 43k in one hour, with only a few real comments.
791
+ - **Cause:** a read that wrote. `pullRecord` (`tools/omnichat.mjs`) rewrote `omnichat-record.json` on every read, with a fresh `pulled_at`. The write is a studio notice (`events.ts`), the notice makes every open omnichat page reread every rule (`log --json`, one cloud request each), and that read wrote again: an endless loop, ~400–600 requests a minute per open Omnichat tab. The hosted studio's offline copy reread the same routes on every notice even with no tab open (~80 a minute). `publish.mjs` (the scheduler, every minute while a cloud job runs) and `metrics.mjs` (the account file) also rewrote unchanged files.
792
+ - **Fixed:** a pull, `writePub` and the metrics account file write only when the content changed; the studio caches the cloud health check for 60 s and each rule's log for 30 s while its record file is unchanged; the offline copy is gone. Rule for the future: anything a read path writes into a watched file must skip an unchanged write, or it loops against whatever it calls.