@vosjs/studio-core 0.42.3 → 0.42.5
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 +10 -0
- package/dist/index.js +43 -23
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -3801,6 +3801,16 @@ interface TrackOptions {
|
|
|
3801
3801
|
* entrance's last pose to the span's end in one straight line.
|
|
3802
3802
|
*/
|
|
3803
3803
|
notBefore?: number;
|
|
3804
|
+
/**
|
|
3805
|
+
* The transition windows, in output seconds: the camera rests through
|
|
3806
|
+
* one (`restSpansThroughTransitions`), so no connected pan runs across
|
|
3807
|
+
* it. A span that ends at a boundary ramps out on its own and the span
|
|
3808
|
+
* after the window ramps in on its own, as two spans a wide gap apart.
|
|
3809
|
+
*/
|
|
3810
|
+
rests?: readonly {
|
|
3811
|
+
t: number;
|
|
3812
|
+
d: number;
|
|
3813
|
+
}[];
|
|
3804
3814
|
}
|
|
3805
3815
|
/**
|
|
3806
3816
|
* Expand the doc's source-anchored zoom spans into a standard @vosjs/timeline
|
package/dist/index.js
CHANGED
|
@@ -6449,17 +6449,25 @@ function connectedWindow(o) {
|
|
|
6449
6449
|
);
|
|
6450
6450
|
return { start, land };
|
|
6451
6451
|
}
|
|
6452
|
-
function withEntrance(head, build) {
|
|
6453
|
-
return prependEntrance(build({ notBefore: head.at(-1)?.t }), head);
|
|
6452
|
+
function withEntrance(head, build, rests) {
|
|
6453
|
+
return prependEntrance(build({ notBefore: head.at(-1)?.t, rests }), head);
|
|
6454
|
+
}
|
|
6455
|
+
function restsBetween(rests, tOut, nextIn) {
|
|
6456
|
+
return (rests ?? []).some(
|
|
6457
|
+
(w) => w.t > 0 && w.d > 0 && w.t < nextIn && w.t + w.d > tOut
|
|
6458
|
+
);
|
|
6454
6459
|
}
|
|
6455
6460
|
var spillLimit = (tIn, tOut) => tIn + (tOut - tIn) / 2;
|
|
6461
|
+
function spansInOutputOrder(spans, segments) {
|
|
6462
|
+
return spans.flatMap((z) => {
|
|
6463
|
+
const ext = spanOutputExtent(segments, z.in, z.out, z.media);
|
|
6464
|
+
return ext ? [{ z, tIn: ext.start, tOut: ext.end }] : [];
|
|
6465
|
+
}).sort((a, b) => a.tIn - b.tIn || a.tOut - b.tOut);
|
|
6466
|
+
}
|
|
6456
6467
|
function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE], opts = {}) {
|
|
6457
6468
|
const notBefore = opts.notBefore ?? -Infinity;
|
|
6458
6469
|
const panEase = style.panEase;
|
|
6459
|
-
const mapped =
|
|
6460
|
-
const ext = spanOutputExtent(segments, z.in, z.out, z.media);
|
|
6461
|
-
return ext ? [{ z, tIn: ext.start, tOut: ext.end }] : [];
|
|
6462
|
-
});
|
|
6470
|
+
const mapped = spansInOutputOrder(zoom, segments);
|
|
6463
6471
|
const { keyframes, push: push2 } = trackEmitter();
|
|
6464
6472
|
const placedAt = (z) => z.screen && z.focusMode !== "auto" ? z.screen : null;
|
|
6465
6473
|
const placed = mapped.some(({ z }) => placedAt(z) !== null);
|
|
@@ -6490,7 +6498,7 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
|
|
|
6490
6498
|
}
|
|
6491
6499
|
const arrived = keyframes.at(-1)?.t ?? tIn;
|
|
6492
6500
|
const next = mapped.at(i + 1);
|
|
6493
|
-
const pan = next && next.tIn - tOut <= style.chainGap ? connectedWindow({
|
|
6501
|
+
const pan = next && next.tIn - tOut <= style.chainGap && !restsBetween(opts.rests, tOut, next.tIn) ? connectedWindow({
|
|
6494
6502
|
arrived,
|
|
6495
6503
|
tOut,
|
|
6496
6504
|
landBy: next.tIn + style.rampInOverlap * transitionMult(next.z.transition),
|
|
@@ -6567,10 +6575,7 @@ function tiltTrackFromDoc(tilt, segments, motion = {}, opts = {}) {
|
|
|
6567
6575
|
const panDur = motion.pan ?? TILT_PAN;
|
|
6568
6576
|
const panEase = TILT_PAN_EASE;
|
|
6569
6577
|
const rest = [0, 0];
|
|
6570
|
-
const mapped =
|
|
6571
|
-
const ext = spanOutputExtent(segments, z.in, z.out, z.media);
|
|
6572
|
-
return ext ? [{ z, tIn: ext.start, tOut: ext.end }] : [];
|
|
6573
|
-
});
|
|
6578
|
+
const mapped = spansInOutputOrder(tilt, segments);
|
|
6574
6579
|
const { keyframes, push: push2 } = trackEmitter();
|
|
6575
6580
|
let chained = false;
|
|
6576
6581
|
for (let i = 0; i < mapped.length; i++) {
|
|
@@ -6589,7 +6594,7 @@ function tiltTrackFromDoc(tilt, segments, motion = {}, opts = {}) {
|
|
|
6589
6594
|
}
|
|
6590
6595
|
const arrived = keyframes.at(-1)?.t ?? tIn;
|
|
6591
6596
|
const next = mapped.at(i + 1);
|
|
6592
|
-
const swing = next && next.tIn - tOut <= chainGap ? connectedWindow({
|
|
6597
|
+
const swing = next && next.tIn - tOut <= chainGap && !restsBetween(opts.rests, tOut, next.tIn) ? connectedWindow({
|
|
6593
6598
|
arrived,
|
|
6594
6599
|
tOut,
|
|
6595
6600
|
landBy: next.tIn,
|
|
@@ -6624,10 +6629,7 @@ function camTrackFromDoc(cam, spans, segments, W, H = 1080) {
|
|
|
6624
6629
|
z.size != null ? clampCamSize(z.size) : rest[2]
|
|
6625
6630
|
];
|
|
6626
6631
|
const panEase = CAM_PAN_EASE;
|
|
6627
|
-
const mapped =
|
|
6628
|
-
const ext = spanOutputExtent(segments, z.in, z.out, z.media);
|
|
6629
|
-
return ext ? [{ z, tIn: ext.start, tOut: ext.end }] : [];
|
|
6630
|
-
});
|
|
6632
|
+
const mapped = spansInOutputOrder(spans, segments);
|
|
6631
6633
|
const { keyframes, push: push2 } = trackEmitter();
|
|
6632
6634
|
let chained = false;
|
|
6633
6635
|
for (let i = 0; i < mapped.length; i++) {
|
|
@@ -6909,9 +6911,24 @@ var SETUP = `async (ctx) => {
|
|
|
6909
6911
|
;(ns.videoBlobs || (ns.videoBlobs = new Map())).set(src, fetched)
|
|
6910
6912
|
return URL.createObjectURL(fetched)
|
|
6911
6913
|
}
|
|
6914
|
+
// Every element handed out by this SETUP, so two players never share one.
|
|
6915
|
+
// A take may name one file as two media (the same shot as a teaser and in
|
|
6916
|
+
// full), or as a media and the footage; the by-src cache would hand both
|
|
6917
|
+
// ONE element, and ON_FRAME's concat rule, which pauses every media that
|
|
6918
|
+
// is not under the playhead, then paused the playing clip every frame under
|
|
6919
|
+
// the other name: play/pause churn, the element falling behind the clock,
|
|
6920
|
+
// and a drift-guard seek every ~0.3 s that read as a stuck picture jumping
|
|
6921
|
+
// forward. A second claim on the same bytes gets its OWN element, kept in
|
|
6922
|
+
// the cache under a slot of its own so a warm LOAD reuses it like the first.
|
|
6923
|
+
const claimed = new Set()
|
|
6912
6924
|
const load = async (src, muted) => {
|
|
6913
|
-
let
|
|
6914
|
-
|
|
6925
|
+
let key = src
|
|
6926
|
+
let v = cache.get(key)
|
|
6927
|
+
for (let n = 2; v && claimed.has(v); n++) {
|
|
6928
|
+
key = src + '#' + n
|
|
6929
|
+
v = cache.get(key)
|
|
6930
|
+
}
|
|
6931
|
+
if (v) { claimed.add(v); return v }
|
|
6915
6932
|
let url = src
|
|
6916
6933
|
if (ctx.data.videoFetchMode === 'blob') {
|
|
6917
6934
|
try { url = await toBlobUrl(src) }
|
|
@@ -6931,7 +6948,8 @@ var SETUP = `async (ctx) => {
|
|
|
6931
6948
|
v.onerror = () => rej(new Error('[studio] video failed to load' + (v.error ? ' (' + v.error.code + (v.error.message ? ': ' + v.error.message : '') + ')' : '')))
|
|
6932
6949
|
v.load()
|
|
6933
6950
|
})
|
|
6934
|
-
cache.set(
|
|
6951
|
+
cache.set(key, v)
|
|
6952
|
+
claimed.add(v)
|
|
6935
6953
|
return v
|
|
6936
6954
|
}
|
|
6937
6955
|
// Shots: the "video" is a still image \u2014 drawImage accepts it directly and the
|
|
@@ -7375,7 +7393,7 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
7375
7393
|
// The card under the playhead: another media's own card fields over the
|
|
7376
7394
|
// take's frame (resolved at lowering), the take's frame for the primary.
|
|
7377
7395
|
var cfr = amId && actM && actM.frame ? actM.frame : frame
|
|
7378
|
-
if (r.media) for (var amK in r.media) { var amE = r.media[amK]; if (amK !== amId && amE && amE.pause && amE.paused === false) amE.pause() }
|
|
7396
|
+
if (r.media) for (var amK in r.media) { var amE = r.media[amK]; if (amK !== amId && amE && amE !== video && amE.pause && amE.paused === false) amE.pause() }
|
|
7379
7397
|
if (amId) {
|
|
7380
7398
|
if (r.video && r.video.pause && r.video.paused === false) r.video.pause()
|
|
7381
7399
|
if (r.cam && r.cam.pause && r.cam.paused === false) r.cam.pause()
|
|
@@ -8860,7 +8878,8 @@ function lowerToComposition(input) {
|
|
|
8860
8878
|
);
|
|
8861
8879
|
const zoomTrack = withEntrance(
|
|
8862
8880
|
entranceZoomKeyframes(cardEnter(doc.frame)),
|
|
8863
|
-
(opts) => zoomTrackFromDoc(zoomSpans, rated, zoomStyle, opts)
|
|
8881
|
+
(opts) => zoomTrackFromDoc(zoomSpans, rated, zoomStyle, opts),
|
|
8882
|
+
transitions
|
|
8864
8883
|
);
|
|
8865
8884
|
const pins = resolvePins(doc, layout, camera, zoomTrack);
|
|
8866
8885
|
const pinsData = pinsDataOf(doc, pins);
|
|
@@ -8960,7 +8979,7 @@ function lowerToComposition(input) {
|
|
|
8960
8979
|
TILT_SPAN_MIN
|
|
8961
8980
|
) : [];
|
|
8962
8981
|
const spans = tilts.length ? (opts) => tiltTrackFromDoc(tilts, rated, zoomStyle.tilt, opts) : () => void 0;
|
|
8963
|
-
const track = withEntrance(head, spans);
|
|
8982
|
+
const track = withEntrance(head, spans, transitions);
|
|
8964
8983
|
return track ? { tiltTrack: track } : {};
|
|
8965
8984
|
})(),
|
|
8966
8985
|
// The card's pose through its enter and its exit: [scale, dy, opacity]
|
|
@@ -9063,7 +9082,8 @@ function docZoomTrack(input) {
|
|
|
9063
9082
|
);
|
|
9064
9083
|
return withEntrance(
|
|
9065
9084
|
entranceZoomKeyframes(cardEnter(doc.frame)),
|
|
9066
|
-
(opts) => zoomTrackFromDoc(spans, rated, zoomStyle, opts)
|
|
9085
|
+
(opts) => zoomTrackFromDoc(spans, rated, zoomStyle, opts),
|
|
9086
|
+
transitions
|
|
9067
9087
|
);
|
|
9068
9088
|
}
|
|
9069
9089
|
function resolvePins(doc, layout, camera, zoomTrack) {
|