@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.
- package/LICENSE +661 -0
- package/dist/_members/composition/ops/compositionOps.d.ts +1 -0
- 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/validators/composition.d.ts +42 -25
- package/dist/_members/composition/validators/render.d.ts +32 -0
- package/dist/_members/core/render/compositionRender.d.ts +17 -1
- package/dist/_members/core/render/types.d.ts +31 -0
- package/dist/authoring/build-tools.js +6 -6
- package/dist/authoring/context.js +4 -4
- package/dist/authoring/tools.js +5 -5
- package/dist/authoring.js +11 -9
- package/dist/{chunk-ZB3C3HM7.js → chunk-7FO3ZJ43.js} +3 -0
- package/dist/{chunk-ODL7GQJG.js → chunk-AP6ZIVAV.js} +2 -2
- package/dist/{chunk-IBYQG46O.js → chunk-AQBREB5O.js} +1 -1
- package/dist/{chunk-YIOY2XEO.js → chunk-DK2ODBNT.js} +15 -5
- package/dist/{chunk-JRQVPFLF.js → chunk-HY3RIEZW.js} +1 -1
- package/dist/{chunk-GEA7E2FL.js → chunk-JJ6XD7NG.js} +151 -1
- package/dist/{chunk-COYMZ76S.js → chunk-MBCXCJOE.js} +1 -1
- package/dist/{chunk-37NJ27UU.js → chunk-OCFDUCF4.js} +3 -0
- package/dist/{chunk-VOO5FQSS.js → chunk-PDYO3DOJ.js} +5 -5
- package/dist/{chunk-MXFAADCQ.js → chunk-PODIYN2K.js} +9 -2
- package/dist/{chunk-NFEGPWGS.js → chunk-TOJEXFXL.js} +1 -1
- package/dist/{chunk-LM4WDUQJ.js → chunk-UHGSZZDI.js} +1 -1
- package/dist/{chunk-XWKZB5U5.js → chunk-ZWMV6DD2.js} +24 -1
- package/dist/compose/renderer.js +3 -3
- package/dist/compose.js +6 -6
- package/dist/composition/graphics-plan.js +1 -1
- package/dist/composition/ops.js +3 -3
- package/dist/composition/primitive-catalog.js +1 -1
- package/dist/composition/projection.js +19 -3
- package/dist/composition/validators.js +6 -4
- package/dist/composition-ops.js +8 -6
- package/dist/composition.js +24 -6
- package/dist/{context-OKX3HHFS.js → context-YWUZDG5X.js} +4 -4
- 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 +1 -0
- package/dist/media-model/testing.js +1071 -718
- package/dist/nle-export/server.js +328 -130
- package/dist/nle-export.js +7 -6
- package/package.json +13 -14
- 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/cloud-import/chunk-XKO6ZSWI.js +0 -162
- package/dist/_members/cloud-import/chunk-XKO6ZSWI.js.map +0 -1
- package/dist/_members/cloud-import/index.js +0 -241
- package/dist/_members/cloud-import/index.js.map +0 -1
- package/dist/_members/cloud-import/multipartUpload.js +0 -7
- package/dist/_members/cloud-import/multipartUpload.js.map +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 +0 -134
- 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
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* THE REQUEST CONTRACT — one definition, both servers.
|
|
3
|
-
*
|
|
4
|
-
* WHY THIS MOVED HERE. `preview_frame` had THREE definitions of its own body:
|
|
5
|
-
* the Convex route's zod (what the cloud actually enforced), the orval-generated
|
|
6
|
-
* `previewFrameBody` (what the SDK and every MCP client enforce), and a
|
|
7
|
-
* hand-written imperative mirror in the desktop plane. Nothing made them agree,
|
|
8
|
-
* and the only sync mechanism was review discipline — comments reading
|
|
9
|
-
* "ALLOWED_KEYS TRACKS THAT SCHEMA … Add server-side keys here in the same
|
|
10
|
-
* change". On 2026-08-15 that mechanism was observed failing in both directions
|
|
11
|
-
* at once: the desktop silently ignored `imageFormat`/`jpegQuality` entirely,
|
|
12
|
-
* while the PUBLISHED contract was `.strict()` and both servers were not — so
|
|
13
|
-
* generated clients rejected keys that either server would have accepted.
|
|
14
|
-
*
|
|
15
|
-
* MOVED VERBATIM. Every `.describe()` string is preserved because the OpenAPI
|
|
16
|
-
* spec — and therefore the generated SDK, the MCP tool schemas and the docs —
|
|
17
|
-
* is built from this object (`requestBody: PreviewFrameRequest`). Rewording a
|
|
18
|
-
* description here republishes the API.
|
|
19
|
-
*
|
|
20
|
-
* STRICTNESS IS DELIBERATELY UNCHANGED. This object ends `})`, not `}).strict()`,
|
|
21
|
-
* exactly as the route defined it, so this extraction is a pure refactor with no
|
|
22
|
-
* behaviour change on a live API. Whether the servers SHOULD be strict — and
|
|
23
|
-
* match the contract they publish — is a product decision with outward-facing
|
|
24
|
-
* consequences for existing callers, tracked as a red row in
|
|
25
|
-
* `conformance.ts` rather than settled quietly here.
|
|
26
|
-
*
|
|
27
|
-
* PURE, because Convex runs this inside a V8 isolate and the desktop bundles it
|
|
28
|
-
* into a webview. zod only; no I/O, no Node APIs.
|
|
29
|
-
*/
|
|
30
|
-
import { z } from "zod";
|
|
31
|
-
export const PreviewFrameRequest = z.object({
|
|
32
|
-
composition: z.unknown().optional().describe("The composition to render. Absent ⇒ the project's ACTIVE composition — what " +
|
|
33
|
-
"create_render will encode. The response's `previewed.source` names what was rendered."),
|
|
34
|
-
compositionId: z.string().optional().describe("Preview a SPECIFIC persisted composition of this project (create_render parity). " +
|
|
35
|
-
"Absent ⇒ the active one. A stale/foreign id is a 404 — never a silent fall-through."),
|
|
36
|
-
session_id: z.string().optional().describe("Compose-session id: render that session's SCRATCH composition (what the session " +
|
|
37
|
-
"has been editing) instead of the active row. Ignored when `composition` is passed."),
|
|
38
|
-
timestamps: z.array(z.number()).min(1),
|
|
39
|
-
// Vision-bound shrink knobs (additive): an AGENT looking at its own work wants
|
|
40
|
-
// the judge's cheap stills (jpeg, 0.5, q70 — what the eval panel grades), not
|
|
41
|
-
// the full-res default a human preview wants. Absent ⇒ unchanged full-res.
|
|
42
|
-
imageFormat: z.enum(["png", "jpeg"]).optional().describe("Still format. Default jpeg — these pixels go to a vision model, where jpeg " +
|
|
43
|
-
"is equivalent and png costs multiples in bytes to store and move. Pass " +
|
|
44
|
-
"png only when you need full fidelity."),
|
|
45
|
-
scale: z.number().min(0.1).max(1).optional().describe("Render scale 0.1–1. Default 0.5, which is what this schema has always " +
|
|
46
|
-
"recommended for vision-bound looks. Pass 1 when judging fine detail — " +
|
|
47
|
-
"it costs ~4x the vision tokens."),
|
|
48
|
-
jpegQuality: z.number().int().min(1).max(100).optional().describe("JPEG quality (jpeg only). Default 70 — the quality the eval panel grades at."),
|
|
49
|
-
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `@cueframe/plane` — the lane-agnostic core of the verb plane.
|
|
3
|
-
*
|
|
4
|
-
* TODAY this package holds only the conformance table (stage 0 of
|
|
5
|
-
* Projects/CueFrame/specs/2026-08-15-plane-lane-parity-design): the shared facts
|
|
6
|
-
* both the desktop plane and the Convex routes must agree on.
|
|
7
|
-
*
|
|
8
|
-
* IT IS DELIBERATELY PURE. Stage 2 adds the layers that belong here —
|
|
9
|
-
* `preconditions` (is this request answerable against the composition) and
|
|
10
|
-
* `describe` (assemble geometry / layers / etag) — both `f(request, state)` with
|
|
11
|
-
* no I/O. Nothing effectful goes in this package: Convex runs it inside a V8
|
|
12
|
-
* isolate, and the whole reason the pure layers can be shared while the
|
|
13
|
-
* orchestration cannot is that pure functions degrade gracefully when the two
|
|
14
|
-
* independently-deployed artifacts skew.
|
|
15
|
-
*/
|
|
16
|
-
export * from "./conformance";
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AnimatedBarChart,
|
|
3
|
-
AnimatedLineChart,
|
|
4
|
-
DitherGradientBg,
|
|
5
|
-
DynamicGrid,
|
|
6
|
-
EcosystemConstellation,
|
|
7
|
-
InfiniteMarquee,
|
|
8
|
-
MeshGradientBg,
|
|
9
|
-
PerspectiveMarquee,
|
|
10
|
-
SilkFlowBg,
|
|
11
|
-
VectorField,
|
|
12
|
-
VolumetricRays,
|
|
13
|
-
catalog
|
|
14
|
-
} from "../chunk-E3KNUSFG.js";
|
|
15
|
-
import "../chunk-3OMURV6Q.js";
|
|
16
|
-
import "../chunk-ROV2ODWC.js";
|
|
17
|
-
import "../chunk-UVKRO5ER.js";
|
|
18
|
-
export {
|
|
19
|
-
AnimatedBarChart,
|
|
20
|
-
AnimatedLineChart,
|
|
21
|
-
DitherGradientBg,
|
|
22
|
-
DynamicGrid,
|
|
23
|
-
EcosystemConstellation,
|
|
24
|
-
InfiniteMarquee,
|
|
25
|
-
MeshGradientBg,
|
|
26
|
-
PerspectiveMarquee,
|
|
27
|
-
SilkFlowBg,
|
|
28
|
-
VectorField,
|
|
29
|
-
VolumetricRays,
|
|
30
|
-
catalog
|
|
31
|
-
};
|
|
32
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,398 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
fillStyle
|
|
3
|
-
} from "../chunk-HIWVFZVH.js";
|
|
4
|
-
import {
|
|
5
|
-
Marker
|
|
6
|
-
} from "../chunk-XHU3WBEI.js";
|
|
7
|
-
import {
|
|
8
|
-
wordPop
|
|
9
|
-
} from "../chunk-G2B3G4HK.js";
|
|
10
|
-
import {
|
|
11
|
-
TEXT_HI,
|
|
12
|
-
VIOLET
|
|
13
|
-
} from "../chunk-3OMURV6Q.js";
|
|
14
|
-
import "../chunk-UVKRO5ER.js";
|
|
15
|
-
|
|
16
|
-
// src/captions/Captions.tsx
|
|
17
|
-
import { useMemo } from "react";
|
|
18
|
-
import { AbsoluteFill, useCurrentFrame, useVideoConfig, interpolate, Easing } from "remotion";
|
|
19
|
-
import { fillTextBox } from "@remotion/layout-utils";
|
|
20
|
-
|
|
21
|
-
// src/captions/paginate.ts
|
|
22
|
-
import { createTikTokStyleCaptions } from "@remotion/captions";
|
|
23
|
-
function paginateCaptionSegments(segments, opts) {
|
|
24
|
-
const raw = [];
|
|
25
|
-
for (const words of segments) {
|
|
26
|
-
if (words.length === 0) continue;
|
|
27
|
-
const rc = words.map((word, i) => ({
|
|
28
|
-
text: i === 0 ? word.text : ` ${word.text}`,
|
|
29
|
-
startMs: word.startMs,
|
|
30
|
-
endMs: word.endMs,
|
|
31
|
-
timestampMs: null,
|
|
32
|
-
confidence: null
|
|
33
|
-
}));
|
|
34
|
-
const { pages } = createTikTokStyleCaptions({
|
|
35
|
-
captions: rc,
|
|
36
|
-
combineTokensWithinMilliseconds: opts.combineMs
|
|
37
|
-
});
|
|
38
|
-
for (const page of pages) raw.push(...splitPageToFit(page, opts.makeBox));
|
|
39
|
-
}
|
|
40
|
-
return assignTimeline(raw, opts.lingerMs);
|
|
41
|
-
}
|
|
42
|
-
function splitPageToFit(page, makeBox) {
|
|
43
|
-
const probe = makeBox();
|
|
44
|
-
if (page.tokens.every((t) => probe.add(t))) {
|
|
45
|
-
return [{ startMs: page.startMs, tokens: page.tokens }];
|
|
46
|
-
}
|
|
47
|
-
const groups = [];
|
|
48
|
-
let box = makeBox();
|
|
49
|
-
let cur = [];
|
|
50
|
-
for (const token of page.tokens) {
|
|
51
|
-
if (cur.length === 0) {
|
|
52
|
-
cur.push(token);
|
|
53
|
-
box.add(token);
|
|
54
|
-
} else if (box.add(token)) {
|
|
55
|
-
cur.push(token);
|
|
56
|
-
} else {
|
|
57
|
-
groups.push(cur);
|
|
58
|
-
box = makeBox();
|
|
59
|
-
cur = [token];
|
|
60
|
-
box.add(token);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
if (cur.length > 0) groups.push(cur);
|
|
64
|
-
return groups.map((tokens, i) => ({
|
|
65
|
-
startMs: i === 0 ? page.startMs : tokens[0].fromMs,
|
|
66
|
-
tokens
|
|
67
|
-
}));
|
|
68
|
-
}
|
|
69
|
-
function assignTimeline(raw, lingerMs) {
|
|
70
|
-
const merged = [];
|
|
71
|
-
for (const p of raw) {
|
|
72
|
-
const prev = merged[merged.length - 1];
|
|
73
|
-
if (prev && p.startMs <= prev.startMs) {
|
|
74
|
-
prev.tokens.push(...p.tokens);
|
|
75
|
-
} else {
|
|
76
|
-
merged.push({ startMs: p.startMs, tokens: [...p.tokens] });
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return merged.map((p, i) => {
|
|
80
|
-
const lastWordEnd = Math.max(...p.tokens.map((t) => t.toMs));
|
|
81
|
-
const cleared = lastWordEnd + lingerMs;
|
|
82
|
-
const endMs = i < merged.length - 1 ? Math.min(merged[i + 1].startMs, cleared) : cleared;
|
|
83
|
-
return {
|
|
84
|
-
text: p.tokens.map((t) => t.text).join(""),
|
|
85
|
-
startMs: p.startMs,
|
|
86
|
-
durationMs: Math.max(1, endMs - p.startMs),
|
|
87
|
-
tokens: p.tokens
|
|
88
|
-
};
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// src/captions/placement.ts
|
|
93
|
-
function resolveCaptionPlacement(position, region) {
|
|
94
|
-
const vertical = region ? { bottom: `${Math.max(0, (1 - (region.y + region.h)) * 100)}%` } : position === "top" ? { top: "8%" } : position === "center" ? { top: "50%", transform: "translateY(-50%)" } : { bottom: "10%" };
|
|
95
|
-
return {
|
|
96
|
-
position: "absolute",
|
|
97
|
-
left: 0,
|
|
98
|
-
right: 0,
|
|
99
|
-
display: "flex",
|
|
100
|
-
justifyContent: "center",
|
|
101
|
-
...vertical
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// src/captions/Captions.tsx
|
|
106
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
107
|
-
var DEFAULT_HIGHLIGHT_COLOR = TEXT_HI;
|
|
108
|
-
var DEFAULT_STYLE = {
|
|
109
|
-
// Fallback STACK, not a bare family: when the vendored Inter face fails to
|
|
110
|
-
// register (the loader swallows failures by design), the browser default is
|
|
111
|
-
// a SERIF — captions must never degrade past a system grotesk.
|
|
112
|
-
fontFamily: "Inter, 'Helvetica Neue', Helvetica, Arial, sans-serif",
|
|
113
|
-
fontSize: 5,
|
|
114
|
-
fontWeight: 600,
|
|
115
|
-
color: TEXT_HI,
|
|
116
|
-
highlightColor: DEFAULT_HIGHLIGHT_COLOR,
|
|
117
|
-
backgroundColor: "transparent",
|
|
118
|
-
position: "bottom",
|
|
119
|
-
textTransform: "none",
|
|
120
|
-
plate: "none",
|
|
121
|
-
entrance: "fade",
|
|
122
|
-
entranceMs: 220,
|
|
123
|
-
exitMs: 180
|
|
124
|
-
};
|
|
125
|
-
function plateStyleFor(kind, backgroundColor) {
|
|
126
|
-
if (kind === "glass") {
|
|
127
|
-
const glass = "blur(28px) saturate(135%)";
|
|
128
|
-
return {
|
|
129
|
-
backgroundColor: "rgba(20,23,31,0.13)",
|
|
130
|
-
backdropFilter: glass,
|
|
131
|
-
WebkitBackdropFilter: glass,
|
|
132
|
-
border: "1px solid rgba(255,255,255,0.32)"
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
if (kind === "solid") {
|
|
136
|
-
return {
|
|
137
|
-
// warm espresso scrim (palette.BG = #14100c → rgb 20,16,12) at plate alpha,
|
|
138
|
-
// not a cold pure-black — keeps the legibility opacity, drops the cold cast.
|
|
139
|
-
backgroundColor: backgroundColor && backgroundColor !== "transparent" ? backgroundColor : "rgba(20,16,12,0.62)"
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
return { backgroundColor: backgroundColor ?? "transparent" };
|
|
143
|
-
}
|
|
144
|
-
var COMBINE_TOKENS_MS = 1500;
|
|
145
|
-
var CAPTION_LINGER_MS = 600;
|
|
146
|
-
function addTokenToBox(box, token, fontFamily, fontSize, fontWeight, emphasis) {
|
|
147
|
-
const isEmp = emphasis?.emphasisSet.has(token.fromMs) ?? false;
|
|
148
|
-
const tokenSize = isEmp ? Math.round(fontSize * (emphasis?.emphasisScale ?? 1.2)) : fontSize;
|
|
149
|
-
const tokenWeight = isEmp ? emphasis?.emphasisFontWeight ?? 900 : fontWeight;
|
|
150
|
-
const tokenFamily = isEmp ? emphasis?.emphasisFontFamily ?? fontFamily : fontFamily;
|
|
151
|
-
return box.add({
|
|
152
|
-
text: token.text,
|
|
153
|
-
fontFamily: tokenFamily,
|
|
154
|
-
fontSize: tokenSize,
|
|
155
|
-
fontWeight: String(tokenWeight)
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
function makeBoxFactory(maxWidth, fontFamily, fontSize, fontWeight, emphasis) {
|
|
159
|
-
return () => {
|
|
160
|
-
const box = fillTextBox({ maxBoxWidth: maxWidth, maxLines: 3 });
|
|
161
|
-
return {
|
|
162
|
-
add: (token) => !addTokenToBox(box, token, fontFamily, fontSize, fontWeight, emphasis).exceedsBox
|
|
163
|
-
};
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
function layoutTokensIntoLines(tokens, maxWidth, fontFamily, fontSize, fontWeight, emphasis) {
|
|
167
|
-
const box = fillTextBox({ maxBoxWidth: maxWidth, maxLines: 3 });
|
|
168
|
-
const lines = [[]];
|
|
169
|
-
for (const token of tokens) {
|
|
170
|
-
const result = addTokenToBox(box, token, fontFamily, fontSize, fontWeight, emphasis);
|
|
171
|
-
if (result.newLine) {
|
|
172
|
-
lines.push([token]);
|
|
173
|
-
} else {
|
|
174
|
-
lines[lines.length - 1].push(token);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
return lines.filter((line) => line.length > 0);
|
|
178
|
-
}
|
|
179
|
-
function Captions({
|
|
180
|
-
segments,
|
|
181
|
-
style: userStyle,
|
|
182
|
-
region
|
|
183
|
-
}) {
|
|
184
|
-
const frame = useCurrentFrame();
|
|
185
|
-
const { fps, width, height } = useVideoConfig();
|
|
186
|
-
const style = { ...DEFAULT_STYLE, ...userStyle };
|
|
187
|
-
const emphasisScale = style.emphasisScale ?? 1.08;
|
|
188
|
-
const emphasisColor = style.emphasisColor ?? style.highlightColor;
|
|
189
|
-
const emphasisFontFamily = style.emphasisFontFamily;
|
|
190
|
-
const emphasisFontWeight = style.emphasisFontWeight ?? 800;
|
|
191
|
-
const emphasisTextTransform = style.emphasisTextTransform ?? style.textTransform;
|
|
192
|
-
const emphasisLetterSpacing = style.emphasisLetterSpacing ?? 0;
|
|
193
|
-
const emphasisFontStyle = style.emphasisFontStyle ?? "normal";
|
|
194
|
-
const entrance = style.entrance ?? "none";
|
|
195
|
-
const entranceFrames = Math.max(1, Math.round((style.entranceMs ?? 160) / 1e3 * fps));
|
|
196
|
-
const staggerFrames = Math.max(0, Math.round((style.entranceStaggerMs ?? 90) / 1e3 * fps));
|
|
197
|
-
const exitMs = style.exitMs ?? 0;
|
|
198
|
-
const emphasisPlate = style.emphasisPlate ?? false;
|
|
199
|
-
const plateColor = style.emphasisPlateColor ?? emphasisColor;
|
|
200
|
-
const plateTextColor = style.emphasisPlateTextColor ?? TEXT_HI;
|
|
201
|
-
const plateAltColor = style.emphasisPlateAltColor ?? plateColor;
|
|
202
|
-
const plateAltTextColor = style.emphasisPlateAltTextColor ?? plateTextColor;
|
|
203
|
-
const plateRadius = style.emphasisPlateRadius ?? 6;
|
|
204
|
-
const platePadX = style.emphasisPlatePadX ?? 0.16;
|
|
205
|
-
const platePadY = style.emphasisPlatePadY ?? 0.04;
|
|
206
|
-
const annotationColor = style.annotationColor ?? VIOLET;
|
|
207
|
-
const maxWidthPercent = style.maxWidthPercent ?? 80;
|
|
208
|
-
const plateStyle = plateStyleFor(style.plate ?? "glass", style.backgroundColor);
|
|
209
|
-
const fontSize = Math.round(height * (style.fontSize / 100));
|
|
210
|
-
const maxTextWidth = width * (maxWidthPercent / 100);
|
|
211
|
-
const { emphasisStartMs, annotateKind } = useMemo(() => {
|
|
212
|
-
const emph = /* @__PURE__ */ new Set();
|
|
213
|
-
const ann = /* @__PURE__ */ new Map();
|
|
214
|
-
for (const w of segments.flat()) {
|
|
215
|
-
if (w.emphasis) emph.add(w.startMs);
|
|
216
|
-
if (w.annotate) ann.set(w.startMs, w.annotate);
|
|
217
|
-
}
|
|
218
|
-
return { emphasisStartMs: emph, annotateKind: ann };
|
|
219
|
-
}, [segments]);
|
|
220
|
-
const emphasisLayout = useMemo(
|
|
221
|
-
() => emphasisStartMs.size > 0 ? { emphasisSet: emphasisStartMs, emphasisScale, emphasisFontFamily, emphasisFontWeight } : void 0,
|
|
222
|
-
[emphasisStartMs, emphasisScale, emphasisFontFamily, emphasisFontWeight]
|
|
223
|
-
);
|
|
224
|
-
const pages = useMemo(
|
|
225
|
-
() => paginateCaptionSegments(segments, {
|
|
226
|
-
combineMs: COMBINE_TOKENS_MS,
|
|
227
|
-
makeBox: makeBoxFactory(maxTextWidth, style.fontFamily, fontSize, style.fontWeight, emphasisLayout),
|
|
228
|
-
lingerMs: CAPTION_LINGER_MS
|
|
229
|
-
}),
|
|
230
|
-
[segments, maxTextWidth, fontSize, style.fontFamily, style.fontWeight, emphasisLayout]
|
|
231
|
-
);
|
|
232
|
-
if (pages.length === 0) return null;
|
|
233
|
-
const currentTimeMs = frame / fps * 1e3;
|
|
234
|
-
const currentPage = pages.find(
|
|
235
|
-
(p) => currentTimeMs >= p.startMs && currentTimeMs < p.startMs + p.durationMs
|
|
236
|
-
);
|
|
237
|
-
if (!currentPage) return null;
|
|
238
|
-
const activeToken = currentPage.tokens.find(
|
|
239
|
-
(t) => currentTimeMs >= t.fromMs && currentTimeMs < t.toMs
|
|
240
|
-
);
|
|
241
|
-
const tokenStartFrame = /* @__PURE__ */ new Map();
|
|
242
|
-
if (entrance !== "none") {
|
|
243
|
-
let minNext = -Infinity;
|
|
244
|
-
for (const t of currentPage.tokens) {
|
|
245
|
-
const s = Math.max(Math.round(t.fromMs / 1e3 * fps), minNext);
|
|
246
|
-
tokenStartFrame.set(t, s);
|
|
247
|
-
minNext = s + staggerFrames;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
const pageEnd = currentPage.startMs + currentPage.durationMs;
|
|
251
|
-
const groupOpacity = exitMs > 0 ? interpolate(currentTimeMs, [pageEnd - exitMs, pageEnd], [1, 0], {
|
|
252
|
-
extrapolateLeft: "clamp",
|
|
253
|
-
extrapolateRight: "clamp"
|
|
254
|
-
}) : 1;
|
|
255
|
-
const lines = layoutTokensIntoLines(
|
|
256
|
-
currentPage.tokens,
|
|
257
|
-
maxTextWidth,
|
|
258
|
-
style.fontFamily,
|
|
259
|
-
fontSize,
|
|
260
|
-
style.fontWeight,
|
|
261
|
-
emphasisLayout
|
|
262
|
-
);
|
|
263
|
-
const wrapperStyle = resolveCaptionPlacement(style.position, region);
|
|
264
|
-
return /* @__PURE__ */ jsx(AbsoluteFill, { style: { pointerEvents: "none" }, children: /* @__PURE__ */ jsx("div", { style: wrapperStyle, children: /* @__PURE__ */ jsx(
|
|
265
|
-
"div",
|
|
266
|
-
{
|
|
267
|
-
style: {
|
|
268
|
-
opacity: groupOpacity,
|
|
269
|
-
display: "flex",
|
|
270
|
-
flexDirection: "column",
|
|
271
|
-
alignItems: "center",
|
|
272
|
-
gap: `${fontSize * 0.25}px`,
|
|
273
|
-
padding: `${fontSize * 0.4}px ${fontSize * 0.8}px`,
|
|
274
|
-
borderRadius: fontSize * 0.5,
|
|
275
|
-
...plateStyle,
|
|
276
|
-
maxWidth: `${maxWidthPercent}%`,
|
|
277
|
-
boxSizing: "border-box"
|
|
278
|
-
},
|
|
279
|
-
children: (() => {
|
|
280
|
-
let plateIdx = 0;
|
|
281
|
-
const RISE_PX = fontSize * 0.4;
|
|
282
|
-
const easeOpacity = (start) => interpolate(frame, [start, start + entranceFrames], [0, 1], {
|
|
283
|
-
extrapolateLeft: "clamp",
|
|
284
|
-
extrapolateRight: "clamp",
|
|
285
|
-
easing: Easing.out(Easing.cubic)
|
|
286
|
-
});
|
|
287
|
-
const entranceOf = (first, isEmph) => {
|
|
288
|
-
if (entrance === "none") return { opacity: 1, scale: 1, y: 0 };
|
|
289
|
-
const start = tokenStartFrame.get(first) ?? 0;
|
|
290
|
-
if (entrance === "word-pop") {
|
|
291
|
-
const { opacity, scale } = wordPop(frame, fps, start, entranceFrames, isEmph ? 0.86 : 0.92);
|
|
292
|
-
return { opacity, scale, y: 0 };
|
|
293
|
-
}
|
|
294
|
-
if (entrance === "stagger-up") {
|
|
295
|
-
const y = interpolate(frame, [start, start + entranceFrames], [RISE_PX, 0], {
|
|
296
|
-
extrapolateLeft: "clamp",
|
|
297
|
-
extrapolateRight: "clamp",
|
|
298
|
-
easing: Easing.out(Easing.cubic)
|
|
299
|
-
});
|
|
300
|
-
return { opacity: easeOpacity(start), scale: 1, y };
|
|
301
|
-
}
|
|
302
|
-
if (entrance === "fade") {
|
|
303
|
-
return { opacity: easeOpacity(start), scale: 1, y: 0 };
|
|
304
|
-
}
|
|
305
|
-
return { opacity: 1, scale: 1, y: 0 };
|
|
306
|
-
};
|
|
307
|
-
return lines.map((line, lineIdx) => {
|
|
308
|
-
const segs = [];
|
|
309
|
-
for (const t of line) {
|
|
310
|
-
const e = emphasisStartMs.has(t.fromMs);
|
|
311
|
-
const last = segs[segs.length - 1];
|
|
312
|
-
if (emphasisPlate && e && last && last.emph) last.tokens.push(t);
|
|
313
|
-
else segs.push({ tokens: [t], emph: e });
|
|
314
|
-
}
|
|
315
|
-
return /* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "center", alignItems: "baseline", gap: `${fontSize * 0.35}px` }, children: segs.map((seg, si) => {
|
|
316
|
-
const first = seg.tokens[0];
|
|
317
|
-
const { opacity, scale, y } = entranceOf(first, seg.emph);
|
|
318
|
-
const entranceTransform = `translateY(${y}px) scale(${scale})`;
|
|
319
|
-
const annKind = seg.tokens.map((t) => annotateKind.get(t.fromMs)).find(Boolean);
|
|
320
|
-
let markerP = 1;
|
|
321
|
-
if (annKind && entrance !== "none") {
|
|
322
|
-
const ms = (tokenStartFrame.get(first) ?? 0) + Math.round(fps * 0.14);
|
|
323
|
-
markerP = interpolate(frame, [ms, ms + Math.round(fps * 0.32)], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
|
|
324
|
-
}
|
|
325
|
-
if (seg.emph && emphasisPlate) {
|
|
326
|
-
const idx = plateIdx++;
|
|
327
|
-
const bg = idx % 2 === 0 ? plateColor : plateAltColor;
|
|
328
|
-
const fg = idx % 2 === 0 ? plateTextColor : plateAltTextColor;
|
|
329
|
-
const efs = Math.round(fontSize * emphasisScale);
|
|
330
|
-
return /* @__PURE__ */ jsxs("span", { style: { position: "relative", display: "inline-block", opacity, transform: entranceTransform, transformOrigin: "center" }, children: [
|
|
331
|
-
/* @__PURE__ */ jsx(
|
|
332
|
-
"span",
|
|
333
|
-
{
|
|
334
|
-
style: {
|
|
335
|
-
display: "inline-block",
|
|
336
|
-
background: bg,
|
|
337
|
-
color: fg,
|
|
338
|
-
borderRadius: plateRadius,
|
|
339
|
-
padding: `${Math.round(efs * platePadY)}px ${Math.round(efs * platePadX)}px`,
|
|
340
|
-
fontFamily: emphasisFontFamily ?? style.fontFamily,
|
|
341
|
-
fontSize: efs,
|
|
342
|
-
fontWeight: emphasisFontWeight,
|
|
343
|
-
fontStyle: emphasisFontStyle,
|
|
344
|
-
textTransform: emphasisTextTransform,
|
|
345
|
-
letterSpacing: emphasisLetterSpacing ? `${emphasisLetterSpacing}px` : void 0,
|
|
346
|
-
lineHeight: 1,
|
|
347
|
-
whiteSpace: "nowrap"
|
|
348
|
-
},
|
|
349
|
-
children: seg.tokens.map((t) => t.text.trim()).join(" ")
|
|
350
|
-
}
|
|
351
|
-
),
|
|
352
|
-
annKind ? /* @__PURE__ */ jsx(Marker, { spec: { kind: annKind, color: annotationColor }, progress: markerP }) : null
|
|
353
|
-
] }, si);
|
|
354
|
-
}
|
|
355
|
-
const token = first;
|
|
356
|
-
const isActive = token === activeToken;
|
|
357
|
-
const isEmphasis = seg.emph;
|
|
358
|
-
const tokenFontSize = isEmphasis ? Math.round(fontSize * emphasisScale) : fontSize;
|
|
359
|
-
const tokenWeight = isEmphasis ? emphasisFontWeight : style.fontWeight;
|
|
360
|
-
const tokenFamily = isEmphasis ? emphasisFontFamily ?? style.fontFamily : style.fontFamily;
|
|
361
|
-
const tokenTransform = isEmphasis ? emphasisTextTransform : style.textTransform;
|
|
362
|
-
const tokenLetterSpacing = isEmphasis && emphasisLetterSpacing ? `${emphasisLetterSpacing}px` : void 0;
|
|
363
|
-
const tokenFontStyle = isEmphasis ? emphasisFontStyle : "normal";
|
|
364
|
-
let tokenColor = style.color;
|
|
365
|
-
if (isActive && !emphasisPlate) tokenColor = style.highlightColor;
|
|
366
|
-
else if (isEmphasis) tokenColor = emphasisColor;
|
|
367
|
-
const gradientFill = isEmphasis && style.emphasisGradient ? fillStyle({ kind: "gradient", value: style.emphasisGradient }) : {};
|
|
368
|
-
const inner = /* @__PURE__ */ jsx(
|
|
369
|
-
"span",
|
|
370
|
-
{
|
|
371
|
-
style: {
|
|
372
|
-
fontFamily: tokenFamily,
|
|
373
|
-
fontSize: tokenFontSize,
|
|
374
|
-
fontWeight: tokenWeight,
|
|
375
|
-
fontStyle: tokenFontStyle,
|
|
376
|
-
color: tokenColor,
|
|
377
|
-
textTransform: tokenTransform,
|
|
378
|
-
letterSpacing: tokenLetterSpacing,
|
|
379
|
-
display: "inline-block",
|
|
380
|
-
...gradientFill
|
|
381
|
-
},
|
|
382
|
-
children: emphasisPlate ? token.text.trim() : token.text
|
|
383
|
-
}
|
|
384
|
-
);
|
|
385
|
-
return /* @__PURE__ */ jsxs("span", { style: { position: "relative", display: "inline-block", opacity, transform: entranceTransform, transformOrigin: "center" }, children: [
|
|
386
|
-
inner,
|
|
387
|
-
annKind ? /* @__PURE__ */ jsx(Marker, { spec: { kind: annKind, color: annotationColor }, progress: markerP }) : null
|
|
388
|
-
] }, si);
|
|
389
|
-
}) }, lineIdx);
|
|
390
|
-
});
|
|
391
|
-
})()
|
|
392
|
-
}
|
|
393
|
-
) }) });
|
|
394
|
-
}
|
|
395
|
-
export {
|
|
396
|
-
Captions
|
|
397
|
-
};
|
|
398
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/captions/Captions.tsx","../../src/captions/paginate.ts","../../src/captions/placement.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport { AbsoluteFill, useCurrentFrame, useVideoConfig, interpolate, Easing } from 'remotion';\nimport { fillTextBox } from '@remotion/layout-utils';\nimport type { TikTokToken } from '@remotion/captions';\nimport type { CaptionWord, CaptionStyle } from '@cueframe/core/render';\nimport { paginateCaptionSegments, type FitBox } from './paginate';\nimport { resolveCaptionPlacement } from './placement';\nimport { Marker } from '../lib/text/marker';\nimport { fillStyle } from '../lib/text/fill';\nimport { wordPop } from '../lib/text/motion';\nimport * as palette from '../lib/palette';\n\n/**\n * Default highlight color for the active word. A warm off-white — the default\n * look does not karaoke-color the spoken word; the word-fade entrance already\n * carries the sync signal. A brand kit's `captionStyle.highlightColor` overrides\n * it (the gold `#E6B450` treatment is now a kit choice, not the floor).\n */\nconst DEFAULT_HIGHLIGHT_COLOR = palette.TEXT_HI;\n\n// Default-look change 2026-07-15: the launch-film clean default replaced the\n// TikTok/Hormozi glass+gold default — plateless white, word-fade entrance,\n// NO text shadow. Captions carry legibility through size and weight;\n// the ONE opt-in legibility device is `plate: 'glass' | 'solid'` (a style /\n// brand-captionProfile choice), never a baked-in shadow. Brand captionProfiles\n// override everything here.\nconst DEFAULT_STYLE: CaptionStyle = {\n // Fallback STACK, not a bare family: when the vendored Inter face fails to\n // register (the loader swallows failures by design), the browser default is\n // a SERIF — captions must never degrade past a system grotesk.\n fontFamily: \"Inter, 'Helvetica Neue', Helvetica, Arial, sans-serif\",\n fontSize: 5,\n fontWeight: 600,\n color: palette.TEXT_HI,\n highlightColor: DEFAULT_HIGHLIGHT_COLOR,\n backgroundColor: 'transparent',\n position: 'bottom',\n textTransform: 'none',\n plate: 'none',\n entrance: 'fade',\n entranceMs: 220,\n exitMs: 180,\n};\n\n/** Caption backdrop-plate treatments. The plate is the caption block's OWN\n * background, so it renders ONLY while a caption is on-screen — it cannot paint\n * during caption-less moments (a title-card open, an inter-sentence pause). This\n * replaces the retired per-frame legibility scrim.\n * - glass: a frosted backdrop-blur pill; footage reads through (tint 0.13 +\n * 28px blur + a hairline light edge). The blur + the text shadow\n * do the legibility work, so the tint stays light.\n * - solid: an opaque dark plate (uses a custom backgroundColor if set).\n * - none: transparent; captions rely on the text shadow (a deliberate opt-out —\n * legible only on controlled/dark backdrops). */\nfunction plateStyleFor(kind: 'glass' | 'solid' | 'none', backgroundColor: string): React.CSSProperties {\n if (kind === 'glass') {\n const glass = 'blur(28px) saturate(135%)';\n return {\n backgroundColor: 'rgba(20,23,31,0.13)',\n backdropFilter: glass,\n WebkitBackdropFilter: glass,\n border: '1px solid rgba(255,255,255,0.32)',\n };\n }\n if (kind === 'solid') {\n return {\n // warm espresso scrim (palette.BG = #14100c → rgb 20,16,12) at plate alpha,\n // not a cold pure-black — keeps the legibility opacity, drops the cold cast.\n backgroundColor: backgroundColor && backgroundColor !== 'transparent' ? backgroundColor : 'rgba(20,16,12,0.62)',\n };\n }\n // 'none' — honor an explicit custom backgroundColor, else fully transparent.\n return { backgroundColor: backgroundColor ?? 'transparent' };\n}\n\n// Group words into pages of ~1.5s each — long enough to read comfortably,\n// short enough to stay in sync with speech.\nconst COMBINE_TOKENS_MS = 1500;\n\n// How long a caption lingers past its last spoken word before clearing. Bridges\n// the sub-second gaps between pages WITHIN speech (no blink) while still clearing\n// during the multi-second silences between sentences (no frozen fragment).\nconst CAPTION_LINGER_MS = 600;\n\n/** Per-token emphasis info for accurate layout measurement. */\ninterface EmphasisLayout {\n emphasisSet: Set<number>;\n emphasisScale: number;\n emphasisFontFamily?: string;\n emphasisFontWeight: number;\n}\n\n/** Add one token to a fillTextBox with emphasis-aware sizing — the single\n * measurement both line-wrapping (`layoutTokensIntoLines`) and page-fit\n * testing (`makeBoxFactory`) share, so pagination and layout never disagree. */\nfunction addTokenToBox(\n box: ReturnType<typeof fillTextBox>,\n token: TikTokToken,\n fontFamily: string,\n fontSize: number,\n fontWeight: number,\n emphasis?: EmphasisLayout,\n): ReturnType<ReturnType<typeof fillTextBox>['add']> {\n const isEmp = emphasis?.emphasisSet.has(token.fromMs) ?? false;\n const tokenSize = isEmp ? Math.round(fontSize * (emphasis?.emphasisScale ?? 1.2)) : fontSize;\n const tokenWeight = isEmp ? (emphasis?.emphasisFontWeight ?? 900) : fontWeight;\n const tokenFamily = isEmp ? (emphasis?.emphasisFontFamily ?? fontFamily) : fontFamily;\n return box.add({\n text: token.text,\n fontFamily: tokenFamily,\n fontSize: tokenSize,\n fontWeight: String(tokenWeight),\n });\n}\n\n/** A `FitBox` factory for `paginateCaptionSegments`: each call returns a fresh\n * incremental 3-line box whose `add(token)` reports whether the box still fits\n * with that token appended. Sharing `addTokenToBox` keeps pagination's fit\n * decision identical to `layoutTokensIntoLines`' wrapping. */\nfunction makeBoxFactory(\n maxWidth: number,\n fontFamily: string,\n fontSize: number,\n fontWeight: number,\n emphasis?: EmphasisLayout,\n): () => FitBox {\n return () => {\n const box = fillTextBox({ maxBoxWidth: maxWidth, maxLines: 3 });\n return {\n add: (token: TikTokToken) =>\n !addTokenToBox(box, token, fontFamily, fontSize, fontWeight, emphasis).exceedsBox,\n };\n };\n}\n\n/** Split tokens into measured lines using fillTextBox for proper word wrapping.\n * Pagination guarantees the page fits 3 lines, so no token is dropped here. */\nfunction layoutTokensIntoLines(\n tokens: TikTokToken[],\n maxWidth: number,\n fontFamily: string,\n fontSize: number,\n fontWeight: number,\n emphasis?: EmphasisLayout,\n): TikTokToken[][] {\n const box = fillTextBox({ maxBoxWidth: maxWidth, maxLines: 3 });\n const lines: TikTokToken[][] = [[]];\n\n for (const token of tokens) {\n const result = addTokenToBox(box, token, fontFamily, fontSize, fontWeight, emphasis);\n\n if (result.newLine) {\n lines.push([token]);\n } else {\n lines[lines.length - 1].push(token);\n }\n }\n\n return lines.filter((line) => line.length > 0);\n}\n\n/**\n * TikTok/Hormozi-style word-level captions layer.\n *\n * Drives `@remotion/captions`'s `createTikTokStyleCaptions` with a\n * pre-timed word stream, paginates ~1.5s at a time, highlights the\n * active token, and applies per-token emphasis (separate font/scale/\n * color/weight) when `CaptionWord.emphasis` is set.\n *\n * Fonts are NOT loaded by this component — the caller (editor's\n * `Root.tsx` or the worker render bundle's bootstrap) is responsible\n * for ensuring `style.fontFamily` is loaded before the bundle renders.\n */\nexport function Captions({\n segments,\n style: userStyle,\n region,\n}: {\n /**\n * Authored caption SEGMENTS. Each segment is a hard caption-page boundary:\n * pagination runs within a segment and never pools words across two, so\n * sentence-bounded segments cut captions at sentence ends.\n */\n segments: CaptionWord[][];\n style?: Partial<CaptionStyle>;\n /**\n * Floor-resolved caption band (output fractions). When set, the caption sits\n * with its BOTTOM edge at `region.y + region.h` — i.e. clear of the platform's\n * bottom-UI strip — instead of the fixed `style.position` offset. Horizontal\n * stays centred (the short-form convention); only the vertical clearance is\n * taken from the floor. See composition-model `resolveCaptionRegion`.\n */\n region?: { y: number; h: number };\n}) {\n const frame = useCurrentFrame();\n const { fps, width, height } = useVideoConfig();\n const style = { ...DEFAULT_STYLE, ...userStyle };\n // Emphasis defaults punch by WEIGHT, barely by size (launch-film default —\n // the 900/1.2 pop is a kit choice via captionProfile, not the floor).\n const emphasisScale = style.emphasisScale ?? 1.08;\n const emphasisColor = style.emphasisColor ?? style.highlightColor;\n const emphasisFontFamily = style.emphasisFontFamily;\n const emphasisFontWeight = style.emphasisFontWeight ?? 800;\n const emphasisTextTransform = style.emphasisTextTransform ?? style.textTransform;\n const emphasisLetterSpacing = style.emphasisLetterSpacing ?? 0;\n const emphasisFontStyle = style.emphasisFontStyle ?? 'normal';\n const entrance = style.entrance ?? 'none';\n const entranceFrames = Math.max(1, Math.round(((style.entranceMs ?? 160) / 1000) * fps));\n const staggerFrames = Math.max(0, Math.round(((style.entranceStaggerMs ?? 90) / 1000) * fps));\n const exitMs = style.exitMs ?? 0;\n const emphasisPlate = style.emphasisPlate ?? false;\n const plateColor = style.emphasisPlateColor ?? emphasisColor;\n const plateTextColor = style.emphasisPlateTextColor ?? palette.TEXT_HI;\n const plateAltColor = style.emphasisPlateAltColor ?? plateColor;\n const plateAltTextColor = style.emphasisPlateAltTextColor ?? plateTextColor;\n const plateRadius = style.emphasisPlateRadius ?? 6;\n const platePadX = style.emphasisPlatePadX ?? 0.16;\n const platePadY = style.emphasisPlatePadY ?? 0.04;\n const annotationColor = style.annotationColor ?? palette.VIOLET;\n const maxWidthPercent = style.maxWidthPercent ?? 80;\n const plateStyle = plateStyleFor(style.plate ?? 'glass', style.backgroundColor);\n\n const fontSize = Math.round(height * (style.fontSize / 100));\n const maxTextWidth = width * (maxWidthPercent / 100);\n\n // Emphasis / annotation lookup maps (keyed by startMs === token.fromMs).\n // Frame-independent → memoized on `segments` so it runs once per render.\n const { emphasisStartMs, annotateKind } = useMemo(() => {\n const emph = new Set<number>();\n const ann = new Map<number, 'circle' | 'underline'>();\n for (const w of segments.flat()) {\n if (w.emphasis) emph.add(w.startMs);\n if (w.annotate) ann.set(w.startMs, w.annotate);\n }\n return { emphasisStartMs: emph, annotateKind: ann };\n }, [segments]);\n\n const emphasisLayout: EmphasisLayout | undefined = useMemo(\n () =>\n emphasisStartMs.size > 0\n ? { emphasisSet: emphasisStartMs, emphasisScale, emphasisFontFamily, emphasisFontWeight }\n : undefined,\n [emphasisStartMs, emphasisScale, emphasisFontFamily, emphasisFontWeight],\n );\n\n // Paginate PER SEGMENT (segment = hard page break) into TikTok-style pages,\n // splitting an over-dense page into sub-pages (never dropping words) and\n // stitching the track contiguous so captions linger through inter-sentence\n // pauses. Memoized on the frame-independent inputs so the fillTextBox\n // measurement runs ONCE per render instead of on every frame.\n const pages = useMemo(\n () =>\n paginateCaptionSegments(segments, {\n combineMs: COMBINE_TOKENS_MS,\n makeBox: makeBoxFactory(maxTextWidth, style.fontFamily, fontSize, style.fontWeight, emphasisLayout),\n lingerMs: CAPTION_LINGER_MS,\n }),\n [segments, maxTextWidth, fontSize, style.fontFamily, style.fontWeight, emphasisLayout],\n );\n\n if (pages.length === 0) return null;\n\n // Find the current page based on frame time\n const currentTimeMs = (frame / fps) * 1000;\n const currentPage = pages.find(\n (p) => currentTimeMs >= p.startMs && currentTimeMs < p.startMs + p.durationMs\n );\n if (!currentPage) return null;\n\n // Find active token\n const activeToken = currentPage.tokens.find(\n (t) => currentTimeMs >= t.fromMs && currentTimeMs < t.toMs\n );\n\n // Per-word entrance: each token enters on its own spoken beat, with a minimum\n // stagger so two words never pop together. Map token → global start frame.\n const tokenStartFrame = new Map<TikTokToken, number>();\n if (entrance !== 'none') {\n let minNext = -Infinity;\n for (const t of currentPage.tokens) {\n const s = Math.max(Math.round((t.fromMs / 1000) * fps), minNext);\n tokenStartFrame.set(t, s);\n minNext = s + staggerFrames;\n }\n }\n\n // Phrase exit: fade the whole group over the page's last `exitMs` before the\n // next page builds fresh (a clean cut when exitMs is 0).\n const pageEnd = currentPage.startMs + currentPage.durationMs;\n const groupOpacity =\n exitMs > 0\n ? interpolate(currentTimeMs, [pageEnd - exitMs, pageEnd], [1, 0], {\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n })\n : 1;\n\n // Wrap tokens into measured lines (emphasis-aware sizing). Pagination already\n // guaranteed this page fits 3 lines, so no token is dropped.\n const lines = layoutTokensIntoLines(\n currentPage.tokens,\n maxTextWidth,\n style.fontFamily,\n fontSize,\n style.fontWeight,\n emphasisLayout,\n );\n\n // Placement. A full-width, structurally-centred band anchored vertically by the\n // floor-resolved `region` (else the style.position preset) — see\n // resolveCaptionPlacement. Horizontal centring lives on the WRAPPER\n // (justifyContent), NOT on the content box, so it can never depend on the\n // content's shrink-to-fit width and the content box's `maxWidth` binds against\n // the FULL frame (matching the pagination measurement, `maxTextWidth`).\n const wrapperStyle = resolveCaptionPlacement(style.position, region);\n\n return (\n <AbsoluteFill style={{ pointerEvents: 'none' }}>\n <div style={wrapperStyle}>\n <div\n style={{\n opacity: groupOpacity,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: `${fontSize * 0.25}px`,\n padding: `${fontSize * 0.4}px ${fontSize * 0.8}px`,\n borderRadius: fontSize * 0.5,\n ...plateStyle,\n maxWidth: `${maxWidthPercent}%`,\n boxSizing: 'border-box',\n }}\n >\n {(() => {\n // plate colour alternates per emphasis run across the whole caption\n let plateIdx = 0;\n // Per-run entrance on the run's first spoken beat. The brand's motion\n // identity selects the treatment; all three share the per-word stagger\n // scaffold above (tokenStartFrame), differing only in the transform:\n // 'word-pop' — cubic-fade opacity + spring scale-settle.\n // 'fade' — cubic-fade opacity only.\n // 'stagger-up' — cubic-fade opacity + upward translate.\n // 'none' — static (handled by the `entrance === 'none'` guard).\n // SOFT: an unknown entrance falls through to the calibrated default\n // (static), never throws.\n const RISE_PX = fontSize * 0.4;\n const easeOpacity = (start: number) =>\n interpolate(frame, [start, start + entranceFrames], [0, 1], {\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n easing: Easing.out(Easing.cubic),\n });\n const entranceOf = (\n first: TikTokToken,\n isEmph: boolean,\n ): { opacity: number; scale: number; y: number } => {\n if (entrance === 'none') return { opacity: 1, scale: 1, y: 0 };\n const start = tokenStartFrame.get(first) ?? 0;\n if (entrance === 'word-pop') {\n const { opacity, scale } = wordPop(frame, fps, start, entranceFrames, isEmph ? 0.86 : 0.92);\n return { opacity, scale, y: 0 };\n }\n if (entrance === 'stagger-up') {\n const y = interpolate(frame, [start, start + entranceFrames], [RISE_PX, 0], {\n extrapolateLeft: 'clamp',\n extrapolateRight: 'clamp',\n easing: Easing.out(Easing.cubic),\n });\n return { opacity: easeOpacity(start), scale: 1, y };\n }\n if (entrance === 'fade') {\n return { opacity: easeOpacity(start), scale: 1, y: 0 };\n }\n // Unknown entrance → calibrated default (no animation).\n return { opacity: 1, scale: 1, y: 0 };\n };\n return lines.map((line, lineIdx) => {\n // group contiguous emphasis tokens into one plated run (so e.g.\n // \"One Zuck\" shares a single plate); everything else is its own run.\n const segs: { tokens: TikTokToken[]; emph: boolean }[] = [];\n for (const t of line) {\n const e = emphasisStartMs.has(t.fromMs);\n const last = segs[segs.length - 1];\n if (emphasisPlate && e && last && last.emph) last.tokens.push(t);\n else segs.push({ tokens: [t], emph: e });\n }\n return (\n <div key={lineIdx} style={{ display: 'flex', justifyContent: 'center', alignItems: 'baseline', gap: `${fontSize * 0.35}px` }}>\n {segs.map((seg, si) => {\n const first = seg.tokens[0];\n const { opacity, scale, y } = entranceOf(first, seg.emph);\n const entranceTransform = `translateY(${y}px) scale(${scale})`;\n const annKind = seg.tokens.map((t) => annotateKind.get(t.fromMs)).find(Boolean);\n let markerP = 1;\n if (annKind && entrance !== 'none') {\n const ms = (tokenStartFrame.get(first) ?? 0) + Math.round(fps * 0.14);\n markerP = interpolate(frame, [ms, ms + Math.round(fps * 0.32)], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });\n }\n\n // emphasis run on a highlighter plate\n if (seg.emph && emphasisPlate) {\n const idx = plateIdx++;\n const bg = idx % 2 === 0 ? plateColor : plateAltColor;\n const fg = idx % 2 === 0 ? plateTextColor : plateAltTextColor;\n const efs = Math.round(fontSize * emphasisScale);\n return (\n <span key={si} style={{ position: 'relative', display: 'inline-block', opacity, transform: entranceTransform, transformOrigin: 'center' }}>\n <span\n style={{\n display: 'inline-block',\n background: bg,\n color: fg,\n borderRadius: plateRadius,\n padding: `${Math.round(efs * platePadY)}px ${Math.round(efs * platePadX)}px`,\n fontFamily: emphasisFontFamily ?? style.fontFamily,\n fontSize: efs,\n fontWeight: emphasisFontWeight,\n fontStyle: emphasisFontStyle,\n textTransform: emphasisTextTransform,\n letterSpacing: emphasisLetterSpacing ? `${emphasisLetterSpacing}px` : undefined,\n lineHeight: 1.0,\n whiteSpace: 'nowrap',\n }}\n >\n {seg.tokens.map((t) => t.text.trim()).join(' ')}\n </span>\n {annKind ? <Marker spec={{ kind: annKind, color: annotationColor }} progress={markerP} /> : null}\n </span>\n );\n }\n\n // plain token (connective, or emphasis when plates are off)\n const token = first;\n const isActive = token === activeToken;\n const isEmphasis = seg.emph;\n const tokenFontSize = isEmphasis ? Math.round(fontSize * emphasisScale) : fontSize;\n const tokenWeight = isEmphasis ? emphasisFontWeight : style.fontWeight;\n const tokenFamily = isEmphasis ? (emphasisFontFamily ?? style.fontFamily) : style.fontFamily;\n const tokenTransform = isEmphasis ? emphasisTextTransform : style.textTransform;\n const tokenLetterSpacing = isEmphasis && emphasisLetterSpacing ? `${emphasisLetterSpacing}px` : undefined;\n const tokenFontStyle = isEmphasis ? emphasisFontStyle : 'normal';\n let tokenColor = style.color;\n if (isActive && !emphasisPlate) tokenColor = style.highlightColor;\n else if (isEmphasis) tokenColor = emphasisColor;\n // 'gradient' fill axis: emphasis text painted with a CSS gradient (bg-clip-text)\n const gradientFill: React.CSSProperties =\n isEmphasis && style.emphasisGradient\n ? fillStyle({ kind: 'gradient', value: style.emphasisGradient })\n : {};\n const inner = (\n <span\n style={{\n fontFamily: tokenFamily,\n fontSize: tokenFontSize,\n fontWeight: tokenWeight,\n fontStyle: tokenFontStyle,\n color: tokenColor,\n textTransform: tokenTransform,\n letterSpacing: tokenLetterSpacing,\n display: 'inline-block',\n ...gradientFill,\n }}\n >\n {emphasisPlate ? token.text.trim() : token.text}\n </span>\n );\n return (\n <span key={si} style={{ position: 'relative', display: 'inline-block', opacity, transform: entranceTransform, transformOrigin: 'center' }}>\n {inner}\n {annKind ? <Marker spec={{ kind: annKind, color: annotationColor }} progress={markerP} /> : null}\n </span>\n );\n })}\n </div>\n );\n });\n })()}\n </div>\n </div>\n </AbsoluteFill>\n );\n}\n","import { createTikTokStyleCaptions } from '@remotion/captions';\nimport type { Caption, TikTokPage, TikTokToken } from '@remotion/captions';\nimport type { CaptionWord } from '@cueframe/core/render';\n\n/** An incremental, stateful fit measurer: `add(token)` returns whether the\n * caption box still fits with that token appended. A fresh box starts empty.\n * Injected so the component measures with real `fillTextBox` font metrics while\n * tests stay deterministic — and so splitting measures each token ONCE\n * (O(n)) instead of re-measuring the whole prefix per token (O(n²)). */\nexport interface FitBox {\n add: (token: TikTokToken) => boolean;\n}\n\n/**\n * Turn authored caption SEGMENTS into renderable pages.\n *\n * Guarantees the old flat-paginate didn't make:\n * 1. **Segment boundaries are hard page breaks.** `createTikTokStyleCaptions`\n * runs PER SEGMENT, so a page never pools words across two segments.\n * Author sentence-bounded segments (`splitIntoSentences`) → captions cut at\n * sentence ends.\n * 2. **No word is dropped, no blank gaps.** A page too dense for the box is\n * split into sub-pages (not truncated), and the whole track is stitched\n * contiguous — each page lingers until the next begins, so captions don't\n * blink off during the pause between sentences (per-segment paging would\n * otherwise end each sentence at its last word). The final page ends at its\n * last word. Pages that would share a start time fold together rather than\n * producing a zero-duration (invisible) page.\n */\nexport function paginateCaptionSegments(\n segments: CaptionWord[][],\n opts: { combineMs: number; makeBox: () => FitBox; lingerMs: number },\n): TikTokPage[] {\n const raw: Array<{ startMs: number; tokens: TikTokToken[] }> = [];\n for (const words of segments) {\n if (words.length === 0) continue;\n // Prepend a space to every word but the segment's first so\n // createTikTokStyleCaptions detects word boundaries (it keys on\n // text.startsWith(' ')).\n const rc: Caption[] = words.map((word, i) => ({\n text: i === 0 ? word.text : ` ${word.text}`,\n startMs: word.startMs,\n endMs: word.endMs,\n timestampMs: null,\n confidence: null,\n }));\n const { pages } = createTikTokStyleCaptions({\n captions: rc,\n combineTokensWithinMilliseconds: opts.combineMs,\n });\n for (const page of pages) raw.push(...splitPageToFit(page, opts.makeBox));\n }\n return assignTimeline(raw, opts.lingerMs);\n}\n\n/**\n * Split one page into groups each satisfying the box, greedily and in O(n): one\n * incremental box is fed token-by-token; when a token would overflow, the group\n * closes and a fresh box starts with it. A single token that cannot fit on its\n * own is still emitted (a word is indivisible). Returns groups with only their\n * start time; durations are assigned globally in `assignTimeline`.\n */\nfunction splitPageToFit(\n page: TikTokPage,\n makeBox: () => FitBox,\n): Array<{ startMs: number; tokens: TikTokToken[] }> {\n // Fast path: the whole page fits.\n const probe = makeBox();\n if (page.tokens.every((t) => probe.add(t))) {\n return [{ startMs: page.startMs, tokens: page.tokens }];\n }\n\n const groups: TikTokToken[][] = [];\n let box = makeBox();\n let cur: TikTokToken[] = [];\n for (const token of page.tokens) {\n if (cur.length === 0) {\n cur.push(token);\n box.add(token); // place at least one token — a word is indivisible\n } else if (box.add(token)) {\n cur.push(token);\n } else {\n groups.push(cur);\n box = makeBox();\n cur = [token];\n box.add(token);\n }\n }\n if (cur.length > 0) groups.push(cur);\n\n return groups.map((tokens, i) => ({\n startMs: i === 0 ? page.startMs : tokens[0].fromMs,\n tokens,\n }));\n}\n\n/**\n * Lay raw pages onto a strictly-increasing timeline. Each page shows until\n * `lingerMs` after its last spoken word, capped at the next page's start:\n * - within speech (next page sooner than lastWord+lingerMs) → contiguous, no\n * blink between consecutive pages;\n * - across a long silent gap (next page later than lastWord+lingerMs) → the\n * caption CLEARS lingerMs after the last word instead of freezing the\n * fragment on screen for the whole multi-second pause;\n * - the final caption lingers lingerMs past its last word (no instant snap).\n * Pages that would share a start time fold together (two words at the same time\n * can't be shown sequentially) so no page is ever zero-duration.\n */\nfunction assignTimeline(\n raw: Array<{ startMs: number; tokens: TikTokToken[] }>,\n lingerMs: number,\n): TikTokPage[] {\n const merged: Array<{ startMs: number; tokens: TikTokToken[] }> = [];\n for (const p of raw) {\n const prev = merged[merged.length - 1];\n if (prev && p.startMs <= prev.startMs) {\n prev.tokens.push(...p.tokens);\n } else {\n merged.push({ startMs: p.startMs, tokens: [...p.tokens] });\n }\n }\n\n return merged.map((p, i) => {\n const lastWordEnd = Math.max(...p.tokens.map((t) => t.toMs));\n const cleared = lastWordEnd + lingerMs;\n const endMs = i < merged.length - 1 ? Math.min(merged[i + 1].startMs, cleared) : cleared;\n return {\n text: p.tokens.map((t) => t.text).join(''),\n startMs: p.startMs,\n durationMs: Math.max(1, endMs - p.startMs),\n tokens: p.tokens,\n };\n });\n}\n","/**\n * Caption container PLACEMENT — pure, render-harness-free CSS math.\n *\n * The caption block is centred horizontally and anchored vertically (a floor-\n * resolved `region`'s bottom edge, else the `style.position` preset). Kept in its\n * own module (no React/Remotion imports beyond the CSSProperties type) so the\n * placement is unit-testable without a render harness — mirrors the cardMotion.ts\n * / CropFromTrajectory pure-helper precedent.\n *\n * WHY A FULL-WIDTH WRAPPER (not `left:50% + translateX(-50%)` on the content box):\n * the old approach positioned the CONTENT box itself with `left:50%` and no\n * `width`/`right`, so its shrink-to-fit *available* width was capped at `100% −\n * left = 50%` of the frame. An authored `maxWidthPercent` above 50 was therefore\n * silently clamped to 50% — the box (and its plate) came out NARROWER than\n * authored while pagination still MEASURED text at the full `maxWidthPercent`\n * (`maxTextWidth = width * maxWidthPercent/100`), so wide phrases overflowed the\n * plate and the centring depended on the content's own width. This wrapper makes\n * horizontal centring STRUCTURAL (`left:0; right:0; justifyContent:center`), so it\n * is independent of the content width, and the content box's `maxWidth` now binds\n * against the FULL frame — matching the pagination measurement exactly.\n */\n\nimport type { CSSProperties } from 'react';\n\n/**\n * The absolutely-positioned, full-width, horizontally-centred band the caption\n * content box sits inside. Vertical anchor:\n * - `region` (floor-resolved) WINS: the band's BOTTOM edge sits at\n * `region.y + region.h` (clear of the platform bottom-UI strip).\n * - else the `position` preset: 'top' → 8% from top, 'center' → vertical\n * centre (translateY only — horizontal is structural), 'bottom'/default →\n * 10% from bottom.\n */\nexport function resolveCaptionPlacement(\n position: 'top' | 'center' | 'bottom' | undefined,\n region: { y: number; h: number } | undefined,\n): CSSProperties {\n const vertical: CSSProperties = region\n ? { bottom: `${Math.max(0, (1 - (region.y + region.h)) * 100)}%` }\n : position === 'top'\n ? { top: '8%' }\n : position === 'center'\n ? { top: '50%', transform: 'translateY(-50%)' }\n : { bottom: '10%' };\n return {\n position: 'absolute',\n left: 0,\n right: 0,\n display: 'flex',\n justifyContent: 'center',\n ...vertical,\n };\n}\n"],"mappings":"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","names":[]}
|