@hypit/hypit 0.1.3 → 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 (486) hide show
  1. package/README.md +5 -3
  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 +107 -16
  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 +35 -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 +33 -19
  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 +69 -0
  63. package/packages/build-result/package.json +2 -1
  64. package/packages/build-result/src/decode.ts +12 -8
  65. package/packages/build-result/src/execution-log.ts +17 -0
  66. package/packages/build-result/src/file-reference.ts +42 -0
  67. package/packages/build-result/src/index.ts +4 -0
  68. package/packages/build-result/src/replace-file-windows.ts +58 -0
  69. package/packages/build-result/src/replace-file.ts +11 -0
  70. package/packages/build-result/src/store.ts +58 -14
  71. package/packages/build-result/src/types.ts +41 -8
  72. package/packages/build-result/src/writer.ts +12 -1
  73. package/packages/build-result-fs/README.md +23 -1
  74. package/packages/build-result-s3/README.md +5 -0
  75. package/packages/build-result-s3/src/repository.ts +23 -5
  76. package/packages/caption/README.md +61 -73
  77. package/packages/caption/package.json +3 -2
  78. package/packages/caption/src/activation.ts +2 -2
  79. package/packages/caption/src/component.ts +20 -5
  80. package/packages/caption/src/display.ts +3 -18
  81. package/packages/caption/src/fragment.ts +3 -7
  82. package/packages/caption/src/index.ts +6 -5
  83. package/packages/caption/src/manifest.ts +29 -46
  84. package/packages/caption/src/style.ts +24 -135
  85. package/packages/caption/src/surface.ts +12 -92
  86. package/packages/caption/src/temporalize.ts +18 -53
  87. package/packages/caption/src/types.ts +8 -35
  88. package/packages/caption/src/visibility.ts +23 -0
  89. package/packages/caption-fine/README.md +31 -11
  90. package/packages/caption-fine/package.json +4 -2
  91. package/packages/caption-fine/src/component.ts +3 -3
  92. package/packages/caption-fine/src/fragment.ts +7 -19
  93. package/packages/caption-fine/src/index.ts +2 -0
  94. package/packages/caption-fine/src/manifest.ts +27 -18
  95. package/packages/caption-fine/src/recipe.ts +7 -0
  96. package/packages/caption-fine/src/render.ts +62 -49
  97. package/packages/caption-fine/src/schedule.ts +39 -35
  98. package/packages/caption-fine/src/style.ts +10 -9
  99. package/packages/caption-fine/src/surface.ts +62 -35
  100. package/packages/caption-fine/src/types.ts +2 -0
  101. package/packages/caption-fine-studio/README.md +24 -2
  102. package/packages/caption-fine-studio/package.json +10 -3
  103. package/packages/caption-fine-studio/src/activation.ts +3 -3
  104. package/packages/caption-fine-studio/src/index.ts +61 -40
  105. package/packages/cli/README.md +81 -3
  106. package/packages/cli/package.json +1 -0
  107. package/packages/cli/src/arguments.ts +39 -15
  108. package/packages/cli/src/build-planning.ts +9 -3
  109. package/packages/cli/src/command.ts +7 -1
  110. package/packages/cli/src/commands/environment.ts +66 -27
  111. package/packages/cli/src/commands/execution.ts +81 -26
  112. package/packages/cli/src/commands/results.ts +7 -11
  113. package/packages/cli/src/index.ts +2 -2
  114. package/packages/cli/src/machine-view.ts +15 -5
  115. package/packages/cli/src/main.ts +38 -42
  116. package/packages/cli/src/observation.ts +7 -1
  117. package/packages/cli/src/output.ts +92 -34
  118. package/packages/cli/src/result-export.ts +22 -13
  119. package/packages/cli/src/run-file.ts +19 -8
  120. package/packages/cli/src/view.ts +64 -18
  121. package/packages/comment-sticker/README.md +3 -3
  122. package/packages/comment-sticker/package.json +1 -1
  123. package/packages/comment-sticker/src/component.ts +4 -4
  124. package/packages/comment-sticker/src/fragment.ts +5 -4
  125. package/packages/comment-sticker/src/manifest.ts +7 -6
  126. package/packages/comment-sticker/src/program.ts +9 -9
  127. package/packages/comment-sticker/src/surface.ts +6 -7
  128. package/packages/comment-sticker-studio/src/index.ts +2 -1
  129. package/packages/compiler-node/src/compiler.ts +1 -0
  130. package/packages/composition/README.md +21 -0
  131. package/packages/composition/src/audio-presentation.ts +44 -0
  132. package/packages/composition/src/index.ts +3 -0
  133. package/packages/composition/src/schema.ts +8 -3
  134. package/packages/composition/src/track.ts +15 -1
  135. package/packages/credential-store-env/README.md +1 -1
  136. package/packages/deck-track/README.md +3 -3
  137. package/packages/deck-track/package.json +1 -1
  138. package/packages/deck-track/src/component.ts +5 -5
  139. package/packages/deck-track/src/fragment.ts +6 -5
  140. package/packages/deck-track/src/lower.ts +12 -12
  141. package/packages/deck-track/src/manifest.ts +8 -7
  142. package/packages/deck-track/src/program.ts +13 -16
  143. package/packages/deck-track/src/surface.ts +9 -10
  144. package/packages/driver-node/src/driver.ts +41 -3
  145. package/packages/elevenlabs-speech/README.md +27 -0
  146. package/packages/{provider-xiaomi-mimo → elevenlabs-speech}/package.json +5 -8
  147. package/packages/elevenlabs-speech/src/activation.ts +26 -0
  148. package/packages/elevenlabs-speech/src/fragment.ts +11 -0
  149. package/packages/elevenlabs-speech/src/index.ts +111 -0
  150. package/packages/elevenlabs-speech/src/surface.ts +167 -0
  151. package/packages/endpoint-kit/README.md +24 -0
  152. package/packages/endpoint-kit/src/index.ts +7 -1
  153. package/packages/estimate/README.md +56 -3
  154. package/packages/estimate/src/program.ts +7 -8
  155. package/packages/film/README.md +12 -7
  156. package/packages/film/package.json +1 -1
  157. package/packages/film/src/component.ts +4 -4
  158. package/packages/film/src/fragment.ts +6 -5
  159. package/packages/film/src/manifest.ts +11 -10
  160. package/packages/film/src/program.ts +5 -5
  161. package/packages/film/src/recipe.ts +2 -1
  162. package/packages/film/src/surface.ts +6 -6
  163. package/packages/film-studio/package.json +1 -1
  164. package/packages/film-studio/src/index.ts +2 -2
  165. package/packages/fishaudio-speech/README.md +33 -0
  166. package/packages/fishaudio-speech/package.json +21 -0
  167. package/packages/fishaudio-speech/src/activation.ts +32 -0
  168. package/packages/fishaudio-speech/src/fragment.ts +11 -0
  169. package/packages/fishaudio-speech/src/index.ts +156 -0
  170. package/packages/fishaudio-speech/src/surface.ts +192 -0
  171. package/packages/fonts-open/README.md +5 -0
  172. package/packages/fonts-open/package.json +5 -1
  173. package/packages/fonts-open/src/studio.ts +21 -0
  174. package/packages/generation/README.md +11 -1
  175. package/packages/generation/src/mapping.ts +28 -30
  176. package/packages/gpt-image/README.md +1 -2
  177. package/packages/grok-imagine/README.md +1 -2
  178. package/packages/hyperframes/README.md +7 -3
  179. package/packages/hyperframes/src/browser-program.ts +11 -2
  180. package/packages/hyperframes/src/document.ts +15 -2
  181. package/packages/interview-emoji-reveal/README.md +4 -4
  182. package/packages/interview-emoji-reveal/package.json +1 -1
  183. package/packages/interview-emoji-reveal/src/component.ts +4 -4
  184. package/packages/interview-emoji-reveal/src/fragment.ts +6 -5
  185. package/packages/interview-emoji-reveal/src/manifest.ts +9 -8
  186. package/packages/interview-emoji-reveal/src/program.ts +14 -14
  187. package/packages/interview-emoji-reveal/src/surface.ts +8 -9
  188. package/packages/media-execution/README.md +7 -3
  189. package/packages/media-execution/src/audio-presentation.ts +23 -0
  190. package/packages/media-execution/src/execute.ts +2 -0
  191. package/packages/media-pipeline/README.md +7 -3
  192. package/packages/media-pipeline/src/audio-plan.ts +4 -1
  193. package/packages/media-pipeline/src/component.ts +16 -2
  194. package/packages/media-pipeline/src/manifest.ts +3 -1
  195. package/packages/media-pipeline/src/types.ts +2 -1
  196. package/packages/media-track/README.md +14 -47
  197. package/packages/media-track/package.json +1 -1
  198. package/packages/media-track/preview/preview.svml +5 -5
  199. package/packages/media-track/src/author.ts +12 -6
  200. package/packages/media-track/src/component.ts +10 -16
  201. package/packages/media-track/src/fragment.ts +8 -7
  202. package/packages/media-track/src/index.ts +3 -1
  203. package/packages/media-track/src/lower.ts +7 -7
  204. package/packages/media-track/src/manifest.ts +16 -38
  205. package/packages/media-track/src/program.ts +62 -67
  206. package/packages/media-track/src/sampling.ts +6 -6
  207. package/packages/media-track/src/sequence.ts +8 -8
  208. package/packages/media-track/src/surface.ts +25 -43
  209. package/packages/media-track-studio/README.md +9 -0
  210. package/packages/media-track-studio/src/index.ts +23 -13
  211. package/packages/mimo-speech/README.md +1 -1
  212. package/packages/minimax-h3/README.md +1 -1
  213. package/packages/nano-banana/README.md +1 -1
  214. package/packages/narrative/README.md +23 -1
  215. package/packages/narrative/src/identity.ts +11 -0
  216. package/packages/narrative/src/index.ts +3 -0
  217. package/packages/narrative/src/schema.ts +28 -27
  218. package/packages/narrative/src/selection.ts +52 -0
  219. package/packages/narrative/src/types.ts +2 -0
  220. package/packages/package-loader-node/README.md +30 -0
  221. package/packages/package-loader-node/package.json +5 -2
  222. package/packages/package-loader-node/src/distribution-resolution.ts +10 -3
  223. package/packages/package-loader-node/src/index.ts +1 -0
  224. package/packages/package-loader-node/src/loader.ts +12 -15
  225. package/packages/package-loader-node/src/location.ts +27 -1
  226. package/packages/package-loader-node/src/module-scope.ts +183 -0
  227. package/packages/package-loader-node/src/types.ts +4 -0
  228. package/packages/performance/README.md +83 -0
  229. package/packages/performance/package.json +30 -0
  230. package/packages/performance/src/activation.ts +11 -0
  231. package/packages/performance/src/component.ts +46 -0
  232. package/packages/performance/src/index.ts +6 -0
  233. package/packages/performance/src/manifest.ts +53 -0
  234. package/packages/{media-track/src/performance.ts → performance/src/media.ts} +9 -10
  235. package/packages/performance/src/program.ts +51 -0
  236. package/packages/performance/src/style.ts +35 -0
  237. package/packages/performance/src/surface.ts +99 -0
  238. package/packages/performance-studio/README.md +25 -0
  239. package/packages/performance-studio/package.json +21 -0
  240. package/packages/performance-studio/src/activation.ts +6 -0
  241. package/packages/performance-studio/src/index.ts +84 -0
  242. package/packages/program-space/README.md +9 -18
  243. package/packages/program-space/src/activation.ts +1 -5
  244. package/packages/program-space/src/index.ts +2 -11
  245. package/packages/program-space/src/surface.ts +1 -20
  246. package/packages/project-context-node/README.md +20 -0
  247. package/packages/project-context-node/package.json +10 -0
  248. package/packages/project-context-node/src/index.ts +3 -0
  249. package/packages/{cli → project-context-node}/src/runtime-selection.ts +7 -2
  250. package/packages/provider-hyperframes-local/README.md +43 -15
  251. package/packages/provider-hyperframes-local/src/activation.ts +4 -3
  252. package/packages/provider-hyperframes-local/src/capture-process.ts +26 -4
  253. package/packages/provider-hyperframes-local/src/capture.ts +96 -26
  254. package/packages/provider-hyperframes-local/src/concurrency.ts +86 -0
  255. package/packages/provider-hyperframes-local/src/opaque-capture.ts +92 -0
  256. package/packages/provider-hyperframes-local/src/options.ts +2 -0
  257. package/packages/provider-hyperframes-local/src/program.ts +6 -3
  258. package/packages/provider-hyperframes-local/src/progress.ts +53 -0
  259. package/packages/provider-hyperframes-local/src/provider.ts +18 -5
  260. package/packages/provider-hyperframes-local/src/render.ts +48 -7
  261. package/packages/provider-hypihub/README.md +48 -17
  262. package/packages/provider-hypihub/package.json +2 -0
  263. package/packages/provider-hypihub/src/mapping.ts +31 -7
  264. package/packages/provider-hypihub/src/oauth.ts +6 -0
  265. package/packages/provider-hypihub/src/provider.ts +25 -13
  266. package/packages/provider-hypihub/src/routes.ts +1 -2
  267. package/packages/provider-hypihub/src/upload.ts +2 -0
  268. package/packages/provider-media-local/README.md +3 -4
  269. package/packages/provider-whisperx-local/README.md +57 -0
  270. package/packages/provider-whisperx-local/src/program.ts +1 -0
  271. package/packages/provider-whisperx-local/src/provider.ts +3 -0
  272. package/packages/ranking/README.md +8 -6
  273. package/packages/ranking/package.json +1 -1
  274. package/packages/ranking/src/component.ts +6 -6
  275. package/packages/ranking/src/fragment.ts +11 -7
  276. package/packages/ranking/src/manifest.ts +21 -14
  277. package/packages/ranking/src/render.ts +33 -35
  278. package/packages/ranking/src/schedule.ts +16 -19
  279. package/packages/ranking/src/surface.ts +12 -13
  280. package/packages/ranking-studio/README.md +29 -0
  281. package/packages/ranking-studio/package.json +8 -3
  282. package/packages/ranking-studio/src/index.ts +71 -12
  283. package/packages/render-hyperframes/README.md +7 -7
  284. package/packages/render-hyperframes/package.json +1 -1
  285. package/packages/render-hyperframes/src/component.ts +11 -1
  286. package/packages/render-hyperframes/src/fragment.ts +7 -4
  287. package/packages/render-hyperframes/src/manifest.ts +4 -4
  288. package/packages/render-hyperframes/src/surface.ts +6 -6
  289. package/packages/runtime/README.md +8 -1
  290. package/packages/runtime/src/catalog.ts +2 -0
  291. package/packages/runtime/src/execution.ts +15 -4
  292. package/packages/runtime/src/index.ts +2 -1
  293. package/packages/runtime/src/log.ts +51 -0
  294. package/packages/runtime/src/types.ts +5 -8
  295. package/packages/runtime-host-node/README.md +30 -0
  296. package/packages/runtime-host-node/package.json +1 -0
  297. package/packages/runtime-host-node/src/index.ts +25 -9
  298. package/packages/runtime-host-node/src/packages.ts +47 -50
  299. package/packages/runtime-kit/README.md +5 -0
  300. package/packages/runtime-kit/src/index.ts +3 -1
  301. package/packages/runtime-local/README.md +111 -4
  302. package/packages/runtime-local/src/config.ts +202 -56
  303. package/packages/runtime-local/src/control.ts +9 -1
  304. package/packages/runtime-local/src/executor.ts +66 -0
  305. package/packages/runtime-local/src/host.ts +37 -17
  306. package/packages/runtime-local/src/log.ts +48 -0
  307. package/packages/runtime-local/src/programs.ts +41 -25
  308. package/packages/runtime-local/src/result-writer.ts +2 -0
  309. package/packages/runtime-local/src/runtime.ts +10 -6
  310. package/packages/runtime-local/src/supervisor.ts +142 -0
  311. package/packages/runtime-local/src/types.ts +9 -2
  312. package/packages/runtime-local/src/worker-process.ts +7 -24
  313. package/packages/runtime-local/src/worker.ts +55 -83
  314. package/packages/screen-overlay/README.md +3 -3
  315. package/packages/screen-overlay/package.json +1 -1
  316. package/packages/screen-overlay/src/component.ts +3 -3
  317. package/packages/screen-overlay/src/fragment.ts +5 -4
  318. package/packages/screen-overlay/src/manifest.ts +7 -6
  319. package/packages/screen-overlay/src/program.ts +9 -9
  320. package/packages/screen-overlay/src/surface.ts +6 -7
  321. package/packages/script/README.md +37 -2
  322. package/packages/script/src/edit.ts +123 -73
  323. package/packages/script/src/lexical.ts +40 -6
  324. package/packages/script/src/manifest.ts +2 -2
  325. package/packages/script/src/narrative.ts +1 -0
  326. package/packages/script/src/parser.ts +36 -8
  327. package/packages/script/src/surface.ts +4 -3
  328. package/packages/script/src/types.ts +5 -1
  329. package/packages/script-studio/package.json +9 -3
  330. package/packages/script-studio/src/index.ts +2 -0
  331. package/packages/script-studio/src/projection.ts +105 -0
  332. package/packages/seedance/README.md +30 -1
  333. package/packages/seedance/src/index.ts +18 -7
  334. package/packages/seedance/src/surface.ts +17 -4
  335. package/packages/seedance-kits/README.md +10 -2
  336. package/packages/seedance-kits/kits/speaker-v1.svs +5 -5
  337. package/packages/seedream/README.md +1 -1
  338. package/packages/sound/README.md +81 -0
  339. package/packages/sound/package.json +25 -0
  340. package/packages/sound/src/activation.ts +11 -0
  341. package/packages/sound/src/component.ts +28 -0
  342. package/packages/sound/src/index.ts +5 -0
  343. package/packages/sound/src/manifest.ts +47 -0
  344. package/packages/sound/src/program.ts +84 -0
  345. package/packages/sound/src/style.ts +34 -0
  346. package/packages/sound/src/surface.ts +90 -0
  347. package/packages/sound-studio/README.md +22 -0
  348. package/packages/sound-studio/package.json +20 -0
  349. package/packages/sound-studio/src/activation.ts +6 -0
  350. package/packages/sound-studio/src/index.ts +74 -0
  351. package/packages/speech/README.md +2 -2
  352. package/packages/speech-alignment/src/align.ts +45 -21
  353. package/packages/speech-alignment/src/local.ts +8 -0
  354. package/packages/speech-alignment/src/locate.ts +1 -1
  355. package/packages/store-sqlite/README.md +7 -0
  356. package/packages/store-sqlite/src/store.ts +84 -83
  357. package/packages/studio/INSPECTOR.md +117 -0
  358. package/packages/studio/README.md +149 -14
  359. package/packages/studio/package.json +8 -7
  360. package/packages/studio/src/build-library.ts +99 -84
  361. package/packages/studio/src/companion-assembly.ts +1 -0
  362. package/packages/studio/src/domain.ts +1 -1
  363. package/packages/studio/src/fallback-companions.ts +3 -3
  364. package/packages/studio/src/feedback-server.ts +51 -0
  365. package/packages/studio/src/feedback-store.ts +66 -0
  366. package/packages/studio/src/feedback.ts +60 -0
  367. package/packages/studio/src/library-media.ts +19 -0
  368. package/packages/studio/src/parameter-values.ts +83 -1
  369. package/packages/studio/src/parameters.ts +132 -43
  370. package/packages/studio/src/preview/render.ts +5 -1
  371. package/packages/studio/src/preview/runtime-shim.ts +49 -3
  372. package/packages/studio/src/programme.ts +14 -30
  373. package/packages/studio/src/server.ts +66 -34
  374. package/packages/studio/src/shared.ts +24 -8
  375. package/packages/studio/src/snapshot.ts +21 -132
  376. package/packages/studio/src/studio-preflight.ts +3 -3
  377. package/packages/studio/src/studio-registry.ts +72 -6
  378. package/packages/studio/src/style.css +342 -190
  379. package/packages/studio/src/temporal-edit.ts +131 -0
  380. package/packages/studio/src/ui/artifact-name.ts +80 -0
  381. package/packages/studio/src/ui/artifact-preview.ts +99 -0
  382. package/packages/studio/src/ui/comments.ts +233 -0
  383. package/packages/studio/src/ui/icons.ts +10 -1
  384. package/packages/studio/src/ui/library.ts +373 -192
  385. package/packages/studio/src/ui/main.ts +291 -110
  386. package/packages/studio/src/ui/material-preview.ts +1 -1
  387. package/packages/studio/src/ui/overlay.ts +31 -26
  388. package/packages/studio/src/ui/scrub-preview.ts +108 -0
  389. package/packages/studio/src/ui/sidebar-panel.ts +31 -0
  390. package/packages/studio/src/ui/stage.ts +188 -9
  391. package/packages/studio/src/ui/timeline.ts +187 -281
  392. package/packages/studio/start.ts +19 -5
  393. package/packages/studio-adapter/README.md +151 -11
  394. package/packages/studio-adapter/src/index.ts +126 -14
  395. package/packages/temporal/README.md +6 -6
  396. package/packages/temporal/package.json +1 -1
  397. package/packages/temporal/src/component.ts +5 -6
  398. package/packages/temporal/src/index.ts +8 -6
  399. package/packages/temporal/src/location.ts +11 -11
  400. package/packages/temporal/src/projection.ts +19 -19
  401. package/packages/temporal/src/rational.ts +4 -4
  402. package/packages/temporal-markup/EDITING.md +183 -0
  403. package/packages/temporal-markup/README.md +31 -11
  404. package/packages/temporal-markup/package.json +1 -1
  405. package/packages/temporal-markup/src/index.ts +20 -25
  406. package/packages/temporal-markup/src/space.ts +10 -41
  407. package/packages/timeline/README.md +31 -0
  408. package/packages/{semantic-track → timeline}/package.json +1 -1
  409. package/packages/timeline/src/activation.ts +8 -0
  410. package/packages/timeline/src/component.ts +24 -0
  411. package/packages/timeline/src/identity.ts +60 -0
  412. package/packages/timeline/src/index.ts +6 -0
  413. package/packages/{semantic-track → timeline}/src/location.ts +20 -20
  414. package/packages/timeline/src/manifest.ts +39 -0
  415. package/packages/{semantic-track → timeline}/src/projection.ts +14 -14
  416. package/packages/timeline/src/types.ts +24 -0
  417. package/packages/timeline-author/README.md +68 -0
  418. package/packages/{speech-track → timeline-author}/package.json +6 -4
  419. package/packages/timeline-author/src/activation.ts +22 -0
  420. package/packages/{speech-track → timeline-author}/src/component.ts +15 -13
  421. package/packages/{speech-track → timeline-author}/src/fragment.ts +14 -23
  422. package/packages/timeline-author/src/index.ts +7 -0
  423. package/packages/timeline-author/src/manifest.ts +78 -0
  424. package/packages/timeline-author/src/program.ts +107 -0
  425. package/packages/timeline-author/src/surface.ts +46 -0
  426. package/packages/timeline-author/src/types.ts +6 -0
  427. package/packages/typography-track/README.md +4 -4
  428. package/packages/typography-track/package.json +1 -1
  429. package/packages/typography-track/src/component.ts +4 -4
  430. package/packages/typography-track/src/fragment.ts +4 -3
  431. package/packages/typography-track/src/manifest.ts +11 -9
  432. package/packages/typography-track/src/program.ts +15 -15
  433. package/packages/typography-track/src/surface.ts +17 -18
  434. package/packages/typography-track-studio/package.json +8 -3
  435. package/packages/typography-track-studio/src/index.ts +5 -1
  436. package/packages/video-cli/README.md +16 -4
  437. package/packages/video-cli/package.json +2 -1
  438. package/packages/video-cli/src/creation.ts +25 -9
  439. package/packages/video-cli/src/index.ts +1 -1
  440. package/packages/video-cli/src/studio-distribution.ts +2 -1
  441. package/packages/volcengine-matting/README.md +3 -3
  442. package/packages/whisperx/README.md +8 -1
  443. package/packages/workspace/src/index.ts +2 -0
  444. package/packages/workspace-fs-node/README.md +4 -1
  445. package/packages/workspace-fs-node/src/workspace.ts +3 -1
  446. package/services/whisperx/README.md +14 -0
  447. package/services/whisperx/pyproject.toml +2 -0
  448. package/services/whisperx/uv.lock +20 -20
  449. package/packages/provider-hyperframes-aws-lambda/README.md +0 -30
  450. package/packages/provider-hyperframes-aws-lambda/package.json +0 -30
  451. package/packages/provider-hyperframes-aws-lambda/src/activation.ts +0 -97
  452. package/packages/provider-hyperframes-aws-lambda/src/client.ts +0 -114
  453. package/packages/provider-hyperframes-aws-lambda/src/index.ts +0 -21
  454. package/packages/provider-hyperframes-aws-lambda/src/provider.ts +0 -522
  455. package/packages/provider-kie/README.md +0 -134
  456. package/packages/provider-kie/package.json +0 -43
  457. package/packages/provider-kie/src/activation.ts +0 -71
  458. package/packages/provider-kie/src/index.ts +0 -10
  459. package/packages/provider-kie/src/mapping.ts +0 -182
  460. package/packages/provider-kie/src/provider.ts +0 -657
  461. package/packages/provider-kie/src/routes.ts +0 -150
  462. package/packages/provider-xiaomi-mimo/README.md +0 -32
  463. package/packages/provider-xiaomi-mimo/src/activation.ts +0 -57
  464. package/packages/provider-xiaomi-mimo/src/index.ts +0 -5
  465. package/packages/provider-xiaomi-mimo/src/provider.ts +0 -214
  466. package/packages/runtime/src/environment.ts +0 -6
  467. package/packages/semantic-track/README.md +0 -21
  468. package/packages/semantic-track/src/activation.ts +0 -8
  469. package/packages/semantic-track/src/component.ts +0 -24
  470. package/packages/semantic-track/src/identity.ts +0 -58
  471. package/packages/semantic-track/src/index.ts +0 -6
  472. package/packages/semantic-track/src/manifest.ts +0 -38
  473. package/packages/semantic-track/src/types.ts +0 -26
  474. package/packages/speech-track/README.md +0 -51
  475. package/packages/speech-track/src/activation.ts +0 -19
  476. package/packages/speech-track/src/index.ts +0 -7
  477. package/packages/speech-track/src/manifest.ts +0 -73
  478. package/packages/speech-track/src/program.ts +0 -64
  479. package/packages/speech-track/src/surface.ts +0 -35
  480. package/packages/speech-track/src/types.ts +0 -6
  481. package/packages/speech-track-studio/README.md +0 -3
  482. package/packages/speech-track-studio/package.json +0 -14
  483. package/packages/speech-track-studio/src/activation.ts +0 -7
  484. package/packages/speech-track-studio/src/index.ts +0 -40
  485. /package/packages/{cli → project-context-node}/src/project-context.ts +0 -0
  486. /package/packages/{speech-track → timeline-author}/preview/Track.png +0 -0
@@ -1,7 +1,7 @@
1
+ import type { Timeline } from "@hypit/timeline";
1
2
  import type { CaptionProgram, TimedCaptionProjection } from "@hypit/caption";
2
3
  import type { ComponentPackage } from "@hypit/component-kit";
3
4
  import type { CaptionDocument } from "@hypit/narrative";
4
- import type { ProgramSpace } from "@hypit/program-space";
5
5
  import type { StoredValue } from "@hypit/protocol";
6
6
  import { canonicalize } from "@hypit/protocol";
7
7
  import type { SpatialRegionTimeline } from "@hypit/spatial";
@@ -36,7 +36,7 @@ export const captionFineComponent = {
36
36
  inline<FineCaptionSchedule>(inputs.schedule?.value, "FineCaptionSchedule"),
37
37
  inline<CaptionProgram>(inputs.program?.value, "CaptionProgram"),
38
38
  inline<CaptionDocument>(inputs.document?.value, "CaptionDocument"),
39
- inline<ProgramSpace>(inputs.space?.value, "ProgramSpace"),
39
+ inline<Timeline>(inputs.timeline?.value, "Timeline"),
40
40
  )) } },
41
41
  needs: {},
42
42
  }),
@@ -48,7 +48,7 @@ export const captionFineComponent = {
48
48
  inline<FineCaptionSchedule>(inputs.schedule?.value, "FineCaptionSchedule"),
49
49
  inline<CaptionProgram>(inputs.program?.value, "CaptionProgram"),
50
50
  inline<CaptionDocument>(inputs.document?.value, "CaptionDocument"),
51
- inline<ProgramSpace>(inputs.space?.value, "ProgramSpace"),
51
+ inline<Timeline>(inputs.timeline?.value, "Timeline"),
52
52
  inline<SpatialRegionTimeline>(inputs.regions?.value, "SpatialRegionTimeline"),
53
53
  )) } },
54
54
  needs: {},
@@ -2,7 +2,7 @@ import { captionProducers, captionTypes } from "@hypit/caption";
2
2
  import { compositionTypes } from "@hypit/composition";
3
3
  import { sealGraphFragment } from "@hypit/elaborator";
4
4
  import { narrativeTypes } from "@hypit/narrative";
5
- import { semanticTrackProducers, semanticTrackTypes } from "@hypit/semantic-track";
5
+ import { timelineTypes } from "@hypit/timeline";
6
6
  import { spatialTypes } from "@hypit/spatial";
7
7
 
8
8
  import { captionFineProducers, captionFineTypes } from "./manifest.js";
@@ -14,21 +14,15 @@ const operation = (id: string) => ({ kind: "fragment-operation" as const, operat
14
14
  export const fineCaptionTrackFragment = sealGraphFragment({
15
15
  inputs: [
16
16
  { name: "document", type: narrativeTypes.captionDocument },
17
- { name: "semantic", type: semanticTrackTypes.track },
17
+ { name: "timeline", type: timelineTypes.track },
18
18
  { name: "program", type: captionTypes.program },
19
19
  ],
20
20
  operations: [
21
- {
22
- id: "caption:space",
23
- producer: semanticTrackProducers.projectProgramSpace,
24
- inputs: { track: input("semantic") },
25
- result: { kind: "output", name: "space" },
26
- },
27
21
  {
28
22
  id: "caption:temporalize-document",
29
23
  producer: captionProducers.temporalizeDocument,
30
24
  inputs: {
31
- document: input("document"), semantic: input("semantic"), program: input("program"),
25
+ document: input("document"), timeline: input("timeline"),
32
26
  },
33
27
  result: { kind: "output", name: "caption" },
34
28
  },
@@ -45,7 +39,7 @@ export const fineCaptionTrackFragment = sealGraphFragment({
45
39
  producer: captionFineProducers.render,
46
40
  inputs: {
47
41
  schedule: operation("caption-fine:schedule"), program: input("program"),
48
- document: input("document"), space: operation("caption:space"),
42
+ document: input("document"), timeline: input("timeline"),
49
43
  },
50
44
  result: { kind: "output", name: "track" },
51
45
  },
@@ -68,22 +62,16 @@ export const fineCaptionTrackFragment = sealGraphFragment({
68
62
  export const fineCaptionRegionTrackFragment = sealGraphFragment({
69
63
  inputs: [
70
64
  { name: "document", type: narrativeTypes.captionDocument },
71
- { name: "semantic", type: semanticTrackTypes.track },
65
+ { name: "timeline", type: timelineTypes.track },
72
66
  { name: "program", type: captionTypes.program },
73
67
  { name: "regions", type: spatialTypes.regionTimeline },
74
68
  ],
75
69
  operations: [
76
- {
77
- id: "caption:space",
78
- producer: semanticTrackProducers.projectProgramSpace,
79
- inputs: { track: input("semantic") },
80
- result: { kind: "output", name: "space" },
81
- },
82
70
  {
83
71
  id: "caption:temporalize-document",
84
72
  producer: captionProducers.temporalizeDocument,
85
73
  inputs: {
86
- document: input("document"), semantic: input("semantic"), program: input("program"),
74
+ document: input("document"), timeline: input("timeline"),
87
75
  },
88
76
  result: { kind: "output", name: "caption" },
89
77
  },
@@ -100,7 +88,7 @@ export const fineCaptionRegionTrackFragment = sealGraphFragment({
100
88
  producer: captionFineProducers.renderWithRegions,
101
89
  inputs: {
102
90
  schedule: operation("caption-fine:schedule"), program: input("program"),
103
- document: input("document"), space: operation("caption:space"), regions: input("regions"),
91
+ document: input("document"), timeline: input("timeline"), regions: input("regions"),
104
92
  },
105
93
  result: { kind: "output", name: "track" },
106
94
  },
@@ -17,3 +17,5 @@ export {
17
17
  } from "./style.js";
18
18
  export { decodeFineCaptionStyleSurface, decodeFineCaptionTrackSurface } from "./surface.js";
19
19
  export type * from "./types.js";
20
+
21
+ export { fineCaptionEditableDefaults } from "./recipe.js";
@@ -1,12 +1,15 @@
1
+ import { temporalDependency, temporalTypes } from "@hypit/temporal";
2
+ import { temporalWindowAttributeVocabulary } from "@hypit/temporal-markup";
3
+ import type { Timeline } from "@hypit/timeline";
1
4
  import { readFile } from "node:fs/promises";
2
5
 
3
6
  import { captionManifest, captionModuleRef, captionTypes } from "@hypit/caption";
4
7
  import { compositionDependency, compositionTypes } from "@hypit/composition";
5
8
  import { mediaDependency, mediaTypes } from "@hypit/media";
6
9
  import { narrativeDependency, narrativeTypes } from "@hypit/narrative";
7
- import { programSpaceDependency, programSpaceTypes } from "@hypit/program-space";
10
+
8
11
  import type { ModuleManifest, ProducerRef } from "@hypit/protocol";
9
- import { semanticTrackDependency, semanticTrackTypes } from "@hypit/semantic-track";
12
+ import { timelineDependency, timelineTypes } from "@hypit/timeline";
10
13
  import { spatialDependency, spatialTypes } from "@hypit/spatial";
11
14
  import { svsRecipeType } from "@hypit/svs";
12
15
 
@@ -35,7 +38,7 @@ export const captionFineMarkupSurfaces = [
35
38
  summary: "Resolves one SVS Recipe and one exact font stack into a complete fine-grained Caption Style.",
36
39
  attributes: [
37
40
  { name: "id", kind: "identifier", required: true,
38
- summary: "Names this Style so a Caption Program can assign it." },
41
+ summary: "Names this Style so a timed Use can select it." },
39
42
  { name: "recipe", kind: "reference", required: true, accepts: [svsRecipeType],
40
43
  summary: "Chooses the Recipe that carries Cue geometry, Paint and local motion.",
41
44
  recipe: [
@@ -206,7 +209,7 @@ export const captionFineMarkupSurfaces = [
206
209
  { name: "karaoke", required: false, values: ["off", "current", "trail"], fallback: "off",
207
210
  summary: "Decides whether the active Paint marks only the Word being spoken or every Word up to it." },
208
211
  { name: "karaoke-transition", required: false, values: ["step", "wipe"], fallback: "step",
209
- summary: "Decides whether the karaoke Paint snaps at the Word boundary or sweeps across the glyphs." },
212
+ summary: "step activates each whole timed unit at its start (normally one Han character in Chinese); wipe sweeps inside that unit's glyphs during its own interval." },
210
213
  { name: "active-box", required: false, values: ["off", "current", "trail"], fallback: "off",
211
214
  summary: "Decides whether a highlight box sits behind the Word being spoken or behind every Word up to it." },
212
215
  { name: "active-box-continuity", required: false, values: ["isolated", "joined"], fallback: "isolated",
@@ -295,9 +298,9 @@ export const captionFineMarkupSurfaces = [
295
298
  },
296
299
  },
297
300
  {
298
- name: "track", tag: "Track", mode: "structured", outputs: [captionFineTypes.schedule, compositionTypes.visualTrack],
301
+ name: "track", tag: "Track", mode: "structured", outputs: [captionFineTypes.schedule, compositionTypes.visualTrack, captionTypes.program, captionTypes.timedProjection, captionTypes.header, captionTypes.filter, temporalTypes.instantSpec, temporalTypes.windowSpec, temporalTypes.instant, temporalTypes.window],
299
302
  vocabulary: {
300
- summary: "Joins the authored CaptionDocument against the SemanticTrack and renders it as one ordinary peer VisualTrack.",
303
+ summary: "Joins the authored CaptionDocument against the Timeline and renders it as one ordinary peer VisualTrack.",
301
304
  appearance: "One block of caption text wrapped into lines inside a rounded Cue box, placed at a Recipe-chosen point on the Canvas and spanning a fraction of its width. Cues follow the speech one after another, each arriving and leaving with its own motion, and the Words of a Cue either stand there together from its first Frame or uncover as they are spoken. As the speech advances, the Word being spoken, or every Word up to it, is repainted in the active Paint, snapping at the Word boundary or sweeping across the glyphs, and it may take a rule beneath it, a rounded highlight capsule behind it and a brief pop at the moment it becomes the spoken one. That capsule either stands alone on each Atom or grows as one continuous run over everything already read, following the Words across line breaks.\n\nEvery Cue uses the ordered exact font stack its Style names, with fallback faces supplying glyphs for other scripts. Emphasis varies by timed unit through the active Paint. Lines follow the common flow, so a line cannot be given a separate face, colour or weight of its own. A caption whose lines are set in different typefaces is outside what this Track can draw.",
302
305
  preview: previewImage("Track.png"),
303
306
  attributes: [
@@ -305,23 +308,30 @@ export const captionFineMarkupSurfaces = [
305
308
  summary: "Names this Track so its rendered output can be placed in a Film." },
306
309
  { name: "document", kind: "reference", required: true, accepts: [narrativeTypes.captionDocument],
307
310
  summary: "Chooses the Script-owned CaptionDocument." },
308
- { name: "semantic", kind: "reference", required: true, accepts: [semanticTrackTypes.track],
309
- summary: "Chooses the continuous SemanticTrack whose Word anchors give every Cue its time." },
310
- { name: "program", kind: "reference", required: true, accepts: [captionTypes.program],
311
- summary: "Chooses the Style assignment that decides which Style each run is rendered in." },
311
+ { name: "timeline", kind: "reference", required: true, accepts: [timelineTypes.track],
312
+ summary: "Chooses the continuous Timeline whose Word anchors give every Cue its time." },
312
313
  { name: "regions", kind: "reference", required: false, accepts: [spatialTypes.regionTimeline],
313
314
  summary: "Optionally follows external, frame-exact regions whose ids equal Script Roles, placing a Cue at its measured speaker region's top center and hiding it on null Frames." },
314
315
  ],
316
+ children: [{ tag: "Use", cardinality: "many", summary: "Presents complete Cues inside a time window. Later matching Uses replace earlier ones.", attributes: [
317
+ { name: "id", kind: "identifier", required: false, summary: "Optional occurrence identity." },
318
+ { name: "style", kind: "reference", required: true, accepts: [captionTypes.style], summary: "Complete Caption Style, including Hidden." },
319
+ { name: "role", kind: "literal", required: false, summary: "Optional speaker filter, independent of the time window." },
320
+ ...temporalWindowAttributeVocabulary,
321
+ ] }],
315
322
  ports: [
316
323
  { name: "schedule", type: captionFineTypes.schedule,
317
324
  summary: "The visible Cue schedule consumed by the renderer and other declared tools." },
318
325
  { name: "track", type: compositionTypes.visualTrack,
319
326
  summary: "The rendered Caption as one self-contained VisualTrack." },
320
327
  ],
321
- example: `<caption-fine:Track id="captions" document={story.caption} semantic={speech.semantic} program={caption-program}/>`,
328
+ example: `<caption-fine:Track id="captions" document={story.caption} timeline={speech.timeline}>
329
+ <caption-fine:Use style={primary-caption}/>
330
+ <caption-fine:Use during={story.selection.answer} style={answer-caption}/>
331
+ </caption-fine:Track>`,
322
332
  notes: [
323
- "The element is empty; it accepts no children and no text.",
324
- "One Track renders the Program's default Style and every ordered replacement together.",
333
+ "Use without time attributes covers the whole Timeline. Role filters content without changing the window.",
334
+ "Script Cue breaks organize text; Use windows change presentation without cutting Cues or restarting word timing. A hidden Use still replaces earlier presentation.",
325
335
  "Without regions, Recipe x/y placement is unchanged. With regions, a measured region overrides x/y for that Frame; a null Frame on that Role track hides the Cue, while a missing Role track retains authored x/y.",
326
336
  "The tracked point replaces Recipe x/y while width and the Recipe anchor still decide the Caption box geometry; anchor-x=center and anchor-y=bottom place the box immediately above the measured region.",
327
337
  ],
@@ -339,9 +349,8 @@ export const captionFineManifest: ModuleManifest = {
339
349
  compositionDependency,
340
350
  mediaDependency,
341
351
  narrativeDependency,
342
- programSpaceDependency,
343
- semanticTrackDependency,
344
- spatialDependency,
352
+ timelineDependency,
353
+ spatialDependency, temporalDependency,
345
354
  ],
346
355
  types: [{ name: captionFineTypes.schedule.name }],
347
356
  capabilities: [],
@@ -362,7 +371,7 @@ export const captionFineManifest: ModuleManifest = {
362
371
  { name: "schedule", type: captionFineTypes.schedule },
363
372
  { name: "program", type: captionTypes.program },
364
373
  { name: "document", type: narrativeTypes.captionDocument },
365
- { name: "space", type: programSpaceTypes.programSpace },
374
+ { name: "timeline", type: timelineTypes.track },
366
375
  ],
367
376
  outputs: [{ name: "track", type: compositionTypes.visualTrack }],
368
377
  needs: [],
@@ -373,7 +382,7 @@ export const captionFineManifest: ModuleManifest = {
373
382
  { name: "schedule", type: captionFineTypes.schedule },
374
383
  { name: "program", type: captionTypes.program },
375
384
  { name: "document", type: narrativeTypes.captionDocument },
376
- { name: "space", type: programSpaceTypes.programSpace },
385
+ { name: "timeline", type: timelineTypes.track },
377
386
  { name: "regions", type: spatialTypes.regionTimeline },
378
387
  ],
379
388
  outputs: [{ name: "track", type: compositionTypes.visualTrack }],
@@ -118,3 +118,10 @@ export const fineCaptionRecipeSchema: ValueSchema = {
118
118
  required.has(name) ? { schema: schemaFor(name) } : { schema: schemaFor(name), optional: true },
119
119
  ])),
120
120
  };
121
+
122
+ /** Static authored defaults; dependent paint values retain their decoder relationships. */
123
+ export const fineCaptionEditableDefaults = {
124
+ opacity: 1, "stroke-width": 0, "shadow-opacity": 0, "glow-opacity": 0,
125
+ karaoke: "off", "karaoke-transition": "step", "active-box": "off",
126
+ "underline": "off", "active-underline": "off",
127
+ } as const;
@@ -1,3 +1,4 @@
1
+ import type { Timeline } from "@hypit/timeline";
1
2
  import { assertCaptionProgramForDocument } from "@hypit/caption";
2
3
  import type { CaptionProgram } from "@hypit/caption";
3
4
  import { assertVisualTrackIdentity, sealVisualTrack } from "@hypit/composition";
@@ -14,7 +15,6 @@ import type {
14
15
  } from "@hypit/composition";
15
16
  import type { CaptionAlignmentUnit, CaptionDocument } from "@hypit/narrative";
16
17
  import { assertProgramSpaceIdentity, programSpaceFrameCount } from "@hypit/program-space";
17
- import type { ProgramSpace } from "@hypit/program-space";
18
18
  import { assertSpatialRegionTimeline } from "@hypit/spatial";
19
19
  import type { CanvasSpace, SpatialFrame, SpatialRegionTimeline } from "@hypit/spatial";
20
20
 
@@ -480,23 +480,6 @@ function karaokeWipeAnimation(
480
480
  ] };
481
481
  }
482
482
 
483
- function typewriterAnimation(
484
- text: string,
485
- parameters: FineCaptionParameters,
486
- startFrame: number,
487
- endFrame: number,
488
- durationFrames: number,
489
- ): VisualAnimation | undefined {
490
- if (parameters.motion.atomReveal !== "typewriter") return undefined;
491
- const graphemes = Math.max(1, [...new Intl.Segmenter("und", { granularity: "grapheme" }).segment(text)].length);
492
- const span = Math.max(1, endFrame - startFrame);
493
- const offsets = Array.from({ length: graphemes + 1 }, (_, index) => startFrame + Math.round(span * index / graphemes));
494
- return animationFrom(durationFrames, [...stepOffsets(startFrame), ...offsets], (frame) => {
495
- const progress = frame < startFrame ? 0 : Math.floor(clamp((frame - startFrame) / span, 0, 1) * graphemes) / graphemes;
496
- return [{ name: "clip-path", value: wipeClip(progress, parameters.layout.direction) }];
497
- });
498
- }
499
-
500
483
  function activeResponseAnimation(
501
484
  parameters: FineCaptionParameters,
502
485
  startFrame: number,
@@ -656,7 +639,7 @@ function structuralRowCount(
656
639
 
657
640
  /**
658
641
  * Acoustic Word windows may overlap. Preserve those measurements in the
659
- * SemanticTrack, but give every current-only visual state one unambiguous
642
+ * Timeline, but give every current-only visual state one unambiguous
660
643
  * owner: as soon as the next authored unit starts, the previous one stops.
661
644
  */
662
645
  function exclusiveActivationFrames(
@@ -867,9 +850,7 @@ function cueElements(
867
850
  // the karaoke wipe keeps sitting on the letterforms it reveals.
868
851
  const gaps = wordGaps(surfaces);
869
852
  const wordGap = uniformGap(gaps);
870
- const atomText = joinSurfaces(surfaces, " ");
871
853
  const entryId = `${atomId}-entry`;
872
- const typewriterId = `${atomId}-typewriter`;
873
854
  const loopId = `${atomId}-loop`;
874
855
  const responseId = `${atomId}-response`;
875
856
  if (parameters.layout.maxWordsPerLine !== undefined
@@ -884,7 +865,6 @@ function cueElements(
884
865
  wordsOnLine = 0;
885
866
  }
886
867
  const entryAnimation = atomLifecycleAnimation(parameters, timing.start, timing.end, durationFrames);
887
- const writerAnimation = typewriterAnimation(atomText, parameters, timing.start, timing.end, durationFrames);
888
868
  const atomLoop = parameters.motion.loopTarget === "active-atom"
889
869
  ? loopAnimation(parameters, durationFrames, activationTiming) : undefined;
890
870
  const responseAnimation = activeResponseAnimation(
@@ -906,20 +886,9 @@ function cueElements(
906
886
  ],
907
887
  ...(entryAnimation === undefined ? {} : { animation: entryAnimation }),
908
888
  });
909
- push({
910
- id: typewriterId,
911
- parent: entryId,
912
- kind: "box",
913
- style: [
914
- { name: "display", value: "inline-flex" },
915
- { name: "min-width", value: "0" },
916
- { name: "transform-origin", value: parameters.layout.direction === "rtl" ? "right center" : "left center" },
917
- ],
918
- ...(writerAnimation === undefined ? {} : { animation: writerAnimation }),
919
- });
920
889
  push({
921
890
  id: loopId,
922
- parent: typewriterId,
891
+ parent: entryId,
923
892
  kind: "box",
924
893
  style: [
925
894
  { name: "display", value: "inline-flex" },
@@ -983,10 +952,53 @@ function cueElements(
983
952
  attributes: [{ name: "data-caption-active-box", value: "isolated" }],
984
953
  });
985
954
  }
955
+ const graphemes = parameters.motion.atomReveal === "typewriter"
956
+ ? surfaces.map((text) =>
957
+ [...new Intl.Segmenter("und", { granularity: "grapheme" }).segment(text)].map((part) => part.segment))
958
+ : [];
959
+ const graphemeCount = graphemes.reduce((sum, word) => sum + word.length, 0);
960
+ const pushText = (element: Omit<VisualTextElement, "order">, wordIndex: number): void => {
961
+ if (parameters.motion.atomReveal !== "typewriter") {
962
+ push(element);
963
+ return;
964
+ }
965
+ // Reveal complete glyphs, not fractions of a Word's width. Variable-width Latin letters,
966
+ // Han characters and combining sequences all retain their actual layout widths.
967
+ const isMargin = (name: string): boolean => name.startsWith("margin-");
968
+ push({
969
+ id: element.id,
970
+ ...(element.parent === undefined ? {} : { parent: element.parent }),
971
+ kind: "box",
972
+ style: [
973
+ { name: "display", value: "inline" },
974
+ { name: "min-width", value: "0" },
975
+ ...element.style.filter(({ name }) => isMargin(name) || name === "opacity"),
976
+ ],
977
+ ...(element.attributes === undefined ? {} : { attributes: element.attributes }),
978
+ });
979
+ const preceding = graphemes.slice(0, wordIndex).reduce((sum, word) => sum + word.length, 0);
980
+ const { attributes: _attributes, ...glyph } = element;
981
+ for (const [index, text] of (graphemes[wordIndex] ?? []).entries()) {
982
+ const revealFrame = timing.start + Math.floor(
983
+ (timing.end - timing.start) * (preceding + index) / Math.max(1, graphemeCount),
984
+ );
985
+ push({
986
+ ...glyph,
987
+ id: `${element.id}-grapheme-${index + 1}`,
988
+ parent: element.id,
989
+ text,
990
+ style: [
991
+ ...element.style.filter(({ name }) => !isMargin(name) && name !== "opacity"),
992
+ { name: "display", value: "inline" },
993
+ ],
994
+ animation: activationStepAnimation("trail", revealFrame, durationFrames, durationFrames),
995
+ });
996
+ }
997
+ };
986
998
  for (const [wordIndex, wordId] of atom.wordIds.entries()) {
987
999
  const text = wordText.get(wordId);
988
1000
  if (text === undefined) throw new Error(`Fine Caption Atom references unknown word ${wordId}`);
989
- push({
1001
+ pushText({
990
1002
  id: `${atomId}-base-${wordIndex + 1}`,
991
1003
  parent: atomId,
992
1004
  kind: "text",
@@ -997,7 +1009,7 @@ function cueElements(
997
1009
  ],
998
1010
  ...glyphPaintFields(parameters.basePaint),
999
1011
  fonts,
1000
- });
1012
+ }, wordIndex);
1001
1013
  }
1002
1014
  const addActivatedTextLayer = (
1003
1015
  suffix: string,
@@ -1026,7 +1038,7 @@ function cueElements(
1026
1038
  });
1027
1039
  for (const [wordIndex, wordId] of atom.wordIds.entries()) {
1028
1040
  const text = wordText.get(wordId)!;
1029
- push({
1041
+ pushText({
1030
1042
  id: `${activeId}-${wordIndex + 1}`,
1031
1043
  parent: activeId,
1032
1044
  kind: "text",
@@ -1041,7 +1053,7 @@ function cueElements(
1041
1053
  ...(kind === "glyph" ? glyphPaintFields(parameters.activePaint) : {}),
1042
1054
  fonts,
1043
1055
  attributes: [{ name: kind === "glyph" ? "data-caption-active-word" : "data-caption-underlined-word", value: wordId }],
1044
- });
1056
+ }, wordIndex);
1045
1057
  }
1046
1058
  };
1047
1059
  if (parameters.karaoke.mode !== "off") addActivatedTextLayer("active", parameters.karaoke.mode, "glyph");
@@ -1057,33 +1069,32 @@ export function renderFineCaption(
1057
1069
  schedule: FineCaptionSchedule,
1058
1070
  program: CaptionProgram,
1059
1071
  document: CaptionDocument,
1060
- space: ProgramSpace,
1072
+ timeline: Timeline,
1061
1073
  regions?: SpatialRegionTimeline,
1062
1074
  ): VisualTrack {
1063
1075
  assertFineCaptionSchedule(schedule);
1064
1076
  assertCaptionProgramForDocument(program, document);
1065
1077
  if (schedule.documentId !== document.id) throw new Error("Fine Caption received another CaptionDocument");
1066
- if (program.wordRuns.length !== 0) {
1067
- throw new Error("Fine Caption accepts one uniform token rule and cannot consume word-specific Style runs");
1068
- }
1069
- assertProgramSpaceIdentity(space);
1070
- if (schedule.spaceId !== space.id || schedule.narrativeId !== document.narrativeId) {
1071
- throw new Error("Fine Caption inputs belong to different ProgramSpaces or Narratives");
1078
+
1079
+ assertProgramSpaceIdentity(timeline);
1080
+ if (schedule.spaceId !== timeline.id || schedule.narrativeId !== document.narrativeId) {
1081
+ throw new Error("Fine Caption inputs belong to different Timelines or Narratives");
1072
1082
  }
1073
1083
  const styles = new Map(program.styles.map((style) => [style.id, style]));
1074
1084
  const wordText = new Map(document.words.map((word) => [word.id, word.text]));
1075
1085
  const atomById = new Map(document.units.map((atom) => [atom.id, atom]));
1076
1086
  for (const style of styles.values()) {
1087
+ if (style.rendering === null) continue;
1077
1088
  if (style.rendering.family !== FINE_CAPTION_FAMILY) {
1078
1089
  throw new Error(`Fine Caption cannot render Style family ${style.rendering.family}`);
1079
1090
  }
1080
1091
  assertFineCaptionParameters(style.rendering.parameters as unknown as FineCaptionParameters);
1081
1092
  }
1082
- const totalFrames = programSpaceFrameCount(space);
1093
+ const totalFrames = programSpaceFrameCount(timeline);
1083
1094
  const regionTracks = regions === undefined ? undefined : (() => {
1084
1095
  assertSpatialRegionTimeline(regions);
1085
1096
  if (regions.frameCount !== totalFrames) {
1086
- throw new Error(`Fine Caption regions cover ${regions.frameCount} Frames but ProgramSpace has ${totalFrames}`);
1097
+ throw new Error(`Fine Caption regions cover ${regions.frameCount} Frames but Timeline has ${totalFrames}`);
1087
1098
  }
1088
1099
  return new Map(regions.tracks.map((track) => [track.id, track]));
1089
1100
  })();
@@ -1093,6 +1104,7 @@ export function renderFineCaption(
1093
1104
  const resolvedAtoms = atoms.map((atom) => atom!);
1094
1105
  const style = styles.get(cue.styleId);
1095
1106
  if (style === undefined) throw new Error(`Fine Caption Cue ${cue.id} references unknown Style ${cue.styleId}`);
1107
+ if (style.rendering === null) return [];
1096
1108
  const parameters = style.rendering.parameters as unknown as FineCaptionParameters;
1097
1109
  const startFrame = Math.max(0, cue.visibleStartFrame);
1098
1110
  const measuredEnd = Math.min(totalFrames, cue.visibleEndFrameExclusive);
@@ -1118,16 +1130,17 @@ export function renderFineCaption(
1118
1130
  return [{
1119
1131
  id: cue.id,
1120
1132
  span: { startFrame, endFrameExclusive },
1133
+ visibility: cue.visibility,
1121
1134
  stacking: { order: parameters.stackingOrder, tieBreak: `${program.id}:${cue.id}` },
1122
1135
  elements: cueElements(resolvedAtoms, atomFrames, parameters, wordText, durationFrames, cue.styleId, trackedPlacement),
1123
1136
  }];
1124
1137
  });
1125
1138
  const track = sealVisualTrack({
1126
- programSpaceId: space.id,
1139
+ programSpaceId: timeline.id,
1127
1140
  visualIr: "hypit.visual-ir@1",
1128
1141
  id: program.id,
1129
1142
  presents,
1130
1143
  });
1131
- assertVisualTrackIdentity(track, space);
1144
+ assertVisualTrackIdentity(track, timeline);
1132
1145
  return track;
1133
1146
  }
@@ -1,4 +1,4 @@
1
- import { applyCaptionMute, assertCaptionProgramForDocument, assertTimedCaptionProjection } from "@hypit/caption";
1
+ import { assertCaptionProgramForDocument, assertTimedCaptionProjection, captionUseVisibility } from "@hypit/caption";
2
2
  import type { CaptionProgram, TimedCaptionProjection } from "@hypit/caption";
3
3
  import type { CaptionDocument } from "@hypit/narrative";
4
4
 
@@ -27,13 +27,11 @@ export function scheduleFineCaption(
27
27
  if (projection.narrativeId !== document.narrativeId) {
28
28
  throw new Error("Fine Caption Schedule received a CaptionDocument from another Narrative");
29
29
  }
30
- if (program.wordRuns.length !== 0) {
31
- throw new Error("Fine Caption accepts one uniform token rule and cannot consume word-specific Style runs");
32
- }
33
- const visibleProjection = applyCaptionMute(projection, program, document);
34
-
35
30
  const parameters = new Map<string, FineCaptionParameters>();
31
+ const activeStyles = new Set(program.uses.map(use => use.styleId));
36
32
  for (const style of program.styles) {
33
+ if (!activeStyles.has(style.id)) continue;
34
+ if (style.rendering === null) continue;
37
35
  if (style.rendering.family !== FINE_CAPTION_FAMILY) {
38
36
  throw new Error(`Fine Caption cannot schedule Style family ${style.rendering.family}`);
39
37
  }
@@ -42,39 +40,41 @@ export function scheduleFineCaption(
42
40
  parameters.set(style.id, value);
43
41
  }
44
42
 
45
- const desired = visibleProjection.cues.map((cue): FineCaptionScheduledCue => {
46
- const style = parameters.get(cue.styleId);
47
- if (style === undefined) throw new Error(`Fine Caption Cue ${cue.id} references unknown Style ${cue.styleId}`);
48
- const visibleStartFrame = Math.max(0, cue.startFrame - style.timing.leadFrames);
49
- const visibleEndFrameExclusive = cue.endFrameExclusive + style.timing.tailFrames;
50
- return {
51
- id: cue.id,
52
- styleId: cue.styleId,
53
- semanticStartFrame: cue.startFrame,
54
- semanticEndFrameExclusive: cue.endFrameExclusive,
55
- visibleStartFrame,
56
- visibleEndFrameExclusive,
57
- units: cue.units,
58
- };
59
- });
60
-
43
+ const units = new Map(document.units.map(unit => [unit.id, unit]));
61
44
  const cues: FineCaptionScheduledCue[] = [];
62
- for (const wanted of desired) {
63
- let cue = wanted;
64
- const previous = cues.at(-1);
65
- if (previous !== undefined) {
66
- const previousStyle = parameters.get(previous.styleId)!;
67
- const currentStyle = parameters.get(cue.styleId)!;
68
- if (previousStyle.timing.handoff === "cut" || currentStyle.timing.handoff === "cut") {
69
- const previousEnd = Math.max(
70
- previous.semanticEndFrameExclusive,
71
- Math.min(previous.visibleEndFrameExclusive, cue.semanticStartFrame),
72
- );
73
- cues[cues.length - 1] = { ...previous, visibleEndFrameExclusive: previousEnd };
45
+ for (const [index, use] of program.uses.entries()) {
46
+ if (use.window.start.source.spaceId !== projection.spaceId) throw new Error("Caption Use belongs to another Timeline");
47
+ const style = parameters.get(use.styleId);
48
+ if (style === undefined) continue; // Hidden still participates in coverage below.
49
+ const desired = projection.cues.filter(cue => use.role === undefined || units.get(cue.units[0]!.unitId)?.role === use.role).map((cue): FineCaptionScheduledCue => ({
50
+ id: `${use.window.subjectId}:${cue.id}`, cueId: cue.id, styleId: use.styleId,
51
+ semanticStartFrame: cue.startFrame, semanticEndFrameExclusive: cue.endFrameExclusive,
52
+ visibleStartFrame: Math.max(0, cue.startFrame - style.timing.leadFrames),
53
+ visibleEndFrameExclusive: cue.endFrameExclusive + style.timing.tailFrames,
54
+ units: cue.units, visibility: [],
55
+ }));
56
+ // Resolve each speaker's ordinary Cue handoff before masking by Use windows.
57
+ desired.sort((a, b) => a.semanticStartFrame - b.semanticStartFrame);
58
+ const previousByRole = new Map<string | undefined, number>();
59
+ const envelopes: FineCaptionScheduledCue[] = [];
60
+ for (const wanted of desired) {
61
+ let cue = wanted;
62
+ const role = units.get(cue.units[0]!.unitId)?.role;
63
+ const previousIndex = previousByRole.get(role);
64
+ const previous = previousIndex === undefined ? undefined : envelopes[previousIndex];
65
+ if (previous !== undefined && style.timing.handoff === "cut" && previous.semanticEndFrameExclusive <= cue.semanticStartFrame) {
66
+ const previousEnd = Math.max(previous.semanticEndFrameExclusive, Math.min(previous.visibleEndFrameExclusive, cue.semanticStartFrame));
67
+ envelopes[previousIndex!] = { ...previous, visibleEndFrameExclusive: previousEnd };
74
68
  cue = { ...cue, visibleStartFrame: Math.min(cue.semanticStartFrame, Math.max(cue.visibleStartFrame, previousEnd)) };
75
69
  }
70
+ previousByRole.set(role, envelopes.length);
71
+ envelopes.push(cue);
72
+ }
73
+ for (const cue of envelopes) {
74
+ const role = units.get(cue.units[0]!.unitId)?.role;
75
+ const visibility = captionUseVisibility(program, index, role, { startFrame: cue.visibleStartFrame, endFrameExclusive: cue.visibleEndFrameExclusive });
76
+ if (visibility.length) cues.push({ ...cue, visibility });
76
77
  }
77
- cues.push(cue);
78
78
  }
79
79
 
80
80
  const ids = new Set<string>();
@@ -110,6 +110,10 @@ export function assertFineCaptionSchedule(value: FineCaptionSchedule): void {
110
110
  throw new Error("Fine Caption Schedule contains an invalid Cue");
111
111
  }
112
112
  ids.add(cue.id);
113
+ if (!cue.cueId || cue.visibility.length === 0 || cue.visibility.some(span =>
114
+ !Number.isSafeInteger(span.startFrame) || !Number.isSafeInteger(span.endFrameExclusive)
115
+ || span.startFrame < cue.visibleStartFrame || span.endFrameExclusive > cue.visibleEndFrameExclusive
116
+ || span.endFrameExclusive <= span.startFrame)) throw new Error("Fine Caption visibility is invalid");
113
117
  for (const [label, frame] of [
114
118
  ["semantic start", cue.semanticStartFrame],
115
119
  ["semantic end", cue.semanticEndFrameExclusive],
@@ -8,6 +8,7 @@ import type { SvsRecipe } from "@hypit/svs";
8
8
  import type { FineCaptionGlyphPaint, FineCaptionParameters } from "./types.js";
9
9
  import {
10
10
  fineCaptionOneShotMotions,
11
+ fineCaptionEditableDefaults,
11
12
  fineCaptionOptionalRecipeProperties,
12
13
  fineCaptionRequiredRecipeProperties,
13
14
  } from "./recipe.js";
@@ -104,14 +105,14 @@ function glyphPaint(recipe: SvsRecipe, prefix: "" | "active-", base?: FineCaptio
104
105
  return {
105
106
  fill: color(recipe, `${prefix}fill`, prefix === "active-" ? "#FFD54A" : base?.fill),
106
107
  ...(gradient === undefined ? {} : { gradient }),
107
- opacity: number(recipe, `${prefix}opacity`, base?.opacity ?? 1),
108
+ opacity: number(recipe, `${prefix}opacity`, base?.opacity ?? fineCaptionEditableDefaults.opacity),
108
109
  stroke: {
109
110
  color: color(recipe, `${prefix}stroke-color`, baseStroke?.color ?? "#000000"),
110
- widthPx: number(recipe, `${prefix}stroke-width`, baseStroke?.widthPx ?? 0),
111
+ widthPx: number(recipe, `${prefix}stroke-width`, baseStroke?.widthPx ?? fineCaptionEditableDefaults["stroke-width"]),
111
112
  },
112
113
  shadow: {
113
114
  color: color(recipe, `${prefix}shadow-color`, baseShadow?.color ?? "#000000"),
114
- opacity: number(recipe, `${prefix}shadow-opacity`, baseShadow?.opacity ?? 0),
115
+ opacity: number(recipe, `${prefix}shadow-opacity`, baseShadow?.opacity ?? fineCaptionEditableDefaults["shadow-opacity"]),
115
116
  offsetXPx: number(recipe, `${prefix}shadow-x`, baseShadow?.offsetXPx ?? 0),
116
117
  offsetYPx: number(recipe, `${prefix}shadow-y`, baseShadow?.offsetYPx ?? 0),
117
118
  blurPx: number(recipe, `${prefix}shadow-blur`, baseShadow?.blurPx ?? 0),
@@ -125,7 +126,7 @@ function glyphPaint(recipe: SvsRecipe, prefix: "" | "active-", base?: FineCaptio
125
126
  },
126
127
  glow: {
127
128
  color: color(recipe, `${prefix}glow-color`, baseGlow?.color ?? "#FFFFFF"),
128
- opacity: number(recipe, `${prefix}glow-opacity`, baseGlow?.opacity ?? 0),
129
+ opacity: number(recipe, `${prefix}glow-opacity`, baseGlow?.opacity ?? fineCaptionEditableDefaults["glow-opacity"]),
129
130
  blurPx: number(recipe, `${prefix}glow-blur`, baseGlow?.blurPx ?? 0),
130
131
  spreadPx: number(recipe, `${prefix}glow-spread`, baseGlow?.spreadPx ?? 0),
131
132
  },
@@ -216,13 +217,13 @@ export function fineCaptionParameters(
216
217
  basePaint,
217
218
  activePaint: glyphPaint(recipe, "active-", basePaint),
218
219
  underline: {
219
- mode: choice(recipe, "underline", ["off", "always"] as const, "off"),
220
+ mode: choice(recipe, "underline", ["off", "always"] as const, fineCaptionEditableDefaults["underline"]),
220
221
  color: color(recipe, "underline-color", basePaint.fill),
221
222
  thicknessPx: number(recipe, "underline-thickness", 2),
222
223
  offsetPx: number(recipe, "underline-offset", 4),
223
224
  },
224
225
  activeUnderline: {
225
- mode: choice(recipe, "active-underline", ["off", "current", "trail"] as const, "off"),
226
+ mode: choice(recipe, "active-underline", ["off", "current", "trail"] as const, fineCaptionEditableDefaults["active-underline"]),
226
227
  color: color(recipe, "active-underline-color", "#FFD54A"),
227
228
  thicknessPx: number(recipe, "active-underline-thickness", 3),
228
229
  offsetPx: number(recipe, "active-underline-offset", 4),
@@ -244,11 +245,11 @@ export function fineCaptionParameters(
244
245
  },
245
246
  },
246
247
  karaoke: {
247
- mode: choice(recipe, "karaoke", ["off", "current", "trail"] as const, "off"),
248
- transition: choice(recipe, "karaoke-transition", ["step", "wipe"] as const, "step"),
248
+ mode: choice(recipe, "karaoke", ["off", "current", "trail"] as const, fineCaptionEditableDefaults["karaoke"]),
249
+ transition: choice(recipe, "karaoke-transition", ["step", "wipe"] as const, fineCaptionEditableDefaults["karaoke-transition"]),
249
250
  },
250
251
  activeBox: {
251
- mode: choice(recipe, "active-box", ["off", "current", "trail"] as const, "off"),
252
+ mode: choice(recipe, "active-box", ["off", "current", "trail"] as const, fineCaptionEditableDefaults["active-box"]),
252
253
  continuity: choice(recipe, "active-box-continuity", ["isolated", "joined"] as const, "isolated"),
253
254
  background: color(recipe, "active-box-background", "#FFD54A"),
254
255
  borderColor: color(recipe, "active-box-border-color", "#00000000"),