auricui-skill 0.0.0-stage → 0.1.2

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 (362) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -2
  3. package/bin/install.mjs +66 -0
  4. package/package.json +29 -4
  5. package/skill/SKILL.md +64 -0
  6. package/skill/agents/openai.yaml +4 -0
  7. package/skill/assets/examples/ApprovalCard.tsx +8 -0
  8. package/skill/assets/examples/BasicApp.tsx +38 -0
  9. package/skill/assets/examples/BriefingCard.tsx +8 -0
  10. package/skill/assets/examples/ChatControls.tsx +49 -0
  11. package/skill/assets/examples/ChatPanel.tsx +73 -0
  12. package/skill/assets/examples/Checkbox.tsx +13 -0
  13. package/skill/assets/examples/Combobox.tsx +14 -0
  14. package/skill/assets/examples/Drawer.tsx +10 -0
  15. package/skill/assets/examples/MemoryCard.tsx +9 -0
  16. package/skill/assets/examples/MessageList.tsx +8 -0
  17. package/skill/assets/examples/Theme.tsx +14 -0
  18. package/skill/assets/examples/ToolCall.tsx +8 -0
  19. package/skill/assets/examples/Tree.tsx +15 -0
  20. package/skill/assets/examples/examples.css +11 -0
  21. package/skill/assets/library/auricui-0.1.0-preview.1.tgz +0 -0
  22. package/skill/assets/library/auricui-0.1.0-preview.3.tgz +0 -0
  23. package/skill/assets/library/auricui-0.1.0-preview.4.tgz +0 -0
  24. package/skill/assets/upstream/LICENSE +21 -0
  25. package/skill/assets/upstream/apps/desktop/chat/src/App.tsx +1099 -0
  26. package/skill/assets/upstream/apps/desktop/chat/src/app-bridge.ts +154 -0
  27. package/skill/assets/upstream/apps/desktop/chat/src/chat.css +1812 -0
  28. package/skill/assets/upstream/apps/desktop/chat/src/components/AddSkill.tsx +223 -0
  29. package/skill/assets/upstream/apps/desktop/chat/src/components/AgentActivityRow.tsx +716 -0
  30. package/skill/assets/upstream/apps/desktop/chat/src/components/AgentIcons.tsx +46 -0
  31. package/skill/assets/upstream/apps/desktop/chat/src/components/AttachmentCard.tsx +34 -0
  32. package/skill/assets/upstream/apps/desktop/chat/src/components/AttachmentPreview.tsx +331 -0
  33. package/skill/assets/upstream/apps/desktop/chat/src/components/BalanceNotice.tsx +22 -0
  34. package/skill/assets/upstream/apps/desktop/chat/src/components/BrandLogo.tsx +35 -0
  35. package/skill/assets/upstream/apps/desktop/chat/src/components/ComposerCard.tsx +182 -0
  36. package/skill/assets/upstream/apps/desktop/chat/src/components/ConversationSessionBar.tsx +292 -0
  37. package/skill/assets/upstream/apps/desktop/chat/src/components/CopyDiagnostics.tsx +24 -0
  38. package/skill/assets/upstream/apps/desktop/chat/src/components/Divider.tsx +47 -0
  39. package/skill/assets/upstream/apps/desktop/chat/src/components/FileChangesList.tsx +119 -0
  40. package/skill/assets/upstream/apps/desktop/chat/src/components/Markdown.tsx +198 -0
  41. package/skill/assets/upstream/apps/desktop/chat/src/components/ModelPopover.tsx +280 -0
  42. package/skill/assets/upstream/apps/desktop/chat/src/components/NoticeCard.tsx +87 -0
  43. package/skill/assets/upstream/apps/desktop/chat/src/components/Popover.tsx +195 -0
  44. package/skill/assets/upstream/apps/desktop/chat/src/components/PreviewFrame.tsx +129 -0
  45. package/skill/assets/upstream/apps/desktop/chat/src/components/ProjectConversation.tsx +852 -0
  46. package/skill/assets/upstream/apps/desktop/chat/src/components/ProjectStarters.tsx +118 -0
  47. package/skill/assets/upstream/apps/desktop/chat/src/components/Tooltip.tsx +191 -0
  48. package/skill/assets/upstream/apps/desktop/chat/src/components/TurnLog.tsx +583 -0
  49. package/skill/assets/upstream/apps/desktop/chat/src/components/TurnQuestionCard.tsx +133 -0
  50. package/skill/assets/upstream/apps/desktop/chat/src/components/dock-pane-bar.ts +14 -0
  51. package/skill/assets/upstream/apps/desktop/chat/src/components/project-version.ts +37 -0
  52. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/MentionMenuPlugin.tsx +372 -0
  53. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/PromptEditor.tsx +476 -0
  54. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/PromptPill.tsx +399 -0
  55. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/PromptReferenceNode.tsx +164 -0
  56. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/index.ts +31 -0
  57. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/mention-menu.ts +206 -0
  58. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/prompt-text.ts +171 -0
  59. package/skill/assets/upstream/apps/desktop/chat/src/components/useStickToBottom.ts +320 -0
  60. package/skill/assets/upstream/apps/desktop/chat/src/components/useTicker.ts +55 -0
  61. package/skill/assets/upstream/apps/desktop/chat/src/i18n/index.ts +42 -0
  62. package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/en-US.ts +408 -0
  63. package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/es.ts +407 -0
  64. package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/ja.ts +407 -0
  65. package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/ko.ts +403 -0
  66. package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/words.ts +6 -0
  67. package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/zh-CN.ts +407 -0
  68. package/skill/assets/upstream/apps/desktop/chat/src/i18n/lookup.ts +12 -0
  69. package/skill/assets/upstream/apps/desktop/chat/src/lib/agent-activity-runs.ts +154 -0
  70. package/skill/assets/upstream/apps/desktop/chat/src/lib/agent-menu-rows.ts +41 -0
  71. package/skill/assets/upstream/apps/desktop/chat/src/lib/agent-refs.ts +105 -0
  72. package/skill/assets/upstream/apps/desktop/chat/src/lib/agent-transcript.ts +440 -0
  73. package/skill/assets/upstream/apps/desktop/chat/src/lib/asset-lists.ts +75 -0
  74. package/skill/assets/upstream/apps/desktop/chat/src/lib/attachment-place.ts +17 -0
  75. package/skill/assets/upstream/apps/desktop/chat/src/lib/balance.ts +16 -0
  76. package/skill/assets/upstream/apps/desktop/chat/src/lib/chat-layer.ts +10 -0
  77. package/skill/assets/upstream/apps/desktop/chat/src/lib/chat-menu.ts +18 -0
  78. package/skill/assets/upstream/apps/desktop/chat/src/lib/chat-store.ts +101 -0
  79. package/skill/assets/upstream/apps/desktop/chat/src/lib/composer-attachments.ts +189 -0
  80. package/skill/assets/upstream/apps/desktop/chat/src/lib/desktop-attachments.ts +178 -0
  81. package/skill/assets/upstream/apps/desktop/chat/src/lib/desktop-bridge.ts +291 -0
  82. package/skill/assets/upstream/apps/desktop/chat/src/lib/developer.ts +39 -0
  83. package/skill/assets/upstream/apps/desktop/chat/src/lib/esc-stop.ts +23 -0
  84. package/skill/assets/upstream/apps/desktop/chat/src/lib/file-changes.ts +32 -0
  85. package/skill/assets/upstream/apps/desktop/chat/src/lib/live-activity.ts +20 -0
  86. package/skill/assets/upstream/apps/desktop/chat/src/lib/local-agent-run.ts +1174 -0
  87. package/skill/assets/upstream/apps/desktop/chat/src/lib/local-sessions.ts +25 -0
  88. package/skill/assets/upstream/apps/desktop/chat/src/lib/model-calls.ts +87 -0
  89. package/skill/assets/upstream/apps/desktop/chat/src/lib/pretty-json.ts +12 -0
  90. package/skill/assets/upstream/apps/desktop/chat/src/lib/preview-top.ts +15 -0
  91. package/skill/assets/upstream/apps/desktop/chat/src/lib/project-resources.ts +66 -0
  92. package/skill/assets/upstream/apps/desktop/chat/src/lib/project-sessions.ts +66 -0
  93. package/skill/assets/upstream/apps/desktop/chat/src/lib/project-versions.ts +116 -0
  94. package/skill/assets/upstream/apps/desktop/chat/src/lib/ref-pictures.ts +119 -0
  95. package/skill/assets/upstream/apps/desktop/chat/src/lib/relative-time.ts +46 -0
  96. package/skill/assets/upstream/apps/desktop/chat/src/lib/skill-pages.ts +29 -0
  97. package/skill/assets/upstream/apps/desktop/chat/src/lib/step-file.ts +23 -0
  98. package/skill/assets/upstream/apps/desktop/chat/src/lib/structural-share.ts +52 -0
  99. package/skill/assets/upstream/apps/desktop/chat/src/lib/studio-film.ts +44 -0
  100. package/skill/assets/upstream/apps/desktop/chat/src/lib/studio-transfer.ts +40 -0
  101. package/skill/assets/upstream/apps/desktop/chat/src/lib/unprompted.ts +27 -0
  102. package/skill/assets/upstream/apps/desktop/chat/src/lib/upload-limits.ts +53 -0
  103. package/skill/assets/upstream/apps/desktop/chat/src/mount.tsx +19 -0
  104. package/skill/assets/upstream/apps/desktop/chat/src/state/local-agent-store.ts +296 -0
  105. package/skill/assets/upstream/apps/desktop/chat/src/studio-refs.ts +307 -0
  106. package/skill/assets/upstream/apps/desktop/package.json +51 -0
  107. package/skill/assets/upstream/apps/desktop/shell/bridge.ts +415 -0
  108. package/skill/assets/upstream/apps/desktop/shell/index.html +27 -0
  109. package/skill/assets/upstream/apps/desktop/shell/main.tsx +17 -0
  110. package/skill/assets/upstream/apps/desktop/shell/shell.css +17 -0
  111. package/skill/assets/upstream/apps/desktop/shell/vite.config.ts +65 -0
  112. package/skill/assets/upstream/apps/desktop/src/agent-definitions.mjs +31 -0
  113. package/skill/assets/upstream/packages/openfilm/LICENSE +21 -0
  114. package/skill/assets/upstream/packages/openfilm/package.json +88 -0
  115. package/skill/assets/upstream/packages/openfilm/src/film-doc.d.mts +125 -0
  116. package/skill/assets/upstream/packages/openfilm/src/film-doc.mjs +986 -0
  117. package/skill/assets/upstream/packages/openfilm/src/overrides.mjs +73 -0
  118. package/skill/assets/upstream/packages/openfilm/src/timeline.mjs +1280 -0
  119. package/skill/assets/upstream/packages/openfilm/studio/server/bridge.js +209 -0
  120. package/skill/assets/upstream/packages/openfilm/studio/server/film-subtitle.mjs +785 -0
  121. package/skill/assets/upstream/packages/openfilm/studio/server/ops.mjs +403 -0
  122. package/skill/assets/upstream/packages/openfilm/studio/server/stage.js +1649 -0
  123. package/skill/assets/upstream/packages/openfilm/studio/server/track-layout.mjs +43 -0
  124. package/skill/assets/upstream/packages/openfilm/studio/ui/src/App.tsx +156 -0
  125. package/skill/assets/upstream/packages/openfilm/studio/ui/src/api.ts +328 -0
  126. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/AudioMeters.tsx +188 -0
  127. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/BlockThumbs.tsx +84 -0
  128. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/BlockWaveform.tsx +201 -0
  129. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/BrandLoadingScreen.tsx +56 -0
  130. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/BrandLogo.tsx +25 -0
  131. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Card.tsx +89 -0
  132. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ColorPicker.tsx +204 -0
  133. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ConfirmDialog.tsx +96 -0
  134. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ContextMenu.tsx +422 -0
  135. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/DesktopDialog.tsx +271 -0
  136. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ExamplesGallery.tsx +372 -0
  137. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FilmFullscreenBar.tsx +147 -0
  138. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FilmInspector.tsx +2310 -0
  139. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FilmStageSelect.tsx +3296 -0
  140. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FocusNav.tsx +28 -0
  141. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FontFamilyPicker.tsx +293 -0
  142. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FramePicker.tsx +69 -0
  143. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/InspectorPanel.tsx +25 -0
  144. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Launcher.tsx +38 -0
  145. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/LayersPanel.tsx +277 -0
  146. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/LiveTime.tsx +101 -0
  147. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/MediaPool.tsx +1413 -0
  148. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/MediaPreview.tsx +188 -0
  149. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/MenuSelect.tsx +161 -0
  150. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/MgOutline.tsx +24 -0
  151. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/OperationHistory.tsx +184 -0
  152. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/PaneDivider.tsx +292 -0
  153. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/PasteAttrsDialog.tsx +69 -0
  154. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/PlaybackMenu.tsx +110 -0
  155. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Popover.tsx +159 -0
  156. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectCover.tsx +60 -0
  157. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectHistoryControls.tsx +748 -0
  158. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectLayoutMenu.tsx +82 -0
  159. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectMenu.tsx +111 -0
  160. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectSources.tsx +587 -0
  161. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectView.tsx +3222 -0
  162. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectsLibrary.tsx +567 -0
  163. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectsView.tsx +1593 -0
  164. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/PropertiesSection.tsx +418 -0
  165. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ResourceInspector.tsx +100 -0
  166. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SelectionToolbar.tsx +157 -0
  167. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SkillsLibrary.tsx +504 -0
  168. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SourcePreview.tsx +464 -0
  169. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SpendAsks.tsx +88 -0
  170. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/StageMaskOverlay.tsx +299 -0
  171. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/StageTransformFrame.tsx +246 -0
  172. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SubtitleInspector.module.css +46 -0
  173. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SubtitleInspector.tsx +884 -0
  174. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SubtitleOverlay.tsx +148 -0
  175. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SubtitleRow.tsx +419 -0
  176. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/TabStrip.tsx +188 -0
  177. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Timeline.tsx +4911 -0
  178. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/TimelineMarkers.tsx +329 -0
  179. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Toast.tsx +55 -0
  180. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Tooltip.tsx +193 -0
  181. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/UpdateButton.tsx +104 -0
  182. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ViewerBar.tsx +98 -0
  183. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/WhatsNew.tsx +147 -0
  184. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/dock-pane-bar.ts +16 -0
  185. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/export/ExportCenter.tsx +1502 -0
  186. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/export/ExportTray.tsx +284 -0
  187. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/film-stage-hit.ts +18 -0
  188. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/inspector-fields.tsx +863 -0
  189. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/inspector-look.tsx +1357 -0
  190. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/player-controls/controls-bar.tsx +397 -0
  191. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/player-controls/transport.tsx +294 -0
  192. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/replace-drop.ts +20 -0
  193. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/AgentsSection.tsx +613 -0
  194. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/CustomServices.tsx +104 -0
  195. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/DiagnosticsGroup.tsx +202 -0
  196. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ModelsSection.tsx +179 -0
  197. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ProviderMark.tsx +24 -0
  198. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ProvidersSection.tsx +177 -0
  199. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/SettingsModal.tsx +511 -0
  200. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/SettingsSelect.tsx +84 -0
  201. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ShortcutsSection.tsx +291 -0
  202. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/StorageGroup.tsx +119 -0
  203. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/theme.ts +47 -0
  204. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ui.tsx +139 -0
  205. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/use-settings.ts +10 -0
  206. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/stage-menu.tsx +283 -0
  207. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/timeline-head-extras.tsx +91 -0
  208. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/typing-target.ts +45 -0
  209. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/use-editor-tools.tsx +408 -0
  210. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/use-page-changes.ts +48 -0
  211. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/use-project-history.ts +113 -0
  212. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/useBlockDrag.ts +639 -0
  213. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/Preview.tsx +426 -0
  214. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/player.ts +558 -0
  215. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/preview-frames.ts +36 -0
  216. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/steps.ts +36 -0
  217. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/undo.ts +156 -0
  218. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/use-film.ts +212 -0
  219. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/use-preview-renders.ts +89 -0
  220. package/skill/assets/upstream/packages/openfilm/studio/ui/src/globals.css +559 -0
  221. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/en.ts +1901 -0
  222. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/es.ts +1900 -0
  223. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/index.ts +130 -0
  224. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/ja.ts +1900 -0
  225. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/ko.ts +1896 -0
  226. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/words.ts +6 -0
  227. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/zh-CN.ts +1901 -0
  228. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/agent-row.ts +21 -0
  229. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/asset-timeline.ts +469 -0
  230. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/audio-levels.ts +60 -0
  231. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/batch-map.ts +28 -0
  232. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/browser.ts +10 -0
  233. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/canvas-fit.ts +116 -0
  234. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/chat-marks.ts +114 -0
  235. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-attrs.ts +102 -0
  236. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-fade.ts +70 -0
  237. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-look.ts +520 -0
  238. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-mask.ts +536 -0
  239. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-replace.ts +60 -0
  240. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/component-props.ts +128 -0
  241. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/context-length.ts +12 -0
  242. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/desktop-build.ts +44 -0
  243. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/diagnostics.ts +68 -0
  244. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/double-press.ts +22 -0
  245. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/dropped-overrides.ts +139 -0
  246. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/export-jobs.ts +191 -0
  247. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/export-spec.ts +261 -0
  248. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/field-input.ts +155 -0
  249. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film-clip-edits.ts +82 -0
  250. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film-frame.ts +134 -0
  251. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film-overrides.ts +107 -0
  252. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film-shape.ts +172 -0
  253. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film.ts +80 -0
  254. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/font-menu.ts +236 -0
  255. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/font-styles.ts +129 -0
  256. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/freeze-frame.ts +49 -0
  257. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/host.ts +438 -0
  258. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/inspect-scrub.ts +26 -0
  259. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/keymap-store.ts +74 -0
  260. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/keymap.ts +529 -0
  261. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/layers-tree.ts +133 -0
  262. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/look.ts +83 -0
  263. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/loudness.ts +58 -0
  264. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/markers.ts +152 -0
  265. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-bar.ts +58 -0
  266. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-folders.ts +45 -0
  267. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-place.ts +102 -0
  268. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-queue.ts +107 -0
  269. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-selection.ts +64 -0
  270. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/menu-position.ts +77 -0
  271. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/mg-transform.ts +111 -0
  272. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/mixed.ts +3 -0
  273. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/page-changes.ts +45 -0
  274. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/picture-files.ts +19 -0
  275. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/preview-prefs.ts +46 -0
  276. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/preview-renders.ts +71 -0
  277. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/project-delete.ts +20 -0
  278. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/project-folders.ts +144 -0
  279. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/project-history.ts +188 -0
  280. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/project-sources.ts +283 -0
  281. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/projects-page.ts +40 -0
  282. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/provider-marks.ts +35 -0
  283. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/providers.ts +163 -0
  284. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/resource-drag.ts +131 -0
  285. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/retry-image.ts +17 -0
  286. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/saved-insert.ts +40 -0
  287. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/saved.ts +125 -0
  288. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/selection-toolbar.ts +158 -0
  289. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/shortcut-hint.ts +21 -0
  290. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/similar-layers.ts +46 -0
  291. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/solo.ts +19 -0
  292. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-clip.ts +60 -0
  293. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-crop.ts +232 -0
  294. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-gesture.ts +277 -0
  295. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-layers.ts +71 -0
  296. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-mask.ts +176 -0
  297. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-measure.ts +53 -0
  298. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-types.ts +155 -0
  299. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/studio-refs.ts +248 -0
  300. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/studio-version.ts +41 -0
  301. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/subtitle-cues.ts +238 -0
  302. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/subtitles.ts +263 -0
  303. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/tab-menu.ts +6 -0
  304. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/template-controls.ts +131 -0
  305. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/theme-changes.ts +31 -0
  306. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/thumb-cache.ts +63 -0
  307. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/thumb-cell.ts +8 -0
  308. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/thumb-frame.ts +76 -0
  309. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/thumb-pick.ts +42 -0
  310. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timecode.ts +161 -0
  311. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-clipboard.ts +279 -0
  312. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-drag.ts +589 -0
  313. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-edit.ts +1138 -0
  314. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-keys.ts +63 -0
  315. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-layout.ts +1038 -0
  316. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-nav.ts +160 -0
  317. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-prefs.ts +73 -0
  318. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-split.ts +40 -0
  319. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-view.ts +105 -0
  320. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/title.ts +39 -0
  321. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/track-heights.ts +55 -0
  322. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/track-lock.ts +27 -0
  323. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/transitions.ts +459 -0
  324. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/type-metrics.ts +83 -0
  325. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-film-subtitles.ts +111 -0
  326. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-fonts.ts +181 -0
  327. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-loaded-thumbs.ts +91 -0
  328. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-subtitle-edits.ts +134 -0
  329. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-subtitle-font.ts +51 -0
  330. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-subtitle-style.ts +68 -0
  331. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/waveform-columns.ts +48 -0
  332. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/web-update.ts +41 -0
  333. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/whats-new.ts +401 -0
  334. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/workspace-resources.ts +373 -0
  335. package/skill/assets/upstream/packages/openfilm/studio/ui/src/main.tsx +10 -0
  336. package/skill/assets/upstream/packages/openfilm/studio/ui/vite.config.ts +12 -0
  337. package/skill/assets/upstream/packages/shared/package.json +45 -0
  338. package/skill/assets/upstream/packages/shared/src/agent-activity.ts +263 -0
  339. package/skill/assets/upstream/packages/shared/src/contract.ts +285 -0
  340. package/skill/assets/upstream/packages/shared/src/index.ts +17 -0
  341. package/skill/assets/upstream/packages/shared/src/markdown-blocks.ts +252 -0
  342. package/skill/assets/upstream/packages/shared/src/modality.ts +4 -0
  343. package/skill/assets/upstream/packages/shared/src/prompt-reference.ts +113 -0
  344. package/skill/assets/upstream/packages/shared/src/title.ts +76 -0
  345. package/skill/assets/upstream/packages/shared/src/turn.ts +68 -0
  346. package/skill/assets/upstream/packages/shared/src/video.ts +26 -0
  347. package/skill/references/agent-components.md +33 -0
  348. package/skill/references/api-index.json +2693 -0
  349. package/skill/references/chat-components.md +65 -0
  350. package/skill/references/components.md +23 -0
  351. package/skill/references/core-components.md +44 -0
  352. package/skill/references/dependencies.md +22 -0
  353. package/skill/references/esm-package.md +48 -0
  354. package/skill/references/integration.md +43 -0
  355. package/skill/references/library-manifest.json +12 -0
  356. package/skill/references/source-manifest.json +325 -0
  357. package/skill/references/studio-components.md +24 -0
  358. package/skill/references/theme-motion.md +49 -0
  359. package/skill/references/troubleshooting.md +27 -0
  360. package/skill/references/verification.md +13 -0
  361. package/skill/scripts/check_dependencies.py +109 -0
  362. package/skill/scripts/inspect_api.py +60 -0
@@ -0,0 +1,21 @@
1
+ import type { HostAgent } from '@/lib/host';
2
+
3
+ /**
4
+ * What Settings › Agents offers for an agent that is not found: Locate (the program is somewhere else), and Install,
5
+ * either its official installer run here (`run`) or its install page (`page`). Claude Code waiting in the Claude app
6
+ * gets neither: the app downloads it once its Code tab is opened, as the row says.
7
+ */
8
+ export function missingActions(agent: Pick<HostAgent, 'setupRequired' | 'install' | 'installer'>, host: { locate: boolean; install: boolean }) {
9
+ if (agent.setupRequired === 'code-tab') return { locate: false, install: null };
10
+ const install: 'run' | 'page' | null = agent.installer && host.install ? 'run' : agent.install ? 'page' : null;
11
+ return { locate: host.locate, install };
12
+ }
13
+
14
+ /**
15
+ * The organization an account's line names, unless it only says the email again: a personal Claude account's
16
+ * organization is "<email>'s Organization".
17
+ */
18
+ export function accountOrg(account: { org?: string | null; email?: string | null }): string | null {
19
+ if (!account.org) return null;
20
+ return account.email && account.org === `${account.email}'s Organization` ? null : account.org;
21
+ }
@@ -0,0 +1,469 @@
1
+ /**
2
+ * A project file dropped on the timeline: which kind of clip it becomes and where it lands.
3
+ *
4
+ * A web page becomes an mg clip, a video or a still a video clip, a sound an audio clip — voice, sfx or music is read
5
+ * from its path. A track has no kind (SPEC): any of them goes on any track. Documents cannot go on the timeline.
6
+ *
7
+ * There is one landing rule (assetDropSpot) and both the preview and the drop ask it, so a file lands where its
8
+ * preview was drawn. Its first rule: never stack on a clip on the same track — stacked clips spread into two rows that
9
+ * share a badge and look broken. With an edit mode asked for (⌥: an overwrite), a file dropped onto a track goes onto it
10
+ * whatever is there: an insert pushes it on, an overwrite cuts it out (lib/timeline-edit planRoom), and only the empty
11
+ * space above or below the tracks opens a new one. Without one, a taken spot opens a new track, shown by a line.
12
+ */
13
+ import { filmAudioRoleOf, filmSrcIsPage, filmSrcIsStill, type FilmBox } from './film.ts';
14
+
15
+ import type { ResourceDragItem } from './resource-drag';
16
+ import { exactRate, frameMs, timecodeFps } from './timecode.ts';
17
+ import { trackByLane } from './timeline-clipboard.ts';
18
+ import {
19
+ MIN_BLOCK_MS,
20
+ newTrackSide,
21
+ rangeOverlaps,
22
+ type DropBand,
23
+ } from './timeline-drag.ts';
24
+ import type { EditMode } from './timeline-edit.ts';
25
+ import { renumberTracks, type TimelineBlockKind, type TimelineTrack } from './timeline-layout.ts';
26
+
27
+ export type AssetClipKind = 'mg' | 'video' | 'audio';
28
+
29
+ export function assetClipKindOf(file: { path: string; kind: string }): AssetClipKind | null {
30
+ /* a web page (`scenes/intro.html`) is an mg clip, its src the page's path; so is a page the pane names one without
31
+ its ending (a bundle of Saved, a folder holding its page) */
32
+ if (filmSrcIsPage(file.path) || file.kind === 'mg') return 'mg';
33
+ if (file.kind === 'video' || file.kind === 'image') return 'video';
34
+ if (file.kind === 'audio') return 'audio';
35
+ return null;
36
+ }
37
+
38
+ /**
39
+ * How long a dropped still, or a web page without a duration, stays: four seconds. The number matters less than
40
+ * having one: neither has a length, a drag cannot ask for one, and
41
+ * film.html needs a length for it (`#t=0,4`). A person can pull the edge right after. (An agent writing film.html
42
+ * gives the fragment itself.)
43
+ */
44
+ export const STILL_DROP_MS = 4000;
45
+
46
+ /** A file with no end of its own: a still, or a page without a duration. Its clip's `time` is its length. */
47
+ function isEndless(file: { path: string; kind: string; endless?: boolean }): boolean {
48
+ const kind = assetClipKindOf(file);
49
+ return (kind === 'video' && filmSrcIsStill(file.path)) || (kind === 'mg' && file.endless === true);
50
+ }
51
+
52
+ /** The length a dropped clip is drawn and written with. */
53
+ export function dropDurMsOf(file: { path: string; kind: string; durationMs?: number; endless?: boolean }): number {
54
+ if (file.durationMs && file.durationMs > 0) return Math.max(MIN_BLOCK_MS, file.durationMs);
55
+ /* for a still this is the `time` written, so preview, placeholder and film.html share it — or the clip would change
56
+ length once written */
57
+ if (isEndless(file)) return STILL_DROP_MS;
58
+ return Math.max(MIN_BLOCK_MS, 1000);
59
+ }
60
+
61
+ /** The film's canvas, in px. */
62
+ export type StageSize = { w: number; h: number };
63
+
64
+ /**
65
+ * Where a dropped video or still sits: in its own shape, as large as the canvas holds, centered, so one side meets the
66
+ * canvas's edge. Without a box it would be the whole canvas with the picture letterboxed inside
67
+ * it, and the box a person picks would not be the picture. None when its shape is the canvas's, or not known yet.
68
+ */
69
+ export function assetFitBox(file: { w?: number | undefined; h?: number | undefined }, stage: StageSize | null | undefined): FilmBox | null {
70
+ if (!stage || !(stage.w > 0 && stage.h > 0) || !(file.w && file.w > 0 && file.h && file.h > 0)) return null;
71
+ const k = Math.min(stage.w / file.w, stage.h / file.h);
72
+ const w = Math.min(stage.w, Math.round(file.w * k));
73
+ const h = Math.min(stage.h, Math.round(file.h * k));
74
+ /* within 2 px of the canvas each way is its shape: the clip fills it as it is */
75
+ if (stage.w - w <= 2 && stage.h - h <= 2) return null;
76
+ return { x: Math.round((stage.w - w) / 2), y: Math.round((stage.h - h) / 2), w, h };
77
+ }
78
+
79
+ /**
80
+ * A dropped page that sets no size of its own, on a canvas of another size: kept at the size it is shown at alone
81
+ * (`size`, 1920 × 1080), scaled whole into the canvas and centered, as a picture is. Left to itself it would be laid
82
+ * out again at the canvas's size, so a 16:9 page would turn 21:9 on a 21:9 canvas. Null on a canvas of its size.
83
+ */
84
+ export function assetPageFit(
85
+ file: { reflows?: boolean | undefined; w?: number | undefined; h?: number | undefined },
86
+ stage: StageSize | null | undefined,
87
+ ): { size: StageSize; box: FilmBox } | null {
88
+ if (!file.reflows || !stage || !(stage.w > 0 && stage.h > 0) || !(file.w && file.w > 0 && file.h && file.h > 0)) return null;
89
+ if (file.w === stage.w && file.h === stage.h) return null;
90
+ const size = { w: file.w, h: file.h };
91
+ return { size, box: assetFitBox(size, stage) ?? { x: 0, y: 0, w: stage.w, h: stage.h } };
92
+ }
93
+
94
+ /**
95
+ * The file as a film.html clip: `src` (its kind is the track it lands on, see assetDropInsert); a still, or a page
96
+ * without a duration, also gets `time`, which is its length, not a trim. A video or still of another shape than the
97
+ * canvas gets a box in its own shape (assetFitBox), a page without a size of its own its size and box (assetPageFit).
98
+ */
99
+ export function assetClipElement(
100
+ file: Pick<ResourceDragItem, 'path' | 'kind' | 'endless' | 'reflows'> & { w?: number | undefined; h?: number | undefined },
101
+ stage?: StageSize | null,
102
+ ): Record<string, unknown> | null {
103
+ const kind = assetClipKindOf(file);
104
+ if (!kind) return null;
105
+ const src = file.path;
106
+ const box = kind === 'video' ? assetFitBox(file, stage) : null;
107
+ const page = kind === 'mg' ? assetPageFit(file, stage) : null;
108
+ return {
109
+ src,
110
+ ...(isEndless(file) ? { time: [0, STILL_DROP_MS / 1000] } : {}),
111
+ ...(box ? { box } : {}),
112
+ ...(page ? { box: page.box, size: page.size } : {}),
113
+ };
114
+ }
115
+
116
+ /** The clip's color and row height: sounds as voice / sfx / music by path. */
117
+ export function assetBlockKindOf(file: { path: string; kind: string }): TimelineBlockKind | null {
118
+ const kind = assetClipKindOf(file);
119
+ if (!kind) return null;
120
+ return kind === 'audio' ? filmAudioRoleOf(file.path) : kind;
121
+ }
122
+
123
+ /** Where the pointer is: the row index and its band; out of range is -1 / tracks.length. */
124
+ export interface AssetLaneHit {
125
+ lane: number;
126
+ band: DropBand;
127
+ }
128
+
129
+ /**
130
+ * Where a drop lands — the one answer the preview and the drop share.
131
+ *
132
+ * `into`: onto an existing row (the time is free there, or the track is locked: refused, but the slot is still drawn
133
+ * where the user points). `new-track`: a new track at film.html index `docAt`, its insert line drawn at the top of
134
+ * row `laneIndex` (which may be tracks.length: at the very bottom).
135
+ */
136
+ export type AssetDropSpot =
137
+ | { action: 'into'; laneIndex: number; lane: string; docIndex: number | null; locked: boolean }
138
+ | { action: 'new-track'; laneIndex: number; docAt: number };
139
+
140
+ /** The time taken on a film.html track (every row spread from it). */
141
+ function occupiedOf(
142
+ tracks: readonly TimelineTrack[],
143
+ docIndex: number | null,
144
+ laneIndex: number,
145
+ ): { startMs: number; endMs: number }[] {
146
+ const rows = docIndex == null
147
+ ? [tracks[laneIndex]].filter((tr): tr is TimelineTrack => Boolean(tr))
148
+ : tracks.filter((tr) => tr.docIndex === docIndex);
149
+ return rows.flatMap((tr) => tr.blocks.map((b) => ({ startMs: b.startMs, endMs: b.endMs })));
150
+ }
151
+
152
+ /** A new track at film.html index `docAt`: which row its insert line is drawn on top of. */
153
+ function newTrackSpot(tracks: readonly TimelineTrack[], docAt: number): AssetDropSpot {
154
+ const i = tracks.findIndex((tr) => tr.docIndex != null && tr.docIndex >= docAt);
155
+ return { action: 'new-track', laneIndex: i >= 0 ? i : tracks.length, docAt };
156
+ }
157
+
158
+ export function assetDropSpot(
159
+ file: Pick<ResourceDragItem, 'path' | 'kind' | 'durationMs'>,
160
+ tracks: readonly TimelineTrack[],
161
+ hit: AssetLaneHit | null,
162
+ atMs: number,
163
+ /** Onto a track whatever is there (the edit makes room); without, a taken spot opens a new track. */
164
+ edit?: EditMode,
165
+ ): AssetDropSpot | null {
166
+ if (!assetClipKindOf(file)) return null;
167
+ const durMs = dropDurMsOf(file);
168
+ const startMs = Math.max(0, atMs);
169
+ const range = { startMs, endMs: startMs + durMs };
170
+ const onFilm = tracks.filter((tr) => tr.docIndex != null);
171
+
172
+ /* pointing at a row: any track takes any clip (SPEC), so it goes onto the row under the pointer */
173
+ if (hit && hit.lane >= 0 && hit.lane < tracks.length) {
174
+ const target = tracks[hit.lane]!;
175
+ /* its top or bottom edge = a new track above / below (without an edit mode) */
176
+ if (target.docIndex != null && hit.band !== 'body' && !edit) {
177
+ return newTrackSpot(tracks, hit.band === 'above' ? target.docIndex : target.docIndex + 1);
178
+ }
179
+ if (target.locked) {
180
+ return { action: 'into', laneIndex: hit.lane, lane: target.lane, docIndex: target.docIndex ?? null, locked: true };
181
+ }
182
+ if (edit || !rangeOverlaps(range, occupiedOf(tracks, target.docIndex ?? null, hit.lane))) {
183
+ return { action: 'into', laneIndex: hit.lane, lane: target.lane, docIndex: target.docIndex ?? null, locked: false };
184
+ }
185
+ /* the time is taken: no stacking, a new track beside this one (newTrackSide) */
186
+ if (target.docIndex != null) return newTrackSpot(tracks, newTrackSide(target.docIndex, target.role));
187
+ /* a row not on film.html cannot open a track: land on it as it is */
188
+ return { action: 'into', laneIndex: hit.lane, lane: target.lane, docIndex: null, locked: false };
189
+ }
190
+
191
+ /* above or below every row: a new track at the top / bottom, like dragging a clip there (moveDestFor) */
192
+ if (hit && hit.lane < 0 && onFilm.length) return newTrackSpot(tracks, onFilm[0]!.docIndex!);
193
+ const docEnd = onFilm.reduce((m, tr) => Math.max(m, tr.docIndex! + 1), 0);
194
+ return { action: 'new-track', laneIndex: tracks.length, docAt: docEnd };
195
+ }
196
+
197
+ /** What the drop tells whoever writes it — folded from `assetDropSpot`, so preview and drop agree. */
198
+ export interface AssetDropTarget {
199
+ /** Onto an existing row: its lane name. Null for a new track or without an answer. */
200
+ lane: string | null;
201
+ /** A new track: its film.html index. */
202
+ insertTrackAt: number | null;
203
+ /** Onto an existing row: what happens to what is there (an insert pushes it on, an overwrite cuts it out). */
204
+ edit?: EditMode;
205
+ }
206
+
207
+ export function assetDropTargetOf(spot: AssetDropSpot | null, edit?: EditMode): AssetDropTarget {
208
+ if (!spot) return { lane: null, insertTrackAt: null };
209
+ if (spot.action === 'new-track') return { lane: null, insertTrackAt: spot.docAt };
210
+ return { lane: spot.lane, insertTrackAt: null, ...(edit ? { edit } : {}) };
211
+ }
212
+
213
+ export type AssetDropPlan =
214
+ | { element: Record<string, unknown>; kind: AssetClipKind; at: number; track?: number | { insert: number } }
215
+ | { error: 'not-clip' | 'locked' };
216
+
217
+ /**
218
+ * The insert a drop becomes. Onto an existing track: `track: index`; a new one: `track: { insert: index }`. A locked
219
+ * target is refused — the user pointed at it, and quietly going elsewhere would confuse more than "locked". Without an
220
+ * answer, no track is named and the insert finds one of the kind.
221
+ */
222
+ export function assetDropInsert(
223
+ file: Pick<ResourceDragItem, 'path' | 'kind' | 'endless' | 'reflows' | 'w' | 'h'>,
224
+ tracks: readonly TimelineTrack[],
225
+ target: AssetDropTarget,
226
+ atMs: number,
227
+ stage?: StageSize | null,
228
+ ): AssetDropPlan {
229
+ const element = assetClipElement(file, stage);
230
+ if (!element) return { error: 'not-clip' };
231
+ const kind = assetClipKindOf(file)!;
232
+ /* where it was dropped: on the frame grid, or on the edge it snapped to (the timeline decides, see its dropAt) */
233
+ const at = Math.max(0, Math.round(atMs)) / 1000;
234
+ if (target.insertTrackAt != null) return { element, kind, at, track: { insert: target.insertTrackAt } };
235
+ if (!target.lane) return { element, kind, at };
236
+ const track = trackByLane(tracks, target.lane);
237
+ if (!track) return { element, kind, at };
238
+ if (track.locked) return { error: 'locked' };
239
+ if (track.docIndex == null) return { element, kind, at };
240
+ return { element, kind, at, track: track.docIndex };
241
+ }
242
+
243
+ /** One clip of a run of dropped files: what assetDropInsert's plan says, per file, and how long it is. */
244
+ export type AssetRunInsert = { element: Record<string, unknown>; at: number; durMs: number; track?: number | { insert: number } };
245
+
246
+ /**
247
+ * Files dropped from the computer, once imported: one after another from `atMs`, each starting on the frame after the
248
+ * one before it ends, on one track. The landing is assetDropSpot's for the whole run, so none of them stacks on a
249
+ * clip; the first opens a new track when it lands on one, the rest follow it there. Files that cannot be clips (a
250
+ * document) are left out; none left is `not-clip`.
251
+ */
252
+ export function assetRunInsert(
253
+ files: readonly Pick<ResourceDragItem, 'path' | 'kind' | 'durationMs' | 'endless' | 'reflows' | 'w' | 'h'>[],
254
+ tracks: readonly TimelineTrack[],
255
+ hit: AssetLaneHit | null,
256
+ atMs: number,
257
+ edit?: EditMode,
258
+ stage?: StageSize | null,
259
+ ): { inserts: AssetRunInsert[] } | { error: 'not-clip' | 'locked' } {
260
+ const usable = files.filter((f) => assetClipElement(f));
261
+ if (!usable.length) return { error: 'not-clip' };
262
+ const lengths = usable.map(dropDurMsOf);
263
+ const whole = { path: usable[0]!.path, kind: usable[0]!.kind, durationMs: lengths.reduce((a, b) => a + b, 0) + lengths.length * frameMs(1) };
264
+ const first = assetDropInsert(usable[0]!, tracks, assetDropTargetOf(assetDropSpot(whole, tracks, hit, atMs, edit)), atMs, stage);
265
+ if ('error' in first) return first;
266
+ /* after the first: the track it went onto (a new one is at the index it was opened at) */
267
+ const then = typeof first.track === 'object' ? first.track.insert : first.track;
268
+ const inserts: AssetRunInsert[] = [];
269
+ let startMs = Math.max(0, Math.round(atMs));
270
+ usable.forEach((file, i) => {
271
+ const track = i === 0 ? first.track : then;
272
+ inserts.push({ element: assetClipElement(file, stage)!, at: Math.round(startMs) / 1000, durMs: lengths[i]!, ...(track != null ? { track } : {}) });
273
+ /* the next one on the first whole frame past this one's end: rounded to the nearest, it could start inside it */
274
+ startMs = frameMs(Math.ceil(((startMs + lengths[i]!) * exactRate(timecodeFps())) / 1000 - 1e-6));
275
+ });
276
+ return { inserts };
277
+ }
278
+
279
+ /**
280
+ * Where a sound dropped on the picture goes: the first sound track free from `atMs` for `durMs`, else a new track
281
+ * below every other (as a lane hit for assetDropSpot / assetRunInsert).
282
+ */
283
+ export function soundLaneHit(tracks: readonly TimelineTrack[], atMs: number, durMs: number): AssetLaneHit {
284
+ const range = { startMs: Math.max(0, atMs), endMs: Math.max(0, atMs) + durMs };
285
+ const free = tracks.findIndex((tr, i) => tr.role === 'audio' && tr.docIndex != null && !tr.locked
286
+ && !rangeOverlaps(range, occupiedOf(tracks, tr.docIndex, i)));
287
+ return { lane: free >= 0 ? free : tracks.length, band: 'body' };
288
+ }
289
+
290
+ /** The length a run of dropped files is drawn and written with, end to end. */
291
+ export function assetRunMs(files: readonly Pick<ResourceDragItem, 'path' | 'kind' | 'durationMs' | 'endless'>[]): number {
292
+ return files.reduce((sum, f) => sum + (assetClipElement(f) ? dropDurMsOf(f) : 0), 0);
293
+ }
294
+
295
+ /**
296
+ * What a drop will look like, for the preview while dragging; the landing is assetDropSpot's. Onto a row: a
297
+ * see-through slot; a new track: only the line between tracks (a slot on the neighbor would look stacked). `atMs` is
298
+ * already snapped. The length is the file's own, else a placeholder; the real length comes once it is written.
299
+ */
300
+ export type AssetDropPreview = {
301
+ kind: AssetClipKind;
302
+ blockKind: TimelineBlockKind;
303
+ title: string;
304
+ startMs: number;
305
+ endMs: number;
306
+ /** The row the slot is on; for a new track, where the line is (may be `tracks.length`). */
307
+ laneIndex: number;
308
+ newTrack: boolean;
309
+ /** A new track's film.html index (the drop uses the same answer); null onto an existing row. */
310
+ docAt: number | null;
311
+ /** The row's lane name; null for a new track. */
312
+ lane: string | null;
313
+ error: 'locked' | null;
314
+ };
315
+
316
+ export function assetDropPreview(
317
+ file: Pick<ResourceDragItem, 'path' | 'kind' | 'name' | 'durationMs'>,
318
+ tracks: readonly TimelineTrack[],
319
+ hit: AssetLaneHit | null,
320
+ atMs: number,
321
+ edit?: EditMode,
322
+ ): AssetDropPreview | null {
323
+ const spot = assetDropSpot(file, tracks, hit, atMs, edit);
324
+ const kind = assetClipKindOf(file);
325
+ const blockKind = assetBlockKindOf(file);
326
+ if (!spot || !kind || !blockKind) return null;
327
+ const durMs = dropDurMsOf(file);
328
+ const startMs = Math.max(0, atMs);
329
+ const base = { kind, blockKind, title: clipTitleOf(file), startMs, endMs: startMs + durMs };
330
+ if (spot.action === 'new-track') {
331
+ return { ...base, laneIndex: spot.laneIndex, newTrack: true, docAt: spot.docAt, lane: null, error: null };
332
+ }
333
+ return {
334
+ ...base,
335
+ laneIndex: spot.laneIndex,
336
+ newTrack: false,
337
+ docAt: null,
338
+ lane: spot.lane,
339
+ error: spot.locked ? 'locked' : null,
340
+ };
341
+ }
342
+
343
+ /** The clip's name, as the timeline names evaluated clips: an MG without its extension, the rest with it. */
344
+ function clipTitleOf(file: Pick<ResourceDragItem, 'name' | 'path' | 'kind'>): string {
345
+ const base = file.name || file.path.split('/').pop() || file.path;
346
+ if (assetClipKindOf(file) !== 'mg') return base;
347
+ return base.replace(/\.[a-z0-9]{1,5}$/i, '') || base;
348
+ }
349
+
350
+ /**
351
+ * A dropped clip not written yet. Writing it and evaluating the film again takes from a few hundred ms to seconds;
352
+ * with nothing on the timeline meanwhile people think the drop missed and drop again. So it is drawn at once,
353
+ * see-through, until the real clip arrives. Everything needed to draw it is known at drop time.
354
+ */
355
+ export interface PendingDrop {
356
+ id: string;
357
+ blockKind: TimelineBlockKind;
358
+ title: string;
359
+ /** film.html's src: the real clip is recognized by it (see withPendingBlocks). */
360
+ src: string;
361
+ startMs: number;
362
+ endMs: number;
363
+ /** Onto an existing row: its lane name. */
364
+ lane: string | null;
365
+ /** A new track: its film.html index. */
366
+ insertTrackAt: number | null;
367
+ }
368
+
369
+ /** How the clip is drawn from the moment it is dropped. */
370
+ export function pendingDropOf(
371
+ file: Pick<ResourceDragItem, 'path' | 'kind' | 'name' | 'durationMs'>,
372
+ target: AssetDropTarget,
373
+ atMs: number,
374
+ ): PendingDrop | null {
375
+ const element = assetClipElement(file);
376
+ const blockKind = assetBlockKindOf(file);
377
+ if (!element || !blockKind || typeof element.src !== 'string') return null;
378
+ /* the same start as the write (assetDropInsert's `at` is this / 1000), so the real clip is recognized */
379
+ const startMs = Math.max(0, Math.round(atMs));
380
+ const durMs = dropDurMsOf(file);
381
+ return {
382
+ id: `pending:${element.src}@${startMs}`,
383
+ blockKind,
384
+ title: clipTitleOf(file),
385
+ src: element.src,
386
+ startMs,
387
+ endMs: startMs + durMs,
388
+ lane: target.lane,
389
+ insertTrackAt: target.insertTrackAt,
390
+ };
391
+ }
392
+
393
+ /**
394
+ * The drops not written yet, laid onto the timeline. A drop steps aside by itself once a clip of the same src overlaps
395
+ * it — not by timing its removal, which shows one clip turning into two and back.
396
+ */
397
+ export function withPendingBlocks(
398
+ tracks: readonly TimelineTrack[],
399
+ drops: readonly PendingDrop[],
400
+ ): TimelineTrack[] {
401
+ /* recognized by "same file, overlapping time", not an exact start: the placeholder's length is a guess (a new file
402
+ is not probed yet) and the written start may be rounded by a millisecond. Too strict, and the placeholder stays
403
+ next to the real clip until the write returns. */
404
+ const live = drops.filter((d) => !tracks.some(
405
+ (tr) => tr.blocks.some((b) => b.src === d.src && b.startMs < d.endMs && b.endMs > d.startMs),
406
+ ));
407
+ if (!live.length) return [...tracks];
408
+
409
+ const out = tracks.map((tr) => ({ ...tr, blocks: [...tr.blocks] }));
410
+ let opened = false;
411
+ for (const drop of live) {
412
+ const block = {
413
+ id: drop.id,
414
+ title: drop.title,
415
+ startMs: drop.startMs,
416
+ endMs: drop.endMs,
417
+ kind: drop.blockKind,
418
+ src: drop.src,
419
+ /* see-through: not written yet. No `loc`: it cannot be selected or dragged, there is nowhere to write an edit */
420
+ off: true,
421
+ };
422
+ const into = drop.lane != null ? out.findIndex((tr) => tr.lane === drop.lane) : -1;
423
+ if (into >= 0) {
424
+ const row = out[into]!;
425
+ row.blocks = [...row.blocks, block].sort((a, b) => a.startMs - b.startMs);
426
+ continue;
427
+ }
428
+ const kind = laneKindForHint(drop.blockKind);
429
+ const role = kind === 'audio' ? 'audio' : drop.blockKind === 'mg' ? 'mg' : 'video';
430
+ /*
431
+ * The new track may already be on film.html, still empty: film.html changes at once, the evaluation catches up
432
+ * later, and layoutTracks has drawn an empty row for it. Adding another row here would draw the track twice.
433
+ *
434
+ * Matched by index, kind and emptiness together: the insert shifted every track after it, so in the not yet
435
+ * updated projection the same index may be another track — putting a video into the MG row. Without such a row,
436
+ * a new row (a brief double track beats a clip on the wrong row).
437
+ */
438
+ const settled = drop.insertTrackAt != null
439
+ ? out.findIndex((tr) => tr.docIndex === drop.insertTrackAt
440
+ && tr.kind === kind
441
+ && !tr.blocks.length
442
+ && (kind === 'audio' || tr.role === role))
443
+ : -1;
444
+ if (settled >= 0) {
445
+ const row = out[settled]!;
446
+ row.blocks = [block];
447
+ continue;
448
+ }
449
+ const at = drop.insertTrackAt != null
450
+ ? out.findIndex((tr) => tr.docIndex != null && tr.docIndex >= drop.insertTrackAt!)
451
+ : -1;
452
+ out.splice(at >= 0 ? at : out.length, 0, {
453
+ lane: drop.id,
454
+ role,
455
+ index: 0,
456
+ name: null,
457
+ kind,
458
+ blocks: [block],
459
+ });
460
+ opened = true;
461
+ }
462
+ /* rows not on film.html have no badge from layoutTracks; give them one now rather than a blank head */
463
+ return opened ? renumberTracks(out) : out;
464
+ }
465
+
466
+ /** The kind of row a clip kind goes on. */
467
+ function laneKindForHint(kind: TimelineBlockKind): 'visual' | 'audio' {
468
+ return kind === 'voice' || kind === 'sfx' || kind === 'music' ? 'audio' : 'visual';
469
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * The audio meters' arithmetic: a channel's peak and RMS level from its latest samples, in dBFS, how a meter falls
3
+ * back after a peak (ballistics), the scale it is drawn on, and when a channel clipped.
4
+ */
5
+
6
+ /** The bottom of the meter: quieter is drawn as nothing. */
7
+ export const METER_FLOOR_DB = -60;
8
+ /** The marks on the scale, dBFS. */
9
+ export const METER_MARKS = [0, -6, -12, -18, -24, -30, -36, -42, -48, -54] as const;
10
+ /** A sample at or past this (0 dBFS, give or take rounding) clipped. */
11
+ export const CLIP_LEVEL = 0.999;
12
+ /** How fast a meter falls after a peak, dB a second (the PPM's 20 dB in 1.7 s, near enough). */
13
+ export const FALL_DB_PER_S = 12;
14
+ /** How long the peak mark stays before it falls, ms. */
15
+ export const PEAK_HOLD_MS = 1500;
16
+
17
+ export type ChannelLevel = { peakDb: number; rmsDb: number; clipped: boolean };
18
+
19
+ const toDb = (v: number) => (v > 0 ? Math.max(METER_FLOOR_DB, 20 * Math.log10(v)) : METER_FLOOR_DB);
20
+
21
+ /** One channel's level from its samples (−1…1). */
22
+ export function channelLevel(samples: ArrayLike<number>): ChannelLevel {
23
+ let peak = 0;
24
+ let sum = 0;
25
+ for (let i = 0; i < samples.length; i++) {
26
+ const v = samples[i]!;
27
+ const a = v < 0 ? -v : v;
28
+ if (a > peak) peak = a;
29
+ sum += v * v;
30
+ }
31
+ const rms = samples.length ? Math.sqrt(sum / samples.length) : 0;
32
+ return { peakDb: toDb(peak), rmsDb: toDb(rms), clipped: peak >= CLIP_LEVEL };
33
+ }
34
+
35
+ /** Where a level sits on the meter, 0 (the floor) to 1 (0 dBFS). */
36
+ export function meterPosition(db: number): number {
37
+ if (!(db > METER_FLOOR_DB)) return 0;
38
+ return Math.min(1, (db - METER_FLOOR_DB) / -METER_FLOOR_DB);
39
+ }
40
+
41
+ /** What the meter shows next: up at once to a louder level, down no faster than FALL_DB_PER_S. */
42
+ export function fallTo(shown: number, now: number, elapsedMs: number): number {
43
+ if (now >= shown) return now;
44
+ return Math.max(now, shown - (FALL_DB_PER_S * elapsedMs) / 1000);
45
+ }
46
+
47
+ /** A held peak: the loudest of late, `db` set at `at` (ms); what it shows at `nowMs` given the level `now`. */
48
+ export type HeldPeak = { db: number; at: number };
49
+
50
+ /** The peak mark: kept PEAK_HOLD_MS, then falling as the meter does; a louder level takes its place at once. */
51
+ export function holdPeak(held: HeldPeak, now: number, nowMs: number): HeldPeak & { shown: number } {
52
+ const fallen = held.db - (FALL_DB_PER_S * Math.max(0, nowMs - held.at - PEAK_HOLD_MS)) / 1000;
53
+ if (now >= fallen) return { db: now, at: nowMs, shown: now };
54
+ return { ...held, shown: fallen };
55
+ }
56
+
57
+ /** A level as the meter's readout writes it: `-6.0`, `-∞` under the floor. */
58
+ export function formatDb(db: number): string {
59
+ return db <= METER_FLOOR_DB ? '-∞' : db.toFixed(1);
60
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Entries set one by one, handed on together: the first one waits `ms`, and everything set in that time goes in the
3
+ * same batch. For the media facts probed as a project opens (ProjectView): thousands of files answer one after another,
4
+ * and each answer set on its own laid out the media pane and the timeline's sources again, the picture stalling for
5
+ * tens of ms each time while a person watched it play.
6
+ */
7
+ export function batchMap<K, V>(flush: (batch: Map<K, V>) => void, ms: number) {
8
+ let batch = new Map<K, V>();
9
+ let timer: ReturnType<typeof setTimeout> | null = null;
10
+ return {
11
+ set(key: K, value: V) {
12
+ batch.set(key, value);
13
+ if (timer != null) return;
14
+ timer = setTimeout(() => {
15
+ timer = null;
16
+ const done = batch;
17
+ batch = new Map();
18
+ flush(done);
19
+ }, ms);
20
+ },
21
+ /** What is waiting dropped (the project closed). */
22
+ cancel() {
23
+ if (timer != null) clearTimeout(timer);
24
+ timer = null;
25
+ batch = new Map();
26
+ },
27
+ };
28
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Whether the page is in a browser built on Chromium (Chrome, Edge, Arc, the desktop app), the engine films are
3
+ * rendered and checked in. Another one (Safari, Firefox) may lack something a film's page draws with, such as canvas
4
+ * filters: its preview can fail where the export does not.
5
+ */
6
+ export function chromiumBased(ua: string = typeof navigator === 'undefined' ? '' : navigator.userAgent,
7
+ brands: readonly { brand: string }[] | undefined = typeof navigator === 'undefined' ? undefined : (navigator as { userAgentData?: { brands?: { brand: string }[] } }).userAgentData?.brands): boolean {
8
+ if (brands?.some((b) => /Chromium/i.test(b.brand))) return true;
9
+ return /\b(Chrome|Chromium|CriOS|Edg)\//.test(ua) && !/\bFirefox\//.test(ua);
10
+ }