@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,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Build a Set keyed by "poolItemId:sourceStart" for O(1) emphasis lookups.
|
|
3
|
-
* sourceStart is rounded to 3 decimal places to handle floating-point drift
|
|
4
|
-
* between transcript sources and stored emphasis data.
|
|
5
|
-
*/
|
|
6
|
-
export function buildEmphasisSet(emphasisWords) {
|
|
7
|
-
const set = new Set();
|
|
8
|
-
for (const w of emphasisWords) {
|
|
9
|
-
set.add(`${w.poolItemId}:${w.sourceStart.toFixed(3)}`);
|
|
10
|
-
}
|
|
11
|
-
return set;
|
|
12
|
-
}
|
|
13
|
-
/** Check if a word (by poolItemId + sourceStart) is in the emphasis set. */
|
|
14
|
-
export function isEmphasized(set, poolItemId, sourceStart) {
|
|
15
|
-
return set.has(`${poolItemId}:${sourceStart.toFixed(3)}`);
|
|
16
|
-
}
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reframe eval — the COMPOSED crop box per output frame.
|
|
3
|
-
*
|
|
4
|
-
* The eval target is the crop box the camera ACTUALLY lands on, in
|
|
5
|
-
* output-crop-normalized space — NOT the raw `centers`/`zoom_scale` of the
|
|
6
|
-
* trajectory JSON. Per the virtual-camera spec ("the composed (post-floor) crop
|
|
7
|
-
* is the eval target … zoom is two-layer"), the jitter / center-crop metrics
|
|
8
|
-
* sample the box `computeCropTransform` produces, so they measure what ships.
|
|
9
|
-
*
|
|
10
|
-
* Phase 0 samples the BASE camera path (the trajectory) — the floor yield is a
|
|
11
|
-
* separate, caption-driven layer with its own golden (Phase 4). The geometry
|
|
12
|
-
* below is the bake half of `computeCropTransform`
|
|
13
|
-
* (packages/execution/render-entry/src/CropFromTrajectory.tsx): crop-window size from
|
|
14
|
-
* `zoom_scale`, center from the per-frame `centers`, coverage-clamped so the
|
|
15
|
-
* window never runs past the source edge. We replicate it here (rather than
|
|
16
|
-
* import the renderer — execution must not depend on the Remotion bundle) and a
|
|
17
|
-
* test pins this replica against the renderer's published clamp behavior.
|
|
18
|
-
*
|
|
19
|
-
* Coordinate system: the crop box is expressed in SOURCE-NORMALIZED units —
|
|
20
|
-
* `cx,cy` ∈ [0,1] (window center vs source dims) and `w,h` ∈ [0,1] (window size
|
|
21
|
-
* as a fraction of the source). Frame-to-frame motion of THIS box is the camera
|
|
22
|
-
* motion; normalizing the per-component delta by the box's own size converts it
|
|
23
|
-
* to output-crop-normalized units (a half-window pan is the same number at any
|
|
24
|
-
* zoom — the zoom-invariant "held feel" the spec requires).
|
|
25
|
-
*/
|
|
26
|
-
import { aspectWhRatio } from '../deriveTrajectory';
|
|
27
|
-
/**
|
|
28
|
-
* Crop-window dimensions (source-normalized) for a given `zoom_scale` + output
|
|
29
|
-
* aspect — the bake half of `computeCropTransform`. The largest output-aspect
|
|
30
|
-
* rect that fits the source, scaled by the clamped zoom. No `faceScale` (the
|
|
31
|
-
* floor's caption-band yield) is applied here — Phase 0 samples the base path.
|
|
32
|
-
*/
|
|
33
|
-
export function cropWindowSize(srcW, srcH, zoomScale, aspect) {
|
|
34
|
-
const outAR = aspectWhRatio(aspect);
|
|
35
|
-
const srcAR = srcW / srcH;
|
|
36
|
-
let cropW;
|
|
37
|
-
let cropH;
|
|
38
|
-
if (srcAR > outAR) {
|
|
39
|
-
cropH = srcH;
|
|
40
|
-
cropW = srcH * outAR;
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
cropW = srcW;
|
|
44
|
-
cropH = srcW / outAR;
|
|
45
|
-
}
|
|
46
|
-
// Mirror the renderer: zoom clamps to [0.4, 1.0] (CropFromTrajectory bakedZoom).
|
|
47
|
-
const bakedZoom = Math.max(0.4, Math.min(1.0, zoomScale));
|
|
48
|
-
cropW *= bakedZoom;
|
|
49
|
-
cropH *= bakedZoom;
|
|
50
|
-
return { w: cropW / srcW, h: cropH / srcH };
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Coverage-clamp a window center so the crop window stays fully inside the
|
|
54
|
-
* source — the geometric invariant `computeCropTransform` enforces via
|
|
55
|
-
* `tx = clamp(…)`, expressed here directly on the source-normalized center.
|
|
56
|
-
* A window of width `w` can have its center range over `[w/2, 1 - w/2]`.
|
|
57
|
-
*/
|
|
58
|
-
function clampCenter(c, sizeFrac) {
|
|
59
|
-
const half = sizeFrac / 2;
|
|
60
|
-
if (sizeFrac >= 1)
|
|
61
|
-
return 0.5; // window covers the whole axis → centered
|
|
62
|
-
return Math.max(half, Math.min(1 - half, c));
|
|
63
|
-
}
|
|
64
|
-
/** The composed crop box for one frame of one segment. */
|
|
65
|
-
export function cropBoxForFrame(seg, frameInSeg, srcW, srcH, aspect) {
|
|
66
|
-
// Eased segments carry a per-frame `zooms`; otherwise the scalar `zoom_scale`.
|
|
67
|
-
const zoom = seg.zooms ? seg.zooms[Math.min(frameInSeg, seg.zooms.length - 1)] : seg.zoom_scale;
|
|
68
|
-
const { w, h } = cropWindowSize(srcW, srcH, zoom, aspect);
|
|
69
|
-
const center = seg.centers[Math.min(frameInSeg, seg.centers.length - 1)] ?? [0.5, 0.5];
|
|
70
|
-
return {
|
|
71
|
-
cx: clampCenter(center[0], w),
|
|
72
|
-
cy: clampCenter(center[1], h),
|
|
73
|
-
w,
|
|
74
|
-
h,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Flatten a `TrajectoryData` to the per-output-frame composed crop-box series
|
|
79
|
-
* over all its segments, in order. This is the series the jitter metric walks.
|
|
80
|
-
*/
|
|
81
|
-
export function cropBoxSeries(traj) {
|
|
82
|
-
const out = [];
|
|
83
|
-
for (const seg of traj.segments) {
|
|
84
|
-
const n = seg.centers.length;
|
|
85
|
-
for (let i = 0; i < n; i++) {
|
|
86
|
-
out.push(cropBoxForFrame(seg, i, traj.src_w, traj.src_h, traj.aspect));
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return out;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* The STATIC center-crop baseline a content-aware reframe MUST beat on
|
|
93
|
-
* smoothness: the same per-segment `zoom_scale` (so the only variable is WHERE
|
|
94
|
-
* the camera points), but the center pinned to source-center every frame
|
|
95
|
-
* (coverage-clamped, which for a centered window is a no-op). A static crop has
|
|
96
|
-
* zero pan jitter by construction — its only frame-to-frame motion is the
|
|
97
|
-
* per-shot `zoom_scale` steps the algorithm itself authors. The reframe is
|
|
98
|
-
* "adding jitter for nothing" if it cannot beat THIS.
|
|
99
|
-
*/
|
|
100
|
-
export function centerCropBoxSeries(traj) {
|
|
101
|
-
const out = [];
|
|
102
|
-
for (const seg of traj.segments) {
|
|
103
|
-
const n = seg.centers.length;
|
|
104
|
-
for (let i = 0; i < n; i++) {
|
|
105
|
-
const zoom = seg.zooms ? seg.zooms[Math.min(i, seg.zooms.length - 1)] : seg.zoom_scale;
|
|
106
|
-
const { w, h } = cropWindowSize(traj.src_w, traj.src_h, zoom, traj.aspect);
|
|
107
|
-
out.push({ cx: 0.5, cy: 0.5, w, h });
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return out;
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* The RAW subject-centroid path baseline (the research bar): the per-frame
|
|
114
|
-
* `centers` the algorithm computed, BEFORE any smoothing/deadzone, composed into
|
|
115
|
-
* a crop box at the same per-segment zoom. A reframe must be SMOOTHER than the
|
|
116
|
-
* path it is smoothing. Phase 0 cannot reconstruct the pre-EMA centroid from the
|
|
117
|
-
* shipped trajectory (it only carries the smoothed `centers`), so this is a
|
|
118
|
-
* scaffold that returns the shipped centers; Phase 3 wires the true raw path via
|
|
119
|
-
* `eval/inclusion` + `eval/index` (keeping `emaSmooth` importable, per the
|
|
120
|
-
* spec's characterization gate).
|
|
121
|
-
*/
|
|
122
|
-
export function rawCentroidBoxSeries(traj) {
|
|
123
|
-
return cropBoxSeries(traj);
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Compose an arbitrary per-frame `centers` series (e.g. the raw tracking
|
|
127
|
-
* centroid, or the same centroid through the OLD `emaSmooth`) into a crop-box
|
|
128
|
-
* series at a fixed per-frame crop window — the Phase-3 "smoother than EMA"
|
|
129
|
-
* characterization baseline. `cropFor(frame)` gives the source-normalized window
|
|
130
|
-
* for that output frame (the same the shipping path uses), so the ONLY variable
|
|
131
|
-
* between ours and the baseline is the smoother. Centers are coverage-clamped
|
|
132
|
-
* exactly as the renderer clamps them.
|
|
133
|
-
*/
|
|
134
|
-
export function cropBoxSeriesFromCenters(centers, cropFor) {
|
|
135
|
-
return centers.map((c, i) => {
|
|
136
|
-
const { w, h } = cropFor(i);
|
|
137
|
-
return { cx: clampCenter(c[0], w), cy: clampCenter(c[1], h), w, h };
|
|
138
|
-
});
|
|
139
|
-
}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reframe eval — the INCLUSION metric (Phase 3 gate) + the shot-aware teleport
|
|
3
|
-
* and old-vs-new smoothness baselines.
|
|
4
|
-
*
|
|
5
|
-
* The Phase-2 gate (jitter ≤ center-crop) is the WRONG bar for a MOVING subject:
|
|
6
|
-
* a static center crop has jitter 0, but the subject walks out of frame. The
|
|
7
|
-
* camera that TRACKS the subject HAS motion (jitter > 0) and is CORRECT. So the
|
|
8
|
-
* Phase-3 gate is INCLUSION: the per-frame RequiredRegion (the padded subject/
|
|
9
|
-
* group box the crop must contain) must stay ⊆ the crop window. Our reframe must
|
|
10
|
-
* reach inclusionRate ≈ 1.0 on a moving subject (the camera tracks), and a
|
|
11
|
-
* static center-crop's inclusionRate must be materially LOWER (the subject walks
|
|
12
|
-
* out). See the virtual-camera spec, "Virtual-camera stability" + the Phase-3
|
|
13
|
-
* gate note.
|
|
14
|
-
*
|
|
15
|
-
* Pure, deterministic, no I/O. Replays the SAME `selectSubjectSet` +
|
|
16
|
-
* `regionsFromBoxes` the shipping all-faces derive uses, so the regions are
|
|
17
|
-
* EXACTLY the boxes the camera was obliged to contain.
|
|
18
|
-
*/
|
|
19
|
-
import { selectSubjectSet } from '../vcam/subjectSet';
|
|
20
|
-
import { buildRequiredRegions } from '../vcam/requiredRegion';
|
|
21
|
-
/** True iff the padded RequiredRegion is fully inside the crop box (the crop
|
|
22
|
-
* window contains the region — the subject stays in frame). */
|
|
23
|
-
export function regionInCrop(region, crop) {
|
|
24
|
-
const rx1 = region.cx - region.w / 2;
|
|
25
|
-
const rx2 = region.cx + region.w / 2;
|
|
26
|
-
const ry1 = region.cy - region.h / 2;
|
|
27
|
-
const ry2 = region.cy + region.h / 2;
|
|
28
|
-
const cx1 = crop.cx - crop.w / 2;
|
|
29
|
-
const cx2 = crop.cx + crop.w / 2;
|
|
30
|
-
const cy1 = crop.cy - crop.h / 2;
|
|
31
|
-
const cy2 = crop.cy + crop.h / 2;
|
|
32
|
-
// A tiny tolerance absorbs float noise at the exact edge (a region flush with
|
|
33
|
-
// the crop edge is contained, not out).
|
|
34
|
-
const eps = 1e-6;
|
|
35
|
-
return rx1 >= cx1 - eps && rx2 <= cx2 + eps && ry1 >= cy1 - eps && ry2 <= cy2 + eps;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* The per-frame RequiredRegions an `all-faces` camera was obliged to contain,
|
|
39
|
-
* over the WHOLE track window (one all-faces segment). Recomputes the shipping
|
|
40
|
-
* selection so the regions match the derive exactly. Null where no framed member
|
|
41
|
-
* is present (occlusion / gap) — those frames are EXCLUDED from inclusionRate
|
|
42
|
-
* (there's no subject to keep in frame).
|
|
43
|
-
*/
|
|
44
|
-
export function requiredRegionsForTrack(track) {
|
|
45
|
-
const cuts = new Set((track.shotBoundaries ?? []).filter((b) => b > 0));
|
|
46
|
-
const sel = selectSubjectSet(track.perFrameTracked, track.srcW, track.srcH, track.srcFps, new Map(Object.entries(track.perKeyframeSpeaker).map(([k, v]) => [Number(k), v])), cuts);
|
|
47
|
-
// Use the SAME canonical RequiredRegions the camera frames (pad + per-shot
|
|
48
|
-
// outlier reject) — the gate measures inclusion against exactly the region the
|
|
49
|
-
// derive was obliged to contain, so it can't be gamed by measuring a looser box.
|
|
50
|
-
return buildRequiredRegions(sel.perFrameBoxes, track.srcFps, cuts);
|
|
51
|
-
}
|
|
52
|
-
/** The all-faces `inclusionRate` for a crop-box series vs the per-frame
|
|
53
|
-
* RequiredRegions: the fraction of REGION-BEARING frames whose region is fully
|
|
54
|
-
* inside the crop. `1.0` ⇒ the subject never walks out of frame. Frames with no
|
|
55
|
-
* region (no subject present) are not counted. */
|
|
56
|
-
export function inclusionRate(regions, crops) {
|
|
57
|
-
let framesWithRegion = 0;
|
|
58
|
-
let contained = 0;
|
|
59
|
-
const n = Math.min(regions.length, crops.length);
|
|
60
|
-
for (let i = 0; i < n; i++) {
|
|
61
|
-
const r = regions[i];
|
|
62
|
-
if (r === null)
|
|
63
|
-
continue;
|
|
64
|
-
framesWithRegion++;
|
|
65
|
-
if (regionInCrop(r, crops[i]))
|
|
66
|
-
contained++;
|
|
67
|
-
}
|
|
68
|
-
return {
|
|
69
|
-
rate: framesWithRegion > 0 ? contained / framesWithRegion : 1,
|
|
70
|
-
framesWithRegion,
|
|
71
|
-
contained,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* The largest per-frame center step measured WITHIN trajectory segments (one per
|
|
76
|
-
* sub-shot), in output-crop-normalized units. Steps ACROSS a segment boundary
|
|
77
|
-
* (a detector shot cut) are EXCLUDED — a camera snap at a real cut is intended
|
|
78
|
-
* (the only reset), so it is not a "teleport". An intra-shot maxStep above the
|
|
79
|
-
* bar is the chase/teleport the gate guards against. `segLens` are the per-
|
|
80
|
-
* segment frame counts (so the walk knows where the cut-snaps are).
|
|
81
|
-
*/
|
|
82
|
-
export function intraShotMaxStep(crops, segLens) {
|
|
83
|
-
let max = 0;
|
|
84
|
-
let frame = 0;
|
|
85
|
-
for (const len of segLens) {
|
|
86
|
-
for (let i = 1; i < len; i++) {
|
|
87
|
-
const a = crops[frame + i - 1];
|
|
88
|
-
const b = crops[frame + i];
|
|
89
|
-
const step = Math.abs(b.cx - a.cx) / Math.max(b.w, 1e-6) + Math.abs(b.cy - a.cy) / Math.max(b.h, 1e-6);
|
|
90
|
-
if (step > max)
|
|
91
|
-
max = step;
|
|
92
|
-
}
|
|
93
|
-
frame += len;
|
|
94
|
-
}
|
|
95
|
-
return max;
|
|
96
|
-
}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reframe eval harness — the public surface for the metrics + the fixture-driven
|
|
3
|
-
* report. Pure TS, no Modal, no R2: every metric replays a cached `SubjectTrack`
|
|
4
|
-
* fixture through the REAL `deriveTrajectory` and measures the composed crop box.
|
|
5
|
-
* See the virtual-camera spec's "Eval / metrics / test harness (built FIRST)".
|
|
6
|
-
*
|
|
7
|
-
* Phase 0 shipped jitter + center-crop. Phase 3 adds the INCLUSION gate (the
|
|
8
|
-
* camera tracks a moving subject ⇒ region ⊆ crop) + the shot-aware teleport
|
|
9
|
-
* metric + the "smoother than the old EMA path" characterization, because pure
|
|
10
|
-
* jitter-beats-center-crop is the WRONG bar once the camera legitimately moves to
|
|
11
|
-
* track (a static center-crop has jitter 0 but loses a walking subject).
|
|
12
|
-
*/
|
|
13
|
-
import { deriveTrajectory, emaSmooth, cropWindowSizeFor, nearestKpValue } from '../deriveTrajectory';
|
|
14
|
-
import { cropBoxSeries, centerCropBoxSeries, rawCentroidBoxSeries, cropBoxSeriesFromCenters, } from './cropBox';
|
|
15
|
-
import { jitter } from './metrics';
|
|
16
|
-
import { requiredRegionsForTrack, inclusionRate, intraShotMaxStep, regionInCrop, } from './inclusion';
|
|
17
|
-
import { selectSubjectSet, selectSingleSubjectBoxes, } from '../vcam/subjectSet';
|
|
18
|
-
import { buildRequiredRegions } from '../vcam/requiredRegion';
|
|
19
|
-
import { segmentShots } from '../vcam/shots';
|
|
20
|
-
export { cropBoxSeries, centerCropBoxSeries, rawCentroidBoxSeries, cropBoxSeriesFromCenters, cropWindowSize, cropBoxForFrame, } from './cropBox';
|
|
21
|
-
export { jitter, iou, mIoU } from './metrics';
|
|
22
|
-
export { requiredRegionsForTrack, inclusionRate, intraShotMaxStep, regionInCrop, } from './inclusion';
|
|
23
|
-
/**
|
|
24
|
-
* Run the base eval over a fixture track + authored reframe segments. Derives the
|
|
25
|
-
* trajectory through the SHIPPING `deriveTrajectory`, composes the crop boxes,
|
|
26
|
-
* and reports jitter vs the center-crop + raw-centroid baselines.
|
|
27
|
-
*/
|
|
28
|
-
export function evalReframe(track, segments, aspect, bakeVersion) {
|
|
29
|
-
const traj = deriveTrajectory(track, segments, aspect, bakeVersion);
|
|
30
|
-
const ours = cropBoxSeries(traj);
|
|
31
|
-
const center = centerCropBoxSeries(traj);
|
|
32
|
-
const raw = rawCentroidBoxSeries(traj);
|
|
33
|
-
const j = jitter(ours);
|
|
34
|
-
const cj = jitter(center);
|
|
35
|
-
const rj = jitter(raw);
|
|
36
|
-
return {
|
|
37
|
-
jitter: j,
|
|
38
|
-
centerCropJitter: cj,
|
|
39
|
-
rawCentroidJitter: rj,
|
|
40
|
-
beatsCenterCrop: j.total <= cj.total,
|
|
41
|
-
frames: ours.length,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* The Phase-3 tracking eval for an `all-faces` segment over the whole window.
|
|
46
|
-
* Recomputes the per-frame RequiredRegions (the SAME `selectSubjectSet` the
|
|
47
|
-
* derive uses) and measures whether the camera keeps the subject in frame
|
|
48
|
-
* (inclusion), how it compares to the old EMA path (smoothness), and that it
|
|
49
|
-
* never teleports within a shot. The fixed crop window per frame is the
|
|
50
|
-
* segment's authored zoom + aspect (all-faces has no eased per-frame zoom).
|
|
51
|
-
*/
|
|
52
|
-
export function evalTracking(track, aspect, bakeVersion) {
|
|
53
|
-
const segments = [
|
|
54
|
-
{ startSec: 0, endSec: track.window.endSec, focus: { mode: 'all-faces' }, zoom: 1 },
|
|
55
|
-
];
|
|
56
|
-
const traj = deriveTrajectory(track, segments, aspect, bakeVersion);
|
|
57
|
-
const ours = cropBoxSeries(traj);
|
|
58
|
-
const center = centerCropBoxSeries(traj);
|
|
59
|
-
const regions = requiredRegionsForTrack(track);
|
|
60
|
-
// The fixed per-frame crop window (zoom 1.0 here — the authored all-faces zoom).
|
|
61
|
-
const win = cropWindowSizeFor(track.srcW, track.srcH, 1.0, aspect);
|
|
62
|
-
const cropFor = () => win;
|
|
63
|
-
// Reconstruct the RAW per-frame tracking centroid + the OLD emaSmooth path over
|
|
64
|
-
// the SAME selection, to prove ours (cameraPath) is no rougher than EMA.
|
|
65
|
-
const cuts = new Set((track.shotBoundaries ?? []).filter((b) => b > 0));
|
|
66
|
-
const sel = selectSubjectSet(track.perFrameTracked, track.srcW, track.srcH, track.srcFps, new Map(Object.entries(track.perKeyframeSpeaker).map(([k, v]) => [Number(k), v])), cuts);
|
|
67
|
-
const rawCenters = sel.centers;
|
|
68
|
-
const emaCenters = emaSmooth(rawCenters, 0.35, cuts);
|
|
69
|
-
const rawBoxes = cropBoxSeriesFromCenters(rawCenters, cropFor);
|
|
70
|
-
const emaBoxes = cropBoxSeriesFromCenters(emaCenters, cropFor);
|
|
71
|
-
const segLens = traj.segments.map((s) => s.centers.length);
|
|
72
|
-
return {
|
|
73
|
-
inclusionRate: inclusionRate(regions, ours).rate,
|
|
74
|
-
centerCropInclusionRate: inclusionRate(regions, center).rate,
|
|
75
|
-
framesWithRegion: inclusionRate(regions, ours).framesWithRegion,
|
|
76
|
-
jitter: jitter(ours),
|
|
77
|
-
emaPathJitter: jitter(emaBoxes),
|
|
78
|
-
rawPathJitter: jitter(rawBoxes),
|
|
79
|
-
intraShotMaxStep: intraShotMaxStep(ours, segLens),
|
|
80
|
-
frames: ours.length,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
/** Resolve a Focus mode + faceId into the single-subject adapter pick. */
|
|
84
|
-
function pickFor(mode, faceId) {
|
|
85
|
-
return mode === 'face' ? { kind: 'face', authoredFaceId: faceId ?? '' } : { kind: 'active-speaker' };
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Characterize the P4 `face` / `active-speaker` migration on a real fixture: the
|
|
89
|
-
* NEW core geometric-deadzone path (run via the SHIPPING `deriveTrajectory`) vs
|
|
90
|
-
* the OLD `emaSmooth` path (reconstructed here over the SAME per-frame chosen-
|
|
91
|
-
* subject centroid the old code used), measured against ONE inclusion region (the
|
|
92
|
-
* chosen subject's per-frame padded BOX). All over a single full-window segment.
|
|
93
|
-
*/
|
|
94
|
-
export function evalSingleSubject(track, mode, aspect, bakeVersion, faceId) {
|
|
95
|
-
const segments = [
|
|
96
|
-
{
|
|
97
|
-
startSec: 0,
|
|
98
|
-
endSec: track.window.endSec,
|
|
99
|
-
focus: mode === 'face' ? { mode: 'face', faceId: faceId ?? 'face-0' } : { mode: 'active-speaker' },
|
|
100
|
-
zoom: 1,
|
|
101
|
-
},
|
|
102
|
-
];
|
|
103
|
-
// NEW: the shipping migrated derive.
|
|
104
|
-
const traj = deriveTrajectory(track, segments, aspect, bakeVersion);
|
|
105
|
-
const newBoxes = cropBoxSeries(traj);
|
|
106
|
-
// The chosen subject's per-frame box (the adapter the migrated derive uses) →
|
|
107
|
-
// the SINGLE inclusion region both paths are judged against + the centroid the
|
|
108
|
-
// OLD emaSmooth consumed.
|
|
109
|
-
const cuts = new Set((track.shotBoundaries ?? []).filter((b) => b > 0));
|
|
110
|
-
const perKf = new Map(Object.entries(track.perKeyframeSpeaker).map(([k, v]) => [Number(k), v]));
|
|
111
|
-
const single = selectSingleSubjectBoxes(track.perFrameTracked, track.srcW, track.srcH, perKf, pickFor(mode, faceId), (frame) => nearestKpValue(perKf, frame));
|
|
112
|
-
const regions = buildRequiredRegions(single.perFrameBoxes, track.srcFps, cuts);
|
|
113
|
-
// OLD: emaSmooth(0.35) over the chosen subject's per-frame centroid (the bare
|
|
114
|
-
// center the deleted branch produced), composed at the SAME zoom-1.0 window.
|
|
115
|
-
const win = cropWindowSizeFor(track.srcW, track.srcH, 1.0, aspect);
|
|
116
|
-
const cropFor = () => win;
|
|
117
|
-
const centroids = single.perFrameBoxes.map((b) => b === null ? null : [(b[0] + b[2]) / 2, (b[1] + b[3]) / 2]);
|
|
118
|
-
const emaCenters = emaSmooth(centroids, 0.35, cuts);
|
|
119
|
-
const emaBoxes = cropBoxSeriesFromCenters(emaCenters.map((c) => [c[0], c[1]]), cropFor);
|
|
120
|
-
// Inclusion vs the chosen subject's padded box region (one bar for both paths).
|
|
121
|
-
const incl = (crops) => {
|
|
122
|
-
let fw = 0;
|
|
123
|
-
let contained = 0;
|
|
124
|
-
for (let i = 0; i < regions.length; i++) {
|
|
125
|
-
const r = regions[i];
|
|
126
|
-
if (r === null)
|
|
127
|
-
continue;
|
|
128
|
-
fw++;
|
|
129
|
-
if (regionInCrop(r, crops[i]))
|
|
130
|
-
contained++;
|
|
131
|
-
}
|
|
132
|
-
return { rate: fw > 0 ? contained / fw : 1, framesWithRegion: fw };
|
|
133
|
-
};
|
|
134
|
-
// Intra-shot max step (cut-snaps excluded) needs per-shot frame counts.
|
|
135
|
-
const segLens = segmentShots(cuts, regions.length).map((s) => s.end - s.start);
|
|
136
|
-
const newIncl = incl(newBoxes);
|
|
137
|
-
return {
|
|
138
|
-
jitter: jitter(newBoxes),
|
|
139
|
-
emaJitter: jitter(emaBoxes),
|
|
140
|
-
inclusionRate: newIncl.rate,
|
|
141
|
-
emaInclusionRate: incl(emaBoxes).rate,
|
|
142
|
-
intraShotMaxStep: intraShotMaxStep(newBoxes, segLens),
|
|
143
|
-
emaIntraShotMaxStep: intraShotMaxStep(emaBoxes, segLens),
|
|
144
|
-
framesWithRegion: newIncl.framesWithRegion,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reframe eval metrics — pure, label-free, deterministic.
|
|
3
|
-
*
|
|
4
|
-
* Tier 1 (HARD CI BLOCKERS, no human labels): `jitter` + the center-crop
|
|
5
|
-
* comparison. These are what gate the build per the virtual-camera spec —
|
|
6
|
-
* "jitter-beats-center-crop is the only ship-blocker".
|
|
7
|
-
*
|
|
8
|
-
* Tier 2 (REPORTED, not blocking): `mIoU` — scaffolded + reported, NOT a gate,
|
|
9
|
-
* because per-frame human ground-truth boxes don't exist yet (RESOLVED #3).
|
|
10
|
-
*
|
|
11
|
-
* `jitter` = mean over frames of the absolute frame-to-frame difference of the
|
|
12
|
-
* composed crop box (center x/y AND size), in output-crop-normalized units. The
|
|
13
|
-
* per-component delta is normalized by the box's own size, so the metric is
|
|
14
|
-
* zoom-invariant: a half-window pan reads the same number at any zoom (the spec's
|
|
15
|
-
* "held feel is zoom-invariant" requirement). Lower is smoother. A static crop
|
|
16
|
-
* has zero pan jitter; the only motion it carries is the per-shot `zoom_scale`
|
|
17
|
-
* steps, which both paths share — so `jitter(ours) ≤ jitter(centerCrop)` isolates
|
|
18
|
-
* "where the camera points" as the sole variable.
|
|
19
|
-
*/
|
|
20
|
-
/**
|
|
21
|
-
* Jitter of a composed crop-box series. Empty / single-frame series → all zeros
|
|
22
|
-
* (no motion to measure). The center delta is divided by the per-frame window
|
|
23
|
-
* size so it is expressed in fractions of the crop window (output-crop space);
|
|
24
|
-
* the zoom delta is divided by the mean window size for the same normalization.
|
|
25
|
-
*/
|
|
26
|
-
export function jitter(boxes) {
|
|
27
|
-
if (boxes.length < 2) {
|
|
28
|
-
return { center: 0, zoom: 0, total: 0, maxCenterStep: 0 };
|
|
29
|
-
}
|
|
30
|
-
let centerAcc = 0;
|
|
31
|
-
let zoomAcc = 0;
|
|
32
|
-
let maxCenterStep = 0;
|
|
33
|
-
let wSum = 0;
|
|
34
|
-
let hSum = 0;
|
|
35
|
-
for (const b of boxes) {
|
|
36
|
-
wSum += b.w;
|
|
37
|
-
hSum += b.h;
|
|
38
|
-
}
|
|
39
|
-
const meanW = wSum / boxes.length || 1e-6;
|
|
40
|
-
const meanH = hSum / boxes.length || 1e-6;
|
|
41
|
-
for (let i = 1; i < boxes.length; i++) {
|
|
42
|
-
const a = boxes[i - 1];
|
|
43
|
-
const b = boxes[i];
|
|
44
|
-
// Center delta in output-crop units: source-normalized delta ÷ window size
|
|
45
|
-
// (so it's a fraction of the visible window, not of the whole source).
|
|
46
|
-
const dxOut = Math.abs(b.cx - a.cx) / Math.max(b.w, 1e-6);
|
|
47
|
-
const dyOut = Math.abs(b.cy - a.cy) / Math.max(b.h, 1e-6);
|
|
48
|
-
const step = dxOut + dyOut;
|
|
49
|
-
centerAcc += step;
|
|
50
|
-
if (step > maxCenterStep)
|
|
51
|
-
maxCenterStep = step;
|
|
52
|
-
// Zoom (window-size) delta, normalized by the mean window size.
|
|
53
|
-
zoomAcc += Math.abs(b.w - a.w) / meanW + Math.abs(b.h - a.h) / meanH;
|
|
54
|
-
}
|
|
55
|
-
const denom = boxes.length - 1;
|
|
56
|
-
const center = centerAcc / denom;
|
|
57
|
-
const zoom = zoomAcc / denom;
|
|
58
|
-
return { center, zoom, total: center + zoom, maxCenterStep };
|
|
59
|
-
}
|
|
60
|
-
/** Intersection-over-union of two source-normalized crop boxes. */
|
|
61
|
-
export function iou(a, b) {
|
|
62
|
-
const ax1 = a.cx - a.w / 2;
|
|
63
|
-
const ax2 = a.cx + a.w / 2;
|
|
64
|
-
const ay1 = a.cy - a.h / 2;
|
|
65
|
-
const ay2 = a.cy + a.h / 2;
|
|
66
|
-
const bx1 = b.cx - b.w / 2;
|
|
67
|
-
const bx2 = b.cx + b.w / 2;
|
|
68
|
-
const by1 = b.cy - b.h / 2;
|
|
69
|
-
const by2 = b.cy + b.h / 2;
|
|
70
|
-
const ix = Math.max(0, Math.min(ax2, bx2) - Math.max(ax1, bx1));
|
|
71
|
-
const iy = Math.max(0, Math.min(ay2, by2) - Math.max(ay1, by1));
|
|
72
|
-
const inter = ix * iy;
|
|
73
|
-
const union = a.w * a.h + b.w * b.h - inter;
|
|
74
|
-
return union > 0 ? inter / union : 0;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* mIoU + IoU@0.5 vs a per-frame ground-truth crop-box series (Tier 2, REPORTED
|
|
78
|
-
* only). Scaffolded now so the harness emits a number the moment labels exist;
|
|
79
|
-
* NOT a CI gate (no hand-labeled fixtures yet — RESOLVED #3). Lengths must match.
|
|
80
|
-
*/
|
|
81
|
-
export function mIoU(ours, groundTruth) {
|
|
82
|
-
const n = Math.min(ours.length, groundTruth.length);
|
|
83
|
-
if (n === 0)
|
|
84
|
-
return { mIoU: 0, iouAt50: 0, n: 0 };
|
|
85
|
-
let sum = 0;
|
|
86
|
-
let hits = 0;
|
|
87
|
-
for (let i = 0; i < n; i++) {
|
|
88
|
-
const v = iou(ours[i], groundTruth[i]);
|
|
89
|
-
sum += v;
|
|
90
|
-
if (v >= 0.5)
|
|
91
|
-
hits++;
|
|
92
|
-
}
|
|
93
|
-
return { mIoU: sum / n, iouAt50: hits / n, n };
|
|
94
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
// ── Constants ──────────────────────────────────────────────────────────────
|
|
2
|
-
export const DEFAULT_FPS = 30;
|
|
3
|
-
export const DEFAULT_WIDTH = 1920;
|
|
4
|
-
export const DEFAULT_HEIGHT = 1080;
|
|
5
|
-
export const DEFAULT_RENDER_SETTINGS = {
|
|
6
|
-
format: 'source',
|
|
7
|
-
quality: 'source',
|
|
8
|
-
resolution: 'source',
|
|
9
|
-
watermark: false,
|
|
10
|
-
captionsEnabled: true,
|
|
11
|
-
};
|
|
12
|
-
export const FORMAT_PRESETS = {
|
|
13
|
-
'16:9': { label: 'Landscape', aspectWidth: 16, aspectHeight: 9 },
|
|
14
|
-
'9:16': { label: 'TikTok / Reels', aspectWidth: 9, aspectHeight: 16 },
|
|
15
|
-
'4:5': { label: 'Instagram Portrait', aspectWidth: 4, aspectHeight: 5 },
|
|
16
|
-
'1:1': { label: 'Square', aspectWidth: 1, aspectHeight: 1 },
|
|
17
|
-
};
|
|
18
|
-
export const RESOLUTION_PRESETS = {
|
|
19
|
-
'1080p': { label: '1080p (Full HD)', height: 1080 },
|
|
20
|
-
'1440p': { label: '1440p (2K)', height: 1440 },
|
|
21
|
-
'4k': { label: '4K (Ultra HD)', height: 2160 },
|
|
22
|
-
};
|
|
23
|
-
// BPP (bits-per-pixel) presets — scales encoding quality proportionally to
|
|
24
|
-
// resolution so file sizes are predictable across 720p through 4K.
|
|
25
|
-
const BPP = {
|
|
26
|
-
maximum: 0.3,
|
|
27
|
-
social: 0.15,
|
|
28
|
-
web: 0.08,
|
|
29
|
-
potato: 0.04,
|
|
30
|
-
};
|
|
31
|
-
// ── Functions ──────────────────────────────────────────────────────────────
|
|
32
|
-
/** Convert a BPP value to an approximate CRF (H.264). */
|
|
33
|
-
export function bppToCrf(bpp) {
|
|
34
|
-
return Math.max(15, Math.min(36, Math.round(51 - bpp * 120)));
|
|
35
|
-
}
|
|
36
|
-
/** Compute output dimensions and CRF from source dims + quality preset. */
|
|
37
|
-
export function computeExportDimensions(sourceWidth, sourceHeight, format, quality) {
|
|
38
|
-
let w;
|
|
39
|
-
let h;
|
|
40
|
-
if (format === 'source') {
|
|
41
|
-
w = sourceWidth;
|
|
42
|
-
h = sourceHeight;
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
const preset = FORMAT_PRESETS[format];
|
|
46
|
-
const shortEdge = Math.min(sourceWidth, sourceHeight);
|
|
47
|
-
const minAspect = Math.min(preset.aspectWidth, preset.aspectHeight);
|
|
48
|
-
w = Math.round(shortEdge * (preset.aspectWidth / minAspect));
|
|
49
|
-
h = Math.round(shortEdge * (preset.aspectHeight / minAspect));
|
|
50
|
-
}
|
|
51
|
-
// Ensure even dimensions (required by most codecs)
|
|
52
|
-
w = w % 2 === 0 ? w : w + 1;
|
|
53
|
-
h = h % 2 === 0 ? h : h + 1;
|
|
54
|
-
if (quality === 'source') {
|
|
55
|
-
return { width: w, height: h, crf: undefined };
|
|
56
|
-
}
|
|
57
|
-
const bpp = BPP[quality];
|
|
58
|
-
if (bpp === undefined)
|
|
59
|
-
return { width: w, height: h, crf: undefined };
|
|
60
|
-
return { width: w, height: h, crf: bppToCrf(bpp) };
|
|
61
|
-
}
|
|
62
|
-
/** Ensure a dimension is even (required by most codecs). */
|
|
63
|
-
export function ensureEven(n) {
|
|
64
|
-
return n % 2 === 0 ? n : n + 1;
|
|
65
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export { buildEmphasisSet, isEmphasized } from './emphasis';
|
|
2
|
-
export { extractCaptionWordsFromDoc, sliceTranscriptWords, splitIntoSentences } from './captions';
|
|
3
|
-
// (auto-reframe module deleted 2026-05-25 — baked-variants substrate
|
|
4
|
-
// replacement. Crop trajectories now live in pre-baked variant videos,
|
|
5
|
-
// not in render-time computation.)
|
|
6
|
-
// (caption-safe-area deleted 2026-06-04 — the composition floor's reframe-yield
|
|
7
|
-
// replaces the scalar caption shift. See @cueframe/composition/projection
|
|
8
|
-
// resolveCompositionFloor + packages/execution/render-entry/src/floor/buildFloorInput.ts.)
|
|
9
|
-
export { compositionToRenderInput, referencedMediaIds, componentRefsByClipId, assembleRenderInput, validateComposition, compositionFormatDimensions, playableSpans, } from './compositionRender';
|
|
10
|
-
// Brand intro/outro bookend timeline math — pure, fps-driven, never throws.
|
|
11
|
-
// Shared by compositionToRenderInput (forward: body → extended total) and the
|
|
12
|
-
// cueframe renderer's MainComposition (bumper → reserved frames + body shift).
|
|
13
|
-
export { bookendFrames, resolveBookendTimeline, CARD_BOOKEND_DEFAULT_MS, VIDEO_BOOKEND_DEFAULT_MS, } from './bookends';
|
|
14
|
-
export { DEFAULT_FPS, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_RENDER_SETTINGS, FORMAT_PRESETS, RESOLUTION_PRESETS, bppToCrf, computeExportDimensions, ensureEven, } from './exportSettings';
|
|
15
|
-
// Crop-trajectory inline derive — PURE STAGE-B math over a cached SubjectTrack.
|
|
16
|
-
// The render derives the crop trajectory INLINE from the track + the clip's
|
|
17
|
-
// reframe (no pre-baked variant cache). See
|
|
18
|
-
// brain/Projects/CueFrame/specs/2026-06-14-render-time-resolution-design.md.
|
|
19
|
-
export { faceArea, resolveSubjectFaces, selectedFaceCenter, isJump, emaSmooth, clip01, captionBandReserve, aspectWhRatio, nearestKpValue, activeWindowsFor, perSubjectSeries, calibrateShotScale, deriveSegment, deriveTrajectory, buildEasedZooms, buildPannedCenters, easeOutCubic, JUMP_THRESHOLD, MIN_SUBJECT_RESOLUTION, } from './deriveTrajectory';
|
|
20
|
-
export { mapFaceIdToPersonId } from './mapFaceToPerson';
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Face→person identity mapping for the perception ESCALATION path.
|
|
3
|
-
*
|
|
4
|
-
* The plan authors subjects against the FACE roster (`face-N`, YuNet/SCRFD).
|
|
5
|
-
* When the face tracker carries that identity in too few frames
|
|
6
|
-
* (`subject_not_tracked` — e.g. the subject looks away for most of a long
|
|
7
|
-
* segment), the compose escalates to the PERSON detector (YOLO11x + BoT-SORT),
|
|
8
|
-
* whose track names identities `person-N`. This maps the authored face id onto
|
|
9
|
-
* the person id whose body boxes CONTAIN that face, scored over exactly the
|
|
10
|
-
* frames where the face DID resolve — the face evidence is sparse but real, and
|
|
11
|
-
* a face box sits inside its own person's box in every such frame.
|
|
12
|
-
*
|
|
13
|
-
* Pure math, no I/O. Tracks may have different frame counts (defensive):
|
|
14
|
-
* frames align by relative position in the shared detection window.
|
|
15
|
-
*/
|
|
16
|
-
/** Fraction of the FACE box's area inside the person box. 1 = fully contained. */
|
|
17
|
-
function containment(face, person) {
|
|
18
|
-
const [fx1, fy1, fx2, fy2] = face;
|
|
19
|
-
const [px1, py1, px2, py2] = person;
|
|
20
|
-
const faceArea = Math.max(0, fx2 - fx1) * Math.max(0, fy2 - fy1);
|
|
21
|
-
if (faceArea === 0)
|
|
22
|
-
return 0;
|
|
23
|
-
const ix = Math.max(0, Math.min(fx2, px2) - Math.max(fx1, px1));
|
|
24
|
-
const iy = Math.max(0, Math.min(fy2, py2) - Math.max(fy1, py1));
|
|
25
|
-
return (ix * iy) / faceArea;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Map one authored face id to the person-track id that carries it, or null when
|
|
29
|
-
* the evidence is missing/ambiguous (caller fails loud — never a guess).
|
|
30
|
-
*
|
|
31
|
-
* Decision rule: sum per-frame containment per person id over the frames where
|
|
32
|
-
* the face resolves; the winner needs (a) support in ≥30% of those frames at
|
|
33
|
-
* ≥60% containment, and (b) a 1.5× margin over the runner-up (two people
|
|
34
|
-
* side-by-side must not coin-flip).
|
|
35
|
-
*/
|
|
36
|
-
export function mapFaceIdToPersonId(faceTrack, personTrack, faceId) {
|
|
37
|
-
const nF = faceTrack.perFrameTracked.length;
|
|
38
|
-
const nP = personTrack.perFrameTracked.length;
|
|
39
|
-
if (nF === 0 || nP === 0)
|
|
40
|
-
return null;
|
|
41
|
-
const scores = new Map();
|
|
42
|
-
let faceFrames = 0;
|
|
43
|
-
for (let i = 0; i < nF; i++) {
|
|
44
|
-
const face = faceTrack.perFrameTracked[i]?.[faceId];
|
|
45
|
-
if (!face)
|
|
46
|
-
continue;
|
|
47
|
-
faceFrames++;
|
|
48
|
-
// Align by relative position — identical-length tracks map i→i exactly.
|
|
49
|
-
const j = nF === 1 ? 0 : Math.round((i * (nP - 1)) / (nF - 1));
|
|
50
|
-
const persons = personTrack.perFrameTracked[j] ?? {};
|
|
51
|
-
for (const [pid, pbox] of Object.entries(persons)) {
|
|
52
|
-
const c = containment(face, pbox);
|
|
53
|
-
if (c <= 0)
|
|
54
|
-
continue;
|
|
55
|
-
const s = scores.get(pid) ?? { total: 0, matched: 0 };
|
|
56
|
-
s.total += c;
|
|
57
|
-
if (c >= 0.6)
|
|
58
|
-
s.matched++;
|
|
59
|
-
scores.set(pid, s);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (faceFrames === 0 || scores.size === 0)
|
|
63
|
-
return null;
|
|
64
|
-
const ranked = [...scores.entries()].sort((a, b) => b[1].total - a[1].total);
|
|
65
|
-
const [winnerId, winner] = ranked[0];
|
|
66
|
-
const runnerUp = ranked[1]?.[1].total ?? 0;
|
|
67
|
-
const margin = runnerUp > 0 ? winner.total / runnerUp : Infinity;
|
|
68
|
-
if (winner.matched / faceFrames < 0.3)
|
|
69
|
-
return null; // too little real containment
|
|
70
|
-
if (margin < 1.5)
|
|
71
|
-
return null; // ambiguous between two people
|
|
72
|
-
return { personId: winnerId, matchedFrames: winner.matched, faceFrames, margin };
|
|
73
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// Self-contained types for the render pipeline.
|
|
2
|
-
// These MUST NOT import from @tauri-apps/* or any barrel that re-exports Tauri types,
|
|
3
|
-
// because Remotion's webpack bundler will try to resolve those imports and fail.
|
|
4
|
-
//
|
|
5
|
-
// OverlayTemplate and OverlayParams are intentionally duplicated from src/types/index.ts.
|
|
6
|
-
// Remotion bundles via webpack which cannot resolve @tauri-apps/* imports that appear
|
|
7
|
-
// in the main types barrel. Keeping these copies decoupled avoids webpack build failures.
|
|
8
|
-
export {};
|