@cueframe/kernel 0.0.1 → 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.
- package/LICENSE +661 -0
- package/dist/_members/account-model/testing/conversationStoreContract.d.ts +1 -1
- package/dist/_members/authoring/providers/resourceApi.d.ts +1 -1
- package/dist/_members/authoring/transpileComponent.d.ts +1 -1
- package/dist/_members/cloud-import/CloudImportService.d.ts +35 -0
- package/dist/_members/cloud-import/ImportProvider.d.ts +73 -0
- package/dist/_members/cloud-import/MediaItemPreprocessor.d.ts +27 -0
- package/dist/_members/cloud-import/cloudConfig.d.ts +23 -0
- package/dist/_members/cloud-import/index.d.ts +9 -0
- package/dist/_members/cloud-import/multipartUpload.d.ts +12 -0
- package/dist/_members/composition/ops/compositionOps.d.ts +2 -1
- package/dist/_members/composition/ops/types.d.ts +1 -1
- package/dist/_members/composition/projection/behind-readiness.d.ts +127 -0
- package/dist/_members/composition/projection/index.d.ts +2 -0
- package/dist/_members/composition/projection/reframe-readiness.d.ts +156 -0
- package/dist/_members/composition/timeline/placement.d.ts +1 -1
- package/dist/_members/composition/validators/composition.d.ts +43 -26
- package/dist/_members/composition/validators/render.d.ts +32 -0
- package/dist/_members/composition-ops/index.d.ts +1 -1
- package/dist/_members/composition-ops/opRecorder.d.ts +1 -1
- package/dist/_members/convex-api/api.d.ts +5 -0
- package/dist/_members/convex-api/dataModel.d.ts +6 -0
- package/dist/_members/core/render/compositionRender.d.ts +17 -1
- package/dist/_members/core/render/exportSettings.d.ts +1 -1
- package/dist/_members/core/render/types.d.ts +31 -0
- package/dist/_members/mcp/curation.d.ts +1 -1
- package/dist/_members/plane/conformance.d.ts +1 -1
- package/dist/_members/render-harness/localRender.d.ts +1 -1
- package/dist/animate.js +828 -79187
- package/dist/authoring/build-tools.js +8 -11
- package/dist/authoring/context.js +5 -5
- package/dist/authoring/models.js +1 -2
- package/dist/authoring/prompts.js +1 -1
- package/dist/authoring/tools.js +7 -7
- package/dist/authoring/transpileComponent.js +3 -2220
- package/dist/authoring.js +30 -30
- package/dist/brand-derivation.js +1 -1
- package/dist/chunk-6IU2UQI5.js +107 -0
- package/dist/{chunk-5I7VDCAC.js → chunk-7FO3ZJ43.js} +4 -1
- package/dist/{chunk-N67PDTKQ.js → chunk-ABL557OT.js} +1 -1
- package/dist/{chunk-MC5DLSEV.js → chunk-AP6ZIVAV.js} +15 -15
- package/dist/{chunk-QLAQHR3L.js → chunk-AQBREB5O.js} +1 -1
- package/dist/{chunk-DSNG6WLU.js → chunk-AYVJXDLB.js} +1 -4
- package/dist/{chunk-6CMVBTTP.js → chunk-DK2ODBNT.js} +19 -9
- package/dist/chunk-DSMLHYJ4.js +82 -0
- package/dist/{chunk-BRKJKB33.js → chunk-FYZVH3MC.js} +1 -1
- package/dist/{chunk-MVEE6HEC.js → chunk-GA23TRNR.js} +5 -7
- package/dist/chunk-HCCBDJLW.js +68 -0
- package/dist/{chunk-JRQVPFLF.js → chunk-HY3RIEZW.js} +1 -1
- package/dist/{chunk-OIRUO5P7.js → chunk-JJ6XD7NG.js} +152 -2
- package/dist/{_members/primitives/chunk-IDAL6G3Y.js → chunk-JQMPHKLU.js} +19 -27
- package/dist/{chunk-G3PBH53P.js → chunk-MBCXCJOE.js} +1 -1
- package/dist/{chunk-UEI3NLNK.js → chunk-MHOQTPOB.js} +1 -4
- package/dist/{chunk-37NJ27UU.js → chunk-OCFDUCF4.js} +3 -0
- package/dist/{chunk-WZTTZHNR.js → chunk-OLFOPQCA.js} +12 -9
- package/dist/{chunk-P43IE4WB.js → chunk-P727GZVO.js} +2 -4
- package/dist/{chunk-52AHXNKM.js → chunk-PDYO3DOJ.js} +5 -5
- package/dist/{chunk-S3P5BFFL.js → chunk-PMY24FUD.js} +2 -4
- package/dist/{chunk-ATAF24QG.js → chunk-PODIYN2K.js} +10 -3
- package/dist/chunk-RF7U3SCL.js +606 -0
- package/dist/{chunk-JD77Y2WM.js → chunk-SW336CJP.js} +1 -4
- package/dist/{chunk-TULRCY6U.js → chunk-TOJEXFXL.js} +1 -1
- package/dist/{chunk-ELLSET2N.js → chunk-UHGSZZDI.js} +3 -6
- package/dist/{chunk-M3I5LMAB.js → chunk-UY4SWJVE.js} +1 -1
- package/dist/{chunk-6QJ3V3VS.js → chunk-YX2GSJK7.js} +1 -1
- package/dist/chunk-ZT7MHRQU.js +104 -0
- package/dist/{chunk-NV4I6GJV.js → chunk-ZWMV6DD2.js} +27 -4
- package/dist/cloud-import/multipart.d.ts +1 -0
- package/dist/cloud-import/multipart.js +8 -0
- package/dist/cloud-import.d.ts +1 -0
- package/dist/cloud-import.js +234 -0
- package/dist/compose/renderer.js +19 -22
- package/dist/compose.js +19 -22
- package/dist/composition/graphics-plan.js +3 -3
- package/dist/composition/ops.js +4 -4
- package/dist/composition/primitive-catalog.js +1 -1
- package/dist/composition/projection.js +21 -5
- package/dist/composition/validators.js +6 -4
- package/dist/composition-ops.js +15 -13
- package/dist/composition.js +26 -8
- package/dist/{context-CEAKQ5T7.js → context-YWUZDG5X.js} +5 -5
- package/dist/convex-api/dataModel.d.ts +1 -0
- package/dist/convex-api/dataModel.js +0 -0
- package/dist/convex-api.d.ts +1 -0
- package/dist/convex-api.js +8 -0
- package/dist/core/render.js +3 -3
- package/dist/core/select.js +2 -2
- package/dist/core.js +3 -3
- package/dist/errors.js +1 -1
- package/dist/mcp/adapter.js +2 -5
- package/dist/mcp/server.js +1 -2
- package/dist/mcp.js +2 -95
- package/dist/media-model/media-kind.js +9 -98
- package/dist/media-model/testing.js +1071 -718
- package/dist/nle-export/server.js +328 -130
- package/dist/nle-export/xml.js +5 -22799
- package/dist/nle-export.js +20 -22
- package/dist/primitives/backgrounds.js +2 -3
- package/dist/primitives/captions.js +4 -243
- package/dist/primitives/effects.js +2 -3
- package/dist/primitives/hero-text.js +2 -3
- package/dist/primitives/layouts.js +2 -3
- package/dist/primitives/lib/index.js +8 -10
- package/dist/primitives/lib/preview.js +1 -2
- package/dist/primitives/lib/schema.js +1 -2
- package/dist/primitives/lib/text/fitText.js +1 -2
- package/dist/primitives/lib.js +8 -10
- package/dist/primitives/scenes.js +1 -2
- package/dist/primitives/text.js +2 -3
- package/dist/primitives/ui-blocks.js +4 -5
- package/dist/primitives.js +19 -21
- package/package.json +125 -16
- package/dist/TextureLoader-UQOFUSAP.js +0 -422
- package/dist/VideoTexture-AQWSPIJG.js +0 -62
- package/dist/_members/account-model/index.js +0 -4
- package/dist/_members/account-model/testing/conversationStoreContract.js +0 -168
- package/dist/_members/account-model/testing/index.js +0 -7
- package/dist/_members/account-model/testing/restorePointStoreContract.js +0 -69
- package/dist/_members/account-model/types/index.js +0 -1
- package/dist/_members/account-model/validators/contextFile.js +0 -18
- package/dist/_members/account-model/validators/conversation.js +0 -95
- package/dist/_members/account-model/validators/dashboardInsight.js +0 -16
- package/dist/_members/account-model/validators/index.js +0 -7
- package/dist/_members/account-model/validators/sessionToken.js +0 -49
- package/dist/_members/account-model/validators/uploadToken.js +0 -16
- package/dist/_members/account-model/validators/userSettings.js +0 -12
- package/dist/_members/account-model/validators/workingComposition.js +0 -20
- package/dist/_members/brand-derivation/constants.js +0 -20
- package/dist/_members/brand-derivation/contrastSafe.js +0 -114
- package/dist/_members/brand-derivation/index.js +0 -1
- package/dist/_members/composition/audio/audioMix.js +0 -61
- package/dist/_members/composition/audio/index.js +0 -5
- package/dist/_members/composition/audio/mixStaging.js +0 -195
- package/dist/_members/composition/audio/musicPack.generated.js +0 -136
- package/dist/_members/composition/audio/musicPack.js +0 -36
- package/dist/_members/composition/audio/pack.generated.js +0 -603
- package/dist/_members/composition/audio/pack.js +0 -48
- package/dist/_members/composition/audio/palette.js +0 -134
- package/dist/_members/composition/autozoom/index.js +0 -83
- package/dist/_members/composition/brand-kit.js +0 -45
- package/dist/_members/composition/brief/contract.js +0 -209
- package/dist/_members/composition/color-grade.js +0 -80
- package/dist/_members/composition/depth.js +0 -8
- package/dist/_members/composition/fixtures/index.js +0 -143
- package/dist/_members/composition/fixtures/vaayaErrored.d.ts +0 -25
- package/dist/_members/composition/fixtures/vaayaErrored.js +0 -203
- package/dist/_members/composition/fonts.js +0 -162
- package/dist/_members/composition/graphics-plan/compile.js +0 -221
- package/dist/_members/composition/graphics-plan/index.js +0 -10
- package/dist/_members/composition/graphics-plan/instantiateMotif.js +0 -44
- package/dist/_members/composition/graphics-plan/motion.js +0 -66
- package/dist/_members/composition/graphics-plan/schemas.js +0 -261
- package/dist/_members/composition/graphics-plan/solve.js +0 -145
- package/dist/_members/composition/index.js +0 -5
- package/dist/_members/composition/invariants/clipPlacement.js +0 -69
- package/dist/_members/composition/invariants/composition.js +0 -28
- package/dist/_members/composition/invariants/errors.js +0 -10
- package/dist/_members/composition/invariants/etag.js +0 -38
- package/dist/_members/composition/invariants/ids.js +0 -33
- package/dist/_members/composition/invariants/index.js +0 -9
- package/dist/_members/composition/invariants/keyframes.js +0 -45
- package/dist/_members/composition/invariants/markers.js +0 -29
- package/dist/_members/composition/invariants/time.js +0 -20
- package/dist/_members/composition/invariants/tracks.js +0 -304
- package/dist/_members/composition/ops/compositionOps.js +0 -1056
- package/dist/_members/composition/ops/headlessStore.js +0 -94
- package/dist/_members/composition/ops/index.js +0 -4
- package/dist/_members/composition/ops/selectors.js +0 -118
- package/dist/_members/composition/ops/timeline-word.js +0 -1
- package/dist/_members/composition/ops/transcript.js +0 -77
- package/dist/_members/composition/ops/types.js +0 -16
- package/dist/_members/composition/primitive-catalog/catalogQuery.js +0 -150
- package/dist/_members/composition/primitive-catalog/disabled.js +0 -32
- package/dist/_members/composition/primitive-catalog/generated/meta.js +0 -15161
- package/dist/_members/composition/primitive-catalog/index.js +0 -46
- package/dist/_members/composition/primitive-catalog/paramValidation.js +0 -231
- package/dist/_members/composition/primitive-catalog/projection.js +0 -164
- package/dist/_members/composition/primitive-catalog/types.js +0 -14
- package/dist/_members/composition/projection/behind-placement.js +0 -62
- package/dist/_members/composition/projection/brandKit.js +0 -482
- package/dist/_members/composition/projection/cardTokens.js +0 -209
- package/dist/_members/composition/projection/composition-floor.js +0 -582
- package/dist/_members/composition/projection/cropProjection.js +0 -257
- package/dist/_members/composition/projection/index.js +0 -7
- package/dist/_members/composition/projection/occlusion-budget.js +0 -104
- package/dist/_members/composition/projection/safe-zones.js +0 -99
- package/dist/_members/composition/reframe/aspectLoss.js +0 -115
- package/dist/_members/composition/reframe/coverage.js +0 -62
- package/dist/_members/composition/reframe/derive.js +0 -73
- package/dist/_members/composition/reframe/index.js +0 -109
- package/dist/_members/composition/reframe/kenBurns.js +0 -64
- package/dist/_members/composition/reframe/shotScale.js +0 -176
- package/dist/_members/composition/reframe/trajectory.js +0 -124
- package/dist/_members/composition/timeline/compound.js +0 -134
- package/dist/_members/composition/timeline/index.js +0 -9
- package/dist/_members/composition/timeline/intent.js +0 -228
- package/dist/_members/composition/timeline/keyframes.js +0 -121
- package/dist/_members/composition/timeline/link.js +0 -59
- package/dist/_members/composition/timeline/occupancy.js +0 -36
- package/dist/_members/composition/timeline/placement.js +0 -74
- package/dist/_members/composition/timeline/plan.js +0 -31
- package/dist/_members/composition/timeline/resolve.js +0 -170
- package/dist/_members/composition/timeline/trims.js +0 -278
- package/dist/_members/composition/types/index.js +0 -1
- package/dist/_members/composition/validators/brandKit.js +0 -295
- package/dist/_members/composition/validators/composePlan.js +0 -113
- package/dist/_members/composition/validators/composition.js +0 -703
- package/dist/_members/composition/validators/font.js +0 -34
- package/dist/_members/composition/validators/graphicKinds.js +0 -30
- package/dist/_members/composition/validators/index.js +0 -9
- package/dist/_members/composition/validators/project.js +0 -29
- package/dist/_members/composition/validators/registry.js +0 -41
- package/dist/_members/composition/validators/render.js +0 -139
- package/dist/_members/composition/validators/session.js +0 -37
- package/dist/_members/composition/validators/webhook.js +0 -72
- package/dist/_members/composition-ops/alphaLayers.js +0 -141
- package/dist/_members/composition-ops/index.js +0 -637
- package/dist/_members/composition-ops/materializeGrid.js +0 -99
- package/dist/_members/composition-ops/opRecorder.js +0 -196
- package/dist/_members/composition-ops/recordingStore.js +0 -14
- package/dist/_members/composition-ops/replaceRegion.js +0 -102
- package/dist/_members/composition-ops/testFixtures.js +0 -19
- package/dist/_members/core/index.js +0 -5
- package/dist/_members/core/render/bookends.js +0 -53
- package/dist/_members/core/render/captions.js +0 -127
- package/dist/_members/core/render/compositionRender.js +0 -1249
- package/dist/_members/core/render/deriveTrajectory.js +0 -889
- package/dist/_members/core/render/emphasis.js +0 -16
- package/dist/_members/core/render/eval/cropBox.js +0 -139
- package/dist/_members/core/render/eval/inclusion.js +0 -96
- package/dist/_members/core/render/eval/index.js +0 -146
- package/dist/_members/core/render/eval/metrics.js +0 -94
- package/dist/_members/core/render/exportSettings.js +0 -65
- package/dist/_members/core/render/index.js +0 -20
- package/dist/_members/core/render/mapFaceToPerson.js +0 -73
- package/dist/_members/core/render/types.js +0 -8
- package/dist/_members/core/render/vcam/cameraPath.js +0 -248
- package/dist/_members/core/render/vcam/constants.js +0 -115
- package/dist/_members/core/render/vcam/errorCodes.js +0 -39
- package/dist/_members/core/render/vcam/framing.js +0 -136
- package/dist/_members/core/render/vcam/requiredRegion.js +0 -137
- package/dist/_members/core/render/vcam/shots.js +0 -53
- package/dist/_members/core/render/vcam/subjectSet.js +0 -388
- package/dist/_members/core/select/errorCodes.js +0 -38
- package/dist/_members/core/select/index.js +0 -26
- package/dist/_members/core/select/model.js +0 -18
- package/dist/_members/core/select/select.js +0 -244
- package/dist/_members/core/select/stabilize.js +0 -242
- package/dist/_members/core/types.js +0 -7
- package/dist/_members/errors/index.js +0 -1
- package/dist/_members/errors/registry.js +0 -560
- package/dist/_members/foundation/codes/index.js +0 -31
- package/dist/_members/foundation/index.js +0 -2
- package/dist/_members/foundation/primitives/index.js +0 -5
- package/dist/_members/mcp/adapter.js +0 -771
- package/dist/_members/mcp/burnedNames.js +0 -73
- package/dist/_members/mcp/core.js +0 -390
- package/dist/_members/mcp/curation.js +0 -792
- package/dist/_members/mcp/executor.js +0 -142
- package/dist/_members/mcp/format.js +0 -9
- package/dist/_members/mcp/generated/catalogPreviews.js +0 -95
- package/dist/_members/mcp/generated/harness.js +0 -81
- package/dist/_members/mcp/generated/operations.js +0 -131
- package/dist/_members/mcp/index.js +0 -50
- package/dist/_members/mcp/internalLoopTools.js +0 -109
- package/dist/_members/mcp/prompts.js +0 -45
- package/dist/_members/mcp/resources.js +0 -166
- package/dist/_members/mcp/server.js +0 -340
- package/dist/_members/mcp/wait.js +0 -378
- package/dist/_members/mcp/x402Meta.js +0 -66
- package/dist/_members/media-model/api.js +0 -175
- package/dist/_members/media-model/index.js +0 -1
- package/dist/_members/media-model/media-kind.js +0 -116
- package/dist/_members/media-model/testing/index.js +0 -1
- package/dist/_members/media-model/testing/mediaStoreContract.js +0 -82
- package/dist/_members/media-model/transcriptSearch.js +0 -70
- package/dist/_members/media-model/transcriptSearchCases.json +0 -79
- package/dist/_members/nle-export/compact-timeline.js +0 -73
- package/dist/_members/nle-export/compact-timeline.js.map +0 -1
- package/dist/_members/nle-export/composition-to-input.js +0 -147
- package/dist/_members/nle-export/composition-to-input.js.map +0 -1
- package/dist/_members/nle-export/fcpxml.js +0 -159
- package/dist/_members/nle-export/fcpxml.js.map +0 -1
- package/dist/_members/nle-export/index.js +0 -12
- package/dist/_members/nle-export/index.js.map +0 -1
- package/dist/_members/nle-export/premiere.js +0 -161
- package/dist/_members/nle-export/premiere.js.map +0 -1
- package/dist/_members/nle-export/server/index.js +0 -2
- package/dist/_members/nle-export/server/index.js.map +0 -1
- package/dist/_members/nle-export/server/pack-zip.js +0 -38
- package/dist/_members/nle-export/server/pack-zip.js.map +0 -1
- package/dist/_members/nle-export/srt.js +0 -50
- package/dist/_members/nle-export/srt.js.map +0 -1
- package/dist/_members/nle-export/types.js +0 -9
- package/dist/_members/nle-export/types.js.map +0 -1
- package/dist/_members/nle-export/xml/index.js +0 -11
- package/dist/_members/nle-export/xml/index.js.map +0 -1
- package/dist/_members/nle-export/xml-utils.js +0 -48
- package/dist/_members/nle-export/xml-utils.js.map +0 -1
- package/dist/_members/perception/activeSpeaker.js +0 -103
- package/dist/_members/perception/audioQuality.js +0 -76
- package/dist/_members/perception/energyBeat.js +0 -99
- package/dist/_members/perception/identityMatch.js +0 -91
- package/dist/_members/perception/index.js +0 -48
- package/dist/_members/perception/visualQuality.js +0 -95
- package/dist/_members/plane/conformance.js +0 -90
- package/dist/_members/plane/contract.js +0 -49
- package/dist/_members/plane/index.js +0 -16
- package/dist/_members/primitives/backgrounds/index.js +0 -32
- package/dist/_members/primitives/backgrounds/index.js.map +0 -1
- package/dist/_members/primitives/captions/index.js +0 -398
- package/dist/_members/primitives/captions/index.js.map +0 -1
- package/dist/_members/primitives/chunk-2LVE4UIT.js +0 -139
- package/dist/_members/primitives/chunk-2LVE4UIT.js.map +0 -1
- package/dist/_members/primitives/chunk-3IQUH6KK.js +0 -20
- package/dist/_members/primitives/chunk-3IQUH6KK.js.map +0 -1
- package/dist/_members/primitives/chunk-3OMURV6Q.js +0 -112
- package/dist/_members/primitives/chunk-3OMURV6Q.js.map +0 -1
- package/dist/_members/primitives/chunk-4IS6TMEG.js +0 -21
- package/dist/_members/primitives/chunk-4IS6TMEG.js.map +0 -1
- package/dist/_members/primitives/chunk-5MWGAEGQ.js +0 -1644
- package/dist/_members/primitives/chunk-5MWGAEGQ.js.map +0 -1
- package/dist/_members/primitives/chunk-7RRPFPQK.js +0 -15
- package/dist/_members/primitives/chunk-7RRPFPQK.js.map +0 -1
- package/dist/_members/primitives/chunk-DH5TRZK2.js +0 -125
- package/dist/_members/primitives/chunk-DH5TRZK2.js.map +0 -1
- package/dist/_members/primitives/chunk-E3KNUSFG.js +0 -2337
- package/dist/_members/primitives/chunk-E3KNUSFG.js.map +0 -1
- package/dist/_members/primitives/chunk-G2B3G4HK.js +0 -47
- package/dist/_members/primitives/chunk-G2B3G4HK.js.map +0 -1
- package/dist/_members/primitives/chunk-HFPFGZXT.js +0 -1494
- package/dist/_members/primitives/chunk-HFPFGZXT.js.map +0 -1
- package/dist/_members/primitives/chunk-HIWVFZVH.js +0 -19
- package/dist/_members/primitives/chunk-HIWVFZVH.js.map +0 -1
- package/dist/_members/primitives/chunk-IDAL6G3Y.js.map +0 -1
- package/dist/_members/primitives/chunk-KNC6JP5F.js +0 -34
- package/dist/_members/primitives/chunk-KNC6JP5F.js.map +0 -1
- package/dist/_members/primitives/chunk-KYRDVZST.js +0 -459
- package/dist/_members/primitives/chunk-KYRDVZST.js.map +0 -1
- package/dist/_members/primitives/chunk-LWLHS2NS.js +0 -3410
- package/dist/_members/primitives/chunk-LWLHS2NS.js.map +0 -1
- package/dist/_members/primitives/chunk-QAQ3P7DR.js +0 -8855
- package/dist/_members/primitives/chunk-QAQ3P7DR.js.map +0 -1
- package/dist/_members/primitives/chunk-ROV2ODWC.js +0 -81
- package/dist/_members/primitives/chunk-ROV2ODWC.js.map +0 -1
- package/dist/_members/primitives/chunk-TCRC2FH3.js +0 -183
- package/dist/_members/primitives/chunk-TCRC2FH3.js.map +0 -1
- package/dist/_members/primitives/chunk-US4YEDAA.js +0 -96
- package/dist/_members/primitives/chunk-US4YEDAA.js.map +0 -1
- package/dist/_members/primitives/chunk-UVKRO5ER.js +0 -13
- package/dist/_members/primitives/chunk-UVKRO5ER.js.map +0 -1
- package/dist/_members/primitives/chunk-W4EIIF2I.js +0 -10
- package/dist/_members/primitives/chunk-W4EIIF2I.js.map +0 -1
- package/dist/_members/primitives/chunk-WPGKIPCO.js +0 -3563
- package/dist/_members/primitives/chunk-WPGKIPCO.js.map +0 -1
- package/dist/_members/primitives/chunk-WZFLEGMD.js +0 -1435
- package/dist/_members/primitives/chunk-WZFLEGMD.js.map +0 -1
- package/dist/_members/primitives/chunk-XHU3WBEI.js +0 -33
- package/dist/_members/primitives/chunk-XHU3WBEI.js.map +0 -1
- package/dist/_members/primitives/chunk-YN7WTZZ7.js +0 -46
- package/dist/_members/primitives/chunk-YN7WTZZ7.js.map +0 -1
- package/dist/_members/primitives/effects/index.js +0 -30
- package/dist/_members/primitives/effects/index.js.map +0 -1
- package/dist/_members/primitives/hero-text/index.js +0 -14
- package/dist/_members/primitives/hero-text/index.js.map +0 -1
- package/dist/_members/primitives/index.js +0 -64
- package/dist/_members/primitives/index.js.map +0 -1
- package/dist/_members/primitives/layouts/index.js +0 -24
- package/dist/_members/primitives/layouts/index.js.map +0 -1
- package/dist/_members/primitives/lib/easings.js +0 -26
- package/dist/_members/primitives/lib/easings.js.map +0 -1
- package/dist/_members/primitives/lib/index.js +0 -74
- package/dist/_members/primitives/lib/index.js.map +0 -1
- package/dist/_members/primitives/lib/palette.js +0 -72
- package/dist/_members/primitives/lib/palette.js.map +0 -1
- package/dist/_members/primitives/lib/preview.js +0 -8
- package/dist/_members/primitives/lib/preview.js.map +0 -1
- package/dist/_members/primitives/lib/schema.js +0 -12
- package/dist/_members/primitives/lib/schema.js.map +0 -1
- package/dist/_members/primitives/lib/seeded-random.js +0 -14
- package/dist/_members/primitives/lib/seeded-random.js.map +0 -1
- package/dist/_members/primitives/lib/text/contrast.js +0 -12
- package/dist/_members/primitives/lib/text/contrast.js.map +0 -1
- package/dist/_members/primitives/lib/text/fill.js +0 -8
- package/dist/_members/primitives/lib/text/fill.js.map +0 -1
- package/dist/_members/primitives/lib/text/fitText.js +0 -10
- package/dist/_members/primitives/lib/text/fitText.js.map +0 -1
- package/dist/_members/primitives/lib/text/marker.js +0 -8
- package/dist/_members/primitives/lib/text/marker.js.map +0 -1
- package/dist/_members/primitives/lib/text/motion.js +0 -16
- package/dist/_members/primitives/lib/text/motion.js.map +0 -1
- package/dist/_members/primitives/lib/text/recolor.js +0 -8
- package/dist/_members/primitives/lib/text/recolor.js.map +0 -1
- package/dist/_members/primitives/lib/text/spec.js +0 -1
- package/dist/_members/primitives/lib/text/spec.js.map +0 -1
- package/dist/_members/primitives/lib/text/stage.js +0 -8
- package/dist/_members/primitives/lib/text/stage.js.map +0 -1
- package/dist/_members/primitives/lib/text/typeface.js +0 -8
- package/dist/_members/primitives/lib/text/typeface.js.map +0 -1
- package/dist/_members/primitives/lib/tokens.js +0 -24
- package/dist/_members/primitives/lib/tokens.js.map +0 -1
- package/dist/_members/primitives/lib/types.js +0 -1
- package/dist/_members/primitives/lib/types.js.map +0 -1
- package/dist/_members/primitives/params-required.json +0 -153
- package/dist/_members/primitives/scenes/index.js +0 -25
- package/dist/_members/primitives/scenes/index.js.map +0 -1
- package/dist/_members/primitives/subject-foreground/index.js +0 -30
- package/dist/_members/primitives/subject-foreground/index.js.map +0 -1
- package/dist/_members/primitives/text/index.js +0 -57
- package/dist/_members/primitives/text/index.js.map +0 -1
- package/dist/_members/primitives/transitions/index.js +0 -67
- package/dist/_members/primitives/transitions/index.js.map +0 -1
- package/dist/_members/primitives/ui-blocks/index.js +0 -76
- package/dist/_members/primitives/ui-blocks/index.js.map +0 -1
- package/dist/_members/primitives/version-map.json +0 -105
- package/dist/_members/primitives/workspace.js +0 -60
- package/dist/_members/primitives/workspace.js.map +0 -1
- package/dist/chunk-7GISRVON.js +0 -14176
- package/dist/chunk-DIBOJJMU.js +0 -16838
- package/dist/chunk-EAUSEGB7.js +0 -420
- package/dist/chunk-FUWJOVVK.js +0 -3633
- package/dist/chunk-G75E7YA4.js +0 -11883
- package/dist/chunk-JCZQT7K3.js +0 -3266
- package/dist/chunk-KF5ETMKB.js +0 -544
- package/dist/chunk-NDKERSXY.js +0 -1296
- package/dist/chunk-V43Y7IE4.js +0 -3621
- package/dist/chunk-VIVQHIGZ.js +0 -4319
- package/dist/chunk-YA3OR2KK.js +0 -249
- package/dist/hls-HD4C5G6W.js +0 -33000
- package/dist/token-RGFIT24D.js +0 -69
- package/dist/token-util-GPLSGYVO.js +0 -5
- package/dist/vision_bundle-5Y376MAR.js +0 -4084
|
@@ -1,637 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @cueframe/composition-ops — the composition OPERATION model (single home).
|
|
3
|
-
*
|
|
4
|
-
* One package owns "what an op is": the serializable `CompositionOp` discriminated
|
|
5
|
-
* union, `applyOp(composition, op)` (pure — applies an op to a wire Composition),
|
|
6
|
-
* and `invertOp` (the inverse, for the op-log / multiplayer undo).
|
|
7
|
-
*
|
|
8
|
-
* Layering (deliberate, not fragmentation):
|
|
9
|
-
* - This package = the op vocabulary + pure apply/inverse. OSS; the agent and the
|
|
10
|
-
* editor both emit + optimistically-apply ops through it.
|
|
11
|
-
* - apply logic is REUSED from `@cueframe/core` (the headless store), not forked.
|
|
12
|
-
* - The server-authoritative persistence (transactional scoped row writes + the
|
|
13
|
-
* op-log) is ONE generic Convex mutation in `services/convex/composition/applyOp.ts`
|
|
14
|
-
* — a thin consumer of this package. Convex functions must live in the Convex app;
|
|
15
|
-
* that is the only piece outside this package, and it does not grow per-op.
|
|
16
|
-
*/
|
|
17
|
-
import { z } from 'zod';
|
|
18
|
-
import { TimelineClip, Marker, Track, Format, ReframeSegment, CaptionSegment, CaptionStyle, PerClipEffect, } from '@cueframe/composition/validators';
|
|
19
|
-
import { createHeadlessStore, findClipById, findTrackContainingClipId, findMarkerById, } from '@cueframe/composition/ops';
|
|
20
|
-
/**
|
|
21
|
-
* The timeline family of a media item, derived from its `mimeType`.
|
|
22
|
-
*
|
|
23
|
-
* `mimeType` is the ONLY trustworthy statement of what a media item is: it is
|
|
24
|
-
* `v.string()` (required) on the schema and byte-detected at ingest — populated
|
|
25
|
-
* on 305/305 prod rows. `mediaItems.kind` is a duplicate of the same fact that
|
|
26
|
-
* nobody maintains (null on every video uploaded in 2026-08) and that is
|
|
27
|
-
* overloaded with provenance values (`source`, `stock`, `gif`, `asset`) which
|
|
28
|
-
* are not families at all. Measured 2026-08-17: where `kind` was set it agreed
|
|
29
|
-
* with the mimeType prefix in 232/232 rows. So there is one fact here, and this
|
|
30
|
-
* is where it is read.
|
|
31
|
-
*
|
|
32
|
-
* THROWS on anything it cannot name. A media item whose type we can't determine
|
|
33
|
-
* must not be silently treated as video — that is precisely how an image reached
|
|
34
|
-
* the video frame-extractor and hung the render for 30s on `delayRender`.
|
|
35
|
-
*/
|
|
36
|
-
export function mediaFamily(mimeType) {
|
|
37
|
-
const top = mimeType.split('/')[0]?.trim().toLowerCase();
|
|
38
|
-
if (top === 'video')
|
|
39
|
-
return 'video';
|
|
40
|
-
if (top === 'audio')
|
|
41
|
-
return 'audio';
|
|
42
|
-
if (top === 'image')
|
|
43
|
-
return 'image';
|
|
44
|
-
throw new Error(`mediaFamily: cannot derive a timeline family from mimeType ${JSON.stringify(mimeType)} — ` +
|
|
45
|
-
`expected a video/*, audio/* or image/* type.`);
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Map an unambiguous `source.kind` to its track family. `media` is the ONLY
|
|
49
|
-
* ambiguous source — a media clip can be video | audio | image, so it returns
|
|
50
|
-
* `undefined` (the family must come from `clip.kind` or a target track). The
|
|
51
|
-
* non-media sources each pin exactly one family.
|
|
52
|
-
*/
|
|
53
|
-
function deriveFromSource(sourceKind) {
|
|
54
|
-
switch (sourceKind) {
|
|
55
|
-
case 'overlay':
|
|
56
|
-
return 'overlay';
|
|
57
|
-
case 'effect':
|
|
58
|
-
return 'effect';
|
|
59
|
-
case 'component':
|
|
60
|
-
return 'overlay';
|
|
61
|
-
case 'alpha-layer':
|
|
62
|
-
return 'overlay';
|
|
63
|
-
case 'card':
|
|
64
|
-
return 'overlay';
|
|
65
|
-
case 'media':
|
|
66
|
-
return undefined; // ambiguous — caller must disambiguate
|
|
67
|
-
case 'composition':
|
|
68
|
-
// A compound clip is video-family by definition: it flattens to the
|
|
69
|
-
// child's tracks at projection, and it PLACES on a video lane
|
|
70
|
-
// (isSourceKindCompatible pins video ↔ composition).
|
|
71
|
-
return 'video';
|
|
72
|
-
default: {
|
|
73
|
-
const _exhaustive = sourceKind;
|
|
74
|
-
throw new Error(`deriveFromSource: unknown source kind ${String(_exhaustive)}`);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Resolve a clip's track family — the single determinate rule:
|
|
80
|
-
* `clip.kind ?? deriveFromSource(source.kind) ?? track?.kind ?? throw`.
|
|
81
|
-
*
|
|
82
|
-
* The `track?.kind` step is a PLACEMENT reading, not a family oracle: "this clip
|
|
83
|
-
* is going on that track, so treat it as that family." It is correct here
|
|
84
|
-
* because this function is PURE — it has no database, and a media clip's real
|
|
85
|
-
* family lives on the media item (`mediaFamily(mimeType)`), which only a
|
|
86
|
-
* DB-aware caller can read. The editor's recording store legitimately adds media
|
|
87
|
-
* clips with no `kind` and a target track.
|
|
88
|
-
*
|
|
89
|
-
* What must NOT happen is a *server* guard treating this placement reading as
|
|
90
|
-
* an assertion and then rejecting the caller for it — that was the old
|
|
91
|
-
* `image_media_on_video_track`. The server stamps the true family from
|
|
92
|
-
* `mediaFamily(mediaItem.mimeType)` at the Convex ingress before folding ops, so
|
|
93
|
-
* by the time this runs server-side, `clip.kind` is already authoritative and
|
|
94
|
-
* the track step is never reached.
|
|
95
|
-
*
|
|
96
|
-
* FAILS LOUD for a media source with neither `clip.kind` nor a track — there is
|
|
97
|
-
* no safe default (no-fallbacks rule). Pure: no state, no side effects.
|
|
98
|
-
*/
|
|
99
|
-
export function resolveClipKind(clip, track) {
|
|
100
|
-
const resolved = clip.kind ?? deriveFromSource(clip.source.kind) ?? track?.kind;
|
|
101
|
-
if (!resolved) {
|
|
102
|
-
throw new Error(`resolveClipKind: clip with a 'media' source has no 'kind' and no track context — ` +
|
|
103
|
-
`cannot determine its family (video | audio | image). Set clip.kind or target a track.`);
|
|
104
|
-
}
|
|
105
|
-
return resolved;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* The serializable composition operation. One discriminated union; every writer
|
|
109
|
-
* (agent, editor) emits these; the server validates with this schema at the
|
|
110
|
-
* boundary. Local-only ops (selectClip/selectOverlay/clearOverlaySelection) are
|
|
111
|
-
* deliberately ABSENT — selection is UI state, never persisted.
|
|
112
|
-
*
|
|
113
|
-
* Cross-field/ripple ops (`cutAndRipple`, `ripple`, `add/removeExcludedRange`)
|
|
114
|
-
* are server-AUTHORITATIVE: the server mutation recomputes downstream timeline
|
|
115
|
-
* state within one transaction (they do not free-merge). They are still
|
|
116
|
-
* expressed here so all writers share one vocabulary. (A `playbackRate` change
|
|
117
|
-
* is also cross-field — it lives at `source.playbackRate` and ripples downstream
|
|
118
|
-
* clips — which is exactly why it is NOT a `clip.update` patch field.)
|
|
119
|
-
*/
|
|
120
|
-
export const CompositionOp = z.discriminatedUnion('type', [
|
|
121
|
-
// ── clips ──
|
|
122
|
-
// `newTrackId` pins the id of the track created when `newTrack` is set, so a
|
|
123
|
-
// recorded op replays to the identical track (byte-faithful op-log).
|
|
124
|
-
// `.strict()` on every variant: an unknown op-level key (e.g. an LLM agent's
|
|
125
|
-
// typo) fails loud instead of being silently stripped. Scope is op-level only —
|
|
126
|
-
// nested validators (TimelineClip, Marker, …) keep their own passthrough.
|
|
127
|
-
// `clip.add` is family-self-routing: the clip's family (resolveClipKind —
|
|
128
|
-
// clip.kind, else derived from source, else the target track) picks the track.
|
|
129
|
-
// `trackId` targets an EXISTING same-family track; `newTrack`/`newTrackId`
|
|
130
|
-
// create a fresh track of the family (the id is pinned for byte-faithful
|
|
131
|
-
// op-replay — same role it played on the old `addClip`). A `media` clip with
|
|
132
|
-
// neither `clip.kind` nor `trackId` is rejected at apply time (ambiguous).
|
|
133
|
-
z.object({ type: z.literal('clip.add'), clip: TimelineClip, trackId: z.string().optional(), newTrack: z.boolean().optional(), newTrackId: z.string().optional() }).strict(),
|
|
134
|
-
// `clip.remove` is cross-family: the store locates the clip by id across every
|
|
135
|
-
// track (one locator replaces the three family-specific removers).
|
|
136
|
-
z.object({ type: z.literal('clip.remove'), clipId: z.string() }).strict(),
|
|
137
|
-
// `clip.update` is cross-family: the store locates the clip by id across every
|
|
138
|
-
// track and merges `patch` (one op replaces the three family-specific updaters
|
|
139
|
-
// updateClip/updateOverlay/updateAudioClip AND setClipProperties). The patch is
|
|
140
|
-
// `TimelineClip.partial()` — opacity/scale/rotation/region/fit are top-level
|
|
141
|
-
// TimelineClip fields, so they fold straight into the patch. This KILLS the
|
|
142
|
-
// historic region/fit silent-drop: the parallel `props` channel (a hand-kept
|
|
143
|
-
// ClipProps mirror that drifted from the validator) is gone — the patch IS the
|
|
144
|
-
// validator, so it can never miss a field. `playbackRate` is deliberately NOT
|
|
145
|
-
// here: it lives at `source.playbackRate`, not as a top-level field, and a rate
|
|
146
|
-
// change is a cross-field ripple recompute (server-authoritative), not a free
|
|
147
|
-
// merge — it does not belong in clip.update.
|
|
148
|
-
//
|
|
149
|
-
// SOURCE PATCH SEMANTICS (T2 note): the merge is SHALLOW (top-level only). A
|
|
150
|
-
// `patch.source` REPLACES the WHOLE `source` object — it does NOT deep-merge.
|
|
151
|
-
// So a partial source (e.g. `{ source: { kind: 'media', mediaId } }` to retarget
|
|
152
|
-
// media) WIPES every other source field (trim, reframe, volume, excludedRanges,
|
|
153
|
-
// …). To change ONE source channel, send the COMPLETE source object with that
|
|
154
|
-
// channel updated (read it from the current clip first). Use `setCropIntents` /
|
|
155
|
-
// `addExcludedRange` for the reframe/excluded channels instead of a source patch.
|
|
156
|
-
z.object({ type: z.literal('clip.update'), clipId: z.string(), patch: TimelineClip.partial() }).strict(),
|
|
157
|
-
z.object({ type: z.literal('removeClipsByMediaId'), mediaId: z.string() }).strict(),
|
|
158
|
-
// ── overlays (load stays; add/remove/update fold into clip.add/clip.remove/clip.update) ──
|
|
159
|
-
z.object({ type: z.literal('loadOverlays'), clips: z.array(TimelineClip) }).strict(),
|
|
160
|
-
// ── markers ──
|
|
161
|
-
z.object({ type: z.literal('addMarker'), marker: Marker }).strict(),
|
|
162
|
-
z.object({ type: z.literal('removeMarker'), markerId: z.string() }).strict(),
|
|
163
|
-
z.object({ type: z.literal('updateMarker'), markerId: z.string(), updates: Marker.partial() }).strict(),
|
|
164
|
-
// ── crop (reframe) ── op `type` kept as 'setCropIntents' so recorded op
|
|
165
|
-
// streams replay unchanged; the segment payload is now ReframeSegment[].
|
|
166
|
-
z.object({ type: z.literal('setCropIntents'), clipId: z.string(), segments: z.array(ReframeSegment).nullable() }).strict(),
|
|
167
|
-
// ── effects ── the per-clip EFFECT channel (`TimelineClip.effects`). The field
|
|
168
|
-
// was always in the validator and `clip.add` always accepted it, but nothing
|
|
169
|
-
// could CHANGE it on an existing clip: the only route was a whole-clip
|
|
170
|
-
// `clip.update`, which this vocabulary steers callers away from (a partial
|
|
171
|
-
// `source` in that patch clobbers the source). WHOLESALE set; `effects: []`
|
|
172
|
-
// clears the channel — the same set/clear shape `setCropIntents` has. The item
|
|
173
|
-
// schema is the validator's own `PerClipEffect`, reused (never re-described).
|
|
174
|
-
z.object({ type: z.literal('setEffects'), clipId: z.string(), effects: z.array(PerClipEffect) }).strict(),
|
|
175
|
-
// ── captions ── style-only overrides (font, color, position, emphasis). Reuse
|
|
176
|
-
// CaptionStyle.partial() so the op vocabulary never hand-drifts from the validator;
|
|
177
|
-
// setCaptionStyle merges (omitted fields don't clobber) onto composition.captions.style.
|
|
178
|
-
z.object({ type: z.literal('setCaptionStyle'), style: CaptionStyle.partial() }).strict(),
|
|
179
|
-
// setCaptions replaces the caption SEGMENTS wholesale (word timings are one
|
|
180
|
-
// coherent document — the only writer used to be the transcript-slice lanes,
|
|
181
|
-
// which locked the caption layer away from clients with their own VO
|
|
182
|
-
// timings); `style` merges when given, keeps the existing style when omitted.
|
|
183
|
-
z.object({ type: z.literal('setCaptions'), segments: z.array(CaptionSegment), style: CaptionStyle.partial().optional() }).strict(),
|
|
184
|
-
// ── motion ── applyMotionPreset is the PUBLIC card-shelling op: wrap a static
|
|
185
|
-
// `card` clip's approved markup in a frame-driven motion shell (layout verbatim),
|
|
186
|
-
// mint it as a live component, and swap the clip source to that component (the
|
|
187
|
-
// director's `apply_motion_preset` capability, minus the box — the live lane).
|
|
188
|
-
// It is ROUTE-MATERIALIZED: generating the shell needs a director esbuild
|
|
189
|
-
// transpile, which the pure engine / applyOp mutation can't run, so the op route
|
|
190
|
-
// (`/composition/apply`) validates + orchestrates it and rewrites it to a
|
|
191
|
-
// `clip.update` BEFORE the mutation. `applyOp` therefore never applies it (it
|
|
192
|
-
// throws — reaching the pure engine means the route path was bypassed), and its
|
|
193
|
-
// recorded/invertible form is the substituted `clip.update` (whose inverse
|
|
194
|
-
// restores the prior card source). `preset` is `z.string()` here (validated
|
|
195
|
-
// against MOTION_PRESETS at the route, which owns @cueframe/authoring — this
|
|
196
|
-
// package stays authoring-free); the OpenAPI mirror enumerates the presets.
|
|
197
|
-
z.object({ type: z.literal('applyMotionPreset'), clipId: z.string(), preset: z.string(), params: z.object({ enterMs: z.number().optional(), exitMs: z.number().optional(), staggerMs: z.number().optional() }).strict().optional() }).strict(),
|
|
198
|
-
// ── grids ── materializeGrid reads a clip's SOURCE-media temporal grid
|
|
199
|
-
// (beat map / word onsets / shot boundaries), maps each grid point from media
|
|
200
|
-
// time to TIMELINE time through the clip's placement, and writes `kind:<grid>`
|
|
201
|
-
// markers (replacing any prior materialization from the same clipId+grid).
|
|
202
|
-
// Like applyMotionPreset it is ROUTE-MATERIALIZED: the pure engine / applyOp
|
|
203
|
-
// MUTATION has no media reader, so the op route (`/composition/apply` +
|
|
204
|
-
// `/composition/ops`) resolves the grid evidence and rewrites the op to a
|
|
205
|
-
// batch of removeMarker+addMarker ops BEFORE the mutation. `applyOp` therefore
|
|
206
|
-
// never applies it (it throws — reaching the pure engine means the route path
|
|
207
|
-
// was bypassed), and its recorded/invertible form is the substituted marker
|
|
208
|
-
// ops (whose own inverses restore the prior markers). `maxMarkers` (≤ 2000)
|
|
209
|
-
// raises the default 500 cap; exceeding it fails loud with the count.
|
|
210
|
-
z.object({ type: z.literal('materializeGrid'), clipId: z.string(), grid: z.enum(['beat', 'word', 'shot']), maxMarkers: z.number().int().positive().max(2000).optional() }).strict(),
|
|
211
|
-
// `captions.fromTranscript` is a REF op: attach caption content from the
|
|
212
|
-
// media's cached transcript (optionally a source-time window), sentence-split
|
|
213
|
-
// server-side. ROUTE-MATERIALIZED like applyMotionPreset/materializeGrid: the
|
|
214
|
-
// API route resolves it to `setCaptions` BEFORE the pure applier — the agent
|
|
215
|
-
// never pastes transcript text. applyOp throws on an unresolved instance (a
|
|
216
|
-
// pure applier cannot do I/O; silent no-op is the bug class this lane kills).
|
|
217
|
-
z.object({
|
|
218
|
-
type: z.literal('captions.fromTranscript'),
|
|
219
|
-
mediaId: z.string().min(1),
|
|
220
|
-
window: z.object({ startSec: z.number().min(0), endSec: z.number().positive() }).strict().optional(),
|
|
221
|
-
}).strict(),
|
|
222
|
-
// ── format ──
|
|
223
|
-
z.object({ type: z.literal('setFormat'), format: Format.pick({ aspectRatio: true, fps: true, resolution: true }) }).strict(),
|
|
224
|
-
// ── tracks ──
|
|
225
|
-
z.object({ type: z.literal('addTrack'), kind: Track.shape.kind, name: z.string().optional(), id: z.string().optional() }).strict(),
|
|
226
|
-
z.object({ type: z.literal('removeTrack'), trackId: z.string() }).strict(),
|
|
227
|
-
// `volume` joined the pickable set with the track fader (2026-08-24). Review
|
|
228
|
-
// finding: the fader's store verb accepted it while THIS payload schema did
|
|
229
|
-
// not — so a fader move recorded into the op journal, or replayed over the
|
|
230
|
-
// REST-op path, failed validation. The store verb and the op vocabulary must
|
|
231
|
-
// widen together or the op-log lies about what the editor can do.
|
|
232
|
-
z.object({ type: z.literal('updateTrack'), trackId: z.string(), updates: Track.pick({ name: true, enabled: true, volume: true }).partial() }).strict(),
|
|
233
|
-
z.object({ type: z.literal('reorderTracks'), fromIndex: z.number(), toIndex: z.number() }).strict(),
|
|
234
|
-
z.object({ type: z.literal('moveClipToTrack'), clipId: z.string(), targetTrackId: z.string(), newStartTime: z.number().optional() }).strict(),
|
|
235
|
-
// `newClipId` PINS the id of the copy duplicateClip mints (the store otherwise
|
|
236
|
-
// mints a uuid-suffixed id internally). Pinning makes the op deterministic so
|
|
237
|
-
// `invertOp` can return a `clip.remove` of that exact id (a non-pinned
|
|
238
|
-
// duplicateClip has no determinate inverse — invertOp throws for it).
|
|
239
|
-
z.object({ type: z.literal('duplicateClip'), clipId: z.string(), newClipId: z.string().optional() }).strict(),
|
|
240
|
-
// ── server-authoritative (cross-field timeline recompute) ──
|
|
241
|
-
z.object({ type: z.literal('cutAndRipple'), start: z.number(), end: z.number() }).strict(),
|
|
242
|
-
z.object({ type: z.literal('ripple'), time: z.number(), amount: z.number() }).strict(),
|
|
243
|
-
z.object({ type: z.literal('addExcludedRange'), clipId: z.string(), sourceStart: z.number(), sourceEnd: z.number(), reason: z.string().optional() }).strict(),
|
|
244
|
-
z.object({ type: z.literal('removeExcludedRange'), clipId: z.string(), rangeIdx: z.number() }).strict(),
|
|
245
|
-
]);
|
|
246
|
-
/**
|
|
247
|
-
* Apply an op to a wire Composition, returning the new Composition (pure).
|
|
248
|
-
* Reuses `@cueframe/core`'s tested op logic via a headless store — no fork.
|
|
249
|
-
*/
|
|
250
|
-
export function applyOp(composition, op) {
|
|
251
|
-
const store = createHeadlessStore(composition);
|
|
252
|
-
applyOpToStore(store, op);
|
|
253
|
-
return store.getState().composition;
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Dispatch ONE op onto a LIVE store — the op→method switch, extracted from
|
|
257
|
-
* `applyOp` so there is exactly one of it.
|
|
258
|
-
*
|
|
259
|
-
* `applyOp` is pure: it mints a throwaway headless store, folds, and hands back
|
|
260
|
-
* a new Composition. That serves every caller that OWNS the composition value
|
|
261
|
-
* (the Convex mutation, the local-harness store, the ensemble author). It does
|
|
262
|
-
* NOT serve a caller whose composition lives inside somebody else's store —
|
|
263
|
-
* desktop's zustand `CompositionState`, which has no whole-composition setter
|
|
264
|
-
* and whose op-recorder/undo trail only sees writes that go through its
|
|
265
|
-
* methods. Handing that caller a fresh Composition value would be a dead end;
|
|
266
|
-
* the only way in is the methods, which is precisely what this switch calls.
|
|
267
|
-
*
|
|
268
|
-
* So: `HeadlessStore` here is a STRUCTURAL contract (`CompositionOps` + a
|
|
269
|
-
* `getState`), not a concrete class — `@cueframe/authoring`'s `CompositionStore`
|
|
270
|
-
* and the desktop store satisfy it, and `LocalExecutor` (cueframe/src/llm) folds
|
|
271
|
-
* a validated batch through it op-by-op. Writing a second switch for that lane
|
|
272
|
-
* is what "one vocabulary" exists to prevent: it would drift silently the first
|
|
273
|
-
* time an op is added here and forgotten there.
|
|
274
|
-
*
|
|
275
|
-
* NOT transactional on its own — it applies ONE op and a throw leaves the store
|
|
276
|
-
* wherever it got to. A caller wanting the server's all-or-nothing contract
|
|
277
|
-
* validates the whole batch on a scratch fold (`ops.reduce(applyOp, current)`)
|
|
278
|
-
* FIRST, and only then commits through this.
|
|
279
|
-
*/
|
|
280
|
-
export function applyOpToStore(store, op) {
|
|
281
|
-
const composition = store.getState().composition;
|
|
282
|
-
switch (op.type) {
|
|
283
|
-
case 'clip.add': {
|
|
284
|
-
if (op.trackId !== undefined) {
|
|
285
|
-
// Target an EXISTING track — it must be the clip's own family (a clip
|
|
286
|
-
// never silently lands on a different-family track). The target track is
|
|
287
|
-
// the family context for resolveClipKind, so an explicit clip.kind that
|
|
288
|
-
// contradicts it is caught here.
|
|
289
|
-
const track = composition.tracks.find((t) => t.id === op.trackId);
|
|
290
|
-
if (!track)
|
|
291
|
-
throw new Error(`clip.add: track '${op.trackId}' not found`);
|
|
292
|
-
const kind = resolveClipKind(op.clip, track);
|
|
293
|
-
if (kind !== track.kind) {
|
|
294
|
-
throw new Error(`clip.add: clip family '${kind}' does not match target track '${op.trackId}' (kind '${track.kind}')`);
|
|
295
|
-
}
|
|
296
|
-
store.addClipToTrack(op.clip, { trackId: op.trackId });
|
|
297
|
-
}
|
|
298
|
-
else {
|
|
299
|
-
// No target track: the clip self-describes its family (kind, else derived
|
|
300
|
-
// from source). A media clip with neither kind nor trackId throws here.
|
|
301
|
-
const kind = resolveClipKind(op.clip);
|
|
302
|
-
store.addClipToTrack(op.clip, op.newTrack ? { kind, newTrack: true, newTrackId: op.newTrackId } : { kind });
|
|
303
|
-
}
|
|
304
|
-
break;
|
|
305
|
-
}
|
|
306
|
-
case 'clip.remove':
|
|
307
|
-
store.removeClip(op.clipId);
|
|
308
|
-
break;
|
|
309
|
-
// `store.updateClip` is cross-family (locates the clip by id across every
|
|
310
|
-
// track, like `removeClip`), so it serves all three former family updaters
|
|
311
|
-
// AND setClipProperties' visual props (region/fit/opacity/scale/rotation +
|
|
312
|
-
// timing) — a plain partial merge of top-level TimelineClip fields.
|
|
313
|
-
case 'clip.update':
|
|
314
|
-
store.updateClip(op.clipId, op.patch);
|
|
315
|
-
break;
|
|
316
|
-
case 'removeClipsByMediaId':
|
|
317
|
-
store.removeClipsByMediaId(op.mediaId);
|
|
318
|
-
break;
|
|
319
|
-
case 'loadOverlays':
|
|
320
|
-
store.loadOverlays(op.clips);
|
|
321
|
-
break;
|
|
322
|
-
case 'addMarker':
|
|
323
|
-
store.addMarker(op.marker);
|
|
324
|
-
break;
|
|
325
|
-
case 'removeMarker':
|
|
326
|
-
store.removeMarker(op.markerId);
|
|
327
|
-
break;
|
|
328
|
-
case 'updateMarker':
|
|
329
|
-
store.updateMarker(op.markerId, op.updates);
|
|
330
|
-
break;
|
|
331
|
-
case 'setCropIntents':
|
|
332
|
-
store.setCropIntents(op.clipId, op.segments);
|
|
333
|
-
break;
|
|
334
|
-
case 'setEffects': {
|
|
335
|
-
// Fail loud on an unknown clip. The engine method (like every op on the
|
|
336
|
-
// factory) silently no-ops when the id doesn't resolve; for a WIRE op that
|
|
337
|
-
// silence is the bug — the caller gets a 200 and no effects. `clip.add`
|
|
338
|
-
// (above) sets the precedent: pre-check, then throw naming the id.
|
|
339
|
-
if (!findClipById(composition, op.clipId)) {
|
|
340
|
-
throw new Error(`setEffects: clip '${op.clipId}' not found`);
|
|
341
|
-
}
|
|
342
|
-
store.setEffects(op.clipId, op.effects);
|
|
343
|
-
break;
|
|
344
|
-
}
|
|
345
|
-
case 'setCaptionStyle':
|
|
346
|
-
store.setCaptionStyle(op.style);
|
|
347
|
-
break;
|
|
348
|
-
case 'setCaptions':
|
|
349
|
-
store.setCaptions(op.segments, op.style);
|
|
350
|
-
break;
|
|
351
|
-
case 'applyMotionPreset':
|
|
352
|
-
// Route-materialized: shelling a card needs a director esbuild transpile
|
|
353
|
-
// (the pure engine can't run it), so the op route rewrites this to a
|
|
354
|
-
// `clip.update` BEFORE the mutation folds ops. Reaching applyOp means the
|
|
355
|
-
// route path was bypassed — fail loud, never a fake apply.
|
|
356
|
-
throw new Error(`applyOp: 'applyMotionPreset' is route-materialized — it needs a director ` +
|
|
357
|
-
`transpile of the generated motion shell and is rewritten to a clip.update ` +
|
|
358
|
-
`at /composition/apply before reaching the pure engine.`);
|
|
359
|
-
case 'materializeGrid':
|
|
360
|
-
// Route-materialized: reading the clip's source-media grid evidence needs a
|
|
361
|
-
// media reader (DB), which the pure engine can't run, so the op route
|
|
362
|
-
// resolves the grid and rewrites this to removeMarker+addMarker ops BEFORE
|
|
363
|
-
// the mutation folds ops. Reaching applyOp means the route path was
|
|
364
|
-
// bypassed — fail loud, never a fake apply.
|
|
365
|
-
throw new Error(`applyOp: 'materializeGrid' is route-materialized — it reads the clip's ` +
|
|
366
|
-
`source-media grid (beat/word/shot) via a media reader and is rewritten to ` +
|
|
367
|
-
`removeMarker+addMarker ops at /composition/apply before reaching the pure engine.`);
|
|
368
|
-
case 'captions.fromTranscript':
|
|
369
|
-
// Route-materialized: resolving the media's cached transcript needs R2 +
|
|
370
|
-
// DB reads the pure engine can't run; the op route slices + sentence-
|
|
371
|
-
// splits and rewrites this to `setCaptions` BEFORE the mutation folds
|
|
372
|
-
// ops. Reaching applyOp means the route path was bypassed — fail loud.
|
|
373
|
-
throw new Error(`applyOp: 'captions.fromTranscript' is route-materialized — it is resolved to ` +
|
|
374
|
-
`setCaptions at /composition/apply before reaching the pure engine.`);
|
|
375
|
-
case 'setFormat':
|
|
376
|
-
store.setFormat(op.format);
|
|
377
|
-
break;
|
|
378
|
-
case 'addTrack':
|
|
379
|
-
store.addTrack(op.kind, op.name, op.id);
|
|
380
|
-
break;
|
|
381
|
-
case 'removeTrack':
|
|
382
|
-
store.removeTrack(op.trackId);
|
|
383
|
-
break;
|
|
384
|
-
case 'updateTrack':
|
|
385
|
-
store.updateTrack(op.trackId, op.updates);
|
|
386
|
-
break;
|
|
387
|
-
case 'reorderTracks':
|
|
388
|
-
store.reorderTracks(op.fromIndex, op.toIndex);
|
|
389
|
-
break;
|
|
390
|
-
case 'moveClipToTrack':
|
|
391
|
-
store.moveClipToTrack(op.clipId, op.targetTrackId, op.newStartTime);
|
|
392
|
-
break;
|
|
393
|
-
case 'duplicateClip': {
|
|
394
|
-
const minted = store.duplicateClip(op.clipId);
|
|
395
|
-
// Pin the copy's id when `newClipId` is supplied so the op is
|
|
396
|
-
// deterministic (replay + a deterministic clip.remove inverse). The store
|
|
397
|
-
// mints a uuid-suffixed id; rename it via a plain id patch.
|
|
398
|
-
if (op.newClipId !== undefined && minted !== undefined && minted !== op.newClipId) {
|
|
399
|
-
store.updateClip(minted, { id: op.newClipId });
|
|
400
|
-
}
|
|
401
|
-
break;
|
|
402
|
-
}
|
|
403
|
-
case 'cutAndRipple':
|
|
404
|
-
store.cutAndRipple(op.start, op.end);
|
|
405
|
-
break;
|
|
406
|
-
case 'ripple':
|
|
407
|
-
store.ripple(op.time, op.amount);
|
|
408
|
-
break;
|
|
409
|
-
case 'addExcludedRange':
|
|
410
|
-
store.addExcludedRange(op.clipId, op.sourceStart, op.sourceEnd, op.reason);
|
|
411
|
-
break;
|
|
412
|
-
case 'removeExcludedRange':
|
|
413
|
-
store.removeExcludedRange(op.clipId, op.rangeIdx);
|
|
414
|
-
break;
|
|
415
|
-
default: {
|
|
416
|
-
const _exhaustive = op;
|
|
417
|
-
throw new Error(`applyOp: unknown op ${_exhaustive.type}`);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
/**
|
|
422
|
-
* The inverse op (for the op-log → selective multiplayer undo / diff / audit).
|
|
423
|
-
*
|
|
424
|
-
* `invertOp(before, op)` returns the op that, applied to `applyOp(before, op)`,
|
|
425
|
-
* restores `before`. It needs the PRE-image to capture the value the forward op
|
|
426
|
-
* overwrote (the patched fields, the replaced reframe segments, the removed
|
|
427
|
-
* clip, …).
|
|
428
|
-
*
|
|
429
|
-
* Coverage (value-restoring): clip.add↔clip.remove, clip.update (prior fields),
|
|
430
|
-
* markers (add/remove/update), setCropIntents (prior segments), setEffects (prior
|
|
431
|
-
* effect stack), setFormat (prior values), addTrack↔removeTrack, updateTrack
|
|
432
|
-
* (prior name/enabled), reorderTracks (reversed), moveClipToTrack (move back),
|
|
433
|
-
* duplicateClip (clip.remove of the PINNED newClipId).
|
|
434
|
-
*
|
|
435
|
-
* DEFERRED — these THROW (fail loud; a wrong inverse silently corrupts undo, so
|
|
436
|
-
* we never fake one):
|
|
437
|
-
* - cutAndRipple / ripple / addExcludedRange / removeExcludedRange — server-
|
|
438
|
-
* authoritative cross-field timeline recomputes (clips split/merge, durations
|
|
439
|
-
* and downstream startTimes recompute, markers + caption words ripple). No
|
|
440
|
-
* clean single-op inverse; restoring them is a snapshot-restore concern.
|
|
441
|
-
* - removeTrack — removes a track AND its clips at a position; there is no
|
|
442
|
-
* op to re-insert a populated track at an index (addTrack appends an EMPTY
|
|
443
|
-
* track), so the pre-image can't be restored as one op.
|
|
444
|
-
* - removeClipsByMediaId / loadOverlays — whole-channel replace/clear (multiple
|
|
445
|
-
* clips across tracks, with positions and scene-marker side effects); no
|
|
446
|
-
* single restoring op.
|
|
447
|
-
* - setCaptionStyle — MERGES (and creates the captions container when absent)
|
|
448
|
-
* with no clear/drop op, so a forward call that adds a style key (or the
|
|
449
|
-
* container) can't be exactly reverted.
|
|
450
|
-
* - duplicateClip WITHOUT `newClipId` — the copy's id is store-minted
|
|
451
|
-
* (non-deterministic), so there is no clip id to remove. Pin `newClipId` for a
|
|
452
|
-
* deterministic inverse.
|
|
453
|
-
*/
|
|
454
|
-
export function invertOp(before, op) {
|
|
455
|
-
switch (op.type) {
|
|
456
|
-
case 'clip.add':
|
|
457
|
-
// The forward add appended `op.clip`; remove it by id. (When the add
|
|
458
|
-
// auto-CREATES a track for a new family, removing the clip leaves that
|
|
459
|
-
// empty track behind — the editor/agent only ever add to existing or
|
|
460
|
-
// explicitly-pinned tracks via this op, so this is the value inverse.)
|
|
461
|
-
return { type: 'clip.remove', clipId: op.clip.id };
|
|
462
|
-
case 'clip.remove': {
|
|
463
|
-
// Restore the pre-image clip onto its ORIGINAL track (so it returns to the
|
|
464
|
-
// same family/position context). The captured clip carries its own `kind`,
|
|
465
|
-
// and we target the original trackId — the determinate add path.
|
|
466
|
-
const found = findClipById(before, op.clipId);
|
|
467
|
-
if (!found) {
|
|
468
|
-
throw new Error(`invertOp(clip.remove): clip '${op.clipId}' not in the pre-image`);
|
|
469
|
-
}
|
|
470
|
-
const track = before.tracks[found.trackIndex];
|
|
471
|
-
return { type: 'clip.add', clip: found.clip, trackId: track.id };
|
|
472
|
-
}
|
|
473
|
-
case 'clip.update': {
|
|
474
|
-
// Restore the prior value of EVERY key the patch named. A key that was
|
|
475
|
-
// absent before maps to `undefined` (the spread writes it as undefined;
|
|
476
|
-
// structural equality treats `{k: undefined}` as absent, so the pre-image
|
|
477
|
-
// is recovered).
|
|
478
|
-
const found = findClipById(before, op.clipId);
|
|
479
|
-
if (!found) {
|
|
480
|
-
throw new Error(`invertOp(clip.update): clip '${op.clipId}' not in the pre-image`);
|
|
481
|
-
}
|
|
482
|
-
const prior = found.clip;
|
|
483
|
-
const inversePatch = {};
|
|
484
|
-
for (const key of Object.keys(op.patch))
|
|
485
|
-
inversePatch[key] = prior[key];
|
|
486
|
-
return { type: 'clip.update', clipId: op.clipId, patch: inversePatch };
|
|
487
|
-
}
|
|
488
|
-
case 'addMarker':
|
|
489
|
-
return { type: 'removeMarker', markerId: op.marker.id };
|
|
490
|
-
case 'removeMarker': {
|
|
491
|
-
const found = findMarkerById(before, op.markerId);
|
|
492
|
-
if (!found) {
|
|
493
|
-
throw new Error(`invertOp(removeMarker): marker '${op.markerId}' not in the pre-image`);
|
|
494
|
-
}
|
|
495
|
-
// Re-add the pre-image marker. (addMarker appends; when the removed marker
|
|
496
|
-
// was not last, the marker is restored by VALUE but not its array index.)
|
|
497
|
-
return { type: 'addMarker', marker: found.marker };
|
|
498
|
-
}
|
|
499
|
-
case 'updateMarker': {
|
|
500
|
-
const found = findMarkerById(before, op.markerId);
|
|
501
|
-
if (!found) {
|
|
502
|
-
throw new Error(`invertOp(updateMarker): marker '${op.markerId}' not in the pre-image`);
|
|
503
|
-
}
|
|
504
|
-
const prior = found.marker;
|
|
505
|
-
const inverseUpdates = {};
|
|
506
|
-
for (const key of Object.keys(op.updates)) {
|
|
507
|
-
inverseUpdates[key] = prior[key];
|
|
508
|
-
}
|
|
509
|
-
return { type: 'updateMarker', markerId: op.markerId, updates: inverseUpdates };
|
|
510
|
-
}
|
|
511
|
-
case 'setCropIntents': {
|
|
512
|
-
// Restore the prior `reframe.segments` (or clear when there were none).
|
|
513
|
-
const found = findClipById(before, op.clipId);
|
|
514
|
-
if (!found) {
|
|
515
|
-
throw new Error(`invertOp(setCropIntents): clip '${op.clipId}' not in the pre-image`);
|
|
516
|
-
}
|
|
517
|
-
const src = found.clip.source;
|
|
518
|
-
const priorSegments = src.kind === 'media' && src.reframe ? src.reframe.segments : null;
|
|
519
|
-
return { type: 'setCropIntents', clipId: op.clipId, segments: priorSegments };
|
|
520
|
-
}
|
|
521
|
-
case 'setEffects': {
|
|
522
|
-
// Wholesale channel, so the inverse is the pre-image array (`[]` when the
|
|
523
|
-
// clip had no effects — which is exactly how the forward op CLEARS).
|
|
524
|
-
const found = findClipById(before, op.clipId);
|
|
525
|
-
if (!found) {
|
|
526
|
-
throw new Error(`invertOp(setEffects): clip '${op.clipId}' not in the pre-image`);
|
|
527
|
-
}
|
|
528
|
-
return { type: 'setEffects', clipId: op.clipId, effects: found.clip.effects ?? [] };
|
|
529
|
-
}
|
|
530
|
-
case 'setFormat': {
|
|
531
|
-
// Restore the prior aspectRatio + fps + resolution. NOTE: setFormat MERGES
|
|
532
|
-
// (carry-forward), so an omitted field keeps the CURRENT value — this
|
|
533
|
-
// inverse restores prior VALUES but cannot DROP a field that was absent
|
|
534
|
-
// before the forward op. A fully-populated prior format round-trips.
|
|
535
|
-
const f = before.format;
|
|
536
|
-
return {
|
|
537
|
-
type: 'setFormat',
|
|
538
|
-
format: {
|
|
539
|
-
aspectRatio: f.aspectRatio,
|
|
540
|
-
...(f.fps !== undefined ? { fps: f.fps } : {}),
|
|
541
|
-
...(f.resolution !== undefined ? { resolution: f.resolution } : {}),
|
|
542
|
-
},
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
|
-
case 'addTrack':
|
|
546
|
-
// The forward addTrack pinned `id` (or one was minted); remove that track.
|
|
547
|
-
// (Our recording seam always pins addTrack's id, so `op.id` is present in
|
|
548
|
-
// practice; if absent, the inverse can't target the minted id.)
|
|
549
|
-
if (op.id === undefined) {
|
|
550
|
-
throw new Error('invertOp(addTrack): no pinned `id` — cannot target the minted track');
|
|
551
|
-
}
|
|
552
|
-
return { type: 'removeTrack', trackId: op.id };
|
|
553
|
-
case 'updateTrack': {
|
|
554
|
-
const track = before.tracks.find((t) => t.id === op.trackId);
|
|
555
|
-
if (!track) {
|
|
556
|
-
throw new Error(`invertOp(updateTrack): track '${op.trackId}' not in the pre-image`);
|
|
557
|
-
}
|
|
558
|
-
const inverseUpdates = {};
|
|
559
|
-
if ('name' in op.updates)
|
|
560
|
-
inverseUpdates.name = track.name;
|
|
561
|
-
if ('enabled' in op.updates)
|
|
562
|
-
inverseUpdates.enabled = track.enabled;
|
|
563
|
-
return { type: 'updateTrack', trackId: op.trackId, updates: inverseUpdates };
|
|
564
|
-
}
|
|
565
|
-
case 'reorderTracks': {
|
|
566
|
-
// reorderTracks splices the element out then re-inserts at clamped(toIndex);
|
|
567
|
-
// the moved element's final index is therefore clamped(toIndex). The inverse
|
|
568
|
-
// moves it from that resting index back to its original `fromIndex`.
|
|
569
|
-
const len = before.tracks.length;
|
|
570
|
-
const restingIndex = Math.max(0, Math.min(op.toIndex, len - 1));
|
|
571
|
-
return { type: 'reorderTracks', fromIndex: restingIndex, toIndex: op.fromIndex };
|
|
572
|
-
}
|
|
573
|
-
case 'moveClipToTrack': {
|
|
574
|
-
// Move the clip back to its ORIGINAL track and restore its prior startTime.
|
|
575
|
-
const found = findTrackContainingClipId(before, op.clipId);
|
|
576
|
-
if (!found) {
|
|
577
|
-
throw new Error(`invertOp(moveClipToTrack): clip '${op.clipId}' not in the pre-image`);
|
|
578
|
-
}
|
|
579
|
-
const priorClip = found.track.contents[found.clipIndex];
|
|
580
|
-
return {
|
|
581
|
-
type: 'moveClipToTrack',
|
|
582
|
-
clipId: op.clipId,
|
|
583
|
-
targetTrackId: found.track.id,
|
|
584
|
-
newStartTime: priorClip.startTime,
|
|
585
|
-
};
|
|
586
|
-
}
|
|
587
|
-
case 'duplicateClip':
|
|
588
|
-
// The copy's id is store-minted unless the op PINS `newClipId`. Without a
|
|
589
|
-
// pin there is no determinate id to remove — fail loud rather than guess.
|
|
590
|
-
if (op.newClipId === undefined) {
|
|
591
|
-
throw new Error('invertOp(duplicateClip): no `newClipId` — the copy id is store-minted and ' +
|
|
592
|
-
'non-deterministic. Pin `newClipId` on the op for a deterministic inverse.');
|
|
593
|
-
}
|
|
594
|
-
return { type: 'clip.remove', clipId: op.newClipId };
|
|
595
|
-
// ── DEFERRED (fail loud — see the doc-comment above for why none has a
|
|
596
|
-
// clean per-op inverse in scope). ──
|
|
597
|
-
case 'cutAndRipple':
|
|
598
|
-
case 'ripple':
|
|
599
|
-
case 'addExcludedRange':
|
|
600
|
-
case 'removeExcludedRange':
|
|
601
|
-
case 'removeTrack':
|
|
602
|
-
case 'removeClipsByMediaId':
|
|
603
|
-
case 'loadOverlays':
|
|
604
|
-
case 'setCaptionStyle':
|
|
605
|
-
case 'setCaptions':
|
|
606
|
-
// applyMotionPreset is route-materialized into a clip.update before it is
|
|
607
|
-
// recorded, so invertOp is never asked to invert it in practice; if it is
|
|
608
|
-
// (a bypassed route path), fail loud — the real inverse lives on the
|
|
609
|
-
// substituted clip.update (which restores the prior card source).
|
|
610
|
-
case 'applyMotionPreset':
|
|
611
|
-
// materializeGrid is route-materialized into removeMarker+addMarker ops
|
|
612
|
-
// before it is recorded, so invertOp never inverts it in practice; the real
|
|
613
|
-
// inverses live on those substituted marker ops. Fail loud if reached.
|
|
614
|
-
case 'materializeGrid':
|
|
615
|
-
// captions.fromTranscript is route-materialized into setCaptions before it
|
|
616
|
-
// is recorded, so invertOp never inverts it in practice; fail loud if reached.
|
|
617
|
-
case 'captions.fromTranscript':
|
|
618
|
-
throw new Error(`invertOp: '${op.type}' has no per-op inverse in scope (server-authoritative ` +
|
|
619
|
-
`cross-field recompute or whole-channel/positional restore) — fail loud, no fake inverse.`);
|
|
620
|
-
default: {
|
|
621
|
-
const _exhaustive = op;
|
|
622
|
-
throw new Error(`invertOp: unknown op ${_exhaustive.type}`);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
export { createRecordingStore } from './recordingStore';
|
|
627
|
-
export { wrapWithOpRecorder } from './opRecorder';
|
|
628
|
-
// ── materializeGrid — the pure media-time → timeline-time grid projection ──
|
|
629
|
-
// (the DB-bound evidence read + idempotent marker replace is the op route's).
|
|
630
|
-
export { materializeGridMarkers, GridError, GRID_DEFAULT_MAX_MARKERS, GRID_HARD_MAX_MARKERS, } from './materializeGrid';
|
|
631
|
-
// ── replaceRegion — the non-rippling cut/overlay lowering (selector switch) ──
|
|
632
|
-
export { replaceRegion } from './replaceRegion';
|
|
633
|
-
// The alpha-layer clip walk (pure, crypto-free) — the SSOT for finding a wire
|
|
634
|
-
// composition's alpha-layer clips. Shared by the director (bake) and Convex
|
|
635
|
-
// (materialize tsxSource into the stage body). The content-hash that keys the
|
|
636
|
-
// bake cache stays director-side (it needs node:crypto, not V8-safe).
|
|
637
|
-
export { collectAlphaLayerClips, collectLiveComponentClips, collectRawComponentClips, } from './alphaLayers';
|