@hypit/hypit 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (486) hide show
  1. package/README.md +5 -3
  2. package/dist/public/caption.d.ts +206 -183
  3. package/dist/public/composition.d.ts +25 -3
  4. package/dist/public/endpoint-kit.d.ts +24 -2
  5. package/dist/public/generation.d.ts +5 -1
  6. package/dist/public/hyperframes.d.ts +19 -1
  7. package/dist/public/narrative.d.ts +17 -3
  8. package/dist/public/performance.d.ts +1590 -0
  9. package/dist/public/program-space.d.ts +179 -32
  10. package/dist/public/runtime-kit.d.ts +21 -8
  11. package/dist/public/sound.d.ts +822 -0
  12. package/dist/public/speech.d.ts +41 -0
  13. package/dist/public/studio-adapter.d.ts +107 -16
  14. package/dist/public/temporal-markup.d.ts +9 -44
  15. package/dist/public/temporal.d.ts +37 -28
  16. package/dist/public/{semantic-track.d.ts → timeline.d.ts} +62 -49
  17. package/examples/README.md +18 -10
  18. package/examples/minimal-author-package/packages/example-component/preview/preview.svml +19 -12
  19. package/examples/minimal-author-package/packages/example-component/src/component.ts +5 -5
  20. package/examples/minimal-author-package/packages/example-component/src/fragment.ts +3 -5
  21. package/examples/minimal-author-package/packages/example-component/src/manifest.ts +8 -10
  22. package/examples/minimal-author-package/packages/example-component/src/surface.ts +2 -2
  23. package/examples/provider-package/README.md +78 -0
  24. package/examples/provider-package/hypit.runtime.json +12 -0
  25. package/examples/provider-package/packages/provider-images/package.json +11 -0
  26. package/examples/provider-package/packages/provider-images/src/activation.ts +24 -0
  27. package/examples/provider-package/packages/provider-images/src/provider.ts +122 -0
  28. package/examples/provider-package/packages/provider-images/tsconfig.json +9 -0
  29. package/examples/semantic-composition/README.md +6 -0
  30. package/examples/semantic-composition/chat.svml +6 -5
  31. package/examples/semantic-composition/packages/chat-scene/README.md +3 -3
  32. package/examples/semantic-composition/packages/chat-scene/src/activation.ts +18 -21
  33. package/examples/semantic-composition/packages/chat-scene/src/render.ts +4 -4
  34. package/examples/semantic-composition/packages/performance-styles/README.md +42 -0
  35. package/examples/semantic-composition/packages/performance-styles/package.json +25 -0
  36. package/examples/semantic-composition/packages/performance-styles/src/activation.ts +57 -0
  37. package/examples/semantic-composition/packages/performance-styles/src/render.ts +54 -0
  38. package/examples/semantic-composition/packages/performance-styles/src/studio.ts +28 -0
  39. package/examples/semantic-composition/packages/performance-styles/tsconfig.json +18 -0
  40. package/examples/semantic-composition/packages/responsive-explainer/README.md +16 -9
  41. package/examples/semantic-composition/packages/responsive-explainer/src/activation.ts +12 -12
  42. package/examples/semantic-composition/packages/responsive-explainer/src/render.ts +5 -5
  43. package/examples/semantic-composition/packages/sound-styles/README.md +36 -0
  44. package/examples/semantic-composition/packages/sound-styles/package.json +25 -0
  45. package/examples/semantic-composition/packages/sound-styles/src/activation.ts +53 -0
  46. package/examples/semantic-composition/packages/sound-styles/src/render.ts +14 -0
  47. package/examples/semantic-composition/packages/sound-styles/tsconfig.json +18 -0
  48. package/package.json +35 -15
  49. package/packages/audio-track/README.md +20 -13
  50. package/packages/audio-track/package.json +1 -1
  51. package/packages/audio-track/src/component.ts +4 -4
  52. package/packages/audio-track/src/fragment.ts +6 -5
  53. package/packages/audio-track/src/index.ts +1 -1
  54. package/packages/audio-track/src/manifest.ts +17 -16
  55. package/packages/audio-track/src/program.ts +21 -25
  56. package/packages/audio-track/src/surface.ts +19 -18
  57. package/packages/audio-track-studio/README.md +23 -0
  58. package/packages/audio-track-studio/src/index.ts +33 -19
  59. package/packages/author-kit/README.md +1 -1
  60. package/packages/background-removal/README.md +4 -7
  61. package/packages/browser-capture/package.json +1 -1
  62. package/packages/build-result/README.md +69 -0
  63. package/packages/build-result/package.json +2 -1
  64. package/packages/build-result/src/decode.ts +12 -8
  65. package/packages/build-result/src/execution-log.ts +17 -0
  66. package/packages/build-result/src/file-reference.ts +42 -0
  67. package/packages/build-result/src/index.ts +4 -0
  68. package/packages/build-result/src/replace-file-windows.ts +58 -0
  69. package/packages/build-result/src/replace-file.ts +11 -0
  70. package/packages/build-result/src/store.ts +58 -14
  71. package/packages/build-result/src/types.ts +41 -8
  72. package/packages/build-result/src/writer.ts +12 -1
  73. package/packages/build-result-fs/README.md +23 -1
  74. package/packages/build-result-s3/README.md +5 -0
  75. package/packages/build-result-s3/src/repository.ts +23 -5
  76. package/packages/caption/README.md +61 -73
  77. package/packages/caption/package.json +3 -2
  78. package/packages/caption/src/activation.ts +2 -2
  79. package/packages/caption/src/component.ts +20 -5
  80. package/packages/caption/src/display.ts +3 -18
  81. package/packages/caption/src/fragment.ts +3 -7
  82. package/packages/caption/src/index.ts +6 -5
  83. package/packages/caption/src/manifest.ts +29 -46
  84. package/packages/caption/src/style.ts +24 -135
  85. package/packages/caption/src/surface.ts +12 -92
  86. package/packages/caption/src/temporalize.ts +18 -53
  87. package/packages/caption/src/types.ts +8 -35
  88. package/packages/caption/src/visibility.ts +23 -0
  89. package/packages/caption-fine/README.md +31 -11
  90. package/packages/caption-fine/package.json +4 -2
  91. package/packages/caption-fine/src/component.ts +3 -3
  92. package/packages/caption-fine/src/fragment.ts +7 -19
  93. package/packages/caption-fine/src/index.ts +2 -0
  94. package/packages/caption-fine/src/manifest.ts +27 -18
  95. package/packages/caption-fine/src/recipe.ts +7 -0
  96. package/packages/caption-fine/src/render.ts +62 -49
  97. package/packages/caption-fine/src/schedule.ts +39 -35
  98. package/packages/caption-fine/src/style.ts +10 -9
  99. package/packages/caption-fine/src/surface.ts +62 -35
  100. package/packages/caption-fine/src/types.ts +2 -0
  101. package/packages/caption-fine-studio/README.md +24 -2
  102. package/packages/caption-fine-studio/package.json +10 -3
  103. package/packages/caption-fine-studio/src/activation.ts +3 -3
  104. package/packages/caption-fine-studio/src/index.ts +61 -40
  105. package/packages/cli/README.md +81 -3
  106. package/packages/cli/package.json +1 -0
  107. package/packages/cli/src/arguments.ts +39 -15
  108. package/packages/cli/src/build-planning.ts +9 -3
  109. package/packages/cli/src/command.ts +7 -1
  110. package/packages/cli/src/commands/environment.ts +66 -27
  111. package/packages/cli/src/commands/execution.ts +81 -26
  112. package/packages/cli/src/commands/results.ts +7 -11
  113. package/packages/cli/src/index.ts +2 -2
  114. package/packages/cli/src/machine-view.ts +15 -5
  115. package/packages/cli/src/main.ts +38 -42
  116. package/packages/cli/src/observation.ts +7 -1
  117. package/packages/cli/src/output.ts +92 -34
  118. package/packages/cli/src/result-export.ts +22 -13
  119. package/packages/cli/src/run-file.ts +19 -8
  120. package/packages/cli/src/view.ts +64 -18
  121. package/packages/comment-sticker/README.md +3 -3
  122. package/packages/comment-sticker/package.json +1 -1
  123. package/packages/comment-sticker/src/component.ts +4 -4
  124. package/packages/comment-sticker/src/fragment.ts +5 -4
  125. package/packages/comment-sticker/src/manifest.ts +7 -6
  126. package/packages/comment-sticker/src/program.ts +9 -9
  127. package/packages/comment-sticker/src/surface.ts +6 -7
  128. package/packages/comment-sticker-studio/src/index.ts +2 -1
  129. package/packages/compiler-node/src/compiler.ts +1 -0
  130. package/packages/composition/README.md +21 -0
  131. package/packages/composition/src/audio-presentation.ts +44 -0
  132. package/packages/composition/src/index.ts +3 -0
  133. package/packages/composition/src/schema.ts +8 -3
  134. package/packages/composition/src/track.ts +15 -1
  135. package/packages/credential-store-env/README.md +1 -1
  136. package/packages/deck-track/README.md +3 -3
  137. package/packages/deck-track/package.json +1 -1
  138. package/packages/deck-track/src/component.ts +5 -5
  139. package/packages/deck-track/src/fragment.ts +6 -5
  140. package/packages/deck-track/src/lower.ts +12 -12
  141. package/packages/deck-track/src/manifest.ts +8 -7
  142. package/packages/deck-track/src/program.ts +13 -16
  143. package/packages/deck-track/src/surface.ts +9 -10
  144. package/packages/driver-node/src/driver.ts +41 -3
  145. package/packages/elevenlabs-speech/README.md +27 -0
  146. package/packages/{provider-xiaomi-mimo → elevenlabs-speech}/package.json +5 -8
  147. package/packages/elevenlabs-speech/src/activation.ts +26 -0
  148. package/packages/elevenlabs-speech/src/fragment.ts +11 -0
  149. package/packages/elevenlabs-speech/src/index.ts +111 -0
  150. package/packages/elevenlabs-speech/src/surface.ts +167 -0
  151. package/packages/endpoint-kit/README.md +24 -0
  152. package/packages/endpoint-kit/src/index.ts +7 -1
  153. package/packages/estimate/README.md +56 -3
  154. package/packages/estimate/src/program.ts +7 -8
  155. package/packages/film/README.md +12 -7
  156. package/packages/film/package.json +1 -1
  157. package/packages/film/src/component.ts +4 -4
  158. package/packages/film/src/fragment.ts +6 -5
  159. package/packages/film/src/manifest.ts +11 -10
  160. package/packages/film/src/program.ts +5 -5
  161. package/packages/film/src/recipe.ts +2 -1
  162. package/packages/film/src/surface.ts +6 -6
  163. package/packages/film-studio/package.json +1 -1
  164. package/packages/film-studio/src/index.ts +2 -2
  165. package/packages/fishaudio-speech/README.md +33 -0
  166. package/packages/fishaudio-speech/package.json +21 -0
  167. package/packages/fishaudio-speech/src/activation.ts +32 -0
  168. package/packages/fishaudio-speech/src/fragment.ts +11 -0
  169. package/packages/fishaudio-speech/src/index.ts +156 -0
  170. package/packages/fishaudio-speech/src/surface.ts +192 -0
  171. package/packages/fonts-open/README.md +5 -0
  172. package/packages/fonts-open/package.json +5 -1
  173. package/packages/fonts-open/src/studio.ts +21 -0
  174. package/packages/generation/README.md +11 -1
  175. package/packages/generation/src/mapping.ts +28 -30
  176. package/packages/gpt-image/README.md +1 -2
  177. package/packages/grok-imagine/README.md +1 -2
  178. package/packages/hyperframes/README.md +7 -3
  179. package/packages/hyperframes/src/browser-program.ts +11 -2
  180. package/packages/hyperframes/src/document.ts +15 -2
  181. package/packages/interview-emoji-reveal/README.md +4 -4
  182. package/packages/interview-emoji-reveal/package.json +1 -1
  183. package/packages/interview-emoji-reveal/src/component.ts +4 -4
  184. package/packages/interview-emoji-reveal/src/fragment.ts +6 -5
  185. package/packages/interview-emoji-reveal/src/manifest.ts +9 -8
  186. package/packages/interview-emoji-reveal/src/program.ts +14 -14
  187. package/packages/interview-emoji-reveal/src/surface.ts +8 -9
  188. package/packages/media-execution/README.md +7 -3
  189. package/packages/media-execution/src/audio-presentation.ts +23 -0
  190. package/packages/media-execution/src/execute.ts +2 -0
  191. package/packages/media-pipeline/README.md +7 -3
  192. package/packages/media-pipeline/src/audio-plan.ts +4 -1
  193. package/packages/media-pipeline/src/component.ts +16 -2
  194. package/packages/media-pipeline/src/manifest.ts +3 -1
  195. package/packages/media-pipeline/src/types.ts +2 -1
  196. package/packages/media-track/README.md +14 -47
  197. package/packages/media-track/package.json +1 -1
  198. package/packages/media-track/preview/preview.svml +5 -5
  199. package/packages/media-track/src/author.ts +12 -6
  200. package/packages/media-track/src/component.ts +10 -16
  201. package/packages/media-track/src/fragment.ts +8 -7
  202. package/packages/media-track/src/index.ts +3 -1
  203. package/packages/media-track/src/lower.ts +7 -7
  204. package/packages/media-track/src/manifest.ts +16 -38
  205. package/packages/media-track/src/program.ts +62 -67
  206. package/packages/media-track/src/sampling.ts +6 -6
  207. package/packages/media-track/src/sequence.ts +8 -8
  208. package/packages/media-track/src/surface.ts +25 -43
  209. package/packages/media-track-studio/README.md +9 -0
  210. package/packages/media-track-studio/src/index.ts +23 -13
  211. package/packages/mimo-speech/README.md +1 -1
  212. package/packages/minimax-h3/README.md +1 -1
  213. package/packages/nano-banana/README.md +1 -1
  214. package/packages/narrative/README.md +23 -1
  215. package/packages/narrative/src/identity.ts +11 -0
  216. package/packages/narrative/src/index.ts +3 -0
  217. package/packages/narrative/src/schema.ts +28 -27
  218. package/packages/narrative/src/selection.ts +52 -0
  219. package/packages/narrative/src/types.ts +2 -0
  220. package/packages/package-loader-node/README.md +30 -0
  221. package/packages/package-loader-node/package.json +5 -2
  222. package/packages/package-loader-node/src/distribution-resolution.ts +10 -3
  223. package/packages/package-loader-node/src/index.ts +1 -0
  224. package/packages/package-loader-node/src/loader.ts +12 -15
  225. package/packages/package-loader-node/src/location.ts +27 -1
  226. package/packages/package-loader-node/src/module-scope.ts +183 -0
  227. package/packages/package-loader-node/src/types.ts +4 -0
  228. package/packages/performance/README.md +83 -0
  229. package/packages/performance/package.json +30 -0
  230. package/packages/performance/src/activation.ts +11 -0
  231. package/packages/performance/src/component.ts +46 -0
  232. package/packages/performance/src/index.ts +6 -0
  233. package/packages/performance/src/manifest.ts +53 -0
  234. package/packages/{media-track/src/performance.ts → performance/src/media.ts} +9 -10
  235. package/packages/performance/src/program.ts +51 -0
  236. package/packages/performance/src/style.ts +35 -0
  237. package/packages/performance/src/surface.ts +99 -0
  238. package/packages/performance-studio/README.md +25 -0
  239. package/packages/performance-studio/package.json +21 -0
  240. package/packages/performance-studio/src/activation.ts +6 -0
  241. package/packages/performance-studio/src/index.ts +84 -0
  242. package/packages/program-space/README.md +9 -18
  243. package/packages/program-space/src/activation.ts +1 -5
  244. package/packages/program-space/src/index.ts +2 -11
  245. package/packages/program-space/src/surface.ts +1 -20
  246. package/packages/project-context-node/README.md +20 -0
  247. package/packages/project-context-node/package.json +10 -0
  248. package/packages/project-context-node/src/index.ts +3 -0
  249. package/packages/{cli → project-context-node}/src/runtime-selection.ts +7 -2
  250. package/packages/provider-hyperframes-local/README.md +43 -15
  251. package/packages/provider-hyperframes-local/src/activation.ts +4 -3
  252. package/packages/provider-hyperframes-local/src/capture-process.ts +26 -4
  253. package/packages/provider-hyperframes-local/src/capture.ts +96 -26
  254. package/packages/provider-hyperframes-local/src/concurrency.ts +86 -0
  255. package/packages/provider-hyperframes-local/src/opaque-capture.ts +92 -0
  256. package/packages/provider-hyperframes-local/src/options.ts +2 -0
  257. package/packages/provider-hyperframes-local/src/program.ts +6 -3
  258. package/packages/provider-hyperframes-local/src/progress.ts +53 -0
  259. package/packages/provider-hyperframes-local/src/provider.ts +18 -5
  260. package/packages/provider-hyperframes-local/src/render.ts +48 -7
  261. package/packages/provider-hypihub/README.md +48 -17
  262. package/packages/provider-hypihub/package.json +2 -0
  263. package/packages/provider-hypihub/src/mapping.ts +31 -7
  264. package/packages/provider-hypihub/src/oauth.ts +6 -0
  265. package/packages/provider-hypihub/src/provider.ts +25 -13
  266. package/packages/provider-hypihub/src/routes.ts +1 -2
  267. package/packages/provider-hypihub/src/upload.ts +2 -0
  268. package/packages/provider-media-local/README.md +3 -4
  269. package/packages/provider-whisperx-local/README.md +57 -0
  270. package/packages/provider-whisperx-local/src/program.ts +1 -0
  271. package/packages/provider-whisperx-local/src/provider.ts +3 -0
  272. package/packages/ranking/README.md +8 -6
  273. package/packages/ranking/package.json +1 -1
  274. package/packages/ranking/src/component.ts +6 -6
  275. package/packages/ranking/src/fragment.ts +11 -7
  276. package/packages/ranking/src/manifest.ts +21 -14
  277. package/packages/ranking/src/render.ts +33 -35
  278. package/packages/ranking/src/schedule.ts +16 -19
  279. package/packages/ranking/src/surface.ts +12 -13
  280. package/packages/ranking-studio/README.md +29 -0
  281. package/packages/ranking-studio/package.json +8 -3
  282. package/packages/ranking-studio/src/index.ts +71 -12
  283. package/packages/render-hyperframes/README.md +7 -7
  284. package/packages/render-hyperframes/package.json +1 -1
  285. package/packages/render-hyperframes/src/component.ts +11 -1
  286. package/packages/render-hyperframes/src/fragment.ts +7 -4
  287. package/packages/render-hyperframes/src/manifest.ts +4 -4
  288. package/packages/render-hyperframes/src/surface.ts +6 -6
  289. package/packages/runtime/README.md +8 -1
  290. package/packages/runtime/src/catalog.ts +2 -0
  291. package/packages/runtime/src/execution.ts +15 -4
  292. package/packages/runtime/src/index.ts +2 -1
  293. package/packages/runtime/src/log.ts +51 -0
  294. package/packages/runtime/src/types.ts +5 -8
  295. package/packages/runtime-host-node/README.md +30 -0
  296. package/packages/runtime-host-node/package.json +1 -0
  297. package/packages/runtime-host-node/src/index.ts +25 -9
  298. package/packages/runtime-host-node/src/packages.ts +47 -50
  299. package/packages/runtime-kit/README.md +5 -0
  300. package/packages/runtime-kit/src/index.ts +3 -1
  301. package/packages/runtime-local/README.md +111 -4
  302. package/packages/runtime-local/src/config.ts +202 -56
  303. package/packages/runtime-local/src/control.ts +9 -1
  304. package/packages/runtime-local/src/executor.ts +66 -0
  305. package/packages/runtime-local/src/host.ts +37 -17
  306. package/packages/runtime-local/src/log.ts +48 -0
  307. package/packages/runtime-local/src/programs.ts +41 -25
  308. package/packages/runtime-local/src/result-writer.ts +2 -0
  309. package/packages/runtime-local/src/runtime.ts +10 -6
  310. package/packages/runtime-local/src/supervisor.ts +142 -0
  311. package/packages/runtime-local/src/types.ts +9 -2
  312. package/packages/runtime-local/src/worker-process.ts +7 -24
  313. package/packages/runtime-local/src/worker.ts +55 -83
  314. package/packages/screen-overlay/README.md +3 -3
  315. package/packages/screen-overlay/package.json +1 -1
  316. package/packages/screen-overlay/src/component.ts +3 -3
  317. package/packages/screen-overlay/src/fragment.ts +5 -4
  318. package/packages/screen-overlay/src/manifest.ts +7 -6
  319. package/packages/screen-overlay/src/program.ts +9 -9
  320. package/packages/screen-overlay/src/surface.ts +6 -7
  321. package/packages/script/README.md +37 -2
  322. package/packages/script/src/edit.ts +123 -73
  323. package/packages/script/src/lexical.ts +40 -6
  324. package/packages/script/src/manifest.ts +2 -2
  325. package/packages/script/src/narrative.ts +1 -0
  326. package/packages/script/src/parser.ts +36 -8
  327. package/packages/script/src/surface.ts +4 -3
  328. package/packages/script/src/types.ts +5 -1
  329. package/packages/script-studio/package.json +9 -3
  330. package/packages/script-studio/src/index.ts +2 -0
  331. package/packages/script-studio/src/projection.ts +105 -0
  332. package/packages/seedance/README.md +30 -1
  333. package/packages/seedance/src/index.ts +18 -7
  334. package/packages/seedance/src/surface.ts +17 -4
  335. package/packages/seedance-kits/README.md +10 -2
  336. package/packages/seedance-kits/kits/speaker-v1.svs +5 -5
  337. package/packages/seedream/README.md +1 -1
  338. package/packages/sound/README.md +81 -0
  339. package/packages/sound/package.json +25 -0
  340. package/packages/sound/src/activation.ts +11 -0
  341. package/packages/sound/src/component.ts +28 -0
  342. package/packages/sound/src/index.ts +5 -0
  343. package/packages/sound/src/manifest.ts +47 -0
  344. package/packages/sound/src/program.ts +84 -0
  345. package/packages/sound/src/style.ts +34 -0
  346. package/packages/sound/src/surface.ts +90 -0
  347. package/packages/sound-studio/README.md +22 -0
  348. package/packages/sound-studio/package.json +20 -0
  349. package/packages/sound-studio/src/activation.ts +6 -0
  350. package/packages/sound-studio/src/index.ts +74 -0
  351. package/packages/speech/README.md +2 -2
  352. package/packages/speech-alignment/src/align.ts +45 -21
  353. package/packages/speech-alignment/src/local.ts +8 -0
  354. package/packages/speech-alignment/src/locate.ts +1 -1
  355. package/packages/store-sqlite/README.md +7 -0
  356. package/packages/store-sqlite/src/store.ts +84 -83
  357. package/packages/studio/INSPECTOR.md +117 -0
  358. package/packages/studio/README.md +149 -14
  359. package/packages/studio/package.json +8 -7
  360. package/packages/studio/src/build-library.ts +99 -84
  361. package/packages/studio/src/companion-assembly.ts +1 -0
  362. package/packages/studio/src/domain.ts +1 -1
  363. package/packages/studio/src/fallback-companions.ts +3 -3
  364. package/packages/studio/src/feedback-server.ts +51 -0
  365. package/packages/studio/src/feedback-store.ts +66 -0
  366. package/packages/studio/src/feedback.ts +60 -0
  367. package/packages/studio/src/library-media.ts +19 -0
  368. package/packages/studio/src/parameter-values.ts +83 -1
  369. package/packages/studio/src/parameters.ts +132 -43
  370. package/packages/studio/src/preview/render.ts +5 -1
  371. package/packages/studio/src/preview/runtime-shim.ts +49 -3
  372. package/packages/studio/src/programme.ts +14 -30
  373. package/packages/studio/src/server.ts +66 -34
  374. package/packages/studio/src/shared.ts +24 -8
  375. package/packages/studio/src/snapshot.ts +21 -132
  376. package/packages/studio/src/studio-preflight.ts +3 -3
  377. package/packages/studio/src/studio-registry.ts +72 -6
  378. package/packages/studio/src/style.css +342 -190
  379. package/packages/studio/src/temporal-edit.ts +131 -0
  380. package/packages/studio/src/ui/artifact-name.ts +80 -0
  381. package/packages/studio/src/ui/artifact-preview.ts +99 -0
  382. package/packages/studio/src/ui/comments.ts +233 -0
  383. package/packages/studio/src/ui/icons.ts +10 -1
  384. package/packages/studio/src/ui/library.ts +373 -192
  385. package/packages/studio/src/ui/main.ts +291 -110
  386. package/packages/studio/src/ui/material-preview.ts +1 -1
  387. package/packages/studio/src/ui/overlay.ts +31 -26
  388. package/packages/studio/src/ui/scrub-preview.ts +108 -0
  389. package/packages/studio/src/ui/sidebar-panel.ts +31 -0
  390. package/packages/studio/src/ui/stage.ts +188 -9
  391. package/packages/studio/src/ui/timeline.ts +187 -281
  392. package/packages/studio/start.ts +19 -5
  393. package/packages/studio-adapter/README.md +151 -11
  394. package/packages/studio-adapter/src/index.ts +126 -14
  395. package/packages/temporal/README.md +6 -6
  396. package/packages/temporal/package.json +1 -1
  397. package/packages/temporal/src/component.ts +5 -6
  398. package/packages/temporal/src/index.ts +8 -6
  399. package/packages/temporal/src/location.ts +11 -11
  400. package/packages/temporal/src/projection.ts +19 -19
  401. package/packages/temporal/src/rational.ts +4 -4
  402. package/packages/temporal-markup/EDITING.md +183 -0
  403. package/packages/temporal-markup/README.md +31 -11
  404. package/packages/temporal-markup/package.json +1 -1
  405. package/packages/temporal-markup/src/index.ts +20 -25
  406. package/packages/temporal-markup/src/space.ts +10 -41
  407. package/packages/timeline/README.md +31 -0
  408. package/packages/{semantic-track → timeline}/package.json +1 -1
  409. package/packages/timeline/src/activation.ts +8 -0
  410. package/packages/timeline/src/component.ts +24 -0
  411. package/packages/timeline/src/identity.ts +60 -0
  412. package/packages/timeline/src/index.ts +6 -0
  413. package/packages/{semantic-track → timeline}/src/location.ts +20 -20
  414. package/packages/timeline/src/manifest.ts +39 -0
  415. package/packages/{semantic-track → timeline}/src/projection.ts +14 -14
  416. package/packages/timeline/src/types.ts +24 -0
  417. package/packages/timeline-author/README.md +68 -0
  418. package/packages/{speech-track → timeline-author}/package.json +6 -4
  419. package/packages/timeline-author/src/activation.ts +22 -0
  420. package/packages/{speech-track → timeline-author}/src/component.ts +15 -13
  421. package/packages/{speech-track → timeline-author}/src/fragment.ts +14 -23
  422. package/packages/timeline-author/src/index.ts +7 -0
  423. package/packages/timeline-author/src/manifest.ts +78 -0
  424. package/packages/timeline-author/src/program.ts +107 -0
  425. package/packages/timeline-author/src/surface.ts +46 -0
  426. package/packages/timeline-author/src/types.ts +6 -0
  427. package/packages/typography-track/README.md +4 -4
  428. package/packages/typography-track/package.json +1 -1
  429. package/packages/typography-track/src/component.ts +4 -4
  430. package/packages/typography-track/src/fragment.ts +4 -3
  431. package/packages/typography-track/src/manifest.ts +11 -9
  432. package/packages/typography-track/src/program.ts +15 -15
  433. package/packages/typography-track/src/surface.ts +17 -18
  434. package/packages/typography-track-studio/package.json +8 -3
  435. package/packages/typography-track-studio/src/index.ts +5 -1
  436. package/packages/video-cli/README.md +16 -4
  437. package/packages/video-cli/package.json +2 -1
  438. package/packages/video-cli/src/creation.ts +25 -9
  439. package/packages/video-cli/src/index.ts +1 -1
  440. package/packages/video-cli/src/studio-distribution.ts +2 -1
  441. package/packages/volcengine-matting/README.md +3 -3
  442. package/packages/whisperx/README.md +8 -1
  443. package/packages/workspace/src/index.ts +2 -0
  444. package/packages/workspace-fs-node/README.md +4 -1
  445. package/packages/workspace-fs-node/src/workspace.ts +3 -1
  446. package/services/whisperx/README.md +14 -0
  447. package/services/whisperx/pyproject.toml +2 -0
  448. package/services/whisperx/uv.lock +20 -20
  449. package/packages/provider-hyperframes-aws-lambda/README.md +0 -30
  450. package/packages/provider-hyperframes-aws-lambda/package.json +0 -30
  451. package/packages/provider-hyperframes-aws-lambda/src/activation.ts +0 -97
  452. package/packages/provider-hyperframes-aws-lambda/src/client.ts +0 -114
  453. package/packages/provider-hyperframes-aws-lambda/src/index.ts +0 -21
  454. package/packages/provider-hyperframes-aws-lambda/src/provider.ts +0 -522
  455. package/packages/provider-kie/README.md +0 -134
  456. package/packages/provider-kie/package.json +0 -43
  457. package/packages/provider-kie/src/activation.ts +0 -71
  458. package/packages/provider-kie/src/index.ts +0 -10
  459. package/packages/provider-kie/src/mapping.ts +0 -182
  460. package/packages/provider-kie/src/provider.ts +0 -657
  461. package/packages/provider-kie/src/routes.ts +0 -150
  462. package/packages/provider-xiaomi-mimo/README.md +0 -32
  463. package/packages/provider-xiaomi-mimo/src/activation.ts +0 -57
  464. package/packages/provider-xiaomi-mimo/src/index.ts +0 -5
  465. package/packages/provider-xiaomi-mimo/src/provider.ts +0 -214
  466. package/packages/runtime/src/environment.ts +0 -6
  467. package/packages/semantic-track/README.md +0 -21
  468. package/packages/semantic-track/src/activation.ts +0 -8
  469. package/packages/semantic-track/src/component.ts +0 -24
  470. package/packages/semantic-track/src/identity.ts +0 -58
  471. package/packages/semantic-track/src/index.ts +0 -6
  472. package/packages/semantic-track/src/manifest.ts +0 -38
  473. package/packages/semantic-track/src/types.ts +0 -26
  474. package/packages/speech-track/README.md +0 -51
  475. package/packages/speech-track/src/activation.ts +0 -19
  476. package/packages/speech-track/src/index.ts +0 -7
  477. package/packages/speech-track/src/manifest.ts +0 -73
  478. package/packages/speech-track/src/program.ts +0 -64
  479. package/packages/speech-track/src/surface.ts +0 -35
  480. package/packages/speech-track/src/types.ts +0 -6
  481. package/packages/speech-track-studio/README.md +0 -3
  482. package/packages/speech-track-studio/package.json +0 -14
  483. package/packages/speech-track-studio/src/activation.ts +0 -7
  484. package/packages/speech-track-studio/src/index.ts +0 -40
  485. /package/packages/{cli → project-context-node}/src/project-context.ts +0 -0
  486. /package/packages/{speech-track → timeline-author}/preview/Track.png +0 -0
@@ -1,7 +1,9 @@
1
1
  import type { SourceRange } from "@hypit/protocol";
2
2
 
3
- import { narrativeValue } from "./narrative.js";
3
+ import { canonicalStringify } from "@hypit/protocol";
4
+ import { captionDocument, narrativeValue } from "./narrative.js";
4
5
  import { parseScript } from "./parser.js";
6
+ import { cleanHorizontalProse } from "./lexical.js";
5
7
  import type { Affinity, ParsedNarrative, SemanticAnchor } from "./types.js";
6
8
 
7
9
  export type ScriptAnchorEditSite = {
@@ -47,18 +49,16 @@ export function scriptAnchorEditSites(parsed: ParsedNarrative): readonly ScriptA
47
49
  const segment = segments.get(segmentId);
48
50
  if (segment === undefined) throw new Error(`Semantic Anchor ${anchor.id} names unknown Segment ${segmentId}.`);
49
51
  if (anchor.kind === "segment-start") {
50
- const first = parsed.tokens[segment.tokenStart];
51
52
  return {
52
53
  anchorId: anchor.id, kind: anchor.kind, segmentId,
53
- offset: first?.range.start ?? segment.contentRange.start,
54
+ offset: segment.contentRange.start,
54
55
  affinity: "left", placement: "before",
55
56
  };
56
57
  }
57
58
  if (anchor.kind === "segment-end") {
58
- const last = parsed.tokens[segment.tokenEndExclusive - 1];
59
59
  return {
60
60
  anchorId: anchor.id, kind: anchor.kind, segmentId,
61
- offset: last?.range.end ?? segment.contentRange.end,
61
+ offset: segment.contentRange.end,
62
62
  affinity: "right", placement: "after",
63
63
  };
64
64
  }
@@ -66,10 +66,10 @@ export function scriptAnchorEditSites(parsed: ParsedNarrative): readonly ScriptA
66
66
  if (token === undefined) throw new Error(`Semantic Anchor ${anchor.id} names no Script Token.`);
67
67
  return anchor.kind === "token-start" ? {
68
68
  anchorId: anchor.id, kind: anchor.kind, segmentId,
69
- offset: token.range.start, affinity: "right", placement: "before",
69
+ offset: token.editRange.start, affinity: "right", placement: "before",
70
70
  } : {
71
71
  anchorId: anchor.id, kind: anchor.kind, segmentId,
72
- offset: token.range.end, affinity: "left", placement: "after",
72
+ offset: token.editRange.end, affinity: "left", placement: "after",
73
73
  };
74
74
  });
75
75
  }
@@ -79,16 +79,6 @@ function marker(id: string, edge: "open" | "close", affinity: Affinity): string
79
79
  return affinity === "left" ? `@/${id}` : `@/${id}~`;
80
80
  }
81
81
 
82
- function insertion(id: string, edge: "open" | "close", site: ScriptAnchorEditSite): string {
83
- const value = marker(id, edge, site.affinity);
84
- return site.placement === "before" ? `${value} ` : ` ${value}`;
85
- }
86
-
87
- function momentInsertion(id: string, site: ScriptAnchorEditSite): string {
88
- const value = site.affinity === "left" ? `~@${id}!` : `@${id}!`;
89
- return site.placement === "before" ? `${value} ` : ` ${value}`;
90
- }
91
-
92
82
  function applyEdits(source: string, edits: readonly Edit[]): string {
93
83
  let next = source;
94
84
  const ordered = [...edits].sort((left, right) =>
@@ -102,73 +92,133 @@ function applyEdits(source: string, edits: readonly Edit[]): string {
102
92
  return next;
103
93
  }
104
94
 
105
- /**
106
- * Relocate one shared Selection by anchor identity. The returned Source is accepted only when
107
- * reparsing proves the requested public Narrative, so Studio never edits prose by frame guess.
108
- */
109
- export function adjustScriptSelection(input: {
95
+ type AdjustmentInput = {
110
96
  readonly sourceName: string;
111
97
  readonly source: string;
112
98
  readonly parsed: ParsedNarrative;
113
- readonly adjustment: ScriptSelectionAdjustment;
114
- }): string {
115
- const selection = input.parsed.selections.find((candidate) => candidate.id === input.adjustment.id);
116
- if (selection === undefined) throw new Error(`Script Selection ${input.adjustment.id} does not exist.`);
117
- const sites = new Map(scriptAnchorEditSites(input.parsed).map((site) => [site.anchorId, site] as const));
118
- const start = sites.get(input.adjustment.startAnchorId);
119
- const end = sites.get(input.adjustment.endAnchorId);
120
- if (start === undefined) throw new Error(`Selection start Anchor ${input.adjustment.startAnchorId} does not exist.`);
121
- if (end === undefined) throw new Error(`Selection end Anchor ${input.adjustment.endAnchorId} does not exist.`);
99
+ };
100
+
101
+ type NamedAnchor = { readonly id: string; readonly edge: "open" | "close" | "moment"; readonly anchorId: string };
122
102
 
103
+ /** Normalize only parser-owned prose. Indentation is read from this edit's input, never stored. */
104
+ function normalizedProse(source: string, parsed: ParsedNarrative, original: string): string {
105
+ const bodyStarts = new Set(parsed.segments.flatMap(segment => [segment.contentRange.start,
106
+ ...segment.atoms.filter(atom => atom.kind === "role").map(atom => atom.range.end)]));
107
+ const bodyEnds = new Set(parsed.segments.map(segment => segment.contentRange.end));
108
+ const indentation = original.split(/\r\n|\r|\n/u).map(line => /^[ \t]*/u.exec(line)![0].length);
109
+ const lines: Array<{ start: number; end: number; indentEnd: number }> = [];
110
+ let offset = 0;
111
+ const parts = source.split(/(\r\n|\r|\n)/u);
112
+ for (let index = 0; index < parts.length; index += 2) {
113
+ const text = parts[index]!;
114
+ lines.push({ start: offset, end: offset + text.length, indentEnd: offset + indentation[index / 2]! });
115
+ offset += text.length + (parts[index + 1]?.length ?? 0);
116
+ }
123
117
  const edits: Edit[] = [];
124
- if (selection.startAnchorId !== start.anchorId) {
125
- edits.push({ range: selection.open.range, replacement: "" });
126
- edits.push({ range: { start: start.offset, end: start.offset }, replacement: insertion(selection.id, "open", start) });
118
+ for (const range of parsed.proseRanges) for (const line of lines) {
119
+ const start = Math.max(range.start, line.indentEnd);
120
+ const end = Math.min(range.end, line.end);
121
+ if (start >= end) continue;
122
+ let text = cleanHorizontalProse(source.slice(start, end));
123
+ const outside = !parsed.segments.some(segment => range.start >= segment.contentRange.start && range.end <= segment.contentRange.end);
124
+ if (start === line.indentEnd || bodyStarts.has(start) || outside) text = text.replace(/^[ \t]+/u, "");
125
+ if (end === line.end || bodyEnds.has(end) || outside) text = text.replace(/[ \t]+$/u, "");
126
+ edits.push({ range: { start, end }, replacement: text });
127
+ }
128
+ return applyEdits(source, edits);
129
+ }
130
+
131
+ /** One canonical boundary spelling, independent of the order of previous gestures. */
132
+ function rewrite(input: AdjustmentInput, markers: readonly NamedAnchor[]): string {
133
+ const ranges = [
134
+ ...input.parsed.moments.map((item) => item.range),
135
+ ...input.parsed.selections.flatMap((item) => [item.open.range, item.close.range]),
136
+ ].map((range) => ({ start: range.start - input.parsed.sourceRange.start, end: range.end - input.parsed.sourceRange.start }))
137
+ .sort((a, b) => a.start - b.start);
138
+ const edits: Edit[] = ranges.map(range => ({ range, replacement: "" }));
139
+ for (const segment of input.parsed.segments) {
140
+ if (segment.selfClosing) edits.push({ range: { start: segment.range.start - input.parsed.sourceRange.start, end: segment.range.end - input.parsed.sourceRange.start }, replacement: `<${segment.id}></${segment.id}>` });
127
141
  }
128
- if (selection.endAnchorId !== end.anchorId) {
129
- edits.push({ range: selection.close.range, replacement: "" });
130
- edits.push({ range: { start: end.offset, end: end.offset }, replacement: insertion(selection.id, "close", end) });
142
+ const unmarked = applyEdits(input.source, edits);
143
+ const base = normalizedProse(unmarked, parseScript(input.sourceName, unmarked), input.source);
144
+ const parsed = parseScript(input.sourceName, base);
145
+ const sites = new Map(scriptAnchorEditSites(parsed).map((site, order) => [site.anchorId, { ...site, order }]));
146
+ const groups = new Map<number, Array<NamedAnchor & { affinity: Affinity; order: number }>>();
147
+ for (const value of markers) {
148
+ const site = sites.get(value.anchorId);
149
+ if (!site) throw new Error(`Semantic Anchor ${value.anchorId} does not exist.`);
150
+ let offset = site.offset;
151
+ const lineStart = Math.max(base.lastIndexOf("\n", offset - 1), base.lastIndexOf("\r", offset - 1)) + 1;
152
+ const indentEnd = lineStart + /^[ \t]*/u.exec(base.slice(lineStart))![0].length;
153
+ if (offset < indentEnd) offset = indentEnd;
154
+ // Reuse horizontal separators without moving a word marker ahead of line indentation.
155
+ let gapStart = offset;
156
+ while (gapStart > 0 && /[ \t]/u.test(base[gapStart - 1]!)) gapStart -= 1;
157
+ if (gapStart > 0 && !/[\r\n]/u.test(base[gapStart - 1]!)) offset = gapStart;
158
+ const group = groups.get(offset) ?? [];
159
+ group.push({ ...value, affinity: site.affinity, order: site.order });
160
+ groups.set(offset, group);
131
161
  }
132
- if (edits.length === 0) return input.source;
133
- const next = applyEdits(input.source, edits);
162
+ const insertions: Edit[] = [...groups].map(([offset, group]) => {
163
+ group.sort((a, b) => a.order - b.order
164
+ || (a.edge === "open" ? 0 : a.edge === "moment" ? 1 : 2) - (b.edge === "open" ? 0 : b.edge === "moment" ? 1 : 2)
165
+ || a.id.localeCompare(b.id));
166
+ let replacement = group.map((item) => item.edge === "moment"
167
+ ? `${item.affinity === "left" ? "~" : ""}@${item.id}!`
168
+ : marker(item.id, item.edge, item.affinity)).join("");
169
+ let end = offset;
170
+ while (end < base.length && /[ \t]/u.test(base[end]!)) end += 1;
171
+ if (end > offset) replacement += " ";
172
+ // Only undelimited names followed by an ASCII name character need a separator.
173
+ if (/[a-z0-9_-]$/u.test(replacement) && /[A-Za-z0-9_-]/u.test(base[offset] ?? "")) replacement += " ";
174
+ return { range: { start: offset, end }, replacement };
175
+ });
176
+ const next = applyEdits(base, insertions);
134
177
  const reparsed = parseScript(input.sourceName, next);
135
- const rewritten = reparsed.selections.find((candidate) => candidate.id === selection.id);
136
- if (rewritten?.startAnchorId !== start.anchorId || rewritten.endAnchorId !== end.anchorId) {
137
- throw new Error(`Script refused to move Selection ${selection.id} to the requested Anchors.`);
178
+ const actual = namedAnchors(reparsed);
179
+ if (canonicalStringify(actual) !== canonicalStringify(markers)) {
180
+ throw new Error("Script marker adjustment did not preserve the requested semantic bindings.");
138
181
  }
139
- const before = narrativeValue(input.parsed, "comparison") as unknown as { readonly selections: readonly { readonly id: string }[] };
140
- const after = narrativeValue(reparsed, "comparison") as unknown as { readonly selections: readonly { readonly id: string }[] };
141
- if (before.selections.length !== after.selections.length
142
- || before.selections.some((item) => !after.selections.some((candidate) => candidate.id === item.id))) {
143
- throw new Error("Script Selection adjustment changed authored identities.");
182
+ // Compare public content, not source offsets or marker-induced parser atom boundaries.
183
+ const content = (value: ParsedNarrative) => ({
184
+ ...narrativeValue(value, "comparison") as Record<string, unknown>, selections: [], moments: [],
185
+ caption: captionDocument(value, "caption", "comparison"),
186
+ });
187
+ if (canonicalStringify(content(input.parsed)) !== canonicalStringify(content(reparsed))) {
188
+ throw new Error("Script marker adjustment changed authored content.");
144
189
  }
145
190
  return next;
146
191
  }
147
192
 
148
- /** Relocate one Moment to an exact semantic Anchor without changing its identity. */
149
- export function adjustScriptMoment(input: {
150
- readonly sourceName: string;
151
- readonly source: string;
152
- readonly parsed: ParsedNarrative;
153
- readonly adjustment: ScriptMomentAdjustment;
154
- }): string {
155
- const moment = input.parsed.moments.find((candidate) => candidate.id === input.adjustment.id);
156
- if (moment === undefined) throw new Error(`Script Moment ${input.adjustment.id} does not exist.`);
157
- const site = scriptAnchorEditSites(input.parsed).find((candidate) => candidate.anchorId === input.adjustment.anchorId);
158
- if (site === undefined) throw new Error(`Moment Anchor ${input.adjustment.anchorId} does not exist.`);
159
- if (moment.anchorId === site.anchorId) return input.source;
160
- const next = applyEdits(input.source, [
161
- { range: moment.range, replacement: "" },
162
- { range: { start: site.offset, end: site.offset }, replacement: momentInsertion(moment.id, site) },
163
- ]);
164
- const reparsed = parseScript(input.sourceName, next);
165
- const rewritten = reparsed.moments.find((candidate) => candidate.id === moment.id);
166
- if (rewritten?.anchorId !== site.anchorId) {
167
- throw new Error(`Script refused to move Moment ${moment.id} to the requested Anchor.`);
168
- }
169
- if (reparsed.moments.length !== input.parsed.moments.length
170
- || input.parsed.moments.some((item) => !reparsed.moments.some((candidate) => candidate.id === item.id))) {
171
- throw new Error("Script Moment adjustment changed authored identities.");
172
- }
173
- return next;
193
+ function namedAnchors(parsed: ParsedNarrative): NamedAnchor[] {
194
+ return [
195
+ ...parsed.selections.flatMap((item): NamedAnchor[] => [
196
+ { id: item.id, edge: "open", anchorId: item.startAnchorId },
197
+ { id: item.id, edge: "close", anchorId: item.endAnchorId },
198
+ ]),
199
+ ...parsed.moments.map((item): NamedAnchor => ({ id: item.id, edge: "moment", anchorId: item.anchorId })),
200
+ ];
201
+ }
202
+
203
+ /** Rewrite a Selection's two endpoints together; Script owns order, not projected time. */
204
+ export function adjustScriptSelection(input: AdjustmentInput & { readonly adjustment: ScriptSelectionAdjustment }): string {
205
+ const { adjustment, parsed } = input;
206
+ const selection = parsed.selections.find((item) => item.id === adjustment.id);
207
+ if (!selection) throw new Error(`Script Selection ${adjustment.id} does not exist.`);
208
+ const order = parsed.semanticIndex.anchors.map((anchor) => anchor.id);
209
+ const start = order.indexOf(adjustment.startAnchorId);
210
+ const end = order.indexOf(adjustment.endAnchorId);
211
+ if (start < 0 || end < start) throw new Error("Selection endpoints must follow Script anchor order.");
212
+ return rewrite(input, namedAnchors(parsed).map((item) => item.id !== adjustment.id ? item : {
213
+ ...item, anchorId: item.edge === "open" ? adjustment.startAnchorId : adjustment.endAnchorId,
214
+ }));
215
+ }
216
+
217
+ /** Relocate a Moment by identity, independently of coincident projected Frames. */
218
+ export function adjustScriptMoment(input: AdjustmentInput & { readonly adjustment: ScriptMomentAdjustment }): string {
219
+ const moment = input.parsed.moments.find((item) => item.id === input.adjustment.id);
220
+ if (!moment) throw new Error(`Script Moment ${input.adjustment.id} does not exist.`);
221
+ return rewrite(input, namedAnchors(input.parsed).map((item) => item.id !== input.adjustment.id ? item : {
222
+ ...item, anchorId: input.adjustment.anchorId,
223
+ }));
174
224
  }
@@ -50,17 +50,51 @@ export function lexicalCount(value: string): number {
50
50
  return lexicalUnits(value).length;
51
51
  }
52
52
 
53
+ /** Source positions for markers; unlike timing units, these include attached punctuation. */
54
+ export function lexicalEditRanges(value: string): readonly { start: number; end: number }[] {
55
+ const units = lexicalUnits(value);
56
+ return units.map((unit, index) => {
57
+ const previousEnd = index === 0 ? 0 : units[index - 1]!.index + units[index - 1]!.text.length;
58
+ const nextStart = units[index + 1]?.index ?? value.length;
59
+ const leading = value.slice(previousEnd, unit.index);
60
+ let start = unit.index;
61
+ for (const [position, character] of [...leading.matchAll(/./gu)].map((match) => [match.index, match[0]] as const)) {
62
+ if (isOpeningPunctuation(character, leading, position, index > 0)) { start = previousEnd + position; break; }
63
+ }
64
+ let end = unit.index + unit.text.length;
65
+ const trailing = value.slice(end, nextStart);
66
+ for (const match of trailing.matchAll(/./gu)) {
67
+ if (/\s/u.test(match[0]) || isOpeningPunctuation(match[0], trailing, match.index, true)) break;
68
+ end += match[0].length;
69
+ }
70
+ return { start, end };
71
+ });
72
+ }
73
+
53
74
  /** Canonical prose spacing; punctuation remains display/speech information, never a timing token. */
54
- export function cleanProjection(value: string): string {
75
+ function attachProseSpacing(value: string): string {
55
76
  return value
56
- .replace(/\s+/gu, " ")
57
- .replace(/\s+([,.;:!?%…,。!?;:、%‰)】》」』〕〉}\]])/gu, "$1")
58
- .replace(/([([{(【《「『〔〈“‘])\s+/gu, "$1")
77
+ .replace(/ +([,.;:!?%…,。!?;:、%‰)】》」』〕〉}\]])/gu, "$1")
78
+ .replace(/([([{(【《「『〔〈“‘]) +/gu, "$1")
59
79
  // Do not erase a cross-script space: `here 你好` must remain two semantic regions.
60
80
  // Only collapse explicit spaces inside one CJK run; the lexical tokenizer already keeps
61
81
  // adjacent Latin and CJK runs separate when no space was authored.
62
- .replace(/([\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}])\s+(?=[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}])/gu, "$1")
63
- .trim();
82
+ .replace(/([\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}]) +(?=[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}])/gu, "$1");
83
+ }
84
+
85
+ export function cleanProjection(value: string): string {
86
+ return attachProseSpacing(value.replace(/\s+/gu, " ")).trim();
87
+ }
88
+
89
+ /** Source formatting keeps line breaks and lexical boundaries, including spaced decimal-like prose. */
90
+ export function cleanHorizontalProse(value: string): string {
91
+ const collapsed = value.replace(/[ \t]+/gu, " ");
92
+ const attached = attachProseSpacing(collapsed);
93
+ const words = (text: string) => lexicalUnits(text).map(unit => unit.text);
94
+ // A separator in `3 .14` cannot be erased into the different token `3.14`.
95
+ const before = words(collapsed);
96
+ const after = words(attached);
97
+ return before.length === after.length && before.every((word, index) => word === after[index]) ? attached : collapsed;
64
98
  }
65
99
 
66
100
  /** Structural markers split atoms but must not invent prose whitespace when those atoms rejoin. */
@@ -32,7 +32,7 @@ export const scriptMarkupSurfaces = [
32
32
  text: "The element's own content is the Script body: named Segments holding prose, Role Cues, Dual Text, flat token attributes, and zero-width Selection and Moment markers. It carries no timecode, no media reference and no generation parameter.",
33
33
  ports: [
34
34
  { name: "", type: narrativeType,
35
- summary: "The whole authored Narrative, addressed by the element's own id." },
35
+ summary: "The complete authored Narrative, including speech structure, semantic anchors and its CaptionDocument, addressed by the element's own id." },
36
36
  { name: "segment.<id>", type: narrativeExcerptType,
37
37
  summary: "One Segment as a narrow Excerpt, used to associate a generated Take with that Segment." },
38
38
  { name: "segment.<id>.dialogue", type: textTypes.text,
@@ -40,7 +40,7 @@ export const scriptMarkupSurfaces = [
40
40
  { name: "segment.<id>.speech", type: textTypes.text,
41
41
  summary: "One Segment as pronunciation only, with Role Cue labels dropped." },
42
42
  { name: "caption", type: captionDocumentType,
43
- summary: "The complete Script-owned CaptionDocument: display Words, N:M Alignment Units, Cue breaks and speech correspondence." },
43
+ summary: "The Narrative's CaptionDocument exported as a narrow view: display Words, N:M Alignment Units, Cue breaks and speech correspondence." },
44
44
  { name: "selection.<id>", type: narrativeSelectionType,
45
45
  summary: "One named range over the Narrative, reusable wherever a Selection is read." },
46
46
  { name: "moment.<id>", type: narrativeMomentType,
@@ -180,6 +180,7 @@ export function narrativeMomentValue(moment: ParsedNarrative["moments"][number],
180
180
  export function narrativeValue(parsed: ParsedNarrative, id: string): CanonicalValue {
181
181
  return canonicalize({
182
182
  id,
183
+ caption: captionDocument(parsed, `${id}.caption`, id),
183
184
  segments: parsed.segments.map((segment) => ({
184
185
  id: segment.id,
185
186
  startAnchorId: segment.startAnchorId,
@@ -5,6 +5,7 @@ import {
5
5
  displayWordSurfaces,
6
6
  joinProjection,
7
7
  lexicalUnits,
8
+ lexicalEditRanges,
8
9
  splitLeadingClosingPunctuation,
9
10
  } from "./lexical.js";
10
11
  import type {
@@ -141,6 +142,7 @@ export function parseScript(
141
142
 
142
143
  const segments: ParsedSegment[] = [];
143
144
  const tokens: ParsedToken[] = [];
145
+ const proseRanges: Array<{ start: number; end: number }> = [];
144
146
  const captionRegions: ParsedCaptionRegion[] = [];
145
147
  const selections = new Map<string, RawSelection>();
146
148
  const moments = new Map<string, RawMoment>();
@@ -237,12 +239,13 @@ export function parseScript(
237
239
  raw: string,
238
240
  absoluteStart: number,
239
241
  dual = false,
240
- ): Array<{ readonly value: string; readonly start: number; readonly end: number }> => {
241
- const pieces: Array<{ value: string; start: number; end: number }> = [];
242
+ ): Array<{ readonly value: string; readonly start: number; readonly end: number; readonly positions: readonly number[] }> => {
243
+ const pieces: Array<{ value: string; start: number; end: number; positions: readonly number[] }> = [];
242
244
  let buffer = "";
243
245
  let bufferStart = 0;
246
+ const positions = [absoluteStart];
244
247
  const flush = (end: number): void => {
245
- if (buffer) pieces.push({ value: buffer, start: absoluteStart + bufferStart, end: absoluteStart + end });
248
+ if (buffer) pieces.push({ value: buffer, start: absoluteStart + bufferStart, end: absoluteStart + end, positions });
246
249
  buffer = "";
247
250
  bufferStart = end;
248
251
  };
@@ -255,10 +258,12 @@ export function parseScript(
255
258
  ?? fail("SCRIPT_ESCAPE", `Unknown Script escape "${raw.slice(index, index + 2)}".`, absoluteStart + index);
256
259
  buffer += escape.value;
257
260
  index += escape.length;
261
+ positions.push(absoluteStart + index);
258
262
  continue;
259
263
  }
260
264
  buffer += raw[index];
261
265
  index += 1;
266
+ positions.push(absoluteStart + index);
262
267
  }
263
268
  flush(raw.length);
264
269
  return pieces;
@@ -424,6 +429,7 @@ export function parseScript(
424
429
  start: number,
425
430
  end: number,
426
431
  captureCaptionRegion = true,
432
+ sourcePositions?: readonly number[],
427
433
  ): void => {
428
434
  if (!current) {
429
435
  if (speech.trim() || caption.trim()) {
@@ -433,7 +439,19 @@ export function parseScript(
433
439
  }
434
440
  current.lexicalRun += speech;
435
441
  const tokenStart = tokens.length;
436
- for (const match of lexicalUnits(speech)) {
442
+ const editRanges = lexicalEditRanges(speech);
443
+ const units = lexicalUnits(speech);
444
+ // Decoded characters may occupy more than one source character (for example \@).
445
+ const position = (index: number): number => sourceOffset + (sourcePositions?.[index] ?? start + index);
446
+ // A punctuation-only piece can follow a display attribute or escaped source piece.
447
+ const preceding = tokens.at(-1);
448
+ const closing = splitLeadingClosingPunctuation(speech).previous;
449
+ if (preceding?.segmentId === current.id && preceding.editRange.end === sourceOffset + start && closing && speech.startsWith(closing)) {
450
+ tokens[tokens.length - 1] = { ...preceding, editRange: {
451
+ start: preceding.editRange.start, end: position(closing.length),
452
+ } };
453
+ }
454
+ for (const [unitIndex, match] of units.entries()) {
437
455
  const normalized = normalizeWord(match.text);
438
456
  if (!normalized) continue;
439
457
  const index = tokens.length;
@@ -449,8 +467,12 @@ export function parseScript(
449
467
  text: match.text,
450
468
  normalized,
451
469
  range: {
452
- start: sourceOffset + start + match.index,
453
- end: sourceOffset + start + match.index + match.text.length,
470
+ start: position(match.index),
471
+ end: position(match.index + match.text.length),
472
+ },
473
+ editRange: {
474
+ start: position(editRanges[unitIndex]!.start),
475
+ end: position(editRanges[unitIndex]!.end),
454
476
  },
455
477
  });
456
478
  }
@@ -486,7 +508,7 @@ export function parseScript(
486
508
  let emittedCaption = false;
487
509
  const addLiteral = (part: string, start: number): void => {
488
510
  for (const piece of literalPieces(part, start, true)) {
489
- addText(piece.value, emittedCaption ? "" : caption, piece.start, piece.end, false);
511
+ addText(piece.value, emittedCaption ? "" : caption, piece.start, piece.end, false, piece.positions);
490
512
  emittedCaption = true;
491
513
  }
492
514
  };
@@ -654,13 +676,18 @@ export function parseScript(
654
676
  offset += 1;
655
677
  }
656
678
  const raw = source.slice(textStart, offset);
657
- for (const piece of literalPieces(raw, textStart)) addText(piece.value, piece.value, piece.start, piece.end);
679
+ if (raw) proseRanges.push({ start: sourceOffset + textStart, end: sourceOffset + offset });
680
+ for (const piece of literalPieces(raw, textStart)) addText(piece.value, piece.value, piece.start, piece.end, true, piece.positions);
658
681
  if (source[offset] === "{") {
659
682
  const block = parseAttributeBlock(source.slice(offset), offset);
660
683
  if (!raw || /\s$/u.test(raw)) {
661
684
  fail("SCRIPT_ATTRIBUTE_TARGET", "A token attribute must immediately follow a display token.", offset);
662
685
  }
663
686
  markLastCaptionSurface(block.attributes, offset);
687
+ const token = tokens.at(-1)!;
688
+ tokens[tokens.length - 1] = { ...token, editRange: {
689
+ start: token.editRange.start, end: sourceOffset + offset + block.length,
690
+ } };
664
691
  offset += block.length;
665
692
  continue;
666
693
  }
@@ -815,6 +842,7 @@ export function parseScript(
815
842
  return {
816
843
 
817
844
  sourceRange: { start: sourceOffset, end: sourceOffset + source.length },
845
+ proseRanges,
818
846
  segments,
819
847
  tokens,
820
848
  turns,
@@ -1,6 +1,5 @@
1
1
  import { ScriptSyntaxError } from "./error.js";
2
2
  import {
3
- captionDocumentValue,
4
3
  narrativeDialogueTextValue,
5
4
  narrativeSegmentExcerptValue,
6
5
  narrativeMomentValue,
@@ -73,6 +72,8 @@ export function decodeScriptSurface(input: ScriptSurfaceInput): ScriptSurfaceOut
73
72
  input.source.slice(input.contentStart, close.start),
74
73
  input.contentStart,
75
74
  );
75
+ const narrative = narrativeValue(parsed, rawId);
76
+ const caption = (narrative as { readonly caption: import("@hypit/protocol").CanonicalValue }).caption;
76
77
  const captionId = `${rawId}.caption`;
77
78
  return {
78
79
  nextOffset: close.end,
@@ -80,7 +81,7 @@ export function decodeScriptSurface(input: ScriptSurfaceInput): ScriptSurfaceOut
80
81
  {
81
82
  id: rawId,
82
83
  type: narrativeType,
83
- value: { kind: "inline", value: narrativeValue(parsed, rawId) },
84
+ value: { kind: "inline", value: narrative },
84
85
  range: { start: input.openingStart, end: close.end },
85
86
  },
86
87
  ...parsed.segments.map((segment) => ({
@@ -106,7 +107,7 @@ export function decodeScriptSurface(input: ScriptSurfaceInput): ScriptSurfaceOut
106
107
  {
107
108
  id: captionId,
108
109
  type: captionDocumentType,
109
- value: { kind: "inline" as const, value: captionDocumentValue(parsed, captionId, rawId) },
110
+ value: { kind: "inline" as const, value: caption },
110
111
  range: { start: input.openingStart, end: close.end },
111
112
  },
112
113
  ...parsed.selections.map((selection) => ({
@@ -45,6 +45,8 @@ export type ParsedToken = NarrativeToken & {
45
45
  readonly index: number;
46
46
  readonly segmentTokenIndex: number;
47
47
  readonly range: SourceRange;
48
+ /** Writable word surface, including attached punctuation and display attributes. */
49
+ readonly editRange: SourceRange;
48
50
  };
49
51
  export type ParsedTurn = NarrativeTurn & { readonly range: SourceRange };
50
52
 
@@ -75,10 +77,12 @@ export type ParsedCaptionRegion = {
75
77
 
76
78
  export type ParsedNarrative = Omit<
77
79
  Narrative,
78
- "id" | "segments" | "tokens" | "turns" | "selections" | "moments"
80
+ "id" | "segments" | "tokens" | "turns" | "selections" | "moments" | "caption"
79
81
  > & {
80
82
  /** Exact Script body range, used only for source-preserving Program-boundary edits. */
81
83
  readonly sourceRange: SourceRange;
84
+ /** Ordinary source prose/whitespace; excludes tags, Dual Text, attributes and comments. */
85
+ readonly proseRanges: readonly SourceRange[];
82
86
  readonly segments: readonly ParsedSegment[];
83
87
  readonly tokens: readonly ParsedToken[];
84
88
  readonly turns: readonly ParsedTurn[];
@@ -4,10 +4,16 @@
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "private": true,
6
6
  "type": "module",
7
- "exports": { ".": "./src/index.ts" },
8
- "hypit": { "activation": "./src/activation.ts" },
7
+ "exports": {
8
+ ".": "./src/index.ts"
9
+ },
10
+ "hypit": {
11
+ "activation": "./src/activation.ts"
12
+ },
9
13
  "dependencies": {
10
14
  "@hypit/script": "workspace:*",
11
- "@hypit/studio-adapter": "workspace:*"
15
+ "@hypit/studio-adapter": "workspace:*",
16
+ "@hypit/narrative": "workspace:*",
17
+ "@hypit/protocol": "workspace:*"
12
18
  }
13
19
  }
@@ -1,9 +1,11 @@
1
+ import { projectScriptTimeline } from "./projection.js";
1
2
  import { adjustScriptMoment, adjustScriptSelection, parseScript, scriptModuleRef } from "@hypit/script";
2
3
  import type { StudioScriptCompanion } from "@hypit/studio-adapter";
3
4
 
4
5
  export const scriptStudioCompanions: readonly StudioScriptCompanion[] = [{
5
6
  id: "script",
6
7
  match: { module: scriptModuleRef, surface: "script" },
8
+ project: projectScriptTimeline,
7
9
  observe(input) {
8
10
  const narrativeId = input.attributes.id ?? "script";
9
11
  if (typeof narrativeId !== "string" || narrativeId.length === 0) return undefined;