@hypit/hypit 0.1.4 → 0.1.6

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 (462) hide show
  1. package/README.md +4 -2
  2. package/dist/public/caption.d.ts +206 -183
  3. package/dist/public/composition.d.ts +25 -3
  4. package/dist/public/endpoint-kit.d.ts +24 -2
  5. package/dist/public/generation.d.ts +5 -1
  6. package/dist/public/hyperframes.d.ts +19 -1
  7. package/dist/public/narrative.d.ts +17 -3
  8. package/dist/public/performance.d.ts +1590 -0
  9. package/dist/public/program-space.d.ts +179 -32
  10. package/dist/public/runtime-kit.d.ts +21 -8
  11. package/dist/public/sound.d.ts +822 -0
  12. package/dist/public/speech.d.ts +41 -0
  13. package/dist/public/studio-adapter.d.ts +77 -15
  14. package/dist/public/temporal-markup.d.ts +9 -44
  15. package/dist/public/temporal.d.ts +37 -28
  16. package/dist/public/{semantic-track.d.ts → timeline.d.ts} +62 -49
  17. package/examples/README.md +18 -10
  18. package/examples/minimal-author-package/packages/example-component/preview/preview.svml +19 -12
  19. package/examples/minimal-author-package/packages/example-component/src/component.ts +5 -5
  20. package/examples/minimal-author-package/packages/example-component/src/fragment.ts +3 -5
  21. package/examples/minimal-author-package/packages/example-component/src/manifest.ts +8 -10
  22. package/examples/minimal-author-package/packages/example-component/src/surface.ts +2 -2
  23. package/examples/provider-package/README.md +78 -0
  24. package/examples/provider-package/hypit.runtime.json +12 -0
  25. package/examples/provider-package/packages/provider-images/package.json +11 -0
  26. package/examples/provider-package/packages/provider-images/src/activation.ts +24 -0
  27. package/examples/provider-package/packages/provider-images/src/provider.ts +122 -0
  28. package/examples/provider-package/packages/provider-images/tsconfig.json +9 -0
  29. package/examples/semantic-composition/README.md +8 -1
  30. package/examples/semantic-composition/chat.svml +6 -5
  31. package/examples/semantic-composition/hypit.runtime.json +1 -1
  32. package/examples/semantic-composition/packages/chat-scene/README.md +3 -3
  33. package/examples/semantic-composition/packages/chat-scene/src/activation.ts +18 -21
  34. package/examples/semantic-composition/packages/chat-scene/src/render.ts +4 -4
  35. package/examples/semantic-composition/packages/performance-styles/README.md +42 -0
  36. package/examples/semantic-composition/packages/performance-styles/package.json +25 -0
  37. package/examples/semantic-composition/packages/performance-styles/src/activation.ts +57 -0
  38. package/examples/semantic-composition/packages/performance-styles/src/render.ts +54 -0
  39. package/examples/semantic-composition/packages/performance-styles/src/studio.ts +28 -0
  40. package/examples/semantic-composition/packages/performance-styles/tsconfig.json +18 -0
  41. package/examples/semantic-composition/packages/responsive-explainer/README.md +16 -9
  42. package/examples/semantic-composition/packages/responsive-explainer/src/activation.ts +12 -12
  43. package/examples/semantic-composition/packages/responsive-explainer/src/render.ts +5 -5
  44. package/examples/semantic-composition/packages/sound-styles/README.md +36 -0
  45. package/examples/semantic-composition/packages/sound-styles/package.json +25 -0
  46. package/examples/semantic-composition/packages/sound-styles/src/activation.ts +53 -0
  47. package/examples/semantic-composition/packages/sound-styles/src/render.ts +14 -0
  48. package/examples/semantic-composition/packages/sound-styles/tsconfig.json +18 -0
  49. package/package.json +35 -15
  50. package/packages/audio-track/README.md +20 -13
  51. package/packages/audio-track/package.json +1 -1
  52. package/packages/audio-track/src/component.ts +4 -4
  53. package/packages/audio-track/src/fragment.ts +6 -5
  54. package/packages/audio-track/src/index.ts +1 -1
  55. package/packages/audio-track/src/manifest.ts +17 -16
  56. package/packages/audio-track/src/program.ts +21 -25
  57. package/packages/audio-track/src/surface.ts +19 -18
  58. package/packages/audio-track-studio/README.md +23 -0
  59. package/packages/audio-track-studio/src/index.ts +28 -17
  60. package/packages/author-kit/README.md +1 -1
  61. package/packages/background-removal/README.md +4 -7
  62. package/packages/browser-capture/package.json +1 -1
  63. package/packages/build-result/README.md +11 -0
  64. package/packages/build-result/src/decode.ts +2 -0
  65. package/packages/build-result/src/execution-log.ts +17 -0
  66. package/packages/build-result/src/index.ts +1 -0
  67. package/packages/build-result/src/store.ts +14 -1
  68. package/packages/build-result/src/types.ts +3 -0
  69. package/packages/build-result-s3/src/repository.ts +4 -0
  70. package/packages/caption/README.md +61 -73
  71. package/packages/caption/package.json +3 -2
  72. package/packages/caption/src/activation.ts +2 -2
  73. package/packages/caption/src/component.ts +20 -5
  74. package/packages/caption/src/display.ts +3 -18
  75. package/packages/caption/src/fragment.ts +3 -7
  76. package/packages/caption/src/index.ts +6 -5
  77. package/packages/caption/src/manifest.ts +29 -46
  78. package/packages/caption/src/style.ts +24 -135
  79. package/packages/caption/src/surface.ts +12 -92
  80. package/packages/caption/src/temporalize.ts +18 -53
  81. package/packages/caption/src/types.ts +8 -35
  82. package/packages/caption/src/visibility.ts +23 -0
  83. package/packages/caption-fine/README.md +21 -9
  84. package/packages/caption-fine/package.json +4 -2
  85. package/packages/caption-fine/src/component.ts +3 -3
  86. package/packages/caption-fine/src/fragment.ts +7 -19
  87. package/packages/caption-fine/src/index.ts +2 -0
  88. package/packages/caption-fine/src/manifest.ts +26 -17
  89. package/packages/caption-fine/src/recipe.ts +7 -0
  90. package/packages/caption-fine/src/render.ts +14 -13
  91. package/packages/caption-fine/src/schedule.ts +39 -35
  92. package/packages/caption-fine/src/style.ts +10 -9
  93. package/packages/caption-fine/src/surface.ts +62 -35
  94. package/packages/caption-fine/src/types.ts +2 -0
  95. package/packages/caption-fine-studio/README.md +24 -2
  96. package/packages/caption-fine-studio/package.json +3 -1
  97. package/packages/caption-fine-studio/src/activation.ts +3 -3
  98. package/packages/caption-fine-studio/src/index.ts +54 -42
  99. package/packages/cli/README.md +57 -4
  100. package/packages/cli/package.json +1 -0
  101. package/packages/cli/src/arguments.ts +25 -6
  102. package/packages/cli/src/build-planning.ts +3 -2
  103. package/packages/cli/src/command.ts +6 -0
  104. package/packages/cli/src/commands/environment.ts +28 -18
  105. package/packages/cli/src/commands/execution.ts +81 -26
  106. package/packages/cli/src/commands/results.ts +7 -11
  107. package/packages/cli/src/index.ts +2 -2
  108. package/packages/cli/src/machine-view.ts +3 -2
  109. package/packages/cli/src/main.ts +34 -42
  110. package/packages/cli/src/observation.ts +7 -1
  111. package/packages/cli/src/output.ts +65 -23
  112. package/packages/cli/src/view.ts +66 -19
  113. package/packages/comment-sticker/README.md +3 -3
  114. package/packages/comment-sticker/package.json +1 -1
  115. package/packages/comment-sticker/src/component.ts +4 -4
  116. package/packages/comment-sticker/src/fragment.ts +5 -4
  117. package/packages/comment-sticker/src/manifest.ts +7 -6
  118. package/packages/comment-sticker/src/program.ts +9 -9
  119. package/packages/comment-sticker/src/surface.ts +6 -7
  120. package/packages/composition/README.md +21 -0
  121. package/packages/composition/src/audio-presentation.ts +44 -0
  122. package/packages/composition/src/index.ts +3 -0
  123. package/packages/composition/src/schema.ts +8 -3
  124. package/packages/composition/src/track.ts +15 -1
  125. package/packages/credential-store-env/README.md +1 -1
  126. package/packages/deck-track/README.md +3 -3
  127. package/packages/deck-track/package.json +1 -1
  128. package/packages/deck-track/src/component.ts +5 -5
  129. package/packages/deck-track/src/fragment.ts +6 -5
  130. package/packages/deck-track/src/lower.ts +12 -12
  131. package/packages/deck-track/src/manifest.ts +8 -7
  132. package/packages/deck-track/src/program.ts +13 -16
  133. package/packages/deck-track/src/surface.ts +9 -10
  134. package/packages/driver-node/src/driver.ts +41 -3
  135. package/packages/elevenlabs-speech/README.md +27 -0
  136. package/packages/{provider-xiaomi-mimo → elevenlabs-speech}/package.json +5 -8
  137. package/packages/elevenlabs-speech/src/activation.ts +26 -0
  138. package/packages/elevenlabs-speech/src/fragment.ts +11 -0
  139. package/packages/elevenlabs-speech/src/index.ts +111 -0
  140. package/packages/elevenlabs-speech/src/surface.ts +167 -0
  141. package/packages/endpoint-kit/README.md +24 -0
  142. package/packages/endpoint-kit/src/index.ts +7 -1
  143. package/packages/film/README.md +12 -7
  144. package/packages/film/package.json +1 -1
  145. package/packages/film/src/component.ts +4 -4
  146. package/packages/film/src/fragment.ts +6 -5
  147. package/packages/film/src/manifest.ts +11 -10
  148. package/packages/film/src/program.ts +5 -5
  149. package/packages/film/src/recipe.ts +2 -1
  150. package/packages/film/src/surface.ts +10 -7
  151. package/packages/film-studio/package.json +1 -1
  152. package/packages/film-studio/src/index.ts +2 -2
  153. package/packages/fishaudio-speech/README.md +33 -0
  154. package/packages/fishaudio-speech/package.json +21 -0
  155. package/packages/fishaudio-speech/src/activation.ts +32 -0
  156. package/packages/fishaudio-speech/src/fragment.ts +11 -0
  157. package/packages/fishaudio-speech/src/index.ts +156 -0
  158. package/packages/fishaudio-speech/src/surface.ts +192 -0
  159. package/packages/generation/README.md +11 -1
  160. package/packages/generation/src/mapping.ts +28 -30
  161. package/packages/gpt-image/README.md +1 -2
  162. package/packages/grok-imagine/README.md +1 -2
  163. package/packages/hyperframes/README.md +7 -3
  164. package/packages/hyperframes/src/browser-program.ts +11 -2
  165. package/packages/hyperframes/src/document.ts +15 -2
  166. package/packages/interview-emoji-reveal/README.md +4 -4
  167. package/packages/interview-emoji-reveal/package.json +1 -1
  168. package/packages/interview-emoji-reveal/src/component.ts +4 -4
  169. package/packages/interview-emoji-reveal/src/fragment.ts +6 -5
  170. package/packages/interview-emoji-reveal/src/manifest.ts +9 -8
  171. package/packages/interview-emoji-reveal/src/program.ts +14 -14
  172. package/packages/interview-emoji-reveal/src/surface.ts +8 -9
  173. package/packages/media-execution/README.md +7 -3
  174. package/packages/media-execution/src/audio-presentation.ts +23 -0
  175. package/packages/media-execution/src/execute.ts +2 -0
  176. package/packages/media-pipeline/README.md +7 -3
  177. package/packages/media-pipeline/src/audio-plan.ts +4 -1
  178. package/packages/media-pipeline/src/component.ts +16 -2
  179. package/packages/media-pipeline/src/manifest.ts +3 -1
  180. package/packages/media-pipeline/src/types.ts +2 -1
  181. package/packages/media-track/README.md +14 -47
  182. package/packages/media-track/package.json +1 -1
  183. package/packages/media-track/preview/preview.svml +5 -5
  184. package/packages/media-track/src/author.ts +12 -6
  185. package/packages/media-track/src/component.ts +10 -16
  186. package/packages/media-track/src/fragment.ts +8 -7
  187. package/packages/media-track/src/index.ts +3 -1
  188. package/packages/media-track/src/lower.ts +7 -7
  189. package/packages/media-track/src/manifest.ts +16 -38
  190. package/packages/media-track/src/program.ts +62 -67
  191. package/packages/media-track/src/sampling.ts +6 -6
  192. package/packages/media-track/src/sequence.ts +8 -8
  193. package/packages/media-track/src/surface.ts +25 -43
  194. package/packages/media-track-studio/README.md +9 -0
  195. package/packages/media-track-studio/src/index.ts +16 -11
  196. package/packages/mimo-speech/README.md +1 -1
  197. package/packages/minimax-h3/README.md +1 -1
  198. package/packages/nano-banana/README.md +1 -1
  199. package/packages/narrative/README.md +23 -1
  200. package/packages/narrative/src/identity.ts +11 -0
  201. package/packages/narrative/src/index.ts +3 -0
  202. package/packages/narrative/src/schema.ts +28 -27
  203. package/packages/narrative/src/selection.ts +52 -0
  204. package/packages/narrative/src/types.ts +2 -0
  205. package/packages/package-loader-node/README.md +30 -0
  206. package/packages/package-loader-node/package.json +5 -2
  207. package/packages/package-loader-node/src/distribution-resolution.ts +10 -3
  208. package/packages/package-loader-node/src/index.ts +1 -0
  209. package/packages/package-loader-node/src/loader.ts +12 -15
  210. package/packages/package-loader-node/src/location.ts +27 -1
  211. package/packages/package-loader-node/src/module-scope.ts +183 -0
  212. package/packages/package-loader-node/src/types.ts +4 -0
  213. package/packages/performance/README.md +83 -0
  214. package/packages/performance/package.json +30 -0
  215. package/packages/performance/src/activation.ts +11 -0
  216. package/packages/performance/src/component.ts +46 -0
  217. package/packages/performance/src/index.ts +6 -0
  218. package/packages/performance/src/manifest.ts +53 -0
  219. package/packages/{media-track/src/performance.ts → performance/src/media.ts} +9 -10
  220. package/packages/performance/src/program.ts +51 -0
  221. package/packages/performance/src/style.ts +35 -0
  222. package/packages/performance/src/surface.ts +99 -0
  223. package/packages/performance-studio/README.md +25 -0
  224. package/packages/performance-studio/package.json +21 -0
  225. package/packages/performance-studio/src/activation.ts +6 -0
  226. package/packages/performance-studio/src/index.ts +84 -0
  227. package/packages/program-space/README.md +9 -18
  228. package/packages/program-space/src/activation.ts +1 -5
  229. package/packages/program-space/src/index.ts +2 -11
  230. package/packages/program-space/src/surface.ts +1 -20
  231. package/packages/project-context-node/README.md +20 -0
  232. package/packages/project-context-node/package.json +10 -0
  233. package/packages/project-context-node/src/index.ts +3 -0
  234. package/packages/{cli → project-context-node}/src/runtime-selection.ts +7 -2
  235. package/packages/provider-hyperframes-local/README.md +43 -15
  236. package/packages/provider-hyperframes-local/src/activation.ts +4 -3
  237. package/packages/provider-hyperframes-local/src/capture-process.ts +26 -4
  238. package/packages/provider-hyperframes-local/src/capture.ts +96 -26
  239. package/packages/provider-hyperframes-local/src/concurrency.ts +86 -0
  240. package/packages/provider-hyperframes-local/src/opaque-capture.ts +92 -0
  241. package/packages/provider-hyperframes-local/src/options.ts +2 -0
  242. package/packages/provider-hyperframes-local/src/program.ts +6 -3
  243. package/packages/provider-hyperframes-local/src/progress.ts +53 -0
  244. package/packages/provider-hyperframes-local/src/provider.ts +18 -5
  245. package/packages/provider-hyperframes-local/src/render.ts +48 -7
  246. package/packages/provider-hypihub/README.md +48 -17
  247. package/packages/provider-hypihub/package.json +2 -0
  248. package/packages/provider-hypihub/src/mapping.ts +31 -7
  249. package/packages/provider-hypihub/src/oauth.ts +6 -0
  250. package/packages/provider-hypihub/src/provider.ts +25 -13
  251. package/packages/provider-hypihub/src/routes.ts +1 -2
  252. package/packages/provider-hypihub/src/upload.ts +2 -0
  253. package/packages/provider-media-local/README.md +3 -4
  254. package/packages/provider-whisperx-local/src/program.ts +1 -0
  255. package/packages/provider-whisperx-local/src/provider.ts +3 -0
  256. package/packages/ranking/README.md +8 -6
  257. package/packages/ranking/package.json +1 -1
  258. package/packages/ranking/src/component.ts +6 -6
  259. package/packages/ranking/src/fragment.ts +11 -7
  260. package/packages/ranking/src/manifest.ts +21 -14
  261. package/packages/ranking/src/render.ts +22 -26
  262. package/packages/ranking/src/schedule.ts +16 -19
  263. package/packages/ranking/src/surface.ts +12 -13
  264. package/packages/ranking-studio/README.md +18 -0
  265. package/packages/ranking-studio/src/index.ts +61 -9
  266. package/packages/render-hyperframes/README.md +7 -7
  267. package/packages/render-hyperframes/package.json +1 -1
  268. package/packages/render-hyperframes/src/component.ts +11 -1
  269. package/packages/render-hyperframes/src/fragment.ts +7 -4
  270. package/packages/render-hyperframes/src/manifest.ts +4 -4
  271. package/packages/render-hyperframes/src/surface.ts +6 -6
  272. package/packages/runtime/README.md +8 -1
  273. package/packages/runtime/src/execution.ts +15 -4
  274. package/packages/runtime/src/index.ts +2 -1
  275. package/packages/runtime/src/log.ts +51 -0
  276. package/packages/runtime/src/types.ts +5 -8
  277. package/packages/runtime-host-node/README.md +30 -0
  278. package/packages/runtime-host-node/package.json +1 -0
  279. package/packages/runtime-host-node/src/index.ts +24 -9
  280. package/packages/runtime-host-node/src/packages.ts +47 -50
  281. package/packages/runtime-kit/README.md +5 -0
  282. package/packages/runtime-kit/src/index.ts +3 -1
  283. package/packages/runtime-local/README.md +109 -4
  284. package/packages/runtime-local/src/config.ts +202 -56
  285. package/packages/runtime-local/src/control.ts +9 -1
  286. package/packages/runtime-local/src/executor.ts +66 -0
  287. package/packages/runtime-local/src/host.ts +37 -17
  288. package/packages/runtime-local/src/log.ts +48 -0
  289. package/packages/runtime-local/src/programs.ts +2 -1
  290. package/packages/runtime-local/src/result-writer.ts +2 -0
  291. package/packages/runtime-local/src/runtime.ts +8 -6
  292. package/packages/runtime-local/src/supervisor.ts +142 -0
  293. package/packages/runtime-local/src/types.ts +9 -2
  294. package/packages/runtime-local/src/worker-process.ts +7 -24
  295. package/packages/runtime-local/src/worker.ts +55 -83
  296. package/packages/screen-overlay/README.md +3 -3
  297. package/packages/screen-overlay/package.json +1 -1
  298. package/packages/screen-overlay/src/component.ts +3 -3
  299. package/packages/screen-overlay/src/fragment.ts +5 -4
  300. package/packages/screen-overlay/src/manifest.ts +7 -6
  301. package/packages/screen-overlay/src/program.ts +9 -9
  302. package/packages/screen-overlay/src/surface.ts +6 -7
  303. package/packages/script/README.md +30 -5
  304. package/packages/script/src/manifest.ts +4 -3
  305. package/packages/script/src/narrative.ts +1 -0
  306. package/packages/script/src/parser.ts +45 -6
  307. package/packages/script/src/surface.ts +4 -3
  308. package/packages/script/src/types.ts +1 -1
  309. package/packages/script-studio/package.json +9 -3
  310. package/packages/script-studio/src/index.ts +2 -0
  311. package/packages/script-studio/src/projection.ts +105 -0
  312. package/packages/seedance/README.md +30 -1
  313. package/packages/seedance/src/index.ts +18 -7
  314. package/packages/seedance/src/surface.ts +17 -4
  315. package/packages/seedance-kits/README.md +7 -1
  316. package/packages/seedream/README.md +1 -1
  317. package/packages/sound/README.md +81 -0
  318. package/packages/sound/package.json +25 -0
  319. package/packages/sound/src/activation.ts +11 -0
  320. package/packages/sound/src/component.ts +28 -0
  321. package/packages/sound/src/index.ts +5 -0
  322. package/packages/sound/src/manifest.ts +47 -0
  323. package/packages/sound/src/program.ts +84 -0
  324. package/packages/sound/src/style.ts +34 -0
  325. package/packages/sound/src/surface.ts +90 -0
  326. package/packages/sound-studio/README.md +22 -0
  327. package/packages/sound-studio/package.json +20 -0
  328. package/packages/sound-studio/src/activation.ts +6 -0
  329. package/packages/sound-studio/src/index.ts +74 -0
  330. package/packages/speech/README.md +2 -2
  331. package/packages/speech-alignment/src/local.ts +8 -0
  332. package/packages/speech-alignment/src/locate.ts +1 -1
  333. package/packages/store-sqlite/README.md +7 -0
  334. package/packages/store-sqlite/src/store.ts +84 -83
  335. package/packages/studio/INSPECTOR.md +15 -2
  336. package/packages/studio/LOCALIZATION.md +98 -0
  337. package/packages/studio/README.md +101 -14
  338. package/packages/studio/locales/en.json +197 -0
  339. package/packages/studio/locales/zh-CN.json +191 -0
  340. package/packages/studio/package.json +8 -7
  341. package/packages/studio/src/companion-assembly.ts +1 -0
  342. package/packages/studio/src/domain.ts +1 -1
  343. package/packages/studio/src/fallback-companions.ts +3 -3
  344. package/packages/studio/src/feedback-server.ts +51 -0
  345. package/packages/studio/src/feedback-store.ts +66 -0
  346. package/packages/studio/src/feedback.ts +60 -0
  347. package/packages/studio/src/localization-node.ts +46 -0
  348. package/packages/studio/src/localization.ts +85 -0
  349. package/packages/studio/src/parameter-values.ts +43 -1
  350. package/packages/studio/src/parameters.ts +114 -24
  351. package/packages/studio/src/preview/render.ts +5 -1
  352. package/packages/studio/src/preview/runtime-shim.ts +49 -3
  353. package/packages/studio/src/programme.ts +14 -30
  354. package/packages/studio/src/server.ts +10 -6
  355. package/packages/studio/src/shared.ts +4 -2
  356. package/packages/studio/src/snapshot.ts +21 -132
  357. package/packages/studio/src/studio-preflight.ts +3 -3
  358. package/packages/studio/src/studio-registry.ts +50 -6
  359. package/packages/studio/src/style.css +223 -50
  360. package/packages/studio/src/ui/artifact-name.ts +8 -6
  361. package/packages/studio/src/ui/artifact-preview.ts +5 -4
  362. package/packages/studio/src/ui/code.ts +17 -16
  363. package/packages/studio/src/ui/comments.ts +234 -0
  364. package/packages/studio/src/ui/dropdown.ts +68 -0
  365. package/packages/studio/src/ui/i18n.ts +109 -0
  366. package/packages/studio/src/ui/icons.ts +6 -0
  367. package/packages/studio/src/ui/library.ts +76 -65
  368. package/packages/studio/src/ui/main.ts +223 -211
  369. package/packages/studio/src/ui/overlay.ts +12 -8
  370. package/packages/studio/src/ui/scrub-preview.ts +110 -0
  371. package/packages/studio/src/ui/stage.ts +93 -29
  372. package/packages/studio/src/ui/timeline.ts +190 -118
  373. package/packages/studio/start.ts +41 -22
  374. package/packages/studio-adapter/README.md +130 -11
  375. package/packages/studio-adapter/src/index.ts +100 -13
  376. package/packages/temporal/README.md +6 -6
  377. package/packages/temporal/package.json +1 -1
  378. package/packages/temporal/src/component.ts +5 -6
  379. package/packages/temporal/src/index.ts +8 -6
  380. package/packages/temporal/src/location.ts +11 -11
  381. package/packages/temporal/src/projection.ts +19 -19
  382. package/packages/temporal/src/rational.ts +4 -4
  383. package/packages/temporal-markup/EDITING.md +2 -2
  384. package/packages/temporal-markup/README.md +27 -11
  385. package/packages/temporal-markup/package.json +1 -1
  386. package/packages/temporal-markup/src/index.ts +20 -25
  387. package/packages/temporal-markup/src/space.ts +10 -41
  388. package/packages/timeline/README.md +31 -0
  389. package/packages/{semantic-track → timeline}/package.json +1 -1
  390. package/packages/timeline/src/activation.ts +8 -0
  391. package/packages/timeline/src/component.ts +24 -0
  392. package/packages/timeline/src/identity.ts +60 -0
  393. package/packages/timeline/src/index.ts +6 -0
  394. package/packages/{semantic-track → timeline}/src/location.ts +20 -20
  395. package/packages/timeline/src/manifest.ts +39 -0
  396. package/packages/{semantic-track → timeline}/src/projection.ts +14 -14
  397. package/packages/timeline/src/types.ts +24 -0
  398. package/packages/timeline-author/README.md +68 -0
  399. package/packages/{speech-track → timeline-author}/package.json +6 -4
  400. package/packages/timeline-author/src/activation.ts +22 -0
  401. package/packages/{speech-track → timeline-author}/src/component.ts +15 -13
  402. package/packages/{speech-track → timeline-author}/src/fragment.ts +14 -23
  403. package/packages/timeline-author/src/index.ts +7 -0
  404. package/packages/timeline-author/src/manifest.ts +78 -0
  405. package/packages/timeline-author/src/program.ts +107 -0
  406. package/packages/timeline-author/src/surface.ts +46 -0
  407. package/packages/timeline-author/src/types.ts +6 -0
  408. package/packages/typography-track/README.md +4 -4
  409. package/packages/typography-track/package.json +1 -1
  410. package/packages/typography-track/src/component.ts +4 -4
  411. package/packages/typography-track/src/fragment.ts +4 -3
  412. package/packages/typography-track/src/manifest.ts +11 -9
  413. package/packages/typography-track/src/program.ts +15 -15
  414. package/packages/typography-track/src/surface.ts +17 -18
  415. package/packages/video-cli/README.md +4 -1
  416. package/packages/video-cli/package.json +2 -1
  417. package/packages/video-cli/src/creation.ts +14 -4
  418. package/packages/video-cli/src/index.ts +1 -1
  419. package/packages/video-cli/src/studio-distribution.ts +2 -1
  420. package/packages/volcengine-matting/README.md +3 -3
  421. package/packages/whisperx/README.md +1 -1
  422. package/services/whisperx/README.md +14 -0
  423. package/services/whisperx/pyproject.toml +2 -0
  424. package/services/whisperx/uv.lock +20 -20
  425. package/packages/provider-hyperframes-aws-lambda/README.md +0 -30
  426. package/packages/provider-hyperframes-aws-lambda/package.json +0 -30
  427. package/packages/provider-hyperframes-aws-lambda/src/activation.ts +0 -97
  428. package/packages/provider-hyperframes-aws-lambda/src/client.ts +0 -114
  429. package/packages/provider-hyperframes-aws-lambda/src/index.ts +0 -21
  430. package/packages/provider-hyperframes-aws-lambda/src/provider.ts +0 -522
  431. package/packages/provider-kie/README.md +0 -134
  432. package/packages/provider-kie/package.json +0 -43
  433. package/packages/provider-kie/src/activation.ts +0 -71
  434. package/packages/provider-kie/src/index.ts +0 -10
  435. package/packages/provider-kie/src/mapping.ts +0 -182
  436. package/packages/provider-kie/src/provider.ts +0 -657
  437. package/packages/provider-kie/src/routes.ts +0 -150
  438. package/packages/provider-xiaomi-mimo/README.md +0 -32
  439. package/packages/provider-xiaomi-mimo/src/activation.ts +0 -57
  440. package/packages/provider-xiaomi-mimo/src/index.ts +0 -5
  441. package/packages/provider-xiaomi-mimo/src/provider.ts +0 -214
  442. package/packages/runtime/src/environment.ts +0 -6
  443. package/packages/semantic-track/README.md +0 -21
  444. package/packages/semantic-track/src/activation.ts +0 -8
  445. package/packages/semantic-track/src/component.ts +0 -24
  446. package/packages/semantic-track/src/identity.ts +0 -58
  447. package/packages/semantic-track/src/index.ts +0 -6
  448. package/packages/semantic-track/src/manifest.ts +0 -38
  449. package/packages/semantic-track/src/types.ts +0 -26
  450. package/packages/speech-track/README.md +0 -51
  451. package/packages/speech-track/src/activation.ts +0 -19
  452. package/packages/speech-track/src/index.ts +0 -7
  453. package/packages/speech-track/src/manifest.ts +0 -73
  454. package/packages/speech-track/src/program.ts +0 -64
  455. package/packages/speech-track/src/surface.ts +0 -35
  456. package/packages/speech-track/src/types.ts +0 -6
  457. package/packages/speech-track-studio/README.md +0 -3
  458. package/packages/speech-track-studio/package.json +0 -14
  459. package/packages/speech-track-studio/src/activation.ts +0 -7
  460. package/packages/speech-track-studio/src/index.ts +0 -40
  461. /package/packages/{cli → project-context-node}/src/project-context.ts +0 -0
  462. /package/packages/{speech-track → timeline-author}/preview/Track.png +0 -0
@@ -1,3 +1,4 @@
1
+ import { userText, uiAttribute, uiText, uiAttr } from "./i18n.js";
1
2
  import type {
2
3
  SemanticToken,
3
4
  StudioSnapshot,
@@ -89,13 +90,13 @@ export function createTimeline(store: Store): Timeline {
89
90
  element.innerHTML = `
90
91
  <div class="timeline-toolbar">
91
92
  <div class="timeline-tools">
92
- <button type="button" class="tool-button active" aria-label="Select" title="Select">${icon("select")}</button>
93
+ <button type="button" class="tool-button active" ${uiAttribute("aria-label", "timeline.select")} ${uiAttribute("title", "timeline.select")}>${icon("select")}</button>
93
94
  </div>
94
95
  <div class="timeline-time" data-timeline-time>00:00:00</div>
95
96
  <div class="timeline-view-actions">
96
- <button type="button" class="icon-button" data-zoom-out aria-label="Zoom out" title="Zoom out">${icon("minus")}</button>
97
- <button type="button" class="icon-button" data-zoom-fit aria-label="Fit timeline" title="Fit timeline">${icon("fit")}</button>
98
- <button type="button" class="icon-button" data-zoom-in aria-label="Zoom in" title="Zoom in">${icon("plus")}</button>
97
+ <button type="button" class="icon-button" data-zoom-out ${uiAttribute("aria-label", "timeline.zoom-out")} ${uiAttribute("title", "timeline.zoom-out")}>${icon("minus")}</button>
98
+ <button type="button" class="icon-button" data-zoom-fit ${uiAttribute("aria-label", "timeline.fit-timeline")} ${uiAttribute("title", "timeline.fit-timeline")}>${icon("fit")}</button>
99
+ <button type="button" class="icon-button" data-zoom-in ${uiAttribute("aria-label", "timeline.zoom-in")} ${uiAttribute("title", "timeline.zoom-in")}>${icon("plus")}</button>
99
100
  </div>
100
101
  </div>
101
102
  <div class="timeline-body" data-timeline-body>
@@ -138,8 +139,8 @@ export function createTimeline(store: Store): Timeline {
138
139
  remember: "hypit-studio.v4.timeline-label-width",
139
140
  });
140
141
  labelHandle.classList.add("timeline-label-handle");
141
- labelHandle.setAttribute("aria-label", "Resize timeline track labels");
142
- labelHandle.title = "Resize track labels";
142
+ uiAttr(labelHandle, "aria-label", "timeline.resize-timeline-track-labels");
143
+ uiAttr(labelHandle, "title", "timeline.resize-track-labels");
143
144
  body.insertBefore(labelHandle, lanes);
144
145
 
145
146
  let state: State | undefined;
@@ -147,11 +148,20 @@ export function createTimeline(store: Store): Timeline {
147
148
  let paintFrame = 0;
148
149
  let rebuildFrame = 0;
149
150
  const readableWordLabels = new Set<string>();
151
+ let selectedWord: string | undefined;
152
+ let overlapMenu: HTMLElement | undefined;
153
+ const closeOverlapMenu = () => { overlapMenu?.remove(); overlapMenu = undefined; };
154
+ element.addEventListener("pointerdown", event => {
155
+ if (!overlapMenu?.contains(event.target as Node)) closeOverlapMenu();
156
+ });
157
+ element.addEventListener("keydown", event => { if (event.key === "Escape") closeOverlapMenu(); });
158
+ body.addEventListener("scroll", closeOverlapMenu);
150
159
  let clipNodes: readonly {
151
160
  readonly node: HTMLElement;
152
161
  readonly start: number;
153
162
  readonly end: number;
154
163
  readonly id: string;
164
+ readonly selectionGroup?: string;
155
165
  }[] = [];
156
166
  let semanticNodes: readonly {
157
167
  readonly node: HTMLElement;
@@ -301,7 +311,7 @@ export function createTimeline(store: Store): Timeline {
301
311
  const from = place(preview.startFrame, state.snapshot.space.frameCount, zoom.window());
302
312
  const to = place(preview.endFrameExclusive, state.snapshot.space.frameCount, zoom.window());
303
313
  activeEdit.node.style.left = `${from * 100}%`;
304
- activeEdit.node.style.width = `max(2px, calc(${Math.max(0, to - from) * 100}% - ${itemMetrics.gapPx}px))`;
314
+ activeEdit.node.style.width = `max(2px, ${Math.max(0, to - from) * 100}%)`;
305
315
  }
306
316
  return;
307
317
  }
@@ -479,29 +489,34 @@ export function createTimeline(store: Store): Timeline {
479
489
  .sort((left, right) => (left.binding.lane.order ?? 0) - (right.binding.lane.order ?? 0));
480
490
 
481
491
  const buildSemanticLane = (snapshot: StudioSnapshot): void => {
482
- if (snapshot.semantic === undefined) {
492
+ if (snapshot.semantic === undefined || snapshot.semantic.segments.length === 0) {
483
493
  return;
484
494
  }
485
495
  const presentation = snapshot.semantic.presentation;
486
- // This is one semantic ruler group, not a regular Film lane. Its three
487
- // bands share the same inner inset as ordinary items, so the first pixel
488
- // of the semantic content aligns with the first pixel of the label card.
489
- const laneHeight = presentation.lane.heightPx;
490
- const bandHeight = Math.max(1, (laneHeight - itemMetrics.insetYPx * 2) / 3);
496
+ const bandHeight = Math.max(1, (presentation.lane.heightPx - itemMetrics.insetYPx * 2) / 3);
497
+ const bands = [
498
+ { kind: "segment", height: bandHeight },
499
+ ...(snapshot.semantic.tokens.length > 0 ? [{ kind: "word", height: bandHeight }] : []),
500
+ ...(snapshot.semantic.selections.length + snapshot.semantic.moments.length > 0
501
+ ? [{ kind: "intent", height: bandHeight }] : []),
502
+ ];
503
+ const laneHeight = bands.reduce((height, band) => height + band.height, itemMetrics.insetYPx * 2);
491
504
  const label = createTrackLabel(
492
- presentation.label ?? "Semantic",
505
+ presentation.label ?? "",
493
506
  presentation.tone,
494
507
  presentation.icon,
495
- `${snapshot.semantic.segments.length} take${snapshot.semantic.segments.length === 1 ? "" : "s"}`,
508
+ "",
496
509
  laneHeight,
497
510
  );
511
+ if (presentation.label === undefined) uiText(label.querySelector("strong")!, "inspector.timeline");
512
+ uiAttr(label, "title", "timeline.segment-count", { count: snapshot.semantic.segments.length });
498
513
  label.classList.add("track-label-semantic");
514
+ label.style.height = `calc(var(--timeline-ruler-height) + ${laneHeight}px)`;
499
515
  labels.append(label);
500
516
 
501
517
  const lane = document.createElement("div");
502
518
  lane.className = `lane semantic-lane track-tone-${presentation.tone}`;
503
519
  lane.style.height = `${laneHeight}px`;
504
- lane.style.setProperty("--semantic-band-height", `${bandHeight}px`);
505
520
  const laneWidth = lanes.clientWidth;
506
521
  const nextSemanticNodes: {
507
522
  node: HTMLElement;
@@ -511,12 +526,15 @@ export function createTimeline(store: Store): Timeline {
511
526
  kind: "segment" | "word" | "selection" | "moment";
512
527
  }[] = [];
513
528
 
514
- const bands = ["segment", "word", "intent"] as const;
515
- for (const [index, kind] of bands.entries()) {
529
+ let bandTop = itemMetrics.insetYPx;
530
+ for (const { kind, height } of bands) {
516
531
  const band = document.createElement("div");
517
532
  band.className = `semantic-band semantic-band-${kind}`;
518
- band.style.top = `${itemMetrics.insetYPx + index * bandHeight}px`;
533
+ band.style.top = `${bandTop}px`;
534
+ band.style.setProperty("--semantic-band-height", `${height}px`);
535
+ uiAttr(band, "aria-label", kind === "intent" ? "timeline.selections-and-moments" : kind === "word" ? "timeline.words" : "timeline.segments");
519
536
  lane.append(band);
537
+ bandTop += height;
520
538
  }
521
539
  const segmentBand = lane.querySelector<HTMLElement>(".semantic-band-segment")!;
522
540
  const wordBand = lane.querySelector<HTMLElement>(".semantic-band-word")!;
@@ -531,11 +549,11 @@ export function createTimeline(store: Store): Timeline {
531
549
  node.className = "semantic-cell semantic-segment";
532
550
  node.tabIndex = 0;
533
551
  node.setAttribute("role", "button");
534
- node.setAttribute("aria-label", `Segment ${segment.id}`);
552
+ uiAttr(node, "aria-label", "timeline.segment-name", { name: segment.id });
535
553
  node.dataset.semanticSegment = segment.id;
536
554
  node.style.left = `${from * 100}%`;
537
555
  const segmentWidth = Math.max(0, to - from) * 100;
538
- node.style.width = `max(2px, calc(${segmentWidth}% - ${itemMetrics.gapPx}px))`;
556
+ node.style.width = `max(2px, ${segmentWidth}%)`;
539
557
  node.title = segment.id;
540
558
  const segmentLabel = document.createElement("span");
541
559
  segmentLabel.className = "semantic-segment-label";
@@ -575,12 +593,12 @@ export function createTimeline(store: Store): Timeline {
575
593
  word.setAttribute("aria-label", token.text);
576
594
  word.style.left = `${wordFrom * 100}%`;
577
595
  const wordWidth = Math.max(0, wordTo - wordFrom);
578
- word.style.width = `max(1px, calc(${wordWidth * 100}% - ${itemMetrics.gapPx}px))`;
596
+ word.style.width = `max(1px, ${wordWidth * 100}%)`;
579
597
  word.title = token.text;
580
598
  const text = document.createElement("span");
581
599
  text.className = "semantic-word-label";
582
600
  text.textContent = token.text;
583
- const wordWidthPx = Math.max(1, wordWidth * laneWidth - itemMetrics.gapPx);
601
+ const wordWidthPx = Math.max(1, wordWidth * laneWidth);
584
602
  const textWidthPx = measuredText(token.text);
585
603
  const contentWidthPx = Math.max(0, wordWidthPx - wordLabelPaddingPx * 2);
586
604
  const wasReadable = readableWordLabels.has(token.id);
@@ -596,6 +614,8 @@ export function createTimeline(store: Store): Timeline {
596
614
  word.append(wordContent);
597
615
  word.addEventListener("click", (event) => {
598
616
  event.stopPropagation();
617
+ store.clearSelection();
618
+ selectedWord = token.id;
599
619
  store.seek(token.startFrame, "timeline");
600
620
  });
601
621
  nextSemanticNodes.push({ node: word, id: token.id, start: token.startFrame, end: token.endFrameExclusive, kind: "word" });
@@ -609,9 +629,9 @@ export function createTimeline(store: Store): Timeline {
609
629
  node.type = "button";
610
630
  node.className = "semantic-cell semantic-selection";
611
631
  node.tabIndex = 0;
612
- node.setAttribute("aria-label", `Selection ${selection.id}`);
632
+ uiAttr(node, "aria-label", "timeline.selection-name", { name: selection.id });
613
633
  node.style.left = `${from * 100}%`;
614
- node.style.width = `max(2px, calc(${Math.max(0, to - from) * 100}% - ${itemMetrics.gapPx}px))`;
634
+ node.style.width = `max(2px, ${Math.max(0, to - from) * 100}%)`;
615
635
  node.title = selection.id;
616
636
  const selectionLabel = document.createElement("span");
617
637
  selectionLabel.className = "semantic-selection-label";
@@ -635,7 +655,7 @@ export function createTimeline(store: Store): Timeline {
635
655
  node.type = "button";
636
656
  node.className = "semantic-moment";
637
657
  node.tabIndex = 0;
638
- node.setAttribute("aria-label", `Moment ${moment.id}`);
658
+ uiAttr(node, "aria-label", "timeline.moment-name", { name: moment.id });
639
659
  node.style.left = `${at * 100}%`;
640
660
  node.title = moment.id;
641
661
  node.addEventListener("click", (event) => {
@@ -645,6 +665,33 @@ export function createTimeline(store: Store): Timeline {
645
665
  intentBand.append(node);
646
666
  nextSemanticNodes.push({ node, id: moment.id, start: moment.frame, end: moment.frame + 1, kind: "moment" });
647
667
  }
668
+ lane.addEventListener("contextmenu", event => {
669
+ const hits = nextSemanticNodes.filter(({ node }) => {
670
+ const rect = node.getBoundingClientRect();
671
+ return event.clientX >= rect.left && event.clientX < rect.right
672
+ && event.clientY >= rect.top && event.clientY < rect.bottom;
673
+ });
674
+ if (hits.length < 2) return;
675
+ event.preventDefault();
676
+ closeOverlapMenu();
677
+ const menu = document.createElement("div");
678
+ menu.className = "timeline-overlap-menu";
679
+ menu.setAttribute("role", "menu");
680
+ uiAttr(menu, "aria-label", "timeline.overlapping-timeline-objects");
681
+ for (const hit of [...hits].reverse()) {
682
+ const option = document.createElement("button");
683
+ option.type = "button";
684
+ option.setAttribute("role", "menuitem");
685
+ option.textContent = hit.node.getAttribute("aria-label") ?? hit.id;
686
+ option.addEventListener("click", () => { closeOverlapMenu(); hit.node.click(); });
687
+ menu.append(option);
688
+ }
689
+ element.append(menu);
690
+ menu.style.left = `${Math.max(0, Math.min(event.clientX, window.innerWidth - menu.offsetWidth - 8))}px`;
691
+ menu.style.top = `${Math.max(0, Math.min(event.clientY, window.innerHeight - menu.offsetHeight - 8))}px`;
692
+ overlapMenu = menu;
693
+ menu.querySelector("button")?.focus();
694
+ });
648
695
  rows.append(lane);
649
696
  semanticNodes = nextSemanticNodes;
650
697
  };
@@ -652,128 +699,149 @@ export function createTimeline(store: Store): Timeline {
652
699
  const buildTrack = (
653
700
  snapshot: StudioSnapshot,
654
701
  track: StudioSnapshot["tracks"][number],
655
- nextClipNodes: { node: HTMLElement; start: number; end: number; id: string }[],
702
+ nextClipNodes: { node: HTMLElement; start: number; end: number; id: string; selectionGroup?: string }[],
656
703
  attached = false,
657
704
  ): void => {
705
+ const trackBands = track.binding.bands ?? [];
706
+ const banded = trackBands.length > 0;
707
+ const layout = [
708
+ ...trackBands.filter(band => band.placement === "before"),
709
+ { id: undefined, heightPx: track.binding.lane.heightPx, display: "content" as const, tone: track.binding.tone },
710
+ ...trackBands.filter(band => band.placement === "after"),
711
+ ];
712
+ const totalHeight = layout.reduce((sum, band) => sum + band.heightPx, 0)
713
+ + (banded ? 2 * itemMetrics.insetYPx : 0);
658
714
  const tone = track.binding.tone;
659
- const laneHeight = track.binding.lane.heightPx;
660
715
  const displayedItems = track.clips.length;
661
716
  const label = createTrackLabel(
662
717
  displayTrackName(track),
663
718
  tone,
664
719
  track.binding.icon,
665
720
  `${displayedItems} item${displayedItems === 1 ? "" : "s"}`,
666
- laneHeight,
721
+ totalHeight,
667
722
  attached,
668
723
  );
669
724
  label.classList.add(`track-facet-${track.binding.facet}`);
670
725
  labels.append(label);
671
726
 
672
- const lane = document.createElement("div");
673
- lane.className = `lane track-tone-${tone} track-facet-${track.binding.facet}${attached ? " lane-attached" : ""}`;
674
- lane.style.height = `${laneHeight}px`;
675
- lane.style.setProperty("--lane-height", `${laneHeight}px`);
676
- const laneWidth = lanes.clientWidth;
727
+ const trackBody = document.createElement("div");
728
+ trackBody.className = banded ? "timeline-track timeline-track-banded" : "timeline-track";
729
+ trackBody.dataset.track = track.id;
730
+ trackBody.style.height = `${totalHeight}px`;
677
731
  const materialMounts: {
678
732
  readonly target: HTMLElement;
679
733
  readonly preview: Extract<StudioSnapshot["tracks"][number]["clips"][number]["display"]["layers"][number], { readonly kind: "preview" }>["preview"];
680
734
  }[] = [];
681
- // Stable order preserves Companion projection order when stack levels tie.
682
- for (const clip of [...track.clips].sort((a, b) => a.stackOrder - b.stackOrder)) {
683
- const from = place(clip.startFrame, snapshot.space.frameCount, zoom.window());
684
- const to = place(clip.endFrameExclusive, snapshot.space.frameCount, zoom.window());
685
- if (to <= 0 || from >= 1) continue;
686
- const node = document.createElement("button");
687
- node.type = "button";
688
- node.className = `clip clip-tone-${tone} clip-facet-${track.binding.facet} clip-chrome-${clip.presentation.chrome}`;
689
- node.classList.toggle("clip-editable", clip.editHandles.some((handle) => handle.enabled));
690
- node.dataset.clip = clip.id;
691
- node.setAttribute("aria-label", clip.display.title);
692
- node.style.left = `${from * 100}%`;
693
- node.style.width = `max(2px, calc(${Math.max(0, to - from) * 100}% - ${itemMetrics.gapPx}px))`;
694
- const visibleWidthPx = visibleItemWidth(from, to, laneWidth);
695
- node.classList.toggle("clip-preview-wide", visibleWidthPx >= 92);
696
- node.title = `${clip.display.title} · ${clip.startFrame}-${clip.endFrameExclusive}f`;
697
- node.innerHTML = `<span class="clip-head"><span class="clip-name"></span><span class="clip-meta"></span></span><span class="clip-body"><span class="clip-layers" aria-hidden="true"></span><span class="clip-phases"></span></span><span class="clip-selection" aria-hidden="true"></span>`;
698
- const layers = node.querySelector<HTMLElement>(".clip-layers")!;
699
- clip.display.layers.forEach((layer, index) => {
700
- const layerNode = document.createElement("span");
701
- layerNode.className = `clip-layer clip-layer-${layer.kind} clip-layer-role-${layer.role}`;
702
- layerNode.style.zIndex = String(index + 1);
703
- if (layer.kind === "text") {
704
- layerNode.textContent = layer.text;
705
- } else {
706
- layerNode.classList.add(`clip-layer-layout-${layer.layout}`);
707
- materialMounts.push({ target: layerNode, preview: layer.preview });
735
+ for (const band of layout) {
736
+ const tone = band.tone ?? track.binding.tone;
737
+ const laneHeight = band.heightPx;
738
+ const lane = document.createElement("div");
739
+ lane.className = `lane track-tone-${tone} track-facet-${track.binding.facet}${attached ? " lane-attached" : ""}`;
740
+ lane.style.height = `${laneHeight}px`;
741
+ if (banded) lane.classList.add("track-band", `track-band-${band.display}`);
742
+ if (band.id !== undefined) lane.dataset.band = band.id;
743
+ lane.style.setProperty("--lane-height", `${laneHeight}px`);
744
+ const laneWidth = lanes.clientWidth;
745
+ // Stable order preserves Companion projection order when stack levels tie.
746
+ for (const clip of track.clips.filter(clip => clip.band === band.id).sort((a, b) => a.stackOrder - b.stackOrder)) {
747
+ const from = place(clip.startFrame, snapshot.space.frameCount, zoom.window());
748
+ const to = place(clip.endFrameExclusive, snapshot.space.frameCount, zoom.window());
749
+ if (to <= 0 || from >= 1) continue;
750
+ const node = document.createElement("button");
751
+ node.type = "button";
752
+ node.className = `clip clip-tone-${tone} clip-facet-${track.binding.facet} clip-chrome-${clip.presentation.chrome}`;
753
+ node.classList.toggle("clip-editable", clip.editHandles.some((handle) => handle.enabled));
754
+ node.dataset.clip = clip.id;
755
+ node.setAttribute("aria-label", clip.display.title);
756
+ node.style.left = `${from * 100}%`;
757
+ node.style.width = `max(2px, ${Math.max(0, to - from) * 100}%)`;
758
+ const visibleWidthPx = visibleItemWidth(from, to, laneWidth);
759
+ node.classList.toggle("clip-preview-wide", visibleWidthPx >= 92);
760
+ node.title = `${clip.display.title} · ${clip.startFrame}-${clip.endFrameExclusive}f`;
761
+ node.innerHTML = `<span class="clip-head"><span class="clip-name"></span><span class="clip-meta"></span></span><span class="clip-body"><span class="clip-layers" aria-hidden="true"></span><span class="clip-phases"></span></span><span class="clip-boundary" aria-hidden="true"></span><span class="clip-selection" aria-hidden="true"></span>`;
762
+ const layers = node.querySelector<HTMLElement>(".clip-layers")!;
763
+ clip.display.layers.forEach((layer, index) => {
764
+ const layerNode = document.createElement("span");
765
+ layerNode.className = `clip-layer clip-layer-${layer.kind} clip-layer-role-${layer.role}`;
766
+ layerNode.style.zIndex = String(index + 1);
767
+ if (layer.kind === "text") {
768
+ layerNode.textContent = layer.text;
769
+ } else {
770
+ layerNode.classList.add(`clip-layer-layout-${layer.layout}`);
771
+ materialMounts.push({ target: layerNode, preview: layer.preview });
772
+ }
773
+ layers.append(layerNode);
774
+ });
775
+ const phaseLayer = node.querySelector<HTMLElement>(".clip-phases")!;
776
+ for (const phase of clip.temporal?.phases ?? []) {
777
+ if (phase.endFrameExclusive <= clip.startFrame || phase.startFrame >= clip.endFrameExclusive) continue;
778
+ const phaseNode = document.createElement("span");
779
+ phaseNode.className = `clip-phase clip-phase-${phase.role}`;
780
+ phaseNode.style.left = `${(phase.startFrame - clip.startFrame) / Math.max(1, clip.endFrameExclusive - clip.startFrame) * 100}%`;
781
+ phaseNode.style.width = `${(phase.endFrameExclusive - phase.startFrame) / Math.max(1, clip.endFrameExclusive - clip.startFrame) * 100}%`;
782
+ phaseLayer.append(phaseNode);
708
783
  }
709
- layers.append(layerNode);
710
- });
711
- const phaseLayer = node.querySelector<HTMLElement>(".clip-phases")!;
712
- for (const phase of clip.temporal?.phases ?? []) {
713
- if (phase.endFrameExclusive <= clip.startFrame || phase.startFrame >= clip.endFrameExclusive) continue;
714
- const phaseNode = document.createElement("span");
715
- phaseNode.className = `clip-phase clip-phase-${phase.role}`;
716
- phaseNode.style.left = `${(phase.startFrame - clip.startFrame) / Math.max(1, clip.endFrameExclusive - clip.startFrame) * 100}%`;
717
- phaseNode.style.width = `${(phase.endFrameExclusive - phase.startFrame) / Math.max(1, clip.endFrameExclusive - clip.startFrame) * 100}%`;
718
- phaseLayer.append(phaseNode);
719
- }
720
- const metaText = clip.presentation.chrome === "point"
721
- ? `${(clip.startFrame / fps(snapshot)).toFixed(2)}s`
722
- : `${((clip.endFrameExclusive - clip.startFrame) / fps(snapshot)).toFixed(2)}s`;
723
- const headerLabel = node.querySelector<HTMLElement>(".clip-name")!;
724
- node.querySelector(".clip-meta")!.textContent = metaText;
725
- headerLabel.textContent = clip.display.title;
726
- node.addEventListener("pointerdown", (event) => {
727
- const rect = node.getBoundingClientRect();
728
- const edge = Math.min(8, Math.max(4, rect.width / 3));
729
- const nearStart = event.clientX - rect.left <= edge;
730
- const nearEnd = rect.right - event.clientX <= edge;
731
- const handle = clip.editHandles.find((candidate) =>
732
- candidate.enabled
733
- && ((candidate.gesture === "trim-start" && nearStart)
734
- || (candidate.gesture === "trim-end" && nearEnd)
735
- || (candidate.gesture === "move" && !nearStart && !nearEnd)));
736
- if (handle !== undefined
737
- && (handle.gesture === "move" || handle.gesture === "trim-start" || handle.gesture === "trim-end")) {
738
- event.stopPropagation();
739
- const pointerFrame = handle.coordinate === "semantic-anchor"
740
- ? rawFrameAt(event.clientX)
741
- : frameAt(event.clientX);
742
- activeEdit = {
743
- clip,
744
- handle,
745
- startFrame: pointerFrame,
746
- pointerId: event.pointerId,
747
- node,
748
- originalLeft: node.style.left,
749
- originalWidth: node.style.width,
750
- };
751
- node.classList.add("editing");
752
- try { lanes.setPointerCapture(event.pointerId); } catch { /* local pointer */ }
784
+ const metaText = clip.presentation.chrome === "point"
785
+ ? `${(clip.startFrame / fps(snapshot)).toFixed(2)}s`
786
+ : `${((clip.endFrameExclusive - clip.startFrame) / fps(snapshot)).toFixed(2)}s`;
787
+ const headerLabel = node.querySelector<HTMLElement>(".clip-name")!;
788
+ node.querySelector(".clip-meta")!.textContent = metaText;
789
+ headerLabel.textContent = clip.display.title;
790
+ node.addEventListener("pointerdown", (event) => {
791
+ const rect = node.getBoundingClientRect();
792
+ const edge = Math.min(8, Math.max(4, rect.width / 3));
793
+ const nearStart = event.clientX - rect.left <= edge;
794
+ const nearEnd = rect.right - event.clientX <= edge;
795
+ const handle = clip.editHandles.find((candidate) =>
796
+ candidate.enabled
797
+ && ((candidate.gesture === "trim-start" && nearStart)
798
+ || (candidate.gesture === "trim-end" && nearEnd)
799
+ || (candidate.gesture === "move" && !nearStart && !nearEnd)));
800
+ if (handle !== undefined
801
+ && (handle.gesture === "move" || handle.gesture === "trim-start" || handle.gesture === "trim-end")) {
802
+ event.stopPropagation();
803
+ const pointerFrame = handle.coordinate === "semantic-anchor"
804
+ ? rawFrameAt(event.clientX)
805
+ : frameAt(event.clientX);
806
+ activeEdit = {
807
+ clip,
808
+ handle,
809
+ startFrame: pointerFrame,
810
+ pointerId: event.pointerId,
811
+ node,
812
+ originalLeft: node.style.left,
813
+ originalWidth: node.style.width,
814
+ };
815
+ node.classList.add("editing");
816
+ try { lanes.setPointerCapture(event.pointerId); } catch { /* local pointer */ }
817
+ store.select(clip.id, "timeline");
818
+ return;
819
+ }
753
820
  store.select(clip.id, "timeline");
754
- return;
755
- }
756
- store.select(clip.id, "timeline");
757
- });
758
- node.addEventListener("dblclick", () => store.seek(clip.startFrame, "timeline"));
759
- nextClipNodes.push({ node, start: clip.startFrame, end: clip.endFrameExclusive, id: clip.id });
760
- lane.append(node);
821
+ });
822
+ node.addEventListener("dblclick", () => store.seek(clip.startFrame, "timeline"));
823
+ nextClipNodes.push({ node, start: clip.startFrame, end: clip.endFrameExclusive, id: clip.id, ...(clip.selectionGroup === undefined ? {} : { selectionGroup: clip.selectionGroup }) });
824
+ lane.append(node);
825
+ }
826
+ trackBody.append(lane);
761
827
  }
762
- rows.append(lane);
828
+ rows.append(trackBody);
829
+ // Cached storyboards render synchronously and need connected, measurable targets.
763
830
  for (const item of materialMounts) mountMaterialPreview(item.target, item.preview);
764
831
  };
765
832
 
766
833
  const build = (snapshot: StudioSnapshot): void => {
834
+ closeOverlapMenu();
767
835
  const scrollTop = body.scrollTop;
768
836
  labels.replaceChildren();
769
837
  rows.replaceChildren();
770
838
  semanticNodes = [];
771
839
  const corner = document.createElement("div");
772
840
  corner.className = "label-corner";
773
- corner.textContent = "";
774
- labels.append(corner);
841
+ userText(corner, "");
842
+ if (snapshot.semantic === undefined || snapshot.semantic.segments.length === 0) labels.append(corner);
775
843
  buildSemanticLane(snapshot);
776
- const nextClipNodes: { node: HTMLElement; start: number; end: number; id: string }[] = [];
844
+ const nextClipNodes: { node: HTMLElement; start: number; end: number; id: string; selectionGroup?: string }[] = [];
777
845
  for (const track of snapshot.tracks) {
778
846
  const attachedTo = track.binding.lane.attachedTo;
779
847
  if (attachedTo !== undefined) continue;
@@ -804,8 +872,10 @@ export function createTimeline(store: Store): Timeline {
804
872
  playhead.classList.toggle("outside", position < 0 || position > lanes.clientWidth);
805
873
  playheadGrip.classList.toggle("outside", position < 0 || position > lanes.clientWidth);
806
874
  timelineTime.textContent = frameTimecode(snapshot, head.frame);
875
+ const chosen = selection.kind === "clip" ? store.clip(selection.clipId) : undefined;
807
876
  for (const item of clipNodes) {
808
- const selected = selection.kind === "clip" && selection.clipId === item.id;
877
+ const selected = chosen !== undefined && (chosen.id === item.id
878
+ || (chosen.selectionGroup !== undefined && chosen.selectionGroup === item.selectionGroup));
809
879
  item.node.classList.toggle("selected", selected);
810
880
  item.node.setAttribute("aria-pressed", String(selected));
811
881
  item.node.classList.toggle("live", head.frame >= item.start && head.frame < item.end);
@@ -815,7 +885,8 @@ export function createTimeline(store: Store): Timeline {
815
885
  (item.kind === "segment" || item.kind === "selection")
816
886
  && head.frame >= item.start && head.frame < item.end);
817
887
  item.node.classList.toggle("current", item.kind === "word" && head.frame >= item.start && head.frame < item.end);
818
- const selected = (item.kind === "segment"
888
+ const selected = (item.kind === "word" && selectedWord === item.id && selection.kind === "none")
889
+ || (item.kind === "segment"
819
890
  && selection.kind === "semantic-segment" && selection.segmentId === item.id)
820
891
  || (item.kind === "selection"
821
892
  && selection.kind === "semantic-selection" && selection.selectionId === item.id)
@@ -862,6 +933,7 @@ export function createTimeline(store: Store): Timeline {
862
933
  zoom.subscribe(scheduleBuild);
863
934
  store.subscribe((value) => {
864
935
  state = value;
936
+ if (value.selection.kind !== "none") selectedWord = undefined;
865
937
  if (value.snapshot.revision !== built) {
866
938
  built = value.snapshot.revision;
867
939
  build(value.snapshot);
@@ -10,6 +10,14 @@ Open a Run in the browser to inspect its composition, Sources and Results.
10
10
 
11
11
  hypit studio --run <build.svrun> [--runtime <hypit.runtime.json>]
12
12
  [--port <number>] [--workspace <directory>] [--package-root <directory>]
13
+ [--locale-pack <./language.json | installed-package/language.json>]...
14
+
15
+ hypit studio --check-locale <./language.json | installed-package/language.json>
16
+ [--package-root <directory>]
17
+
18
+ Language packs are explicit JSON data. Relative files use the current directory;
19
+ package exports resolve from --package-root (the project by default).
20
+ --check-locale lists missing translations and unknown IDs without opening a Run.
13
21
 
14
22
  Relative command-line paths start at the current directory; --workspace selects
15
23
  the project, without rebasing those paths. Otherwise the nearest package.json
@@ -24,9 +32,9 @@ function invalidArguments(message: string): never {
24
32
  throw new Error(`${message}. See hypit studio --help.`);
25
33
  }
26
34
 
27
- function argumentsByName(argv: readonly string[]): ReadonlyMap<string, string> {
28
- const accepted = new Set(["run", "runtime", "port", "workspace", "package-root"]);
29
- const result = new Map<string, string>();
35
+ function argumentsByName(argv: readonly string[]): ReadonlyMap<string, readonly string[]> {
36
+ const accepted = new Set(["run", "runtime", "port", "workspace", "package-root", "locale-pack", "check-locale"]);
37
+ const result = new Map<string, string[]>();
30
38
  for (let index = 0; index < argv.length; index += 2) {
31
39
  const flag = argv[index];
32
40
  const value = argv[index + 1];
@@ -35,7 +43,7 @@ function argumentsByName(argv: readonly string[]): ReadonlyMap<string, string> {
35
43
  }
36
44
  const name = flag.slice(2);
37
45
  if (!accepted.has(name)) invalidArguments(`Unknown option --${name}`);
38
- result.set(name, value);
46
+ result.set(name, [...result.get(name) ?? [], value]);
39
47
  }
40
48
  return result;
41
49
  }
@@ -47,21 +55,12 @@ export async function runStudio(argv: readonly string[], io: Pick<CliIo, "write"
47
55
  }
48
56
  const values = argumentsByName(argv[0] === "--" ? argv.slice(1) : argv);
49
57
  const invokedFrom = process.env.INIT_CWD ?? process.cwd();
50
- const runArgument = values.get("run");
51
- if (runArgument === undefined || runArgument.trim().length === 0) invalidArguments("Missing --run");
52
- const { createServer } = await import("vite");
53
- const { findRuntimeProfile, resolveProjectRoot } = await import("@hypit/cli");
54
- const { resolveDistributionPackageImport } = await import("@hypit/package-loader-node");
55
- const { videoCliDistribution, videoStudioCompanionPackages } = await import("@hypit/video-cli");
56
- const { openStudioBuildLibrary } = await import("./src/build-library.js");
57
- const { loadStudioCompanionRegistry } = await import("./src/companion-assembly.js");
58
- const { loadStudioDomain } = await import("./src/domain.js");
59
- const { loadStudioRun } = await import("./src/run.js");
60
- const { studioPlugin } = await import("./src/server.js");
61
- const { inspectStudioRun } = await import("./src/studio-preflight.js");
62
- const runPath = resolve(invokedFrom, runArgument);
63
- const packageRootArgument = values.get("package-root");
64
- const workspaceArgument = values.get("workspace");
58
+ const runArgument = values.get("run")?.at(-1);
59
+
60
+ const { findRuntimeProfile, resolveProjectRoot } = await import("@hypit/project-context-node");
61
+
62
+ const packageRootArgument = values.get("package-root")?.at(-1);
63
+ const workspaceArgument = values.get("workspace")?.at(-1);
65
64
  const requestedWorkspaceRoot = workspaceArgument === undefined
66
65
  ? undefined
67
66
  : resolve(invokedFrom, workspaceArgument);
@@ -72,7 +71,26 @@ export async function runStudio(argv: readonly string[], io: Pick<CliIo, "write"
72
71
  const packageRoot = packageRootArgument === undefined
73
72
  ? workspaceRoot
74
73
  : resolve(invokedFrom, packageRootArgument);
75
- const runtimeArgument = values.get("runtime");
74
+ const { describeLanguagePack, loadLanguagePack, studioLanguages, studioLocalizationPlugin } = await import("./src/localization-node.js");
75
+ const checkLocale = values.get("check-locale")?.at(-1);
76
+ if (checkLocale !== undefined) {
77
+ io.write(describeLanguagePack(await loadLanguagePack(checkLocale, invokedFrom, packageRoot)) + "\n");
78
+ return;
79
+ }
80
+ if (runArgument === undefined || runArgument.trim().length === 0) invalidArguments("Missing --run");
81
+ const runPath = resolve(invokedFrom, runArgument);
82
+ const { createServer } = await import("vite");
83
+ const { resolveDistributionPackageImport } = await import("@hypit/package-loader-node");
84
+ const { videoCliDistribution, videoStudioCompanionPackages } = await import("@hypit/video-cli");
85
+ const { openStudioBuildLibrary } = await import("./src/build-library.js");
86
+ const { loadStudioCompanionRegistry } = await import("./src/companion-assembly.js");
87
+ const { loadStudioDomain } = await import("./src/domain.js");
88
+ const { loadStudioRun } = await import("./src/run.js");
89
+ const { studioPlugin } = await import("./src/server.js");
90
+ const { studioFeedbackPlugin } = await import("./src/feedback-server.js");
91
+ const { inspectStudioRun } = await import("./src/studio-preflight.js");
92
+ const languages = await studioLanguages(values.get("locale-pack") ?? [], invokedFrom, packageRoot);
93
+ const runtimeArgument = values.get("runtime")?.at(-1);
76
94
  const selectedRuntime = runtimeArgument === undefined
77
95
  ? await findRuntimeProfile(workspaceRoot)
78
96
  : undefined;
@@ -88,7 +106,7 @@ export async function runStudio(argv: readonly string[], io: Pick<CliIo, "write"
88
106
  ...(packageRoot === workspaceRoot ? [] : [` Package root ${packageRoot}`]),
89
107
  "",
90
108
  ].join("\n"));
91
- const port = Number(values.get("port") ?? "5179");
109
+ const port = Number(values.get("port")?.at(-1) ?? "5179");
92
110
  if (!Number.isSafeInteger(port) || port <= 0) invalidArguments("--port must be a positive integer");
93
111
 
94
112
  const distributionPackageRoot = videoCliDistribution.packageRoot ?? resolve(here, "../..");
@@ -136,7 +154,7 @@ export async function runStudio(argv: readonly string[], io: Pick<CliIo, "write"
136
154
  // available for Source and material previews.
137
155
  fs: { allow: [workspaceRoot, packageRoot, distributionPackageRoot, here] },
138
156
  },
139
- plugins: [distributionImports, studioPlugin({
157
+ plugins: [distributionImports, studioLocalizationPlugin(languages), studioFeedbackPlugin(workspaceRoot, runPath), studioPlugin({
140
158
  source,
141
159
  runPath,
142
160
  workspaceRoot,
@@ -152,4 +170,5 @@ export async function runStudio(argv: readonly string[], io: Pick<CliIo, "write"
152
170
  });
153
171
  await server.listen();
154
172
  server.printUrls();
173
+ for (const url of server.resolvedUrls?.local ?? []) io.write(` Comments ${url}#comments\n`);
155
174
  }