@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,134 +0,0 @@
1
- import { InvariantError } from "../invariants/errors";
2
- import { retimeChannel } from "./keyframes";
3
- export const MAX_COMPOUND_DEPTH = 4;
4
- /** Does this composition contain any compound clip at all? Cheap gate. */
5
- export function hasCompoundClips(composition) {
6
- for (const track of composition.tracks) {
7
- for (const item of track.contents) {
8
- if ("source" in item && item.source.kind === "composition")
9
- return true;
10
- }
11
- }
12
- return false;
13
- }
14
- export function flattenCompoundClips(composition, resolve) {
15
- return flatten(composition, resolve, [], 0);
16
- }
17
- function flatten(composition, resolve, path, depth) {
18
- if (!hasCompoundClips(composition))
19
- return composition;
20
- if (depth >= MAX_COMPOUND_DEPTH) {
21
- throw new InvariantError({
22
- code: "compound_depth_exceeded",
23
- message: `compound clips nest deeper than ${MAX_COMPOUND_DEPTH} ` +
24
- `(path: ${path.join(" → ") || "(root)"}) — flattening refused`,
25
- details: { path, maxDepth: MAX_COMPOUND_DEPTH },
26
- });
27
- }
28
- const outTracks = [];
29
- for (const track of composition.tracks) {
30
- const kept = [];
31
- /** Tracks minted from compound children on this host track, in order. */
32
- const minted = [];
33
- for (const item of track.contents) {
34
- if (!("source" in item) || item.source.kind !== "composition") {
35
- kept.push(item);
36
- continue;
37
- }
38
- const compound = item;
39
- const source = compound.source;
40
- if (path.includes(source.compositionId)) {
41
- throw new InvariantError({
42
- code: "compound_cycle",
43
- message: `composition "${source.compositionId}" embeds itself ` +
44
- `(${[...path, source.compositionId].join(" → ")}) — there is no finite flattening`,
45
- details: { cycle: [...path, source.compositionId] },
46
- });
47
- }
48
- const child = resolve(source.compositionId);
49
- if (!child) {
50
- throw new InvariantError({
51
- code: "compound_unresolved",
52
- message: `clip "${compound.id}" embeds composition "${source.compositionId}", ` +
53
- `which the caller could not resolve — rendering without it would ship a ` +
54
- `deliverable missing a sequence`,
55
- details: { clipId: compound.id, compositionId: source.compositionId },
56
- });
57
- }
58
- const flatChild = flatten(child, resolve, [...path, source.compositionId], depth + 1);
59
- // Minted tracks inherit the HOST track's disabled state — a compound clip
60
- // on a muted track must vanish with it, not outlive it on lanes of its
61
- // own (review finding 2026-08-24).
62
- const projected = projectChild(flatChild, compound, source);
63
- minted.push(...(track.enabled === false
64
- ? projected.map((t) => ({ ...t, enabled: false }))
65
- : projected));
66
- }
67
- outTracks.push({ ...track, contents: kept });
68
- outTracks.push(...minted);
69
- }
70
- return { ...composition, tracks: outTracks };
71
- }
72
- /** The child's tracks, windowed and shifted into the host's time. */
73
- function projectChild(child, compound, source) {
74
- const windowStart = source.trim?.start ?? 0;
75
- const windowEnd = Math.min(source.trim?.end ?? Number.POSITIVE_INFINITY, windowStart + compound.duration);
76
- const out = [];
77
- for (const track of child.tracks) {
78
- const contents = [];
79
- for (const item of track.contents) {
80
- if (!("source" in item))
81
- continue;
82
- const clip = item;
83
- const clipEnd = clip.startTime + clip.duration;
84
- const start = Math.max(clip.startTime, windowStart);
85
- const end = Math.min(clipEnd, windowEnd);
86
- if (end - start <= 1e-6)
87
- continue; // outside the window
88
- const headDelta = start - clip.startTime;
89
- const duration = end - start;
90
- const projected = {
91
- ...clip,
92
- id: `${compound.id}:${clip.id}`,
93
- startTime: compound.startTime + (start - windowStart),
94
- duration,
95
- source: windowedSource(clip, headDelta, duration),
96
- ...(clip.animate ? { animate: windowedAnimate(clip, headDelta, duration) } : {}),
97
- // A child's link group must not merge with an identically-named one in
98
- // the host or a sibling instance — scope it like the ids.
99
- ...(clip.linkGroupId ? { linkGroupId: `${compound.id}:${clip.linkGroupId}` } : {}),
100
- };
101
- contents.push(projected);
102
- }
103
- if (contents.length > 0) {
104
- out.push({
105
- ...track,
106
- id: `${compound.id}:${track.id}`,
107
- contents,
108
- });
109
- }
110
- }
111
- return out;
112
- }
113
- /** The clip's source with its own window advanced by the flatten cut. */
114
- function windowedSource(clip, headDelta, duration) {
115
- const source = clip.source;
116
- if (source.kind !== "media" || !source.trim)
117
- return source;
118
- const rate = source.playbackRate ?? 1;
119
- const start = source.trim.start + headDelta * rate;
120
- return { ...source, trim: { start, end: start + duration * rate } };
121
- }
122
- function windowedAnimate(clip, headDelta, duration) {
123
- if (!clip.animate)
124
- return undefined;
125
- const out = {};
126
- for (const [param, channel] of Object.entries(clip.animate)) {
127
- if (!channel)
128
- continue;
129
- const retimed = retimeChannel(channel, headDelta, duration);
130
- if (retimed.length >= 2)
131
- out[param] = retimed;
132
- }
133
- return Object.keys(out).length > 0 ? out : undefined;
134
- }
@@ -1,9 +0,0 @@
1
- export * from "./occupancy";
2
- export * from "./plan";
3
- export * from "./placement";
4
- export * from "./resolve";
5
- export * from "./keyframes";
6
- export * from "./compound";
7
- export * from "./trims";
8
- export * from "./link";
9
- export * from "./intent";
@@ -1,228 +0,0 @@
1
- import { collidingClips } from "./occupancy";
2
- import { resolvePlacement } from "./placement";
3
- import { resolveOverlaps } from "./resolve";
4
- import { emptyPlan } from "./plan";
5
- import { expandClipIdsToLinkGroups } from "./link";
6
- /** Occupancy rows only — the full clip rows come from `clipsById`. */
7
- function projectTracks(composition) {
8
- return composition.tracks.map((t) => ({
9
- id: t.id,
10
- kind: t.kind,
11
- contents: t.contents
12
- .filter((c) => "source" in c && !!c.id)
13
- .map((c) => ({ id: c.id, startTime: c.startTime, duration: c.duration })),
14
- }));
15
- }
16
- function indexClips(composition) {
17
- const clipsById = new Map();
18
- const trackIdByClipId = new Map();
19
- for (const track of composition.tracks) {
20
- for (const item of track.contents) {
21
- if (!("source" in item))
22
- continue;
23
- const clip = item;
24
- clipsById.set(clip.id, clip);
25
- trackIdByClipId.set(clip.id, track.id);
26
- }
27
- }
28
- return { clipsById, trackIdByClipId };
29
- }
30
- /** `source.kind` is what compatibility is judged on, not the track family. */
31
- const sourceKindOf = (clip) => clip.source.kind;
32
- /** Keep the mutable occupancy in step with the ops we just emitted. */
33
- function applyOpsToOccupancy(track, ops) {
34
- for (const op of ops) {
35
- switch (op.op) {
36
- case "removeClip":
37
- track.contents = track.contents.filter((c) => c.id !== op.clipId);
38
- break;
39
- case "updateClip": {
40
- const row = track.contents.find((c) => c.id === op.clipId);
41
- if (!row)
42
- break;
43
- if (op.patch.startTime != null)
44
- row.startTime = op.patch.startTime;
45
- if (op.patch.duration != null)
46
- row.duration = op.patch.duration;
47
- break;
48
- }
49
- case "insertClip":
50
- track.contents.push({
51
- id: op.clip.id,
52
- startTime: op.clip.startTime,
53
- duration: op.clip.duration,
54
- });
55
- break;
56
- default:
57
- break;
58
- }
59
- }
60
- }
61
- /**
62
- * Every requested move, plus one per unrequested link partner shifted by the
63
- * same delta. A partner already named explicitly is not duplicated.
64
- */
65
- function expandMovesToLinkGroups(composition, moves, clipsById) {
66
- const named = new Set(moves.map((m) => m.clipId));
67
- const out = [...moves];
68
- for (const move of moves) {
69
- const clip = clipsById.get(move.clipId);
70
- if (!clip?.linkGroupId)
71
- continue;
72
- const delta = move.startTime - clip.startTime;
73
- for (const partnerId of expandClipIdsToLinkGroups(composition, [move.clipId])) {
74
- if (named.has(partnerId))
75
- continue;
76
- const partner = clipsById.get(partnerId);
77
- if (!partner)
78
- continue;
79
- named.add(partnerId);
80
- out.push({
81
- clipId: partnerId,
82
- // The partner keeps its own lane — linking couples TIME, not track.
83
- toTrackId: trackIdOf(composition, partnerId) ?? move.toTrackId,
84
- startTime: Math.max(0, partner.startTime + delta),
85
- duration: partner.duration,
86
- });
87
- }
88
- }
89
- return out;
90
- }
91
- function trackIdOf(composition, clipId) {
92
- for (const track of composition.tracks) {
93
- for (const item of track.contents) {
94
- if ("source" in item && item.id === clipId)
95
- return track.id;
96
- }
97
- }
98
- return null;
99
- }
100
- export function resolveMoveIntent(args) {
101
- const { composition, intent, newClipId } = args;
102
- const policy = intent.policy ?? "resolve";
103
- const plan = emptyPlan(intent.label ?? (intent.moves.length > 1 ? "Move clips" : "Move clip"));
104
- const { clipsById, trackIdByClipId } = indexClips(composition);
105
- const tracks = projectTracks(composition);
106
- // A move that names one member of a link group moves the whole group, by the
107
- // same delta. Selection expansion already covers the UI path; this covers the
108
- // agent's, which names clip ids directly and never went through a selection.
109
- const withPartners = expandMovesToLinkGroups(composition, intent.moves, clipsById);
110
- const movingIds = withPartners.map((m) => m.clipId);
111
- // Every moving clip leaves its lane before anything is placed, so a clip
112
- // never collides with where it used to be — including the whole group, which
113
- // is why this is done up front rather than per move.
114
- for (const track of tracks) {
115
- track.contents = track.contents.filter((c) => !movingIds.includes(c.id));
116
- }
117
- const selection = [];
118
- for (const move of withPartners) {
119
- const clip = clipsById.get(move.clipId);
120
- if (!clip) {
121
- plan.refusals.push({ reason: "clip-not-found", entity: { kind: "clip", clipId: move.clipId } });
122
- continue;
123
- }
124
- if (!(move.duration > 0)) {
125
- plan.refusals.push({ reason: "zero-duration", entity: { kind: "clip", clipId: move.clipId } });
126
- continue;
127
- }
128
- const startTime = Math.max(0, move.startTime);
129
- const span = { startTime, duration: move.duration, excludeClipIds: movingIds };
130
- // `allowOccupied` — a user dragging a clip onto a busy lane means "put it
131
- // there and deal with what is in the way", not "find me somewhere near it".
132
- const placement = resolvePlacement({
133
- tracks,
134
- sourceKind: sourceKindOf(clip),
135
- spans: [span],
136
- strategy: { type: "explicit", trackId: move.toTrackId },
137
- allowOccupied: true,
138
- });
139
- if (placement.kind === "refused") {
140
- plan.refusals.push({
141
- reason: placement.reason,
142
- entity: { kind: "clip", clipId: move.clipId },
143
- });
144
- continue;
145
- }
146
- if (placement.kind === "newTrack") {
147
- // `explicit` + `allowOccupied` never mints a lane; a newTrack result here
148
- // would mean the resolver changed under us. Refuse rather than invent one.
149
- plan.refusals.push({
150
- reason: "track-not-found",
151
- entity: { kind: "clip", clipId: move.clipId },
152
- });
153
- continue;
154
- }
155
- const target = tracks[placement.trackIndex];
156
- const trackKind = placement.trackKind;
157
- const resolution = resolveOverlaps({
158
- track: target,
159
- trackKind,
160
- span,
161
- policy,
162
- clipsById,
163
- newClipId,
164
- });
165
- if (resolution.refusals.length > 0) {
166
- plan.refusals.push(...resolution.refusals);
167
- // A move that cannot clear its landing zone is not applied at all — a
168
- // partial group move is worse than none, because half a gesture is a
169
- // state the user did not ask for and cannot name in undo.
170
- continue;
171
- }
172
- plan.ops.push(...resolution.ops);
173
- applyOpsToOccupancy(target, resolution.ops);
174
- const fromTrackId = trackIdByClipId.get(move.clipId);
175
- if (fromTrackId !== placement.trackId) {
176
- plan.ops.push({
177
- op: "moveToTrack",
178
- clipId: move.clipId,
179
- toTrackId: placement.trackId,
180
- startTime,
181
- });
182
- // `moveClipToTrack` preserves duration, so a gesture that also resized
183
- // needs the geometry patch after the move.
184
- if (Math.abs(move.duration - clip.duration) > 1e-6) {
185
- plan.ops.push({
186
- op: "updateClip",
187
- clipId: move.clipId,
188
- trackKind,
189
- patch: { duration: move.duration },
190
- });
191
- }
192
- }
193
- else {
194
- plan.ops.push({
195
- op: "updateClip",
196
- clipId: move.clipId,
197
- trackKind,
198
- patch: { startTime, duration: move.duration },
199
- });
200
- }
201
- target.contents.push({ id: move.clipId, startTime, duration: move.duration });
202
- selection.push({ kind: "clip", clipId: move.clipId });
203
- }
204
- plan.resultingSelection = selection;
205
- return plan;
206
- }
207
- /**
208
- * The gate's read-only half: does this composition still satisfy the one rule
209
- * the move path exists to protect? Kept next to the resolver so a resolution
210
- * bug fails here rather than reaching the document.
211
- */
212
- export function planLeavesOverlaps(composition) {
213
- const found = [];
214
- for (const track of projectTracks(composition)) {
215
- for (const row of track.contents) {
216
- const others = collidingClips(track, {
217
- startTime: row.startTime,
218
- duration: row.duration,
219
- excludeClipIds: [row.id],
220
- });
221
- for (const other of others) {
222
- if (row.id < other.id)
223
- found.push({ trackId: track.id, clipIds: [row.id, other.id] });
224
- }
225
- }
226
- }
227
- return found;
228
- }
@@ -1,121 +0,0 @@
1
- /** Named easings, as cubic-bezier control points. EXPORTED so the curve
2
- * editor draws exactly what the interpolator evaluates — a UI restating these
3
- * numbers is a curve that lies about the motion. */
4
- export const EASING_CONTROL_POINTS = {
5
- linear: [0, 0, 1, 1],
6
- ease: [0.25, 0.1, 0.25, 1],
7
- easeIn: [0.42, 0, 1, 1],
8
- easeOut: [0, 0, 0.58, 1],
9
- easeInOut: [0.42, 0, 0.58, 1],
10
- };
11
- function controlPoints(easing) {
12
- if (!easing)
13
- return EASING_CONTROL_POINTS.linear;
14
- if (typeof easing === "string")
15
- return EASING_CONTROL_POINTS[easing] ?? EASING_CONTROL_POINTS.linear;
16
- return easing.cubicBezier;
17
- }
18
- /**
19
- * y at x for a cubic-bezier easing curve, x ∈ [0,1].
20
- *
21
- * Newton-Raphson with a bisection fallback — the standard approach, and the
22
- * fallback matters: Newton diverges on the near-vertical segments that the
23
- * overshoot presets (a "pop") deliberately have.
24
- */
25
- export function bezierEasing(t, [x1, y1, x2, y2]) {
26
- if (t <= 0)
27
- return 0;
28
- if (t >= 1)
29
- return 1;
30
- if (x1 === y1 && x2 === y2)
31
- return t; // linear
32
- const curveX = (u) => {
33
- const v = 1 - u;
34
- return 3 * v * v * u * x1 + 3 * v * u * u * x2 + u * u * u;
35
- };
36
- const curveY = (u) => {
37
- const v = 1 - u;
38
- return 3 * v * v * u * y1 + 3 * v * u * u * y2 + u * u * u;
39
- };
40
- const slopeX = (u) => {
41
- const v = 1 - u;
42
- return 3 * v * v * x1 + 6 * v * u * (x2 - x1) + 3 * u * u * (1 - x2);
43
- };
44
- let u = t;
45
- for (let i = 0; i < 8; i++) {
46
- const x = curveX(u) - t;
47
- if (Math.abs(x) < 1e-6)
48
- return curveY(u);
49
- const d = slopeX(u);
50
- if (Math.abs(d) < 1e-6)
51
- break;
52
- u -= x / d;
53
- }
54
- let lo = 0;
55
- let hi = 1;
56
- u = t;
57
- for (let i = 0; i < 20; i++) {
58
- const x = curveX(u);
59
- if (Math.abs(x - t) < 1e-6)
60
- break;
61
- if (x < t)
62
- lo = u;
63
- else
64
- hi = u;
65
- u = (lo + hi) / 2;
66
- }
67
- return curveY(u);
68
- }
69
- /** Channel sorted by time. Authoring order is not guaranteed to be time order. */
70
- export function sortedChannel(channel) {
71
- return [...channel].sort((a, b) => a.time - b.time);
72
- }
73
- /**
74
- * The channel's value at `clipTime` (seconds from the clip's start).
75
- *
76
- * Holds flat outside the channel's range rather than extrapolating — a value
77
- * invented beyond the last keyframe is a value nobody authored, and for
78
- * opacity or scale it is the difference between a clean hold and a fade to
79
- * something absurd.
80
- */
81
- export function valueAt(channel, clipTime) {
82
- const points = sortedChannel(channel);
83
- if (points.length === 0)
84
- return 0;
85
- if (clipTime <= points[0].time)
86
- return points[0].value;
87
- const last = points[points.length - 1];
88
- if (clipTime >= last.time)
89
- return last.value;
90
- let i = 0;
91
- while (i < points.length - 1 && points[i + 1].time <= clipTime)
92
- i++;
93
- const a = points[i];
94
- const b = points[i + 1];
95
- const span = b.time - a.time;
96
- if (span <= 0)
97
- return b.value;
98
- // The easing belongs to the keyframe being APPROACHED — "how do I arrive
99
- // here" — which is the convention every timeline UI draws.
100
- const eased = bezierEasing((clipTime - a.time) / span, controlPoints(b.easing));
101
- return a.value + (b.value - a.value) * eased;
102
- }
103
- /** True when this param is animated on this clip. */
104
- export function isAnimated(animate, param) {
105
- const channel = animate?.[param];
106
- return !!channel && channel.length >= 2;
107
- }
108
- /**
109
- * Re-time a channel for a clip whose window moved.
110
- *
111
- * The ONE case clip-relative time does not survive for free: trimming the head
112
- * shifts every keyframe's origin. Keyframes that fall outside the new window
113
- * are dropped rather than clamped — clamping would silently stack several onto
114
- * the same instant, which is exactly the `varying_keyframe_duplicate_time`
115
- * violation the invariants refuse.
116
- */
117
- export function retimeChannel(channel, headDelta, newDuration) {
118
- return sortedChannel(channel)
119
- .map((k) => ({ ...k, time: k.time - headDelta }))
120
- .filter((k) => k.time >= 0 && k.time <= newDuration);
121
- }
@@ -1,59 +0,0 @@
1
- /** Every clip id sharing a group with any of `clipIds`, including the inputs. */
2
- export function expandClipIdsToLinkGroups(composition, clipIds) {
3
- const seedIds = new Set(clipIds);
4
- if (seedIds.size === 0)
5
- return [];
6
- const groupsWanted = new Set();
7
- const all = [];
8
- for (const track of composition.tracks) {
9
- for (const item of track.contents) {
10
- if (!("source" in item))
11
- continue;
12
- const clip = item;
13
- all.push(clip);
14
- if (seedIds.has(clip.id) && clip.linkGroupId)
15
- groupsWanted.add(clip.linkGroupId);
16
- }
17
- }
18
- const out = new Set(seedIds);
19
- if (groupsWanted.size > 0) {
20
- for (const clip of all) {
21
- if (clip.linkGroupId && groupsWanted.has(clip.linkGroupId))
22
- out.add(clip.id);
23
- }
24
- }
25
- return [...out];
26
- }
27
- /**
28
- * Selection with every link partner pulled in.
29
- *
30
- * Non-clip entities pass through untouched — a keyframe is not linked to
31
- * anything by this mechanism, and silently widening it would be worse than not
32
- * handling it.
33
- */
34
- export function expandToLinkGroup(composition, entities) {
35
- const clipIds = entities.filter((e) => e.kind === "clip").map((e) => e.clipId);
36
- if (clipIds.length === 0)
37
- return [...entities];
38
- const expanded = expandClipIdsToLinkGroups(composition, clipIds);
39
- const known = new Set(clipIds);
40
- const out = [...entities];
41
- for (const id of expanded) {
42
- if (!known.has(id))
43
- out.push({ kind: "clip", clipId: id });
44
- }
45
- return out;
46
- }
47
- /** The other members of `clipId`'s group. Empty when it is unlinked. */
48
- export function linkPartners(composition, clipId) {
49
- return expandClipIdsToLinkGroups(composition, [clipId]).filter((id) => id !== clipId);
50
- }
51
- /**
52
- * Ids for a new group. Returned rather than assigned so the caller decides how
53
- * the clips get updated — the kernel never mutates a composition.
54
- */
55
- export function makeLinkGroup(clipIds, newGroupId) {
56
- if (clipIds.length < 2)
57
- return null;
58
- return { linkGroupId: newGroupId(), clipIds };
59
- }
@@ -1,36 +0,0 @@
1
- const excluded = (span, id) => !!span.excludeClipIds && span.excludeClipIds.includes(id);
2
- /** Half-open overlap: `[aStart, aEnd)` against `[bStart, bEnd)`. */
3
- export function spansOverlap(aStart, aDuration, bStart, bDuration) {
4
- return aStart < bStart + bDuration && aStart + aDuration > bStart;
5
- }
6
- /** A span fits when it overlaps nothing already on the track. */
7
- export function spansFit(track, spans) {
8
- return spans.every((span) => collidingClips(track, span).length === 0);
9
- }
10
- /**
11
- * Everything on `track` that this span would sit on top of, in start order.
12
- * Returned rather than counted because the resolution strategies need to know
13
- * WHICH clips collide and HOW — a clip fully covered by the incoming span is a
14
- * different edit from one it merely clips the tail of.
15
- */
16
- export function collidingClips(track, span) {
17
- return track.contents
18
- .filter((c) => !excluded(span, c.id) &&
19
- c.duration > 0 &&
20
- spansOverlap(span.startTime, span.duration, c.startTime, c.duration))
21
- .slice()
22
- .sort((a, b) => a.startTime - b.startTime);
23
- }
24
- export function classifyOverlap(span, clip) {
25
- const spanEnd = span.startTime + span.duration;
26
- const clipEnd = clip.startTime + clip.duration;
27
- const startsAtOrBefore = span.startTime <= clip.startTime;
28
- const endsAtOrAfter = spanEnd >= clipEnd;
29
- if (startsAtOrBefore && endsAtOrAfter)
30
- return "covers";
31
- if (startsAtOrBefore)
32
- return "trims-head";
33
- if (endsAtOrAfter)
34
- return "trims-tail";
35
- return "engulfed-by";
36
- }
@@ -1,74 +0,0 @@
1
- /**
2
- * WHERE A SOURCE GOES.
3
- *
4
- * Hoisted from `cueframe/src/components/Timeline/fabric/placement.ts` (2026-08-23)
5
- * for the reason the module's own header predicted and the repo rule requires:
6
- * the cloud director writes compositions too, so a placement rule that lives in
7
- * the desktop is a rule the cloud does not have. This is now the single home.
8
- *
9
- * The vocabulary — strategy → resolve → a result that is either an existing
10
- * track or an instruction to mint one at an index — is unchanged. What changed
11
- * is that the DRAG path can reach it: previously the only caller was the media
12
- * drop path, so two of the four strategies had never been constructed by
13
- * production code at all.
14
- */
15
- import { isSourceKindCompatible } from "../invariants/tracks";
16
- import { spansFit } from "./occupancy";
17
- /** The track kind a source belongs on, or null when nothing accepts it. */
18
- export function trackKindForSource(sourceKind) {
19
- const kinds = ["video", "audio", "image", "overlay", "effect"];
20
- return kinds.find((k) => isSourceKindCompatible(k, sourceKind)) ?? null;
21
- }
22
- export function resolvePlacement(args) {
23
- const { tracks, sourceKind, trackKind, spans, strategy, allowOccupied = false } = args;
24
- const preferredKind = trackKind ?? trackKindForSource(sourceKind);
25
- if (!preferredKind)
26
- return { kind: "refused", reason: "no-compatible-track-kind" };
27
- const fits = (t) => trackKind ? t.kind === trackKind : isSourceKindCompatible(t.kind, sourceKind);
28
- const asExisting = (index) => ({
29
- kind: "existingTrack",
30
- trackId: tracks[index].id,
31
- trackIndex: index,
32
- trackKind: tracks[index].kind,
33
- });
34
- switch (strategy.type) {
35
- case "explicit": {
36
- const index = tracks.findIndex((t) => t.id === strategy.trackId);
37
- if (index < 0)
38
- return { kind: "refused", reason: "track-not-found" };
39
- if (!fits(tracks[index])) {
40
- return { kind: "refused", reason: "incompatible-track" };
41
- }
42
- if (!allowOccupied && !spansFit(tracks[index], spans)) {
43
- // A compatible lane that is already occupied gets a sibling directly
44
- // below it rather than silently pushing the drop elsewhere.
45
- return { kind: "newTrack", insertIndex: index + 1, trackKind: tracks[index].kind };
46
- }
47
- return asExisting(index);
48
- }
49
- case "firstAvailable": {
50
- const index = tracks.findIndex((t) => fits(t) && spansFit(t, spans));
51
- if (index >= 0)
52
- return asExisting(index);
53
- return { kind: "newTrack", insertIndex: tracks.length, trackKind: preferredKind };
54
- }
55
- case "preferIndex": {
56
- const hovered = tracks[strategy.trackIndex];
57
- if (hovered && fits(hovered) && spansFit(hovered, spans)) {
58
- return asExisting(strategy.trackIndex);
59
- }
60
- const insertIndex = strategy.hoverDirection === "above" ? strategy.trackIndex : strategy.trackIndex + 1;
61
- return {
62
- kind: "newTrack",
63
- insertIndex: Math.max(0, Math.min(tracks.length, insertIndex)),
64
- trackKind: hovered && fits(hovered) ? hovered.kind : preferredKind,
65
- };
66
- }
67
- case "alwaysNew":
68
- return {
69
- kind: "newTrack",
70
- insertIndex: strategy.position === "highest" ? 0 : tracks.length,
71
- trackKind: preferredKind,
72
- };
73
- }
74
- }