@cueframe/kernel 0.1.0 → 0.1.1

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 (355) hide show
  1. package/LICENSE +661 -0
  2. package/dist/_members/composition/ops/compositionOps.d.ts +1 -0
  3. package/dist/_members/composition/projection/behind-readiness.d.ts +127 -0
  4. package/dist/_members/composition/projection/index.d.ts +2 -0
  5. package/dist/_members/composition/projection/reframe-readiness.d.ts +156 -0
  6. package/dist/_members/composition/validators/composition.d.ts +42 -25
  7. package/dist/_members/composition/validators/render.d.ts +32 -0
  8. package/dist/_members/core/render/compositionRender.d.ts +17 -1
  9. package/dist/_members/core/render/types.d.ts +31 -0
  10. package/dist/authoring/build-tools.js +6 -6
  11. package/dist/authoring/context.js +4 -4
  12. package/dist/authoring/tools.js +5 -5
  13. package/dist/authoring.js +11 -9
  14. package/dist/{chunk-ZB3C3HM7.js → chunk-7FO3ZJ43.js} +3 -0
  15. package/dist/{chunk-ODL7GQJG.js → chunk-AP6ZIVAV.js} +2 -2
  16. package/dist/{chunk-IBYQG46O.js → chunk-AQBREB5O.js} +1 -1
  17. package/dist/{chunk-YIOY2XEO.js → chunk-DK2ODBNT.js} +15 -5
  18. package/dist/{chunk-JRQVPFLF.js → chunk-HY3RIEZW.js} +1 -1
  19. package/dist/{chunk-GEA7E2FL.js → chunk-JJ6XD7NG.js} +151 -1
  20. package/dist/{chunk-COYMZ76S.js → chunk-MBCXCJOE.js} +1 -1
  21. package/dist/{chunk-37NJ27UU.js → chunk-OCFDUCF4.js} +3 -0
  22. package/dist/{chunk-VOO5FQSS.js → chunk-PDYO3DOJ.js} +5 -5
  23. package/dist/{chunk-MXFAADCQ.js → chunk-PODIYN2K.js} +9 -2
  24. package/dist/{chunk-NFEGPWGS.js → chunk-TOJEXFXL.js} +1 -1
  25. package/dist/{chunk-LM4WDUQJ.js → chunk-UHGSZZDI.js} +1 -1
  26. package/dist/{chunk-XWKZB5U5.js → chunk-ZWMV6DD2.js} +24 -1
  27. package/dist/compose/renderer.js +3 -3
  28. package/dist/compose.js +6 -6
  29. package/dist/composition/graphics-plan.js +1 -1
  30. package/dist/composition/ops.js +3 -3
  31. package/dist/composition/primitive-catalog.js +1 -1
  32. package/dist/composition/projection.js +19 -3
  33. package/dist/composition/validators.js +6 -4
  34. package/dist/composition-ops.js +8 -6
  35. package/dist/composition.js +24 -6
  36. package/dist/{context-OKX3HHFS.js → context-YWUZDG5X.js} +4 -4
  37. package/dist/core/render.js +3 -3
  38. package/dist/core/select.js +2 -2
  39. package/dist/core.js +3 -3
  40. package/dist/errors.js +1 -1
  41. package/dist/mcp/adapter.js +1 -0
  42. package/dist/media-model/testing.js +1071 -718
  43. package/dist/nle-export/server.js +328 -130
  44. package/dist/nle-export.js +7 -6
  45. package/package.json +13 -14
  46. package/dist/_members/account-model/index.js +0 -4
  47. package/dist/_members/account-model/testing/conversationStoreContract.js +0 -168
  48. package/dist/_members/account-model/testing/index.js +0 -7
  49. package/dist/_members/account-model/testing/restorePointStoreContract.js +0 -69
  50. package/dist/_members/account-model/types/index.js +0 -1
  51. package/dist/_members/account-model/validators/contextFile.js +0 -18
  52. package/dist/_members/account-model/validators/conversation.js +0 -95
  53. package/dist/_members/account-model/validators/dashboardInsight.js +0 -16
  54. package/dist/_members/account-model/validators/index.js +0 -7
  55. package/dist/_members/account-model/validators/sessionToken.js +0 -49
  56. package/dist/_members/account-model/validators/uploadToken.js +0 -16
  57. package/dist/_members/account-model/validators/userSettings.js +0 -12
  58. package/dist/_members/account-model/validators/workingComposition.js +0 -20
  59. package/dist/_members/brand-derivation/constants.js +0 -20
  60. package/dist/_members/brand-derivation/contrastSafe.js +0 -114
  61. package/dist/_members/brand-derivation/index.js +0 -1
  62. package/dist/_members/cloud-import/chunk-XKO6ZSWI.js +0 -162
  63. package/dist/_members/cloud-import/chunk-XKO6ZSWI.js.map +0 -1
  64. package/dist/_members/cloud-import/index.js +0 -241
  65. package/dist/_members/cloud-import/index.js.map +0 -1
  66. package/dist/_members/cloud-import/multipartUpload.js +0 -7
  67. package/dist/_members/cloud-import/multipartUpload.js.map +0 -1
  68. package/dist/_members/composition/audio/audioMix.js +0 -61
  69. package/dist/_members/composition/audio/index.js +0 -5
  70. package/dist/_members/composition/audio/mixStaging.js +0 -195
  71. package/dist/_members/composition/audio/musicPack.generated.js +0 -136
  72. package/dist/_members/composition/audio/musicPack.js +0 -36
  73. package/dist/_members/composition/audio/pack.generated.js +0 -603
  74. package/dist/_members/composition/audio/pack.js +0 -48
  75. package/dist/_members/composition/audio/palette.js +0 -134
  76. package/dist/_members/composition/autozoom/index.js +0 -83
  77. package/dist/_members/composition/brand-kit.js +0 -45
  78. package/dist/_members/composition/brief/contract.js +0 -209
  79. package/dist/_members/composition/color-grade.js +0 -80
  80. package/dist/_members/composition/depth.js +0 -8
  81. package/dist/_members/composition/fixtures/index.js +0 -143
  82. package/dist/_members/composition/fixtures/vaayaErrored.d.ts +0 -25
  83. package/dist/_members/composition/fixtures/vaayaErrored.js +0 -203
  84. package/dist/_members/composition/fonts.js +0 -162
  85. package/dist/_members/composition/graphics-plan/compile.js +0 -221
  86. package/dist/_members/composition/graphics-plan/index.js +0 -10
  87. package/dist/_members/composition/graphics-plan/instantiateMotif.js +0 -44
  88. package/dist/_members/composition/graphics-plan/motion.js +0 -66
  89. package/dist/_members/composition/graphics-plan/schemas.js +0 -261
  90. package/dist/_members/composition/graphics-plan/solve.js +0 -145
  91. package/dist/_members/composition/index.js +0 -5
  92. package/dist/_members/composition/invariants/clipPlacement.js +0 -69
  93. package/dist/_members/composition/invariants/composition.js +0 -28
  94. package/dist/_members/composition/invariants/errors.js +0 -10
  95. package/dist/_members/composition/invariants/etag.js +0 -38
  96. package/dist/_members/composition/invariants/ids.js +0 -33
  97. package/dist/_members/composition/invariants/index.js +0 -9
  98. package/dist/_members/composition/invariants/keyframes.js +0 -45
  99. package/dist/_members/composition/invariants/markers.js +0 -29
  100. package/dist/_members/composition/invariants/time.js +0 -20
  101. package/dist/_members/composition/invariants/tracks.js +0 -304
  102. package/dist/_members/composition/ops/compositionOps.js +0 -1056
  103. package/dist/_members/composition/ops/headlessStore.js +0 -94
  104. package/dist/_members/composition/ops/index.js +0 -4
  105. package/dist/_members/composition/ops/selectors.js +0 -118
  106. package/dist/_members/composition/ops/timeline-word.js +0 -1
  107. package/dist/_members/composition/ops/transcript.js +0 -77
  108. package/dist/_members/composition/ops/types.js +0 -16
  109. package/dist/_members/composition/primitive-catalog/catalogQuery.js +0 -150
  110. package/dist/_members/composition/primitive-catalog/disabled.js +0 -32
  111. package/dist/_members/composition/primitive-catalog/generated/meta.js +0 -15161
  112. package/dist/_members/composition/primitive-catalog/index.js +0 -46
  113. package/dist/_members/composition/primitive-catalog/paramValidation.js +0 -231
  114. package/dist/_members/composition/primitive-catalog/projection.js +0 -164
  115. package/dist/_members/composition/primitive-catalog/types.js +0 -14
  116. package/dist/_members/composition/projection/behind-placement.js +0 -62
  117. package/dist/_members/composition/projection/brandKit.js +0 -482
  118. package/dist/_members/composition/projection/cardTokens.js +0 -209
  119. package/dist/_members/composition/projection/composition-floor.js +0 -582
  120. package/dist/_members/composition/projection/cropProjection.js +0 -257
  121. package/dist/_members/composition/projection/index.js +0 -7
  122. package/dist/_members/composition/projection/occlusion-budget.js +0 -104
  123. package/dist/_members/composition/projection/safe-zones.js +0 -99
  124. package/dist/_members/composition/reframe/aspectLoss.js +0 -115
  125. package/dist/_members/composition/reframe/coverage.js +0 -62
  126. package/dist/_members/composition/reframe/derive.js +0 -73
  127. package/dist/_members/composition/reframe/index.js +0 -109
  128. package/dist/_members/composition/reframe/kenBurns.js +0 -64
  129. package/dist/_members/composition/reframe/shotScale.js +0 -176
  130. package/dist/_members/composition/reframe/trajectory.js +0 -124
  131. package/dist/_members/composition/timeline/compound.js +0 -134
  132. package/dist/_members/composition/timeline/index.js +0 -9
  133. package/dist/_members/composition/timeline/intent.js +0 -228
  134. package/dist/_members/composition/timeline/keyframes.js +0 -121
  135. package/dist/_members/composition/timeline/link.js +0 -59
  136. package/dist/_members/composition/timeline/occupancy.js +0 -36
  137. package/dist/_members/composition/timeline/placement.js +0 -74
  138. package/dist/_members/composition/timeline/plan.js +0 -31
  139. package/dist/_members/composition/timeline/resolve.js +0 -170
  140. package/dist/_members/composition/timeline/trims.js +0 -278
  141. package/dist/_members/composition/types/index.js +0 -1
  142. package/dist/_members/composition/validators/brandKit.js +0 -295
  143. package/dist/_members/composition/validators/composePlan.js +0 -113
  144. package/dist/_members/composition/validators/composition.js +0 -703
  145. package/dist/_members/composition/validators/font.js +0 -34
  146. package/dist/_members/composition/validators/graphicKinds.js +0 -30
  147. package/dist/_members/composition/validators/index.js +0 -9
  148. package/dist/_members/composition/validators/project.js +0 -29
  149. package/dist/_members/composition/validators/registry.js +0 -41
  150. package/dist/_members/composition/validators/render.js +0 -139
  151. package/dist/_members/composition/validators/session.js +0 -37
  152. package/dist/_members/composition/validators/webhook.js +0 -72
  153. package/dist/_members/composition-ops/alphaLayers.js +0 -141
  154. package/dist/_members/composition-ops/index.js +0 -637
  155. package/dist/_members/composition-ops/materializeGrid.js +0 -99
  156. package/dist/_members/composition-ops/opRecorder.js +0 -196
  157. package/dist/_members/composition-ops/recordingStore.js +0 -14
  158. package/dist/_members/composition-ops/replaceRegion.js +0 -102
  159. package/dist/_members/composition-ops/testFixtures.js +0 -19
  160. package/dist/_members/core/index.js +0 -5
  161. package/dist/_members/core/render/bookends.js +0 -53
  162. package/dist/_members/core/render/captions.js +0 -127
  163. package/dist/_members/core/render/compositionRender.js +0 -1249
  164. package/dist/_members/core/render/deriveTrajectory.js +0 -889
  165. package/dist/_members/core/render/emphasis.js +0 -16
  166. package/dist/_members/core/render/eval/cropBox.js +0 -139
  167. package/dist/_members/core/render/eval/inclusion.js +0 -96
  168. package/dist/_members/core/render/eval/index.js +0 -146
  169. package/dist/_members/core/render/eval/metrics.js +0 -94
  170. package/dist/_members/core/render/exportSettings.js +0 -65
  171. package/dist/_members/core/render/index.js +0 -20
  172. package/dist/_members/core/render/mapFaceToPerson.js +0 -73
  173. package/dist/_members/core/render/types.js +0 -8
  174. package/dist/_members/core/render/vcam/cameraPath.js +0 -248
  175. package/dist/_members/core/render/vcam/constants.js +0 -115
  176. package/dist/_members/core/render/vcam/errorCodes.js +0 -39
  177. package/dist/_members/core/render/vcam/framing.js +0 -136
  178. package/dist/_members/core/render/vcam/requiredRegion.js +0 -137
  179. package/dist/_members/core/render/vcam/shots.js +0 -53
  180. package/dist/_members/core/render/vcam/subjectSet.js +0 -388
  181. package/dist/_members/core/select/errorCodes.js +0 -38
  182. package/dist/_members/core/select/index.js +0 -26
  183. package/dist/_members/core/select/model.js +0 -18
  184. package/dist/_members/core/select/select.js +0 -244
  185. package/dist/_members/core/select/stabilize.js +0 -242
  186. package/dist/_members/core/types.js +0 -7
  187. package/dist/_members/errors/index.js +0 -1
  188. package/dist/_members/errors/registry.js +0 -560
  189. package/dist/_members/foundation/codes/index.js +0 -31
  190. package/dist/_members/foundation/index.js +0 -2
  191. package/dist/_members/foundation/primitives/index.js +0 -5
  192. package/dist/_members/mcp/adapter.js +0 -771
  193. package/dist/_members/mcp/burnedNames.js +0 -73
  194. package/dist/_members/mcp/core.js +0 -390
  195. package/dist/_members/mcp/curation.js +0 -792
  196. package/dist/_members/mcp/executor.js +0 -142
  197. package/dist/_members/mcp/format.js +0 -9
  198. package/dist/_members/mcp/generated/catalogPreviews.js +0 -95
  199. package/dist/_members/mcp/generated/harness.js +0 -81
  200. package/dist/_members/mcp/generated/operations.js +0 -131
  201. package/dist/_members/mcp/index.js +0 -50
  202. package/dist/_members/mcp/internalLoopTools.js +0 -109
  203. package/dist/_members/mcp/prompts.js +0 -45
  204. package/dist/_members/mcp/resources.js +0 -166
  205. package/dist/_members/mcp/server.js +0 -340
  206. package/dist/_members/mcp/wait.js +0 -378
  207. package/dist/_members/mcp/x402Meta.js +0 -66
  208. package/dist/_members/media-model/api.js +0 -175
  209. package/dist/_members/media-model/index.js +0 -1
  210. package/dist/_members/media-model/media-kind.js +0 -116
  211. package/dist/_members/media-model/testing/index.js +0 -1
  212. package/dist/_members/media-model/testing/mediaStoreContract.js +0 -82
  213. package/dist/_members/media-model/transcriptSearch.js +0 -70
  214. package/dist/_members/media-model/transcriptSearchCases.json +0 -79
  215. package/dist/_members/nle-export/compact-timeline.js +0 -73
  216. package/dist/_members/nle-export/compact-timeline.js.map +0 -1
  217. package/dist/_members/nle-export/composition-to-input.js +0 -147
  218. package/dist/_members/nle-export/composition-to-input.js.map +0 -1
  219. package/dist/_members/nle-export/fcpxml.js +0 -159
  220. package/dist/_members/nle-export/fcpxml.js.map +0 -1
  221. package/dist/_members/nle-export/index.js +0 -12
  222. package/dist/_members/nle-export/index.js.map +0 -1
  223. package/dist/_members/nle-export/premiere.js +0 -161
  224. package/dist/_members/nle-export/premiere.js.map +0 -1
  225. package/dist/_members/nle-export/server/index.js +0 -2
  226. package/dist/_members/nle-export/server/index.js.map +0 -1
  227. package/dist/_members/nle-export/server/pack-zip.js +0 -38
  228. package/dist/_members/nle-export/server/pack-zip.js.map +0 -1
  229. package/dist/_members/nle-export/srt.js +0 -50
  230. package/dist/_members/nle-export/srt.js.map +0 -1
  231. package/dist/_members/nle-export/types.js +0 -9
  232. package/dist/_members/nle-export/types.js.map +0 -1
  233. package/dist/_members/nle-export/xml/index.js +0 -11
  234. package/dist/_members/nle-export/xml/index.js.map +0 -1
  235. package/dist/_members/nle-export/xml-utils.js +0 -48
  236. package/dist/_members/nle-export/xml-utils.js.map +0 -1
  237. package/dist/_members/perception/activeSpeaker.js +0 -103
  238. package/dist/_members/perception/audioQuality.js +0 -76
  239. package/dist/_members/perception/energyBeat.js +0 -99
  240. package/dist/_members/perception/identityMatch.js +0 -91
  241. package/dist/_members/perception/index.js +0 -48
  242. package/dist/_members/perception/visualQuality.js +0 -95
  243. package/dist/_members/plane/conformance.js +0 -90
  244. package/dist/_members/plane/contract.js +0 -49
  245. package/dist/_members/plane/index.js +0 -16
  246. package/dist/_members/primitives/backgrounds/index.js +0 -32
  247. package/dist/_members/primitives/backgrounds/index.js.map +0 -1
  248. package/dist/_members/primitives/captions/index.js +0 -398
  249. package/dist/_members/primitives/captions/index.js.map +0 -1
  250. package/dist/_members/primitives/chunk-2LVE4UIT.js +0 -139
  251. package/dist/_members/primitives/chunk-2LVE4UIT.js.map +0 -1
  252. package/dist/_members/primitives/chunk-3IQUH6KK.js +0 -20
  253. package/dist/_members/primitives/chunk-3IQUH6KK.js.map +0 -1
  254. package/dist/_members/primitives/chunk-3OMURV6Q.js +0 -112
  255. package/dist/_members/primitives/chunk-3OMURV6Q.js.map +0 -1
  256. package/dist/_members/primitives/chunk-4IS6TMEG.js +0 -21
  257. package/dist/_members/primitives/chunk-4IS6TMEG.js.map +0 -1
  258. package/dist/_members/primitives/chunk-5MWGAEGQ.js +0 -1644
  259. package/dist/_members/primitives/chunk-5MWGAEGQ.js.map +0 -1
  260. package/dist/_members/primitives/chunk-7RRPFPQK.js +0 -15
  261. package/dist/_members/primitives/chunk-7RRPFPQK.js.map +0 -1
  262. package/dist/_members/primitives/chunk-DH5TRZK2.js +0 -125
  263. package/dist/_members/primitives/chunk-DH5TRZK2.js.map +0 -1
  264. package/dist/_members/primitives/chunk-E3KNUSFG.js +0 -2337
  265. package/dist/_members/primitives/chunk-E3KNUSFG.js.map +0 -1
  266. package/dist/_members/primitives/chunk-G2B3G4HK.js +0 -47
  267. package/dist/_members/primitives/chunk-G2B3G4HK.js.map +0 -1
  268. package/dist/_members/primitives/chunk-HFPFGZXT.js +0 -1494
  269. package/dist/_members/primitives/chunk-HFPFGZXT.js.map +0 -1
  270. package/dist/_members/primitives/chunk-HIWVFZVH.js +0 -19
  271. package/dist/_members/primitives/chunk-HIWVFZVH.js.map +0 -1
  272. package/dist/_members/primitives/chunk-IDAL6G3Y.js +0 -134
  273. package/dist/_members/primitives/chunk-IDAL6G3Y.js.map +0 -1
  274. package/dist/_members/primitives/chunk-KNC6JP5F.js +0 -34
  275. package/dist/_members/primitives/chunk-KNC6JP5F.js.map +0 -1
  276. package/dist/_members/primitives/chunk-KYRDVZST.js +0 -459
  277. package/dist/_members/primitives/chunk-KYRDVZST.js.map +0 -1
  278. package/dist/_members/primitives/chunk-LWLHS2NS.js +0 -3410
  279. package/dist/_members/primitives/chunk-LWLHS2NS.js.map +0 -1
  280. package/dist/_members/primitives/chunk-QAQ3P7DR.js +0 -8855
  281. package/dist/_members/primitives/chunk-QAQ3P7DR.js.map +0 -1
  282. package/dist/_members/primitives/chunk-ROV2ODWC.js +0 -81
  283. package/dist/_members/primitives/chunk-ROV2ODWC.js.map +0 -1
  284. package/dist/_members/primitives/chunk-TCRC2FH3.js +0 -183
  285. package/dist/_members/primitives/chunk-TCRC2FH3.js.map +0 -1
  286. package/dist/_members/primitives/chunk-US4YEDAA.js +0 -96
  287. package/dist/_members/primitives/chunk-US4YEDAA.js.map +0 -1
  288. package/dist/_members/primitives/chunk-UVKRO5ER.js +0 -13
  289. package/dist/_members/primitives/chunk-UVKRO5ER.js.map +0 -1
  290. package/dist/_members/primitives/chunk-W4EIIF2I.js +0 -10
  291. package/dist/_members/primitives/chunk-W4EIIF2I.js.map +0 -1
  292. package/dist/_members/primitives/chunk-WPGKIPCO.js +0 -3563
  293. package/dist/_members/primitives/chunk-WPGKIPCO.js.map +0 -1
  294. package/dist/_members/primitives/chunk-WZFLEGMD.js +0 -1435
  295. package/dist/_members/primitives/chunk-WZFLEGMD.js.map +0 -1
  296. package/dist/_members/primitives/chunk-XHU3WBEI.js +0 -33
  297. package/dist/_members/primitives/chunk-XHU3WBEI.js.map +0 -1
  298. package/dist/_members/primitives/chunk-YN7WTZZ7.js +0 -46
  299. package/dist/_members/primitives/chunk-YN7WTZZ7.js.map +0 -1
  300. package/dist/_members/primitives/effects/index.js +0 -30
  301. package/dist/_members/primitives/effects/index.js.map +0 -1
  302. package/dist/_members/primitives/hero-text/index.js +0 -14
  303. package/dist/_members/primitives/hero-text/index.js.map +0 -1
  304. package/dist/_members/primitives/index.js +0 -64
  305. package/dist/_members/primitives/index.js.map +0 -1
  306. package/dist/_members/primitives/layouts/index.js +0 -24
  307. package/dist/_members/primitives/layouts/index.js.map +0 -1
  308. package/dist/_members/primitives/lib/easings.js +0 -26
  309. package/dist/_members/primitives/lib/easings.js.map +0 -1
  310. package/dist/_members/primitives/lib/index.js +0 -74
  311. package/dist/_members/primitives/lib/index.js.map +0 -1
  312. package/dist/_members/primitives/lib/palette.js +0 -72
  313. package/dist/_members/primitives/lib/palette.js.map +0 -1
  314. package/dist/_members/primitives/lib/preview.js +0 -8
  315. package/dist/_members/primitives/lib/preview.js.map +0 -1
  316. package/dist/_members/primitives/lib/schema.js +0 -12
  317. package/dist/_members/primitives/lib/schema.js.map +0 -1
  318. package/dist/_members/primitives/lib/seeded-random.js +0 -14
  319. package/dist/_members/primitives/lib/seeded-random.js.map +0 -1
  320. package/dist/_members/primitives/lib/text/contrast.js +0 -12
  321. package/dist/_members/primitives/lib/text/contrast.js.map +0 -1
  322. package/dist/_members/primitives/lib/text/fill.js +0 -8
  323. package/dist/_members/primitives/lib/text/fill.js.map +0 -1
  324. package/dist/_members/primitives/lib/text/fitText.js +0 -10
  325. package/dist/_members/primitives/lib/text/fitText.js.map +0 -1
  326. package/dist/_members/primitives/lib/text/marker.js +0 -8
  327. package/dist/_members/primitives/lib/text/marker.js.map +0 -1
  328. package/dist/_members/primitives/lib/text/motion.js +0 -16
  329. package/dist/_members/primitives/lib/text/motion.js.map +0 -1
  330. package/dist/_members/primitives/lib/text/recolor.js +0 -8
  331. package/dist/_members/primitives/lib/text/recolor.js.map +0 -1
  332. package/dist/_members/primitives/lib/text/spec.js +0 -1
  333. package/dist/_members/primitives/lib/text/spec.js.map +0 -1
  334. package/dist/_members/primitives/lib/text/stage.js +0 -8
  335. package/dist/_members/primitives/lib/text/stage.js.map +0 -1
  336. package/dist/_members/primitives/lib/text/typeface.js +0 -8
  337. package/dist/_members/primitives/lib/text/typeface.js.map +0 -1
  338. package/dist/_members/primitives/lib/tokens.js +0 -24
  339. package/dist/_members/primitives/lib/tokens.js.map +0 -1
  340. package/dist/_members/primitives/lib/types.js +0 -1
  341. package/dist/_members/primitives/lib/types.js.map +0 -1
  342. package/dist/_members/primitives/params-required.json +0 -153
  343. package/dist/_members/primitives/scenes/index.js +0 -25
  344. package/dist/_members/primitives/scenes/index.js.map +0 -1
  345. package/dist/_members/primitives/subject-foreground/index.js +0 -30
  346. package/dist/_members/primitives/subject-foreground/index.js.map +0 -1
  347. package/dist/_members/primitives/text/index.js +0 -57
  348. package/dist/_members/primitives/text/index.js.map +0 -1
  349. package/dist/_members/primitives/transitions/index.js +0 -67
  350. package/dist/_members/primitives/transitions/index.js.map +0 -1
  351. package/dist/_members/primitives/ui-blocks/index.js +0 -76
  352. package/dist/_members/primitives/ui-blocks/index.js.map +0 -1
  353. package/dist/_members/primitives/version-map.json +0 -105
  354. package/dist/_members/primitives/workspace.js +0 -60
  355. package/dist/_members/primitives/workspace.js.map +0 -1
@@ -1,99 +0,0 @@
1
- /**
2
- * materializeGrid — the pure media-time → timeline-time grid projection.
3
- *
4
- * A temporal GRID (beat map / word onsets / shot boundaries) lives in a media
5
- * item's own SOURCE time. To land cuts and transition midpoints on it, the grid
6
- * points must be mapped THROUGH a clip's placement (startTime, trim, playbackRate,
7
- * excludedRanges) into the composition's timeline, and written as markers.
8
- *
9
- * This module owns the pure projection + the marker minting; the DB-bound work
10
- * (reading the clip's source media evidence, idempotent marker replace) is the
11
- * route's — `services/convex/api/routes/materializeGrid.ts` — because the op is
12
- * route-materialized (the pure engine has no media reader), exactly like
13
- * `applyMotionPreset`.
14
- *
15
- * Source-time↔timeline mapping is NOT reinvented: the visible-window geometry
16
- * reuses `playableSpans` (@cueframe/core/render — the SAME trim-minus-excluded
17
- * span split the renderer projects), and the per-point timeline formula is the
18
- * one `mergeTimelineTranscripts` uses (`startTime + playedSource / playbackRate`),
19
- * extended to accumulate played source ACROSS excluded gaps.
20
- */
21
- import { playableSpans } from '@cueframe/core/render';
22
- /**
23
- * Fail-loud carrier for the materializeGrid guards. `code` is a registered
24
- * ErrorCode the op route re-throws as an `ApiError` (422) or folds into a
25
- * `dry_run` verdict. `opIndex` is stamped by the route (it knows the batch
26
- * position); the pure mapper leaves it undefined.
27
- */
28
- export class GridError extends Error {
29
- code;
30
- opIndex;
31
- constructor(code, message, opIndex) {
32
- super(message);
33
- this.code = code;
34
- this.opIndex = opIndex;
35
- this.name = 'GridError';
36
- }
37
- }
38
- /** Default marker cap (soft — a caller may raise it up to the hard ceiling). */
39
- export const GRID_DEFAULT_MAX_MARKERS = 500;
40
- /** Hard ceiling on markers materialized from one grid (never exceeded). */
41
- export const GRID_HARD_MAX_MARKERS = 2000;
42
- /**
43
- * Project media-time grid points (ms, in the source's own time) onto the
44
- * timeline through `placement`, minting one marker per VISIBLE point. Points
45
- * outside the clip's visible window (before/after the trim, or inside an
46
- * excluded range) are SKIPPED. Markers are named deterministically
47
- * (`<grid>-<n>`, id `grid-<grid>-<clipId>-<n>`, `n` = the running visible index)
48
- * so a re-run reproduces the exact set; `metadata.sourceClipId` records the
49
- * origin clip so the route can replace a prior materialization idempotently.
50
- *
51
- * Fails loud (`grid_cap_exceeded`) when the visible count exceeds `maxMarkers`
52
- * (default 500) — no silent truncation.
53
- */
54
- export function materializeGridMarkers(placement, gridPointsMs, opts) {
55
- const { grid, clipId } = opts;
56
- const cap = opts.maxMarkers ?? GRID_DEFAULT_MAX_MARKERS;
57
- const rate = placement.playbackRate ?? 1;
58
- const trimStart = placement.trim?.start ?? 0;
59
- // Rate-correct source window when trim is absent: the clip plays
60
- // `duration * rate` source-seconds from `trimStart`.
61
- const trimEnd = placement.trim?.end ?? trimStart + placement.duration * rate;
62
- const spans = playableSpans(trimStart, trimEnd, placement.excludedRanges);
63
- const markers = [];
64
- let n = 0;
65
- for (const ms of gridPointsMs) {
66
- const sourceSec = ms / 1000;
67
- // Accumulate played source-seconds before this point, walking visible spans
68
- // in order. A point that falls in a gap (excluded range) or past the last
69
- // span is not visible → skipped (no marker, index not advanced).
70
- let playedBefore = 0;
71
- let visible = false;
72
- for (const span of spans) {
73
- if (sourceSec < span.start)
74
- break; // in a gap before this span → invisible
75
- if (sourceSec < span.end) {
76
- playedBefore += sourceSec - span.start;
77
- visible = true;
78
- break;
79
- }
80
- playedBefore += span.end - span.start; // whole span is before the point
81
- }
82
- if (!visible)
83
- continue;
84
- markers.push({
85
- id: `grid-${grid}-${clipId}-${n}`,
86
- startTime: placement.startTime + playedBefore / rate,
87
- kind: grid,
88
- name: `${grid}-${n}`,
89
- metadata: { sourceClipId: clipId },
90
- });
91
- n++;
92
- }
93
- if (markers.length > cap) {
94
- throw new GridError('grid_cap_exceeded', `materializeGrid: ${markers.length} '${grid}' markers fall inside clip '${clipId}' — ` +
95
- `over the cap of ${cap}. Raise maxMarkers (≤ ${GRID_HARD_MAX_MARKERS}) or narrow the ` +
96
- `clip's visible window (trim / excludedRanges) so fewer grid points land.`);
97
- }
98
- return markers;
99
- }
@@ -1,196 +0,0 @@
1
- const genTrackId = (kind) => `track-${kind}-${crypto.randomUUID().slice(0, 8)}`;
2
- export function wrapWithOpRecorder(base, opts) {
3
- const { record, getComposition } = opts;
4
- const wrapped = {
5
- // ── clips ──
6
- // clip.add is family-self-routing; a bare `media` source is ambiguous, so
7
- // the editor's video-lane addClip stamps kind:'video' (replay byte-faithful:
8
- // the SAME object goes to the base store and the op). Every mapping derives
9
- // from ARGS + BEFORE-state only, so ops record BEFORE the base mutation —
10
- // `before` is exact and a throwing base never leaves a phantom op behind
11
- // (record throws first on invalid input; base throws are surfaced to the
12
- // caller with the op already journaled, which the flush's server apply
13
- // would then reject loudly — never silently).
14
- addClip: (clip, options) => {
15
- const before = getComposition();
16
- const c = clip.kind ? clip : { ...clip, kind: 'video' };
17
- if (options?.newTrack) {
18
- const newTrackId = options.newTrackId ?? genTrackId('video');
19
- record({ type: 'clip.add', clip: c, newTrack: true, newTrackId }, before);
20
- base.addClip(c, { newTrack: true, newTrackId });
21
- }
22
- else {
23
- record({ type: 'clip.add', clip: c }, before);
24
- base.addClip(c);
25
- }
26
- },
27
- removeClip: (id) => {
28
- record({ type: 'clip.remove', clipId: id }, getComposition());
29
- base.removeClip(id);
30
- },
31
- updateClip: (id, updates) => {
32
- record({ type: 'clip.update', clipId: id, patch: updates }, getComposition());
33
- base.updateClip(id, updates);
34
- },
35
- removeClipsByMediaId: (mediaId) => {
36
- record({ type: 'removeClipsByMediaId', mediaId }, getComposition());
37
- base.removeClipsByMediaId(mediaId);
38
- },
39
- setClipProperties: (id, props) => {
40
- // playbackRate is a cross-field ripple (source.playbackRate), NOT a free
41
- // clip.update merge. Editor lane: apply locally (the store's ripple is
42
- // correct) + signal unjournalable (→ snapshot barrier). Bench lane
43
- // (no handler): throw — its op-log must replay byte-faithfully.
44
- const { playbackRate, ...patch } = props;
45
- if (playbackRate !== undefined) {
46
- if (opts.onUnjournalable) {
47
- const result = base.setClipProperties(id, props);
48
- opts.onUnjournalable('setClipProperties.playbackRate');
49
- return result;
50
- }
51
- throw new Error('opRecorder.setClipProperties: playbackRate is not serializable as a clip.update op ' +
52
- '(source.playbackRate triggers a cross-field ripple). Use the server-authoritative ripple path.');
53
- }
54
- record({ type: 'clip.update', clipId: id, patch: patch }, getComposition());
55
- return base.setClipProperties(id, props);
56
- },
57
- // ── overlays (pre-emit the overlay track on first add: pinned id, targeted clip.add) ──
58
- addOverlay: (clip) => {
59
- const before = getComposition();
60
- const track = before.tracks.find((t) => t.kind === 'overlay');
61
- let trackId = track?.id;
62
- if (!trackId) {
63
- trackId = genTrackId('overlay');
64
- record({ type: 'addTrack', kind: 'overlay', id: trackId }, before);
65
- base.addTrack('overlay', undefined, trackId);
66
- }
67
- record({ type: 'clip.add', clip, trackId }, getComposition());
68
- base.addOverlay(clip);
69
- },
70
- removeOverlay: (id) => {
71
- record({ type: 'clip.remove', clipId: id }, getComposition());
72
- base.removeOverlay(id);
73
- },
74
- updateOverlay: (id, updates) => {
75
- record({ type: 'clip.update', clipId: id, patch: updates }, getComposition());
76
- base.updateOverlay(id, updates);
77
- },
78
- loadOverlays: (clips) => {
79
- record({ type: 'loadOverlays', clips }, getComposition());
80
- base.loadOverlays(clips);
81
- },
82
- // ── audio (same pre-emit rule) ──
83
- addAudioClip: (clip) => {
84
- const before = getComposition();
85
- const track = before.tracks.find((t) => t.kind === 'audio');
86
- let trackId = track?.id;
87
- if (!trackId) {
88
- trackId = genTrackId('audio');
89
- record({ type: 'addTrack', kind: 'audio', id: trackId }, before);
90
- base.addTrack('audio', undefined, trackId);
91
- }
92
- record({ type: 'clip.add', clip, trackId }, getComposition());
93
- base.addAudioClip(clip);
94
- },
95
- removeAudioClip: (id) => {
96
- record({ type: 'clip.remove', clipId: id }, getComposition());
97
- base.removeAudioClip(id);
98
- },
99
- updateAudioClip: (id, updates) => {
100
- record({ type: 'clip.update', clipId: id, patch: updates }, getComposition());
101
- base.updateAudioClip(id, updates);
102
- },
103
- // ── markers ──
104
- addMarker: (marker) => {
105
- record({ type: 'addMarker', marker }, getComposition());
106
- base.addMarker(marker);
107
- },
108
- removeMarker: (id) => {
109
- record({ type: 'removeMarker', markerId: id }, getComposition());
110
- base.removeMarker(id);
111
- },
112
- updateMarker: (id, updates) => {
113
- record({ type: 'updateMarker', markerId: id, updates }, getComposition());
114
- base.updateMarker(id, updates);
115
- },
116
- // ── crop / effects / captions / format ──
117
- setCropIntents: (clipId, segments) => {
118
- record({ type: 'setCropIntents', clipId, segments }, getComposition());
119
- base.setCropIntents(clipId, segments);
120
- },
121
- // Wholesale array — `[]` records the clear, same as any other set.
122
- setEffects: (clipId, effects) => {
123
- record({ type: 'setEffects', clipId, effects }, getComposition());
124
- base.setEffects(clipId, effects);
125
- },
126
- setCaptionStyle: (style) => {
127
- record({ type: 'setCaptionStyle', style }, getComposition());
128
- base.setCaptionStyle(style);
129
- },
130
- setCaptions: (segments, style) => {
131
- record({ type: 'setCaptions', segments, ...(style !== undefined ? { style } : {}) }, getComposition());
132
- base.setCaptions(segments, style);
133
- },
134
- setFormat: (format) => {
135
- record({ type: 'setFormat', format }, getComposition());
136
- base.setFormat(format);
137
- },
138
- // ── tracks (always pin the id) ──
139
- addTrack: (kind, name, id) => {
140
- const useId = id ?? genTrackId(kind);
141
- record({ type: 'addTrack', kind, ...(name !== undefined ? { name } : {}), id: useId }, getComposition());
142
- base.addTrack(kind, name, useId);
143
- },
144
- removeTrack: (trackId) => {
145
- record({ type: 'removeTrack', trackId }, getComposition());
146
- base.removeTrack(trackId);
147
- },
148
- updateTrack: (trackId, updates) => {
149
- record({ type: 'updateTrack', trackId, updates }, getComposition());
150
- base.updateTrack(trackId, updates);
151
- },
152
- reorderTracks: (fromIndex, toIndex) => {
153
- record({ type: 'reorderTracks', fromIndex, toIndex }, getComposition());
154
- base.reorderTracks(fromIndex, toIndex);
155
- },
156
- moveClipToTrack: (clipId, targetTrackId, newStartTime) => {
157
- record({
158
- type: 'moveClipToTrack',
159
- clipId,
160
- targetTrackId,
161
- ...(newStartTime !== undefined ? { newStartTime } : {}),
162
- }, getComposition());
163
- base.moveClipToTrack(clipId, targetTrackId, newStartTime);
164
- },
165
- duplicateClip: (id) => {
166
- record({ type: 'duplicateClip', clipId: id }, getComposition());
167
- return base.duplicateClip(id);
168
- },
169
- // ── server-authoritative (cross-field timeline recompute) ──
170
- cutAndRipple: (start, end) => {
171
- record({ type: 'cutAndRipple', start, end }, getComposition());
172
- base.cutAndRipple(start, end);
173
- },
174
- ripple: (time, amount) => {
175
- record({ type: 'ripple', time, amount }, getComposition());
176
- base.ripple(time, amount);
177
- },
178
- addExcludedRange: (clipId, sourceStart, sourceEnd, reason) => {
179
- record({
180
- type: 'addExcludedRange',
181
- clipId,
182
- sourceStart,
183
- sourceEnd,
184
- ...(reason !== undefined ? { reason } : {}),
185
- }, getComposition());
186
- base.addExcludedRange(clipId, sourceStart, sourceEnd, reason);
187
- },
188
- removeExcludedRange: (clipId, rangeIdx) => {
189
- record({ type: 'removeExcludedRange', clipId, rangeIdx }, getComposition());
190
- base.removeExcludedRange(clipId, rangeIdx);
191
- },
192
- };
193
- // Non-mutation members (getState, selection passthroughs, …) fall through to
194
- // base untouched; the wrapped mutations shadow them.
195
- return { ...base, ...wrapped };
196
- }
@@ -1,14 +0,0 @@
1
- import { createHeadlessStore, } from '@cueframe/composition/ops';
2
- import { wrapWithOpRecorder } from './opRecorder';
3
- export function createRecordingStore(initial) {
4
- const base = createHeadlessStore(initial);
5
- const ops = [];
6
- const wrapped = wrapWithOpRecorder(base, {
7
- record: (op, _before) => ops.push(op),
8
- getComposition: () => base.getState().composition,
9
- });
10
- return {
11
- ...wrapped,
12
- getOps: () => [...ops],
13
- };
14
- }
@@ -1,102 +0,0 @@
1
- /**
2
- * `replaceRegion` — the NON-RIPPLING cut/overlay lowering (selector-abstraction
3
- * spec §6.2). The genuinely-new timeline primitive the switch instance needs:
4
- * neither existing authoring mode fits a same-track temporal cut —
5
- * - `add_clip mode:"layer"` makes a FRESH track (b-roll over A-roll), and
6
- * - `add_clip mode:"ripple-insert"` SHIFTS downstream content.
7
- * A multicam switch is an OVERWRITE: A→B→C occupy the SAME region of the SAME
8
- * track, back to back, with nothing rippling.
9
- *
10
- * PLACEMENT: this lives in `@cueframe/composition-ops` (NOT framework-bound; it
11
- * already depends on `@cueframe/composition` + `@cueframe/core`). It does NOT
12
- * import the Selector core — it consumes a plain `CutSchedule` (the resolver's
13
- * lowered advisory), so the source-only concepts (`programAudioSourceId`, cut vs
14
- * overlay, source-window placement) live HERE, never in the core.
15
- *
16
- * Two kinds (spec §6.2):
17
- * - `kind:"cut"` (synced angles): video follows the chosen source; AUDIO FOLLOWS
18
- * the video UNLESS `programAudioSourceId` is set, in which case audio is pinned
19
- * to one continuous bed on a separate audio track while video cuts (topology-i).
20
- * - `kind:"overlay"` (b-roll cutaway): video-over on a NEW overlay/video track,
21
- * primary audio continues (this defers to the existing layer semantics; the
22
- * presence-gate authored its windows). The switch instance authors `cut`.
23
- *
24
- * Validates fail-loud: the authored segments tile the region without overlap/gap
25
- * (the `Gap.strict()` lesson) and every source window is in-media; the result
26
- * round-trips `Composition.parse` + `validateComposition`. Pure + deterministic.
27
- */
28
- import { Composition as CompositionSchema, } from '@cueframe/composition/validators';
29
- const EPS = 1e-3;
30
- /** Author a non-rippling cut schedule (+ optional pinned audio bed) onto a fresh
31
- * video track of the composition. Returns the new composition (pure). */
32
- export function replaceRegion(input) {
33
- const { cutSchedule, programAudioSourceId, durationByMediaId } = input;
34
- if (cutSchedule.length === 0) {
35
- throw new Error('replaceRegion: empty cut schedule');
36
- }
37
- // 1. Validate the schedule TILES its region (no gap, no overlap) — the
38
- // Gap.strict() lesson: an overlap/gap is a silent render artifact.
39
- const sorted = [...cutSchedule].sort((a, b) => a.startSec - b.startSec);
40
- for (let i = 0; i < sorted.length; i++) {
41
- const s = sorted[i];
42
- if (s.endSec <= s.startSec)
43
- throw new Error(`replaceRegion: cut span '${s.candidateId}' has non-positive duration [${s.startSec},${s.endSec}]`);
44
- const dur = durationByMediaId[s.mediaId];
45
- if (dur !== undefined && (s.sourceInSec < -EPS || s.sourceOutSec > dur + EPS)) {
46
- throw new Error(`replaceRegion: cut span '${s.candidateId}' source [${s.sourceInSec},${s.sourceOutSec}] out of media [0,${dur}]`);
47
- }
48
- if (i > 0) {
49
- const prev = sorted[i - 1];
50
- if (Math.abs(s.startSec - prev.endSec) > EPS) {
51
- throw new Error(`replaceRegion: cut schedule is not contiguous — gap/overlap between ${prev.endSec} and ${s.startSec}`);
52
- }
53
- }
54
- }
55
- const regionStart = sorted[0].startSec;
56
- const regionEnd = sorted[sorted.length - 1].endSec;
57
- // 2. Build the video cut track — each span is one OVERWRITE clip, placed back-
58
- // to-back (no ripple). When audio is pinned, the video clips are muted (the
59
- // pinned bed carries the program audio); else audio follows (default volume).
60
- const audioPinned = programAudioSourceId !== undefined;
61
- // `mediaId` is a branded `Id<"mediaItems">` on the validator, but the resolver
62
- // supplies a plain string. Cast the source at the boundary (the same pattern as
63
- // authoring/timeline.ts `add_clip`), then the schema re-validates the whole shape.
64
- const mediaClip = (id, startTime, duration, mediaId, trimStart, trimEnd, extra = {}) => ({
65
- id,
66
- startTime,
67
- duration,
68
- source: { kind: 'media', mediaId, trim: { start: trimStart, end: trimEnd }, ...extra },
69
- });
70
- const videoTrack = {
71
- id: `switch-cut-${stableSuffix(sorted)}`,
72
- kind: 'video',
73
- name: input.trackName ?? 'Switch Cut',
74
- contents: sorted.map((s, i) => mediaClip(`cut-${i}-${s.candidateId}`, s.startSec, s.endSec - s.startSec, s.mediaId, s.sourceInSec, s.sourceOutSec, audioPinned ? { muted: true } : {})),
75
- };
76
- const tracks = [...input.composition.tracks, videoTrack];
77
- // 3. Pinned program audio bed (topology-i): ONE continuous clip on a separate
78
- // audio track spanning the whole region from the program source.
79
- if (audioPinned) {
80
- const dur = durationByMediaId[programAudioSourceId];
81
- const audioOut = regionEnd - regionStart; // program audio starts at region start
82
- if (dur !== undefined && audioOut > dur + EPS) {
83
- throw new Error(`replaceRegion: program audio source '${programAudioSourceId}' (${dur}s) shorter than the region (${audioOut}s)`);
84
- }
85
- tracks.push({
86
- id: `switch-audio-${programAudioSourceId}`,
87
- kind: 'audio',
88
- name: 'Program Audio',
89
- contents: [
90
- mediaClip(`program-audio-${programAudioSourceId}`, regionStart, regionEnd - regionStart, programAudioSourceId, 0, regionEnd - regionStart, { sync: 'independent' }),
91
- ],
92
- });
93
- }
94
- const next = { ...input.composition, tracks };
95
- // 4. Round-trip through the canonical zod validator (Composition.parse) — the
96
- // Gap.strict() union + every per-field invariant fire here, fail-loud.
97
- return CompositionSchema.parse(next);
98
- }
99
- /** A stable id suffix from the schedule (deterministic — no Date/random). */
100
- function stableSuffix(spans) {
101
- return spans.map((s) => `${s.candidateId}@${s.startSec.toFixed(2)}`).join('_').slice(0, 48).replace(/[^a-zA-Z0-9_@.-]/g, '');
102
- }
@@ -1,19 +0,0 @@
1
- /** A media-source clip with an EXPLICIT family `kind` (video|audio|image). */
2
- export const mediaClip = (id, kind) => ({
3
- id,
4
- startTime: 0,
5
- duration: 5,
6
- ...(kind ? { kind } : {}),
7
- source: { kind: 'media', mediaId: 'media-1', trim: { start: 0, end: 5 } },
8
- });
9
- /** An overlay-source clip — family derives from `source.kind` (no clip.kind). */
10
- export const overlayClip = (id) => ({
11
- id,
12
- startTime: 0,
13
- duration: 3,
14
- source: { kind: 'overlay', primitiveId: 'cinematic-title', params: { text: 'hi' } },
15
- });
16
- /** An audio clip: a media source carried on the `audio` family. */
17
- export const audioClip = (id) => mediaClip(id, 'audio');
18
- /** A minimal valid Marker (point marker on the timeline). */
19
- export const marker = (id, startTime = 1) => ({ id, startTime, kind: 'note', name: `marker ${id}` });
@@ -1,5 +0,0 @@
1
- export * from './types';
2
- // Re-export render module, excluding OverlayTemplate and OverlayParams which
3
- // are already exported from ./types with a different (generic) shape.
4
- // Consumers that need the Remotion-specific versions import from '@cueframe/core/render'.
5
- export { buildEmphasisSet, isEmphasized, extractCaptionWordsFromDoc, DEFAULT_FPS, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_RENDER_SETTINGS, FORMAT_PRESETS, RESOLUTION_PRESETS, bppToCrf, computeExportDimensions, ensureEven, } from './render';
@@ -1,53 +0,0 @@
1
- /** Card bumper default length when the kit didn't set one (mirrors the resolver). */
2
- export const CARD_BOOKEND_DEFAULT_MS = 1500;
3
- /**
4
- * Video bumper fallback length when the kit set no `durationMs`. The resolver
5
- * forces no default for `kind:'video'` ("clip length governs"), but the pure
6
- * timeline math can't probe the clip's intrinsic length, so the renderer
7
- * reserves this deterministic window. A kit that sets `durationMs` overrides it.
8
- */
9
- export const VIDEO_BOOKEND_DEFAULT_MS = 3000;
10
- /**
11
- * Frames a single intro/outro bumper reserves on the timeline, or 0 when it is
12
- * absent/odd (soft). `card` always reserves (defaults to 1.5s); `video` reserves
13
- * only with a usable `src` (else there is nothing to play).
14
- */
15
- export function bookendFrames(bumper, fps) {
16
- if (!bumper)
17
- return 0;
18
- if (bumper.kind !== "card" && bumper.kind !== "video")
19
- return 0;
20
- if (!Number.isFinite(fps) || fps <= 0)
21
- return 0;
22
- // A video bumper with no source can't render — soft no-op.
23
- if (bumper.kind === "video" &&
24
- (typeof bumper.src !== "string" || bumper.src.length === 0)) {
25
- return 0;
26
- }
27
- const fallbackMs = bumper.kind === "card" ? CARD_BOOKEND_DEFAULT_MS : VIDEO_BOOKEND_DEFAULT_MS;
28
- const ms = typeof bumper.durationMs === "number" &&
29
- Number.isFinite(bumper.durationMs) &&
30
- bumper.durationMs > 0
31
- ? bumper.durationMs
32
- : fallbackMs;
33
- const frames = Math.round((ms / 1000) * fps);
34
- return frames > 0 ? frames : 0;
35
- }
36
- /**
37
- * Forward timeline math: given the resolved kit's bumpers and the body's frame
38
- * length, place the bookends and compute the extended total. fps-driven; a
39
- * non-positive body folds to 0 (the total is then just the bookends).
40
- */
41
- export function resolveBookendTimeline(brandKit, bodyFrames, fps) {
42
- const introFrames = bookendFrames(brandKit?.intro, fps);
43
- const outroFrames = bookendFrames(brandKit?.outro, fps);
44
- const safeBody = Number.isFinite(bodyFrames) && bodyFrames > 0 ? bodyFrames : 0;
45
- return {
46
- introFrames,
47
- outroFrames,
48
- bodyStartFrames: introFrames,
49
- bodyFrames: safeBody,
50
- outroStartFrames: introFrames + safeBody,
51
- totalFrames: introFrames + safeBody + outroFrames,
52
- };
53
- }
@@ -1,127 +0,0 @@
1
- import { buildEmphasisSet, isEmphasized } from './emphasis';
2
- /**
3
- * Slice a transcript's word stream to a clip window.
4
- *
5
- * Source: `utterances[].words[]` with second-precision `start` / `end`.
6
- * Output: `CaptionWord[]` with millisecond timings rebased so the
7
- * first word's `startMs` is 0 (relative to the clip, not the source).
8
- * Words wholly outside `[fromSec, toSec)` are dropped; words that
9
- * straddle either edge are clamped to the boundary.
10
- *
11
- * Pure function — no I/O, no DB. Caller fetches the transcript blob
12
- * (typically from R2) and feeds the parsed `utterances` here.
13
- */
14
- export function sliceTranscriptWords(utterances, fromSec, toSec) {
15
- const out = [];
16
- for (const utt of utterances) {
17
- if (!utt.words || utt.words.length === 0)
18
- continue;
19
- for (const w of utt.words) {
20
- if (w.end <= fromSec)
21
- continue;
22
- if (w.start >= toSec)
23
- continue;
24
- const start = Math.max(w.start, fromSec);
25
- const end = Math.min(w.end, toSec);
26
- const text = (w.text ?? '').trim();
27
- if (!text)
28
- continue;
29
- out.push({
30
- text,
31
- startMs: Math.round((start - fromSec) * 1000),
32
- endMs: Math.round((end - fromSec) * 1000),
33
- });
34
- }
35
- }
36
- return out;
37
- }
38
- /**
39
- * Walk a TipTap doc JSONContent and extract non-deleted timedWord nodes
40
- * as CaptionWord[].
41
- *
42
- * In v2 the wire-shape composition encodes cuts physically (clip
43
- * startTime/duration), so caption timings are taken straight off the
44
- * timedWord attrs without any deletion-range shift.
45
- *
46
- * This makes the ProseMirror doc the single source of truth for caption text,
47
- * instead of re-reading raw Whisper transcripts.
48
- */
49
- export function extractCaptionWordsFromDoc(doc, emphasisWords) {
50
- const captions = [];
51
- const emphasisSet = buildEmphasisSet(emphasisWords);
52
- function walk(node) {
53
- if (node.type === 'timedWord' && node.attrs && !node.attrs.deleted) {
54
- const start = node.attrs.start;
55
- const end = node.attrs.end;
56
- const text = node.content?.[0]?.text ?? '';
57
- if (!text.trim())
58
- return;
59
- captions.push({
60
- text,
61
- startMs: start * 1000,
62
- endMs: end * 1000,
63
- emphasis: isEmphasized(emphasisSet, node.attrs.mediaId, node.attrs.sourceStart) || undefined,
64
- });
65
- }
66
- if (node.content) {
67
- for (const child of node.content)
68
- walk(child);
69
- }
70
- }
71
- walk(doc);
72
- return captions;
73
- }
74
- // Common abbreviations whose trailing period is NOT a sentence end. Lower-cased,
75
- // period stripped. Not exhaustive — sentence-boundary disambiguation is
76
- // inherently lossy; this covers the frequent cases (titles, latin, units) so
77
- // captions don't false-break mid-sentence. Erring toward UNDER-splitting is
78
- // correct here: a missed split merges two short sentences (mildly long page),
79
- // whereas a false split is the exact mid-sentence cut this fix removes.
80
- const SENTENCE_ABBREVIATIONS = new Set([
81
- 'mr', 'mrs', 'ms', 'dr', 'prof', 'sr', 'jr', 'st', 'rev', 'gen', 'sen', 'gov',
82
- 'rep', 'capt', 'sgt', 'lt', 'col', 'vs', 'etc', 'inc', 'ltd', 'co', 'corp',
83
- 'mt', 'no', 'vol', 'dept', 'fig', 'al', 'approx',
84
- ]);
85
- /** Whether a word's text terminates a sentence. `!`/`?` always do; a trailing
86
- * `.` does NOT when the token is an initialism (`U.S.`, `e.g.`, `a.m.`) or a
87
- * known abbreviation (`Dr.`, `etc.`). A number like "3.14" ends in a digit. */
88
- function isSentenceEnd(text) {
89
- const t = text.trim();
90
- if (/[!?]$/.test(t))
91
- return true;
92
- if (!t.endsWith('.'))
93
- return false;
94
- // Initialism / dotted abbreviation: every letter followed by a period
95
- // (U.S., e.g., i.e., a.m., p.m.) — internal periods mark it as not-a-stop.
96
- if (/^(\p{L}\.)+$/u.test(t))
97
- return false;
98
- if (SENTENCE_ABBREVIATIONS.has(t.slice(0, -1).toLowerCase()))
99
- return false;
100
- return true;
101
- }
102
- /**
103
- * Group a flat word stream into sentence-bounded segments — start a new segment
104
- * after any word that ends a sentence (`isSentenceEnd`). Caption words carry
105
- * punctuation from Deepgram's `punctuated_word`, so the trailing-character test
106
- * is reliable; abbreviations and initialisms are guarded so they don't
107
- * false-split mid-sentence.
108
- *
109
- * This is how a raw transcript slice becomes `composition.captions.segments`:
110
- * the renderer treats each segment as a hard caption-page boundary, so
111
- * sentence-bounded segments make captions cut at sentence ends. A stream with
112
- * no terminal punctuation yields a single segment; an empty stream yields none.
113
- */
114
- export function splitIntoSentences(words) {
115
- const segments = [];
116
- let current = [];
117
- for (const word of words) {
118
- current.push(word);
119
- if (isSentenceEnd(word.text)) {
120
- segments.push(current);
121
- current = [];
122
- }
123
- }
124
- if (current.length > 0)
125
- segments.push(current);
126
- return segments;
127
- }