@hypit/hypit 0.0.1 → 0.1.0

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 (962) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +203 -0
  3. package/README.zh-CN.md +195 -0
  4. package/bin/hypit.mjs +46 -0
  5. package/dist/public/artifact.d.ts +75 -0
  6. package/dist/public/author-kit.d.ts +559 -0
  7. package/dist/public/browser-capture.d.ts +56 -0
  8. package/dist/public/caption.d.ts +751 -0
  9. package/dist/public/composition.d.ts +672 -0
  10. package/dist/public/endpoint-kit.d.ts +366 -0
  11. package/dist/public/generation.d.ts +591 -0
  12. package/dist/public/hyperframes.d.ts +774 -0
  13. package/dist/public/media.d.ts +708 -0
  14. package/dist/public/model-kit.d.ts +523 -0
  15. package/dist/public/narrative.d.ts +315 -0
  16. package/dist/public/program-space.d.ts +193 -0
  17. package/dist/public/runtime-kit.d.ts +427 -0
  18. package/dist/public/semantic-track.d.ts +418 -0
  19. package/dist/public/spatial.d.ts +1193 -0
  20. package/dist/public/speech.d.ts +391 -0
  21. package/dist/public/studio-adapter.d.ts +686 -0
  22. package/dist/public/svs.d.ts +311 -0
  23. package/dist/public/temporal-markup.d.ts +343 -0
  24. package/dist/public/temporal.d.ts +497 -0
  25. package/dist/public/text.d.ts +817 -0
  26. package/dist/public/visual-ir.d.ts +98 -0
  27. package/docs/public/hypit-logo-dark.svg +36 -0
  28. package/docs/public/hypit-logo-light.svg +38 -0
  29. package/examples/README.md +24 -0
  30. package/examples/minimal-author-package/README.md +18 -0
  31. package/examples/minimal-author-package/packages/example-component/README.md +44 -0
  32. package/examples/minimal-author-package/packages/example-component/package.json +27 -0
  33. package/examples/minimal-author-package/packages/example-component/preview/Box.png +0 -0
  34. package/examples/minimal-author-package/packages/example-component/preview/build.svrun +6 -0
  35. package/examples/minimal-author-package/packages/example-component/preview/preview.svml +47 -0
  36. package/examples/minimal-author-package/packages/example-component/preview/recipes.svs +8 -0
  37. package/examples/minimal-author-package/packages/example-component/src/activation.ts +10 -0
  38. package/examples/minimal-author-package/packages/example-component/src/component.ts +44 -0
  39. package/examples/minimal-author-package/packages/example-component/src/fragment.ts +32 -0
  40. package/examples/minimal-author-package/packages/example-component/src/index.ts +6 -0
  41. package/examples/minimal-author-package/packages/example-component/src/manifest.ts +82 -0
  42. package/examples/minimal-author-package/packages/example-component/src/style.ts +13 -0
  43. package/examples/minimal-author-package/packages/example-component/src/surface.ts +41 -0
  44. package/examples/minimal-author-package/packages/example-component/src/temporal.ts +6 -0
  45. package/examples/minimal-author-package/packages/example-component/tsconfig.json +18 -0
  46. package/examples/semantic-composition/README.md +35 -0
  47. package/examples/semantic-composition/chat.svml +25 -0
  48. package/examples/semantic-composition/chat.svrun +6 -0
  49. package/examples/semantic-composition/chat.svs +4 -0
  50. package/examples/semantic-composition/hypit.runtime.json +8 -0
  51. package/examples/semantic-composition/packages/chat-scene/README.md +29 -0
  52. package/examples/semantic-composition/packages/chat-scene/package.json +11 -0
  53. package/examples/semantic-composition/packages/chat-scene/src/activation.ts +112 -0
  54. package/examples/semantic-composition/packages/chat-scene/src/render.ts +64 -0
  55. package/examples/semantic-composition/packages/chat-scene/tsconfig.json +18 -0
  56. package/examples/semantic-composition/packages/responsive-explainer/README.md +45 -0
  57. package/examples/semantic-composition/packages/responsive-explainer/package.json +11 -0
  58. package/examples/semantic-composition/packages/responsive-explainer/src/activation.ts +90 -0
  59. package/examples/semantic-composition/packages/responsive-explainer/src/render.ts +68 -0
  60. package/examples/semantic-composition/packages/responsive-explainer/tsconfig.json +18 -0
  61. package/package.json +259 -7
  62. package/packages/artifact/README.md +10 -0
  63. package/packages/artifact/package.json +16 -0
  64. package/packages/artifact/src/activation.ts +8 -0
  65. package/packages/artifact/src/index.ts +24 -0
  66. package/packages/audio-track/README.md +43 -0
  67. package/packages/audio-track/package.json +36 -0
  68. package/packages/audio-track/src/activation.ts +20 -0
  69. package/packages/audio-track/src/component.ts +40 -0
  70. package/packages/audio-track/src/fragment.ts +63 -0
  71. package/packages/audio-track/src/index.ts +7 -0
  72. package/packages/audio-track/src/manifest.ts +151 -0
  73. package/packages/audio-track/src/program.ts +254 -0
  74. package/packages/audio-track/src/surface.ts +187 -0
  75. package/packages/audio-track/src/types.ts +62 -0
  76. package/packages/audio-track-studio/README.md +3 -0
  77. package/packages/audio-track-studio/package.json +14 -0
  78. package/packages/audio-track-studio/src/activation.ts +7 -0
  79. package/packages/audio-track-studio/src/index.ts +72 -0
  80. package/packages/author-kit/README.md +31 -0
  81. package/packages/author-kit/package.json +16 -0
  82. package/packages/author-kit/src/index.ts +59 -0
  83. package/packages/background-removal/README.md +29 -0
  84. package/packages/background-removal/package.json +16 -0
  85. package/packages/background-removal/src/activation.ts +18 -0
  86. package/packages/background-removal/src/component.ts +32 -0
  87. package/packages/background-removal/src/fragment.ts +18 -0
  88. package/packages/background-removal/src/index.ts +6 -0
  89. package/packages/background-removal/src/manifest.ts +45 -0
  90. package/packages/background-removal/src/program.ts +19 -0
  91. package/packages/background-removal/src/surface.ts +27 -0
  92. package/packages/background-removal/src/types.ts +5 -0
  93. package/packages/browser-capture/README.md +82 -0
  94. package/packages/browser-capture/package.json +15 -0
  95. package/packages/browser-capture/src/browser.ts +19 -0
  96. package/packages/browser-capture/src/index.ts +198 -0
  97. package/packages/build-result/package.json +13 -0
  98. package/packages/build-result/src/decode.ts +286 -0
  99. package/packages/build-result/src/index.ts +25 -0
  100. package/packages/build-result/src/store.ts +505 -0
  101. package/packages/build-result/src/types.ts +354 -0
  102. package/packages/build-result/src/writer.ts +184 -0
  103. package/packages/build-result-fs/README.md +29 -0
  104. package/packages/build-result-fs/package.json +17 -0
  105. package/packages/build-result-fs/src/activation.ts +62 -0
  106. package/packages/build-result-fs/src/index.ts +1 -0
  107. package/packages/build-result-kit/README.md +10 -0
  108. package/packages/build-result-kit/package.json +15 -0
  109. package/packages/build-result-kit/src/index.ts +144 -0
  110. package/packages/build-result-s3/README.md +49 -0
  111. package/packages/build-result-s3/package.json +19 -0
  112. package/packages/build-result-s3/src/activation.ts +71 -0
  113. package/packages/build-result-s3/src/client.ts +254 -0
  114. package/packages/build-result-s3/src/index.ts +4 -0
  115. package/packages/build-result-s3/src/repository.ts +361 -0
  116. package/packages/caption/README.md +77 -0
  117. package/packages/caption/package.json +28 -0
  118. package/packages/caption/src/activation.ts +17 -0
  119. package/packages/caption/src/component.ts +38 -0
  120. package/packages/caption/src/display.ts +111 -0
  121. package/packages/caption/src/error.ts +9 -0
  122. package/packages/caption/src/fragment.ts +26 -0
  123. package/packages/caption/src/index.ts +33 -0
  124. package/packages/caption/src/manifest.ts +97 -0
  125. package/packages/caption/src/style.ts +170 -0
  126. package/packages/caption/src/surface.ts +96 -0
  127. package/packages/caption/src/temporalize.ts +124 -0
  128. package/packages/caption/src/types.ts +71 -0
  129. package/packages/caption-fine/README.md +108 -0
  130. package/packages/caption-fine/package.json +30 -0
  131. package/packages/caption-fine/preview/Track.png +0 -0
  132. package/packages/caption-fine/src/activation.ts +32 -0
  133. package/packages/caption-fine/src/component.ts +58 -0
  134. package/packages/caption-fine/src/fragment.ts +112 -0
  135. package/packages/caption-fine/src/index.ts +19 -0
  136. package/packages/caption-fine/src/manifest.ts +383 -0
  137. package/packages/caption-fine/src/recipe.ts +120 -0
  138. package/packages/caption-fine/src/render.ts +1133 -0
  139. package/packages/caption-fine/src/schedule.ts +126 -0
  140. package/packages/caption-fine/src/spacing.ts +69 -0
  141. package/packages/caption-fine/src/style.ts +370 -0
  142. package/packages/caption-fine/src/surface.ts +152 -0
  143. package/packages/caption-fine/src/types.ts +191 -0
  144. package/packages/caption-fine-studio/README.md +3 -0
  145. package/packages/caption-fine-studio/package.json +15 -0
  146. package/packages/caption-fine-studio/src/activation.ts +7 -0
  147. package/packages/caption-fine-studio/src/index.ts +163 -0
  148. package/packages/cli/README.md +51 -0
  149. package/packages/cli/package.json +33 -0
  150. package/packages/cli/src/arguments.ts +605 -0
  151. package/packages/cli/src/build-planning.ts +460 -0
  152. package/packages/cli/src/command.ts +202 -0
  153. package/packages/cli/src/commands/environment.ts +391 -0
  154. package/packages/cli/src/commands/execution.ts +321 -0
  155. package/packages/cli/src/commands/results.ts +187 -0
  156. package/packages/cli/src/commands/types.ts +9 -0
  157. package/packages/cli/src/distribution.ts +74 -0
  158. package/packages/cli/src/index.ts +30 -0
  159. package/packages/cli/src/machine-view.ts +28 -0
  160. package/packages/cli/src/main.ts +654 -0
  161. package/packages/cli/src/oauth.ts +228 -0
  162. package/packages/cli/src/observation.ts +203 -0
  163. package/packages/cli/src/output.ts +1007 -0
  164. package/packages/cli/src/paths.ts +7 -0
  165. package/packages/cli/src/project-context.ts +38 -0
  166. package/packages/cli/src/reachability.ts +91 -0
  167. package/packages/cli/src/result-export.ts +148 -0
  168. package/packages/cli/src/result-query.ts +46 -0
  169. package/packages/cli/src/run-file.ts +186 -0
  170. package/packages/cli/src/runtime-port.ts +13 -0
  171. package/packages/cli/src/runtime-selection.ts +94 -0
  172. package/packages/cli/src/runtime-view.ts +15 -0
  173. package/packages/cli/src/source-discovery.ts +150 -0
  174. package/packages/cli/src/source-packages.ts +91 -0
  175. package/packages/cli/src/view.ts +228 -0
  176. package/packages/comment-sticker/README.md +41 -0
  177. package/packages/comment-sticker/package.json +29 -0
  178. package/packages/comment-sticker/preview/Track.png +0 -0
  179. package/packages/comment-sticker/src/activation.ts +32 -0
  180. package/packages/comment-sticker/src/author.ts +148 -0
  181. package/packages/comment-sticker/src/component.ts +97 -0
  182. package/packages/comment-sticker/src/fragment.ts +124 -0
  183. package/packages/comment-sticker/src/index.ts +8 -0
  184. package/packages/comment-sticker/src/manifest.ts +373 -0
  185. package/packages/comment-sticker/src/program.ts +610 -0
  186. package/packages/comment-sticker/src/surface.ts +172 -0
  187. package/packages/comment-sticker/src/types.ts +109 -0
  188. package/packages/comment-sticker-studio/README.md +3 -0
  189. package/packages/comment-sticker-studio/package.json +14 -0
  190. package/packages/comment-sticker-studio/src/activation.ts +7 -0
  191. package/packages/comment-sticker-studio/src/index.ts +132 -0
  192. package/packages/compiler-markup-node/README.md +12 -0
  193. package/packages/compiler-markup-node/package.json +22 -0
  194. package/packages/compiler-markup-node/src/index.ts +59 -0
  195. package/packages/compiler-node/README.md +60 -0
  196. package/packages/compiler-node/package.json +25 -0
  197. package/packages/compiler-node/src/compiler.ts +207 -0
  198. package/packages/compiler-node/src/error.ts +11 -0
  199. package/packages/compiler-node/src/graph-query.ts +51 -0
  200. package/packages/compiler-node/src/index.ts +27 -0
  201. package/packages/compiler-node/src/modules.ts +107 -0
  202. package/packages/compiler-node/src/run.ts +355 -0
  203. package/packages/component-kit/README.md +97 -0
  204. package/packages/component-kit/package.json +13 -0
  205. package/packages/component-kit/src/index.ts +155 -0
  206. package/packages/composition/README.md +53 -0
  207. package/packages/composition/package.json +29 -0
  208. package/packages/composition/src/activation.ts +3 -0
  209. package/packages/composition/src/component.ts +10 -0
  210. package/packages/composition/src/index.ts +18 -0
  211. package/packages/composition/src/manifest.ts +13 -0
  212. package/packages/composition/src/schema.ts +194 -0
  213. package/packages/composition/src/track.ts +1403 -0
  214. package/packages/core/README.md +22 -0
  215. package/packages/core/package.json +13 -0
  216. package/packages/core/src/error.ts +12 -0
  217. package/packages/core/src/graph.ts +341 -0
  218. package/packages/core/src/index.ts +32 -0
  219. package/packages/core/src/link.ts +240 -0
  220. package/packages/core/src/machine.ts +60 -0
  221. package/packages/core/src/plan.ts +504 -0
  222. package/packages/core/src/reducer.ts +428 -0
  223. package/packages/core/src/reference.ts +25 -0
  224. package/packages/core/src/slice.ts +108 -0
  225. package/packages/credential-store-env/README.md +11 -0
  226. package/packages/credential-store-env/package.json +17 -0
  227. package/packages/credential-store-env/src/activation.ts +25 -0
  228. package/packages/credential-store-env/src/index.ts +23 -0
  229. package/packages/credential-store-os/README.md +13 -0
  230. package/packages/credential-store-os/package.json +22 -0
  231. package/packages/credential-store-os/runtime/windows-credential.ps1 +59 -0
  232. package/packages/credential-store-os/src/activation.ts +32 -0
  233. package/packages/credential-store-os/src/index.ts +2 -0
  234. package/packages/credential-store-os/src/store.ts +196 -0
  235. package/packages/deck-track/README.md +52 -0
  236. package/packages/deck-track/package.json +35 -0
  237. package/packages/deck-track/preview/DepthStack.png +0 -0
  238. package/packages/deck-track/src/activation.ts +32 -0
  239. package/packages/deck-track/src/author.ts +217 -0
  240. package/packages/deck-track/src/component.ts +86 -0
  241. package/packages/deck-track/src/fragment.ts +148 -0
  242. package/packages/deck-track/src/index.ts +16 -0
  243. package/packages/deck-track/src/lower.ts +370 -0
  244. package/packages/deck-track/src/manifest.ts +438 -0
  245. package/packages/deck-track/src/program.ts +367 -0
  246. package/packages/deck-track/src/surface.ts +286 -0
  247. package/packages/deck-track/src/types.ts +119 -0
  248. package/packages/deck-track-studio/README.md +3 -0
  249. package/packages/deck-track-studio/package.json +14 -0
  250. package/packages/deck-track-studio/src/activation.ts +7 -0
  251. package/packages/deck-track-studio/src/index.ts +134 -0
  252. package/packages/driver-node/README.md +23 -0
  253. package/packages/driver-node/package.json +18 -0
  254. package/packages/driver-node/src/driver.ts +616 -0
  255. package/packages/driver-node/src/index.ts +10 -0
  256. package/packages/driver-node/src/planning.ts +67 -0
  257. package/packages/driver-node/src/registry.ts +234 -0
  258. package/packages/driver-node/src/resources.ts +36 -0
  259. package/packages/driver-node/src/types.ts +69 -0
  260. package/packages/elaborator/README.md +74 -0
  261. package/packages/elaborator/package.json +16 -0
  262. package/packages/elaborator/src/author.ts +308 -0
  263. package/packages/elaborator/src/fragment.ts +505 -0
  264. package/packages/elaborator/src/frontend-facet.ts +30 -0
  265. package/packages/elaborator/src/index.ts +78 -0
  266. package/packages/elaborator/src/source.ts +608 -0
  267. package/packages/endpoint-kit/README.md +111 -0
  268. package/packages/endpoint-kit/package.json +14 -0
  269. package/packages/endpoint-kit/src/index.ts +488 -0
  270. package/packages/estimate/README.md +32 -0
  271. package/packages/estimate/package.json +20 -0
  272. package/packages/estimate/src/activation.ts +11 -0
  273. package/packages/estimate/src/index.ts +16 -0
  274. package/packages/estimate/src/manifest.ts +34 -0
  275. package/packages/estimate/src/policy.ts +70 -0
  276. package/packages/estimate/src/program.ts +196 -0
  277. package/packages/estimate/src/types.ts +15 -0
  278. package/packages/film/README.md +49 -0
  279. package/packages/film/package.json +34 -0
  280. package/packages/film/src/activation.ts +16 -0
  281. package/packages/film/src/component.ts +61 -0
  282. package/packages/film/src/fragment.ts +83 -0
  283. package/packages/film/src/index.ts +11 -0
  284. package/packages/film/src/manifest.ts +152 -0
  285. package/packages/film/src/program.ts +110 -0
  286. package/packages/film/src/recipe.ts +24 -0
  287. package/packages/film/src/surface.ts +146 -0
  288. package/packages/film/src/types.ts +26 -0
  289. package/packages/film-studio/package.json +16 -0
  290. package/packages/film-studio/src/activation.ts +8 -0
  291. package/packages/film-studio/src/index.ts +17 -0
  292. package/packages/fonts-open/README.md +77 -0
  293. package/packages/fonts-open/package.json +130 -0
  294. package/packages/fonts-open/src/activation.ts +30 -0
  295. package/packages/fonts-open/src/catalog.ts +317 -0
  296. package/packages/fonts-open/src/index.ts +13 -0
  297. package/packages/fonts-open/src/manifest.ts +83 -0
  298. package/packages/fonts-open/src/surface.ts +239 -0
  299. package/packages/generation/README.md +19 -0
  300. package/packages/generation/package.json +23 -0
  301. package/packages/generation/src/activation.ts +9 -0
  302. package/packages/generation/src/component.ts +77 -0
  303. package/packages/generation/src/identity.ts +80 -0
  304. package/packages/generation/src/index.ts +79 -0
  305. package/packages/generation/src/manifest.ts +65 -0
  306. package/packages/generation/src/mapping.ts +231 -0
  307. package/packages/generation/src/ports.ts +222 -0
  308. package/packages/generation/src/request.ts +427 -0
  309. package/packages/generation/src/schema.ts +62 -0
  310. package/packages/generation/src/types.ts +17 -0
  311. package/packages/gpt-image/README.md +54 -0
  312. package/packages/gpt-image/package.json +34 -0
  313. package/packages/gpt-image/src/activation.ts +39 -0
  314. package/packages/gpt-image/src/fragment.ts +101 -0
  315. package/packages/gpt-image/src/index.ts +203 -0
  316. package/packages/gpt-image/src/surface.ts +194 -0
  317. package/packages/gpt-image-kits/README.md +44 -0
  318. package/packages/gpt-image-kits/kits/phone-ugc-v1.svs +34 -0
  319. package/packages/gpt-image-kits/package.json +15 -0
  320. package/packages/grok-imagine/README.md +21 -0
  321. package/packages/grok-imagine/package.json +21 -0
  322. package/packages/grok-imagine/src/activation.ts +29 -0
  323. package/packages/grok-imagine/src/index.ts +174 -0
  324. package/packages/grok-imagine/src/surface.ts +149 -0
  325. package/packages/host/README.md +5 -0
  326. package/packages/host/package.json +10 -0
  327. package/packages/host/src/facet.ts +6 -0
  328. package/packages/host/src/frontend.ts +56 -0
  329. package/packages/host/src/index.ts +9 -0
  330. package/packages/hyperframes/README.md +69 -0
  331. package/packages/hyperframes/package.json +36 -0
  332. package/packages/hyperframes/src/activation.ts +8 -0
  333. package/packages/hyperframes/src/browser-program.ts +79 -0
  334. package/packages/hyperframes/src/component.ts +32 -0
  335. package/packages/hyperframes/src/document.ts +827 -0
  336. package/packages/hyperframes/src/fragment.ts +32 -0
  337. package/packages/hyperframes/src/index.ts +13 -0
  338. package/packages/hyperframes/src/manifest.ts +67 -0
  339. package/packages/hyperframes/src/project.ts +118 -0
  340. package/packages/hyperframes/src/text.ts +1179 -0
  341. package/packages/hyperframes/src/types.ts +38 -0
  342. package/packages/image-compose/README.md +25 -0
  343. package/packages/image-compose/package.json +18 -0
  344. package/packages/image-compose/src/activation.ts +21 -0
  345. package/packages/image-compose/src/component.ts +100 -0
  346. package/packages/image-compose/src/fragment.ts +54 -0
  347. package/packages/image-compose/src/index.ts +10 -0
  348. package/packages/image-compose/src/manifest.ts +119 -0
  349. package/packages/image-compose/src/program.ts +75 -0
  350. package/packages/image-compose/src/surface.ts +83 -0
  351. package/packages/image-compose/src/types.ts +22 -0
  352. package/packages/image-transform/README.md +29 -0
  353. package/packages/image-transform/package.json +21 -0
  354. package/packages/image-transform/src/activation.ts +33 -0
  355. package/packages/image-transform/src/component.ts +67 -0
  356. package/packages/image-transform/src/fragment.ts +25 -0
  357. package/packages/image-transform/src/index.ts +13 -0
  358. package/packages/image-transform/src/manifest.ts +209 -0
  359. package/packages/image-transform/src/program.ts +23 -0
  360. package/packages/image-transform/src/surface.ts +216 -0
  361. package/packages/image-transform/src/types.ts +20 -0
  362. package/packages/interview-emoji-reveal/README.md +39 -0
  363. package/packages/interview-emoji-reveal/package.json +23 -0
  364. package/packages/interview-emoji-reveal/preview/Track.png +0 -0
  365. package/packages/interview-emoji-reveal/src/activation.ts +14 -0
  366. package/packages/interview-emoji-reveal/src/component.ts +45 -0
  367. package/packages/interview-emoji-reveal/src/fragment.ts +62 -0
  368. package/packages/interview-emoji-reveal/src/index.ts +16 -0
  369. package/packages/interview-emoji-reveal/src/manifest.ts +174 -0
  370. package/packages/interview-emoji-reveal/src/program.ts +242 -0
  371. package/packages/interview-emoji-reveal/src/style.ts +47 -0
  372. package/packages/interview-emoji-reveal/src/surface.ts +110 -0
  373. package/packages/interview-emoji-reveal/src/types.ts +52 -0
  374. package/packages/markup/README.md +81 -0
  375. package/packages/markup/package.json +16 -0
  376. package/packages/markup/src/element.ts +39 -0
  377. package/packages/markup/src/error.ts +20 -0
  378. package/packages/markup/src/frontend.ts +518 -0
  379. package/packages/markup/src/host-facet.ts +115 -0
  380. package/packages/markup/src/index.ts +25 -0
  381. package/packages/markup/src/registry.ts +83 -0
  382. package/packages/markup/src/syntax.ts +271 -0
  383. package/packages/markup/src/types.ts +246 -0
  384. package/packages/media/README.md +37 -0
  385. package/packages/media/package.json +19 -0
  386. package/packages/media/src/activation.ts +38 -0
  387. package/packages/media/src/component.ts +16 -0
  388. package/packages/media/src/frame-range.ts +33 -0
  389. package/packages/media/src/identity.ts +227 -0
  390. package/packages/media/src/index.ts +15 -0
  391. package/packages/media/src/manifest.ts +122 -0
  392. package/packages/media/src/render.ts +140 -0
  393. package/packages/media/src/schema.ts +69 -0
  394. package/packages/media/src/surface.ts +150 -0
  395. package/packages/media/src/types.ts +121 -0
  396. package/packages/media-execution/README.md +28 -0
  397. package/packages/media-execution/package.json +17 -0
  398. package/packages/media-execution/src/execute.ts +1322 -0
  399. package/packages/media-execution/src/index.ts +16 -0
  400. package/packages/media-execution/src/probe.ts +315 -0
  401. package/packages/media-execution/src/surface.ts +286 -0
  402. package/packages/media-execution/src/toolchain.ts +81 -0
  403. package/packages/media-execution/src/webp.ts +200 -0
  404. package/packages/media-pipeline/README.md +113 -0
  405. package/packages/media-pipeline/package.json +27 -0
  406. package/packages/media-pipeline/src/activation.ts +47 -0
  407. package/packages/media-pipeline/src/audio-plan.ts +113 -0
  408. package/packages/media-pipeline/src/component.ts +373 -0
  409. package/packages/media-pipeline/src/fragment.ts +167 -0
  410. package/packages/media-pipeline/src/index.ts +46 -0
  411. package/packages/media-pipeline/src/manifest.ts +653 -0
  412. package/packages/media-pipeline/src/operations.ts +248 -0
  413. package/packages/media-pipeline/src/selection.ts +110 -0
  414. package/packages/media-pipeline/src/surface.ts +389 -0
  415. package/packages/media-pipeline/src/types.ts +175 -0
  416. package/packages/media-track/README.md +197 -0
  417. package/packages/media-track/package.json +29 -0
  418. package/packages/media-track/preview/Track.png +0 -0
  419. package/packages/media-track/preview/build.svrun +5 -0
  420. package/packages/media-track/preview/flush.png +0 -0
  421. package/packages/media-track/preview/preview.svml +47 -0
  422. package/packages/media-track/preview/recipes.svs +23 -0
  423. package/packages/media-track/preview/rounded.png +0 -0
  424. package/packages/media-track/src/activation.ts +20 -0
  425. package/packages/media-track/src/author.ts +317 -0
  426. package/packages/media-track/src/component.ts +162 -0
  427. package/packages/media-track/src/fragment.ts +57 -0
  428. package/packages/media-track/src/index.ts +65 -0
  429. package/packages/media-track/src/layers.ts +308 -0
  430. package/packages/media-track/src/lower.ts +335 -0
  431. package/packages/media-track/src/manifest.ts +624 -0
  432. package/packages/media-track/src/motion.ts +387 -0
  433. package/packages/media-track/src/performance.ts +37 -0
  434. package/packages/media-track/src/presentation.ts +35 -0
  435. package/packages/media-track/src/program.ts +565 -0
  436. package/packages/media-track/src/sampling.ts +118 -0
  437. package/packages/media-track/src/sequence.ts +403 -0
  438. package/packages/media-track/src/sounds.ts +71 -0
  439. package/packages/media-track/src/surface.ts +668 -0
  440. package/packages/media-track/src/types.ts +311 -0
  441. package/packages/media-track-studio/README.md +3 -0
  442. package/packages/media-track-studio/package.json +15 -0
  443. package/packages/media-track-studio/src/activation.ts +7 -0
  444. package/packages/media-track-studio/src/index.ts +235 -0
  445. package/packages/mimo-speech/README.md +33 -0
  446. package/packages/mimo-speech/package.json +21 -0
  447. package/packages/mimo-speech/src/activation.ts +32 -0
  448. package/packages/mimo-speech/src/fragment.ts +11 -0
  449. package/packages/mimo-speech/src/index.ts +160 -0
  450. package/packages/mimo-speech/src/surface.ts +193 -0
  451. package/packages/minimax-h3/README.md +21 -0
  452. package/packages/minimax-h3/package.json +21 -0
  453. package/packages/minimax-h3/src/activation.ts +14 -0
  454. package/packages/minimax-h3/src/index.ts +188 -0
  455. package/packages/minimax-h3/src/surface.ts +87 -0
  456. package/packages/model-kit/README.md +52 -0
  457. package/packages/model-kit/package.json +19 -0
  458. package/packages/model-kit/src/index.ts +728 -0
  459. package/packages/nano-banana/README.md +23 -0
  460. package/packages/nano-banana/package.json +21 -0
  461. package/packages/nano-banana/src/activation.ts +14 -0
  462. package/packages/nano-banana/src/index.ts +172 -0
  463. package/packages/nano-banana/src/surface.ts +120 -0
  464. package/packages/narrative/README.md +7 -0
  465. package/packages/narrative/package.json +17 -0
  466. package/packages/narrative/src/activation.ts +7 -0
  467. package/packages/narrative/src/component.ts +33 -0
  468. package/packages/narrative/src/identity.ts +131 -0
  469. package/packages/narrative/src/index.ts +11 -0
  470. package/packages/narrative/src/manifest.ts +30 -0
  471. package/packages/narrative/src/schema.ts +89 -0
  472. package/packages/narrative/src/types.ts +141 -0
  473. package/packages/package-loader-node/README.md +23 -0
  474. package/packages/package-loader-node/package.json +15 -0
  475. package/packages/package-loader-node/src/contribution.ts +97 -0
  476. package/packages/package-loader-node/src/distribution-resolution.ts +146 -0
  477. package/packages/package-loader-node/src/index.ts +27 -0
  478. package/packages/package-loader-node/src/loader.ts +301 -0
  479. package/packages/package-loader-node/src/location.ts +279 -0
  480. package/packages/package-loader-node/src/types.ts +60 -0
  481. package/packages/program-space/README.md +20 -0
  482. package/packages/program-space/package.json +17 -0
  483. package/packages/program-space/src/activation.ts +19 -0
  484. package/packages/program-space/src/index.ts +107 -0
  485. package/packages/program-space/src/surface.ts +55 -0
  486. package/packages/protocol/README.md +11 -0
  487. package/packages/protocol/package.json +10 -0
  488. package/packages/protocol/src/build-id.ts +52 -0
  489. package/packages/protocol/src/build.ts +265 -0
  490. package/packages/protocol/src/canonical.ts +37 -0
  491. package/packages/protocol/src/error.ts +11 -0
  492. package/packages/protocol/src/identity.ts +59 -0
  493. package/packages/protocol/src/index.ts +9 -0
  494. package/packages/protocol/src/module.ts +67 -0
  495. package/packages/protocol/src/value.ts +88 -0
  496. package/packages/provider-hyperframes-aws-lambda/README.md +30 -0
  497. package/packages/provider-hyperframes-aws-lambda/package.json +30 -0
  498. package/packages/provider-hyperframes-aws-lambda/src/activation.ts +97 -0
  499. package/packages/provider-hyperframes-aws-lambda/src/client.ts +114 -0
  500. package/packages/provider-hyperframes-aws-lambda/src/index.ts +21 -0
  501. package/packages/provider-hyperframes-aws-lambda/src/provider.ts +522 -0
  502. package/packages/provider-hyperframes-local/README.md +129 -0
  503. package/packages/provider-hyperframes-local/package.json +34 -0
  504. package/packages/provider-hyperframes-local/src/activation.ts +107 -0
  505. package/packages/provider-hyperframes-local/src/capture-process.ts +110 -0
  506. package/packages/provider-hyperframes-local/src/capture-worker.ts +17 -0
  507. package/packages/provider-hyperframes-local/src/capture.ts +184 -0
  508. package/packages/provider-hyperframes-local/src/index.ts +10 -0
  509. package/packages/provider-hyperframes-local/src/options.ts +19 -0
  510. package/packages/provider-hyperframes-local/src/output.ts +73 -0
  511. package/packages/provider-hyperframes-local/src/process.ts +83 -0
  512. package/packages/provider-hyperframes-local/src/program.ts +58 -0
  513. package/packages/provider-hyperframes-local/src/provider.ts +62 -0
  514. package/packages/provider-hyperframes-local/src/render.ts +114 -0
  515. package/packages/provider-hyperframes-local/src/sampling.ts +89 -0
  516. package/packages/provider-hypihub/README.md +143 -0
  517. package/packages/provider-hypihub/package.json +26 -0
  518. package/packages/provider-hypihub/src/activation.ts +91 -0
  519. package/packages/provider-hypihub/src/index.ts +2 -0
  520. package/packages/provider-hypihub/src/mapping.ts +145 -0
  521. package/packages/provider-hypihub/src/oauth.ts +113 -0
  522. package/packages/provider-hypihub/src/provider.ts +566 -0
  523. package/packages/provider-hypihub/src/routes.ts +134 -0
  524. package/packages/provider-hypihub/src/upload.ts +402 -0
  525. package/packages/provider-image-opencv-local/README.md +16 -0
  526. package/packages/provider-image-opencv-local/package.json +27 -0
  527. package/packages/provider-image-opencv-local/runtime/raster_execute.py +299 -0
  528. package/packages/provider-image-opencv-local/src/activation.ts +61 -0
  529. package/packages/provider-image-opencv-local/src/deployment.ts +68 -0
  530. package/packages/provider-image-opencv-local/src/index.ts +2 -0
  531. package/packages/provider-image-opencv-local/src/program.ts +60 -0
  532. package/packages/provider-image-opencv-local/src/provider.ts +155 -0
  533. package/packages/provider-kie/README.md +134 -0
  534. package/packages/provider-kie/package.json +43 -0
  535. package/packages/provider-kie/src/activation.ts +71 -0
  536. package/packages/provider-kie/src/index.ts +10 -0
  537. package/packages/provider-kie/src/mapping.ts +182 -0
  538. package/packages/provider-kie/src/provider.ts +657 -0
  539. package/packages/provider-kie/src/routes.ts +150 -0
  540. package/packages/provider-media-local/README.md +58 -0
  541. package/packages/provider-media-local/package.json +28 -0
  542. package/packages/provider-media-local/src/activation.ts +65 -0
  543. package/packages/provider-media-local/src/index.ts +2 -0
  544. package/packages/provider-media-local/src/program.ts +19 -0
  545. package/packages/provider-media-local/src/provider.ts +150 -0
  546. package/packages/provider-whisperx-local/README.md +44 -0
  547. package/packages/provider-whisperx-local/package.json +27 -0
  548. package/packages/provider-whisperx-local/src/activation.ts +93 -0
  549. package/packages/provider-whisperx-local/src/index.ts +5 -0
  550. package/packages/provider-whisperx-local/src/program.ts +157 -0
  551. package/packages/provider-whisperx-local/src/provider.ts +191 -0
  552. package/packages/provider-xiaomi-mimo/README.md +32 -0
  553. package/packages/provider-xiaomi-mimo/package.json +24 -0
  554. package/packages/provider-xiaomi-mimo/src/activation.ts +57 -0
  555. package/packages/provider-xiaomi-mimo/src/index.ts +5 -0
  556. package/packages/provider-xiaomi-mimo/src/provider.ts +214 -0
  557. package/packages/ranking/README.md +67 -0
  558. package/packages/ranking/package.json +33 -0
  559. package/packages/ranking/preview/Column.svg +29 -0
  560. package/packages/ranking/preview/TierBoard.png +0 -0
  561. package/packages/ranking/preview/TierBoard.svg +36 -0
  562. package/packages/ranking/preview/TopThree.png +0 -0
  563. package/packages/ranking/src/activation.ts +38 -0
  564. package/packages/ranking/src/component.ts +271 -0
  565. package/packages/ranking/src/fragment.ts +206 -0
  566. package/packages/ranking/src/index.ts +26 -0
  567. package/packages/ranking/src/manifest.ts +807 -0
  568. package/packages/ranking/src/render.ts +698 -0
  569. package/packages/ranking/src/schedule.ts +895 -0
  570. package/packages/ranking/src/style.ts +272 -0
  571. package/packages/ranking/src/surface.ts +322 -0
  572. package/packages/ranking/src/tier.ts +176 -0
  573. package/packages/ranking/src/types.ts +277 -0
  574. package/packages/ranking-studio/README.md +3 -0
  575. package/packages/ranking-studio/package.json +14 -0
  576. package/packages/ranking-studio/src/activation.ts +7 -0
  577. package/packages/ranking-studio/src/index.ts +255 -0
  578. package/packages/raster/README.md +7 -0
  579. package/packages/raster/package.json +14 -0
  580. package/packages/raster/src/activation.ts +7 -0
  581. package/packages/raster/src/index.ts +7 -0
  582. package/packages/raster/src/manifest.ts +14 -0
  583. package/packages/raster/src/program.ts +128 -0
  584. package/packages/raster/src/schema.ts +53 -0
  585. package/packages/raster/src/types.ts +61 -0
  586. package/packages/render-hyperframes/README.md +58 -0
  587. package/packages/render-hyperframes/package.json +33 -0
  588. package/packages/render-hyperframes/src/activation.ts +18 -0
  589. package/packages/render-hyperframes/src/component.ts +37 -0
  590. package/packages/render-hyperframes/src/fragment.ts +73 -0
  591. package/packages/render-hyperframes/src/index.ts +6 -0
  592. package/packages/render-hyperframes/src/manifest.ts +100 -0
  593. package/packages/render-hyperframes/src/product.ts +29 -0
  594. package/packages/render-hyperframes/src/surface.ts +65 -0
  595. package/packages/resource-store-fs/README.md +13 -0
  596. package/packages/resource-store-fs/package.json +14 -0
  597. package/packages/resource-store-fs/src/index.ts +2 -0
  598. package/packages/resource-store-fs/src/store.ts +154 -0
  599. package/packages/resource-store-s3/README.md +15 -0
  600. package/packages/resource-store-s3/package.json +15 -0
  601. package/packages/resource-store-s3/src/client.ts +138 -0
  602. package/packages/resource-store-s3/src/index.ts +10 -0
  603. package/packages/resource-store-s3/src/store.ts +258 -0
  604. package/packages/run/README.md +23 -0
  605. package/packages/run/package.json +16 -0
  606. package/packages/run/src/candidate.ts +33 -0
  607. package/packages/run/src/facet.ts +59 -0
  608. package/packages/run/src/frontend-facet.ts +23 -0
  609. package/packages/run/src/frontend.ts +62 -0
  610. package/packages/run/src/graph.ts +65 -0
  611. package/packages/run/src/index.ts +33 -0
  612. package/packages/run/src/registry.ts +24 -0
  613. package/packages/run/src/resolve.ts +213 -0
  614. package/packages/run/src/types.ts +147 -0
  615. package/packages/run-markup/README.md +60 -0
  616. package/packages/run-markup/package.json +22 -0
  617. package/packages/run-markup/src/activation.ts +10 -0
  618. package/packages/run-markup/src/frontend.ts +16 -0
  619. package/packages/run-markup/src/index.ts +5 -0
  620. package/packages/run-markup/src/syntax.ts +304 -0
  621. package/packages/runtime/README.md +39 -0
  622. package/packages/runtime/package.json +15 -0
  623. package/packages/runtime/src/capacity.ts +51 -0
  624. package/packages/runtime/src/catalog.ts +30 -0
  625. package/packages/runtime/src/credentials.ts +124 -0
  626. package/packages/runtime/src/environment.ts +6 -0
  627. package/packages/runtime/src/execution.ts +125 -0
  628. package/packages/runtime/src/index.ts +24 -0
  629. package/packages/runtime/src/operations.ts +99 -0
  630. package/packages/runtime/src/scheduler.ts +281 -0
  631. package/packages/runtime/src/submission.ts +24 -0
  632. package/packages/runtime/src/types.ts +157 -0
  633. package/packages/runtime-host-node/README.md +25 -0
  634. package/packages/runtime-host-node/package.json +19 -0
  635. package/packages/runtime-host-node/src/index.ts +421 -0
  636. package/packages/runtime-host-node/src/packages.ts +158 -0
  637. package/packages/runtime-kit/README.md +42 -0
  638. package/packages/runtime-kit/package.json +16 -0
  639. package/packages/runtime-kit/src/index.ts +307 -0
  640. package/packages/runtime-kit/src/request-deadline.ts +17 -0
  641. package/packages/runtime-local/README.md +119 -0
  642. package/packages/runtime-local/package.json +33 -0
  643. package/packages/runtime-local/src/actions.ts +20 -0
  644. package/packages/runtime-local/src/config.ts +1229 -0
  645. package/packages/runtime-local/src/control.ts +120 -0
  646. package/packages/runtime-local/src/credentials.ts +61 -0
  647. package/packages/runtime-local/src/host.ts +174 -0
  648. package/packages/runtime-local/src/index.ts +36 -0
  649. package/packages/runtime-local/src/process-control.ts +59 -0
  650. package/packages/runtime-local/src/process-logs.ts +33 -0
  651. package/packages/runtime-local/src/programs.ts +441 -0
  652. package/packages/runtime-local/src/result-writer.ts +246 -0
  653. package/packages/runtime-local/src/runtime.ts +342 -0
  654. package/packages/runtime-local/src/types.ts +100 -0
  655. package/packages/runtime-local/src/worker-process.ts +343 -0
  656. package/packages/runtime-local/src/worker.ts +449 -0
  657. package/packages/screen-overlay/README.md +17 -0
  658. package/packages/screen-overlay/package.json +31 -0
  659. package/packages/screen-overlay/preview/Track.png +0 -0
  660. package/packages/screen-overlay/src/activation.ts +15 -0
  661. package/packages/screen-overlay/src/component.ts +20 -0
  662. package/packages/screen-overlay/src/fragment.ts +40 -0
  663. package/packages/screen-overlay/src/index.ts +7 -0
  664. package/packages/screen-overlay/src/manifest.ts +305 -0
  665. package/packages/screen-overlay/src/program.ts +321 -0
  666. package/packages/screen-overlay/src/surface.ts +90 -0
  667. package/packages/screen-overlay/src/types.ts +69 -0
  668. package/packages/screen-overlay-studio/README.md +3 -0
  669. package/packages/screen-overlay-studio/package.json +14 -0
  670. package/packages/screen-overlay-studio/src/activation.ts +7 -0
  671. package/packages/screen-overlay-studio/src/index.ts +80 -0
  672. package/packages/script/README.md +137 -0
  673. package/packages/script/package.json +22 -0
  674. package/packages/script/src/activation.ts +20 -0
  675. package/packages/script/src/edit.ts +174 -0
  676. package/packages/script/src/error.ts +13 -0
  677. package/packages/script/src/format.ts +83 -0
  678. package/packages/script/src/index.ts +20 -0
  679. package/packages/script/src/lexical.ts +133 -0
  680. package/packages/script/src/manifest.ts +95 -0
  681. package/packages/script/src/narrative.ts +232 -0
  682. package/packages/script/src/parser.ts +850 -0
  683. package/packages/script/src/surface.ts +132 -0
  684. package/packages/script/src/types.ts +125 -0
  685. package/packages/script-studio/package.json +13 -0
  686. package/packages/script-studio/src/activation.ts +8 -0
  687. package/packages/script-studio/src/index.ts +61 -0
  688. package/packages/seedance/README.md +19 -0
  689. package/packages/seedance/package.json +22 -0
  690. package/packages/seedance/src/activation.ts +38 -0
  691. package/packages/seedance/src/fragment.ts +46 -0
  692. package/packages/seedance/src/index.ts +329 -0
  693. package/packages/seedance/src/surface.ts +355 -0
  694. package/packages/seedance-kits/README.md +153 -0
  695. package/packages/seedance-kits/kits/broll-v1.svs +52 -0
  696. package/packages/seedance-kits/kits/call-v1.svs +55 -0
  697. package/packages/seedance-kits/kits/camera-reference-v1.svs +9 -0
  698. package/packages/seedance-kits/kits/motion-reference-v1.svs +9 -0
  699. package/packages/seedance-kits/kits/podcast-v1.svs +55 -0
  700. package/packages/seedance-kits/kits/speaker-v1.svs +136 -0
  701. package/packages/seedance-kits/kits/street-interview-v1.svs +49 -0
  702. package/packages/seedance-kits/package.json +24 -0
  703. package/packages/seedream/README.md +21 -0
  704. package/packages/seedream/package.json +21 -0
  705. package/packages/seedream/src/activation.ts +12 -0
  706. package/packages/seedream/src/index.ts +162 -0
  707. package/packages/seedream/src/surface.ts +84 -0
  708. package/packages/semantic-take-adjust/package.json +21 -0
  709. package/packages/semantic-take-adjust/src/activation.ts +22 -0
  710. package/packages/semantic-take-adjust/src/component.ts +31 -0
  711. package/packages/semantic-take-adjust/src/fragment.ts +24 -0
  712. package/packages/semantic-take-adjust/src/index.ts +12 -0
  713. package/packages/semantic-take-adjust/src/manifest.ts +57 -0
  714. package/packages/semantic-take-adjust/src/program.ts +49 -0
  715. package/packages/semantic-take-adjust/src/surface.ts +96 -0
  716. package/packages/semantic-take-adjust/src/types.ts +9 -0
  717. package/packages/semantic-track/README.md +21 -0
  718. package/packages/semantic-track/package.json +22 -0
  719. package/packages/semantic-track/src/activation.ts +8 -0
  720. package/packages/semantic-track/src/component.ts +24 -0
  721. package/packages/semantic-track/src/identity.ts +58 -0
  722. package/packages/semantic-track/src/index.ts +6 -0
  723. package/packages/semantic-track/src/location.ts +81 -0
  724. package/packages/semantic-track/src/manifest.ts +38 -0
  725. package/packages/semantic-track/src/projection.ts +71 -0
  726. package/packages/semantic-track/src/types.ts +26 -0
  727. package/packages/source/README.md +13 -0
  728. package/packages/source/package.json +13 -0
  729. package/packages/source/src/header.ts +80 -0
  730. package/packages/source/src/index.ts +17 -0
  731. package/packages/source/src/unit.ts +38 -0
  732. package/packages/spatial/README.md +77 -0
  733. package/packages/spatial/package.json +24 -0
  734. package/packages/spatial/src/activation.ts +43 -0
  735. package/packages/spatial/src/author.ts +59 -0
  736. package/packages/spatial/src/component.ts +45 -0
  737. package/packages/spatial/src/fragment.ts +36 -0
  738. package/packages/spatial/src/geometry.ts +238 -0
  739. package/packages/spatial/src/index.ts +37 -0
  740. package/packages/spatial/src/manifest.ts +341 -0
  741. package/packages/spatial/src/region-timeline.ts +69 -0
  742. package/packages/spatial/src/schema.ts +47 -0
  743. package/packages/spatial/src/surface.ts +319 -0
  744. package/packages/spatial/src/types.ts +101 -0
  745. package/packages/speech/README.md +16 -0
  746. package/packages/speech/package.json +19 -0
  747. package/packages/speech/src/activation.ts +7 -0
  748. package/packages/speech/src/component.ts +43 -0
  749. package/packages/speech/src/identity.ts +73 -0
  750. package/packages/speech/src/index.ts +6 -0
  751. package/packages/speech/src/manifest.ts +30 -0
  752. package/packages/speech/src/materialize.ts +103 -0
  753. package/packages/speech/src/schema.ts +42 -0
  754. package/packages/speech/src/types.ts +54 -0
  755. package/packages/speech-alignment/README.md +29 -0
  756. package/packages/speech-alignment/package.json +25 -0
  757. package/packages/speech-alignment/src/activation.ts +8 -0
  758. package/packages/speech-alignment/src/align.ts +235 -0
  759. package/packages/speech-alignment/src/component.ts +37 -0
  760. package/packages/speech-alignment/src/error.ts +9 -0
  761. package/packages/speech-alignment/src/index.ts +7 -0
  762. package/packages/speech-alignment/src/local.ts +64 -0
  763. package/packages/speech-alignment/src/locate.ts +473 -0
  764. package/packages/speech-alignment/src/manifest.ts +37 -0
  765. package/packages/speech-alignment/src/normalize.ts +79 -0
  766. package/packages/speech-alignment/src/types.ts +30 -0
  767. package/packages/speech-evidence/README.md +3 -0
  768. package/packages/speech-evidence/package.json +16 -0
  769. package/packages/speech-evidence/src/activation.ts +3 -0
  770. package/packages/speech-evidence/src/index.ts +102 -0
  771. package/packages/speech-track/README.md +51 -0
  772. package/packages/speech-track/package.json +28 -0
  773. package/packages/speech-track/preview/Track.png +0 -0
  774. package/packages/speech-track/src/activation.ts +19 -0
  775. package/packages/speech-track/src/component.ts +45 -0
  776. package/packages/speech-track/src/fragment.ts +74 -0
  777. package/packages/speech-track/src/index.ts +7 -0
  778. package/packages/speech-track/src/manifest.ts +73 -0
  779. package/packages/speech-track/src/program.ts +64 -0
  780. package/packages/speech-track/src/surface.ts +35 -0
  781. package/packages/speech-track/src/types.ts +6 -0
  782. package/packages/speech-track-studio/README.md +3 -0
  783. package/packages/speech-track-studio/package.json +14 -0
  784. package/packages/speech-track-studio/src/activation.ts +7 -0
  785. package/packages/speech-track-studio/src/index.ts +40 -0
  786. package/packages/store-sqlite/README.md +14 -0
  787. package/packages/store-sqlite/package.json +18 -0
  788. package/packages/store-sqlite/src/index.ts +2 -0
  789. package/packages/store-sqlite/src/store.ts +1101 -0
  790. package/packages/studio/README.md +125 -0
  791. package/packages/studio/index.html +10 -0
  792. package/packages/studio/package.json +50 -0
  793. package/packages/studio/src/build-library.ts +281 -0
  794. package/packages/studio/src/companion-assembly.ts +39 -0
  795. package/packages/studio/src/compile.ts +166 -0
  796. package/packages/studio/src/domain.ts +139 -0
  797. package/packages/studio/src/execute.ts +57 -0
  798. package/packages/studio/src/fallback-companions.ts +98 -0
  799. package/packages/studio/src/observe.ts +202 -0
  800. package/packages/studio/src/parameter-values.ts +81 -0
  801. package/packages/studio/src/parameters.ts +550 -0
  802. package/packages/studio/src/preview/render.ts +51 -0
  803. package/packages/studio/src/preview/runtime-shim.ts +184 -0
  804. package/packages/studio/src/programme.ts +276 -0
  805. package/packages/studio/src/run.ts +85 -0
  806. package/packages/studio/src/server.ts +725 -0
  807. package/packages/studio/src/session.ts +111 -0
  808. package/packages/studio/src/shared.ts +315 -0
  809. package/packages/studio/src/snapshot.ts +454 -0
  810. package/packages/studio/src/source-transaction.ts +57 -0
  811. package/packages/studio/src/storyboard.ts +133 -0
  812. package/packages/studio/src/studio-preflight.ts +198 -0
  813. package/packages/studio/src/studio-registry.ts +406 -0
  814. package/packages/studio/src/studio-trace.ts +136 -0
  815. package/packages/studio/src/style.css +1525 -0
  816. package/packages/studio/src/surface-preview.ts +35 -0
  817. package/packages/studio/src/temporal-graph.ts +227 -0
  818. package/packages/studio/src/ui/code.ts +450 -0
  819. package/packages/studio/src/ui/icons.ts +51 -0
  820. package/packages/studio/src/ui/library.ts +378 -0
  821. package/packages/studio/src/ui/main.ts +1001 -0
  822. package/packages/studio/src/ui/markers.ts +152 -0
  823. package/packages/studio/src/ui/material-preview.ts +176 -0
  824. package/packages/studio/src/ui/overlay.ts +144 -0
  825. package/packages/studio/src/ui/resize.ts +74 -0
  826. package/packages/studio/src/ui/selection.ts +178 -0
  827. package/packages/studio/src/ui/stage.ts +231 -0
  828. package/packages/studio/src/ui/syntax.ts +195 -0
  829. package/packages/studio/src/ui/timeline.ts +1041 -0
  830. package/packages/studio/src/ui/writeback.ts +10 -0
  831. package/packages/studio/src/ui/zoom.ts +129 -0
  832. package/packages/studio/start.ts +143 -0
  833. package/packages/studio-adapter/README.md +186 -0
  834. package/packages/studio-adapter/package.json +14 -0
  835. package/packages/studio-adapter/src/index.ts +850 -0
  836. package/packages/svs/README.md +37 -0
  837. package/packages/svs/package.json +21 -0
  838. package/packages/svs/src/activation.ts +11 -0
  839. package/packages/svs/src/format.ts +16 -0
  840. package/packages/svs/src/frontend.ts +33 -0
  841. package/packages/svs/src/index.ts +5 -0
  842. package/packages/svs/src/manifest.ts +17 -0
  843. package/packages/svs/src/parser.ts +279 -0
  844. package/packages/svs/src/types.ts +26 -0
  845. package/packages/temporal/README.md +31 -0
  846. package/packages/temporal/package.json +20 -0
  847. package/packages/temporal/src/activation.ts +9 -0
  848. package/packages/temporal/src/component.ts +68 -0
  849. package/packages/temporal/src/index.ts +110 -0
  850. package/packages/temporal/src/location.ts +67 -0
  851. package/packages/temporal/src/projection.ts +280 -0
  852. package/packages/temporal/src/rational.ts +80 -0
  853. package/packages/temporal/src/sample.ts +43 -0
  854. package/packages/temporal/src/schedule.ts +52 -0
  855. package/packages/temporal/src/types.ts +124 -0
  856. package/packages/temporal-markup/README.md +75 -0
  857. package/packages/temporal-markup/package.json +18 -0
  858. package/packages/temporal-markup/src/index.ts +537 -0
  859. package/packages/temporal-markup/src/space.ts +59 -0
  860. package/packages/text/README.md +59 -0
  861. package/packages/text/package.json +21 -0
  862. package/packages/text/src/activation.ts +33 -0
  863. package/packages/text/src/component.ts +72 -0
  864. package/packages/text/src/fragment.ts +57 -0
  865. package/packages/text/src/frontend.ts +39 -0
  866. package/packages/text/src/index.ts +27 -0
  867. package/packages/text/src/manifest.ts +170 -0
  868. package/packages/text/src/program.ts +418 -0
  869. package/packages/text/src/surface.ts +212 -0
  870. package/packages/text/src/svs.ts +189 -0
  871. package/packages/text/src/types.ts +82 -0
  872. package/packages/transport-aws-lambda/README.md +20 -0
  873. package/packages/transport-aws-lambda/package.json +14 -0
  874. package/packages/transport-aws-lambda/src/index.ts +131 -0
  875. package/packages/typography-track/README.md +50 -0
  876. package/packages/typography-track/package.json +34 -0
  877. package/packages/typography-track/preview/Mask.png +0 -0
  878. package/packages/typography-track/preview/Track.png +0 -0
  879. package/packages/typography-track/src/activation.ts +36 -0
  880. package/packages/typography-track/src/component.ts +93 -0
  881. package/packages/typography-track/src/fragment.ts +30 -0
  882. package/packages/typography-track/src/index.ts +11 -0
  883. package/packages/typography-track/src/manifest.ts +556 -0
  884. package/packages/typography-track/src/program.ts +622 -0
  885. package/packages/typography-track/src/surface.ts +842 -0
  886. package/packages/typography-track/src/types.ts +109 -0
  887. package/packages/typography-track-studio/README.md +3 -0
  888. package/packages/typography-track-studio/package.json +14 -0
  889. package/packages/typography-track-studio/src/activation.ts +7 -0
  890. package/packages/typography-track-studio/src/index.ts +116 -0
  891. package/packages/validation/README.md +11 -0
  892. package/packages/validation/package.json +15 -0
  893. package/packages/validation/src/index.ts +100 -0
  894. package/packages/video-cli/README.md +181 -0
  895. package/packages/video-cli/package.json +37 -0
  896. package/packages/video-cli/src/capture.ts +174 -0
  897. package/packages/video-cli/src/cli.ts +109 -0
  898. package/packages/video-cli/src/compiler.ts +32 -0
  899. package/packages/video-cli/src/creation.ts +449 -0
  900. package/packages/video-cli/src/distribution.ts +88 -0
  901. package/packages/video-cli/src/index.ts +50 -0
  902. package/packages/video-cli/src/media.ts +701 -0
  903. package/packages/video-cli/src/package-selection.ts +34 -0
  904. package/packages/video-cli/src/process.ts +71 -0
  905. package/packages/video-cli/src/studio-distribution.ts +19 -0
  906. package/packages/video-cli/src/transcript.ts +71 -0
  907. package/packages/video-cli/src/vocabulary.ts +386 -0
  908. package/packages/visual-ir/README.md +36 -0
  909. package/packages/visual-ir/package.json +16 -0
  910. package/packages/visual-ir/src/activation.ts +3 -0
  911. package/packages/visual-ir/src/index.ts +7 -0
  912. package/packages/visual-ir/src/style.ts +222 -0
  913. package/packages/volcengine-matting/README.md +89 -0
  914. package/packages/volcengine-matting/package.json +16 -0
  915. package/packages/volcengine-matting/src/activation.ts +13 -0
  916. package/packages/volcengine-matting/src/index.ts +45 -0
  917. package/packages/volcengine-matting/src/surface.ts +48 -0
  918. package/packages/whisperx/README.md +34 -0
  919. package/packages/whisperx/package.json +28 -0
  920. package/packages/whisperx/src/activation.ts +18 -0
  921. package/packages/whisperx/src/component.ts +64 -0
  922. package/packages/whisperx/src/evidence.ts +69 -0
  923. package/packages/whisperx/src/fragment.ts +76 -0
  924. package/packages/whisperx/src/index.ts +14 -0
  925. package/packages/whisperx/src/manifest.ts +92 -0
  926. package/packages/whisperx/src/surface.ts +90 -0
  927. package/packages/whisperx/src/transcript.ts +97 -0
  928. package/packages/whisperx/src/types.ts +9 -0
  929. package/packages/workspace/README.md +4 -0
  930. package/packages/workspace/package.json +14 -0
  931. package/packages/workspace/src/index.ts +38 -0
  932. package/packages/workspace-fs-node/README.md +13 -0
  933. package/packages/workspace-fs-node/package.json +15 -0
  934. package/packages/workspace-fs-node/src/index.ts +6 -0
  935. package/packages/workspace-fs-node/src/workspace.ts +226 -0
  936. package/packages/yt-dlp/README.md +31 -0
  937. package/packages/yt-dlp/package.json +10 -0
  938. package/packages/yt-dlp/src/download.ts +104 -0
  939. package/packages/yt-dlp/src/index.ts +1 -0
  940. package/services/image-opencv/README.md +33 -0
  941. package/services/image-opencv/package.json +14 -0
  942. package/services/image-opencv/pyproject.toml +13 -0
  943. package/services/image-opencv/uv.lock +56 -0
  944. package/services/whisperx/README.md +82 -0
  945. package/services/whisperx/package.json +15 -0
  946. package/services/whisperx/pyproject.toml +26 -0
  947. package/services/whisperx/src/hypit_whisperx_service/__init__.py +6 -0
  948. package/services/whisperx/src/hypit_whisperx_service/__main__.py +29 -0
  949. package/services/whisperx/src/hypit_whisperx_service/application.py +88 -0
  950. package/services/whisperx/src/hypit_whisperx_service/audio.py +66 -0
  951. package/services/whisperx/src/hypit_whisperx_service/check.py +35 -0
  952. package/services/whisperx/src/hypit_whisperx_service/config.py +81 -0
  953. package/services/whisperx/src/hypit_whisperx_service/engine.py +173 -0
  954. package/services/whisperx/src/hypit_whisperx_service/prepare.py +19 -0
  955. package/services/whisperx/src/hypit_whisperx_service/resources.py +41 -0
  956. package/services/whisperx/src/hypit_whisperx_service/server.py +101 -0
  957. package/services/whisperx/uv.lock +3381 -0
  958. package/services/yt-dlp/README.md +19 -0
  959. package/services/yt-dlp/package.json +14 -0
  960. package/services/yt-dlp/pyproject.toml +13 -0
  961. package/services/yt-dlp/uv.lock +23 -0
  962. package/index.js +0 -1
@@ -0,0 +1,1133 @@
1
+ import { assertCaptionProgramForDocument } from "@hypit/caption";
2
+ import type { CaptionProgram } from "@hypit/caption";
3
+ import { assertVisualTrackIdentity, sealVisualTrack } from "@hypit/composition";
4
+ import type {
5
+ VisualAnimation,
6
+ VisualBoxElement,
7
+ VisualColorPaint,
8
+ VisualElement,
9
+ VisualKeyframe,
10
+ VisualStyleDeclaration,
11
+ VisualTextElement,
12
+ VisualTextPaintLayer,
13
+ VisualTrack,
14
+ } from "@hypit/composition";
15
+ import type { CaptionAlignmentUnit, CaptionDocument } from "@hypit/narrative";
16
+ import { assertProgramSpaceIdentity, programSpaceFrameCount } from "@hypit/program-space";
17
+ import type { ProgramSpace } from "@hypit/program-space";
18
+ import { assertSpatialRegionTimeline } from "@hypit/spatial";
19
+ import type { CanvasSpace, SpatialFrame, SpatialRegionTimeline } from "@hypit/spatial";
20
+
21
+ import { assertFineCaptionParameters, FINE_CAPTION_FAMILY } from "./style.js";
22
+ import { assertFineCaptionSchedule } from "./schedule.js";
23
+ import { joinSurfaces, uniformGap, wordGapBetween, wordGaps } from "./spacing.js";
24
+ import type {
25
+ FineCaptionActiveUnderline,
26
+ FineCaptionGlyphPaint,
27
+ FineCaptionOneShotMotion,
28
+ FineCaptionParameters,
29
+ FineCaptionSchedule,
30
+ FineCaptionUnderline,
31
+ } from "./types.js";
32
+
33
+ function clamp(value: number, minimum: number, maximum: number): number {
34
+ return Math.max(minimum, Math.min(maximum, value));
35
+ }
36
+
37
+ function compactNumber(value: number): string {
38
+ return String(Math.round(value * 1_000_000) / 1_000_000);
39
+ }
40
+
41
+ function alphaColor(hex: string, opacity: number): string {
42
+ const red = Number.parseInt(hex.slice(1, 3), 16);
43
+ const green = Number.parseInt(hex.slice(3, 5), 16);
44
+ const blue = Number.parseInt(hex.slice(5, 7), 16);
45
+ const authoredAlpha = hex.length === 9 ? Number.parseInt(hex.slice(7, 9), 16) / 255 : 1;
46
+ return `rgba(${red},${green},${blue},${compactNumber(authoredAlpha * opacity)})`;
47
+ }
48
+
49
+ function typographyStyle(parameters: FineCaptionParameters): VisualStyleDeclaration[] {
50
+ return [
51
+ { name: "font-size", value: `${compactNumber(parameters.typography.fontSizePx)}px` },
52
+ { name: "font-kerning", value: parameters.typography.kerning },
53
+ { name: "font-variant-caps", value: parameters.typography.variantCaps },
54
+ { name: "letter-spacing", value: `${compactNumber(parameters.layout.letterSpacingPx)}px` },
55
+ { name: "line-height", value: parameters.layout.lineHeight },
56
+ { name: "text-transform", value: parameters.typography.textTransform },
57
+ ];
58
+ }
59
+
60
+ function underlineStyle(underline: FineCaptionUnderline | FineCaptionActiveUnderline): VisualStyleDeclaration[] {
61
+ if (underline.mode === "off") return [];
62
+ return [
63
+ { name: "text-decoration", value: "underline" },
64
+ { name: "text-decoration-color", value: underline.color },
65
+ { name: "text-decoration-thickness", value: `${compactNumber(underline.thicknessPx)}px` },
66
+ { name: "text-underline-offset", value: `${compactNumber(underline.offsetPx)}px` },
67
+ ];
68
+ }
69
+
70
+ /**
71
+ * The glyph body and its outline, as ordered Paint.
72
+ *
73
+ * An outline belongs outside the letter. `-webkit-text-stroke` cannot put it there: it centres the
74
+ * stroke on the glyph edge, so half the width is always inside. Declaring the Paint hands placement
75
+ * to the renderer, which keeps the authored width wholly outside while the body preserves the
76
+ * original letterform.
77
+ *
78
+ * A caption with no outline keeps its plain fill, which is one element and one paint rather than
79
+ * two, and is what most captions are.
80
+ */
81
+ /**
82
+ * CSS blur is a radius; a Gaussian blur is a deviation. The radius covers about two deviations, so
83
+ * the same number means twice the cloud when it moves from one to the other. Authors tuned these
84
+ * against the radius, and the outline is what moved, not the shadow.
85
+ */
86
+ function deviationFromBlurRadius(radiusPx: number): number {
87
+ return radiusPx / 2;
88
+ }
89
+
90
+ /**
91
+ * The soft effects, ordered from the back forward.
92
+ *
93
+ * `text-shadow` paints its list front to back — the first shadow named is the one on top — while
94
+ * Paint layers are drawn in the order they are declared. So this reverses: the far end of a long
95
+ * shadow first, then the glow, then the drop shadow nearest the letter.
96
+ */
97
+ function softPaints(paint: FineCaptionGlyphPaint): VisualTextPaintLayer[] {
98
+ const layers: VisualTextPaintLayer[] = [];
99
+ if (paint.longShadow.opacity > 0 && paint.longShadow.distancePx > 0) {
100
+ const steps = Math.min(32, Math.max(1, Math.ceil(paint.longShadow.distancePx)));
101
+ const radians = paint.longShadow.angleDeg * Math.PI / 180;
102
+ for (let step = steps; step >= 1; step -= 1) {
103
+ const distance = paint.longShadow.distancePx * step / steps;
104
+ layers.push({
105
+ kind: "shadow",
106
+ paint: { kind: "solid", color: alphaColor(paint.longShadow.color, paint.longShadow.opacity) },
107
+ offsetX: Math.cos(radians) * distance,
108
+ offsetY: Math.sin(radians) * distance,
109
+ blurPx: 0,
110
+ spreadPx: 0,
111
+ });
112
+ }
113
+ }
114
+ if (paint.glow.opacity > 0) {
115
+ layers.push({
116
+ kind: "glow",
117
+ paint: { kind: "solid", color: alphaColor(paint.glow.color, paint.glow.opacity) },
118
+ blurPx: deviationFromBlurRadius(paint.glow.blurPx),
119
+ spreadPx: paint.glow.spreadPx,
120
+ });
121
+ }
122
+ if (paint.shadow.opacity > 0) {
123
+ layers.push({
124
+ kind: "shadow",
125
+ paint: { kind: "solid", color: alphaColor(paint.shadow.color, paint.shadow.opacity) },
126
+ offsetX: paint.shadow.offsetXPx,
127
+ offsetY: paint.shadow.offsetYPx,
128
+ blurPx: deviationFromBlurRadius(paint.shadow.blurPx),
129
+ spreadPx: paint.shadow.spreadPx,
130
+ });
131
+ }
132
+ return layers;
133
+ }
134
+
135
+ function glyphPaints(paint: FineCaptionGlyphPaint): VisualTextPaintLayer[] | undefined {
136
+ if (paint.stroke.widthPx === 0 && paint.shadow.spreadPx === 0 && paint.glow.spreadPx === 0) return undefined;
137
+ const fill: VisualColorPaint = paint.gradient === undefined
138
+ ? { kind: "solid", color: paint.fill }
139
+ : {
140
+ kind: "linear-gradient",
141
+ angleDeg: paint.gradient.angleDeg,
142
+ stops: [
143
+ { offset: 0, color: paint.gradient.from, opacity: 1 },
144
+ { offset: 1, color: paint.gradient.to, opacity: 1 },
145
+ ],
146
+ };
147
+ // Back to front: the soft effects fall behind the outline they are cast from, the outline sits
148
+ // outside the letter, and the body sits over its own outline.
149
+ return [
150
+ ...softPaints(paint),
151
+ ...(paint.stroke.widthPx === 0 ? [] : [{
152
+ kind: "stroke" as const,
153
+ placement: "outside" as const,
154
+ widthPx: paint.stroke.widthPx,
155
+ paint: { kind: "solid" as const, color: paint.stroke.color },
156
+ }]),
157
+ { kind: "fill", paint: fill },
158
+ ];
159
+ }
160
+
161
+ /** The Paint fields of a text element, absent rather than empty when there is no outline. */
162
+ function glyphPaintFields(paint: FineCaptionGlyphPaint): { paints?: readonly VisualTextPaintLayer[] } {
163
+ const paints = glyphPaints(paint);
164
+ return paints === undefined ? {} : { paints };
165
+ }
166
+
167
+ function glyphStyle(
168
+ parameters: FineCaptionParameters,
169
+ paint: FineCaptionGlyphPaint,
170
+ underline?: FineCaptionUnderline,
171
+ ): VisualStyleDeclaration[] {
172
+ const shadows: string[] = [];
173
+ if (paint.shadow.opacity > 0) {
174
+ shadows.push([
175
+ `${compactNumber(paint.shadow.offsetXPx)}px`,
176
+ `${compactNumber(paint.shadow.offsetYPx)}px`,
177
+ `${compactNumber(paint.shadow.blurPx)}px`,
178
+ alphaColor(paint.shadow.color, paint.shadow.opacity),
179
+ ].join(" "));
180
+ }
181
+ if (paint.glow.opacity > 0) {
182
+ shadows.push(`0 0 ${compactNumber(paint.glow.blurPx)}px ${alphaColor(paint.glow.color, paint.glow.opacity)}`);
183
+ }
184
+ if (paint.longShadow.opacity > 0 && paint.longShadow.distancePx > 0) {
185
+ const steps = Math.min(32, Math.max(1, Math.ceil(paint.longShadow.distancePx)));
186
+ const radians = paint.longShadow.angleDeg * Math.PI / 180;
187
+ for (let step = 1; step <= steps; step += 1) {
188
+ const distance = paint.longShadow.distancePx * step / steps;
189
+ shadows.push([
190
+ `${compactNumber(Math.cos(radians) * distance)}px`,
191
+ `${compactNumber(Math.sin(radians) * distance)}px`,
192
+ "0",
193
+ alphaColor(paint.longShadow.color, paint.longShadow.opacity),
194
+ ].join(" "));
195
+ }
196
+ }
197
+ // An outlined caption carries its body and outline as Paint instead, so the fill is spelled once
198
+ // — there, not here — and the two cannot disagree.
199
+ const painted = glyphPaints(paint) !== undefined;
200
+ return [
201
+ ...(painted ? [] : [{ name: "color", value: paint.fill }] as const),
202
+ ...typographyStyle(parameters),
203
+ { name: "min-width", value: "0" },
204
+ { name: "opacity", value: paint.opacity },
205
+ { name: "white-space", value: "normal" },
206
+ ...(painted || paint.gradient === undefined ? [] : [
207
+ { name: "background-image", value: `linear-gradient(${compactNumber(paint.gradient.angleDeg)}deg,${paint.gradient.from},${paint.gradient.to})` },
208
+ { name: "background-clip", value: "text" },
209
+ { name: "-webkit-background-clip", value: "text" },
210
+ { name: "-webkit-text-fill-color", value: "transparent" },
211
+ ] as const),
212
+ // An outlined caption casts its shadows as Paint, behind the outline. Left here as well they
213
+ // would be cast by the body alone, and so land on top of the ring they are supposed to be under.
214
+ ...(painted || shadows.length === 0 ? [] : [{ name: "text-shadow", value: shadows.join(",") }] as const),
215
+ ...(underline === undefined ? [] : underlineStyle(underline)),
216
+ ];
217
+ }
218
+
219
+ function transparentGlyphStyle(
220
+ parameters: FineCaptionParameters,
221
+ underline?: FineCaptionUnderline | FineCaptionActiveUnderline,
222
+ ): VisualStyleDeclaration[] {
223
+ return [
224
+ { name: "color", value: "#00000000" },
225
+ ...typographyStyle(parameters),
226
+ { name: "min-width", value: "0" },
227
+ { name: "white-space", value: "normal" },
228
+ ...(underline === undefined ? [] : underlineStyle(underline)),
229
+ ];
230
+ }
231
+
232
+ function styleIdentity(style: readonly VisualStyleDeclaration[]): string {
233
+ return JSON.stringify(style);
234
+ }
235
+
236
+ function animationFrom(
237
+ durationFrames: number,
238
+ offsets: Iterable<number>,
239
+ styleAt: (frame: number) => readonly VisualStyleDeclaration[],
240
+ ): VisualAnimation | undefined {
241
+ const keyframes = [...new Set([0, durationFrames, ...offsets])]
242
+ .filter((frame) => Number.isSafeInteger(frame) && frame >= 0 && frame <= durationFrames)
243
+ .sort((left, right) => left - right)
244
+ .map((atFrame): VisualKeyframe => ({ atFrame, style: styleAt(atFrame) }));
245
+ if (new Set(keyframes.map((keyframe) => styleIdentity(keyframe.style))).size === 1) return undefined;
246
+ return { keyframes };
247
+ }
248
+
249
+ function stepOffsets(...boundaries: number[]): number[] {
250
+ return boundaries.flatMap((boundary) => [boundary - 1, boundary]);
251
+ }
252
+
253
+ type MotionSnapshot = {
254
+ readonly opacity: number;
255
+ readonly transform: string;
256
+ readonly filter: string;
257
+ readonly clipPath: string;
258
+ };
259
+
260
+ function easeOut(value: number): number {
261
+ return 1 - Math.pow(1 - value, 3);
262
+ }
263
+
264
+ function easeOutBack(value: number): number {
265
+ const c1 = 1.3;
266
+ const c3 = c1 + 1;
267
+ return 1 + c3 * Math.pow(value - 1, 3) + c1 * Math.pow(value - 1, 2);
268
+ }
269
+
270
+ function easeOutBounce(value: number): number {
271
+ let x = value;
272
+ const n1 = 7.5625;
273
+ const d1 = 2.75;
274
+ if (x < 1 / d1) return n1 * x * x;
275
+ if (x < 2 / d1) return n1 * (x -= 1.5 / d1) * x + 0.75;
276
+ if (x < 2.5 / d1) return n1 * (x -= 2.25 / d1) * x + 0.9375;
277
+ return n1 * (x -= 2.625 / d1) * x + 0.984375;
278
+ }
279
+
280
+ function easeOutElastic(value: number): number {
281
+ if (value === 0 || value === 1) return value;
282
+ return Math.pow(2, -10 * value) * Math.sin((value * 10 - 0.75) * (2 * Math.PI / 3)) + 1;
283
+ }
284
+
285
+ const neutralMotion: MotionSnapshot = { opacity: 1, transform: "none", filter: "none", clipPath: "inset(0% 0% 0% 0%)" };
286
+
287
+ /**
288
+ * Whether a motion needs `clip-path` at all.
289
+ *
290
+ * `inset(0% 0% 0% 0%)` reads as a no-op and is not one: it clips the element and everything inside it
291
+ * to its border box. These boxes carry no padding, so their border box is exactly the glyph advance —
292
+ * and an outline is painted outside that, by a filter that contributes nothing to layout. Emitted as
293
+ * the resting value of every motion, it cut the outline off on all four sides, along with the glow,
294
+ * the drop shadow and the long shadow, which reach further still.
295
+ *
296
+ * A wipe is the only motion that has anything to clip. Every keyframe of one animation has to declare
297
+ * the same properties, so this is decided once per animation rather than per frame.
298
+ */
299
+ function wipes(kind: FineCaptionOneShotMotion): boolean {
300
+ return kind === "wipe-left" || kind === "wipe-right" || kind === "wipe-up" || kind === "wipe-down";
301
+ }
302
+
303
+ function motionSnapshot(
304
+ kind: FineCaptionOneShotMotion,
305
+ progress: number,
306
+ distancePx: number,
307
+ startScale?: number,
308
+ ): MotionSnapshot {
309
+ const value = clamp(progress, 0, 1);
310
+ const eased = easeOut(value);
311
+ const state = (opacity: number, transform = "none", filter = "none", clipPath = neutralMotion.clipPath): MotionSnapshot =>
312
+ ({ opacity, transform, filter, clipPath });
313
+ const scaleFrom = (fallback: number, motionProgress: number): string =>
314
+ `scale(${compactNumber((startScale ?? fallback) + (1 - (startScale ?? fallback)) * motionProgress)})`;
315
+ const optionalScale = (): string => startScale === undefined ? "" : ` ${scaleFrom(1, eased)}`;
316
+ if (kind === "none") return neutralMotion;
317
+ if (kind === "fade") return state(eased, startScale === undefined ? "none" : scaleFrom(1, eased));
318
+ if (kind === "blur-in") return state(eased, scaleFrom(0.96, eased), `blur(${compactNumber((1 - eased) * 16)}px)`);
319
+ if (kind === "pop") return state(eased, scaleFrom(0.6, easeOutBack(value)));
320
+ if (kind === "scale") return state(eased, scaleFrom(0.2, eased));
321
+ if (kind === "spring") {
322
+ const settled = value >= 1 ? 1 : 1 - Math.exp(-5 * value) * Math.cos(10 * value);
323
+ return state(eased, scaleFrom(0.72, settled));
324
+ }
325
+ if (kind === "bounce") return state(eased, scaleFrom(0, easeOutBounce(value)));
326
+ if (kind === "elastic") return state(eased, scaleFrom(0, easeOutElastic(value)));
327
+ if (kind === "stamp") return state(eased, scaleFrom(1.35, easeOutBack(value)));
328
+ if (kind === "tilt") return state(eased, `rotate(${compactNumber((1 - eased) * -8)}deg) ${scaleFrom(0.94, eased)}`);
329
+ if (kind === "zoom-blur") return state(eased, scaleFrom(1.18, eased), `blur(${compactNumber((1 - eased) * 18)}px)`);
330
+ if (kind === "flip-x") return state(eased, `perspective(600px) rotateX(${compactNumber((1 - eased) * 88)}deg) ${scaleFrom(0.92, eased)}`);
331
+ if (kind === "flip-y") return state(eased, `perspective(600px) rotateY(${compactNumber((1 - eased) * -88)}deg) ${scaleFrom(0.92, eased)}`);
332
+ if (kind === "spin") return state(eased, `rotate(${compactNumber((1 - eased) * -180)}deg) ${scaleFrom(0.55, eased)}`);
333
+ if (kind === "squash") return state(eased, `scaleX(${compactNumber(1.28 - 0.28 * easeOutBack(value))}) scaleY(${compactNumber(0.48 + 0.52 * easeOutBack(value))})${optionalScale()}`);
334
+ if (kind === "stretch") return state(eased, `scaleX(${compactNumber(0.5 + 0.5 * easeOutBack(value))}) scaleY(${compactNumber(1.35 - 0.35 * easeOutBack(value))})${optionalScale()}`);
335
+ const hidden = compactNumber((1 - eased) * 100);
336
+ const wipeTransform = startScale === undefined ? "none" : scaleFrom(1, eased);
337
+ if (kind === "wipe-left") return state(1, wipeTransform, "none", `inset(0% 0% 0% ${hidden}%)`);
338
+ if (kind === "wipe-right") return state(1, wipeTransform, "none", `inset(0% ${hidden}% 0% 0%)`);
339
+ if (kind === "wipe-up") return state(1, wipeTransform, "none", `inset(0% 0% ${hidden}% 0%)`);
340
+ if (kind === "wipe-down") return state(1, wipeTransform, "none", `inset(${hidden}% 0% 0% 0%)`);
341
+ const remaining = compactNumber((1 - value) * distancePx);
342
+ const transform = kind === "slide-left" ? `translateX(-${remaining}px)`
343
+ : kind === "slide-right" ? `translateX(${remaining}px)`
344
+ : kind === "slide-up" ? `translateY(-${remaining}px)`
345
+ : `translateY(${remaining}px)`;
346
+ return state(eased, `${transform}${optionalScale()}`);
347
+ }
348
+
349
+ function cueEntranceSnapshot(
350
+ parameters: FineCaptionParameters,
351
+ progress: number,
352
+ ): MotionSnapshot {
353
+ const value = clamp(progress, 0, 1);
354
+ const authored = motionSnapshot(
355
+ parameters.motion.cueEnter,
356
+ value,
357
+ parameters.motion.slideDistancePx,
358
+ parameters.motion.cueEnterStartScale,
359
+ );
360
+ const snapshot = parameters.motion.cueEnter !== "spring" ? authored : (() => {
361
+ const start = parameters.motion.cueEnterStartScale ?? 0.72;
362
+ const scale = value <= 0.5
363
+ ? start + (1.05 - start) * value / 0.5
364
+ : value <= 0.75
365
+ ? 1.05 + (0.95 - 1.05) * (value - 0.5) / 0.25
366
+ : 0.95 + (1 - 0.95) * (value - 0.75) / 0.25;
367
+ return { ...authored, opacity: 1, transform: `scale(${compactNumber(scale)})` };
368
+ })();
369
+ return snapshot;
370
+ }
371
+
372
+ function snapshotStyle(snapshot: MotionSnapshot, clipped = true): VisualStyleDeclaration[] {
373
+ return [
374
+ { name: "opacity", value: snapshot.opacity },
375
+ { name: "transform", value: snapshot.transform },
376
+ { name: "filter", value: snapshot.filter },
377
+ ...(clipped ? [{ name: "clip-path", value: snapshot.clipPath }] : []),
378
+ ];
379
+ }
380
+
381
+ function transitionOffsets(start: number, frames: number, kind: FineCaptionOneShotMotion): number[] {
382
+ if (frames === 0) return stepOffsets(start);
383
+ const samples = ["spring", "bounce", "elastic"].includes(kind) ? Math.min(frames, 12) : Math.min(frames, 4);
384
+ return Array.from({ length: samples + 1 }, (_, index) => start + Math.round(frames * index / samples));
385
+ }
386
+
387
+ function cueAnimation(parameters: FineCaptionParameters, durationFrames: number): VisualAnimation | undefined {
388
+ const enterFrames = parameters.motion.cueEnter === "none"
389
+ ? 0 : Math.min(parameters.motion.cueEnterFrames, Math.floor(durationFrames / 2));
390
+ const exitFrames = parameters.motion.cueExit === "none"
391
+ ? 0 : Math.min(parameters.motion.cueExitFrames, Math.floor(durationFrames / 2));
392
+ const offsets = [
393
+ ...transitionOffsets(0, enterFrames, parameters.motion.cueEnter),
394
+ ...transitionOffsets(durationFrames - exitFrames, exitFrames, parameters.motion.cueExit),
395
+ ];
396
+ const clipped = wipes(parameters.motion.cueEnter) || wipes(parameters.motion.cueExit);
397
+ return animationFrom(durationFrames, offsets, (frame) => {
398
+ const enterProgress = enterFrames === 0 ? 1 : clamp(frame / enterFrames, 0, 1);
399
+ const exitProgress = exitFrames === 0 ? 1 : clamp((durationFrames - frame) / exitFrames, 0, 1);
400
+ const enter = cueEntranceSnapshot(parameters, enterProgress);
401
+ const exit = motionSnapshot(parameters.motion.cueExit, exitProgress, parameters.motion.slideDistancePx);
402
+ return snapshotStyle(enterProgress < 1 ? enter : exit, clipped);
403
+ });
404
+ }
405
+
406
+ function atomLifecycleAnimation(
407
+ parameters: FineCaptionParameters,
408
+ startFrame: number,
409
+ endFrame: number,
410
+ durationFrames: number,
411
+ ): VisualAnimation | undefined {
412
+ const shouldWait = parameters.motion.atomReveal === "on-start" || parameters.motion.atomEnter !== "none";
413
+ if (!shouldWait && parameters.motion.atomExit === "none") return undefined;
414
+ const enterFrames = parameters.motion.atomEnter === "none" ? 0
415
+ : Math.min(parameters.motion.atomEnterFrames, Math.max(0, endFrame - startFrame));
416
+ const exitFrames = parameters.motion.atomExit === "none" ? 0
417
+ : Math.min(parameters.motion.atomExitFrames, Math.max(0, endFrame - startFrame - enterFrames));
418
+ const offsets = [
419
+ ...transitionOffsets(startFrame, enterFrames, parameters.motion.atomEnter),
420
+ ...transitionOffsets(endFrame - exitFrames, exitFrames, parameters.motion.atomExit),
421
+ ...stepOffsets(endFrame),
422
+ ];
423
+ const clipped = wipes(parameters.motion.atomEnter) || wipes(parameters.motion.atomExit);
424
+ return animationFrom(durationFrames, offsets, (frame) => {
425
+ if (frame < startFrame) return shouldWait ? [{ name: "opacity", value: 0 }] : snapshotStyle(neutralMotion, clipped);
426
+ if (frame >= endFrame && parameters.motion.atomExit !== "none") {
427
+ return snapshotStyle(motionSnapshot(parameters.motion.atomExit, 0, parameters.motion.slideDistancePx), clipped);
428
+ }
429
+ const enterProgress = enterFrames === 0 ? 1 : clamp((frame - startFrame) / enterFrames, 0, 1);
430
+ const exitProgress = exitFrames === 0 ? 1 : clamp((endFrame - frame) / exitFrames, 0, 1);
431
+ if (enterProgress < 1) return snapshotStyle(motionSnapshot(parameters.motion.atomEnter, enterProgress, parameters.motion.slideDistancePx), clipped);
432
+ return snapshotStyle(motionSnapshot(parameters.motion.atomExit, exitProgress, parameters.motion.slideDistancePx), clipped);
433
+ });
434
+ }
435
+
436
+ function activationStepAnimation(
437
+ mode: "current" | "trail",
438
+ startFrame: number,
439
+ endFrame: number,
440
+ durationFrames: number,
441
+ ): VisualAnimation {
442
+ return animationFrom(durationFrames, stepOffsets(startFrame, endFrame), (frame) => {
443
+ const active = mode === "trail"
444
+ ? frame >= startFrame
445
+ : frame >= startFrame && (frame < endFrame || (endFrame === durationFrames && frame === durationFrames));
446
+ return [{ name: "opacity", value: active ? 1 : 0 }];
447
+ }) ?? { keyframes: [
448
+ { atFrame: 0, style: [{ name: "opacity", value: 1 }] },
449
+ { atFrame: durationFrames, style: [{ name: "opacity", value: 1 }] },
450
+ ] };
451
+ }
452
+
453
+ function wipeClip(progress: number, direction: FineCaptionParameters["layout"]["direction"]): string {
454
+ const hidden = compactNumber((1 - clamp(progress, 0, 1)) * 100);
455
+ return direction === "rtl" ? `inset(0 0 0 ${hidden}%)` : `inset(0 ${hidden}% 0 0)`;
456
+ }
457
+
458
+ function karaokeWipeAnimation(
459
+ parameters: FineCaptionParameters,
460
+ mode: "current" | "trail",
461
+ startFrame: number,
462
+ endFrame: number,
463
+ durationFrames: number,
464
+ ): VisualAnimation {
465
+ if (mode === "current" && endFrame - startFrame <= 1) {
466
+ return activationStepAnimation(mode, startFrame, endFrame, durationFrames);
467
+ }
468
+ const revealEnd = mode === "current" ? endFrame - 1 : endFrame;
469
+ return animationFrom(durationFrames, [startFrame, revealEnd, endFrame], (frame) => {
470
+ let progress = 0;
471
+ if (frame >= startFrame && frame <= revealEnd) {
472
+ progress = revealEnd === startFrame ? 1 : (frame - startFrame) / (revealEnd - startFrame);
473
+ } else if (mode === "trail" && frame > revealEnd) {
474
+ progress = 1;
475
+ }
476
+ return [{ name: "clip-path", value: wipeClip(progress, parameters.layout.direction) }];
477
+ }) ?? { keyframes: [
478
+ { atFrame: 0, style: [{ name: "clip-path", value: wipeClip(1, parameters.layout.direction) }] },
479
+ { atFrame: durationFrames, style: [{ name: "clip-path", value: wipeClip(1, parameters.layout.direction) }] },
480
+ ] };
481
+ }
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
+ function activeResponseAnimation(
501
+ parameters: FineCaptionParameters,
502
+ startFrame: number,
503
+ endFrame: number,
504
+ durationFrames: number,
505
+ ): VisualAnimation | undefined {
506
+ const response = parameters.motion.activeResponse;
507
+ if (response === "none" || endFrame <= startFrame) return undefined;
508
+ if (response === "scale") {
509
+ return animationFrom(durationFrames, stepOffsets(startFrame, endFrame), (frame) => {
510
+ const active = frame >= startFrame && (frame < endFrame || (endFrame === durationFrames && frame === durationFrames));
511
+ return [{ name: "transform", value: `scale(${compactNumber(active ? parameters.motion.activeScale : 1)})` }];
512
+ });
513
+ }
514
+ const frames = Math.min(parameters.motion.activeResponseFrames, Math.max(1, endFrame - startFrame));
515
+ const clipped = wipes(response);
516
+ return animationFrom(durationFrames, transitionOffsets(startFrame, frames, response), (frame) => {
517
+ if (frame < startFrame || frame > startFrame + frames) return snapshotStyle(neutralMotion, clipped);
518
+ const progress = clamp((frame - startFrame) / frames, 0, 1);
519
+ if (response === "pop" || response === "spring") {
520
+ const amplitude = parameters.motion.activeScale - 1;
521
+ const responseScale = response === "pop"
522
+ ? 1 + amplitude * Math.sin(Math.PI * progress)
523
+ : 1 + amplitude * Math.exp(-4 * progress) * Math.sin(12 * progress);
524
+ return [{ name: "transform", value: `scale(${compactNumber(responseScale)})` }];
525
+ }
526
+ return snapshotStyle(motionSnapshot(response, progress, parameters.motion.slideDistancePx), clipped);
527
+ });
528
+ }
529
+
530
+ function loopAnimation(
531
+ parameters: FineCaptionParameters,
532
+ durationFrames: number,
533
+ activeWindow?: { readonly start: number; readonly end: number },
534
+ ): VisualAnimation | undefined {
535
+ if (parameters.motion.loop === "none") return undefined;
536
+ const period = parameters.motion.loopPeriodFrames;
537
+ const start = activeWindow?.start ?? 0;
538
+ const end = activeWindow?.end ?? durationFrames;
539
+ const offsets: number[] = [...stepOffsets(start, end)];
540
+ for (let frame = start; frame <= end; frame += Math.max(1, Math.round(period / 4))) offsets.push(frame);
541
+ return animationFrom(durationFrames, offsets, (frame) => {
542
+ const active = frame >= start && (frame < end || (end === durationFrames && frame === durationFrames));
543
+ if (!active) return parameters.motion.loop === "glow-pulse"
544
+ ? [{ name: "filter", value: "none" }]
545
+ : parameters.motion.loop === "flicker" ? [{ name: "opacity", value: 1 }]
546
+ : [{ name: "transform", value: "none" }];
547
+ const phase = 2 * Math.PI * ((frame - start) % period) / period;
548
+ if (parameters.motion.loop === "shake") {
549
+ return [{ name: "transform", value: `translateX(${compactNumber(Math.sin(phase * 2) * 3 * parameters.motion.loopIntensity)}px)` }];
550
+ }
551
+ if (parameters.motion.loop === "wobble") {
552
+ return [{ name: "transform", value: `rotate(${compactNumber(Math.sin(phase) * 2.5 * parameters.motion.loopIntensity)}deg)` }];
553
+ }
554
+ if (parameters.motion.loop === "breathe") {
555
+ return [{ name: "transform", value: `scale(${compactNumber(1 + Math.sin(phase) * 0.035 * parameters.motion.loopIntensity)})` }];
556
+ }
557
+ if (parameters.motion.loop === "float") {
558
+ return [{ name: "transform", value: `translateY(${compactNumber(Math.sin(phase) * 3.2 * parameters.motion.loopIntensity)}px)` }];
559
+ }
560
+ if (parameters.motion.loop === "pulse") {
561
+ return [{ name: "transform", value: `scale(${compactNumber(1 + (Math.sin(phase) + 1) * 0.0375 * parameters.motion.loopIntensity)})` }];
562
+ }
563
+ if (parameters.motion.loop === "flicker") {
564
+ return [{ name: "opacity", value: clamp(1 - (Math.sin(phase * 5) + 1) * 0.11 * parameters.motion.loopIntensity, 0.15, 1) }];
565
+ }
566
+ const strength = (0.35 + 0.65 * (Math.sin(phase) + 1) / 2) * parameters.motion.loopIntensity;
567
+ const paint = activeWindow === undefined ? parameters.basePaint : parameters.activePaint;
568
+ const color = paint.glow.opacity > 0 ? paint.glow.color : paint.fill;
569
+ const opacity = paint.glow.opacity > 0 ? paint.glow.opacity : 0.65;
570
+ const blur = paint.glow.blurPx > 0 ? paint.glow.blurPx : 8;
571
+ return [{ name: "filter", value: `drop-shadow(0 0 ${compactNumber(blur * strength)}px ${alphaColor(color, opacity)})` }];
572
+ });
573
+ }
574
+
575
+ function activeBoxAnimation(
576
+ parameters: FineCaptionParameters,
577
+ startFrame: number,
578
+ endFrame: number,
579
+ durationFrames: number,
580
+ mode: "current" | "trail" = parameters.activeBox.mode === "off" ? "current" : parameters.activeBox.mode,
581
+ ): VisualAnimation {
582
+ const box = parameters.activeBox;
583
+ const logicalEnd = mode === "trail" ? durationFrames : endFrame;
584
+ const enterFrames = box.enter === "none" ? 0 : Math.min(box.transitionFrames, Math.max(0, logicalEnd - startFrame));
585
+ const exitFrames = box.exit === "none" ? 0 : Math.min(box.transitionFrames, Math.max(0, logicalEnd - startFrame));
586
+ const offsets = [
587
+ ...stepOffsets(startFrame, logicalEnd),
588
+ ...transitionOffsets(startFrame, enterFrames, box.enter),
589
+ ...transitionOffsets(logicalEnd - exitFrames, exitFrames, box.exit),
590
+ ];
591
+ return animationFrom(durationFrames, offsets, (frame) => {
592
+ if (frame < startFrame || frame > logicalEnd || (frame === logicalEnd && logicalEnd !== durationFrames)) {
593
+ return [{ name: "opacity", value: 0 }, { name: "transform", value: "scale(0.82)" }];
594
+ }
595
+ const enterProgress = enterFrames === 0 ? 1 : clamp((frame - startFrame) / enterFrames, 0, 1);
596
+ const exitProgress = exitFrames === 0 ? 1 : clamp((logicalEnd - frame) / exitFrames, 0, 1);
597
+ const kind = enterProgress < 1 ? box.enter : box.exit;
598
+ return snapshotStyle(motionSnapshot(kind, Math.min(enterProgress, exitProgress), parameters.motion.slideDistancePx),
599
+ wipes(box.enter) || wipes(box.exit));
600
+ }) ?? { keyframes: [
601
+ { atFrame: 0, style: [{ name: "opacity", value: 1 }] },
602
+ { atFrame: durationFrames, style: [{ name: "opacity", value: 1 }] },
603
+ ] };
604
+ }
605
+
606
+ function anchorTransform(parameters: FineCaptionParameters): string | undefined {
607
+ const x = parameters.placement.anchorX === "left" ? 0 : parameters.placement.anchorX === "center" ? -50 : -100;
608
+ const y = parameters.placement.anchorY === "top" ? 0 : parameters.placement.anchorY === "center" ? -50 : -100;
609
+ return x === 0 && y === 0 ? undefined : `translate(${x}%,${y}%)`;
610
+ }
611
+
612
+ function trackedPlacementAnimation(
613
+ parameters: FineCaptionParameters,
614
+ frames: readonly (SpatialFrame | null)[],
615
+ canvas: CanvasSpace,
616
+ ): VisualAnimation {
617
+ if (frames.length === 0) throw new Error("Fine Caption tracked placement has no Frames");
618
+ const anchor = anchorTransform(parameters);
619
+ const transform = (frame: SpatialFrame | null): string => {
620
+ const xPx = frame === null ? parameters.placement.x * canvas.widthPx : frame.xPx + frame.widthPx / 2;
621
+ const yPx = frame === null ? parameters.placement.y * canvas.heightPx : frame.yPx;
622
+ return `translate(${compactNumber(xPx)}px,${compactNumber(yPx)}px)${anchor === undefined ? "" : ` ${anchor}`}`;
623
+ };
624
+ const keyframes: VisualKeyframe[] = frames.map((frame, atFrame) => ({
625
+ atFrame,
626
+ style: [
627
+ { name: "transform", value: transform(frame) },
628
+ { name: "opacity", value: frame === null ? 0 : 1 },
629
+ ],
630
+ }));
631
+ keyframes.push({
632
+ atFrame: frames.length,
633
+ style: [
634
+ { name: "transform", value: transform(frames.at(-1)!) },
635
+ { name: "opacity", value: frames.at(-1) === null ? 0 : 1 },
636
+ ],
637
+ });
638
+ return { keyframes };
639
+ }
640
+
641
+ function structuralRowCount(
642
+ atoms: readonly CaptionAlignmentUnit[],
643
+ maxWordsPerLine: number,
644
+ ): number {
645
+ let rows = atoms.length === 0 ? 0 : 1;
646
+ let wordsOnRow = 0;
647
+ for (const atom of atoms) {
648
+ if (wordsOnRow > 0 && wordsOnRow + atom.wordIds.length > maxWordsPerLine) {
649
+ rows += 1;
650
+ wordsOnRow = 0;
651
+ }
652
+ wordsOnRow += atom.wordIds.length;
653
+ }
654
+ return rows;
655
+ }
656
+
657
+ /**
658
+ * Acoustic Word windows may overlap. Preserve those measurements in the
659
+ * SemanticTrack, but give every current-only visual state one unambiguous
660
+ * owner: as soon as the next authored unit starts, the previous one stops.
661
+ */
662
+ function exclusiveActivationFrames(
663
+ atoms: readonly CaptionAlignmentUnit[],
664
+ atomFrames: ReadonlyMap<string, { readonly start: number; readonly end: number }>,
665
+ ): ReadonlyMap<string, { readonly start: number; readonly end: number }> {
666
+ return new Map(atoms.map((atom, index) => {
667
+ const timing = atomFrames.get(atom.id);
668
+ if (timing === undefined) throw new Error(`Fine Caption is missing timing for Atom ${atom.id}`);
669
+ const next = atoms[index + 1];
670
+ const nextStart = next === undefined ? undefined : atomFrames.get(next.id)?.start;
671
+ if (next !== undefined && nextStart === undefined) {
672
+ throw new Error(`Fine Caption is missing timing for Atom ${next.id}`);
673
+ }
674
+ return [atom.id, {
675
+ start: timing.start,
676
+ end: nextStart === undefined ? timing.end : Math.min(timing.end, nextStart),
677
+ }];
678
+ }));
679
+ }
680
+
681
+ function cueElements(
682
+ atoms: readonly CaptionAlignmentUnit[],
683
+ atomFrames: ReadonlyMap<string, { readonly start: number; readonly end: number }>,
684
+ parameters: FineCaptionParameters,
685
+ wordText: ReadonlyMap<string, string>,
686
+ durationFrames: number,
687
+ styleId: string,
688
+ trackedPlacement?: {
689
+ readonly frames: readonly (SpatialFrame | null)[];
690
+ readonly canvas: CanvasSpace;
691
+ },
692
+ ): VisualElement[] {
693
+ type UnorderedVisualElement = Omit<VisualBoxElement, "order"> | Omit<VisualTextElement, "order">;
694
+ const elements: VisualElement[] = [];
695
+ let order = 0;
696
+ const push = (element: UnorderedVisualElement): void => {
697
+ elements.push({ ...element, order } as VisualElement);
698
+ order += 1;
699
+ };
700
+ const placementAnimation = trackedPlacement === undefined
701
+ ? undefined
702
+ : trackedPlacementAnimation(parameters, trackedPlacement.frames, trackedPlacement.canvas);
703
+ const transform = placementAnimation === undefined
704
+ ? anchorTransform(parameters)
705
+ : (() => {
706
+ const value = placementAnimation.keyframes[0]?.style.find((declaration) => declaration.name === "transform")?.value;
707
+ if (typeof value !== "string") throw new Error("Fine Caption tracked placement has no initial transform");
708
+ return value;
709
+ })();
710
+ const cueMotion = cueAnimation(parameters, durationFrames);
711
+ const cueLoop = parameters.motion.loopTarget === "cue" ? loopAnimation(parameters, durationFrames) : undefined;
712
+ const activationFrames = exclusiveActivationFrames(atoms, atomFrames);
713
+ const gapPx = `${compactNumber(parameters.layout.wordGapPx)}px`;
714
+ const atomSurfaces = atoms.map((atom) => atom.wordIds.map((wordId) => wordText.get(wordId) ?? ""));
715
+ // A Cue whose boundaries all agree carries one `column-gap`, which is also what keeps a row that
716
+ // wraps from opening on a margin. A Cue that mixes scripts spaces each element instead.
717
+ const atomGaps = atomSurfaces.map((surfaces, index) => {
718
+ const previous = atomSurfaces[index - 1];
719
+ return previous === undefined ? false : wordGapBetween(previous.at(-1) ?? "", surfaces[0] ?? "");
720
+ });
721
+ const cueGap = uniformGap(atomGaps);
722
+ // The Visual IR carries physical margins, so the leading edge follows the Cue's own direction.
723
+ const marginStart = parameters.layout.direction === "rtl" ? "margin-right" : "margin-left";
724
+ const spacedStyle = (spaced: boolean): readonly VisualStyleDeclaration[] =>
725
+ spaced ? [{ name: marginStart, value: gapPx }] : [];
726
+ const fonts = parameters.typography.exactFonts;
727
+ if (parameters.layout.maxLines !== undefined) {
728
+ const rows = structuralRowCount(atoms, parameters.layout.maxWordsPerLine!);
729
+ if (rows > parameters.layout.maxLines) {
730
+ throw new Error(`Fine Caption Style ${styleId} constructs ${rows} rows for a Cue whose maximum is ${parameters.layout.maxLines}`);
731
+ }
732
+ }
733
+ push({
734
+ id: "placement",
735
+ kind: "box",
736
+ style: [
737
+ { name: "align-items", value: parameters.layout.blockAlign === "start" ? "flex-start"
738
+ : parameters.layout.blockAlign === "end" ? "flex-end" : "center" },
739
+ { name: "display", value: "flex" },
740
+ { name: "justify-content", value: parameters.layout.textAlign === "left" ? "flex-start"
741
+ : parameters.layout.textAlign === "right" ? "flex-end" : "center" },
742
+ { name: "left", value: placementAnimation === undefined ? `${compactNumber(parameters.placement.x * 100)}%` : "0px" },
743
+ { name: "position", value: "absolute" },
744
+ { name: "top", value: placementAnimation === undefined ? `${compactNumber(parameters.placement.y * 100)}%` : "0px" },
745
+ ...(parameters.placement.height === undefined ? [] : [
746
+ { name: "height", value: `${compactNumber(parameters.placement.height * 100)}%` },
747
+ ] as const),
748
+ ...(transform === undefined ? [] : [{ name: "transform", value: transform }] as const),
749
+ { name: "width", value: `${compactNumber(parameters.placement.width * 100)}%` },
750
+ ],
751
+ ...(placementAnimation === undefined ? {} : { animation: placementAnimation }),
752
+ });
753
+ push({
754
+ id: "cue-motion",
755
+ parent: "placement",
756
+ kind: "box",
757
+ style: [{ name: "display", value: "inline-grid" }, { name: "transform-origin", value: "center center" }],
758
+ ...(cueMotion === undefined ? {} : { animation: cueMotion }),
759
+ });
760
+ push({
761
+ id: "cue-loop",
762
+ parent: "cue-motion",
763
+ kind: "box",
764
+ style: [
765
+ { name: "display", value: "inline-flex" },
766
+ { name: "grid-area", value: "1 / 1" },
767
+ { name: "transform-origin", value: "center center" },
768
+ ],
769
+ ...(cueLoop === undefined ? {} : { animation: cueLoop }),
770
+ });
771
+ push({
772
+ id: "cue",
773
+ parent: "cue-loop",
774
+ kind: "box",
775
+ style: [
776
+ { name: "background", value: parameters.cueBox.background },
777
+ ...(parameters.cueBox.shadow.opacity === 0 ? [] : [{
778
+ name: "box-shadow",
779
+ value: `${compactNumber(parameters.cueBox.shadow.offsetXPx)}px ${compactNumber(parameters.cueBox.shadow.offsetYPx)}px ${compactNumber(parameters.cueBox.shadow.blurPx)}px ${compactNumber(parameters.cueBox.shadow.spreadPx)}px ${alphaColor(parameters.cueBox.shadow.color, parameters.cueBox.shadow.opacity)}`,
780
+ }] as const),
781
+ { name: "box-sizing", value: "border-box" },
782
+ { name: "border-color", value: parameters.cueBox.borderColor },
783
+ { name: "border-radius", value: `${compactNumber(parameters.cueBox.radiusPx)}px` },
784
+ { name: "border-style", value: "solid" },
785
+ { name: "border-width", value: `${compactNumber(parameters.cueBox.borderWidthPx)}px` },
786
+ ...(cueGap === true ? [{ name: "column-gap", value: gapPx }] as const : []),
787
+ { name: "direction", value: parameters.layout.direction },
788
+ { name: "display", value: "flex" },
789
+ { name: "flex-wrap", value: "wrap" },
790
+ { name: "justify-content", value: parameters.layout.textAlign === "left" ? "flex-start"
791
+ : parameters.layout.textAlign === "right" ? "flex-end" : "center" },
792
+ { name: "max-width", value: "100%" },
793
+ { name: "overflow", value: "visible" },
794
+ { name: "padding", value: `${compactNumber(parameters.cueBox.paddingYPx)}px ${compactNumber(parameters.cueBox.paddingXPx)}px` },
795
+ { name: "position", value: "relative" },
796
+ { name: "text-align", value: parameters.layout.textAlign },
797
+ { name: "width", value: parameters.layout.inlineSize === "fixed" ? "100%" : "max-content" },
798
+ ],
799
+ });
800
+
801
+ if (parameters.activeBox.mode === "trail" && parameters.activeBox.continuity === "joined") {
802
+ for (const [prefixIndex, atom] of atoms.entries()) {
803
+ const timing = atomFrames.get(atom.id);
804
+ if (timing === undefined) throw new Error(`Fine Caption is missing timing for Atom ${atom.id}`);
805
+ const next = atoms[prefixIndex + 1];
806
+ const nextStart = next === undefined ? durationFrames : atomFrames.get(next.id)?.start;
807
+ if (nextStart === undefined) throw new Error("Fine Caption is missing timing for the next Atom");
808
+ // A no-break space inside an atom keeps its words on one row; the boundaries between atoms
809
+ // take an ordinary space. Both are spaced only where the surfaces meeting there call for one.
810
+ const prefixText = joinSurfaces(
811
+ atoms.slice(0, prefixIndex + 1).map((prefixAtom, index) => {
812
+ for (const wordId of prefixAtom.wordIds) {
813
+ if (!wordText.has(wordId)) throw new Error(`Fine Caption Atom references unknown word ${wordId}`);
814
+ }
815
+ return joinSurfaces(atomSurfaces[index] ?? [], "\u00A0");
816
+ }),
817
+ " ",
818
+ );
819
+ const layerId = `joined-box-${prefixIndex + 1}`;
820
+ push({
821
+ id: layerId,
822
+ parent: "cue",
823
+ kind: "box",
824
+ style: [
825
+ { name: "box-sizing", value: "border-box" },
826
+ { name: "direction", value: parameters.layout.direction },
827
+ { name: "inset", value: "0" },
828
+ { name: "padding", value: `${compactNumber(parameters.cueBox.paddingYPx)}px ${compactNumber(parameters.cueBox.paddingXPx)}px` },
829
+ { name: "position", value: "absolute" },
830
+ { name: "text-align", value: parameters.layout.textAlign },
831
+ ],
832
+ animation: activeBoxAnimation(parameters, timing.start, nextStart, durationFrames, "current"),
833
+ attributes: [{ name: "data-caption-active-box", value: "joined" }],
834
+ });
835
+ push({
836
+ id: `${layerId}-text`,
837
+ parent: layerId,
838
+ kind: "text",
839
+ text: prefixText,
840
+ style: [
841
+ ...transparentGlyphStyle(parameters).filter(({ name }) => name !== "white-space"),
842
+ { name: "-webkit-box-decoration-break", value: "clone" },
843
+ { name: "background", value: parameters.activeBox.background },
844
+ { name: "border-color", value: parameters.activeBox.borderColor },
845
+ { name: "border-radius", value: `${compactNumber(parameters.activeBox.radiusPx)}px` },
846
+ { name: "border-style", value: "solid" },
847
+ { name: "border-width", value: `${compactNumber(parameters.activeBox.borderWidthPx)}px` },
848
+ { name: "box-decoration-break", value: "clone" },
849
+ { name: "display", value: "inline" },
850
+ { name: "padding", value: `${compactNumber(parameters.activeBox.paddingYPx)}px ${compactNumber(parameters.activeBox.paddingXPx)}px` },
851
+ { name: "white-space", value: "normal" },
852
+ ],
853
+ fonts,
854
+ });
855
+ }
856
+ }
857
+
858
+ let wordsOnLine = 0;
859
+ for (const [atomIndex, atom] of atoms.entries()) {
860
+ const timing = atomFrames.get(atom.id);
861
+ if (timing === undefined) throw new Error(`Fine Caption is missing timing for Atom ${atom.id}`);
862
+ const activationTiming = activationFrames.get(atom.id);
863
+ if (activationTiming === undefined) throw new Error(`Fine Caption is missing activation timing for Atom ${atom.id}`);
864
+ const atomId = `atom-${atomIndex + 1}`;
865
+ const surfaces = atomSurfaces[atomIndex] ?? [];
866
+ // The base glyphs and the activated copy stacked over them are laid out from this one list, so
867
+ // the karaoke wipe keeps sitting on the letterforms it reveals.
868
+ const gaps = wordGaps(surfaces);
869
+ const wordGap = uniformGap(gaps);
870
+ const atomText = joinSurfaces(surfaces, " ");
871
+ const entryId = `${atomId}-entry`;
872
+ const typewriterId = `${atomId}-typewriter`;
873
+ const loopId = `${atomId}-loop`;
874
+ const responseId = `${atomId}-response`;
875
+ if (parameters.layout.maxWordsPerLine !== undefined
876
+ && wordsOnLine > 0
877
+ && wordsOnLine + atom.wordIds.length > parameters.layout.maxWordsPerLine) {
878
+ push({
879
+ id: `line-break-${atomIndex}`,
880
+ parent: "cue",
881
+ kind: "box",
882
+ style: [{ name: "flex-basis", value: "100%" }, { name: "height", value: "0" }],
883
+ });
884
+ wordsOnLine = 0;
885
+ }
886
+ const entryAnimation = atomLifecycleAnimation(parameters, timing.start, timing.end, durationFrames);
887
+ const writerAnimation = typewriterAnimation(atomText, parameters, timing.start, timing.end, durationFrames);
888
+ const atomLoop = parameters.motion.loopTarget === "active-atom"
889
+ ? loopAnimation(parameters, durationFrames, activationTiming) : undefined;
890
+ const responseAnimation = activeResponseAnimation(
891
+ parameters,
892
+ activationTiming.start,
893
+ activationTiming.end,
894
+ durationFrames,
895
+ );
896
+ push({
897
+ id: entryId,
898
+ parent: "cue",
899
+ kind: "box",
900
+ style: [
901
+ { name: "display", value: "inline-flex" },
902
+ { name: "min-width", value: "0" },
903
+ // A row that wraps opens at its own edge, so an atom that starts one carries no margin.
904
+ ...(cueGap === undefined && wordsOnLine > 0 ? spacedStyle(atomGaps[atomIndex] ?? false) : []),
905
+ { name: "transform-origin", value: "center center" },
906
+ ],
907
+ ...(entryAnimation === undefined ? {} : { animation: entryAnimation }),
908
+ });
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
+ push({
921
+ id: loopId,
922
+ parent: typewriterId,
923
+ kind: "box",
924
+ style: [
925
+ { name: "display", value: "inline-flex" },
926
+ { name: "min-width", value: "0" },
927
+ { name: "transform-origin", value: "center center" },
928
+ ],
929
+ ...(atomLoop === undefined ? {} : { animation: atomLoop }),
930
+ });
931
+ push({
932
+ id: responseId,
933
+ parent: loopId,
934
+ kind: "box",
935
+ style: [
936
+ { name: "display", value: "inline-flex" },
937
+ { name: "min-width", value: "0" },
938
+ { name: "transform-origin", value: "center center" },
939
+ ],
940
+ ...(responseAnimation === undefined ? {} : { animation: responseAnimation }),
941
+ });
942
+ push({
943
+ id: atomId,
944
+ parent: responseId,
945
+ kind: "box",
946
+ style: [
947
+ ...(wordGap === true ? [{ name: "column-gap", value: gapPx }] as const : []),
948
+ { name: "display", value: "inline-flex" },
949
+ { name: "min-width", value: "0" },
950
+ { name: "overflow-wrap", value: "anywhere" },
951
+ { name: "position", value: "relative" },
952
+ { name: "white-space", value: "normal" },
953
+ { name: "word-break", value: parameters.layout.wrap === "grapheme" ? "break-all" : "normal" },
954
+ ],
955
+ attributes: [{ name: "data-caption-atom", value: atom.id }],
956
+ });
957
+ const useIsolatedBox = parameters.activeBox.mode !== "off"
958
+ && !(parameters.activeBox.mode === "trail" && parameters.activeBox.continuity === "joined");
959
+ if (useIsolatedBox) {
960
+ push({
961
+ id: `${atomId}-box`,
962
+ parent: atomId,
963
+ kind: "box",
964
+ style: [
965
+ { name: "background", value: parameters.activeBox.background },
966
+ { name: "border-color", value: parameters.activeBox.borderColor },
967
+ { name: "border-radius", value: `${compactNumber(parameters.activeBox.radiusPx)}px` },
968
+ { name: "border-style", value: "solid" },
969
+ { name: "border-width", value: `${compactNumber(parameters.activeBox.borderWidthPx)}px` },
970
+ { name: "bottom", value: `${compactNumber(-parameters.activeBox.paddingYPx)}px` },
971
+ { name: "left", value: `${compactNumber(-parameters.activeBox.paddingXPx)}px` },
972
+ { name: "position", value: "absolute" },
973
+ { name: "right", value: `${compactNumber(-parameters.activeBox.paddingXPx)}px` },
974
+ { name: "top", value: `${compactNumber(-parameters.activeBox.paddingYPx)}px` },
975
+ { name: "transform-origin", value: "center center" },
976
+ ],
977
+ animation: activeBoxAnimation(
978
+ parameters,
979
+ parameters.activeBox.mode === "current" ? activationTiming.start : timing.start,
980
+ parameters.activeBox.mode === "current" ? activationTiming.end : timing.end,
981
+ durationFrames,
982
+ ),
983
+ attributes: [{ name: "data-caption-active-box", value: "isolated" }],
984
+ });
985
+ }
986
+ for (const [wordIndex, wordId] of atom.wordIds.entries()) {
987
+ const text = wordText.get(wordId);
988
+ if (text === undefined) throw new Error(`Fine Caption Atom references unknown word ${wordId}`);
989
+ push({
990
+ id: `${atomId}-base-${wordIndex + 1}`,
991
+ parent: atomId,
992
+ kind: "text",
993
+ text,
994
+ style: [
995
+ ...glyphStyle(parameters, parameters.basePaint, parameters.underline),
996
+ ...(wordGap === undefined ? spacedStyle(gaps[wordIndex] ?? false) : []),
997
+ ],
998
+ ...glyphPaintFields(parameters.basePaint),
999
+ fonts,
1000
+ });
1001
+ }
1002
+ const addActivatedTextLayer = (
1003
+ suffix: string,
1004
+ mode: "current" | "trail",
1005
+ kind: "glyph" | "underline",
1006
+ ): void => {
1007
+ const activeId = `${atomId}-${suffix}`;
1008
+ const activeTiming = mode === "current" ? activationTiming : timing;
1009
+ push({
1010
+ id: activeId,
1011
+ parent: atomId,
1012
+ kind: "box",
1013
+ style: [
1014
+ ...(wordGap === true ? [{ name: "column-gap", value: gapPx }] as const : []),
1015
+ { name: "display", value: "inline-flex" },
1016
+ { name: "inset", value: "0" },
1017
+ // The wipe's own `clip-path` is what reveals this layer a word at a time, and it clips to the
1018
+ // same border box, so an `overflow` here adds nothing — except at full reveal, where the
1019
+ // clip has opened and this was still cutting the outline off at the glyph advance.
1020
+ { name: "position", value: "absolute" },
1021
+ ],
1022
+ animation: kind === "glyph" && parameters.karaoke.transition === "wipe"
1023
+ ? karaokeWipeAnimation(parameters, mode, activeTiming.start, activeTiming.end, durationFrames)
1024
+ : activationStepAnimation(mode, activeTiming.start, activeTiming.end, durationFrames),
1025
+ attributes: [{ name: kind === "glyph" ? "data-caption-karaoke" : "data-caption-active-underline", value: mode }],
1026
+ });
1027
+ for (const [wordIndex, wordId] of atom.wordIds.entries()) {
1028
+ const text = wordText.get(wordId)!;
1029
+ push({
1030
+ id: `${activeId}-${wordIndex + 1}`,
1031
+ parent: activeId,
1032
+ kind: "text",
1033
+ text,
1034
+ style: [
1035
+ ...(kind === "glyph"
1036
+ ? glyphStyle(parameters, parameters.activePaint)
1037
+ : transparentGlyphStyle(parameters, parameters.activeUnderline)),
1038
+ ...(wordGap === undefined ? spacedStyle(gaps[wordIndex] ?? false) : []),
1039
+ ],
1040
+ // The underline layer paints no glyph at all, so it declares no glyph Paint either.
1041
+ ...(kind === "glyph" ? glyphPaintFields(parameters.activePaint) : {}),
1042
+ fonts,
1043
+ attributes: [{ name: kind === "glyph" ? "data-caption-active-word" : "data-caption-underlined-word", value: wordId }],
1044
+ });
1045
+ }
1046
+ };
1047
+ if (parameters.karaoke.mode !== "off") addActivatedTextLayer("active", parameters.karaoke.mode, "glyph");
1048
+ if (parameters.activeUnderline.mode !== "off") {
1049
+ addActivatedTextLayer("underline", parameters.activeUnderline.mode, "underline");
1050
+ }
1051
+ wordsOnLine += atom.wordIds.length;
1052
+ }
1053
+ return elements;
1054
+ }
1055
+
1056
+ export function renderFineCaption(
1057
+ schedule: FineCaptionSchedule,
1058
+ program: CaptionProgram,
1059
+ document: CaptionDocument,
1060
+ space: ProgramSpace,
1061
+ regions?: SpatialRegionTimeline,
1062
+ ): VisualTrack {
1063
+ assertFineCaptionSchedule(schedule);
1064
+ assertCaptionProgramForDocument(program, document);
1065
+ 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");
1072
+ }
1073
+ const styles = new Map(program.styles.map((style) => [style.id, style]));
1074
+ const wordText = new Map(document.words.map((word) => [word.id, word.text]));
1075
+ const atomById = new Map(document.units.map((atom) => [atom.id, atom]));
1076
+ for (const style of styles.values()) {
1077
+ if (style.rendering.family !== FINE_CAPTION_FAMILY) {
1078
+ throw new Error(`Fine Caption cannot render Style family ${style.rendering.family}`);
1079
+ }
1080
+ assertFineCaptionParameters(style.rendering.parameters as unknown as FineCaptionParameters);
1081
+ }
1082
+ const totalFrames = programSpaceFrameCount(space);
1083
+ const regionTracks = regions === undefined ? undefined : (() => {
1084
+ assertSpatialRegionTimeline(regions);
1085
+ if (regions.frameCount !== totalFrames) {
1086
+ throw new Error(`Fine Caption regions cover ${regions.frameCount} Frames but ProgramSpace has ${totalFrames}`);
1087
+ }
1088
+ return new Map(regions.tracks.map((track) => [track.id, track]));
1089
+ })();
1090
+ const presents = schedule.cues.flatMap((cue) => {
1091
+ const atoms = cue.units.map((timing) => atomById.get(timing.unitId));
1092
+ if (atoms.some((atom) => atom === undefined)) throw new Error(`Fine Caption Cue ${cue.id} references unknown Atom`);
1093
+ const resolvedAtoms = atoms.map((atom) => atom!);
1094
+ const style = styles.get(cue.styleId);
1095
+ if (style === undefined) throw new Error(`Fine Caption Cue ${cue.id} references unknown Style ${cue.styleId}`);
1096
+ const parameters = style.rendering.parameters as unknown as FineCaptionParameters;
1097
+ const startFrame = Math.max(0, cue.visibleStartFrame);
1098
+ const measuredEnd = Math.min(totalFrames, cue.visibleEndFrameExclusive);
1099
+ const endFrameExclusive = Math.min(totalFrames, Math.max(startFrame + 1, measuredEnd));
1100
+ if (startFrame >= totalFrames || endFrameExclusive <= startFrame) return [];
1101
+ const durationFrames = endFrameExclusive - startFrame;
1102
+ const trackedPlacement = regionTracks === undefined ? undefined : (() => {
1103
+ const role = resolvedAtoms[0]?.role;
1104
+ if (role === undefined || resolvedAtoms.some((atom) => atom.role !== role)) {
1105
+ throw new Error(`Fine Caption Cue ${cue.id} must contain exactly one Script Role to follow regions`);
1106
+ }
1107
+ const track = regionTracks.get(role);
1108
+ if (track === undefined) return undefined;
1109
+ return {
1110
+ frames: track.frames.slice(startFrame, endFrameExclusive),
1111
+ canvas: regions!.canvas,
1112
+ };
1113
+ })();
1114
+ const atomFrames = new Map(cue.units.map((atom) => [atom.unitId, {
1115
+ start: clamp(atom.startFrame - startFrame, 0, durationFrames),
1116
+ end: clamp(Math.max(atom.endFrameExclusive - startFrame, atom.startFrame - startFrame + 1), 0, durationFrames),
1117
+ }]));
1118
+ return [{
1119
+ id: cue.id,
1120
+ span: { startFrame, endFrameExclusive },
1121
+ stacking: { order: parameters.stackingOrder, tieBreak: `${program.id}:${cue.id}` },
1122
+ elements: cueElements(resolvedAtoms, atomFrames, parameters, wordText, durationFrames, cue.styleId, trackedPlacement),
1123
+ }];
1124
+ });
1125
+ const track = sealVisualTrack({
1126
+ programSpaceId: space.id,
1127
+ visualIr: "hypit.visual-ir@1",
1128
+ id: program.id,
1129
+ presents,
1130
+ });
1131
+ assertVisualTrackIdentity(track, space);
1132
+ return track;
1133
+ }