@vosjs/studio-core 0.9.1 → 0.11.0
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/index.d.ts +337 -42
- package/dist/index.js +695 -261
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -424,12 +424,358 @@ function projectFromArtifact(artifact, videoUrl, opts = {}) {
|
|
|
424
424
|
return { doc, videoUrl };
|
|
425
425
|
}
|
|
426
426
|
|
|
427
|
+
// src/lower/motion.ts
|
|
428
|
+
import { sortKeyframes } from "@vosjs/timeline";
|
|
429
|
+
|
|
430
|
+
// src/anim.ts
|
|
431
|
+
var CARD_ENTER_KINDS = [
|
|
432
|
+
"none",
|
|
433
|
+
"fade",
|
|
434
|
+
"rise",
|
|
435
|
+
"tilt-in",
|
|
436
|
+
"pull-out"
|
|
437
|
+
];
|
|
438
|
+
var CARD_EXIT_KINDS = ["none", "fade", "recede"];
|
|
439
|
+
var TEXT_ENTER_KINDS = [
|
|
440
|
+
"none",
|
|
441
|
+
"fade",
|
|
442
|
+
"rise",
|
|
443
|
+
"pop",
|
|
444
|
+
"blur",
|
|
445
|
+
"typewriter"
|
|
446
|
+
];
|
|
447
|
+
var TEXT_EXIT_KINDS = ["none", "fade", "rise"];
|
|
448
|
+
var MEDIA_ENTER_KINDS = ["none", "fade", "rise"];
|
|
449
|
+
var MEDIA_EXIT_KINDS = ["none", "fade", "rise"];
|
|
450
|
+
var IDLE_KINDS = ["spin", "float"];
|
|
451
|
+
var UNIT_KINDS = /* @__PURE__ */ new Set(["pop", "blur", "typewriter"]);
|
|
452
|
+
function animStep(step) {
|
|
453
|
+
if (step == null) return null;
|
|
454
|
+
if (typeof step === "string") return { kind: step };
|
|
455
|
+
return step;
|
|
456
|
+
}
|
|
457
|
+
function enterOf(anim) {
|
|
458
|
+
return animStep(anim?.enter);
|
|
459
|
+
}
|
|
460
|
+
function exitOf(anim) {
|
|
461
|
+
return animStep(anim?.exit);
|
|
462
|
+
}
|
|
463
|
+
function isUnitStep(step) {
|
|
464
|
+
if (!step) return false;
|
|
465
|
+
if (UNIT_KINDS.has(step.kind)) return true;
|
|
466
|
+
if (step.kind !== "fade" && step.kind !== "rise") return false;
|
|
467
|
+
return step.unit !== void 0 || step.stagger !== void 0 || step.seconds !== void 0 || step.direction !== void 0;
|
|
468
|
+
}
|
|
469
|
+
function overlayFxSpec(clip) {
|
|
470
|
+
const step = enterOf(clip.anim);
|
|
471
|
+
if (!isUnitStep(step) || !step || step.kind === "none") return null;
|
|
472
|
+
const kind = step.kind;
|
|
473
|
+
const fx = kind === "fade" || kind === "rise" || kind === "pop" || kind === "blur" || kind === "typewriter" ? kind : "rise";
|
|
474
|
+
return {
|
|
475
|
+
fx,
|
|
476
|
+
...step.unit !== void 0 ? { unit: step.unit } : {},
|
|
477
|
+
...step.direction !== void 0 ? { direction: step.direction } : {},
|
|
478
|
+
...step.stagger !== void 0 ? { stagger: step.stagger } : {},
|
|
479
|
+
...step.seconds !== void 0 ? { duration: step.seconds } : {}
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
var BLOCK_KINDS = /* @__PURE__ */ new Set(["none", "fade", "rise"]);
|
|
483
|
+
function enterKey(clip) {
|
|
484
|
+
const step = enterOf(clip.anim);
|
|
485
|
+
if (!step) return "rise";
|
|
486
|
+
return BLOCK_KINDS.has(step.kind) ? step.kind : "rise";
|
|
487
|
+
}
|
|
488
|
+
function exitKey(clip) {
|
|
489
|
+
const step = exitOf(clip.anim);
|
|
490
|
+
if (!step) return "fade";
|
|
491
|
+
return BLOCK_KINDS.has(step.kind) ? step.kind : "fade";
|
|
492
|
+
}
|
|
493
|
+
function idleKey(clip) {
|
|
494
|
+
const idle = clip.anim?.idle;
|
|
495
|
+
return idle === "spin" || idle === "float" ? idle : null;
|
|
496
|
+
}
|
|
497
|
+
function lastLayerEnd(doc) {
|
|
498
|
+
let end = 0;
|
|
499
|
+
for (const o of doc.overlays ?? []) end = Math.max(end, o.start + o.duration);
|
|
500
|
+
for (const o of doc.objects ?? [])
|
|
501
|
+
if (o.span) end = Math.max(end, o.span.start + o.span.duration);
|
|
502
|
+
return Number.isFinite(end) && end > 0 ? end : 0;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// src/lower/motion.ts
|
|
506
|
+
import { splitBySpeed, totalDuration } from "@vosjs/timeline";
|
|
507
|
+
function docRestTime(doc) {
|
|
508
|
+
if (doc.endCard) return null;
|
|
509
|
+
const last = doc.segments.at(-1);
|
|
510
|
+
const hold = last?.hold;
|
|
511
|
+
if (typeof hold !== "number" || !(hold > 0)) return null;
|
|
512
|
+
const segs = doc.segments.length ? doc.segments : [{ in: 0, out: doc.source.meta.durationMs / 1e3 }];
|
|
513
|
+
const total = totalDuration(
|
|
514
|
+
withHolds(segs, splitBySpeed(segs, doc.speed ?? []))
|
|
515
|
+
);
|
|
516
|
+
const rest = total - hold;
|
|
517
|
+
if (!(rest >= 0)) return null;
|
|
518
|
+
return Math.round(rest * 1e3) / 1e3;
|
|
519
|
+
}
|
|
520
|
+
var ENTRANCE_SECONDS = 1.2;
|
|
521
|
+
var END_CARD_SECONDS = 2.5;
|
|
522
|
+
var END_CARD_RECEDE = 0.7;
|
|
523
|
+
var CARD_FADE_SECONDS = 0.35;
|
|
524
|
+
var TILT_IN_POSE = [-9, 14];
|
|
525
|
+
var PULL_OUT_LEVEL = 1.32;
|
|
526
|
+
var END_CARD_FROM = "endcard";
|
|
527
|
+
var HOLD_SOURCE_SPAN = 2e-3;
|
|
528
|
+
function cardEnter(frame) {
|
|
529
|
+
return enterOf(frame.anim);
|
|
530
|
+
}
|
|
531
|
+
function cardExit(frame) {
|
|
532
|
+
return exitOf(frame.anim);
|
|
533
|
+
}
|
|
534
|
+
function entranceSeconds(e) {
|
|
535
|
+
if (!e || e.kind === "none") return 0;
|
|
536
|
+
return Math.max(0.2, Math.min(3, e.seconds ?? ENTRANCE_SECONDS));
|
|
537
|
+
}
|
|
538
|
+
function exitSeconds(e) {
|
|
539
|
+
if (!e || e.kind === "none") return 0;
|
|
540
|
+
const house = e.kind === "fade" ? CARD_FADE_SECONDS : END_CARD_RECEDE;
|
|
541
|
+
return Math.max(0.1, Math.min(3, e.seconds ?? house));
|
|
542
|
+
}
|
|
543
|
+
function withHolds(docSegments, rated) {
|
|
544
|
+
const out = [];
|
|
545
|
+
const pending = docSegments.filter((s) => typeof s.hold === "number" && s.hold > 0).map((s) => ({ out: s.out, hold: s.hold, used: false }));
|
|
546
|
+
for (let i = 0; i < rated.length; i++) {
|
|
547
|
+
const piece = rated[i];
|
|
548
|
+
out.push(piece);
|
|
549
|
+
const next = rated[i + 1];
|
|
550
|
+
for (const p of pending) {
|
|
551
|
+
if (p.used) continue;
|
|
552
|
+
const endsHere = Math.abs(piece.out - p.out) < 1e-9;
|
|
553
|
+
const nextContinues = next && Math.abs(next.in - p.out) < 1e-9 && next.out > p.out;
|
|
554
|
+
if (endsHere && !nextContinues) {
|
|
555
|
+
out.push({
|
|
556
|
+
in: p.out - HOLD_SOURCE_SPAN,
|
|
557
|
+
out: p.out,
|
|
558
|
+
rate: HOLD_SOURCE_SPAN / p.hold
|
|
559
|
+
});
|
|
560
|
+
p.used = true;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return out;
|
|
565
|
+
}
|
|
566
|
+
function entranceTiltKeyframes(e) {
|
|
567
|
+
const s = entranceSeconds(e);
|
|
568
|
+
if (!s || e?.kind !== "tilt-in") return [];
|
|
569
|
+
return [
|
|
570
|
+
{ t: 0, value: [...TILT_IN_POSE], ease: "none" },
|
|
571
|
+
{ t: s, value: [0, 0], ease: "power3.out" }
|
|
572
|
+
];
|
|
573
|
+
}
|
|
574
|
+
function entranceZoomKeyframes(e) {
|
|
575
|
+
const s = entranceSeconds(e);
|
|
576
|
+
if (!s) return [];
|
|
577
|
+
if (e?.kind === "pull-out")
|
|
578
|
+
return [
|
|
579
|
+
{ t: 0, value: [PULL_OUT_LEVEL, 0.5, 0.42], ease: "none" },
|
|
580
|
+
{ t: s, value: [1, 0.5, 0.5], ease: "power3.out" }
|
|
581
|
+
];
|
|
582
|
+
return [
|
|
583
|
+
{ t: 0, value: [1, 0.5, 0.5], ease: "none" },
|
|
584
|
+
{ t: s, value: [1, 0.5, 0.5], ease: "none" }
|
|
585
|
+
];
|
|
586
|
+
}
|
|
587
|
+
function prependEntrance(track, head) {
|
|
588
|
+
if (!head.length) return track;
|
|
589
|
+
const end = head[head.length - 1].t;
|
|
590
|
+
const rest = (track?.keyframes ?? []).filter((k) => k.t > end + 0.1);
|
|
591
|
+
return { keyframes: sortKeyframes([...head, ...rest]) };
|
|
592
|
+
}
|
|
593
|
+
function exitPose(e) {
|
|
594
|
+
return e?.kind === "fade" ? [1, 0, 0] : [0.9, -0.02, 0.22];
|
|
595
|
+
}
|
|
596
|
+
function cardPoseTrack(enter, exit, footageEnd, outputEnd2 = footageEnd) {
|
|
597
|
+
const keyframes = [];
|
|
598
|
+
const s = entranceSeconds(enter);
|
|
599
|
+
if (s) {
|
|
600
|
+
const from = enter?.kind === "rise" ? [0.96, 0.08, 0.7] : enter?.kind === "pull-out" || enter?.kind === "fade" ? enter.kind === "fade" ? [1, 0, 0] : [1, 0, 1] : [0.94, 0.05, 0.7];
|
|
601
|
+
keyframes.push({ t: 0, value: from, ease: "none" });
|
|
602
|
+
keyframes.push({ t: s, value: [1, 0, 1], ease: "power3.out" });
|
|
603
|
+
}
|
|
604
|
+
const x = exitSeconds(exit);
|
|
605
|
+
if (x > 0 && footageEnd > 0) {
|
|
606
|
+
const room = outputEnd2 - footageEnd;
|
|
607
|
+
const t0 = Math.max(s, room > 1e-6 ? footageEnd : footageEnd - x);
|
|
608
|
+
const t1 = room > 1e-6 ? t0 + Math.min(x, Math.max(0.1, room)) : t0 + x;
|
|
609
|
+
keyframes.push({ t: t0, value: [1, 0, 1], ease: "none" });
|
|
610
|
+
keyframes.push({ t: t1, value: exitPose(exit), ease: "power2.out" });
|
|
611
|
+
}
|
|
612
|
+
if (!keyframes.length) return void 0;
|
|
613
|
+
return { keyframes: sortKeyframes(keyframes) };
|
|
614
|
+
}
|
|
615
|
+
function endCardClips(card, doc, endStart) {
|
|
616
|
+
const seconds = Math.max(1, Math.min(8, card.seconds ?? END_CARD_SECONDS));
|
|
617
|
+
const anim = { enter: "rise", exit: "none" };
|
|
618
|
+
const clips = [];
|
|
619
|
+
const text = (id, body, preset, y, delay) => ({
|
|
620
|
+
id,
|
|
621
|
+
kind: "text",
|
|
622
|
+
text: body,
|
|
623
|
+
preset,
|
|
624
|
+
start: endStart + delay,
|
|
625
|
+
duration: Math.max(0.3, seconds - delay),
|
|
626
|
+
transform: { x: 0.5, y, scale: 1, rotation: 0 },
|
|
627
|
+
anim,
|
|
628
|
+
from: END_CARD_FROM,
|
|
629
|
+
align: "center",
|
|
630
|
+
...card.ink ? { color: card.ink } : {},
|
|
631
|
+
shadow: 0
|
|
632
|
+
});
|
|
633
|
+
if (card.headline?.trim())
|
|
634
|
+
clips.push(text("endcard-title", card.headline.trim(), "title", 0.44, 0.35));
|
|
635
|
+
if (card.sub?.trim())
|
|
636
|
+
clips.push(text("endcard-sub", card.sub.trim(), "caption", 0.57, 0.5));
|
|
637
|
+
const mark = card.mark;
|
|
638
|
+
const wide = !!mark && mark.aspect > 2.2;
|
|
639
|
+
if (mark && mark.key) {
|
|
640
|
+
const size = resolveExportSize(doc);
|
|
641
|
+
const designW = 1080 * size.width / Math.max(1, size.height);
|
|
642
|
+
const hPx = wide ? 44 : 30;
|
|
643
|
+
const clip = {
|
|
644
|
+
id: "endcard-markimg",
|
|
645
|
+
kind: "image",
|
|
646
|
+
key: mark.key,
|
|
647
|
+
width: Math.min(0.9, hPx * Math.max(0.2, mark.aspect) / designW),
|
|
648
|
+
radius: 0,
|
|
649
|
+
shadow: "none",
|
|
650
|
+
start: endStart + 0.65,
|
|
651
|
+
duration: Math.max(0.3, seconds - 0.65),
|
|
652
|
+
transform: { x: 0.5, y: wide ? 0.88 : 0.835, scale: 1, rotation: 0 },
|
|
653
|
+
anim,
|
|
654
|
+
from: END_CARD_FROM
|
|
655
|
+
};
|
|
656
|
+
clips.push(clip);
|
|
657
|
+
}
|
|
658
|
+
if (card.wordmark?.trim() && !wide)
|
|
659
|
+
clips.push(
|
|
660
|
+
text(
|
|
661
|
+
"endcard-mark",
|
|
662
|
+
card.wordmark.trim(),
|
|
663
|
+
"label",
|
|
664
|
+
mark && mark.key ? 0.895 : 0.88,
|
|
665
|
+
0.65
|
|
666
|
+
)
|
|
667
|
+
);
|
|
668
|
+
return clips;
|
|
669
|
+
}
|
|
670
|
+
function expandEndCard(doc, outputDuration) {
|
|
671
|
+
const card = doc.endCard;
|
|
672
|
+
if (!card || !doc.segments.length) return { doc, endStart: null, seconds: 0 };
|
|
673
|
+
const seconds = Math.max(1, Math.min(8, card.seconds ?? END_CARD_SECONDS));
|
|
674
|
+
const segments = doc.segments.map(
|
|
675
|
+
(s, i) => i === doc.segments.length - 1 ? { ...s, hold: (s.hold ?? 0) + seconds } : s
|
|
676
|
+
);
|
|
677
|
+
const endStart = outputDuration;
|
|
678
|
+
const overlays = [
|
|
679
|
+
...doc.overlays ?? [],
|
|
680
|
+
...endCardClips(card, doc, endStart)
|
|
681
|
+
];
|
|
682
|
+
return { doc: { ...doc, segments, overlays }, endStart, seconds };
|
|
683
|
+
}
|
|
684
|
+
var hasLegacyClipMotion = (o) => o.enter !== void 0 || o.exit !== void 0 || o.kind === "text" && o.fx !== void 0;
|
|
685
|
+
function migrateClipAnim(o) {
|
|
686
|
+
const anim = { ...o.anim ?? {} };
|
|
687
|
+
if (o.kind === "text" && o.fx) {
|
|
688
|
+
const fx = o.fx;
|
|
689
|
+
anim.enter = {
|
|
690
|
+
kind: fx.fx,
|
|
691
|
+
unit: fx.unit ?? "block",
|
|
692
|
+
...fx.direction !== void 0 ? { direction: fx.direction } : {},
|
|
693
|
+
...fx.stagger !== void 0 ? { stagger: fx.stagger } : {},
|
|
694
|
+
...fx.duration !== void 0 ? { seconds: fx.duration } : {}
|
|
695
|
+
};
|
|
696
|
+
} else if (o.enter !== void 0 && anim.enter === void 0) {
|
|
697
|
+
anim.enter = o.enter;
|
|
698
|
+
}
|
|
699
|
+
if (o.exit !== void 0 && anim.exit === void 0) anim.exit = o.exit;
|
|
700
|
+
return anim;
|
|
701
|
+
}
|
|
702
|
+
function migrateMotion(doc) {
|
|
703
|
+
const frame = doc.frame ?? {};
|
|
704
|
+
const segments = Array.isArray(doc.segments) ? doc.segments : [];
|
|
705
|
+
const overlays = Array.isArray(doc.overlays) ? doc.overlays : [];
|
|
706
|
+
const objects = Array.isArray(doc.objects) ? doc.objects : [];
|
|
707
|
+
const legacy = frame.entrance !== void 0 || doc.endCard !== void 0 || overlays.some(hasLegacyClipMotion) || objects.some((o) => o.animation !== void 0);
|
|
708
|
+
if (!legacy) return doc;
|
|
709
|
+
const out = { ...doc };
|
|
710
|
+
const nextFrame = { ...frame };
|
|
711
|
+
if (frame.entrance !== void 0) {
|
|
712
|
+
const e = frame.entrance;
|
|
713
|
+
if (e && e.kind !== "none") {
|
|
714
|
+
nextFrame.anim = {
|
|
715
|
+
...frame.anim ?? {},
|
|
716
|
+
enter: e.seconds !== void 0 ? { kind: e.kind, seconds: e.seconds } : e.kind
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
delete nextFrame.entrance;
|
|
720
|
+
}
|
|
721
|
+
let nextOverlays = overlays.map((o) => {
|
|
722
|
+
if (!hasLegacyClipMotion(o)) return o;
|
|
723
|
+
const next = { ...o, anim: migrateClipAnim(o) };
|
|
724
|
+
delete next.enter;
|
|
725
|
+
delete next.exit;
|
|
726
|
+
if (next.kind === "text") delete next.fx;
|
|
727
|
+
return next;
|
|
728
|
+
});
|
|
729
|
+
if (doc.endCard !== void 0) {
|
|
730
|
+
const card = doc.endCard;
|
|
731
|
+
if (card && segments.length) {
|
|
732
|
+
const seconds = Math.max(1, Math.min(8, card.seconds ?? END_CARD_SECONDS));
|
|
733
|
+
const rated = withHolds(segments, splitBySpeed(segments, doc.speed ?? []));
|
|
734
|
+
const endStart = totalDuration(rated);
|
|
735
|
+
nextOverlays = [...nextOverlays, ...endCardClips(card, doc, endStart)];
|
|
736
|
+
nextFrame.anim = {
|
|
737
|
+
...nextFrame.anim ?? {},
|
|
738
|
+
exit: {
|
|
739
|
+
kind: "recede",
|
|
740
|
+
seconds: Math.min(END_CARD_RECEDE, seconds * 0.4)
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
delete out.endCard;
|
|
745
|
+
}
|
|
746
|
+
const nextObjects = objects.map((o) => {
|
|
747
|
+
if (o.animation === void 0) return o;
|
|
748
|
+
const next = {
|
|
749
|
+
...o,
|
|
750
|
+
anim: {
|
|
751
|
+
...o.anim ?? {},
|
|
752
|
+
...o.anim?.idle === void 0 ? { idle: o.animation ?? null } : {}
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
delete next.animation;
|
|
756
|
+
return next;
|
|
757
|
+
});
|
|
758
|
+
if (doc.frame !== void 0 || nextFrame.anim !== void 0)
|
|
759
|
+
out.frame = nextFrame;
|
|
760
|
+
if (doc.overlays !== void 0 || nextOverlays.length)
|
|
761
|
+
out.overlays = nextOverlays;
|
|
762
|
+
if (doc.objects !== void 0) out.objects = nextObjects;
|
|
763
|
+
return out;
|
|
764
|
+
}
|
|
765
|
+
function outputEnd(doc, footageEnd) {
|
|
766
|
+
return Math.max(footageEnd, lastLayerEnd(doc));
|
|
767
|
+
}
|
|
768
|
+
|
|
427
769
|
// src/docVersion.ts
|
|
428
|
-
var DOC_SCHEMA_VERSION =
|
|
770
|
+
var DOC_SCHEMA_VERSION = 3;
|
|
429
771
|
function migrateHostedDoc(raw) {
|
|
430
772
|
const version = typeof raw.docSchemaVersion === "number" ? raw.docSchemaVersion : 0;
|
|
431
773
|
if (version >= DOC_SCHEMA_VERSION) return raw;
|
|
432
|
-
|
|
774
|
+
let doc = raw;
|
|
775
|
+
if (version < 3 && doc.source && typeof doc.source === "object") {
|
|
776
|
+
doc = migrateMotion(doc);
|
|
777
|
+
}
|
|
778
|
+
return { ...doc, docSchemaVersion: DOC_SCHEMA_VERSION };
|
|
433
779
|
}
|
|
434
780
|
|
|
435
781
|
// src/doc/studioDoc.ts
|
|
@@ -1102,8 +1448,8 @@ import {
|
|
|
1102
1448
|
segmentRate as segmentRate2,
|
|
1103
1449
|
sortKeyframes as sortKeyframes2,
|
|
1104
1450
|
sourceToTimeline as sourceToTimeline2,
|
|
1105
|
-
splitBySpeed,
|
|
1106
|
-
totalDuration
|
|
1451
|
+
splitBySpeed as splitBySpeed2,
|
|
1452
|
+
totalDuration as totalDuration2
|
|
1107
1453
|
} from "@vosjs/timeline";
|
|
1108
1454
|
import { timelineRuntimeCode as timelineRuntimeCode2 } from "@vosjs/timeline/bundle";
|
|
1109
1455
|
|
|
@@ -1452,7 +1798,7 @@ function overlaySegments(text, unit) {
|
|
|
1452
1798
|
}
|
|
1453
1799
|
var FX_DIR = { forward: 0, reverse: 1, center: 2 };
|
|
1454
1800
|
function resolveOverlayFx(clip, clipDuration) {
|
|
1455
|
-
const spec = clip.fx;
|
|
1801
|
+
const spec = overlayFxSpec(clip) ?? clip.fx ?? null;
|
|
1456
1802
|
if (!spec) return null;
|
|
1457
1803
|
const unit = spec.unit ?? "block";
|
|
1458
1804
|
const units = overlaySegments(clip.text, unit);
|
|
@@ -2772,150 +3118,6 @@ var STUDIO_FRAME = `(ctx, content, dt) => {
|
|
|
2772
3118
|
|
|
2773
3119
|
}`;
|
|
2774
3120
|
|
|
2775
|
-
// src/lower/motion.ts
|
|
2776
|
-
import { sortKeyframes } from "@vosjs/timeline";
|
|
2777
|
-
var ENTRANCE_SECONDS = 1.2;
|
|
2778
|
-
var END_CARD_SECONDS = 2.5;
|
|
2779
|
-
var END_CARD_RECEDE = 0.7;
|
|
2780
|
-
var TILT_IN_POSE = [-9, 14];
|
|
2781
|
-
var PULL_OUT_LEVEL = 1.32;
|
|
2782
|
-
var HOLD_SOURCE_SPAN = 2e-3;
|
|
2783
|
-
function entranceSeconds(e) {
|
|
2784
|
-
if (!e || e.kind === "none") return 0;
|
|
2785
|
-
return Math.max(0.2, Math.min(3, e.seconds ?? ENTRANCE_SECONDS));
|
|
2786
|
-
}
|
|
2787
|
-
function withHolds(docSegments, rated) {
|
|
2788
|
-
const out = [];
|
|
2789
|
-
const pending = docSegments.filter((s) => typeof s.hold === "number" && s.hold > 0).map((s) => ({ out: s.out, hold: s.hold, used: false }));
|
|
2790
|
-
for (let i = 0; i < rated.length; i++) {
|
|
2791
|
-
const piece = rated[i];
|
|
2792
|
-
out.push(piece);
|
|
2793
|
-
const next = rated[i + 1];
|
|
2794
|
-
for (const p of pending) {
|
|
2795
|
-
if (p.used) continue;
|
|
2796
|
-
const endsHere = Math.abs(piece.out - p.out) < 1e-9;
|
|
2797
|
-
const nextContinues = next && Math.abs(next.in - p.out) < 1e-9 && next.out > p.out;
|
|
2798
|
-
if (endsHere && !nextContinues) {
|
|
2799
|
-
out.push({
|
|
2800
|
-
in: p.out - HOLD_SOURCE_SPAN,
|
|
2801
|
-
out: p.out,
|
|
2802
|
-
rate: HOLD_SOURCE_SPAN / p.hold
|
|
2803
|
-
});
|
|
2804
|
-
p.used = true;
|
|
2805
|
-
}
|
|
2806
|
-
}
|
|
2807
|
-
}
|
|
2808
|
-
return out;
|
|
2809
|
-
}
|
|
2810
|
-
function entranceTiltKeyframes(e) {
|
|
2811
|
-
const s = entranceSeconds(e);
|
|
2812
|
-
if (!s || e?.kind !== "tilt-in") return [];
|
|
2813
|
-
return [
|
|
2814
|
-
{ t: 0, value: [...TILT_IN_POSE], ease: "none" },
|
|
2815
|
-
{ t: s, value: [0, 0], ease: "power3.out" }
|
|
2816
|
-
];
|
|
2817
|
-
}
|
|
2818
|
-
function entranceZoomKeyframes(e) {
|
|
2819
|
-
const s = entranceSeconds(e);
|
|
2820
|
-
if (!s) return [];
|
|
2821
|
-
if (e?.kind === "pull-out")
|
|
2822
|
-
return [
|
|
2823
|
-
{ t: 0, value: [PULL_OUT_LEVEL, 0.5, 0.42], ease: "none" },
|
|
2824
|
-
{ t: s, value: [1, 0.5, 0.5], ease: "power3.out" }
|
|
2825
|
-
];
|
|
2826
|
-
return [
|
|
2827
|
-
{ t: 0, value: [1, 0.5, 0.5], ease: "none" },
|
|
2828
|
-
{ t: s, value: [1, 0.5, 0.5], ease: "none" }
|
|
2829
|
-
];
|
|
2830
|
-
}
|
|
2831
|
-
function prependEntrance(track, head) {
|
|
2832
|
-
if (!head.length) return track;
|
|
2833
|
-
const end = head[head.length - 1].t;
|
|
2834
|
-
const rest = (track?.keyframes ?? []).filter((k) => k.t > end + 0.1);
|
|
2835
|
-
return { keyframes: sortKeyframes([...head, ...rest]) };
|
|
2836
|
-
}
|
|
2837
|
-
function cardPoseTrack(e, endStart, endSeconds) {
|
|
2838
|
-
const keyframes = [];
|
|
2839
|
-
const s = entranceSeconds(e);
|
|
2840
|
-
if (s) {
|
|
2841
|
-
const from = e?.kind === "rise" ? [0.96, 0.08, 0.7] : e?.kind === "pull-out" ? [1, 0, 1] : [0.94, 0.05, 0.7];
|
|
2842
|
-
keyframes.push({ t: 0, value: from, ease: "none" });
|
|
2843
|
-
keyframes.push({ t: s, value: [1, 0, 1], ease: "power3.out" });
|
|
2844
|
-
}
|
|
2845
|
-
if (endStart !== null && endSeconds > 0) {
|
|
2846
|
-
const t0 = Math.max(endStart, s);
|
|
2847
|
-
keyframes.push({ t: t0, value: [1, 0, 1], ease: "none" });
|
|
2848
|
-
keyframes.push({
|
|
2849
|
-
t: t0 + Math.min(END_CARD_RECEDE, endSeconds * 0.4),
|
|
2850
|
-
value: [0.9, -0.02, 0.22],
|
|
2851
|
-
ease: "power2.out"
|
|
2852
|
-
});
|
|
2853
|
-
}
|
|
2854
|
-
if (!keyframes.length) return void 0;
|
|
2855
|
-
return { keyframes: sortKeyframes(keyframes) };
|
|
2856
|
-
}
|
|
2857
|
-
function expandEndCard(doc, outputDuration) {
|
|
2858
|
-
const card = doc.endCard;
|
|
2859
|
-
if (!card || !doc.segments.length) return { doc, endStart: null, seconds: 0 };
|
|
2860
|
-
const seconds = Math.max(1, Math.min(8, card.seconds ?? END_CARD_SECONDS));
|
|
2861
|
-
const segments = doc.segments.map(
|
|
2862
|
-
(s, i) => i === doc.segments.length - 1 ? { ...s, hold: (s.hold ?? 0) + seconds } : s
|
|
2863
|
-
);
|
|
2864
|
-
const endStart = outputDuration;
|
|
2865
|
-
const clips = [];
|
|
2866
|
-
const text = (id, body, preset, y, delay) => ({
|
|
2867
|
-
id,
|
|
2868
|
-
kind: "text",
|
|
2869
|
-
text: body,
|
|
2870
|
-
preset,
|
|
2871
|
-
start: endStart + delay,
|
|
2872
|
-
duration: Math.max(0.3, seconds - delay),
|
|
2873
|
-
transform: { x: 0.5, y, scale: 1, rotation: 0 },
|
|
2874
|
-
enter: "rise",
|
|
2875
|
-
exit: "none",
|
|
2876
|
-
align: "center",
|
|
2877
|
-
...card.ink ? { color: card.ink } : {},
|
|
2878
|
-
shadow: 0
|
|
2879
|
-
});
|
|
2880
|
-
if (card.headline?.trim())
|
|
2881
|
-
clips.push(text("endcard-title", card.headline.trim(), "title", 0.44, 0.35));
|
|
2882
|
-
if (card.sub?.trim())
|
|
2883
|
-
clips.push(text("endcard-sub", card.sub.trim(), "caption", 0.57, 0.5));
|
|
2884
|
-
const mark = card.mark;
|
|
2885
|
-
const wide = !!mark && mark.aspect > 2.2;
|
|
2886
|
-
if (mark && mark.key) {
|
|
2887
|
-
const size = resolveExportSize(doc);
|
|
2888
|
-
const designW = 1080 * size.width / Math.max(1, size.height);
|
|
2889
|
-
const hPx = wide ? 44 : 30;
|
|
2890
|
-
const clip = {
|
|
2891
|
-
id: "endcard-markimg",
|
|
2892
|
-
kind: "image",
|
|
2893
|
-
key: mark.key,
|
|
2894
|
-
width: Math.min(0.9, hPx * Math.max(0.2, mark.aspect) / designW),
|
|
2895
|
-
radius: 0,
|
|
2896
|
-
shadow: "none",
|
|
2897
|
-
start: endStart + 0.65,
|
|
2898
|
-
duration: Math.max(0.3, seconds - 0.65),
|
|
2899
|
-
transform: { x: 0.5, y: wide ? 0.88 : 0.835, scale: 1, rotation: 0 },
|
|
2900
|
-
enter: "rise",
|
|
2901
|
-
exit: "none"
|
|
2902
|
-
};
|
|
2903
|
-
clips.push(clip);
|
|
2904
|
-
}
|
|
2905
|
-
if (card.wordmark?.trim() && !wide)
|
|
2906
|
-
clips.push(
|
|
2907
|
-
text(
|
|
2908
|
-
"endcard-mark",
|
|
2909
|
-
card.wordmark.trim(),
|
|
2910
|
-
"label",
|
|
2911
|
-
mark && mark.key ? 0.895 : 0.88,
|
|
2912
|
-
0.65
|
|
2913
|
-
)
|
|
2914
|
-
);
|
|
2915
|
-
const overlays = [...doc.overlays ?? [], ...clips];
|
|
2916
|
-
return { doc: { ...doc, segments, overlays }, endStart, seconds };
|
|
2917
|
-
}
|
|
2918
|
-
|
|
2919
3121
|
// src/lower/extractClicks.ts
|
|
2920
3122
|
import { segmentRate, sourceToTimeline } from "@vosjs/timeline";
|
|
2921
3123
|
var CLICK_FX_PRE = 0.06;
|
|
@@ -3020,10 +3222,10 @@ var CAM_PAN_EASE = ZOOM_PAN_EASE;
|
|
|
3020
3222
|
var PROGRAM_DURATION = 1;
|
|
3021
3223
|
function ratedSegments(doc) {
|
|
3022
3224
|
const segs = isRecordingDoc(doc) ? doc.segments.length ? doc.segments : [{ in: 0, out: doc.source.meta.durationMs / 1e3 }] : [{ in: 0, out: programDuration(doc) }];
|
|
3023
|
-
return withHolds(segs,
|
|
3225
|
+
return withHolds(segs, splitBySpeed2(segs, doc.speed ?? []));
|
|
3024
3226
|
}
|
|
3025
3227
|
function durationSec(doc, rated) {
|
|
3026
|
-
const trimmed =
|
|
3228
|
+
const trimmed = totalDuration2(rated);
|
|
3027
3229
|
return trimmed > 0 ? trimmed : doc.source.meta.durationMs / 1e3;
|
|
3028
3230
|
}
|
|
3029
3231
|
function spanOutputExtent(segments, sIn, sOut) {
|
|
@@ -4608,7 +4810,7 @@ function studioLayerData(layers, duration) {
|
|
|
4608
4810
|
ry: round5(o.transform3d.ry),
|
|
4609
4811
|
rz: round5(o.transform3d.rz),
|
|
4610
4812
|
scale: round5(o.transform3d.scale || OBJECT_DEFAULT_SCALE),
|
|
4611
|
-
anim: o
|
|
4813
|
+
anim: idleKey(o),
|
|
4612
4814
|
// Pose keyframes: clip-local [x,y,z,rx,ry,rz,scale] track,
|
|
4613
4815
|
// sampled at t − span.start. Omitted when absent — parity.
|
|
4614
4816
|
...(() => {
|
|
@@ -4640,8 +4842,8 @@ function studioLayerData(layers, duration) {
|
|
|
4640
4842
|
y: round5(o.transform.y),
|
|
4641
4843
|
scale: round5(o.transform.scale || 1),
|
|
4642
4844
|
rot: round5(o.transform.rotation || 0),
|
|
4643
|
-
enter: o
|
|
4644
|
-
exit: o
|
|
4845
|
+
enter: enterKey(o),
|
|
4846
|
+
exit: exitKey(o),
|
|
4645
4847
|
// Pose keyframes: a CLIP-LOCAL [x, y, scale, rot, opacity]
|
|
4646
4848
|
// track, sampled in ON_FRAME at t − start. Omitted when the clip
|
|
4647
4849
|
// has no motion — data byte parity.
|
|
@@ -4729,11 +4931,10 @@ function studioLayerData(layers, duration) {
|
|
|
4729
4931
|
};
|
|
4730
4932
|
}
|
|
4731
4933
|
function lowerToComposition(input) {
|
|
4732
|
-
const
|
|
4733
|
-
const expanded = expandEndCard(input, before);
|
|
4734
|
-
const doc = expanded.doc;
|
|
4934
|
+
const doc = migrateMotion(input);
|
|
4735
4935
|
const rated = ratedSegments(doc);
|
|
4736
|
-
const
|
|
4936
|
+
const footageEnd = durationSec(doc, rated);
|
|
4937
|
+
const duration = outputEnd(doc, footageEnd);
|
|
4737
4938
|
const fx = doc.cursor.clickFx;
|
|
4738
4939
|
const smoothed = smoothCursor(doc.source.cursor, {
|
|
4739
4940
|
factor: doc.cursor.smoothing,
|
|
@@ -4807,7 +5008,7 @@ function lowerToComposition(input) {
|
|
|
4807
5008
|
// A pull-out entrance writes the track's head.
|
|
4808
5009
|
zoomTrack: prependEntrance(
|
|
4809
5010
|
zoomTrackFromDoc(zoomSpans, rated, zoomStyle),
|
|
4810
|
-
entranceZoomKeyframes(doc.frame
|
|
5011
|
+
entranceZoomKeyframes(cardEnter(doc.frame))
|
|
4811
5012
|
),
|
|
4812
5013
|
// Tilt spans: OUTPUT-time [rx, ry] degree track. The rest pose is
|
|
4813
5014
|
// FLAT — there is no static card tilt any more — and the motion constants
|
|
@@ -4816,18 +5017,19 @@ function lowerToComposition(input) {
|
|
|
4816
5017
|
// spans and no tilt-in entrance — byte parity. The entrance is a
|
|
4817
5018
|
// producer of this track, never a second pose.
|
|
4818
5019
|
...(() => {
|
|
4819
|
-
const head = entranceTiltKeyframes(doc.frame
|
|
5020
|
+
const head = entranceTiltKeyframes(cardEnter(doc.frame));
|
|
4820
5021
|
const spans = doc.tilt && doc.tilt.length ? tiltTrackFromDoc(doc.tilt, rated, zoomStyle.tilt) : void 0;
|
|
4821
5022
|
const track = prependEntrance(spans, head);
|
|
4822
5023
|
return track ? { tiltTrack: track } : {};
|
|
4823
5024
|
})(),
|
|
4824
|
-
// The card's pose through
|
|
4825
|
-
//
|
|
5025
|
+
// The card's pose through its enter and its exit: [scale, dy, opacity]
|
|
5026
|
+
// in output seconds. Absent when the card carries neither.
|
|
4826
5027
|
...(() => {
|
|
4827
5028
|
const track = cardPoseTrack(
|
|
4828
|
-
doc.frame
|
|
4829
|
-
|
|
4830
|
-
|
|
5029
|
+
cardEnter(doc.frame),
|
|
5030
|
+
cardExit(doc.frame),
|
|
5031
|
+
footageEnd,
|
|
5032
|
+
duration
|
|
4831
5033
|
);
|
|
4832
5034
|
return track ? { cardPoseTrack: track } : {};
|
|
4833
5035
|
})()
|
|
@@ -5278,6 +5480,92 @@ function zoomCoversRect(span, rect, layout, tol = 0.02) {
|
|
|
5278
5480
|
return rect.x >= w.x0 - tol && rect.x + rect.w <= w.x1 + tol && rect.y >= w.y0 - tol && rect.y + rect.h <= w.y1 + tol;
|
|
5279
5481
|
}
|
|
5280
5482
|
|
|
5483
|
+
// src/digest/style.ts
|
|
5484
|
+
import { totalDuration as totalDuration4 } from "@vosjs/timeline";
|
|
5485
|
+
|
|
5486
|
+
// src/audioBeds.ts
|
|
5487
|
+
import { totalDuration as totalDuration3 } from "@vosjs/timeline";
|
|
5488
|
+
var round32 = (v) => Math.round(v * 1e3) / 1e3;
|
|
5489
|
+
function docOutputDuration(doc) {
|
|
5490
|
+
const footage = totalDuration3(ratedSegments(doc));
|
|
5491
|
+
return isRecordingDoc(doc) ? outputEnd(migrateMotion(doc), footage) : footage;
|
|
5492
|
+
}
|
|
5493
|
+
function musicBedClip(input) {
|
|
5494
|
+
const track = round32(input.trackDuration);
|
|
5495
|
+
const output = round32(input.outputDuration);
|
|
5496
|
+
const clip = {
|
|
5497
|
+
id: input.id,
|
|
5498
|
+
key: input.key,
|
|
5499
|
+
name: input.name,
|
|
5500
|
+
start: 0,
|
|
5501
|
+
in: 0,
|
|
5502
|
+
out: track,
|
|
5503
|
+
duration: track,
|
|
5504
|
+
// Under speech, not over it; catalog tracks are loudness-normalized so
|
|
5505
|
+
// one default means the same thing across the library.
|
|
5506
|
+
gain: 0.5,
|
|
5507
|
+
fadeIn: 0,
|
|
5508
|
+
// A bed that just stops reads as a glitch; clamp so a very short cut
|
|
5509
|
+
// still spends most of its time at full level.
|
|
5510
|
+
fadeOut: output > 0 ? Math.min(1.5, round32(output / 4)) : 1.5,
|
|
5511
|
+
duck: input.hasMic || void 0
|
|
5512
|
+
};
|
|
5513
|
+
if (output <= 0) return clip;
|
|
5514
|
+
if (track >= output) {
|
|
5515
|
+
clip.out = output;
|
|
5516
|
+
} else {
|
|
5517
|
+
clip.loop = true;
|
|
5518
|
+
clip.loopLen = output;
|
|
5519
|
+
}
|
|
5520
|
+
return clip;
|
|
5521
|
+
}
|
|
5522
|
+
function isMusicBed(clip, outputDuration) {
|
|
5523
|
+
if (clip.start > 0.05) return false;
|
|
5524
|
+
if (clip.loop) return true;
|
|
5525
|
+
const placed = clip.out - clip.in;
|
|
5526
|
+
return Math.abs(placed - outputDuration) <= 1;
|
|
5527
|
+
}
|
|
5528
|
+
function refillAudioBeds(doc, prevDuration, nextDuration) {
|
|
5529
|
+
const EPS2 = 0.05;
|
|
5530
|
+
if (Math.abs(nextDuration - prevDuration) <= EPS2 || nextDuration <= 0) {
|
|
5531
|
+
return false;
|
|
5532
|
+
}
|
|
5533
|
+
let changed = false;
|
|
5534
|
+
for (const clip of doc.audio) {
|
|
5535
|
+
if (clip.start >= nextDuration) continue;
|
|
5536
|
+
const placed = clip.loop ? Math.max(clip.out - clip.in, clip.loopLen ?? clip.out - clip.in) : clip.out - clip.in;
|
|
5537
|
+
if (Math.abs(clip.start + placed - prevDuration) > EPS2) continue;
|
|
5538
|
+
const span = clip.out - clip.in;
|
|
5539
|
+
const nextLen = round32(nextDuration - clip.start);
|
|
5540
|
+
if (clip.loop) {
|
|
5541
|
+
if (nextLen >= span) {
|
|
5542
|
+
clip.loopLen = nextLen;
|
|
5543
|
+
} else {
|
|
5544
|
+
clip.loop = void 0;
|
|
5545
|
+
clip.loopLen = void 0;
|
|
5546
|
+
clip.out = round32(clip.in + nextLen);
|
|
5547
|
+
}
|
|
5548
|
+
} else {
|
|
5549
|
+
if (clip.in + nextLen <= clip.duration) {
|
|
5550
|
+
clip.out = round32(clip.in + nextLen);
|
|
5551
|
+
} else {
|
|
5552
|
+
clip.out = clip.duration;
|
|
5553
|
+
clip.loop = true;
|
|
5554
|
+
clip.loopLen = nextLen;
|
|
5555
|
+
}
|
|
5556
|
+
}
|
|
5557
|
+
changed = true;
|
|
5558
|
+
}
|
|
5559
|
+
return changed;
|
|
5560
|
+
}
|
|
5561
|
+
function voiceKey(doc) {
|
|
5562
|
+
if (!("source" in doc)) return null;
|
|
5563
|
+
const src = doc.source;
|
|
5564
|
+
if (src.micKey) return src.micKey;
|
|
5565
|
+
if (src.meta.hasAudio && !src.meta.hasMic) return src.videoKey;
|
|
5566
|
+
return null;
|
|
5567
|
+
}
|
|
5568
|
+
|
|
5281
5569
|
// src/digest/style.ts
|
|
5282
5570
|
var STYLE_FIELDS = [
|
|
5283
5571
|
"zoomStyle",
|
|
@@ -5297,15 +5585,210 @@ function pickStyle(doc) {
|
|
|
5297
5585
|
}
|
|
5298
5586
|
return out;
|
|
5299
5587
|
}
|
|
5300
|
-
function copyStyle(from, to) {
|
|
5588
|
+
function copyStyle(from, to, opts = {}) {
|
|
5301
5589
|
const next = structuredClone(to);
|
|
5302
5590
|
const style = pickStyle(from);
|
|
5303
5591
|
for (const k of STYLE_FIELDS) {
|
|
5304
5592
|
if (k in style) next[k] = style[k];
|
|
5305
5593
|
else delete next[k];
|
|
5306
5594
|
}
|
|
5307
|
-
|
|
5595
|
+
const styled = next;
|
|
5596
|
+
return opts.layout ? copyLayout(from, styled, { keys: opts.keys }).doc : styled;
|
|
5597
|
+
}
|
|
5598
|
+
var LAYOUT_FRAME_FIELDS = [
|
|
5599
|
+
"background",
|
|
5600
|
+
"padding",
|
|
5601
|
+
"radius",
|
|
5602
|
+
"shadow",
|
|
5603
|
+
"shadowContact",
|
|
5604
|
+
"shadowColor",
|
|
5605
|
+
"inset",
|
|
5606
|
+
"border",
|
|
5607
|
+
"borderWidth",
|
|
5608
|
+
"borderColor",
|
|
5609
|
+
"fit",
|
|
5610
|
+
"focus",
|
|
5611
|
+
"focusFollow",
|
|
5612
|
+
"parallax",
|
|
5613
|
+
"anim"
|
|
5614
|
+
];
|
|
5615
|
+
var STAGE_CLIP_PREFIX = "stage-";
|
|
5616
|
+
var REST_TILT_ID = "rest";
|
|
5617
|
+
var isStageClip = (clip) => clip.id.startsWith(STAGE_CLIP_PREFIX);
|
|
5618
|
+
function restLeanOf(doc) {
|
|
5619
|
+
const spans = doc.tilt ?? [];
|
|
5620
|
+
const named = spans.find((z) => z.id === REST_TILT_ID || z.id === "stage");
|
|
5621
|
+
if (named) return { rx: named.rx, ry: named.ry };
|
|
5622
|
+
const total = anchorSourceDuration(doc);
|
|
5623
|
+
const whole = spans.find((z) => z.out - z.in >= total * 0.9);
|
|
5624
|
+
return whole ? { rx: whole.rx, ry: whole.ry } : null;
|
|
5625
|
+
}
|
|
5626
|
+
function layoutOf(doc) {
|
|
5627
|
+
const frame = doc.frame;
|
|
5628
|
+
return {
|
|
5629
|
+
frame: LAYOUT_FRAME_FIELDS.filter((k) => frame[k] !== void 0),
|
|
5630
|
+
clips: (doc.overlays ?? []).filter(isStageClip).map((o) => o.id),
|
|
5631
|
+
lean: restLeanOf(doc) !== null,
|
|
5632
|
+
hold: (doc.segments.at(-1)?.hold ?? 0) > 0
|
|
5633
|
+
};
|
|
5634
|
+
}
|
|
5635
|
+
function copyLayout(from, to, opts = {}) {
|
|
5636
|
+
const doc = structuredClone(to);
|
|
5637
|
+
const notes = [];
|
|
5638
|
+
const frame = doc.frame;
|
|
5639
|
+
const src = from.frame;
|
|
5640
|
+
for (const k of LAYOUT_FRAME_FIELDS) {
|
|
5641
|
+
if (src[k] !== void 0) frame[k] = structuredClone(src[k]);
|
|
5642
|
+
else delete frame[k];
|
|
5643
|
+
}
|
|
5644
|
+
if (from.frame.backgroundMedia)
|
|
5645
|
+
doc.frame.backgroundMedia = structuredClone(from.frame.backgroundMedia);
|
|
5646
|
+
const outDur = docOutputDuration(doc);
|
|
5647
|
+
const own = new Map((doc.overlays ?? []).map((o) => [o.id, o]));
|
|
5648
|
+
const merged = (doc.overlays ?? []).filter(
|
|
5649
|
+
(o) => !isStageClip(o)
|
|
5650
|
+
);
|
|
5651
|
+
const skippedMarks = [];
|
|
5652
|
+
for (const clip of (from.overlays ?? []).filter(isStageClip)) {
|
|
5653
|
+
const mine = own.get(clip.id);
|
|
5654
|
+
const next = structuredClone(clip);
|
|
5655
|
+
next.start = 0;
|
|
5656
|
+
next.duration = Math.max(0.3, Math.round(outDur * 1e3) / 1e3);
|
|
5657
|
+
if (next.kind === "text") {
|
|
5658
|
+
if (mine?.kind === "text") next.text = mine.text;
|
|
5659
|
+
} else if (opts.keys?.[clip.id]) {
|
|
5660
|
+
next.key = opts.keys[clip.id];
|
|
5661
|
+
} else if (mine && mine.kind !== "text") {
|
|
5662
|
+
next.key = mine.key;
|
|
5663
|
+
} else {
|
|
5664
|
+
skippedMarks.push(clip.id);
|
|
5665
|
+
continue;
|
|
5666
|
+
}
|
|
5667
|
+
merged.push(next);
|
|
5668
|
+
}
|
|
5669
|
+
for (const o of doc.overlays ?? []) {
|
|
5670
|
+
if (isStageClip(o) && !merged.some((m) => m.id === o.id)) merged.push(o);
|
|
5671
|
+
}
|
|
5672
|
+
doc.overlays = merged.length ? merged : void 0;
|
|
5673
|
+
if (skippedMarks.length)
|
|
5674
|
+
notes.push(
|
|
5675
|
+
`${skippedMarks.join(", ")} left out: the layout's image is its own brand's; add yours`
|
|
5676
|
+
);
|
|
5677
|
+
const lean = restLeanOf(from);
|
|
5678
|
+
if (lean) {
|
|
5679
|
+
if (!doc.tilt?.length) {
|
|
5680
|
+
doc.tilt = [
|
|
5681
|
+
{
|
|
5682
|
+
id: REST_TILT_ID,
|
|
5683
|
+
in: 0,
|
|
5684
|
+
out: Math.round(anchorSourceDuration(doc) * 1e3) / 1e3,
|
|
5685
|
+
rx: lean.rx,
|
|
5686
|
+
ry: lean.ry,
|
|
5687
|
+
source: "manual"
|
|
5688
|
+
}
|
|
5689
|
+
];
|
|
5690
|
+
} else {
|
|
5691
|
+
notes.push("lean kept: this take has tilt spans of its own");
|
|
5692
|
+
}
|
|
5693
|
+
}
|
|
5694
|
+
const hold = from.segments.at(-1)?.hold;
|
|
5695
|
+
const last = doc.segments.at(-1);
|
|
5696
|
+
if (typeof hold === "number" && hold > 0 && last) last.hold = hold;
|
|
5697
|
+
return { doc, notes };
|
|
5698
|
+
}
|
|
5699
|
+
var shiftBy = (at, templateEnd, takeEnd) => at === "start" ? 0 : at === "end" ? takeEnd - templateEnd : at;
|
|
5700
|
+
function clipsFrom(doc, from) {
|
|
5701
|
+
return {
|
|
5702
|
+
overlays: (doc.overlays ?? []).filter((o) => o.from === from),
|
|
5703
|
+
objects: (doc.objects ?? []).filter((o) => o.from === from),
|
|
5704
|
+
audio: (doc.audio ?? []).filter((a) => a.from === from)
|
|
5705
|
+
};
|
|
5706
|
+
}
|
|
5707
|
+
function dropTemplate(doc, from) {
|
|
5708
|
+
const has = clipsFrom(doc, from);
|
|
5709
|
+
if (!has.overlays.length && !has.objects.length && !has.audio.length)
|
|
5710
|
+
return doc;
|
|
5711
|
+
const out = { ...doc };
|
|
5712
|
+
if (doc.overlays) out.overlays = doc.overlays.filter((o) => o.from !== from);
|
|
5713
|
+
if (doc.objects) out.objects = doc.objects.filter((o) => o.from !== from);
|
|
5714
|
+
out.audio = doc.audio.filter((a) => a.from !== from);
|
|
5715
|
+
return out;
|
|
5308
5716
|
}
|
|
5717
|
+
function applyTemplate(template, take, opts) {
|
|
5718
|
+
const from = opts.from ?? "template";
|
|
5719
|
+
const notes = [];
|
|
5720
|
+
const base = dropTemplate(take, from);
|
|
5721
|
+
const doc = structuredClone(base);
|
|
5722
|
+
const templateEnd = totalDuration4(ratedSegments(template));
|
|
5723
|
+
const takeEnd = totalDuration4(ratedSegments(take));
|
|
5724
|
+
const shift = shiftBy(opts.at, templateEnd, takeEnd);
|
|
5725
|
+
const own = new Map((take.overlays ?? []).map((o) => [o.id, o]));
|
|
5726
|
+
const overlays = (doc.overlays ?? []).filter(
|
|
5727
|
+
(o) => !(template.overlays ?? []).some((t) => t.id === o.id)
|
|
5728
|
+
);
|
|
5729
|
+
const skipped = [];
|
|
5730
|
+
for (const clip of template.overlays ?? []) {
|
|
5731
|
+
const next = structuredClone(clip);
|
|
5732
|
+
next.start = Math.max(0, round33(clip.start + shift));
|
|
5733
|
+
next.from = from;
|
|
5734
|
+
const mine = own.get(clip.id);
|
|
5735
|
+
if (next.kind === "text") {
|
|
5736
|
+
const word = opts.words?.[clip.id];
|
|
5737
|
+
if (word !== void 0) next.text = word;
|
|
5738
|
+
else if (mine?.kind === "text") next.text = mine.text;
|
|
5739
|
+
} else if (opts.keys?.[clip.id]) {
|
|
5740
|
+
next.key = opts.keys[clip.id];
|
|
5741
|
+
} else if (mine && mine.kind !== "text") {
|
|
5742
|
+
next.key = mine.key;
|
|
5743
|
+
} else if (!/^(https?:|\/\/)/.test(next.key)) {
|
|
5744
|
+
skipped.push(clip.id);
|
|
5745
|
+
continue;
|
|
5746
|
+
}
|
|
5747
|
+
overlays.push(next);
|
|
5748
|
+
}
|
|
5749
|
+
if (skipped.length)
|
|
5750
|
+
notes.push(
|
|
5751
|
+
`${skipped.join(", ")}: the template's media key is its own; pass keys[id] or the take's clip`
|
|
5752
|
+
);
|
|
5753
|
+
if (overlays.length || doc.overlays) doc.overlays = overlays;
|
|
5754
|
+
const objects = (doc.objects ?? []).filter(
|
|
5755
|
+
(o) => !(template.objects ?? []).some((t) => t.id === o.id)
|
|
5756
|
+
);
|
|
5757
|
+
for (const clip of template.objects ?? []) {
|
|
5758
|
+
const next = structuredClone(clip);
|
|
5759
|
+
if (next.span)
|
|
5760
|
+
next.span.start = Math.max(0, round33(next.span.start + shift));
|
|
5761
|
+
next.from = from;
|
|
5762
|
+
objects.push(next);
|
|
5763
|
+
}
|
|
5764
|
+
if (objects.length || doc.objects) doc.objects = objects;
|
|
5765
|
+
const audio = doc.audio.filter(
|
|
5766
|
+
(a) => !template.audio.some((t) => t.id === a.id)
|
|
5767
|
+
);
|
|
5768
|
+
for (const clip of template.audio) {
|
|
5769
|
+
const next = structuredClone(clip);
|
|
5770
|
+
next.start = Math.max(0, round33(clip.start + shift));
|
|
5771
|
+
next.from = from;
|
|
5772
|
+
audio.push(next);
|
|
5773
|
+
}
|
|
5774
|
+
doc.audio = audio;
|
|
5775
|
+
if (template.frame.anim) {
|
|
5776
|
+
doc.frame = {
|
|
5777
|
+
...doc.frame,
|
|
5778
|
+
anim: { ...doc.frame.anim ?? {}, ...template.frame.anim }
|
|
5779
|
+
};
|
|
5780
|
+
}
|
|
5781
|
+
if (opts.look) {
|
|
5782
|
+
const laid = copyLayout(template, doc, { keys: opts.keys });
|
|
5783
|
+
laid.doc.overlays = (laid.doc.overlays ?? []).map(
|
|
5784
|
+
(o) => isStageClip(o) ? { ...o, from } : o
|
|
5785
|
+
);
|
|
5786
|
+
notes.push(...laid.notes);
|
|
5787
|
+
return { doc: laid.doc, notes };
|
|
5788
|
+
}
|
|
5789
|
+
return { doc, notes };
|
|
5790
|
+
}
|
|
5791
|
+
var round33 = (v) => Math.round(v * 1e3) / 1e3;
|
|
5309
5792
|
|
|
5310
5793
|
// src/digest/geometry.ts
|
|
5311
5794
|
var CROP_MIN_FRAC = 0.25;
|
|
@@ -5382,7 +5865,6 @@ function cropBox(m, geo, meta) {
|
|
|
5382
5865
|
}
|
|
5383
5866
|
|
|
5384
5867
|
// src/digest/build.ts
|
|
5385
|
-
import { totalDuration as totalDuration2 } from "@vosjs/timeline";
|
|
5386
5868
|
var DIGEST_VERSION = 1;
|
|
5387
5869
|
function buildDigest(input) {
|
|
5388
5870
|
const { doc, meta } = { doc: input.doc, meta: input.doc.source.meta };
|
|
@@ -5450,7 +5932,7 @@ function buildDigest(input) {
|
|
|
5450
5932
|
};
|
|
5451
5933
|
}
|
|
5452
5934
|
function outputDurationOf(doc) {
|
|
5453
|
-
return
|
|
5935
|
+
return docOutputDuration(doc);
|
|
5454
5936
|
}
|
|
5455
5937
|
function round8(v) {
|
|
5456
5938
|
return Math.round(v * 1e3) / 1e3;
|
|
@@ -5548,7 +6030,7 @@ function round9(v) {
|
|
|
5548
6030
|
|
|
5549
6031
|
// src/lower/lowerStudioDoc.ts
|
|
5550
6032
|
import { applyTimelineEdits } from "@vosjs/shared/timelineEdits";
|
|
5551
|
-
import { totalDuration as
|
|
6033
|
+
import { totalDuration as totalDuration5 } from "@vosjs/timeline";
|
|
5552
6034
|
function lowerStudioDoc(doc, opts = {}) {
|
|
5553
6035
|
return isRecordingDoc(doc) ? lowerToComposition(doc) : lowerProgramDoc(doc, opts);
|
|
5554
6036
|
}
|
|
@@ -5579,7 +6061,7 @@ function lowerProgramDoc(doc, opts = {}) {
|
|
|
5579
6061
|
) : doc.program.config;
|
|
5580
6062
|
const own = programDuration(doc);
|
|
5581
6063
|
const rated = ratedSegments(doc);
|
|
5582
|
-
const duration = own > 0 ?
|
|
6064
|
+
const duration = own > 0 ? totalDuration5(rated) : 0;
|
|
5583
6065
|
const entryData = studioLayerData(doc, duration);
|
|
5584
6066
|
const baseData = anchor.data && typeof anchor.data === "object" ? anchor.data : {};
|
|
5585
6067
|
const retimed = !!doc.speed?.length && own > 0;
|
|
@@ -6177,99 +6659,15 @@ import {
|
|
|
6177
6659
|
removeSegment,
|
|
6178
6660
|
segmentRate as segmentRate3,
|
|
6179
6661
|
sourceToTimeline as sourceToTimeline3,
|
|
6180
|
-
splitBySpeed as
|
|
6181
|
-
totalDuration as
|
|
6662
|
+
splitBySpeed as splitBySpeed3,
|
|
6663
|
+
totalDuration as totalDuration6,
|
|
6182
6664
|
trimSegment
|
|
6183
6665
|
} from "@vosjs/timeline";
|
|
6184
|
-
|
|
6185
|
-
// src/audioBeds.ts
|
|
6186
|
-
import { totalDuration as totalDuration4 } from "@vosjs/timeline";
|
|
6187
|
-
var round32 = (v) => Math.round(v * 1e3) / 1e3;
|
|
6188
|
-
function docOutputDuration(doc) {
|
|
6189
|
-
return totalDuration4(ratedSegments(doc));
|
|
6190
|
-
}
|
|
6191
|
-
function musicBedClip(input) {
|
|
6192
|
-
const track = round32(input.trackDuration);
|
|
6193
|
-
const output = round32(input.outputDuration);
|
|
6194
|
-
const clip = {
|
|
6195
|
-
id: input.id,
|
|
6196
|
-
key: input.key,
|
|
6197
|
-
name: input.name,
|
|
6198
|
-
start: 0,
|
|
6199
|
-
in: 0,
|
|
6200
|
-
out: track,
|
|
6201
|
-
duration: track,
|
|
6202
|
-
// Under speech, not over it; catalog tracks are loudness-normalized so
|
|
6203
|
-
// one default means the same thing across the library.
|
|
6204
|
-
gain: 0.5,
|
|
6205
|
-
fadeIn: 0,
|
|
6206
|
-
// A bed that just stops reads as a glitch; clamp so a very short cut
|
|
6207
|
-
// still spends most of its time at full level.
|
|
6208
|
-
fadeOut: output > 0 ? Math.min(1.5, round32(output / 4)) : 1.5,
|
|
6209
|
-
duck: input.hasMic || void 0
|
|
6210
|
-
};
|
|
6211
|
-
if (output <= 0) return clip;
|
|
6212
|
-
if (track >= output) {
|
|
6213
|
-
clip.out = output;
|
|
6214
|
-
} else {
|
|
6215
|
-
clip.loop = true;
|
|
6216
|
-
clip.loopLen = output;
|
|
6217
|
-
}
|
|
6218
|
-
return clip;
|
|
6219
|
-
}
|
|
6220
|
-
function isMusicBed(clip, outputDuration) {
|
|
6221
|
-
if (clip.start > 0.05) return false;
|
|
6222
|
-
if (clip.loop) return true;
|
|
6223
|
-
const placed = clip.out - clip.in;
|
|
6224
|
-
return Math.abs(placed - outputDuration) <= 1;
|
|
6225
|
-
}
|
|
6226
|
-
function refillAudioBeds(doc, prevDuration, nextDuration) {
|
|
6227
|
-
const EPS2 = 0.05;
|
|
6228
|
-
if (Math.abs(nextDuration - prevDuration) <= EPS2 || nextDuration <= 0) {
|
|
6229
|
-
return false;
|
|
6230
|
-
}
|
|
6231
|
-
let changed = false;
|
|
6232
|
-
for (const clip of doc.audio) {
|
|
6233
|
-
if (clip.start >= nextDuration) continue;
|
|
6234
|
-
const placed = clip.loop ? Math.max(clip.out - clip.in, clip.loopLen ?? clip.out - clip.in) : clip.out - clip.in;
|
|
6235
|
-
if (Math.abs(clip.start + placed - prevDuration) > EPS2) continue;
|
|
6236
|
-
const span = clip.out - clip.in;
|
|
6237
|
-
const nextLen = round32(nextDuration - clip.start);
|
|
6238
|
-
if (clip.loop) {
|
|
6239
|
-
if (nextLen >= span) {
|
|
6240
|
-
clip.loopLen = nextLen;
|
|
6241
|
-
} else {
|
|
6242
|
-
clip.loop = void 0;
|
|
6243
|
-
clip.loopLen = void 0;
|
|
6244
|
-
clip.out = round32(clip.in + nextLen);
|
|
6245
|
-
}
|
|
6246
|
-
} else {
|
|
6247
|
-
if (clip.in + nextLen <= clip.duration) {
|
|
6248
|
-
clip.out = round32(clip.in + nextLen);
|
|
6249
|
-
} else {
|
|
6250
|
-
clip.out = clip.duration;
|
|
6251
|
-
clip.loop = true;
|
|
6252
|
-
clip.loopLen = nextLen;
|
|
6253
|
-
}
|
|
6254
|
-
}
|
|
6255
|
-
changed = true;
|
|
6256
|
-
}
|
|
6257
|
-
return changed;
|
|
6258
|
-
}
|
|
6259
|
-
function voiceKey(doc) {
|
|
6260
|
-
if (!("source" in doc)) return null;
|
|
6261
|
-
const src = doc.source;
|
|
6262
|
-
if (src.micKey) return src.micKey;
|
|
6263
|
-
if (src.meta.hasAudio && !src.meta.hasMic) return src.videoKey;
|
|
6264
|
-
return null;
|
|
6265
|
-
}
|
|
6266
|
-
|
|
6267
|
-
// src/timeline/lanes.ts
|
|
6268
6666
|
function effectiveSegments(doc) {
|
|
6269
6667
|
if (isRecordingDoc(doc) && doc.segments.length) return doc.segments;
|
|
6270
6668
|
return [{ in: 0, out: anchorSourceDuration(doc) }];
|
|
6271
6669
|
}
|
|
6272
|
-
var outputLen = (seg, speeds) =>
|
|
6670
|
+
var outputLen = (seg, speeds) => totalDuration6(splitBySpeed3([seg], speeds));
|
|
6273
6671
|
var segmentStarts = (segments, speeds) => {
|
|
6274
6672
|
const starts = [];
|
|
6275
6673
|
let acc = 0;
|
|
@@ -6326,7 +6724,7 @@ var videoLane = {
|
|
|
6326
6724
|
if (index < 0 || index >= segments.length) return null;
|
|
6327
6725
|
const seg = segments[index];
|
|
6328
6726
|
const starts = segmentStarts(segments, speeds);
|
|
6329
|
-
const fullMap =
|
|
6727
|
+
const fullMap = splitBySpeed3([{ in: 0, out: sourceDuration }], speeds);
|
|
6330
6728
|
const edgeSrc = g.edge === "start" ? seg.in : seg.out;
|
|
6331
6729
|
const edgeOutNow = g.edge === "start" ? starts[index] : starts[index] + outputLen(seg, speeds);
|
|
6332
6730
|
const anchorOut = sourceToTimeline3(fullMap, Math.min(edgeSrc, sourceDuration)) ?? edgeSrc;
|
|
@@ -6349,7 +6747,7 @@ var videoLane = {
|
|
|
6349
6747
|
);
|
|
6350
6748
|
if (index < 0) return null;
|
|
6351
6749
|
const s = segments[index];
|
|
6352
|
-
const sourceT = mapTime2(
|
|
6750
|
+
const sourceT = mapTime2(splitBySpeed3([s], speeds), g.t - starts[index]);
|
|
6353
6751
|
if (sourceT - s.in < 0.05 || s.out - sourceT < 0.05) return null;
|
|
6354
6752
|
const next = [
|
|
6355
6753
|
...segments.slice(0, index),
|
|
@@ -6901,7 +7299,7 @@ var speedLane = {
|
|
|
6901
7299
|
const sp = spans.find((s) => s.id === g.id);
|
|
6902
7300
|
if (!sp) return null;
|
|
6903
7301
|
const others = spans.filter((o) => o.id !== g.id);
|
|
6904
|
-
const base =
|
|
7302
|
+
const base = splitBySpeed3(effectiveSegments(doc), others);
|
|
6905
7303
|
if (g.type === "move") {
|
|
6906
7304
|
const len = sp.out - sp.in;
|
|
6907
7305
|
let newIn = clampToKept(
|
|
@@ -7427,6 +7825,9 @@ export {
|
|
|
7427
7825
|
CAM_SPAN_MIN,
|
|
7428
7826
|
CAPTURE_COVERAGE_MIN,
|
|
7429
7827
|
CARD_EDGE_OVERDRAW,
|
|
7828
|
+
CARD_ENTER_KINDS,
|
|
7829
|
+
CARD_EXIT_KINDS,
|
|
7830
|
+
CARD_FADE_SECONDS,
|
|
7430
7831
|
CARD_FOV,
|
|
7431
7832
|
CARD_Z,
|
|
7432
7833
|
CHANNEL_SPECS_HASH,
|
|
@@ -7465,6 +7866,8 @@ export {
|
|
|
7465
7866
|
DIGEST_VERSION,
|
|
7466
7867
|
DOC_SCHEMA_VERSION,
|
|
7467
7868
|
DRAG_FIT_LEVEL,
|
|
7869
|
+
END_CARD_FROM,
|
|
7870
|
+
END_CARD_RECEDE,
|
|
7468
7871
|
END_CARD_SECONDS,
|
|
7469
7872
|
ENTRANCE_SECONDS,
|
|
7470
7873
|
EXPORT_RESOLUTION_OPTIONS,
|
|
@@ -7475,7 +7878,11 @@ export {
|
|
|
7475
7878
|
FRAME_BORDER_DEFAULT,
|
|
7476
7879
|
FRAME_BORDER_WIDTH_DEFAULT,
|
|
7477
7880
|
HOUSE_GRADIENT,
|
|
7881
|
+
IDLE_KINDS,
|
|
7882
|
+
LAYOUT_FRAME_FIELDS,
|
|
7478
7883
|
LOOK_KINDS,
|
|
7884
|
+
MEDIA_ENTER_KINDS,
|
|
7885
|
+
MEDIA_EXIT_KINDS,
|
|
7479
7886
|
MINIMAL_BAR_THEMES,
|
|
7480
7887
|
MOTION_DELTA,
|
|
7481
7888
|
MOTION_EASE,
|
|
@@ -7494,16 +7901,20 @@ export {
|
|
|
7494
7901
|
PLAYBACK_ACTIVITY,
|
|
7495
7902
|
PROGRAM_RETIME,
|
|
7496
7903
|
REJECT_OVERLAP,
|
|
7904
|
+
REST_TILT_ID,
|
|
7497
7905
|
SCENE_MOTION,
|
|
7498
7906
|
SCENE_QUIET,
|
|
7499
7907
|
SPEED_RATE_MAX,
|
|
7500
7908
|
SPEED_RATE_MIN,
|
|
7501
7909
|
SPEED_SPAN_MIN,
|
|
7910
|
+
STAGE_CLIP_PREFIX,
|
|
7502
7911
|
STUDIO_ENTRY_ID,
|
|
7503
7912
|
STYLE_FIELDS,
|
|
7504
7913
|
TEXT3D_DEPTH_DEFAULT,
|
|
7505
7914
|
TEXT3D_DEPTH_MAX,
|
|
7506
7915
|
TEXT3D_DEPTH_MIN,
|
|
7916
|
+
TEXT_ENTER_KINDS,
|
|
7917
|
+
TEXT_EXIT_KINDS,
|
|
7507
7918
|
TEXT_PRESETS,
|
|
7508
7919
|
TILT_AUTO_DEAD_ZONE,
|
|
7509
7920
|
TILT_AUTO_MIN,
|
|
@@ -7534,7 +7945,9 @@ export {
|
|
|
7534
7945
|
ZOOM_STYLE_OPTIONS,
|
|
7535
7946
|
anchorKindOf,
|
|
7536
7947
|
anchorSourceDuration,
|
|
7948
|
+
animStep,
|
|
7537
7949
|
applyLook,
|
|
7950
|
+
applyTemplate,
|
|
7538
7951
|
aspectRatioValue,
|
|
7539
7952
|
audioLane,
|
|
7540
7953
|
backdropMedia,
|
|
@@ -7546,6 +7959,8 @@ export {
|
|
|
7546
7959
|
camRectFromPose,
|
|
7547
7960
|
camRestPose,
|
|
7548
7961
|
camTrackFromDoc,
|
|
7962
|
+
cardEnter,
|
|
7963
|
+
cardExit,
|
|
7549
7964
|
cardInset,
|
|
7550
7965
|
cardPointToScreen,
|
|
7551
7966
|
cardPoseTrack,
|
|
@@ -7557,9 +7972,11 @@ export {
|
|
|
7557
7972
|
clampZoomLevel,
|
|
7558
7973
|
clipEnvelope,
|
|
7559
7974
|
clipLength,
|
|
7975
|
+
clipsFrom,
|
|
7560
7976
|
computeCardLayout,
|
|
7561
7977
|
computeMicRms,
|
|
7562
7978
|
computePeaks,
|
|
7979
|
+
copyLayout,
|
|
7563
7980
|
copyStyle,
|
|
7564
7981
|
cropBox,
|
|
7565
7982
|
cursorIdleFade,
|
|
@@ -7568,13 +7985,21 @@ export {
|
|
|
7568
7985
|
destinationsForChannel,
|
|
7569
7986
|
docCardLayout,
|
|
7570
7987
|
docOutputDuration,
|
|
7988
|
+
docRestTime,
|
|
7571
7989
|
docToCropSpace,
|
|
7572
7990
|
docToFullSpace,
|
|
7991
|
+
dropTemplate,
|
|
7573
7992
|
duckCurve,
|
|
7574
7993
|
effectiveSegments,
|
|
7994
|
+
endCardClips,
|
|
7995
|
+
enterKey,
|
|
7996
|
+
enterOf,
|
|
7575
7997
|
entranceSeconds,
|
|
7576
7998
|
envelopeAt,
|
|
7577
7999
|
envelopeValueAt,
|
|
8000
|
+
exitKey,
|
|
8001
|
+
exitOf,
|
|
8002
|
+
exitSeconds,
|
|
7578
8003
|
expandEndCard,
|
|
7579
8004
|
expectedFrameSize,
|
|
7580
8005
|
exportSizeFor,
|
|
@@ -7585,12 +8010,17 @@ export {
|
|
|
7585
8010
|
hexToRgbTriplet,
|
|
7586
8011
|
houseLook,
|
|
7587
8012
|
idleGaps,
|
|
8013
|
+
idleKey,
|
|
7588
8014
|
isLookKind,
|
|
7589
8015
|
isMusicBed,
|
|
7590
8016
|
isPlayback,
|
|
7591
8017
|
isProgramDoc,
|
|
7592
8018
|
isRecordingDoc,
|
|
7593
8019
|
isRejected,
|
|
8020
|
+
isStageClip,
|
|
8021
|
+
isUnitStep,
|
|
8022
|
+
lastLayerEnd,
|
|
8023
|
+
layoutOf,
|
|
7594
8024
|
levelForFocusFraction,
|
|
7595
8025
|
lookFromBrand,
|
|
7596
8026
|
lookKindForGround,
|
|
@@ -7599,6 +8029,7 @@ export {
|
|
|
7599
8029
|
lowerToComposition,
|
|
7600
8030
|
micLane,
|
|
7601
8031
|
migrateHostedDoc,
|
|
8032
|
+
migrateMotion,
|
|
7602
8033
|
momentsFromDoc,
|
|
7603
8034
|
motionTrack,
|
|
7604
8035
|
musicBedClip,
|
|
@@ -7607,11 +8038,13 @@ export {
|
|
|
7607
8038
|
objectMotionPoseAt,
|
|
7608
8039
|
objectsLane,
|
|
7609
8040
|
outputDurationOf,
|
|
8041
|
+
outputEnd,
|
|
7610
8042
|
outputRangeToSource,
|
|
7611
8043
|
overlapFraction,
|
|
7612
8044
|
overlayFaceFor,
|
|
7613
8045
|
overlayFontFaces,
|
|
7614
8046
|
overlayFontString,
|
|
8047
|
+
overlayFxSpec,
|
|
7615
8048
|
overlayHit,
|
|
7616
8049
|
overlayLines,
|
|
7617
8050
|
overlayMotionBase,
|
|
@@ -7640,6 +8073,7 @@ export {
|
|
|
7640
8073
|
resolveOverlayStyle,
|
|
7641
8074
|
resolveText3dAsset,
|
|
7642
8075
|
resolveZoomStyle,
|
|
8076
|
+
restLeanOf,
|
|
7643
8077
|
sceneChanges,
|
|
7644
8078
|
scrollRuns,
|
|
7645
8079
|
setSpeedInRange,
|