@hypit/hypit 0.1.4 → 0.1.5

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 (449) 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 +6 -0
  30. package/examples/semantic-composition/chat.svml +6 -5
  31. package/examples/semantic-composition/packages/chat-scene/README.md +3 -3
  32. package/examples/semantic-composition/packages/chat-scene/src/activation.ts +18 -21
  33. package/examples/semantic-composition/packages/chat-scene/src/render.ts +4 -4
  34. package/examples/semantic-composition/packages/performance-styles/README.md +42 -0
  35. package/examples/semantic-composition/packages/performance-styles/package.json +25 -0
  36. package/examples/semantic-composition/packages/performance-styles/src/activation.ts +57 -0
  37. package/examples/semantic-composition/packages/performance-styles/src/render.ts +54 -0
  38. package/examples/semantic-composition/packages/performance-styles/src/studio.ts +28 -0
  39. package/examples/semantic-composition/packages/performance-styles/tsconfig.json +18 -0
  40. package/examples/semantic-composition/packages/responsive-explainer/README.md +16 -9
  41. package/examples/semantic-composition/packages/responsive-explainer/src/activation.ts +12 -12
  42. package/examples/semantic-composition/packages/responsive-explainer/src/render.ts +5 -5
  43. package/examples/semantic-composition/packages/sound-styles/README.md +36 -0
  44. package/examples/semantic-composition/packages/sound-styles/package.json +25 -0
  45. package/examples/semantic-composition/packages/sound-styles/src/activation.ts +53 -0
  46. package/examples/semantic-composition/packages/sound-styles/src/render.ts +14 -0
  47. package/examples/semantic-composition/packages/sound-styles/tsconfig.json +18 -0
  48. package/package.json +32 -15
  49. package/packages/audio-track/README.md +20 -13
  50. package/packages/audio-track/package.json +1 -1
  51. package/packages/audio-track/src/component.ts +4 -4
  52. package/packages/audio-track/src/fragment.ts +6 -5
  53. package/packages/audio-track/src/index.ts +1 -1
  54. package/packages/audio-track/src/manifest.ts +17 -16
  55. package/packages/audio-track/src/program.ts +21 -25
  56. package/packages/audio-track/src/surface.ts +19 -18
  57. package/packages/audio-track-studio/README.md +23 -0
  58. package/packages/audio-track-studio/src/index.ts +28 -17
  59. package/packages/author-kit/README.md +1 -1
  60. package/packages/background-removal/README.md +4 -7
  61. package/packages/browser-capture/package.json +1 -1
  62. package/packages/build-result/README.md +11 -0
  63. package/packages/build-result/src/decode.ts +2 -0
  64. package/packages/build-result/src/execution-log.ts +17 -0
  65. package/packages/build-result/src/index.ts +1 -0
  66. package/packages/build-result/src/store.ts +14 -1
  67. package/packages/build-result/src/types.ts +3 -0
  68. package/packages/build-result-s3/src/repository.ts +4 -0
  69. package/packages/caption/README.md +61 -73
  70. package/packages/caption/package.json +3 -2
  71. package/packages/caption/src/activation.ts +2 -2
  72. package/packages/caption/src/component.ts +20 -5
  73. package/packages/caption/src/display.ts +3 -18
  74. package/packages/caption/src/fragment.ts +3 -7
  75. package/packages/caption/src/index.ts +6 -5
  76. package/packages/caption/src/manifest.ts +29 -46
  77. package/packages/caption/src/style.ts +24 -135
  78. package/packages/caption/src/surface.ts +12 -92
  79. package/packages/caption/src/temporalize.ts +18 -53
  80. package/packages/caption/src/types.ts +8 -35
  81. package/packages/caption/src/visibility.ts +23 -0
  82. package/packages/caption-fine/README.md +14 -9
  83. package/packages/caption-fine/package.json +4 -2
  84. package/packages/caption-fine/src/component.ts +3 -3
  85. package/packages/caption-fine/src/fragment.ts +7 -19
  86. package/packages/caption-fine/src/index.ts +2 -0
  87. package/packages/caption-fine/src/manifest.ts +26 -17
  88. package/packages/caption-fine/src/recipe.ts +7 -0
  89. package/packages/caption-fine/src/render.ts +14 -13
  90. package/packages/caption-fine/src/schedule.ts +39 -35
  91. package/packages/caption-fine/src/style.ts +10 -9
  92. package/packages/caption-fine/src/surface.ts +62 -35
  93. package/packages/caption-fine/src/types.ts +2 -0
  94. package/packages/caption-fine-studio/README.md +24 -2
  95. package/packages/caption-fine-studio/package.json +3 -1
  96. package/packages/caption-fine-studio/src/activation.ts +3 -3
  97. package/packages/caption-fine-studio/src/index.ts +54 -42
  98. package/packages/cli/README.md +57 -4
  99. package/packages/cli/package.json +1 -0
  100. package/packages/cli/src/arguments.ts +25 -6
  101. package/packages/cli/src/build-planning.ts +3 -2
  102. package/packages/cli/src/command.ts +6 -0
  103. package/packages/cli/src/commands/environment.ts +28 -18
  104. package/packages/cli/src/commands/execution.ts +81 -26
  105. package/packages/cli/src/commands/results.ts +7 -11
  106. package/packages/cli/src/index.ts +2 -2
  107. package/packages/cli/src/machine-view.ts +3 -2
  108. package/packages/cli/src/main.ts +34 -42
  109. package/packages/cli/src/observation.ts +7 -1
  110. package/packages/cli/src/output.ts +65 -23
  111. package/packages/cli/src/view.ts +64 -18
  112. package/packages/comment-sticker/README.md +3 -3
  113. package/packages/comment-sticker/package.json +1 -1
  114. package/packages/comment-sticker/src/component.ts +4 -4
  115. package/packages/comment-sticker/src/fragment.ts +5 -4
  116. package/packages/comment-sticker/src/manifest.ts +7 -6
  117. package/packages/comment-sticker/src/program.ts +9 -9
  118. package/packages/comment-sticker/src/surface.ts +6 -7
  119. package/packages/composition/README.md +21 -0
  120. package/packages/composition/src/audio-presentation.ts +44 -0
  121. package/packages/composition/src/index.ts +3 -0
  122. package/packages/composition/src/schema.ts +8 -3
  123. package/packages/composition/src/track.ts +15 -1
  124. package/packages/credential-store-env/README.md +1 -1
  125. package/packages/deck-track/README.md +3 -3
  126. package/packages/deck-track/package.json +1 -1
  127. package/packages/deck-track/src/component.ts +5 -5
  128. package/packages/deck-track/src/fragment.ts +6 -5
  129. package/packages/deck-track/src/lower.ts +12 -12
  130. package/packages/deck-track/src/manifest.ts +8 -7
  131. package/packages/deck-track/src/program.ts +13 -16
  132. package/packages/deck-track/src/surface.ts +9 -10
  133. package/packages/driver-node/src/driver.ts +41 -3
  134. package/packages/elevenlabs-speech/README.md +27 -0
  135. package/packages/{provider-xiaomi-mimo → elevenlabs-speech}/package.json +5 -8
  136. package/packages/elevenlabs-speech/src/activation.ts +26 -0
  137. package/packages/elevenlabs-speech/src/fragment.ts +11 -0
  138. package/packages/elevenlabs-speech/src/index.ts +111 -0
  139. package/packages/elevenlabs-speech/src/surface.ts +167 -0
  140. package/packages/endpoint-kit/README.md +24 -0
  141. package/packages/endpoint-kit/src/index.ts +7 -1
  142. package/packages/film/README.md +12 -7
  143. package/packages/film/package.json +1 -1
  144. package/packages/film/src/component.ts +4 -4
  145. package/packages/film/src/fragment.ts +6 -5
  146. package/packages/film/src/manifest.ts +11 -10
  147. package/packages/film/src/program.ts +5 -5
  148. package/packages/film/src/recipe.ts +2 -1
  149. package/packages/film/src/surface.ts +6 -6
  150. package/packages/film-studio/package.json +1 -1
  151. package/packages/film-studio/src/index.ts +2 -2
  152. package/packages/fishaudio-speech/README.md +33 -0
  153. package/packages/fishaudio-speech/package.json +21 -0
  154. package/packages/fishaudio-speech/src/activation.ts +32 -0
  155. package/packages/fishaudio-speech/src/fragment.ts +11 -0
  156. package/packages/fishaudio-speech/src/index.ts +156 -0
  157. package/packages/fishaudio-speech/src/surface.ts +192 -0
  158. package/packages/generation/README.md +11 -1
  159. package/packages/generation/src/mapping.ts +28 -30
  160. package/packages/gpt-image/README.md +1 -2
  161. package/packages/grok-imagine/README.md +1 -2
  162. package/packages/hyperframes/README.md +7 -3
  163. package/packages/hyperframes/src/browser-program.ts +11 -2
  164. package/packages/hyperframes/src/document.ts +15 -2
  165. package/packages/interview-emoji-reveal/README.md +4 -4
  166. package/packages/interview-emoji-reveal/package.json +1 -1
  167. package/packages/interview-emoji-reveal/src/component.ts +4 -4
  168. package/packages/interview-emoji-reveal/src/fragment.ts +6 -5
  169. package/packages/interview-emoji-reveal/src/manifest.ts +9 -8
  170. package/packages/interview-emoji-reveal/src/program.ts +14 -14
  171. package/packages/interview-emoji-reveal/src/surface.ts +8 -9
  172. package/packages/media-execution/README.md +7 -3
  173. package/packages/media-execution/src/audio-presentation.ts +23 -0
  174. package/packages/media-execution/src/execute.ts +2 -0
  175. package/packages/media-pipeline/README.md +7 -3
  176. package/packages/media-pipeline/src/audio-plan.ts +4 -1
  177. package/packages/media-pipeline/src/component.ts +16 -2
  178. package/packages/media-pipeline/src/manifest.ts +3 -1
  179. package/packages/media-pipeline/src/types.ts +2 -1
  180. package/packages/media-track/README.md +14 -47
  181. package/packages/media-track/package.json +1 -1
  182. package/packages/media-track/preview/preview.svml +5 -5
  183. package/packages/media-track/src/author.ts +12 -6
  184. package/packages/media-track/src/component.ts +10 -16
  185. package/packages/media-track/src/fragment.ts +8 -7
  186. package/packages/media-track/src/index.ts +3 -1
  187. package/packages/media-track/src/lower.ts +7 -7
  188. package/packages/media-track/src/manifest.ts +16 -38
  189. package/packages/media-track/src/program.ts +62 -67
  190. package/packages/media-track/src/sampling.ts +6 -6
  191. package/packages/media-track/src/sequence.ts +8 -8
  192. package/packages/media-track/src/surface.ts +25 -43
  193. package/packages/media-track-studio/README.md +9 -0
  194. package/packages/media-track-studio/src/index.ts +16 -11
  195. package/packages/mimo-speech/README.md +1 -1
  196. package/packages/minimax-h3/README.md +1 -1
  197. package/packages/nano-banana/README.md +1 -1
  198. package/packages/narrative/README.md +23 -1
  199. package/packages/narrative/src/identity.ts +11 -0
  200. package/packages/narrative/src/index.ts +3 -0
  201. package/packages/narrative/src/schema.ts +28 -27
  202. package/packages/narrative/src/selection.ts +52 -0
  203. package/packages/narrative/src/types.ts +2 -0
  204. package/packages/package-loader-node/README.md +30 -0
  205. package/packages/package-loader-node/package.json +5 -2
  206. package/packages/package-loader-node/src/distribution-resolution.ts +10 -3
  207. package/packages/package-loader-node/src/index.ts +1 -0
  208. package/packages/package-loader-node/src/loader.ts +12 -15
  209. package/packages/package-loader-node/src/location.ts +27 -1
  210. package/packages/package-loader-node/src/module-scope.ts +183 -0
  211. package/packages/package-loader-node/src/types.ts +4 -0
  212. package/packages/performance/README.md +83 -0
  213. package/packages/performance/package.json +30 -0
  214. package/packages/performance/src/activation.ts +11 -0
  215. package/packages/performance/src/component.ts +46 -0
  216. package/packages/performance/src/index.ts +6 -0
  217. package/packages/performance/src/manifest.ts +53 -0
  218. package/packages/{media-track/src/performance.ts → performance/src/media.ts} +9 -10
  219. package/packages/performance/src/program.ts +51 -0
  220. package/packages/performance/src/style.ts +35 -0
  221. package/packages/performance/src/surface.ts +99 -0
  222. package/packages/performance-studio/README.md +25 -0
  223. package/packages/performance-studio/package.json +21 -0
  224. package/packages/performance-studio/src/activation.ts +6 -0
  225. package/packages/performance-studio/src/index.ts +84 -0
  226. package/packages/program-space/README.md +9 -18
  227. package/packages/program-space/src/activation.ts +1 -5
  228. package/packages/program-space/src/index.ts +2 -11
  229. package/packages/program-space/src/surface.ts +1 -20
  230. package/packages/project-context-node/README.md +20 -0
  231. package/packages/project-context-node/package.json +10 -0
  232. package/packages/project-context-node/src/index.ts +3 -0
  233. package/packages/{cli → project-context-node}/src/runtime-selection.ts +7 -2
  234. package/packages/provider-hyperframes-local/README.md +43 -15
  235. package/packages/provider-hyperframes-local/src/activation.ts +4 -3
  236. package/packages/provider-hyperframes-local/src/capture-process.ts +26 -4
  237. package/packages/provider-hyperframes-local/src/capture.ts +96 -26
  238. package/packages/provider-hyperframes-local/src/concurrency.ts +86 -0
  239. package/packages/provider-hyperframes-local/src/opaque-capture.ts +92 -0
  240. package/packages/provider-hyperframes-local/src/options.ts +2 -0
  241. package/packages/provider-hyperframes-local/src/program.ts +6 -3
  242. package/packages/provider-hyperframes-local/src/progress.ts +53 -0
  243. package/packages/provider-hyperframes-local/src/provider.ts +18 -5
  244. package/packages/provider-hyperframes-local/src/render.ts +48 -7
  245. package/packages/provider-hypihub/README.md +48 -17
  246. package/packages/provider-hypihub/package.json +2 -0
  247. package/packages/provider-hypihub/src/mapping.ts +31 -7
  248. package/packages/provider-hypihub/src/oauth.ts +6 -0
  249. package/packages/provider-hypihub/src/provider.ts +25 -13
  250. package/packages/provider-hypihub/src/routes.ts +1 -2
  251. package/packages/provider-hypihub/src/upload.ts +2 -0
  252. package/packages/provider-media-local/README.md +3 -4
  253. package/packages/provider-whisperx-local/src/program.ts +1 -0
  254. package/packages/provider-whisperx-local/src/provider.ts +3 -0
  255. package/packages/ranking/README.md +8 -6
  256. package/packages/ranking/package.json +1 -1
  257. package/packages/ranking/src/component.ts +6 -6
  258. package/packages/ranking/src/fragment.ts +11 -7
  259. package/packages/ranking/src/manifest.ts +21 -14
  260. package/packages/ranking/src/render.ts +22 -26
  261. package/packages/ranking/src/schedule.ts +16 -19
  262. package/packages/ranking/src/surface.ts +12 -13
  263. package/packages/ranking-studio/README.md +18 -0
  264. package/packages/ranking-studio/src/index.ts +61 -9
  265. package/packages/render-hyperframes/README.md +7 -7
  266. package/packages/render-hyperframes/package.json +1 -1
  267. package/packages/render-hyperframes/src/component.ts +11 -1
  268. package/packages/render-hyperframes/src/fragment.ts +7 -4
  269. package/packages/render-hyperframes/src/manifest.ts +4 -4
  270. package/packages/render-hyperframes/src/surface.ts +6 -6
  271. package/packages/runtime/README.md +8 -1
  272. package/packages/runtime/src/execution.ts +15 -4
  273. package/packages/runtime/src/index.ts +2 -1
  274. package/packages/runtime/src/log.ts +51 -0
  275. package/packages/runtime/src/types.ts +5 -8
  276. package/packages/runtime-host-node/README.md +30 -0
  277. package/packages/runtime-host-node/package.json +1 -0
  278. package/packages/runtime-host-node/src/index.ts +24 -9
  279. package/packages/runtime-host-node/src/packages.ts +47 -50
  280. package/packages/runtime-kit/README.md +5 -0
  281. package/packages/runtime-kit/src/index.ts +3 -1
  282. package/packages/runtime-local/README.md +92 -4
  283. package/packages/runtime-local/src/config.ts +202 -56
  284. package/packages/runtime-local/src/control.ts +9 -1
  285. package/packages/runtime-local/src/executor.ts +66 -0
  286. package/packages/runtime-local/src/host.ts +37 -17
  287. package/packages/runtime-local/src/log.ts +48 -0
  288. package/packages/runtime-local/src/programs.ts +2 -1
  289. package/packages/runtime-local/src/result-writer.ts +2 -0
  290. package/packages/runtime-local/src/runtime.ts +8 -6
  291. package/packages/runtime-local/src/supervisor.ts +142 -0
  292. package/packages/runtime-local/src/types.ts +9 -2
  293. package/packages/runtime-local/src/worker-process.ts +7 -24
  294. package/packages/runtime-local/src/worker.ts +55 -83
  295. package/packages/screen-overlay/README.md +3 -3
  296. package/packages/screen-overlay/package.json +1 -1
  297. package/packages/screen-overlay/src/component.ts +3 -3
  298. package/packages/screen-overlay/src/fragment.ts +5 -4
  299. package/packages/screen-overlay/src/manifest.ts +7 -6
  300. package/packages/screen-overlay/src/program.ts +9 -9
  301. package/packages/screen-overlay/src/surface.ts +6 -7
  302. package/packages/script/README.md +15 -2
  303. package/packages/script/src/manifest.ts +2 -2
  304. package/packages/script/src/narrative.ts +1 -0
  305. package/packages/script/src/surface.ts +4 -3
  306. package/packages/script/src/types.ts +1 -1
  307. package/packages/script-studio/package.json +9 -3
  308. package/packages/script-studio/src/index.ts +2 -0
  309. package/packages/script-studio/src/projection.ts +105 -0
  310. package/packages/seedance/README.md +30 -1
  311. package/packages/seedance/src/index.ts +18 -7
  312. package/packages/seedance/src/surface.ts +17 -4
  313. package/packages/seedance-kits/README.md +7 -1
  314. package/packages/seedream/README.md +1 -1
  315. package/packages/sound/README.md +81 -0
  316. package/packages/sound/package.json +25 -0
  317. package/packages/sound/src/activation.ts +11 -0
  318. package/packages/sound/src/component.ts +28 -0
  319. package/packages/sound/src/index.ts +5 -0
  320. package/packages/sound/src/manifest.ts +47 -0
  321. package/packages/sound/src/program.ts +84 -0
  322. package/packages/sound/src/style.ts +34 -0
  323. package/packages/sound/src/surface.ts +90 -0
  324. package/packages/sound-studio/README.md +22 -0
  325. package/packages/sound-studio/package.json +20 -0
  326. package/packages/sound-studio/src/activation.ts +6 -0
  327. package/packages/sound-studio/src/index.ts +74 -0
  328. package/packages/speech/README.md +2 -2
  329. package/packages/speech-alignment/src/local.ts +8 -0
  330. package/packages/speech-alignment/src/locate.ts +1 -1
  331. package/packages/store-sqlite/README.md +7 -0
  332. package/packages/store-sqlite/src/store.ts +84 -83
  333. package/packages/studio/INSPECTOR.md +15 -2
  334. package/packages/studio/README.md +88 -14
  335. package/packages/studio/package.json +8 -7
  336. package/packages/studio/src/companion-assembly.ts +1 -0
  337. package/packages/studio/src/domain.ts +1 -1
  338. package/packages/studio/src/fallback-companions.ts +3 -3
  339. package/packages/studio/src/feedback-server.ts +51 -0
  340. package/packages/studio/src/feedback-store.ts +66 -0
  341. package/packages/studio/src/feedback.ts +60 -0
  342. package/packages/studio/src/parameter-values.ts +43 -1
  343. package/packages/studio/src/parameters.ts +114 -24
  344. package/packages/studio/src/preview/render.ts +5 -1
  345. package/packages/studio/src/preview/runtime-shim.ts +49 -3
  346. package/packages/studio/src/programme.ts +14 -30
  347. package/packages/studio/src/server.ts +10 -6
  348. package/packages/studio/src/shared.ts +4 -2
  349. package/packages/studio/src/snapshot.ts +21 -132
  350. package/packages/studio/src/studio-preflight.ts +3 -3
  351. package/packages/studio/src/studio-registry.ts +50 -6
  352. package/packages/studio/src/style.css +209 -48
  353. package/packages/studio/src/ui/comments.ts +233 -0
  354. package/packages/studio/src/ui/icons.ts +5 -0
  355. package/packages/studio/src/ui/main.ts +145 -86
  356. package/packages/studio/src/ui/overlay.ts +12 -8
  357. package/packages/studio/src/ui/scrub-preview.ts +108 -0
  358. package/packages/studio/src/ui/stage.ts +67 -4
  359. package/packages/studio/src/ui/timeline.ts +177 -108
  360. package/packages/studio/start.ts +4 -2
  361. package/packages/studio-adapter/README.md +130 -11
  362. package/packages/studio-adapter/src/index.ts +100 -13
  363. package/packages/temporal/README.md +6 -6
  364. package/packages/temporal/package.json +1 -1
  365. package/packages/temporal/src/component.ts +5 -6
  366. package/packages/temporal/src/index.ts +8 -6
  367. package/packages/temporal/src/location.ts +11 -11
  368. package/packages/temporal/src/projection.ts +19 -19
  369. package/packages/temporal/src/rational.ts +4 -4
  370. package/packages/temporal-markup/EDITING.md +2 -2
  371. package/packages/temporal-markup/README.md +27 -11
  372. package/packages/temporal-markup/package.json +1 -1
  373. package/packages/temporal-markup/src/index.ts +20 -25
  374. package/packages/temporal-markup/src/space.ts +10 -41
  375. package/packages/timeline/README.md +31 -0
  376. package/packages/{semantic-track → timeline}/package.json +1 -1
  377. package/packages/timeline/src/activation.ts +8 -0
  378. package/packages/timeline/src/component.ts +24 -0
  379. package/packages/timeline/src/identity.ts +60 -0
  380. package/packages/timeline/src/index.ts +6 -0
  381. package/packages/{semantic-track → timeline}/src/location.ts +20 -20
  382. package/packages/timeline/src/manifest.ts +39 -0
  383. package/packages/{semantic-track → timeline}/src/projection.ts +14 -14
  384. package/packages/timeline/src/types.ts +24 -0
  385. package/packages/timeline-author/README.md +68 -0
  386. package/packages/{speech-track → timeline-author}/package.json +6 -4
  387. package/packages/timeline-author/src/activation.ts +22 -0
  388. package/packages/{speech-track → timeline-author}/src/component.ts +15 -13
  389. package/packages/{speech-track → timeline-author}/src/fragment.ts +14 -23
  390. package/packages/timeline-author/src/index.ts +7 -0
  391. package/packages/timeline-author/src/manifest.ts +78 -0
  392. package/packages/timeline-author/src/program.ts +107 -0
  393. package/packages/timeline-author/src/surface.ts +46 -0
  394. package/packages/timeline-author/src/types.ts +6 -0
  395. package/packages/typography-track/README.md +4 -4
  396. package/packages/typography-track/package.json +1 -1
  397. package/packages/typography-track/src/component.ts +4 -4
  398. package/packages/typography-track/src/fragment.ts +4 -3
  399. package/packages/typography-track/src/manifest.ts +11 -9
  400. package/packages/typography-track/src/program.ts +15 -15
  401. package/packages/typography-track/src/surface.ts +17 -18
  402. package/packages/video-cli/README.md +4 -1
  403. package/packages/video-cli/package.json +2 -1
  404. package/packages/video-cli/src/creation.ts +14 -4
  405. package/packages/video-cli/src/index.ts +1 -1
  406. package/packages/video-cli/src/studio-distribution.ts +2 -1
  407. package/packages/volcengine-matting/README.md +3 -3
  408. package/packages/whisperx/README.md +1 -1
  409. package/services/whisperx/README.md +14 -0
  410. package/services/whisperx/pyproject.toml +2 -0
  411. package/services/whisperx/uv.lock +20 -20
  412. package/packages/provider-hyperframes-aws-lambda/README.md +0 -30
  413. package/packages/provider-hyperframes-aws-lambda/package.json +0 -30
  414. package/packages/provider-hyperframes-aws-lambda/src/activation.ts +0 -97
  415. package/packages/provider-hyperframes-aws-lambda/src/client.ts +0 -114
  416. package/packages/provider-hyperframes-aws-lambda/src/index.ts +0 -21
  417. package/packages/provider-hyperframes-aws-lambda/src/provider.ts +0 -522
  418. package/packages/provider-kie/README.md +0 -134
  419. package/packages/provider-kie/package.json +0 -43
  420. package/packages/provider-kie/src/activation.ts +0 -71
  421. package/packages/provider-kie/src/index.ts +0 -10
  422. package/packages/provider-kie/src/mapping.ts +0 -182
  423. package/packages/provider-kie/src/provider.ts +0 -657
  424. package/packages/provider-kie/src/routes.ts +0 -150
  425. package/packages/provider-xiaomi-mimo/README.md +0 -32
  426. package/packages/provider-xiaomi-mimo/src/activation.ts +0 -57
  427. package/packages/provider-xiaomi-mimo/src/index.ts +0 -5
  428. package/packages/provider-xiaomi-mimo/src/provider.ts +0 -214
  429. package/packages/runtime/src/environment.ts +0 -6
  430. package/packages/semantic-track/README.md +0 -21
  431. package/packages/semantic-track/src/activation.ts +0 -8
  432. package/packages/semantic-track/src/component.ts +0 -24
  433. package/packages/semantic-track/src/identity.ts +0 -58
  434. package/packages/semantic-track/src/index.ts +0 -6
  435. package/packages/semantic-track/src/manifest.ts +0 -38
  436. package/packages/semantic-track/src/types.ts +0 -26
  437. package/packages/speech-track/README.md +0 -51
  438. package/packages/speech-track/src/activation.ts +0 -19
  439. package/packages/speech-track/src/index.ts +0 -7
  440. package/packages/speech-track/src/manifest.ts +0 -73
  441. package/packages/speech-track/src/program.ts +0 -64
  442. package/packages/speech-track/src/surface.ts +0 -35
  443. package/packages/speech-track/src/types.ts +0 -6
  444. package/packages/speech-track-studio/README.md +0 -3
  445. package/packages/speech-track-studio/package.json +0 -14
  446. package/packages/speech-track-studio/src/activation.ts +0 -7
  447. package/packages/speech-track-studio/src/index.ts +0 -40
  448. /package/packages/{cli → project-context-node}/src/project-context.ts +0 -0
  449. /package/packages/{speech-track → timeline-author}/preview/Track.png +0 -0
@@ -1,6 +1,6 @@
1
1
  import type { Clip, StudioFailure, StudioInspectorDomain, StudioSnapshot } from "../shared.js";
2
2
  import type { CanonicalValue, ValueSchema } from "@hypit/protocol";
3
- import { parameterAuthorValue, parameterNumber, parameterOption, validateParameterValue } from "../parameter-values.js";
3
+ import { parameterAuthorValue, parameterControlForSchema, parameterNumber, parameterOption, parameterRecordSchema, parameterRecordVariants, validateParameterValue } from "../parameter-values.js";
4
4
  import { createCodePane } from "./code.js";
5
5
  import { icon } from "./icons.js";
6
6
  import { createLibraryPane } from "./library.js";
@@ -13,6 +13,7 @@ import { semanticGestureSpan } from "../temporal-edit.js";
13
13
  import type { SemanticTarget } from "../temporal-edit.js";
14
14
  import { applyStudioMutation } from "./writeback.js";
15
15
  import { createTimeline } from "./timeline.js";
16
+ import { createComments } from "./comments.js";
16
17
  import "../style.css";
17
18
 
18
19
  const app = document.querySelector<HTMLElement>("#app")!;
@@ -39,6 +40,10 @@ app.innerHTML = `
39
40
  <div class="topbar-right">
40
41
  <div class="meta" data-meta></div>
41
42
  <div class="status" data-status></div>
43
+ <div class="view-tabs" role="tablist" aria-label="Studio view">
44
+ <button type="button" role="tab" data-view="studio" aria-selected="true">${icon("studio")}Studio</button>
45
+ <button type="button" role="tab" data-view="comments" aria-selected="false">${icon("comments")}Comments</button>
46
+ </div>
42
47
  </div>
43
48
  </header>
44
49
  <main class="studio-shell">
@@ -65,6 +70,7 @@ const code = createCodePane();
65
70
  const stage = createStage(store, (id) => library.selectArtifact(id));
66
71
  const library = createLibraryPane(code, (artifact) => stage.openArtifact(artifact), (artifact) => stage.renameArtifact(artifact));
67
72
  const timeline = createTimeline(store);
73
+ const comments = createComments(store, stage);
68
74
  app.querySelector<HTMLElement>("[data-library]")!.append(library.element);
69
75
  app.querySelector<HTMLElement>("[data-timeline]")!.append(timeline.element);
70
76
  app.querySelector<HTMLElement>("[data-stage]")!.append(stage.element);
@@ -91,6 +97,14 @@ const workspaceHandle = createHandle({
91
97
  });
92
98
  workspaceHandle.classList.add("workspace-handle");
93
99
  upperShell.insertBefore(workspaceHandle, workspacePanel);
100
+ const commentsHandle = createHandle({
101
+ axis: "column", initial: 360, minimum: 280, invert: true,
102
+ maximum: () => Math.max(280, upperShell.clientWidth - 360),
103
+ apply: (size) => { upperShell.style.setProperty("--comments-width", `${size}px`); },
104
+ remember: "hypit-studio.comments-width",
105
+ });
106
+ commentsHandle.classList.add("comments-handle");
107
+ upperShell.append(commentsHandle, comments.element);
94
108
  shell.insertBefore(createHandle({
95
109
  axis: "row", initial: Math.round(window.innerHeight * 0.45), minimum: 220, invert: true,
96
110
  maximum: () => Math.max(260, shell.clientHeight - 260),
@@ -104,6 +118,29 @@ const project = app.querySelector<HTMLElement>("[data-project]")!;
104
118
  const status = app.querySelector<HTMLElement>("[data-status]")!;
105
119
  const failureView = app.querySelector<HTMLElement>("[data-failure]")!;
106
120
 
121
+ const changeView = (): void => {
122
+ const current = window.location.hash === "#comments" ? "comments" : "studio";
123
+ shell.dataset.view = current;
124
+ app.querySelectorAll<HTMLButtonElement>(".view-tabs [data-view]").forEach((button) => {
125
+ const selected = button.dataset.view === current;
126
+ button.setAttribute("aria-selected", String(selected)); button.tabIndex = selected ? 0 : -1;
127
+ });
128
+ comments.activate(current === "comments");
129
+ };
130
+ app.querySelectorAll<HTMLButtonElement>(".view-tabs [data-view]").forEach((button) => {
131
+ button.addEventListener("click", () => { window.location.hash = button.dataset.view!; });
132
+ button.addEventListener("keydown", (event) => {
133
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
134
+ event.preventDefault();
135
+ event.stopPropagation();
136
+ const next = button.dataset.view === "studio" ? "comments" : "studio";
137
+ window.location.hash = next;
138
+ app.querySelector<HTMLButtonElement>(`.view-tabs [data-view="${next}"]`)!.focus();
139
+ });
140
+ });
141
+ window.addEventListener("hashchange", changeView);
142
+ changeView();
143
+
107
144
  timeline.element.addEventListener("studio:write", (event) => {
108
145
  const state = (event as CustomEvent<{ readonly state?: string }>).detail.state;
109
146
  status.className = state === "error" ? "status error" : state === "saved" ? "status saved" : "status saving";
@@ -154,7 +191,7 @@ const domainPresentation: Readonly<Record<StudioInspectorDomain, { readonly labe
154
191
  how: { label: "How", icon: "how" },
155
192
  when: { label: "When", icon: "when" },
156
193
  };
157
- const domainOrder: readonly StudioInspectorDomain[] = ["where", "how", "when"];
194
+ const domainOrder: readonly StudioInspectorDomain[] = ["where", "when", "how"];
158
195
  const inspectorDomainByEntity = new Map<string, StudioInspectorDomain>();
159
196
  const inspectorPageByEntity = new Map<string, string>();
160
197
 
@@ -230,8 +267,8 @@ document.addEventListener("keydown", (event) => {
230
267
  }, true);
231
268
 
232
269
  function selectControl(
233
- entityId: string,
234
270
  parameter: Clip["inspector"][number],
271
+ change: (value: CanonicalValue) => void,
235
272
  ): HTMLElement {
236
273
  const control = document.createElement("div");
237
274
  control.className = "parameter-select parameter-control";
@@ -286,7 +323,7 @@ function selectControl(
286
323
  }
287
324
  close(false);
288
325
  trigger.focus();
289
- commitControl(entityId, parameter, option.value);
326
+ change(option.value);
290
327
  });
291
328
  return item;
292
329
  });
@@ -437,7 +474,8 @@ function fieldLabel(name: string): string {
437
474
 
438
475
  function blankValue(schema: ValueSchema): CanonicalValue {
439
476
  if (schema.kind === "string") return "";
440
- if (schema.kind === "number" || schema.kind === "null" || schema.kind === "literal" || schema.kind === "oneOf") return null;
477
+ if (schema.kind === "literal") return schema.value;
478
+ if (schema.kind === "number" || schema.kind === "null" || schema.kind === "oneOf") return null;
441
479
  if (schema.kind === "boolean") return false;
442
480
  if (schema.kind === "array") return [];
443
481
  if (schema.kind === "object") return Object.fromEntries(Object.entries(schema.fields)
@@ -452,31 +490,12 @@ function scalarDraftControl(
452
490
  held: CanonicalValue | undefined,
453
491
  change: (value: CanonicalValue) => void,
454
492
  ): HTMLElement {
455
- if (schema.kind === "string" && schema.format === "color") {
456
- return colorValueControl(label, typeof held === "string" ? held : "", change, true);
457
- }
458
- const input = document.createElement("input");
459
- input.className = "parameter-value parameter-structured-value";
460
- input.setAttribute("aria-label", label);
461
- input.spellcheck = false;
462
- if (schema.kind === "boolean") {
463
- input.type = "checkbox";
464
- input.checked = held === true;
465
- input.addEventListener("change", () => change(input.checked));
466
- return input;
467
- }
468
- input.type = "text";
469
- if (schema.kind === "number") input.inputMode = "decimal";
470
- input.value = held === undefined || held === null ? "" : textValue(held);
471
- input.addEventListener("input", () => {
472
- if (schema.kind === "number") {
473
- const number = Number(input.value);
474
- change(input.value.trim().length === 0 || !Number.isFinite(number) ? null : number);
475
- } else {
476
- change(input.value);
477
- }
478
- });
479
- return input;
493
+ return parameterControl("", {
494
+ id: label, label, domain: "how", section: { id: "record", label: "" },
495
+ control: parameterControlForSchema(schema) ?? "text",
496
+ ...(schema.kind === "string" && schema.enum !== undefined ? { options: schema.enum } : {}),
497
+ schema, value: held ?? null,
498
+ }, change);
480
499
  }
481
500
 
482
501
  function recordDraftControl(
@@ -490,30 +509,34 @@ function recordDraftControl(
490
509
  const fields = document.createElement("div");
491
510
  fields.className = "parameter-record-fields";
492
511
  for (const [name, field] of Object.entries(schema.fields)) {
493
- const row = document.createElement("label");
494
- row.className = "parameter-record-field";
495
- const copy = document.createElement("span");
496
- copy.textContent = fieldLabel(name);
497
- row.append(copy, scalarDraftControl(fieldLabel(name), field.schema, record[name], (next) => {
512
+ if (field.schema.kind === "literal") continue;
513
+ fields.append(scalarDraftControl(fieldLabel(name), field.schema, record[name], (next) => {
498
514
  record = { ...record, [name]: next };
499
515
  change(record);
500
516
  }));
501
- fields.append(row);
502
517
  }
503
518
  return fields;
504
519
  }
505
520
 
506
- function structuredControl(entityId: string, parameter: Clip["inspector"][number]): HTMLElement {
507
- const schema = parameter.schema;
521
+ function structuredControl(entityId: string, parameter: Clip["inspector"][number], change: (value: CanonicalValue) => void): HTMLElement {
522
+ const declaredSchema = parameter.schema;
508
523
  const shell = document.createElement("div");
509
524
  shell.className = "parameter-structured";
510
- if (schema === undefined || (schema.kind !== "array" && schema.kind !== "object")) return shell;
525
+ if (declaredSchema === undefined || (declaredSchema.kind !== "array" && declaredSchema.kind !== "object" && !parameterRecordVariants(declaredSchema).length)) return shell;
511
526
  let draft = structuredClone(parameter.value);
512
- let refreshDecisions = (): void => {};
527
+ const notice = document.createElement("div");
528
+ notice.className = "parameter-structured-notice";
529
+ notice.setAttribute("role", "status");
530
+ const save = (): void => {
531
+ const changed = !sameValue(draft, parameter.value);
532
+ notice.hidden = !changed || valid();
533
+ notice.textContent = "Complete the required fields with valid values to save.";
534
+ if (changed && valid()) change(draft);
535
+ };
513
536
 
514
537
  const valid = (): boolean => {
515
538
  try {
516
- validateParameterValue(draft, schema, parameter.label);
539
+ validateParameterValue(draft, declaredSchema, parameter.label);
517
540
  return true;
518
541
  } catch {
519
542
  return false;
@@ -522,6 +545,21 @@ function structuredControl(entityId: string, parameter: Clip["inspector"][number
522
545
 
523
546
  const render = (): void => {
524
547
  shell.replaceChildren();
548
+ const variants = parameterRecordVariants(declaredSchema);
549
+ const schema = declaredSchema.kind === "array" ? declaredSchema : parameterRecordSchema(declaredSchema, draft);
550
+ if (schema === undefined) return;
551
+ if (variants.length) {
552
+ const active = variants.find(variant => variant.schema === schema)!;
553
+ shell.append(parameterControl(entityId, {
554
+ ...parameter, control: "select", value: variants.indexOf(active),
555
+ options: variants.map((variant, index) => ({ value: index, label: textValue(variant.value) })),
556
+ }, (next) => {
557
+ if (next === variants.indexOf(active)) return;
558
+ draft = blankValue(variants[Number(next)]!.schema);
559
+ render();
560
+ save();
561
+ }));
562
+ }
525
563
  const summary = document.createElement("div");
526
564
  summary.className = "parameter-structured-summary";
527
565
  const count = document.createElement("span");
@@ -529,7 +567,7 @@ function structuredControl(entityId: string, parameter: Clip["inspector"][number
529
567
  ? `${draft.length} ${draft.length === 1 ? "item" : "items"}`
530
568
  : "Structured value";
531
569
  summary.append(count);
532
- shell.append(summary);
570
+ if (schema.kind === "array") shell.append(summary);
533
571
 
534
572
  if (schema.kind === "array") {
535
573
  const list = Array.isArray(draft) ? draft : [];
@@ -542,12 +580,12 @@ function structuredControl(entityId: string, parameter: Clip["inspector"][number
542
580
  ? recordDraftControl(schema.items, item, (next) => {
543
581
  const current = Array.isArray(draft) ? draft : [];
544
582
  draft = current.map((candidate, heldIndex) => heldIndex === index ? next : candidate);
545
- refreshDecisions();
583
+ save();
546
584
  })
547
585
  : scalarDraftControl(`${parameter.label} ${index + 1}`, schema.items, item, (next) => {
548
586
  const current = Array.isArray(draft) ? draft : [];
549
587
  draft = current.map((candidate, heldIndex) => heldIndex === index ? next : candidate);
550
- refreshDecisions();
588
+ save();
551
589
  });
552
590
  const actions = document.createElement("span");
553
591
  actions.className = "parameter-list-actions";
@@ -557,6 +595,7 @@ function structuredControl(entityId: string, parameter: Clip["inspector"][number
557
595
  reordered.splice(index + offset, 0, moving!);
558
596
  draft = reordered;
559
597
  render();
598
+ save();
560
599
  };
561
600
  const up = document.createElement("button");
562
601
  up.type = "button";
@@ -579,6 +618,7 @@ function structuredControl(entityId: string, parameter: Clip["inspector"][number
579
618
  const current = Array.isArray(draft) ? draft : [];
580
619
  draft = current.filter((_, heldIndex) => heldIndex !== index);
581
620
  render();
621
+ save();
582
622
  });
583
623
  actions.append(up, down, remove);
584
624
  row.append(editor, actions);
@@ -588,7 +628,7 @@ function structuredControl(entityId: string, parameter: Clip["inspector"][number
588
628
  } else {
589
629
  shell.append(recordDraftControl(schema, draft, (next) => {
590
630
  draft = next;
591
- refreshDecisions();
631
+ save();
592
632
  }));
593
633
  }
594
634
 
@@ -605,69 +645,81 @@ function structuredControl(entityId: string, parameter: Clip["inspector"][number
605
645
  const current = Array.isArray(draft) ? draft : [];
606
646
  draft = [...current, blankValue(schema.items)];
607
647
  render();
648
+ save();
608
649
  });
609
650
  footer.append(add);
610
651
  }
611
- const decisions = document.createElement("span");
612
- decisions.className = "parameter-structured-decisions";
613
- const reset = document.createElement("button");
614
- reset.type = "button";
615
- reset.textContent = "Reset";
616
- reset.disabled = sameValue(draft, parameter.value);
617
- reset.addEventListener("click", () => {
618
- draft = structuredClone(parameter.value);
619
- render();
620
- });
621
- const apply = document.createElement("button");
622
- apply.type = "button";
623
- apply.className = "primary";
624
- apply.textContent = "Apply";
625
- apply.addEventListener("click", () => commitControl(entityId, parameter, draft));
626
- refreshDecisions = () => {
627
- reset.disabled = sameValue(draft, parameter.value);
628
- apply.disabled = reset.disabled || !valid();
629
- };
630
- refreshDecisions();
631
- decisions.append(reset, apply);
632
- footer.append(decisions);
633
- shell.append(footer);
652
+ if (schema.kind === "array") shell.append(footer);
653
+ notice.hidden = sameValue(draft, parameter.value) || valid();
654
+ shell.append(notice);
634
655
  };
635
656
  render();
636
657
  return shell;
637
658
  }
638
659
 
639
- function parameterControl(entityId: string, parameter: Clip["inspector"][number]): HTMLElement {
660
+ function parameterControl(
661
+ entityId: string,
662
+ parameter: Clip["inspector"][number],
663
+ change?: (value: CanonicalValue) => void,
664
+ ): HTMLElement {
665
+ const editable = parameter.edit !== undefined || change !== undefined;
666
+ const commit = change ?? ((value: CanonicalValue) => commitControl(entityId, parameter, value));
667
+ if (editable && parameter.control === "record" && parameter.schema !== undefined && parameterRecordVariants(parameter.schema).length) {
668
+ return structuredControl(entityId, parameter, commit);
669
+ }
640
670
  const row = document.createElement("div");
641
- row.className = `parameter-row parameter-editable control-${parameter.control}`;
671
+ row.className = `parameter-row ${!editable ? "parameter-readonly" : "parameter-editable"} control-${parameter.control}`;
642
672
  const name = document.createElement("span");
643
673
  name.className = "parameter-label";
644
674
  name.textContent = parameter.label;
645
675
  name.title = parameter.summary ?? parameter.label;
646
676
  const right = document.createElement("span");
647
677
  right.className = "parameter-right parameter-control";
678
+ if (!editable) {
679
+ const value = document.createElement("span");
680
+ value.className = "parameter-display";
681
+ let displayValue = textValue(parameter.value);
682
+ let unitLabel = parameter.unit;
683
+ if (parameter.control === "number") {
684
+ try {
685
+ const numeric = parameterNumber(change && parameter.value === null ? 0 : parameter.value, parameter.number);
686
+ displayValue = String(numeric.value);
687
+ unitLabel = numeric.suffix || parameter.unit;
688
+ } catch { /* Keep the actual value visible when it is not a scalar. */ }
689
+ } else if (parameter.control === "select") {
690
+ displayValue = parameter.options?.map(parameterOption).find(option => option.value === parameter.value)?.label ?? displayValue;
691
+ }
692
+ value.textContent = displayValue;
693
+ right.append(value);
694
+ if (unitLabel !== undefined) {
695
+ const unit = document.createElement("small"); unit.textContent = unitLabel; right.append(unit);
696
+ }
697
+ row.append(name, right);
698
+ return row;
699
+ }
648
700
  let unitLabel = parameter.unit;
649
701
  if (parameter.control === "select") {
650
- right.append(selectControl(entityId, parameter));
702
+ right.append(selectControl(parameter, commit));
651
703
  } else if (parameter.control === "color") {
652
704
  right.append(colorValueControl(parameter.label, textValue(parameter.value), (next) => {
653
- commitControl(entityId, parameter, next);
705
+ commit(next);
654
706
  }));
655
707
  if (parameter.swatches?.length) {
656
708
  const palette = document.createElement("span"); palette.className = "parameter-swatches";
657
709
  for (const color of parameter.swatches) {
658
710
  const swatch = document.createElement("button"); swatch.type = "button";
659
711
  swatch.style.backgroundColor = color; swatch.title = color; swatch.setAttribute("aria-label", `Use ${color}`);
660
- swatch.addEventListener("click", () => commitControl(entityId, parameter, color)); palette.append(swatch);
712
+ swatch.addEventListener("click", () => commit(color)); palette.append(swatch);
661
713
  }
662
714
  right.append(palette);
663
715
  }
664
716
  } else if (parameter.control === "list" || parameter.control === "record") {
665
- right.append(structuredControl(entityId, parameter));
717
+ right.append(structuredControl(entityId, parameter, commit));
666
718
  } else {
667
719
  if (parameter.multiline && parameter.control === "text") {
668
720
  const value = document.createElement("textarea"); value.className = "parameter-value parameter-multiline";
669
721
  value.value = textValue(parameter.value); value.setAttribute("aria-label", parameter.label);
670
- value.addEventListener("change", () => commitControl(entityId, parameter, value.value)); right.append(value);
722
+ value.addEventListener("change", () => commit(value.value)); right.append(value);
671
723
  row.append(name, right); return row;
672
724
  }
673
725
  const value = document.createElement("input");
@@ -678,8 +730,8 @@ function parameterControl(entityId: string, parameter: Clip["inspector"][number]
678
730
  if (value.type === "checkbox") value.checked = parameter.value === true || parameter.value === "true";
679
731
  else if (parameter.control === "number") {
680
732
  try {
681
- const numeric = parameterNumber(parameter.value, parameter.number);
682
- value.type = "number"; value.inputMode = "decimal"; value.value = String(numeric.value);
733
+ const numeric = parameterNumber(change && parameter.value === null ? 0 : parameter.value, parameter.number);
734
+ value.type = "number"; value.inputMode = "decimal"; value.value = change && parameter.value === null ? "" : String(numeric.value);
683
735
  const schema = parameter.schema?.kind === "number" ? parameter.schema : undefined;
684
736
  const scale = parameter.number?.scale ?? 1;
685
737
  const minimum = parameter.number?.minimum ?? (schema?.minimum === undefined ? undefined : schema.minimum * scale);
@@ -698,11 +750,12 @@ function parameterControl(entityId: string, parameter: Clip["inspector"][number]
698
750
  if (!value.title) value.title = parameter.summary ?? parameter.label;
699
751
  value.addEventListener("change", () => {
700
752
  if (value.type === "checkbox") {
701
- commitControl(entityId, parameter, value.checked);
753
+ commit(value.checked);
702
754
  } else if (parameter.control === "number") {
703
- if (value.reportValidity()) commitControl(entityId, parameter, value.valueAsNumber);
755
+ if (change) commit(Number.isFinite(value.valueAsNumber) ? value.valueAsNumber : null);
756
+ else if (value.reportValidity()) commit(value.valueAsNumber);
704
757
  } else {
705
- commitControl(entityId, parameter, value.value);
758
+ commit(value.value);
706
759
  }
707
760
  });
708
761
  right.append(value);
@@ -802,7 +855,7 @@ function renderInspector(snapshot: StudioSnapshot, clipId: string | undefined):
802
855
  defaultWorkspaceHeading();
803
856
  const empty = document.createElement("div");
804
857
  empty.className = "inspector-empty";
805
- empty.textContent = "No adjustable parameters";
858
+ empty.textContent = "No details for this selection";
806
859
  inspector.replaceChildren(empty);
807
860
  return;
808
861
  }
@@ -813,17 +866,22 @@ function renderInspector(snapshot: StudioSnapshot, clipId: string | undefined):
813
866
 
814
867
  const domainFields = clip.inspector.filter((field) => field.domain === activeDomain);
815
868
  const pages = new Map<string, { readonly label: string; readonly fields: typeof domainFields }>();
816
- for (const field of domainFields) {
817
- const id = field.page?.id ?? "default";
869
+ const commonFields = domainFields.filter(field => field.page === undefined);
870
+ for (const field of domainFields.filter(field => field.page !== undefined)) {
871
+ const id = field.page!.id;
818
872
  const page = pages.get(id) ?? { label: field.page?.label ?? "", fields: [] };
819
873
  pages.set(id, { ...page, fields: [...page.fields, field] });
820
874
  }
821
875
  const pageIds = [...pages.keys()];
876
+ if (pageIds.length === 0) {
877
+ inspector.replaceChildren(...parameterGroups(clip.id, commonFields));
878
+ return;
879
+ }
822
880
  const memoryKey = `${clip.id}:${activeDomain}`;
823
881
  const rememberedPage = inspectorPageByEntity.get(memoryKey);
824
882
  const activePage = rememberedPage !== undefined && pages.has(rememberedPage) ? rememberedPage : pageIds[0]!;
825
883
  inspectorPageByEntity.set(memoryKey, activePage);
826
- const page = pages.get(activePage)!;
884
+ const page = pages.get(activePage);
827
885
  const subtabs = document.createElement("div");
828
886
  subtabs.className = "inspector-subtabs";
829
887
  if (pageIds.length > 1) {
@@ -841,7 +899,7 @@ function renderInspector(snapshot: StudioSnapshot, clipId: string | undefined):
841
899
  return button;
842
900
  }));
843
901
  }
844
- inspector.replaceChildren(...(pageIds.length > 1 ? [subtabs] : []), ...parameterGroups(clip.id, page.fields));
902
+ inspector.replaceChildren(...(pageIds.length > 1 ? [subtabs] : []), ...parameterGroups(clip.id, [...commonFields, ...(page?.fields ?? [])]));
845
903
  }
846
904
 
847
905
  function renderSemanticInspector(snapshot: StudioSnapshot, segmentId: string): void {
@@ -850,7 +908,7 @@ function renderSemanticInspector(snapshot: StudioSnapshot, segmentId: string): v
850
908
  defaultWorkspaceHeading();
851
909
  const empty = document.createElement("div");
852
910
  empty.className = "inspector-empty";
853
- empty.textContent = "No adjustable parameters";
911
+ empty.textContent = "No details for this selection";
854
912
  inspector.replaceChildren(empty);
855
913
  }
856
914
 
@@ -1060,6 +1118,7 @@ window.addEventListener("keydown", (event) => {
1060
1118
  event.preventDefault();
1061
1119
  return;
1062
1120
  }
1121
+ if (shell.dataset.view === "comments" && ["-", "_", "=", "+", "\\", "f", "F"].includes(event.key)) return;
1063
1122
  if (event.key === "-" || event.key === "_") {
1064
1123
  timeline.zoomOut();
1065
1124
  event.preventDefault();
@@ -20,6 +20,7 @@ export type Overlay = {
20
20
  readonly element: SVGSVGElement;
21
21
  /** The topmost clip drawn at a point, in client coordinates. */
22
22
  hitTest(clientX: number, clientY: number): Clip | undefined;
23
+ hitsAt(clientX: number, clientY: number): readonly Clip[];
23
24
  /** Redraw against the picture, once it has mounted or moved. */
24
25
  refresh(): void;
25
26
  };
@@ -127,19 +128,22 @@ export function createOverlay(store: Store, measure: Measure): Overlay {
127
128
  draw();
128
129
  });
129
130
 
130
- return {
131
- element,
132
- refresh: draw,
133
- hitTest(clientX, clientY) {
131
+ const hitsAt = (clientX: number, clientY: number): readonly Clip[] => {
134
132
  const box = element.getBoundingClientRect();
135
- if (box.width === 0 || box.height === 0) return undefined;
133
+ if (box.width === 0 || box.height === 0) return [];
136
134
  const x = (clientX - box.left) / box.width * canvas.width;
137
135
  const y = (clientY - box.top) / box.height * canvas.height;
138
136
  // Hit individual parts, not the empty space inside a group's union box.
139
- return entities.flatMap((clip) => drawnParts(clip)
137
+ const hits = entities.flatMap((clip) => drawnParts(clip)
140
138
  .filter((part) => inside(part, x, y))
141
139
  .map((part) => ({ clip, order: part.stackOrder })))
142
- .sort((left, right) => right.order - left.order)[0]?.clip;
143
- },
140
+ .sort((left, right) => right.order - left.order);
141
+ return [...new Map(hits.map(({ clip }) => [clip.id, clip])).values()];
142
+ };
143
+ return {
144
+ element,
145
+ refresh: draw,
146
+ hitsAt,
147
+ hitTest: (x, y) => hitsAt(x, y)[0],
144
148
  };
145
149
  }
@@ -0,0 +1,108 @@
1
+ import type { StudioSnapshot } from "../shared.js";
2
+ import { feedbackClock } from "../feedback.js";
3
+
4
+ type PreviewWindow = Window & {
5
+ __hypitSeekFrame?: (frame: number) => Promise<boolean>;
6
+ __hypitSetMuted?: (muted: boolean) => Promise<boolean>;
7
+ };
8
+
9
+ /** One lazy, muted picture for scrubbing; it never changes the main playhead. */
10
+ export function createScrubPreview(container: HTMLElement) {
11
+ const element = document.createElement("div");
12
+ element.className = "scrub-preview";
13
+ element.hidden = true;
14
+ element.innerHTML = '<div class="scrub-preview-picture"><span>Loading frame…</span></div><div class="scrub-preview-time"></div>';
15
+ element.setAttribute("aria-hidden", "true");
16
+ const picture = element.querySelector<HTMLElement>(".scrub-preview-picture")!;
17
+ const status = picture.querySelector<HTMLElement>("span")!;
18
+ const time = element.querySelector<HTMLElement>(".scrub-preview-time")!;
19
+ container.append(element);
20
+ let iframe: HTMLIFrameElement | undefined;
21
+ let revision: number | undefined;
22
+ let ready = false;
23
+ let seeking = false;
24
+ let requested: number | undefined;
25
+ let displayed: number | undefined;
26
+
27
+ const seek = async (): Promise<void> => {
28
+ const current = iframe;
29
+ if (!ready || seeking || current === undefined || requested === undefined || requested === displayed) return;
30
+ seeking = true;
31
+ try {
32
+ while (iframe === current && requested !== undefined && requested !== displayed) {
33
+ const frame: number = requested;
34
+ const target = current.contentWindow as PreviewWindow | null;
35
+ const placed = await target?.__hypitSeekFrame?.(frame);
36
+ if (iframe !== current) return;
37
+ if (!placed) throw new Error("Frame unavailable");
38
+ displayed = frame;
39
+ if (requested === frame) {
40
+ current.style.visibility = "visible";
41
+ status.hidden = true;
42
+ element.dataset.frame = String(frame);
43
+ }
44
+ }
45
+ } catch {
46
+ if (iframe === current) status.textContent = "Frame unavailable";
47
+ } finally {
48
+ if (iframe === current) seeking = false;
49
+ }
50
+ };
51
+ const hide = (): void => { element.hidden = true; requested = undefined; };
52
+ const clear = (): void => {
53
+ hide(); iframe?.remove(); iframe = undefined; revision = undefined;
54
+ ready = false; seeking = false; displayed = undefined;
55
+ delete element.dataset.frame;
56
+ };
57
+ return {
58
+ hide, clear,
59
+ show(snapshot: StudioSnapshot, frame: number, clientX: number): void {
60
+ if (snapshot.revision !== revision) clear();
61
+ if (iframe === undefined) {
62
+ revision = snapshot.revision;
63
+ const { canvasWidth, canvasHeight } = snapshot.space;
64
+ const scale = Math.min(200 / canvasWidth, 170 / canvasHeight);
65
+ picture.style.width = `${canvasWidth * scale}px`;
66
+ picture.style.height = `${canvasHeight * scale}px`;
67
+ const created = document.createElement("iframe");
68
+ created.title = "Hovered frame";
69
+ created.tabIndex = -1;
70
+ created.setAttribute("sandbox", "allow-scripts allow-same-origin");
71
+ created.setAttribute("allow", "autoplay 'none'");
72
+ created.style.width = `${canvasWidth}px`;
73
+ created.style.height = `${canvasHeight}px`;
74
+ created.style.transform = `scale(${scale})`;
75
+ created.style.visibility = "hidden";
76
+ created.addEventListener("load", () => {
77
+ void (async () => {
78
+ const target = created.contentWindow as PreviewWindow | null;
79
+ await target?.__hypitSetMuted?.(true);
80
+ if (iframe !== created) return;
81
+ ready = true;
82
+ await seek();
83
+ })().catch(() => { if (iframe === created) status.textContent = "Frame unavailable"; });
84
+ });
85
+ created.srcdoc = snapshot.preview.srcdoc;
86
+ iframe = created;
87
+ picture.prepend(created);
88
+ }
89
+ requested = frame;
90
+ element.hidden = false;
91
+ const room = container.getBoundingClientRect();
92
+ const left = Math.max(0, Math.min(clientX - room.left - element.offsetWidth / 2, room.width - element.offsetWidth));
93
+ element.style.left = `${left}px`;
94
+ time.textContent = feedbackClock(frame * snapshot.space.frameRate.denominator / snapshot.space.frameRate.numerator);
95
+ if (frame !== displayed) {
96
+ iframe.style.visibility = "hidden";
97
+ status.textContent = "Loading frame…";
98
+ status.hidden = false;
99
+ delete element.dataset.frame;
100
+ } else {
101
+ iframe.style.visibility = "visible";
102
+ status.hidden = true;
103
+ element.dataset.frame = String(frame);
104
+ }
105
+ void seek();
106
+ },
107
+ };
108
+ }