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,299 @@
1
+ /**
2
+ * A mask edited on the picture (the inspector's Mask › Edit on picture): its outline over the clip or layer in hand,
3
+ * turned with it, and its handles — a press inside moves it (anywhere in the box for a line or a band), the squares
4
+ * resize it, the round knob above turns it, the knob below pulled outward feathers it. The geometry is lib/stage-mask's.
5
+ *
6
+ * A drag shows on the picture as it goes (the session's preview, a frame at a time) and is written once, at the
7
+ * release: one change, one undo step. Esc during a drag gives it up. Its presses are its own: none reaches the stage
8
+ * (which would move the clip or start a marquee); a press elsewhere goes on to the stage as usual.
9
+ */
10
+ import * as React from 'react';
11
+
12
+ import { FRAME_BLUE, GestureHint, type FrameGeometry } from '@/components/StageTransformFrame';
13
+ import { useT } from '@/i18n';
14
+ import { HEART_D, STAR_D, type Mask } from '@/lib/clip-mask';
15
+ import {
16
+ draggedMask, featherPx, handlePivot, lineInBox, maskFrame, maskHandles, toLocal, type MaskDrag, type MaskHandleId,
17
+ type MaskSession,
18
+ } from '@/lib/stage-mask';
19
+
20
+ type P = { x: number; y: number };
21
+
22
+ /** A resize cursor for a handle turned `angle` degrees (as the frame's). */
23
+ function resizeCursor(angle: number): string {
24
+ const a = ((angle % 180) + 180) % 180;
25
+ if (a < 22.5 || a >= 157.5) return 'ew-resize';
26
+ if (a < 67.5) return 'nwse-resize';
27
+ if (a < 112.5) return 'ns-resize';
28
+ return 'nesw-resize';
29
+ }
30
+ const HANDLE_ANGLE: Record<MaskHandleId, number> = { e: 0, w: 0, n: 90, s: 90, nw: 45, se: 45, ne: 135, sw: 135 };
31
+
32
+ const fmt = (n: number) => String(Math.round(n * 10) / 10);
33
+
34
+ export function StageMaskOverlay({ frame, session }: {
35
+ /** The box the mask is drawn in, on the overlay (whole: a crop does not move a mask). */
36
+ frame: FrameGeometry;
37
+ session: MaskSession;
38
+ }) {
39
+ const t = useT();
40
+ const rootRef = React.useRef<HTMLDivElement | null>(null);
41
+ const sessionRef = React.useRef(session);
42
+ sessionRef.current = session;
43
+ /* what is drawn while dragging, and after the release until the written mask comes back as the session's */
44
+ const [live, setLive] = React.useState<Mask | null>(null);
45
+ const [hint, setHint] = React.useState<{ x: number; y: number; text: string } | null>(null);
46
+ const drag = React.useRef<{ kind: MaskDrag; m0: Mask; from: P; frame: FrameGeometry; el: Element; pointerId: number; last: Mask } | null>(null);
47
+ const previewRaf = React.useRef(0);
48
+ const settle = React.useRef<ReturnType<typeof setTimeout> | null>(null);
49
+
50
+ React.useEffect(() => {
51
+ if (drag.current) return;
52
+ setLive(null);
53
+ }, [session]);
54
+ React.useEffect(() => () => {
55
+ if (previewRaf.current) cancelAnimationFrame(previewRaf.current);
56
+ if (settle.current) clearTimeout(settle.current);
57
+ }, []);
58
+
59
+ const stagePoint = (e: { clientX: number; clientY: number }): P => {
60
+ const r = rootRef.current?.getBoundingClientRect();
61
+ return { x: e.clientX - (r?.left ?? 0), y: e.clientY - (r?.top ?? 0) };
62
+ };
63
+ const end = () => {
64
+ const d = drag.current;
65
+ drag.current = null;
66
+ if (previewRaf.current) { cancelAnimationFrame(previewRaf.current); previewRaf.current = 0; }
67
+ setHint(null);
68
+ try { if (d?.el.hasPointerCapture(d.pointerId)) d.el.releasePointerCapture(d.pointerId); } catch { /* gone already */ }
69
+ return d;
70
+ };
71
+ const cancel = () => {
72
+ const d = end();
73
+ if (!d) return;
74
+ setLive(null);
75
+ sessionRef.current.cancel();
76
+ };
77
+ const finish = () => {
78
+ const d = end();
79
+ if (!d) return;
80
+ if (JSON.stringify(d.last) === JSON.stringify(d.m0)) { setLive(null); return; }
81
+ setLive(d.last);
82
+ sessionRef.current.commit(d.last);
83
+ /* a write refused never comes back: the mask as written shows again */
84
+ if (settle.current) clearTimeout(settle.current);
85
+ settle.current = setTimeout(() => { if (!drag.current) setLive(null); }, 2000);
86
+ };
87
+ const step = (e: { clientX: number; clientY: number; shiftKey: boolean; altKey: boolean }) => {
88
+ const d = drag.current;
89
+ if (!d) return;
90
+ const p = stagePoint(e);
91
+ const box = { w: Math.max(1, d.frame.w), h: Math.max(1, d.frame.h) };
92
+ const next = draggedMask(d.m0, d.kind, box, d.from, toLocal(d.frame, p), { shift: e.shiftKey, alt: e.altKey });
93
+ d.last = next;
94
+ setLive(next);
95
+ const text = d.kind.kind === 'move' ? `X ${fmt(next.x)}% Y ${fmt(next.y)}%`
96
+ : d.kind.kind === 'turn' ? `${fmt(next.rotate)}°`
97
+ : d.kind.kind === 'feather' ? `${t('inspector.maskFeather')} ${fmt(next.feather)}%`
98
+ : next.shape === 'mirror' ? `${fmt(next.h)}%` : `${fmt(next.w)}% × ${fmt(next.h)}%`;
99
+ setHint({ x: p.x, y: p.y, text });
100
+ if (!previewRaf.current) {
101
+ previewRaf.current = requestAnimationFrame(() => {
102
+ previewRaf.current = 0;
103
+ if (drag.current) sessionRef.current.preview(drag.current.last);
104
+ });
105
+ }
106
+ };
107
+
108
+ /* Esc gives a drag up, before the stage hears it (it would let the clip go) */
109
+ React.useEffect(() => {
110
+ const onKey = (e: KeyboardEvent) => {
111
+ if (e.key !== 'Escape' || !drag.current) return;
112
+ e.preventDefault();
113
+ e.stopImmediatePropagation();
114
+ cancel();
115
+ };
116
+ window.addEventListener('keydown', onKey, true);
117
+ return () => window.removeEventListener('keydown', onKey, true);
118
+ // eslint-disable-next-line react-hooks/exhaustive-deps
119
+ }, []);
120
+
121
+ const m = live ?? session.mask;
122
+ const box = { w: Math.max(1, frame.w), h: Math.max(1, frame.h) };
123
+ const f = maskFrame(m, box);
124
+ const handles = maskHandles(m, box);
125
+ const fpx = featherPx(m, box);
126
+ const line = m.shape === 'linear' || m.shape === 'mirror';
127
+ const rad = (f.r * Math.PI) / 180;
128
+ const ux = { x: Math.cos(rad), y: Math.sin(rad) };
129
+ const uy = { x: -Math.sin(rad), y: Math.cos(rad) };
130
+ const at = (a: number, b: number): P => ({ x: f.cx + ux.x * a + uy.x * b, y: f.cy + ux.y * a + uy.y * b });
131
+ const segment = (off: number, key: string, dashed?: boolean) => {
132
+ const seg = lineInBox(at(0, off), ux, box.w, box.h);
133
+ return seg ? <Stroke key={key} d={`M${seg[0].x} ${seg[0].y}L${seg[1].x} ${seg[1].y}`} dashed={dashed} /> : null;
134
+ };
135
+ /* an ellipse `grow` px out of the mask's (its feather's outer edge) */
136
+ const ellipsePath = (grow: number) => {
137
+ const w = Math.max(0, f.w / 2 + grow);
138
+ const h = Math.max(0, f.h / 2 + grow);
139
+ return `M${f.cx - w} ${f.cy}a${w} ${h} 0 1 0 ${2 * w} 0a${w} ${h} 0 1 0 ${-2 * w} 0Z`;
140
+ };
141
+
142
+ return (
143
+ <div
144
+ ref={rootRef}
145
+ className="pointer-events-none absolute left-0 top-0 z-[6]"
146
+ onPointerDown={(e) => {
147
+ const part = (e.target as HTMLElement | null)?.closest('[data-mask-kind]');
148
+ if (!part || e.button !== 0) return;
149
+ e.stopPropagation();
150
+ e.preventDefault();
151
+ const kind = part.getAttribute('data-mask-kind');
152
+ const handle = part.getAttribute('data-mask-handle') as MaskHandleId | null;
153
+ const dk: MaskDrag | null = kind === 'move' ? { kind: 'move' } : kind === 'turn' ? { kind: 'turn' } : kind === 'feather' ? { kind: 'feather' }
154
+ : kind === 'resize' && handle ? { kind: 'resize', handle: handlePivot(handle) } : null;
155
+ if (!dk) return;
156
+ if (settle.current) { clearTimeout(settle.current); settle.current = null; }
157
+ part.setPointerCapture(e.pointerId);
158
+ drag.current = { kind: dk, m0: m, from: toLocal(frame, stagePoint(e)), frame, el: part, pointerId: e.pointerId, last: m };
159
+ }}
160
+ onPointerMove={(e) => { if (!drag.current) return; e.stopPropagation(); step(e); }}
161
+ onPointerUp={(e) => { if (!drag.current) return; e.stopPropagation(); step(e); finish(); }}
162
+ onPointerCancel={(e) => { if (!drag.current) return; e.stopPropagation(); finish(); }}
163
+ /* the system took the pointer: kept where it last was, as the stage's own gestures are */
164
+ onLostPointerCapture={(e) => { e.stopPropagation(); if (drag.current) finish(); }}
165
+ onDoubleClick={(e) => { if ((e.target as HTMLElement | null)?.closest('[data-mask-kind]')) e.stopPropagation(); }}
166
+ >
167
+ <div
168
+ className="absolute"
169
+ style={{
170
+ left: frame.cx - frame.w / 2,
171
+ top: frame.cy - frame.h / 2,
172
+ width: frame.w,
173
+ height: frame.h,
174
+ transform: frame.r ? `rotate(${frame.r}deg)` : undefined,
175
+ }}
176
+ >
177
+ {/* moved from inside the shape; a line or a band from anywhere in the box */}
178
+ <div
179
+ data-mask-kind="move"
180
+ aria-label={t('stageMask.move')}
181
+ className={`pointer-events-auto absolute ${drag.current?.kind.kind === 'move' ? 'cursor-grabbing' : 'cursor-move'}`}
182
+ style={line ? { inset: 0 } : {
183
+ left: f.cx - Math.max(f.w, 12) / 2,
184
+ top: f.cy - Math.max(f.h, 12) / 2,
185
+ width: Math.max(f.w, 12),
186
+ height: Math.max(f.h, 12),
187
+ transform: f.r ? `rotate(${f.r}deg)` : undefined,
188
+ }}
189
+ />
190
+ <svg aria-hidden className="pointer-events-none absolute left-0 top-0 overflow-visible" width={box.w} height={box.h}>
191
+ {m.shape === 'linear' ? (
192
+ <>
193
+ {segment(0, 'line')}
194
+ {fpx > 0 ? <>{segment(fpx / 2, 'a', true)}{segment(-fpx / 2, 'b', true)}</> : null}
195
+ </>
196
+ ) : m.shape === 'mirror' ? (
197
+ <>
198
+ {segment(-f.h / 2, 'top')}
199
+ {segment(f.h / 2, 'bottom')}
200
+ {fpx > 0 ? <>{segment(-f.h / 2 - fpx / 2, 'ta', true)}{segment(f.h / 2 + fpx / 2, 'ba', true)}</> : null}
201
+ </>
202
+ ) : m.shape === 'ellipse' ? (
203
+ <>
204
+ <Stroke d={ellipsePath(0)} />
205
+ {fpx > 0 ? <Stroke d={ellipsePath(fpx / 2)} dashed /> : null}
206
+ </>
207
+ ) : m.shape === 'rect' ? (
208
+ <g transform={`rotate(${f.r} ${f.cx} ${f.cy})`}>
209
+ <Stroke rect={{ x: f.cx - f.w / 2, y: f.cy - f.h / 2, w: f.w, h: f.h, r: Math.min((m.radius / 100) * Math.min(box.w, box.h), f.w / 2, f.h / 2) }} />
210
+ {fpx > 0 ? <Stroke rect={{ x: f.cx - f.w / 2 - fpx / 2, y: f.cy - f.h / 2 - fpx / 2, w: f.w + fpx, h: f.h + fpx, r: 0 }} dashed /> : null}
211
+ </g>
212
+ ) : (
213
+ <g transform={`translate(${f.cx} ${f.cy}) rotate(${f.r}) scale(${Math.max(f.w, 0.01) / 2} ${Math.max(f.h, 0.01) / 2})`}>
214
+ <Stroke d={m.shape === 'star' ? STAR_D : HEART_D} scaled />
215
+ </g>
216
+ )}
217
+ {/* the knobs' stems */}
218
+ {handles.turn && !line ? <Stroke d={`M${at(0, -f.h / 2).x} ${at(0, -f.h / 2).y}L${handles.turn.x} ${handles.turn.y}`} thin /> : null}
219
+ {handles.feather ? (() => {
220
+ const from = line ? at(0, m.shape === 'mirror' ? -f.h / 2 : 0) : at(0, f.h / 2);
221
+ return <Stroke d={`M${from.x} ${from.y}L${handles.feather.at.x} ${handles.feather.at.y}`} thin dashed />;
222
+ })() : null}
223
+ {handles.turn && line ? <Stroke d={`M${f.cx} ${f.cy}L${handles.turn.x} ${handles.turn.y}`} thin /> : null}
224
+ </svg>
225
+ {/* the point a line or a band goes through */}
226
+ {line ? <Dot at={{ x: f.cx, y: f.cy }} size={8} kind="move" label={t('stageMask.move')} cursor="move" /> : null}
227
+ {handles.resize.map((h) => (
228
+ <div
229
+ key={h.id}
230
+ data-mask-kind="resize"
231
+ data-mask-handle={h.id}
232
+ aria-label={t('stageMask.resize')}
233
+ className="pointer-events-auto absolute flex items-center justify-center"
234
+ style={{
235
+ left: h.at.x - 7,
236
+ top: h.at.y - 7,
237
+ width: 14,
238
+ height: 14,
239
+ transform: f.r ? `rotate(${f.r}deg)` : undefined,
240
+ cursor: resizeCursor(HANDLE_ANGLE[h.id] + f.r + frame.r),
241
+ }}
242
+ >
243
+ <span className="block h-[8px] w-[8px] bg-white" style={{ border: `1px solid ${FRAME_BLUE}` }} />
244
+ </div>
245
+ ))}
246
+ {handles.turn ? <Dot at={handles.turn} size={10} kind="turn" label={t('stageMask.turn')} cursor="grab" /> : null}
247
+ {handles.feather ? (
248
+ <Dot at={handles.feather.at} size={10} kind="feather" label={t('stageMask.feather')} cursor={resizeCursor(90 + f.r + frame.r)} filled />
249
+ ) : null}
250
+ </div>
251
+ {hint ? <GestureHint x={hint.x} y={hint.y} text={hint.text} /> : null}
252
+ </div>
253
+ );
254
+ }
255
+
256
+ /** An outline: a dark line under a white one, to show on any picture. */
257
+ function Stroke({ d, rect, dashed, thin, scaled }: {
258
+ d?: string;
259
+ rect?: { x: number; y: number; w: number; h: number; r: number };
260
+ dashed?: boolean;
261
+ thin?: boolean;
262
+ /** Drawn in a scaled group: the stroke keeps its width on screen. */
263
+ scaled?: boolean;
264
+ }) {
265
+ const common = { fill: 'none', vectorEffect: scaled ? 'non-scaling-stroke' as const : undefined, strokeLinejoin: 'round' as const };
266
+ const shape = (stroke: string, width: number, dash?: string) => (rect
267
+ ? <rect x={rect.x} y={rect.y} width={Math.max(0, rect.w)} height={Math.max(0, rect.h)} rx={rect.r} stroke={stroke} strokeWidth={width} strokeDasharray={dash} {...common} />
268
+ : <path d={d} stroke={stroke} strokeWidth={width} strokeDasharray={dash} {...common} />);
269
+ return (
270
+ <>
271
+ {shape('rgba(0,0,0,.45)', thin ? 2 : 3, dashed ? '4 3' : undefined)}
272
+ {shape(dashed ? 'rgba(255,255,255,.8)' : '#fff', thin ? 1 : 1.5, dashed ? '4 3' : undefined)}
273
+ </>
274
+ );
275
+ }
276
+
277
+ /** A round knob. */
278
+ function Dot({ at, size, kind, label, cursor, filled }: { at: P; size: number; kind: 'move' | 'turn' | 'feather'; label: string; cursor: string; filled?: boolean }) {
279
+ return (
280
+ <div
281
+ data-mask-kind={kind}
282
+ aria-label={label}
283
+ title={label}
284
+ className="pointer-events-auto absolute flex items-center justify-center"
285
+ style={{ left: at.x - 8, top: at.y - 8, width: 16, height: 16, cursor }}
286
+ >
287
+ <span
288
+ className="block rounded-full"
289
+ style={{
290
+ width: size,
291
+ height: size,
292
+ background: filled ? FRAME_BLUE : '#fff',
293
+ border: `1.5px solid ${filled ? '#fff' : FRAME_BLUE}`,
294
+ boxShadow: '0 0 0 0.5px rgba(0,0,0,.25), 0 1px 3px rgba(0,0,0,.3)',
295
+ }}
296
+ />
297
+ </div>
298
+ );
299
+ }
@@ -0,0 +1,246 @@
1
+ /**
2
+ * The frame of the thing in hand on the stage, shared by a whole clip and a layer inside one.
3
+ *
4
+ * A 1px blue border and white corner squares with a blue edge (scale); an invisible ring outside the corners turns the
5
+ * pointer into the rotate cursor; invisible strips on the edges stretch one side (a layer's override scale has x and y;
6
+ * a video's or still's box takes any proportions, its CSS fitting the picture in it; a page's is never stretched, so
7
+ * its frame has corners only). A blue size label sits below the frame. While a gesture runs, a value tag follows the
8
+ * pointer: the position when moving, the size when scaling, the angle when turning.
9
+ *
10
+ * Geometry is the frame's own center, size and angle, not its bounding box: a turned thing has a turned frame.
11
+ *
12
+ * Four sets of data attributes: a whole clip's (`data-mg-kind` / `data-mg-handle`), a layer's (`data-layer-kind` /
13
+ * `data-layer-handle`), a crop's in crop mode (`data-crop-kind` / `data-crop-handle`) and several clips' together
14
+ * (`data-group-kind` / `data-group-handle`); one pointer press is routed by the set it lands on.
15
+ */
16
+ /** The stage's "this one" blue: the frame, picked layers and linked outlines are drawn in it. */
17
+ export const FRAME_BLUE = '#0d99ff';
18
+
19
+ export type FrameCorner = 'nw' | 'ne' | 'se' | 'sw';
20
+ export type FrameEdge = 'n' | 'e' | 's' | 'w';
21
+
22
+ export interface FrameGeometry {
23
+ /** Center, in the stage overlay's px. */
24
+ cx: number;
25
+ cy: number;
26
+ /** Width and height before turning. */
27
+ w: number;
28
+ h: number;
29
+ /** Clockwise, degrees. */
30
+ r: number;
31
+ }
32
+
33
+ const CORNERS: FrameCorner[] = ['nw', 'ne', 'se', 'sw'];
34
+
35
+ /** The handle ring's least size (px): 8px squares at least a square apart, with room left to press and drag. */
36
+ export const HANDLE_BOX_MIN = 28;
37
+ const EDGES: FrameEdge[] = ['n', 'e', 's', 'w'];
38
+
39
+ const CORNER_AT: Record<FrameCorner, { x: 0 | 1; y: 0 | 1 }> = {
40
+ nw: { x: 0, y: 0 }, ne: { x: 1, y: 0 }, se: { x: 1, y: 1 }, sw: { x: 0, y: 1 },
41
+ };
42
+
43
+ /*
44
+ * The rotate cursor: a quarter arc with an arrow at each end (browsers have no such cursor). Drawn for the
45
+ * top-right corner; other corners and turned frames turn it, cached in 15° steps.
46
+ */
47
+ const ROTATE_CURSORS = new Map<number, string>();
48
+ function rotateCursor(angle: number): string {
49
+ const a = ((Math.round(angle / 15) * 15) % 360 + 360) % 360;
50
+ const hit = ROTATE_CURSORS.get(a);
51
+ if (hit) return hit;
52
+ const arc = 'M5 8A11 11 0 0 1 16 19M8.2 4.8L5 8l3.2 3.2M12.8 15.8L16 19l3.2-3.2';
53
+ const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">'
54
+ + `<g transform="rotate(${a} 12 12)" fill="none" stroke-linecap="round" stroke-linejoin="round">`
55
+ + `<path d="${arc}" stroke="white" stroke-width="3.6"/>`
56
+ + `<path d="${arc}" stroke="black" stroke-width="1.5"/>`
57
+ + '</g></svg>';
58
+ const css = `url("data:image/svg+xml,${encodeURIComponent(svg)}") 12 12, crosshair`;
59
+ ROTATE_CURSORS.set(a, css);
60
+ return css;
61
+ }
62
+ const ROTATE_AT: Record<FrameCorner, number> = { ne: 0, se: 90, sw: 180, nw: 270 };
63
+
64
+ /** A resize cursor for an angle: after a 90° turn, the top edge drags sideways. */
65
+ function resizeCursor(angle: number): string {
66
+ const a = ((angle % 180) + 180) % 180;
67
+ if (a < 22.5 || a >= 157.5) return 'ew-resize';
68
+ if (a < 67.5) return 'nwse-resize';
69
+ if (a < 112.5) return 'ns-resize';
70
+ return 'nesw-resize';
71
+ }
72
+
73
+ const CORNER_ANGLE: Record<FrameCorner, number> = { nw: 45, ne: 135, se: 45, sw: 135 };
74
+ const EDGE_ANGLE: Record<FrameEdge, number> = { n: 90, s: 90, e: 0, w: 0 };
75
+
76
+ export function StageTransformFrame({
77
+ frame,
78
+ scope,
79
+ corners = 'scale',
80
+ edges = false,
81
+ rotate = true,
82
+ label,
83
+ moving = false,
84
+ bounds,
85
+ }: {
86
+ frame: FrameGeometry;
87
+ /**
88
+ * Which set of handle attributes (see the file head): `mg` for a whole clip, `layer` for a layer, `crop` for a crop,
89
+ * `group` for several clips selected together.
90
+ */
91
+ scope: 'mg' | 'layer' | 'crop' | 'group';
92
+ corners?: 'scale' | 'none';
93
+ edges?: boolean;
94
+ rotate?: boolean;
95
+ /** The size label below the frame; null for none. */
96
+ label?: string | null;
97
+ /** Being moved: a light fill. */
98
+ moving?: boolean;
99
+ /** The stage's size in overlay px: the size label stays on it (below it is the viewer's own bar). */
100
+ bounds?: { w: number; h: number };
101
+ }) {
102
+ const w = Math.max(frame.w, 1);
103
+ const h = Math.max(frame.h, 1);
104
+ /*
105
+ * Handles sit on a frame at least HANDLE_BOX_MIN big: on something tiny (an icon, a thin line) corner squares on its
106
+ * own edges would pile up over it. The blue border keeps the true size and the handles go on the ring
107
+ * outside, the whole middle still draggable.
108
+ */
109
+ const hw = Math.max(w, HANDLE_BOX_MIN);
110
+ const hh = Math.max(h, HANDLE_BOX_MIN);
111
+ const kindAttr = `data-${scope}-kind`;
112
+ const handleAttr = `data-${scope}-handle`;
113
+ const attrs = (kind: string, handle: string) => ({ [kindAttr]: kind, [handleAttr]: handle });
114
+ /* edge strips leave room for the corners; on a short frame in proportion, never below zero */
115
+ const insetX = Math.min(8, hw / 4);
116
+ const insetY = Math.min(8, hh / 4);
117
+ return (
118
+ <>
119
+ <div
120
+ className="pointer-events-none absolute"
121
+ style={{
122
+ left: frame.cx - hw / 2,
123
+ top: frame.cy - hh / 2,
124
+ width: hw,
125
+ height: hh,
126
+ transform: frame.r ? `rotate(${frame.r}deg)` : undefined,
127
+ transformOrigin: 'center',
128
+ }}
129
+ >
130
+ <div
131
+ {...attrs('move', 'move')}
132
+ /* inside a crop the hand pans the picture: the grab hand says so */
133
+ className={`pointer-events-auto absolute inset-0 ${moving ? 'cursor-grabbing' : scope === 'crop' ? 'cursor-grab' : 'cursor-default'}`}
134
+ />
135
+ <div
136
+ aria-hidden
137
+ className="pointer-events-none absolute"
138
+ style={{
139
+ left: (hw - w) / 2,
140
+ top: (hh - h) / 2,
141
+ width: w,
142
+ height: h,
143
+ /* a border on something a pixel or two big would cover it: outline it from outside instead */
144
+ ...(w < 3 || h < 3 ? { boxShadow: `0 0 0 1px ${FRAME_BLUE}` } : { border: `1px solid ${FRAME_BLUE}` }),
145
+ background: moving ? 'rgba(13,153,255,.06)' : 'transparent',
146
+ }}
147
+ />
148
+ {edges ? EDGES.map((edge) => (
149
+ <div
150
+ key={edge}
151
+ {...attrs('stretch', edge)}
152
+ aria-hidden
153
+ className="pointer-events-auto absolute"
154
+ style={{
155
+ cursor: resizeCursor(EDGE_ANGLE[edge] + frame.r),
156
+ ...(edge === 'n' ? { left: insetX, right: insetX, top: -4, height: 8 }
157
+ : edge === 's' ? { left: insetX, right: insetX, bottom: -4, height: 8 }
158
+ : edge === 'w' ? { top: insetY, bottom: insetY, left: -4, width: 8 }
159
+ : { top: insetY, bottom: insetY, right: -4, width: 8 }),
160
+ }}
161
+ />
162
+ )) : null}
163
+ {rotate ? CORNERS.map((corner) => {
164
+ const at = CORNER_AT[corner];
165
+ return (
166
+ <div
167
+ key={`rot-${corner}`}
168
+ {...attrs('rotate', corner)}
169
+ aria-hidden
170
+ className="pointer-events-auto absolute"
171
+ style={{
172
+ width: 20,
173
+ height: 20,
174
+ left: at.x ? undefined : -20,
175
+ right: at.x ? -20 : undefined,
176
+ top: at.y ? undefined : -20,
177
+ bottom: at.y ? -20 : undefined,
178
+ cursor: rotateCursor(ROTATE_AT[corner] + frame.r),
179
+ }}
180
+ />
181
+ );
182
+ }) : null}
183
+ {corners === 'scale' ? CORNERS.map((corner) => {
184
+ const at = CORNER_AT[corner];
185
+ return (
186
+ <div
187
+ key={corner}
188
+ {...attrs('scale', corner)}
189
+ aria-hidden
190
+ className="pointer-events-auto absolute flex items-center justify-center"
191
+ style={{
192
+ width: 14,
193
+ height: 14,
194
+ left: `calc(${at.x * 100}% - 7px)`,
195
+ top: `calc(${at.y * 100}% - 7px)`,
196
+ cursor: resizeCursor(CORNER_ANGLE[corner] + frame.r),
197
+ }}
198
+ >
199
+ <span
200
+ className="block h-[8px] w-[8px] bg-white"
201
+ style={{ border: `1px solid ${FRAME_BLUE}`, boxShadow: '0 0 0 0.5px rgba(0,0,0,.08)' }}
202
+ />
203
+ </div>
204
+ );
205
+ }) : null}
206
+ </div>
207
+ {/* shown while dragging too: the frame moves and its size changes, and the label follows */}
208
+ {label ? <FrameLabel frame={{ ...frame, w: hw, h: hh }} text={label} {...(bounds ? { bounds } : {})} /> : null}
209
+ </>
210
+ );
211
+ }
212
+
213
+ /** The label's height (14px line + 1px padding each side) and its gap to the frame. */
214
+ const LABEL_H = 16;
215
+ const LABEL_GAP = 6;
216
+
217
+ /**
218
+ * The size label: 6px below the bounding box's bottom, centered; it does not turn with the frame. Something reaching
219
+ * the stage's bottom (a full-frame clip) has it just inside its bottom edge instead, clear of the viewer's bar.
220
+ */
221
+ function FrameLabel({ frame, text, bounds }: { frame: FrameGeometry; text: string; bounds?: { w: number; h: number } }) {
222
+ const rad = (frame.r * Math.PI) / 180;
223
+ const halfH = (Math.abs(frame.w * Math.sin(rad)) + Math.abs(frame.h * Math.cos(rad))) / 2;
224
+ const below = frame.cy + halfH + LABEL_GAP;
225
+ const top = bounds && below + LABEL_H > bounds.h ? Math.max(0, Math.min(below, bounds.h) - LABEL_H - LABEL_GAP) : below;
226
+ return (
227
+ <div
228
+ className="pointer-events-none absolute z-[7] -translate-x-1/2 whitespace-nowrap rounded-[3px] px-1 py-[1px] text-[10px] font-medium leading-[14px] text-white tabular-nums"
229
+ style={{ left: frame.cx, top, background: FRAME_BLUE }}
230
+ >
231
+ {text}
232
+ </div>
233
+ );
234
+ }
235
+
236
+ /** The value tag next to the pointer while a gesture runs. */
237
+ export function GestureHint({ x, y, text }: { x: number; y: number; text: string }) {
238
+ return (
239
+ <div
240
+ className="pointer-events-none absolute z-[8] whitespace-nowrap rounded-[4px] px-1.5 py-[2px] text-[10.5px] font-medium leading-[15px] text-white tabular-nums shadow-[0_1px_4px_rgba(0,0,0,.25)]"
241
+ style={{ left: x + 14, top: y + 16, background: 'rgba(30,30,30,.92)' }}
242
+ >
243
+ {text}
244
+ </div>
245
+ );
246
+ }
@@ -0,0 +1,46 @@
1
+ /* A quiet, consistent range control across Chromium, Safari and Firefox. */
2
+ .range {
3
+ appearance: none;
4
+ -webkit-appearance: none;
5
+ flex: 1;
6
+ min-width: 24px;
7
+ width: 0;
8
+ height: 20px;
9
+ margin: 0;
10
+ background: transparent;
11
+ cursor: pointer;
12
+ }
13
+ .range::-webkit-slider-runnable-track {
14
+ height: 3px;
15
+ border-radius: 3px;
16
+ background: var(--surface-3);
17
+ }
18
+ .range::-moz-range-track {
19
+ height: 3px;
20
+ border-radius: 3px;
21
+ background: var(--surface-3);
22
+ }
23
+ .range::-webkit-slider-thumb {
24
+ appearance: none;
25
+ -webkit-appearance: none;
26
+ width: 10px;
27
+ height: 10px;
28
+ margin-top: -3.5px;
29
+ border: 0;
30
+ border-radius: 50%;
31
+ background: var(--text-dim);
32
+ box-shadow: 0 0 0 2px var(--panel);
33
+ }
34
+ .range::-moz-range-thumb {
35
+ width: 10px;
36
+ height: 10px;
37
+ border: 0;
38
+ border-radius: 50%;
39
+ background: var(--text-dim);
40
+ box-shadow: 0 0 0 2px var(--panel);
41
+ }
42
+ .range:focus-visible {
43
+ outline: 1px solid var(--text-muted);
44
+ outline-offset: 2px;
45
+ border-radius: 3px;
46
+ }