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,397 @@
1
+ /**
2
+ * The control bar laid over the bottom of the picture in full screen (YouTube's classic layout): bare buttons over a
3
+ * gradient — play, volume and time on the left; subtitles, settings and exit full screen on the right. The volume
4
+ * slider slides out on hover; its clip box is padded 7px each side so the knob is whole at 0 and 100%.
5
+ *
6
+ * Settings holds one row, playback speed. (A quality row was tried and dropped: films are drawn as vectors, so it
7
+ * changed nothing in most of them.)
8
+ */
9
+ import * as React from 'react';
10
+ import { useT } from '@/i18n';
11
+ import {
12
+ TransportIconBtn,
13
+ TransportSeekBar,
14
+ transportTimeText,
15
+ } from './transport';
16
+
17
+ /* YouTube-style icons, 24×24, currentColor */
18
+ function Icon({ d, size = 24 }: { d: string; size?: number }) {
19
+ return (
20
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor" aria-hidden focusable="false" style={{ display: 'block' }}>
21
+ <path d={d} />
22
+ </svg>
23
+ );
24
+ }
25
+
26
+ const PATH_PLAY = 'M8 5v14l11-7z';
27
+ const PATH_PAUSE = 'M6 5h4v14H6zM14 5h4v14h-4z';
28
+ const PATH_VOL_HIGH = 'M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z';
29
+ const PATH_VOL_LOW = 'M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02z';
30
+ const PATH_VOL_MUTE = 'M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z';
31
+ const PATH_SETTINGS = 'M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z';
32
+ const PATH_FULLSCREEN_EXIT = 'M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z';
33
+ /* the speed row's icon (material "speed") */
34
+ const PATH_SPEED = 'M20.38 8.57l-1.23 1.85a8 8 0 0 1-.22 7.58H5.07A8 8 0 0 1 15.58 6.85l1.85-1.23A10 10 0 0 0 3.35 19a2 2 0 0 0 1.72 1h13.85a2 2 0 0 0 1.74-1 10 10 0 0 0-.27-10.44zm-9.79 6.84a2 2 0 0 0 2.83 0l5.66-8.49-8.49 5.66a2 2 0 0 0 0 2.83z';
35
+ const PATH_CHEVRON = 'M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z';
36
+ const PATH_CHEVRON_BACK = 'M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z';
37
+ const PATH_CHECK = 'M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z';
38
+
39
+ /** The subtitles mark (YouTube's), also the timeline's subtitles toggle. */
40
+ export function CaptionsIcon({ size = 24 }: { size?: number }) {
41
+ return (
42
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor" aria-hidden focusable="false" style={{ display: 'block' }}>
43
+ <path d="M19 4H5c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 7H9.5v-.5h-2v3h2V13H11v1c0 .55-.45 1-1 1H7c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1h3c.55 0 1 .45 1 1v1zm7 0h-1.5v-.5h-2v3h2V13H18v1c0 .55-.45 1-1 1h-3c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1h3c.55 0 1 .45 1 1v1z" />
44
+ </svg>
45
+ );
46
+ }
47
+
48
+ const SPEED_OPTIONS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
49
+
50
+ export interface PlayerControlsBarProps {
51
+ timeMs: number;
52
+ totalMs: number;
53
+ onPreview(ms: number): void;
54
+ onCommit(ms: number): void;
55
+
56
+ playing: boolean;
57
+ onToggle(): void;
58
+
59
+ volume: number;
60
+ muted: boolean;
61
+ onVolumeChange(v: number): void;
62
+ onToggleMute(): void;
63
+
64
+ /** Absent: no subtitles button (nothing to show). */
65
+ captions?: { on: boolean; onToggle(): void };
66
+
67
+ rate: number;
68
+ onRateChange(rate: number): void;
69
+
70
+ onExitFullscreen(): void;
71
+
72
+ /** Shown or not (the host runs the idle timer); while the settings panel is open it shows regardless. */
73
+ visible: boolean;
74
+ /** The pointer touched the bar: the host restarts its idle timer. */
75
+ onShow?(): void;
76
+ }
77
+
78
+ export function PlayerControlsBar({
79
+ timeMs,
80
+ totalMs,
81
+ onPreview,
82
+ onCommit,
83
+ playing,
84
+ onToggle,
85
+ volume,
86
+ muted,
87
+ onVolumeChange,
88
+ onToggleMute,
89
+ captions,
90
+ rate,
91
+ onRateChange,
92
+ onExitFullscreen,
93
+ visible,
94
+ onShow,
95
+ }: PlayerControlsBarProps) {
96
+ const t = useT();
97
+ const [settingsOpen, setSettingsOpen] = React.useState(false);
98
+ const shown = visible || settingsOpen;
99
+
100
+ return (
101
+ <div
102
+ data-vp-controls
103
+ style={{
104
+ position: 'absolute',
105
+ left: 0,
106
+ right: 0,
107
+ bottom: 0,
108
+ zIndex: 10,
109
+ padding: '28px 16px 8px',
110
+ /* only as dark as white text and buttons need to stand */
111
+ background: 'linear-gradient(transparent, rgba(0,0,0,.45))',
112
+ opacity: shown ? 1 : 0,
113
+ transition: 'opacity .25s',
114
+ pointerEvents: shown ? 'auto' : 'none',
115
+ }}
116
+ onClick={(e) => e.stopPropagation()}
117
+ onMouseEnter={onShow}
118
+ onMouseMove={onShow}
119
+ onPointerDown={(e) => { e.stopPropagation(); onShow?.(); }}
120
+ >
121
+ <TransportSeekBar
122
+ timeMs={timeMs}
123
+ totalMs={totalMs}
124
+ onPreview={onPreview}
125
+ onCommit={onCommit}
126
+ />
127
+ <div style={{ display: 'flex', alignItems: 'center', gap: 4, marginTop: 2, color: '#fff', fontSize: 12 }}>
128
+ <TransportIconBtn onClick={onToggle} title={playing ? t('player.pauseTitle') : t('player.playTitle')}>
129
+ <Icon d={playing ? PATH_PAUSE : PATH_PLAY} />
130
+ </TransportIconBtn>
131
+ <VolumeControl
132
+ volume={volume}
133
+ muted={muted}
134
+ onVolumeChange={onVolumeChange}
135
+ onToggleMute={onToggleMute}
136
+ />
137
+ <span style={{ opacity: 0.9, fontVariantNumeric: 'tabular-nums', fontSize: 12, marginLeft: 6, whiteSpace: 'nowrap' }}>
138
+ {transportTimeText(timeMs)} / {transportTimeText(totalMs)}
139
+ </span>
140
+ <span style={{ flex: 1 }} />
141
+ {captions ? (
142
+ <TransportIconBtn onClick={captions.onToggle} title={t('player.captionsTitle')}>
143
+ <span style={{ position: 'relative', display: 'block' }}>
144
+ <CaptionsIcon />
145
+ {captions.on && (
146
+ <span style={{ position: 'absolute', left: 3, right: 3, bottom: -3, height: 3, borderRadius: 1, background: '#f03' }} />
147
+ )}
148
+ </span>
149
+ </TransportIconBtn>
150
+ ) : null}
151
+ <SettingsMenu
152
+ open={settingsOpen}
153
+ onOpenChange={setSettingsOpen}
154
+ rate={rate}
155
+ onRateChange={onRateChange}
156
+ />
157
+ <TransportIconBtn onClick={onExitFullscreen} title={t('player.exitFullscreenTitle')}>
158
+ <Icon d={PATH_FULLSCREEN_EXIT} />
159
+ </TransportIconBtn>
160
+ </div>
161
+ </div>
162
+ );
163
+ }
164
+
165
+ /** The slider's track length, and the padding at each end for the knob (radius 6 + 1). */
166
+ const VOL_TRACK_W = 52;
167
+ const VOL_PAD = 7;
168
+
169
+ /** Volume: the button, and a slider that slides out on hover. */
170
+ function VolumeControl({
171
+ volume,
172
+ muted,
173
+ onVolumeChange,
174
+ onToggleMute,
175
+ }: {
176
+ volume: number;
177
+ muted: boolean;
178
+ onVolumeChange(v: number): void;
179
+ onToggleMute(): void;
180
+ }) {
181
+ const t = useT();
182
+ const [hover, setHover] = React.useState(false);
183
+ const trackRef = React.useRef<HTMLDivElement | null>(null);
184
+ const draggingRef = React.useRef(false);
185
+ const effective = muted || volume === 0 ? 0 : volume;
186
+ const iconPath = effective === 0 ? PATH_VOL_MUTE : effective < 0.5 ? PATH_VOL_LOW : PATH_VOL_HIGH;
187
+ const open = hover || draggingRef.current;
188
+ const fullW = VOL_TRACK_W + VOL_PAD * 2;
189
+
190
+ const setFromClientX = (clientX: number) => {
191
+ const el = trackRef.current;
192
+ if (!el) return;
193
+ const r = el.getBoundingClientRect();
194
+ if (!(r.width > 0)) return;
195
+ onVolumeChange(Math.max(0, Math.min(1, (clientX - r.left) / r.width)));
196
+ };
197
+
198
+ return (
199
+ <div
200
+ style={{ display: 'flex', alignItems: 'center' }}
201
+ onMouseEnter={() => setHover(true)}
202
+ onMouseLeave={() => setHover(false)}
203
+ >
204
+ <TransportIconBtn onClick={onToggleMute} title={effective === 0 ? t('player.unmuteTitle') : t('player.muteTitle')}>
205
+ <Icon d={iconPath} />
206
+ </TransportIconBtn>
207
+ <div
208
+ style={{
209
+ width: open ? fullW : 0,
210
+ opacity: open ? 1 : 0,
211
+ overflow: 'hidden',
212
+ transition: 'width .2s ease, opacity .2s ease',
213
+ display: 'flex',
214
+ alignItems: 'center',
215
+ height: 24,
216
+ }}
217
+ >
218
+ <div
219
+ role="slider"
220
+ aria-label={t('player.volume')}
221
+ aria-valuemin={0}
222
+ aria-valuemax={1}
223
+ aria-valuenow={effective}
224
+ style={{
225
+ position: 'relative',
226
+ display: 'flex',
227
+ alignItems: 'center',
228
+ width: fullW,
229
+ height: 24,
230
+ padding: `0 ${VOL_PAD}px`,
231
+ boxSizing: 'border-box',
232
+ cursor: 'pointer',
233
+ touchAction: 'none',
234
+ }}
235
+ onPointerDown={(e) => {
236
+ e.preventDefault();
237
+ e.stopPropagation();
238
+ draggingRef.current = true;
239
+ try { e.currentTarget.setPointerCapture(e.pointerId); } catch { /* not capturable */ }
240
+ setFromClientX(e.clientX);
241
+ }}
242
+ onPointerMove={(e) => { if (draggingRef.current) setFromClientX(e.clientX); }}
243
+ onPointerUp={() => { draggingRef.current = false; }}
244
+ onPointerCancel={() => { draggingRef.current = false; }}
245
+ >
246
+ <div ref={trackRef} style={{ position: 'relative', width: VOL_TRACK_W, height: 3, borderRadius: 1.5, background: 'rgba(255,255,255,.3)', pointerEvents: 'none' }}>
247
+ <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: `${effective * 100}%`, borderRadius: 1.5, background: '#fff', pointerEvents: 'none' }} />
248
+ <div
249
+ style={{
250
+ position: 'absolute',
251
+ left: `${effective * 100}%`,
252
+ top: '50%',
253
+ width: 12,
254
+ height: 12,
255
+ marginLeft: -6,
256
+ marginTop: -6,
257
+ borderRadius: '50%',
258
+ background: '#fff',
259
+ pointerEvents: 'none',
260
+ }}
261
+ />
262
+ </div>
263
+ </div>
264
+ </div>
265
+ </div>
266
+ );
267
+ }
268
+
269
+ /**
270
+ * The settings panel: a root row (playback speed) that opens a list. As YouTube: icon left, current value and a chevron
271
+ * right; the list starts with a "‹ title" row back to the root.
272
+ */
273
+ function SettingsMenu({
274
+ open,
275
+ onOpenChange,
276
+ rate,
277
+ onRateChange,
278
+ }: {
279
+ open: boolean;
280
+ onOpenChange(open: boolean): void;
281
+ rate: number;
282
+ onRateChange(rate: number): void;
283
+ }) {
284
+ const t = useT();
285
+ const [view, setView] = React.useState<'root' | 'speed'>('root');
286
+ const wrapRef = React.useRef<HTMLDivElement | null>(null);
287
+
288
+ React.useEffect(() => {
289
+ if (!open) { setView('root'); return; }
290
+ const onDocDown = (e: PointerEvent) => {
291
+ if (wrapRef.current && !wrapRef.current.contains(e.target as Node)) onOpenChange(false);
292
+ };
293
+ document.addEventListener('pointerdown', onDocDown, true);
294
+ return () => document.removeEventListener('pointerdown', onDocDown, true);
295
+ }, [open, onOpenChange]);
296
+
297
+ const row: React.CSSProperties = {
298
+ display: 'flex',
299
+ alignItems: 'center',
300
+ gap: 14,
301
+ width: '100%',
302
+ padding: '10px 16px',
303
+ border: 0,
304
+ background: 'transparent',
305
+ color: '#eee',
306
+ fontSize: 13,
307
+ cursor: 'pointer',
308
+ textAlign: 'left',
309
+ whiteSpace: 'nowrap',
310
+ };
311
+ const value: React.CSSProperties = { marginLeft: 'auto', display: 'inline-flex', alignItems: 'center', gap: 2, opacity: 0.75 };
312
+ const rateText = (r: number) => (r === 1 ? t('player.speedNormal') : `${r}×`);
313
+
314
+ return (
315
+ <div ref={wrapRef} style={{ position: 'relative' }}>
316
+ <TransportIconBtn onClick={() => onOpenChange(!open)} title={t('player.settings')} active={open}>
317
+ <span style={{ display: 'block', transform: open ? 'rotate(30deg)' : 'none', transition: 'transform .15s' }}>
318
+ <Icon d={PATH_SETTINGS} />
319
+ </span>
320
+ </TransportIconBtn>
321
+ {open && (
322
+ <div
323
+ style={{
324
+ position: 'absolute',
325
+ right: 0,
326
+ bottom: 46,
327
+ minWidth: 232,
328
+ borderRadius: 12,
329
+ background: 'rgba(28,28,28,.94)',
330
+ backdropFilter: 'blur(8px)',
331
+ WebkitBackdropFilter: 'blur(8px)',
332
+ padding: '6px 0',
333
+ zIndex: 30,
334
+ boxShadow: '0 8px 28px rgba(0,0,0,.45)',
335
+ }}
336
+ >
337
+ {view === 'root' ? (
338
+ <button type="button" style={row} onClick={() => setView('speed')}>
339
+ <Icon d={PATH_SPEED} size={20} />
340
+ <span>{t('player.speed')}</span>
341
+ <span style={value}>{rateText(rate)}<Icon d={PATH_CHEVRON} size={18} /></span>
342
+ </button>
343
+ ) : (
344
+ <>
345
+ <button
346
+ type="button"
347
+ style={{ ...row, padding: '8px 12px', borderBottom: '1px solid rgba(255,255,255,.12)', marginBottom: 4 }}
348
+ onClick={() => setView('root')}
349
+ >
350
+ <Icon d={PATH_CHEVRON_BACK} size={20} />
351
+ <span>{t('player.speed')}</span>
352
+ </button>
353
+ {SPEED_OPTIONS.map((s) => (
354
+ <MenuOption
355
+ key={s}
356
+ style={row}
357
+ checked={s === rate}
358
+ onClick={() => { onRateChange(s); onOpenChange(false); }}
359
+ >
360
+ {rateText(s)}
361
+ </MenuOption>
362
+ ))}
363
+ </>
364
+ )}
365
+ </div>
366
+ )}
367
+ </div>
368
+ );
369
+ }
370
+
371
+ function MenuOption({
372
+ checked,
373
+ onClick,
374
+ style,
375
+ children,
376
+ }: {
377
+ checked: boolean;
378
+ onClick(): void;
379
+ style: React.CSSProperties;
380
+ children: React.ReactNode;
381
+ }) {
382
+ const [hover, setHover] = React.useState(false);
383
+ return (
384
+ <button
385
+ type="button"
386
+ style={{ ...style, gap: 10, background: hover ? 'rgba(255,255,255,.1)' : 'transparent' }}
387
+ onMouseEnter={() => setHover(true)}
388
+ onMouseLeave={() => setHover(false)}
389
+ onClick={onClick}
390
+ >
391
+ <span style={{ width: 20, display: 'inline-flex', justifyContent: 'center' }}>
392
+ {checked ? <Icon d={PATH_CHECK} size={18} /> : null}
393
+ </span>
394
+ <span>{children}</span>
395
+ </button>
396
+ );
397
+ }
@@ -0,0 +1,294 @@
1
+ /** The player bar's two parts: the seek bar and the round icon button. */
2
+ import React from 'react';
3
+ import { useT } from '@/i18n';
4
+ import { stepFrames } from '@/lib/timecode';
5
+ import { JUMP_FRAMES } from '@/lib/timeline-keys';
6
+
7
+ /** The played part and the knob. */
8
+ const SEEK_COLOR = '#f03';
9
+
10
+ export function TransportSeekBar({
11
+ timeMs,
12
+ totalMs,
13
+ onPreview,
14
+ onCommit,
15
+ }: {
16
+ timeMs: number;
17
+ totalMs: number;
18
+ /** While dragging: show that frame only. */
19
+ onPreview(ms: number): void;
20
+ /** On release: go there. */
21
+ onCommit(ms: number): void;
22
+ }) {
23
+ const t = useT();
24
+ const ref = React.useRef<HTMLDivElement | null>(null);
25
+ const fillRef = React.useRef<HTMLDivElement | null>(null);
26
+ const thumbRef = React.useRef<HTMLDivElement | null>(null);
27
+ const dragging = React.useRef(false);
28
+ const [hovering, setHovering] = React.useState(false);
29
+ const [dragActive, setDragActive] = React.useState(false);
30
+ /** pointer x from the bar's left edge, in px */
31
+ const [hoverX, setHoverX] = React.useState<number | null>(null);
32
+ const active = hovering || dragActive;
33
+ /* the last valid position while dragging: on release/cancel clientX can be 0 (Safari, lost capture) */
34
+ const lastValidMs = React.useRef(timeMs);
35
+ const activePointerId = React.useRef<number | null>(null);
36
+ const cleanupDragListeners = React.useRef<(() => void) | null>(null);
37
+
38
+ React.useEffect(() => {
39
+ if (!dragging.current) lastValidMs.current = timeMs;
40
+ }, [timeMs]);
41
+
42
+ const applyProgress = React.useCallback((ms: number) => {
43
+ const pct = totalMs ? (ms / totalMs) * 100 : 0;
44
+ if (fillRef.current) fillRef.current.style.width = `${pct}%`;
45
+ if (thumbRef.current) thumbRef.current.style.left = `${pct}%`;
46
+ }, [totalMs]);
47
+
48
+ React.useEffect(() => {
49
+ applyProgress(timeMs);
50
+ }, [timeMs, applyProgress]);
51
+
52
+ const pos = React.useCallback((clientX: number): number | null => {
53
+ const el = ref.current;
54
+ if (!el) return null;
55
+ const r = el.getBoundingClientRect();
56
+ /* no width yet (bar not laid out) or a bad coordinate: skip, never jump to the start on NaN/0 */
57
+ if (!(r.width > 0) || !Number.isFinite(clientX)) return null;
58
+ /* Safari sometimes reports clientX 0 on capture release; not valid unless the bar touches the left edge */
59
+ if (clientX === 0 && r.left > 1) return null;
60
+ return Math.max(0, Math.min(1, (clientX - r.left) / r.width)) * totalMs;
61
+ }, [totalMs]);
62
+
63
+ const cleanupDocumentDrag = React.useCallback(() => {
64
+ cleanupDragListeners.current?.();
65
+ cleanupDragListeners.current = null;
66
+ activePointerId.current = null;
67
+ }, []);
68
+
69
+ const previewAt = React.useCallback((clientX: number) => {
70
+ const ms = pos(clientX);
71
+ if (ms == null) return;
72
+ lastValidMs.current = ms;
73
+ onPreview(ms);
74
+ }, [onPreview, pos]);
75
+
76
+ const finishDrag = React.useCallback((releaseClientX?: number) => {
77
+ if (!dragging.current) return;
78
+ dragging.current = false;
79
+ setDragActive(false);
80
+ cleanupDocumentDrag();
81
+ let ms = lastValidMs.current;
82
+ if (releaseClientX != null) {
83
+ const atRelease = pos(releaseClientX);
84
+ if (atRelease != null) ms = atRelease;
85
+ }
86
+ if (!Number.isFinite(ms)) return;
87
+ onCommit(ms);
88
+ }, [cleanupDocumentDrag, onCommit, pos]);
89
+
90
+ React.useEffect(() => cleanupDocumentDrag, [cleanupDocumentDrag]);
91
+
92
+ /* pointer capture is the main path; the document listeners are the fallback when capture is lost and the release
93
+ never comes back to the bar (it would stick to the pointer) */
94
+ return (
95
+ <div
96
+ ref={ref}
97
+ role="slider"
98
+ aria-label={t('player.seek')}
99
+ aria-valuemin={0}
100
+ aria-valuemax={totalMs}
101
+ aria-valuenow={Math.max(0, Math.min(totalMs, timeMs))}
102
+ tabIndex={0}
103
+ onKeyDown={event => {
104
+ if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) return;
105
+ event.preventDefault();
106
+ event.stopPropagation();
107
+ /* a frame, ⇧ a second: the arrows step the same everywhere in Studio */
108
+ const next = event.key === 'Home' ? 0 : event.key === 'End' ? totalMs
109
+ : Math.max(0, Math.min(totalMs, stepFrames(timeMs, (event.key === 'ArrowRight' ? 1 : -1) * (event.shiftKey ? JUMP_FRAMES : 1))));
110
+ onPreview(next);
111
+ onCommit(next);
112
+ }}
113
+ style={{
114
+ position: 'relative',
115
+ height: 16,
116
+ cursor: 'pointer',
117
+ display: 'flex',
118
+ alignItems: 'center',
119
+ touchAction: 'none',
120
+ }}
121
+ onPointerDown={e => {
122
+ if (e.button !== 0 && e.pointerType === 'mouse') return;
123
+ e.preventDefault();
124
+ e.stopPropagation();
125
+ const ms = pos(e.clientX);
126
+ if (ms == null) return;
127
+ dragging.current = true;
128
+ setDragActive(true);
129
+ lastValidMs.current = ms;
130
+ cleanupDocumentDrag();
131
+ activePointerId.current = e.pointerId;
132
+ const doc = e.currentTarget.ownerDocument;
133
+ const onDocMove = (ev: PointerEvent) => {
134
+ if (ev.pointerId !== activePointerId.current) return;
135
+ ev.preventDefault();
136
+ previewAt(ev.clientX);
137
+ };
138
+ const onDocEnd = (ev: PointerEvent) => {
139
+ if (ev.pointerId !== activePointerId.current) return;
140
+ ev.preventDefault();
141
+ finishDrag(ev.clientX);
142
+ };
143
+ doc.addEventListener('pointermove', onDocMove, true);
144
+ doc.addEventListener('pointerup', onDocEnd, true);
145
+ doc.addEventListener('pointercancel', onDocEnd, true);
146
+ cleanupDragListeners.current = () => {
147
+ doc.removeEventListener('pointermove', onDocMove, true);
148
+ doc.removeEventListener('pointerup', onDocEnd, true);
149
+ doc.removeEventListener('pointercancel', onDocEnd, true);
150
+ };
151
+ try { e.currentTarget.setPointerCapture(e.pointerId); } catch { /* the document listeners cover it */ }
152
+ onPreview(ms);
153
+ }}
154
+ onPointerMove={e => {
155
+ const r = ref.current?.getBoundingClientRect();
156
+ if (r && r.width > 0) setHoverX(Math.max(0, Math.min(r.width, e.clientX - r.left)));
157
+ if (!dragging.current) return;
158
+ previewAt(e.clientX);
159
+ }}
160
+ onMouseEnter={() => setHovering(true)}
161
+ onMouseLeave={() => { setHovering(false); setHoverX(null); }}
162
+ onPointerUp={e => {
163
+ if (!dragging.current) return;
164
+ try { e.currentTarget.releasePointerCapture(e.pointerId); } catch { /* already released */ }
165
+ finishDrag(e.clientX);
166
+ }}
167
+ onPointerCancel={(e) => {
168
+ finishDrag(e.clientX);
169
+ }}
170
+ >
171
+ {/* hover time bubble */}
172
+ {hovering && hoverX != null && (() => {
173
+ const el = ref.current;
174
+ const w = el?.getBoundingClientRect().width ?? 0;
175
+ if (!(w > 0) || !Number.isFinite(totalMs)) return null;
176
+ const hoverMs = (hoverX / w) * totalMs;
177
+ return (
178
+ <div
179
+ style={{
180
+ position: 'absolute',
181
+ left: hoverX,
182
+ bottom: 20,
183
+ transform: 'translateX(-50%)',
184
+ padding: '3px 8px',
185
+ borderRadius: 4,
186
+ background: 'rgba(0,0,0,.82)',
187
+ color: '#fff',
188
+ fontSize: 12,
189
+ whiteSpace: 'nowrap',
190
+ pointerEvents: 'none',
191
+ fontVariantNumeric: 'tabular-nums',
192
+ textAlign: 'center',
193
+ }}
194
+ >
195
+ {transportTimeText(hoverMs)}
196
+ </div>
197
+ );
198
+ })()}
199
+ <div
200
+ style={{
201
+ position: 'relative',
202
+ width: '100%',
203
+ height: active ? 5 : 3,
204
+ borderRadius: active ? 2.5 : 1.5,
205
+ background: 'rgba(255,255,255,.25)',
206
+ pointerEvents: 'none',
207
+ transition: 'height .1s',
208
+ }}
209
+ >
210
+ <div
211
+ ref={fillRef}
212
+ style={{
213
+ position: 'absolute',
214
+ left: 0,
215
+ top: 0,
216
+ bottom: 0,
217
+ width: '0%',
218
+ background: SEEK_COLOR,
219
+ pointerEvents: 'none',
220
+ }}
221
+ />
222
+ {/* the round thumb: shown on hover and while dragging */}
223
+ <div
224
+ ref={thumbRef}
225
+ style={{
226
+ position: 'absolute',
227
+ left: '0%',
228
+ top: '50%',
229
+ width: 13,
230
+ height: 13,
231
+ marginLeft: -6.5,
232
+ marginTop: -6.5,
233
+ borderRadius: '50%',
234
+ background: SEEK_COLOR,
235
+ transform: active ? 'scale(1)' : 'scale(0)',
236
+ transition: 'transform .1s',
237
+ pointerEvents: 'none',
238
+ }}
239
+ />
240
+ </div>
241
+ </div>
242
+ );
243
+ }
244
+
245
+ export function TransportIconBtn({
246
+ children,
247
+ onClick,
248
+ title,
249
+ active,
250
+ }: {
251
+ children: React.ReactNode;
252
+ onClick(): void;
253
+ title?: string;
254
+ /** Buttons that open a panel (settings): a light background while it is open. */
255
+ active?: boolean;
256
+ }) {
257
+ const [hover, setHover] = React.useState(false);
258
+ return (
259
+ <button
260
+ type="button"
261
+ onClick={onClick}
262
+ title={title}
263
+ aria-label={title}
264
+ onMouseEnter={() => setHover(true)}
265
+ onMouseLeave={() => setHover(false)}
266
+ /* no focus on click: the next Space would land on the button with a focus ring; Tab focus is kept */
267
+ onMouseDown={(e) => e.preventDefault()}
268
+ style={{
269
+ border: 0,
270
+ background: active ? 'rgba(255,255,255,.2)' : 'transparent',
271
+ color: '#fff',
272
+ cursor: 'pointer',
273
+ padding: '4px 6px',
274
+ borderRadius: 6,
275
+ lineHeight: 1,
276
+ display: 'flex',
277
+ alignItems: 'center',
278
+ justifyContent: 'center',
279
+ flexShrink: 0,
280
+ opacity: hover ? 1 : 0.9,
281
+ transform: hover ? 'scale(1.08)' : 'scale(1)',
282
+ transition: 'opacity .1s, transform .1s',
283
+ }}
284
+ >
285
+ {children}
286
+ </button>
287
+ );
288
+ }
289
+
290
+ /** `m:ss`, for the bar's readout and the hover bubble. */
291
+ export function transportTimeText(ms: number): string {
292
+ const s = Math.floor(ms / 1000);
293
+ return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, '0')}`;
294
+ }