@cueframe/kernel 0.2.45 → 0.2.47
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/dist/_members/composition/ops/compositionOps.shared.d.ts +1 -1
- package/dist/_members/composition/projection/cropProjection.d.ts +2 -1
- package/dist/_members/composition-ops/index.d.ts +4 -0
- package/dist/_members/composition-ops/materializeCaptions.d.ts +19 -0
- package/dist/_members/core/render/compositionRender.d.ts +1 -1
- package/dist/_members/core/render/index.d.ts +1 -1
- package/dist/_members/core/render/trackProjection.d.ts +24 -0
- package/dist/_members/core/render/types.d.ts +1 -0
- package/dist/_members/errors/registry.d.ts +18 -0
- package/dist/_members/mcp/generated/harness.d.ts +1 -1
- package/dist/_members/mcp/server.d.ts +2 -0
- package/dist/authoring/build-tools.js +3 -3
- package/dist/authoring/context.js +2 -2
- package/dist/authoring/tools.js +2 -2
- package/dist/authoring.js +6 -6
- package/dist/{chunk-S3HHEJMZ.js → chunk-4FKNPTLX.js} +1 -1
- package/dist/{chunk-JVWLZNHC.js → chunk-ACURZCPN.js} +1 -1
- package/dist/{chunk-46PFSJZE.js → chunk-AOIY7NGF.js} +3059 -3120
- package/dist/{chunk-MJWRC7G7.js → chunk-BBNF4QLD.js} +2 -2
- package/dist/{chunk-5YO4LAB7.js → chunk-CFIQY4OE.js} +1 -1
- package/dist/{chunk-VVKBCBNR.js → chunk-DV7ZFVL4.js} +1 -1
- package/dist/{chunk-ULQJWGUV.js → chunk-E63UEO5C.js} +3 -0
- package/dist/{chunk-AMFFWX3C.js → chunk-FEG264CF.js} +55 -32
- package/dist/{chunk-EDBQPQAG.js → chunk-FGJ7GKWZ.js} +6 -6
- package/dist/{chunk-SPF3AXTB.js → chunk-FYS2XUKJ.js} +1 -1
- package/dist/{chunk-QISFYLBB.js → chunk-IMIUHG2E.js} +1 -1
- package/dist/{chunk-CYILSHK5.js → chunk-JPMVNMF3.js} +1 -1
- package/dist/chunk-KCXADPOC.js +1085 -0
- package/dist/{chunk-4S2YZQJP.js → chunk-N54EGUVM.js} +1 -1
- package/dist/{chunk-HUZN2HRT.js → chunk-OYWX4NEP.js} +48 -9
- package/dist/{chunk-ZUJCWFS7.js → chunk-SLUTOUWI.js} +1 -1
- package/dist/{chunk-DENF4TPI.js → chunk-T56BK7NS.js} +6 -4
- package/dist/{chunk-B4VMU2IJ.js → chunk-TBHSOEYK.js} +1 -1
- package/dist/{chunk-POTCIQTA.js → chunk-VEQTURKN.js} +90 -11
- package/dist/{chunk-OZNULDQE.js → chunk-XSBVOXSB.js} +1 -1
- package/dist/{chunk-URZR6C3N.js → chunk-Z4G3VM3H.js} +1 -1
- package/dist/compose.js +1 -1
- package/dist/composition/invariants.js +2 -2
- package/dist/composition/ops.js +1 -1
- package/dist/composition/projection.js +2 -2
- package/dist/composition/timeline.js +2 -2
- package/dist/composition-ops.js +36 -894
- package/dist/composition.js +4 -4
- package/dist/{context-KNFL62QR.js → context-YNR73FNI.js} +2 -2
- package/dist/core/render.js +7 -5
- package/dist/core/select.js +2 -2
- package/dist/core.js +5 -5
- package/dist/director/ai-sdk.js +3 -3
- package/dist/director/domain.js +2 -2
- package/dist/director.js +3 -3
- package/dist/errors.js +1 -1
- package/dist/mcp/adapter.js +3 -3
- package/dist/mcp/core.js +1 -1
- package/dist/mcp/curation.js +1 -1
- package/dist/mcp/scene-shot.js +2 -2
- package/dist/mcp/server.js +26 -5
- package/dist/mcp.js +28 -9
- package/dist/render-harness/cardAssetAdmission.js +2 -2
- package/dist/render-harness/cardFonts.js +2 -2
- package/dist/render-harness.js +7 -7
- package/package.json +11 -11
|
@@ -1,16 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SCENE_SHOT_RESOURCE_DESCRIPTION,
|
|
3
|
+
SCENE_SHOT_RESOURCE_URI,
|
|
4
|
+
sceneShotContract
|
|
5
|
+
} from "./chunk-FYS2XUKJ.js";
|
|
1
6
|
import {
|
|
2
7
|
querySchemaShape,
|
|
3
8
|
serializeQuery,
|
|
4
9
|
waitForJob
|
|
5
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-XSBVOXSB.js";
|
|
6
11
|
import {
|
|
7
12
|
CURATED_TOOLS
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import {
|
|
10
|
-
SCENE_SHOT_RESOURCE_DESCRIPTION,
|
|
11
|
-
SCENE_SHOT_RESOURCE_URI,
|
|
12
|
-
sceneShotContract
|
|
13
|
-
} from "./chunk-SPF3AXTB.js";
|
|
13
|
+
} from "./chunk-CFIQY4OE.js";
|
|
14
14
|
import {
|
|
15
15
|
GENERATED_OPERATIONS,
|
|
16
16
|
apiErrorFrom,
|
|
@@ -28,7 +28,10 @@ import {
|
|
|
28
28
|
text,
|
|
29
29
|
textWithData,
|
|
30
30
|
withMedia
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-AOIY7NGF.js";
|
|
32
|
+
import {
|
|
33
|
+
CompositionOp
|
|
34
|
+
} from "./chunk-KCXADPOC.js";
|
|
32
35
|
|
|
33
36
|
// ../mcp/src/prompts.ts
|
|
34
37
|
var skillListCache = null;
|
|
@@ -74,10 +77,12 @@ var SERVER_INSTRUCTIONS = `You are driving CueFrame \u2014 an API-first, agent-n
|
|
|
74
77
|
|
|
75
78
|
## Two lanes (pick per job)
|
|
76
79
|
|
|
80
|
+
For \`apply_composition\` edits, call \`describe_composition_ops\` to list operation types, then \`describe_composition_ops({type})\` for only the selected operation's exact JSON Schema. To caption an EDITED timeline, save the clip edits first, then make a SEPARATE \`apply_composition\` call with \`{type:"captions.fromComposition", trackId}\`. It captions all transcribed speech clips on the saved track using placement, trims and exclusions. Clips must have saved duration matching playable source duration divided by playbackRate; otherwise the operation fails with an actionable error. Re-run it after later timeline edits; generated captions are a snapshot. \`captions.fromTranscript\` replaces all captions from ONE media transcript rebased to zero and does not follow a montage. Do not calculate word timing manually.
|
|
81
|
+
|
|
77
82
|
ORIENT FIRST: call \`get_account\` to see your org, plan, per-feature entitlements, and per-call cost ceilings BEFORE a metered call. READ \`balance\`, NOT \`included\` \u2014 CueFrame is CREDIT-FUNDED, so rendering, generation, preview stills, the judge and the Director carry no separate per-plan allowance: they all spend ONE shared wallet (\`fundedBy\`: \`credits\`; generation is metered in provider-cost units against that wallet), and each \`balance\` restates that same wallet in that feature's own unit. Check the requested cost against the balance. For generation, also check get_account.generationLimit: free accounts have a separate provider-cost cap even with a positive wallet. A billing_required response with reason free_generation_cap requires a credit-pack purchase through the normal checkout flow. Every new org starts with a free credit grant, so an account with NO usage history can still render, generate, preview and score. \`create_render\`, \`compose\`, \`generate_media\`, and \`create_brand_kit\` return 402 \`billing_required\` (the error \`details.featureId\` names it) once the funding balance is exhausted, or when the plan genuinely lacks a non-credit feature. \`get_profile\` is the org's TASTE in one read (brand kits, registered critics + their reference media, recent checkpoint decisions) \u2014 read it before composing for an org you haven't worked with. \`get_usage\` is the metered-usage ledger (per project/job/period); render/compose/score/preview/generate terminals also stamp \`listUsd\` \u2014 the event's LIST price (a plan allowance may zero the invoice line; Autumn/your invoice is the charge authority).
|
|
78
83
|
|
|
79
84
|
**AUTHOR lane \u2014 you bring the plan, CueFrame is the faithful hands (the default):**
|
|
80
|
-
\`new_composition\` (mint) \u2192 \`apply_composition\` (add your media clips; overlays/scenes from \`list_catalog\` per each entry's \`placement\`; BRAND/TEXT GRAPHICS: default to authoring your OWN \`{kind:'card', html, tokens}\` clip \u2014 your typography and layout, sized to the format's pixel frame \u2014 then shell it with \`applyMotionPreset\` (persist the card first, shell in the NEXT call). A card's \`tokens\` KEY \`x\` is projected to the CSS custom property \`--cf-x\`, so its html reads \`var(--cf-x)\`: write \`tokens:{"plate":"#0af"}\` + \`background:var(--cf-plate)\`. NEVER put dashes in the key \u2014 \`"--plate"\` becomes \`--cf---plate\`, your \`var(--plate)\` matches nothing, and CSS degrades that SILENTLY to a transparent background with black text (the render still succeeds). \`apply_composition\` returns \`warnings[]\` when it catches this. Catalog text primitives are the quick generic fallback, never the brand-identity path; place with \`region\` + clip-level \`position\`/\`scale\`/\`rotation\`/\`opacity\` \u2014 all of which RENDER; crop intents;
|
|
85
|
+
\`new_composition\` (mint) \u2192 \`apply_composition\` (add your media clips; overlays/scenes from \`list_catalog\` per each entry's \`placement\`; BRAND/TEXT GRAPHICS: default to authoring your OWN \`{kind:'card', html, tokens}\` clip \u2014 your typography and layout, sized to the format's pixel frame \u2014 then shell it with \`applyMotionPreset\` (persist the card first, shell in the NEXT call). A card's \`tokens\` KEY \`x\` is projected to the CSS custom property \`--cf-x\`, so its html reads \`var(--cf-x)\`: write \`tokens:{"plate":"#0af"}\` + \`background:var(--cf-plate)\`. NEVER put dashes in the key \u2014 \`"--plate"\` becomes \`--cf---plate\`, your \`var(--plate)\` matches nothing, and CSS degrades that SILENTLY to a transparent background with black text (the render still succeeds). \`apply_composition\` returns \`warnings[]\` when it catches this. Catalog text primitives are the quick generic fallback, never the brand-identity path; place with \`region\` + clip-level \`position\`/\`scale\`/\`rotation\`/\`opacity\` \u2014 all of which RENDER; crop intents; caption edits discovered with \`describe_composition_ops\` and styled with \`setCaptionStyle\`; \`dry_run:true\` validates without persisting) \u2192 \`validate_composition\` (full dry-run of an INLINE composition; its \`quote\` states the render price. From the ops lane you do not hold the full composition JSON \u2014 use \`apply_composition dry_run:true\` + previews instead, and take prices from get_account/get_usage) \u2192 \`preview_frame\` (defaults to the PERSISTED composition \u2014 exactly what create_render will encode; the response's \`previewed.source\` says so; trust a preview as render-truth ONLY when it is "persisted") \u2192 \`score_composition\` (the standalone sighted judge: per-criterion scores + worst-first critique + a durable kind:'score' Checkpoint) \u2192 fix the lowest criterion \u2192 \`create_render\` \u2192 \`wait_job(kind:"render")\` or webhook \`render.completed\`. Rendering is FAITHFUL to the saved composition \u2014 a golden-tested contract, never a re-interpretation. \`derive_composition\` makes a reframed sibling for another aspect; \`list_compositions\` / \`delete_composition\` manage the set.
|
|
81
86
|
|
|
82
87
|
**DIRECTOR lane \u2014 the hosted Director composes FROM your brief (opt in for full authoring):**
|
|
83
88
|
1. \`create_project\` \u2192 get media in (\`import_media\` / \`generate_media\`; webhook \`media.completed\`) \u2192 \`get_media_context\` (detected faces + transcript \u2014 ground your beats in the real footage).
|
|
@@ -441,9 +446,42 @@ function registerCuratedTools(server, ex, opts) {
|
|
|
441
446
|
}
|
|
442
447
|
}));
|
|
443
448
|
}
|
|
449
|
+
registerCompositionOpDiscovery(server, opts?.onEvent);
|
|
444
450
|
registerWaitJob(server, ex, opts?.waitCapMs, opts?.onEvent);
|
|
445
451
|
registerPreviewCard(server, ex, opts?.waitCapMs, opts?.onEvent);
|
|
446
452
|
}
|
|
453
|
+
function describeCompositionOps(type) {
|
|
454
|
+
const variants = CompositionOp.options;
|
|
455
|
+
const knownTypes = variants.map((variant2) => variant2.shape.type.value);
|
|
456
|
+
if (type === void 0) {
|
|
457
|
+
return {
|
|
458
|
+
operations: variants.map((variant2) => ({
|
|
459
|
+
type: variant2.shape.type.value,
|
|
460
|
+
description: variant2.description ?? ""
|
|
461
|
+
}))
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
const variant = variants.find((candidate) => candidate.shape.type.value === type);
|
|
465
|
+
if (!variant) {
|
|
466
|
+
throw new Error(`Unknown CompositionOp type ${JSON.stringify(type)}. Known types: ${knownTypes.join(", ")}`);
|
|
467
|
+
}
|
|
468
|
+
return { type, schema: z.toJSONSchema(variant, { io: "input" }) };
|
|
469
|
+
}
|
|
470
|
+
function registerCompositionOpDiscovery(server, onEvent) {
|
|
471
|
+
server.registerTool("describe_composition_ops", {
|
|
472
|
+
title: "Describe Composition Operations",
|
|
473
|
+
description: "Discover the exact CompositionOp vocabulary accepted by apply_composition. Omit type for a compact list of operation names and descriptions; pass type for only that operation's JSON Schema. Read this before authoring edits or captions.",
|
|
474
|
+
inputSchema: z.object({ type: z.string().optional().describe("Exact CompositionOp type, such as captions.fromComposition. Omit for the operation list.") }),
|
|
475
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
476
|
+
}, async (args) => timed(onEvent, "describe_composition_ops", async () => {
|
|
477
|
+
try {
|
|
478
|
+
const data = describeCompositionOps(args.type);
|
|
479
|
+
return textWithData(JSON.stringify(data), data);
|
|
480
|
+
} catch (error) {
|
|
481
|
+
return errText(fmtErr(error));
|
|
482
|
+
}
|
|
483
|
+
}));
|
|
484
|
+
}
|
|
447
485
|
function registerPreviewCard(server, ex, waitCapMs, onEvent) {
|
|
448
486
|
const op = opById("previewFrameJob");
|
|
449
487
|
server.registerTool(
|
|
@@ -567,5 +605,6 @@ export {
|
|
|
567
605
|
registerRawTools,
|
|
568
606
|
titleCase,
|
|
569
607
|
registerCuratedTools,
|
|
608
|
+
describeCompositionOps,
|
|
570
609
|
buildServer
|
|
571
610
|
};
|
|
@@ -101,7 +101,8 @@ function checkExcludedRanges(track) {
|
|
|
101
101
|
if (!ranges || ranges.length === 0) continue;
|
|
102
102
|
const trim = content.source.trim;
|
|
103
103
|
const trimStart = trim?.start ?? 0;
|
|
104
|
-
const
|
|
104
|
+
const rate = content.source.playbackRate ?? 1;
|
|
105
|
+
const trimEnd = trim?.end ?? trimStart + content.duration * rate;
|
|
105
106
|
let prevEnd = -Infinity;
|
|
106
107
|
let total = 0;
|
|
107
108
|
let earlyExit = false;
|
|
@@ -159,18 +160,19 @@ function checkExcludedRanges(track) {
|
|
|
159
160
|
}
|
|
160
161
|
if (earlyExit) continue;
|
|
161
162
|
const trimSpan = trimEnd - trimStart;
|
|
162
|
-
const expectedDuration = trimSpan - total;
|
|
163
|
+
const expectedDuration = (trimSpan - total) / rate;
|
|
163
164
|
if (Math.abs(expectedDuration - content.duration) > 1e-3) {
|
|
164
165
|
violations.push({
|
|
165
166
|
code: "excluded_range_duration_mismatch",
|
|
166
|
-
message: `Track ${track.id}: TimelineClip ${content.id} duration (${content.duration}) \u2260 trimSpan (${trimSpan}) \u2212 \u03A3excluded (${total}) = ${expectedDuration}`,
|
|
167
|
+
message: `Track ${track.id}: TimelineClip ${content.id} duration (${content.duration}) \u2260 (trimSpan (${trimSpan}) \u2212 \u03A3excluded (${total})) \xF7 playbackRate (${rate}) = ${expectedDuration}`,
|
|
167
168
|
details: {
|
|
168
169
|
trackId: track.id,
|
|
169
170
|
clipId: content.id,
|
|
170
171
|
expected: expectedDuration,
|
|
171
172
|
actual: content.duration,
|
|
172
173
|
trimSpan,
|
|
173
|
-
totalExcluded: total
|
|
174
|
+
totalExcluded: total,
|
|
175
|
+
playbackRate: rate
|
|
174
176
|
}
|
|
175
177
|
});
|
|
176
178
|
}
|
|
@@ -48,12 +48,44 @@ function findMarkerById(composition, id) {
|
|
|
48
48
|
}
|
|
49
49
|
return void 0;
|
|
50
50
|
}
|
|
51
|
-
function trimSourceFor(source, clipRelStart, clipRelEnd) {
|
|
51
|
+
function trimSourceFor(source, clipRelStart, clipRelEnd, clipDuration) {
|
|
52
52
|
if (source.kind !== "media") return source;
|
|
53
53
|
const baseStart = source.trim?.start ?? 0;
|
|
54
|
+
const rate = source.playbackRate ?? 1;
|
|
55
|
+
const excluded = source.excludedRanges ?? [];
|
|
56
|
+
const excludedDuration = excluded.reduce((sum, range) => sum + range.end - range.start, 0);
|
|
57
|
+
const baseEnd = source.trim?.end ?? baseStart + clipDuration * rate + excludedDuration;
|
|
58
|
+
const playable = [];
|
|
59
|
+
let cursor = baseStart;
|
|
60
|
+
for (const range of excluded) {
|
|
61
|
+
if (range.start > cursor) playable.push({ start: cursor, end: range.start });
|
|
62
|
+
cursor = Math.max(cursor, range.end);
|
|
63
|
+
}
|
|
64
|
+
if (cursor < baseEnd) playable.push({ start: cursor, end: baseEnd });
|
|
65
|
+
const sourceAt = (outputSeconds, edge) => {
|
|
66
|
+
let remaining = outputSeconds * rate;
|
|
67
|
+
for (let i = 0; i < playable.length; i++) {
|
|
68
|
+
const span = playable[i];
|
|
69
|
+
const length = span.end - span.start;
|
|
70
|
+
if (remaining < length - 1e-9) return span.start + remaining;
|
|
71
|
+
if (Math.abs(remaining - length) <= 1e-9) {
|
|
72
|
+
return edge === "start" && playable[i + 1] ? playable[i + 1].start : span.end;
|
|
73
|
+
}
|
|
74
|
+
remaining -= length;
|
|
75
|
+
}
|
|
76
|
+
return baseEnd;
|
|
77
|
+
};
|
|
78
|
+
const start = sourceAt(clipRelStart, "start");
|
|
79
|
+
const end = sourceAt(clipRelEnd, "end");
|
|
80
|
+
const retained = excluded.flatMap((range) => {
|
|
81
|
+
const clippedStart = Math.max(range.start, start);
|
|
82
|
+
const clippedEnd = Math.min(range.end, end);
|
|
83
|
+
return clippedEnd > clippedStart ? [{ ...range, start: clippedStart, end: clippedEnd }] : [];
|
|
84
|
+
});
|
|
54
85
|
return {
|
|
55
86
|
...source,
|
|
56
|
-
trim: { start
|
|
87
|
+
trim: { start, end },
|
|
88
|
+
...retained.length > 0 ? { excludedRanges: retained } : { excludedRanges: void 0 }
|
|
57
89
|
};
|
|
58
90
|
}
|
|
59
91
|
function cutTimedRange(start, end, cutStart, cutEnd) {
|
|
@@ -234,7 +266,11 @@ function createCompositionOps(get, set) {
|
|
|
234
266
|
const oldRate = clip.source.playbackRate ?? 1;
|
|
235
267
|
if (props.playbackRate !== oldRate) {
|
|
236
268
|
const trim = clip.source.trim;
|
|
237
|
-
const
|
|
269
|
+
const excludedDuration = clip.source.excludedRanges?.reduce(
|
|
270
|
+
(sum, range) => sum + range.end - range.start,
|
|
271
|
+
0
|
|
272
|
+
) ?? 0;
|
|
273
|
+
const sourceDuration = trim ? trim.end - trim.start - excludedDuration : clip.duration * oldRate;
|
|
238
274
|
const newDuration = sourceDuration / props.playbackRate;
|
|
239
275
|
const oldEnd = clip.startTime + clip.duration;
|
|
240
276
|
const delta = newDuration - clip.duration;
|
|
@@ -252,6 +288,16 @@ function createCompositionOps(get, set) {
|
|
|
252
288
|
if (props.fit !== void 0) target.fit = props.fit;
|
|
253
289
|
if (rateChange) {
|
|
254
290
|
if (target.source.kind === "media") {
|
|
291
|
+
if (!target.source.trim && target.source.excludedRanges?.length) {
|
|
292
|
+
const excludedDuration = target.source.excludedRanges.reduce(
|
|
293
|
+
(sum, range) => sum + range.end - range.start,
|
|
294
|
+
0
|
|
295
|
+
);
|
|
296
|
+
target.source.trim = {
|
|
297
|
+
start: 0,
|
|
298
|
+
end: target.duration * (target.source.playbackRate ?? 1) + excludedDuration
|
|
299
|
+
};
|
|
300
|
+
}
|
|
255
301
|
target.source.playbackRate = rateChange.newRate;
|
|
256
302
|
}
|
|
257
303
|
target.duration = rateChange.newDuration;
|
|
@@ -421,7 +467,7 @@ function createCompositionOps(get, set) {
|
|
|
421
467
|
}
|
|
422
468
|
if (cs < start) {
|
|
423
469
|
const leftDuration = start - cs;
|
|
424
|
-
const leftSource = trimSourceFor(c.source, 0, leftDuration);
|
|
470
|
+
const leftSource = trimSourceFor(c.source, 0, leftDuration, c.duration);
|
|
425
471
|
next.push({ ...c, id: c.id, duration: leftDuration, source: leftSource });
|
|
426
472
|
}
|
|
427
473
|
if (ce > end) {
|
|
@@ -430,7 +476,8 @@ function createCompositionOps(get, set) {
|
|
|
430
476
|
const rightSource = trimSourceFor(
|
|
431
477
|
c.source,
|
|
432
478
|
sourceOffsetIntoOriginal,
|
|
433
|
-
sourceOffsetIntoOriginal + rightDuration
|
|
479
|
+
sourceOffsetIntoOriginal + rightDuration,
|
|
480
|
+
c.duration
|
|
434
481
|
);
|
|
435
482
|
next.push({
|
|
436
483
|
...c,
|
|
@@ -472,7 +519,7 @@ function createCompositionOps(get, set) {
|
|
|
472
519
|
const before = target.source.excludedRanges ?? [];
|
|
473
520
|
const beforeTotal = before.reduce((acc, r) => acc + (r.end - r.start), 0);
|
|
474
521
|
const trimStart = target.source.trim?.start ?? 0;
|
|
475
|
-
const trimEnd = target.source.trim?.end ?? trimStart + target.duration + beforeTotal;
|
|
522
|
+
const trimEnd = target.source.trim?.end ?? trimStart + target.duration * (target.source.playbackRate ?? 1) + beforeTotal;
|
|
476
523
|
const lo = Math.max(sourceStart, trimStart);
|
|
477
524
|
const hi = Math.min(sourceEnd, trimEnd);
|
|
478
525
|
if (!(hi > lo)) return;
|
|
@@ -510,9 +557,12 @@ function createCompositionOps(get, set) {
|
|
|
510
557
|
});
|
|
511
558
|
}
|
|
512
559
|
const afterTotal = merged.reduce((acc, r) => acc + (r.end - r.start), 0);
|
|
513
|
-
const
|
|
514
|
-
if (
|
|
560
|
+
const addedSourceDuration = afterTotal - beforeTotal;
|
|
561
|
+
if (addedSourceDuration <= 0) return;
|
|
562
|
+
const rate = target.source.playbackRate ?? 1;
|
|
563
|
+
const delta = addedSourceDuration / rate;
|
|
515
564
|
if (target.duration - delta <= 1e-3) return;
|
|
565
|
+
if (!target.source.trim) target.source.trim = { start: trimStart, end: trimEnd };
|
|
516
566
|
target.source.excludedRanges = merged;
|
|
517
567
|
target.duration = target.duration - delta;
|
|
518
568
|
for (let i = found.clipIndex + 1; i < track.contents.length; i++) {
|
|
@@ -522,7 +572,7 @@ function createCompositionOps(get, set) {
|
|
|
522
572
|
(acc, r) => acc + Math.max(0, Math.min(r.end, lo) - Math.max(r.start, trimStart)),
|
|
523
573
|
0
|
|
524
574
|
);
|
|
525
|
-
const tStart = target.startTime + (lo - trimStart
|
|
575
|
+
const tStart = target.startTime + (lo - trimStart - excludedBeforeLo) / rate;
|
|
526
576
|
const tEnd = tStart + delta;
|
|
527
577
|
if (draft.composition.markers) {
|
|
528
578
|
draft.composition.markers = draft.composition.markers.flatMap((m) => {
|
|
@@ -551,9 +601,19 @@ function createCompositionOps(get, set) {
|
|
|
551
601
|
const ranges = target.source.excludedRanges;
|
|
552
602
|
if (!ranges || rangeIdx < 0 || rangeIdx >= ranges.length) return;
|
|
553
603
|
const removed = ranges[rangeIdx];
|
|
554
|
-
const restored = removed.end - removed.start;
|
|
604
|
+
const restored = (removed.end - removed.start) / (target.source.playbackRate ?? 1);
|
|
555
605
|
if (restored <= 0) return;
|
|
606
|
+
const trimStart = target.source.trim?.start ?? 0;
|
|
607
|
+
const excludedBefore = ranges.reduce((sum, range, index) => index === rangeIdx ? sum : sum + Math.max(0, Math.min(range.end, removed.start) - Math.max(range.start, trimStart)), 0);
|
|
608
|
+
const insertAt = target.startTime + (removed.start - trimStart - excludedBefore) / (target.source.playbackRate ?? 1);
|
|
556
609
|
const next = ranges.filter((_, i) => i !== rangeIdx);
|
|
610
|
+
if (!target.source.trim) {
|
|
611
|
+
const totalExcluded = ranges.reduce((sum, range) => sum + range.end - range.start, 0);
|
|
612
|
+
target.source.trim = {
|
|
613
|
+
start: 0,
|
|
614
|
+
end: target.duration * (target.source.playbackRate ?? 1) + totalExcluded
|
|
615
|
+
};
|
|
616
|
+
}
|
|
557
617
|
if (next.length === 0) {
|
|
558
618
|
delete target.source.excludedRanges;
|
|
559
619
|
} else {
|
|
@@ -563,6 +623,24 @@ function createCompositionOps(get, set) {
|
|
|
563
623
|
for (let i = found.clipIndex + 1; i < track.contents.length; i++) {
|
|
564
624
|
track.contents[i].startTime = track.contents[i].startTime + restored;
|
|
565
625
|
}
|
|
626
|
+
for (const marker of draft.composition.markers ?? []) {
|
|
627
|
+
const shifted = shiftTimedRange(marker.startTime, marker.endTime, insertAt, restored);
|
|
628
|
+
if (shifted) {
|
|
629
|
+
marker.startTime = shifted.start;
|
|
630
|
+
if (shifted.end !== void 0) marker.endTime = shifted.end;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
if (draft.composition.captions) {
|
|
634
|
+
for (const segment of draft.composition.captions.segments) {
|
|
635
|
+
for (const word of segment.words) {
|
|
636
|
+
const shifted = shiftTimedRange(word.startMs, word.endMs, insertAt * 1e3, restored * 1e3);
|
|
637
|
+
if (shifted) {
|
|
638
|
+
word.startMs = shifted.start;
|
|
639
|
+
word.endMs = shifted.end ?? word.endMs;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
566
644
|
});
|
|
567
645
|
},
|
|
568
646
|
setCropIntents: (clipId, segments) => {
|
|
@@ -622,7 +700,8 @@ function createCompositionOps(get, set) {
|
|
|
622
700
|
...Object.fromEntries(Object.entries(style).filter(([, v]) => v !== void 0))
|
|
623
701
|
} : existing?.style;
|
|
624
702
|
const styleField = mergedStyle && Object.keys(mergedStyle).length > 0 ? { style: mergedStyle } : {};
|
|
625
|
-
|
|
703
|
+
const depthField = existing?.zPlane ? { zPlane: existing.zPlane } : {};
|
|
704
|
+
draft.composition.captions = derivedFrom ? { source: "derived", from: derivedFrom, segments, ...styleField, ...depthField } : { source: "authored", segments, ...styleField, ...depthField };
|
|
626
705
|
});
|
|
627
706
|
},
|
|
628
707
|
ripple: (time, amount) => {
|
package/dist/compose.js
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
otioFrames,
|
|
12
12
|
otioRationalTime,
|
|
13
13
|
sourceFrame
|
|
14
|
-
} from "../chunk-
|
|
14
|
+
} from "../chunk-TBHSOEYK.js";
|
|
15
15
|
import {
|
|
16
16
|
InvariantError,
|
|
17
17
|
checkClipDurationMatchesTrim,
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
checkTracks,
|
|
23
23
|
checkTransitions,
|
|
24
24
|
isSourceKindCompatible
|
|
25
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-T56BK7NS.js";
|
|
26
26
|
import "../chunk-2ESYSVXG.js";
|
|
27
27
|
export {
|
|
28
28
|
InvariantError,
|
package/dist/composition/ops.js
CHANGED
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
silhouetteKeepOutForWindow,
|
|
33
33
|
sourceRectToOutput,
|
|
34
34
|
sourceWindowKey
|
|
35
|
-
} from "../chunk-
|
|
35
|
+
} from "../chunk-FGJ7GKWZ.js";
|
|
36
36
|
import {
|
|
37
37
|
BRAND_TOKEN_REFS,
|
|
38
38
|
BRAND_TOKEN_ROOT_KEYS,
|
|
@@ -74,7 +74,7 @@ import {
|
|
|
74
74
|
contrastRatio
|
|
75
75
|
} from "../chunk-ILO4NEZ3.js";
|
|
76
76
|
import "../chunk-VG2ND6PX.js";
|
|
77
|
-
import "../chunk-
|
|
77
|
+
import "../chunk-E63UEO5C.js";
|
|
78
78
|
import "../chunk-AVTEPAWI.js";
|
|
79
79
|
import "../chunk-2ESYSVXG.js";
|
|
80
80
|
export {
|
|
@@ -26,8 +26,8 @@ import {
|
|
|
26
26
|
trackKindForSource,
|
|
27
27
|
trimForSubRange,
|
|
28
28
|
valueAt
|
|
29
|
-
} from "../chunk-
|
|
30
|
-
import "../chunk-
|
|
29
|
+
} from "../chunk-IMIUHG2E.js";
|
|
30
|
+
import "../chunk-T56BK7NS.js";
|
|
31
31
|
import {
|
|
32
32
|
expandClipIdsToLinkGroups,
|
|
33
33
|
expandToLinkGroup,
|