@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,257 +0,0 @@
1
- /**
2
- * Crop→output projection — the SINGLE SOURCE OF TRUTH for mapping source-space
3
- * trajectory/face geometry into OUTPUT (post-crop) coordinates. Previously these
4
- * primitives lived in the Remotion app layer (packages/execution/render-entry/src/
5
- * CropFromTrajectory.tsx + floor/sourceToOutput.ts); lifted here so BOTH the
6
- * render path (buildFloorInput, CropFromTrajectory) AND the Director activity
7
- * (structure-first graphics keep-outs) derive output geometry from ONE copy —
8
- * no duplication, no approximation.
9
- *
10
- * All functions are pure math (no React/Remotion). The section-aware
11
- * output→trajectory map + fail-loud coverage checks are preserved verbatim.
12
- */
13
- import { CueframeError, encodeError } from "@cueframe/errors";
14
- import { activeFaceKeepOutSeries, boundingBox } from "./composition-floor";
15
- // Max fps-conversion rounding error at a segment seam: round(sec*srcFps) on the
16
- // segment edge vs round(...*srcFps/fps) in the frame map can disagree by ~1
17
- // frame; 2 is that bound plus one frame of safety. NOT a tunable behavior knob.
18
- export const FRAME_ROUNDING_TOLERANCE = 2;
19
- /**
20
- * Resolve which trajectory segment (and index within it) a clip-relative source
21
- * frame lands in. A frame within FRAME_ROUNDING_TOLERANCE of a segment edge
22
- * clamps to the nearest edge; ANY larger gap FAILS LOUD (a real coverage/mapping
23
- * bug — a cropIntent gap with no excludedRange, or a bad trim/section mapping —
24
- * must not silently clamp onto the wrong frames).
25
- */
26
- export function resolveSegmentAt(traj, srcFrame) {
27
- for (const seg of traj.segments) {
28
- const segStartFrame = Math.round(seg.start_sec * traj.src_fps);
29
- const segEndFrame = Math.round(seg.end_sec * traj.src_fps);
30
- if (srcFrame >= segStartFrame && srcFrame < segEndFrame) {
31
- const inSegIdx = Math.max(0, Math.min(srcFrame - segStartFrame, seg.centers.length - 1));
32
- return { seg, inSegIdx };
33
- }
34
- }
35
- if (traj.segments.length === 0) {
36
- throw new Error(encodeError(new CueframeError('trajectory_unresolved', 'trajectory has no segments')));
37
- }
38
- // Out of every segment: find the nearest edge + its distance.
39
- let best = traj.segments[0];
40
- let bestInIdx = 0;
41
- let bestDist = Infinity;
42
- for (const seg of traj.segments) {
43
- const a = Math.round(seg.start_sec * traj.src_fps);
44
- const b = Math.round(seg.end_sec * traj.src_fps);
45
- const before = srcFrame < a;
46
- const dist = before ? a - srcFrame : srcFrame - (b - 1);
47
- if (dist < bestDist) {
48
- bestDist = dist;
49
- best = seg;
50
- bestInIdx = before ? 0 : Math.max(0, seg.centers.length - 1);
51
- }
52
- }
53
- if (bestDist > FRAME_ROUNDING_TOLERANCE) {
54
- throw new Error(encodeError(new CueframeError('trajectory_coverage_gap', `srcFrame ${srcFrame} is ${bestDist} frames outside every trajectory segment ` +
55
- `(nearest [${best.start_sec.toFixed(2)}–${best.end_sec.toFixed(2)}s]). A coverage/` +
56
- `mapping bug (a cropIntent gap with no excludedRange, or an output→trajectory frame ` +
57
- `mismatch) — refusing to silently clamp a crop onto the wrong frames.`, { srcFrame, gapFrames: bestDist, nearest: [best.start_sec, best.end_sec] })));
58
- }
59
- // Within rounding slack of an edge → clamp (legitimate seam rounding).
60
- return { seg: best, inSegIdx: Math.max(0, Math.min(bestInIdx, best.centers.length - 1)) };
61
- }
62
- /**
63
- * Map an OUTPUT frame to the CLIP-RELATIVE trajectory frame, section-aware. The
64
- * trajectory is clip-relative (frame 0 = the clip's `trim.start`), but a clip
65
- * with `excludedRanges` plays N playable spans, each seeking to a
66
- * SOURCE-ABSOLUTE `sourceInFrames` with the trimmed gaps removed. So output
67
- * frame F does NOT equal trajectory frame F; the section walk bridges the gaps.
68
- */
69
- export function outputToTrajectoryFrame(sections, trimStartFrames, outFrame, srcFps, fps) {
70
- let cum = 0;
71
- for (const s of sections) {
72
- if (outFrame < cum + s.durationInFrames) {
73
- const clipFramesAtFps = s.sourceInFrames - trimStartFrames + (outFrame - cum);
74
- return Math.round((clipFramesAtFps * srcFps) / fps);
75
- }
76
- cum += s.durationInFrames;
77
- }
78
- // Tail rounding overrun (±1-frame seam at the very end) — the sections tile the
79
- // whole output by construction; clamp to the last span's final played frame.
80
- const last = sections[sections.length - 1];
81
- const clipFramesAtFps = last.sourceInFrames - trimStartFrames + (last.durationInFrames - 1);
82
- return Math.round((clipFramesAtFps * srcFps) / fps);
83
- }
84
- /**
85
- * Pure crop-transform math. Given the resolved per-frame center + crop params,
86
- * the output dims, and the composition floor's reframe, returns the CSS
87
- * transform (`tx`, `ty`, scaled source dims). `tyNoShift` is the y-translation
88
- * WITHOUT the reframe, exposed so tests can assert magnitude.
89
- */
90
- export function computeCropTransform(input) {
91
- const { traj, outW, outH, cx, cy, zoomScale, verticalBias, lateralBias, reframe = { kind: 'transform', dy: 0, zoom: 1 }, } = input;
92
- const reframeDy = reframe.kind === 'transform' ? reframe.dy : 0;
93
- const faceScale = reframe.kind === 'transform' ? reframe.zoom : 1;
94
- // Crop window dimensions in source coords (largest output-aspect rect that fits
95
- // the source, scaled by zoom). zoom_scale<1.0 shrinks (= more zoom).
96
- const outAR = outW / outH;
97
- const srcAR = traj.src_w / traj.src_h;
98
- let cropW;
99
- let cropH;
100
- if (srcAR > outAR) {
101
- cropH = traj.src_h;
102
- cropW = traj.src_h * outAR;
103
- }
104
- else {
105
- cropW = traj.src_w;
106
- cropH = traj.src_w / outAR;
107
- }
108
- const bakedZoom = Math.max(0.4, Math.min(1.0, zoomScale));
109
- const effectiveZoom = Math.min(1.0, bakedZoom / Math.max(faceScale, 0.01));
110
- cropW *= effectiveZoom;
111
- cropH *= effectiveZoom;
112
- // Scale source uniformly so crop window = output dimensions.
113
- const scale = outW / cropW;
114
- const scaledSrcW = traj.src_w * scale;
115
- const scaledSrcH = traj.src_h * scale;
116
- // Translate so the crop center sits at the output center, with bias applied in
117
- // crop-window units (matches the bake's center+bias math).
118
- const biasXPx = cropW * lateralBias * scale;
119
- const biasYPx = cropH * verticalBias * scale;
120
- const txRaw = outW / 2 - cx * scaledSrcW + biasXPx;
121
- const tyNoShift = outH / 2 - cy * scaledSrcH + biasYPx;
122
- // Reframe-yield: slide the source by dy·outH (dy<0 raises the subject).
123
- const tyRaw = tyNoShift + reframeDy * outH;
124
- // Coverage clamp — the scaled source must ALWAYS cover the output canvas (no
125
- // black edge). A GEOMETRIC INVARIANT (cx/cy are raw face centroids).
126
- const tx = Math.min(0, Math.max(outW - scaledSrcW, txRaw));
127
- const ty = Math.min(0, Math.max(outH - scaledSrcH, tyRaw));
128
- return { tx, ty, tyNoShift, scaledSrcW, scaledSrcH };
129
- }
130
- /**
131
- * Map a SOURCE-normalized rect (`{x,y,w,h}` in [0,1] against source dims) to an
132
- * OUTPUT-normalized rect, applying the per-frame crop — the `crop∘FaceBoxSource`
133
- * the composition floor's `FaceBoxOutput` is defined as. NOT clamped: a face near
134
- * the source edge can map partly off-frame, and that is the truth the floor needs
135
- * (`faceKeepOut` clamps to [0,1] when it builds the keep-out).
136
- */
137
- export function sourceRectToOutput(src, t, outW, outH) {
138
- return {
139
- x: (t.tx + src.x * t.scaledSrcW) / outW,
140
- y: (t.ty + src.y * t.scaledSrcH) / outH,
141
- w: (src.w * t.scaledSrcW) / outW,
142
- h: (src.h * t.scaledSrcH) / outH,
143
- };
144
- }
145
- /**
146
- * Build per-clip `Subject[]` with OUTPUT-space face boxes, accumulated by
147
- * `face_id` across the clip's output frames — the projection loop factored out of
148
- * the render's buildFloorInput so the Director derives IDENTICAL keep-outs. For
149
- * each output frame: section-aware output→trajectory map → resolve segment →
150
- * crop transform → project each source face box to output.
151
- */
152
- export function buildSubjectsOutput(args) {
153
- const { traj, sections, trimStartFrames, durationInFrames, outW, outH, fps } = args;
154
- const series = new Map();
155
- const activeBySubject = new Map();
156
- const order = [];
157
- const emptySeries = () => Array(durationInFrames).fill(null);
158
- for (let f = 0; f < durationInFrames; f++) {
159
- const srcFrame = outputToTrajectoryFrame(sections, trimStartFrames, f, traj.src_fps, fps);
160
- const { seg, inSegIdx } = resolveSegmentAt(traj, srcFrame);
161
- const [cx, cy] = seg.centers[inSegIdx];
162
- const transform = computeCropTransform({
163
- traj: { src_w: traj.src_w, src_h: traj.src_h },
164
- outW,
165
- outH,
166
- cx,
167
- cy,
168
- zoomScale: seg.zoom_scale,
169
- verticalBias: seg.vertical_bias,
170
- lateralBias: seg.lateral_bias,
171
- });
172
- for (const subj of seg.subjects) {
173
- if (!series.has(subj.face_id)) {
174
- series.set(subj.face_id, emptySeries());
175
- activeBySubject.set(subj.face_id, subj.active_windows ?? []);
176
- order.push(subj.face_id);
177
- }
178
- const srcBox = subj.face_box_series[inSegIdx];
179
- if (!srcBox)
180
- continue;
181
- const [x, y, w, h] = srcBox;
182
- series.get(subj.face_id)[f] = sourceRectToOutput({ x, y, w, h }, transform, outW, outH);
183
- }
184
- }
185
- return order.map((id) => ({
186
- id,
187
- faceBoxSeries: series.get(id),
188
- activeWindows: (activeBySubject.get(id) ?? []).map(([startFrame, endFrame]) => ({ startFrame, endFrame })),
189
- }));
190
- }
191
- /**
192
- * The face keep-out rect(s) covering a beat window [startFrame, endFrame) in
193
- * OUTPUT coords — for the structure-first graphics solver. Unions the
194
- * speaker-active face keep-outs across the window into ONE bounding rect (so a
195
- * graphic placed clear of it is clear of the face at EVERY frame of the beat).
196
- * Empty when no face is present in the window (e.g. b-roll).
197
- */
198
- export function faceKeepOutForWindow(subjects, startFrame, endFrame, depthMode = false) {
199
- const series = activeFaceKeepOutSeries(subjects, depthMode);
200
- const inWindow = series
201
- .slice(Math.max(0, startFrame), Math.max(0, endFrame))
202
- .filter((r) => r != null);
203
- return inWindow.length ? [boundingBox(inWindow)] : [];
204
- }
205
- /**
206
- * Per-output-frame OUTPUT-space subject-SILHOUETTE keep-out — the silhouette twin
207
- * of buildSubjectsOutput. For each output frame: section-aware output→trajectory
208
- * map → resolve segment → crop transform (the SAME primitives buildSubjectsOutput
209
- * uses for the FACE box) → project the source silhouette bbox supplied by the
210
- * provider. `null` where the provider has no subject that frame. Unlike the face
211
- * path this applies NO face-relative padding — the silhouette already includes
212
- * hair/head/torso, so the projected box IS the keep-out. Off-crop overflow is
213
- * clamped into the visible output frame [0,1] (the keep-out only concerns what is
214
- * on screen).
215
- */
216
- export function buildSilhouetteKeepOutOutput(args) {
217
- const { traj, silhouette, sections, trimStartFrames, durationInFrames, outW, outH, fps } = args;
218
- const series = new Array(durationInFrames).fill(null);
219
- for (let f = 0; f < durationInFrames; f++) {
220
- const srcFrame = outputToTrajectoryFrame(sections, trimStartFrames, f, traj.src_fps, fps);
221
- const srcBox = silhouette.bboxAtSourceFrame(srcFrame);
222
- if (!srcBox)
223
- continue;
224
- const { seg, inSegIdx } = resolveSegmentAt(traj, srcFrame);
225
- const [cx, cy] = seg.centers[inSegIdx];
226
- const transform = computeCropTransform({
227
- traj: { src_w: traj.src_w, src_h: traj.src_h },
228
- outW,
229
- outH,
230
- cx,
231
- cy,
232
- zoomScale: seg.zoom_scale,
233
- verticalBias: seg.vertical_bias,
234
- lateralBias: seg.lateral_bias,
235
- });
236
- const out = sourceRectToOutput(srcBox, transform, outW, outH);
237
- const x = Math.max(0, Math.min(1, out.x));
238
- const y = Math.max(0, Math.min(1, out.y));
239
- const right = Math.max(0, Math.min(1, out.x + out.w));
240
- const bot = Math.max(0, Math.min(1, out.y + out.h));
241
- series[f] = { x, y, w: Math.max(0, right - x), h: Math.max(0, bot - y) };
242
- }
243
- return series;
244
- }
245
- /**
246
- * Union the projected silhouette keep-out across a beat window [startFrame,
247
- * endFrame) into ONE OUTPUT-space rect (so a graphic clear of it is clear of the
248
- * subject at EVERY frame of the window) — the silhouette twin of
249
- * faceKeepOutForWindow. Empty when no frame in the window carries a silhouette
250
- * (degenerate zero-area rects are dropped).
251
- */
252
- export function silhouetteKeepOutForWindow(series, startFrame, endFrame) {
253
- const inWindow = series
254
- .slice(Math.max(0, startFrame), Math.max(0, endFrame))
255
- .filter((r) => r != null && r.w > 0 && r.h > 0);
256
- return inWindow.length ? [boundingBox(inWindow)] : [];
257
- }
@@ -1,7 +0,0 @@
1
- export * from "./brandKit";
2
- export * from "./cardTokens";
3
- export * from "./composition-floor";
4
- export * from "./safe-zones";
5
- export * from "./behind-placement";
6
- export * from "./occlusion-budget";
7
- export * from "./cropProjection";
@@ -1,104 +0,0 @@
1
- /**
2
- * Occlusion budget for behind-subject text (launch-grade text-behind-subject,
3
- * Phase 2). Pure decisions over matte geometry sidecar frames: estimate how much
4
- * of a text rect the subject covers, then verdict the window — too little bite
5
- * reads as no depth at all; too much swallows the line; a covered TOP half eats
6
- * the letter tops that carry legibility. The caller (a director activity) maps
7
- * timeline→source frames, samples K frames, and degrades the overlay to front
8
- * on any non-pass verdict — the overlay is never dropped.
9
- */
10
- /** Budget thresholds (frame-fraction coverage of the TEXT rect). Calibration
11
- * defaults — Phase-7 fixtures tune them, the deploy-test is the truth.
12
- * `minBite`: below this at EVERY sample the silhouette never bites the line —
13
- * the depth effect is invisible, so don't pay its cost. `maxCoverage`: above
14
- * this at ANY sample the body swallows the line. `maxTopHalf`: text-bearing
15
- * overlays lose legibility when letter TOPS go under — cap the upper half. */
16
- export const BUDGET = { minBite: 0.15, maxCoverage: 0.65, maxTopHalf: 0.35 };
17
- /** Behind hero text extent heuristic (calibration constants; Phase-7 fixtures tune). */
18
- export const BEHIND_TEXT_EXTENT = { heightFrac: 0.18 };
19
- /**
20
- * Verdict a window of coverage samples against the budget. Samples are checked
21
- * in order; the FIRST violating sample decides (deterministic): a text-bearing
22
- * overlay whose top half exceeds `maxTopHalf` → "tops-occluded"; any sample over
23
- * `maxCoverage` → "swallow". If no sample violates but the maximum total never
24
- * reaches `minBite` → "no-depth" (so is an empty window). Else "pass".
25
- * `worstFrame` is the violating sample's frame for the two per-sample verdicts.
26
- */
27
- export function evaluateOcclusionBudget(samples, opts = { textBearing: true }) {
28
- let maxTotal = 0;
29
- for (const s of samples) {
30
- if (opts.textBearing && s.topHalf > BUDGET.maxTopHalf) {
31
- return { verdict: "tops-occluded", worstFrame: s.f };
32
- }
33
- if (s.total > BUDGET.maxCoverage) {
34
- return { verdict: "swallow", worstFrame: s.f };
35
- }
36
- if (s.total > maxTotal)
37
- maxTotal = s.total;
38
- }
39
- if (maxTotal < BUDGET.minBite)
40
- return { verdict: "no-depth" };
41
- return { verdict: "pass" };
42
- }
43
- /**
44
- * Estimate matte coverage of a text rect from the sidecar's marginal profiles.
45
- * APPROXIMATION (documented): overlap(textRect, bbox) area fraction, weighted by the
46
- * mean col-bucket coverage across the intersected x-span (cols[i] = fraction of that
47
- * column covered by the subject). topHalf uses the same estimate restricted to the
48
- * text rect's upper half via the rows marginal weighting. Marginals can't give exact
49
- * 2-D intersection — constants are calibrated against fixtures, and the deploy-test
50
- * is the truth.
51
- *
52
- * All rects source-normalized [0,1]. A null bbox (no subject) → {0, 0}.
53
- */
54
- export function estimateCoverage(textRect, frame) {
55
- if (!frame.bbox)
56
- return { total: 0, topHalf: 0 };
57
- const subject = {
58
- x: frame.bbox[0],
59
- y: frame.bbox[1],
60
- w: frame.bbox[2] - frame.bbox[0],
61
- h: frame.bbox[3] - frame.bbox[1],
62
- };
63
- const total = coverageOfRect(textRect, subject, frame.cols);
64
- const topRect = { x: textRect.x, y: textRect.y, w: textRect.w, h: textRect.h / 2 };
65
- const topHalf = coverageOfRect(topRect, subject, frame.cols, frame.rows);
66
- return { total: clamp01(total), topHalf: clamp01(topHalf) };
67
- }
68
- const clamp01 = (v) => Math.max(0, Math.min(1, v));
69
- function intersect(a, b) {
70
- const x0 = Math.max(a.x, b.x);
71
- const y0 = Math.max(a.y, b.y);
72
- const x1 = Math.min(a.x + a.w, b.x + b.w);
73
- const y1 = Math.min(a.y + a.h, b.y + b.h);
74
- if (x1 <= x0 || y1 <= y0)
75
- return null;
76
- return { x: x0, y: y0, w: x1 - x0, h: y1 - y0 };
77
- }
78
- /** Unweighted mean of the marginal buckets a [lo, hi) frame-normalized span
79
- * overlaps. Bucket i covers [i/N, (i+1)/N). */
80
- function meanBuckets(buckets, lo, hi) {
81
- const n = buckets.length;
82
- if (n === 0 || hi <= lo)
83
- return 0;
84
- const i0 = Math.max(0, Math.min(n - 1, Math.floor(lo * n)));
85
- const i1 = Math.max(0, Math.min(n - 1, Math.ceil(hi * n) - 1));
86
- let sum = 0;
87
- for (let i = i0; i <= i1; i++)
88
- sum += buckets[i];
89
- return sum / (i1 - i0 + 1);
90
- }
91
- /** (overlap area / rect area) × mean col coverage over the overlap's x-span,
92
- * optionally × mean row coverage over its y-span (the topHalf refinement). */
93
- function coverageOfRect(rect, subject, cols, rows) {
94
- const rectArea = rect.w * rect.h;
95
- if (rectArea <= 0)
96
- return 0;
97
- const inter = intersect(rect, subject);
98
- if (!inter)
99
- return 0;
100
- const areaFrac = (inter.w * inter.h) / rectArea;
101
- const meanCol = meanBuckets(cols, inter.x, inter.x + inter.w);
102
- const rowWeight = rows ? meanBuckets(rows, inter.y, inter.y + inter.h) : 1;
103
- return areaFrac * meanCol * rowWeight;
104
- }
@@ -1,99 +0,0 @@
1
- /** Bump on ANY change to a profile rect or the broadcast defaults below. The
2
- * render consumer embeds this into renderCacheKey (spec §15) so a profile edit
3
- * invalidates cached renders transitively, the way BAKE_VERSION already does —
4
- * never a remembered manual bump. */
5
- // v2: platform-name normalization (ig→reels, youtube→shorts) so the suggestion
6
- // vocabulary resolves to a profile instead of silently falling to broadcast.
7
- export const SAFE_ZONE_PROFILE_VERSION = "safezones-v2-2026.06.05";
8
- /** A centered inset of the output rect by `(1 - frac)/2` on every edge. For
9
- * fractions-of-output coordinates this IS the title/action-safe margin and is
10
- * aspect-agnostic (the output rect already carries the aspect). */
11
- function inset(frac) {
12
- const m = (1 - frac) / 2;
13
- return { x: m, y: m, w: frac, h: frac };
14
- }
15
- const TITLE_SAFE_FRAC = 0.9;
16
- const ACTION_SAFE_FRAC = 0.93;
17
- function broadcast() {
18
- return { exclusions: [], titleSafe: inset(TITLE_SAFE_FRAC), actionSafe: inset(ACTION_SAFE_FRAC) };
19
- }
20
- /**
21
- * Platform-UI exclusion rects per (platform, aspect). Fractions of output.
22
- * Extend as a platform changes its chrome. Keyed off the suggestion's
23
- * `platforms[]` + `format` (the destination the agent already chose).
24
- */
25
- const PROFILES = {
26
- tiktok: {
27
- "9:16": [
28
- { x: 0, y: 0.82, w: 1, h: 0.18 }, // bottom username/caption strip
29
- { x: 0.86, y: 0.45, w: 0.14, h: 0.4 }, // right action rail (like/comment/share)
30
- { x: 0, y: 0, w: 1, h: 0.06 }, // top (following/for-you tabs)
31
- ],
32
- },
33
- reels: {
34
- "9:16": [
35
- { x: 0, y: 0.8, w: 1, h: 0.2 }, // bottom caption + audio strip
36
- { x: 0.85, y: 0.42, w: 0.15, h: 0.42 }, // right action rail
37
- ],
38
- },
39
- shorts: {
40
- "9:16": [
41
- { x: 0, y: 0.84, w: 1, h: 0.16 }, // bottom title/channel strip
42
- { x: 0.88, y: 0.4, w: 0.12, h: 0.4 }, // right action rail
43
- ],
44
- },
45
- };
46
- /**
47
- * Map the suggestion's platform vocabulary (what the agent/clip pass emits) to a
48
- * PROFILES key. Suggestions say `ig`/`instagram`/`youtube`; the profile table is
49
- * keyed by the surface-with-chrome (`reels`/`shorts`/`tiktok`). Without this, an
50
- * `ig` clip silently falls through to broadcast and captions sit under the Reels
51
- * UI. Unknown names pass through unchanged (→ broadcast fallback).
52
- */
53
- const PLATFORM_ALIASES = {
54
- ig: "reels",
55
- instagram: "reels",
56
- reels: "reels",
57
- igreels: "reels",
58
- yt: "shorts",
59
- youtube: "shorts",
60
- ytshorts: "shorts",
61
- shorts: "shorts",
62
- tiktok: "tiktok",
63
- tt: "tiktok",
64
- };
65
- /** Normalize a platform name to a PROFILES key (lowercased, aliased). */
66
- export function normalizePlatform(platform) {
67
- const k = (platform ?? "").trim().toLowerCase();
68
- return PLATFORM_ALIASES[k] ?? k;
69
- }
70
- /**
71
- * Resolve the safe-zone profile for a destination. Unknown platform (or an
72
- * aspect a known platform has no profile for) → broadcast title/action-safe only
73
- * (no platform exclusions) so the floor degrades to a correct, conservative
74
- * result rather than throwing.
75
- */
76
- export function lookupSafeZones(platform, aspect) {
77
- const base = broadcast();
78
- const key = normalizePlatform(platform);
79
- // Exact platform when known; otherwise the UNION of every platform's chrome
80
- // for this aspect — so when the destination isn't threaded, captions/overlays
81
- // still clear ANY vertical surface's UI (the robust default) rather than
82
- // silently dropping to broadcast and sitting under the bottom strip. A
83
- // non-social aspect (16:9) has no profiles → union is empty → broadcast.
84
- const exclusions = PROFILES[key]?.[aspect] ?? unionExclusionsForAspect(aspect);
85
- // Copy the rects so callers can't mutate the shared table.
86
- return { ...base, exclusions: exclusions.map((r) => ({ ...r })) };
87
- }
88
- /** Every known platform's exclusion rects for an aspect, concatenated. The
89
- * caller (placeInLegalArea) avoids all of them, so overlap is fine — the net
90
- * effect is the most-constraining chrome across platforms. */
91
- function unionExclusionsForAspect(aspect) {
92
- const all = [];
93
- for (const platform of Object.keys(PROFILES)) {
94
- const ex = PROFILES[platform]?.[aspect];
95
- if (ex)
96
- all.push(...ex);
97
- }
98
- return all;
99
- }
@@ -1,115 +0,0 @@
1
- /**
2
- * Aspect-loss advisory: a source whose shape disagrees with the output frame,
3
- * placed with no authored camera.
4
- *
5
- * A `cover` fill scales the source until it covers the frame and throws the
6
- * overflow away, centred. For a 3840×5760 portrait photo in a 16:9 frame that
7
- * discards ~62% of the image about the middle — reliably decapitating anyone in
8
- * it. In the 2026-08-05 toddler-parks session 15 of 68 imported candidates were
9
- * portrait, every one placed into 16:9 with no crop intent, and nothing said a
10
- * word at any point in the pipeline.
11
- *
12
- * Note this is WORSE for stills than the `fit` field suggests: `fit` is not
13
- * threaded to the image path at all (MainComposition routes `kind:'image'` to
14
- * StillCrop, which has no `fit` prop), so an image is always cropped by the
15
- * derived still trajectory — whose faceless default centre is a hardcoded
16
- * [0.5, 0.5]. Declaring `fit:"contain"` does not avoid this; authoring a
17
- * `reframe` (or a `kenBurns`) does.
18
- *
19
- * ADVISORY only — same `(input) => string[]` contract as `detectNoAudioTrack`.
20
- * Cropping to fill is a legitimate choice; this only says nobody made it.
21
- */
22
- /**
23
- * Fraction of the source that survives a `cover` fill. Purely a function of the
24
- * two aspect ratios: the narrower dimension is fully used, the wider one is
25
- * trimmed to match.
26
- */
27
- export function coverVisibleFraction(source, target) {
28
- const s = source.width / source.height;
29
- const t = target.width / target.height;
30
- if (!Number.isFinite(s) || !Number.isFinite(t) || s <= 0 || t <= 0)
31
- return 1;
32
- return Math.min(s, t) / Math.max(s, t);
33
- }
34
- /**
35
- * Warn below this much of the source surviving. 0.75 = "more than a quarter of
36
- * the picture is being thrown away" — comfortably past a 4:3-in-16:9 letterbox
37
- * nudge (0.84) and well inside portrait-in-landscape (0.38).
38
- */
39
- const VISIBLE_FRACTION_FLOOR = 0.75;
40
- /** How many clips to name before eliding. */
41
- const MAX_NAMED = 6;
42
- /** Collect every `kind:'media'` clip source, with its enclosing clip's id. */
43
- function collectMediaClips(value, nearestId, out) {
44
- if (Array.isArray(value)) {
45
- for (const v of value)
46
- collectMediaClips(v, nearestId, out);
47
- return;
48
- }
49
- if (value === null || typeof value !== "object")
50
- return;
51
- const obj = value;
52
- const id = typeof obj.id === "string" ? obj.id : nearestId;
53
- if (obj.kind === "media" && typeof obj.mediaId === "string") {
54
- const reframe = obj.reframe;
55
- const hasReframe = Array.isArray(reframe?.segments) && reframe.segments.length > 0;
56
- out.push({
57
- mediaId: obj.mediaId,
58
- hasCamera: hasReframe || obj.kenBurns != null,
59
- ...(id !== undefined ? { clipId: id } : {}),
60
- });
61
- return;
62
- }
63
- for (const v of Object.values(obj))
64
- collectMediaClips(v, id, out);
65
- }
66
- /**
67
- * Advisory for media placed into a materially different frame shape with no
68
- * authored camera.
69
- *
70
- * `dimensionsByMediaId` is expected to be partial: image dimensions are
71
- * populated LAZILY (they are not known at upload /complete), so a media with no
72
- * width/height is SKIPPED rather than guessed at — an advisory that fires on
73
- * missing metadata would train agents to ignore the channel.
74
- */
75
- export function detectAspectCropLoss(composition, dimensionsByMediaId, target) {
76
- const placed = [];
77
- collectMediaClips(composition, undefined, placed);
78
- if (placed.length === 0)
79
- return [];
80
- const offenders = [];
81
- const seen = new Set();
82
- for (const clip of placed) {
83
- if (clip.hasCamera)
84
- continue;
85
- const dim = dimensionsByMediaId[clip.mediaId];
86
- if (!dim?.width || !dim?.height)
87
- continue; // dimensions arrive lazily — never guess
88
- const visible = coverVisibleFraction({ width: dim.width, height: dim.height }, target);
89
- if (visible >= VISIBLE_FRACTION_FLOOR)
90
- continue;
91
- const label = clip.clipId ?? clip.mediaId;
92
- if (seen.has(label))
93
- continue;
94
- seen.add(label);
95
- offenders.push({ label, lostPct: Math.round((1 - visible) * 100) });
96
- }
97
- if (offenders.length === 0)
98
- return [];
99
- const worst = offenders.reduce((a, b) => (b.lostPct > a.lostPct ? b : a));
100
- const shown = offenders
101
- .slice(0, MAX_NAMED)
102
- .map((o) => `${o.label} (−${o.lostPct}%)`)
103
- .join(", ");
104
- const elided = offenders.length > MAX_NAMED ? ` (+${offenders.length - MAX_NAMED} more)` : "";
105
- return [
106
- `aspect_crop_loss — ${offenders.length} clip${offenders.length === 1 ? "" : "s"} ` +
107
- `${offenders.length === 1 ? "is" : "are"} shaped very differently from the ` +
108
- `${target.width}×${target.height} output and author no camera, so each is centre-cropped ` +
109
- `to fill — discarding up to ${worst.lostPct}% of the picture with faces and subjects as ` +
110
- `likely to fall outside the crop as inside it: ${shown}${elided}. Author a \`reframe\` ` +
111
- `(focus a face, a point, or all-faces) or a \`kenBurns\` move on these clips, or render a ` +
112
- `format closer to their shape. Note \`fit:"contain"\` does NOT avoid this for stills — ` +
113
- `images are cropped by the still trajectory, which centres when it has no focus.`,
114
- ];
115
- }
@@ -1,62 +0,0 @@
1
- /**
2
- * Reframe coverage invariant — the SINGLE source of truth for
3
- * "a clip's `reframe.segments` MUST tile its PLAYED window: `[0, duration]`
4
- * minus the clip's excluded spans" (clip-relative source seconds; segment 0 =
5
- * the clip's `trim.start`). An excluded span is never walked by the renderer
6
- * (`playableSpans` skips it and rebases across the gap), so it needs NO
7
- * reframe coverage — demanding it would reject the compiler's own canonical
8
- * trim output (trim → excludedRange + segments tiling the remainder).
9
- *
10
- * Pure arithmetic, ZERO runtime imports (structural param types only), so it is
11
- * safe in BOTH the Convex V8 isolate (save-time `validateReframeCoverage`) AND
12
- * the Temporal workflow sandbox (the compose-loop pre-derive gate). One
13
- * definition, no drift — the two chokepoints enforce the exact same rule.
14
- *
15
- * Why it matters: `deriveTrajectory` bakes coverage = the union of the AUTHORED
16
- * segments (it clamps, never extends). If the segments leave a gap (a forgotten
17
- * head lead-in, or a source-absolute-vs-clip-relative time-base mis-map), the
18
- * render walks a played frame no segment covers and `resolveSegmentAt` throws
19
- * `trajectory_coverage_gap` deep in the renderer. Catching the gap on this pure
20
- * path — where BOTH the played window and the segments are known — turns that
21
- * cryptic late crash into an early, actionable, clip-named error.
22
- */
23
- /** Seam-rounding slack: two segments meeting within EPS seconds are contiguous,
24
- * not a gap (matches the fps-conversion tolerance at a segment edge). */
25
- export const REFRAME_COVERAGE_EPS = 1e-3;
26
- /**
27
- * The FIRST uncovered `[start, end]` span (in clip-relative source seconds) where
28
- * `segments` fail to tile the PLAYED window — `[0, duration]` minus `excluded` —
29
- * or `null` when every played instant is covered. Order-independent (sorts a
30
- * copy). A legitimate subjectless lead-in is NOT a gap only when it is handled
31
- * EXPLICITLY: either a frame-center segment covering it, or an excluded span
32
- * removing it from playback (the compiler's trim → excludedRange path). This
33
- * helper never invents either (feedback_never_add_fallbacks).
34
- *
35
- * `excluded` spans are clip-relative like the segments (source-absolute
36
- * `excludedRanges` convert via `- trim.start` at the call site). An excluded
37
- * instant counts as covered because the renderer never resolves a trajectory
38
- * there (`playableSpans` drops it), so the sweep unions segments + exclusions
39
- * and any remaining hole is exactly a played-and-uncovered span — the set that
40
- * crashes `resolveSegmentAt`.
41
- */
42
- export function firstReframeCoverageGap(segments, duration, eps = REFRAME_COVERAGE_EPS, excluded = []) {
43
- if (duration <= eps)
44
- return null; // a zero/degenerate window has nothing to tile
45
- const covered = [...segments, ...excluded].sort((a, b) => a.startSec - b.startSec);
46
- let cursor = 0;
47
- for (const span of covered) {
48
- // Spans at/after the window end are outside the coverage domain — a
49
- // malformed exclusion like [duration+0.5, …] must not manufacture a
50
- // phantom gap [duration, span.start] on a fully-tiled window (the save
51
- // guard separately rejects out-of-trim exclusions; THIS helper only
52
- // answers coverage). Sorted input → nothing later can matter either.
53
- if (span.startSec >= duration - eps)
54
- break;
55
- if (span.startSec > cursor + eps)
56
- return [cursor, span.startSec]; // head / interior gap
57
- cursor = Math.max(cursor, span.endSec);
58
- }
59
- if (cursor < duration - eps)
60
- return [cursor, duration]; // tail gap
61
- return null;
62
- }