@vosjs/studio-core 0.35.3 → 0.36.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 +13 -2
- package/dist/index.js +141 -50
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -3630,6 +3630,17 @@ declare function spanOutputExtent(segments: readonly (Segment & {
|
|
|
3630
3630
|
start: number;
|
|
3631
3631
|
end: number;
|
|
3632
3632
|
} | null;
|
|
3633
|
+
/** What a span→track expansion is told about the time around it. */
|
|
3634
|
+
interface TrackOptions {
|
|
3635
|
+
/**
|
|
3636
|
+
* No span motion before this output time: the card's entrance owns it
|
|
3637
|
+
* (`prependEntrance` drops what the track put there). A span already
|
|
3638
|
+
* under way at it ramps in FROM it, at its full duration where the span
|
|
3639
|
+
* has the room, instead of losing its ramp and creeping from the
|
|
3640
|
+
* entrance's last pose to the span's end in one straight line.
|
|
3641
|
+
*/
|
|
3642
|
+
notBefore?: number;
|
|
3643
|
+
}
|
|
3633
3644
|
/**
|
|
3634
3645
|
* Expand the doc's source-anchored zoom spans into a standard @vosjs/timeline
|
|
3635
3646
|
* keyframe track in OUTPUT time (values are [level, cx, cy] vectors):
|
|
@@ -3647,7 +3658,7 @@ declare function spanOutputExtent(segments: readonly (Segment & {
|
|
|
3647
3658
|
interface LoweredZoomSpan extends ZoomSpan {
|
|
3648
3659
|
followEvents?: FollowEvent[];
|
|
3649
3660
|
}
|
|
3650
|
-
declare function zoomTrackFromDoc(zoom: LoweredZoomSpan[], segments: Segment[], style?: ZoomStyleParams): KeyframeTrack<number[]>;
|
|
3661
|
+
declare function zoomTrackFromDoc(zoom: LoweredZoomSpan[], segments: Segment[], style?: ZoomStyleParams, opts?: TrackOptions): KeyframeTrack<number[]>;
|
|
3651
3662
|
/**
|
|
3652
3663
|
* Expand the doc's source-anchored tilt spans into an OUTPUT-time keyframe
|
|
3653
3664
|
* track of [rx, ry] DEGREES (ON_FRAME converts to radians at the mesh):
|
|
@@ -3670,7 +3681,7 @@ declare function tiltTrackFromDoc(tilt: TiltSpan[], segments: Segment[], motion?
|
|
|
3670
3681
|
rampOut?: number;
|
|
3671
3682
|
chainGap?: number;
|
|
3672
3683
|
pan?: number;
|
|
3673
|
-
}): KeyframeTrack<number[]>;
|
|
3684
|
+
}, opts?: TrackOptions): KeyframeTrack<number[]>;
|
|
3674
3685
|
/**
|
|
3675
3686
|
* The bubble's rest pose as [x, y, size] frame fractions, resolved through the
|
|
3676
3687
|
* SAME oracle the picking layer uses (camBubbleRect) so the corner math can
|
package/dist/index.js
CHANGED
|
@@ -6041,7 +6041,20 @@ function trackEmitter() {
|
|
|
6041
6041
|
};
|
|
6042
6042
|
return { keyframes, push: push2 };
|
|
6043
6043
|
}
|
|
6044
|
-
function
|
|
6044
|
+
function connectedWindow(o) {
|
|
6045
|
+
const start = Math.max(o.arrived, Math.min(o.tOut, o.landBy - o.dur));
|
|
6046
|
+
const land = Math.max(
|
|
6047
|
+
start + o.floor,
|
|
6048
|
+
Math.min(start + o.dur, Math.max(o.latest, o.landBy))
|
|
6049
|
+
);
|
|
6050
|
+
return { start, land };
|
|
6051
|
+
}
|
|
6052
|
+
function withEntrance(head, build) {
|
|
6053
|
+
return prependEntrance(build({ notBefore: head.at(-1)?.t }), head);
|
|
6054
|
+
}
|
|
6055
|
+
var spillLimit = (tIn, tOut) => tIn + (tOut - tIn) / 2;
|
|
6056
|
+
function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE], opts = {}) {
|
|
6057
|
+
const notBefore = opts.notBefore ?? -Infinity;
|
|
6045
6058
|
const panEase = style.panEase;
|
|
6046
6059
|
const mapped = [...zoom].sort((a, b) => a.in - b.in).flatMap((z) => {
|
|
6047
6060
|
const ext = spanOutputExtent(segments, z.in, z.out, z.media);
|
|
@@ -6062,19 +6075,35 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
|
|
|
6062
6075
|
let cur = entry;
|
|
6063
6076
|
const m = transitionMult(z.transition);
|
|
6064
6077
|
if (!chained) {
|
|
6078
|
+
if (tOut <= notBefore + RAMP_FLOOR) continue;
|
|
6065
6079
|
const startWanted = tIn - (style.rampIn - style.rampInOverlap) * m;
|
|
6066
|
-
const start = push2(
|
|
6080
|
+
const start = push2(
|
|
6081
|
+
Math.max(startWanted, notBefore),
|
|
6082
|
+
[1, z.cx, z.cy, 0, ...sc(z)],
|
|
6083
|
+
"none"
|
|
6084
|
+
);
|
|
6067
6085
|
push2(
|
|
6068
6086
|
rampLanding(start, startWanted, style.rampIn * m, tOut),
|
|
6069
6087
|
entry,
|
|
6070
6088
|
spanEase(z.ease, style.ease)
|
|
6071
6089
|
);
|
|
6072
6090
|
}
|
|
6091
|
+
const arrived = keyframes.at(-1)?.t ?? tIn;
|
|
6092
|
+
const next = mapped.at(i + 1);
|
|
6093
|
+
const pan = next && next.tIn - tOut <= style.chainGap ? connectedWindow({
|
|
6094
|
+
arrived,
|
|
6095
|
+
tOut,
|
|
6096
|
+
landBy: next.tIn + style.rampInOverlap * transitionMult(next.z.transition),
|
|
6097
|
+
latest: spillLimit(next.tIn, next.tOut),
|
|
6098
|
+
dur: style.pan * transitionMult(next.z.transition),
|
|
6099
|
+
floor: RAMP_FLOOR
|
|
6100
|
+
}) : null;
|
|
6101
|
+
const holdEnd = pan ? pan.start : tOut;
|
|
6073
6102
|
let inPath = false;
|
|
6074
6103
|
for (const e of z.followEvents ?? []) {
|
|
6075
6104
|
const eOut = sourceToTimeline(segments, e.t);
|
|
6076
|
-
if (eOut === null || eOut <= tIn || eOut >=
|
|
6077
|
-
if (eOut - tIn < RAMP_FLOOR ||
|
|
6105
|
+
if (eOut === null || eOut <= tIn || eOut >= holdEnd) continue;
|
|
6106
|
+
if (eOut - tIn < RAMP_FLOOR || holdEnd - eOut < RAMP_FLOOR) continue;
|
|
6078
6107
|
const next2 = [cur[0], e.cx, e.cy, 1, ...cur.slice(4)];
|
|
6079
6108
|
if (e.path) {
|
|
6080
6109
|
if (!inPath) {
|
|
@@ -6087,14 +6116,14 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
|
|
|
6087
6116
|
} else {
|
|
6088
6117
|
inPath = false;
|
|
6089
6118
|
push2(eOut, cur, "none");
|
|
6090
|
-
push2(Math.min(eOut + style.followRecenter,
|
|
6119
|
+
push2(Math.min(eOut + style.followRecenter, holdEnd), next2, panEase);
|
|
6091
6120
|
}
|
|
6092
6121
|
cur = next2;
|
|
6093
6122
|
}
|
|
6094
6123
|
const drift = Math.max(0, style.holdDrift ?? 0);
|
|
6095
6124
|
const landed = keyframes.at(-1)?.t;
|
|
6096
|
-
if (drift > 0 && z.focusMode !== "auto" && !(z.followEvents ?? []).length && landed !== void 0 &&
|
|
6097
|
-
const grow = Math.min(HOLD_DRIFT_MAX, drift * (
|
|
6125
|
+
if (drift > 0 && z.focusMode !== "auto" && !(z.followEvents ?? []).length && landed !== void 0 && holdEnd > landed) {
|
|
6126
|
+
const grow = Math.min(HOLD_DRIFT_MAX, drift * (holdEnd - landed));
|
|
6098
6127
|
cur = [
|
|
6099
6128
|
clampZoomLevel(cur[0] * (1 + grow)),
|
|
6100
6129
|
cur[1],
|
|
@@ -6102,13 +6131,11 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
|
|
|
6102
6131
|
cur[3],
|
|
6103
6132
|
...cur.slice(4)
|
|
6104
6133
|
];
|
|
6105
|
-
push2(
|
|
6134
|
+
push2(holdEnd, cur, "sine.inOut");
|
|
6106
6135
|
} else {
|
|
6107
|
-
push2(
|
|
6136
|
+
push2(holdEnd, cur, "none");
|
|
6108
6137
|
}
|
|
6109
|
-
|
|
6110
|
-
if (next && next.tIn - tOut <= style.chainGap) {
|
|
6111
|
-
const mNext = transitionMult(next.z.transition);
|
|
6138
|
+
if (next && pan) {
|
|
6112
6139
|
const nextValue = [
|
|
6113
6140
|
clampZoomLevel(next.z.level),
|
|
6114
6141
|
next.z.cx,
|
|
@@ -6116,17 +6143,7 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
|
|
|
6116
6143
|
1,
|
|
6117
6144
|
...sc(next.z)
|
|
6118
6145
|
];
|
|
6119
|
-
push2(
|
|
6120
|
-
Math.max(
|
|
6121
|
-
tOut + RAMP_FLOOR,
|
|
6122
|
-
Math.min(
|
|
6123
|
-
tOut + style.pan * mNext,
|
|
6124
|
-
next.tIn + style.rampInOverlap * mNext
|
|
6125
|
-
)
|
|
6126
|
-
),
|
|
6127
|
-
nextValue,
|
|
6128
|
-
panEase
|
|
6129
|
-
);
|
|
6146
|
+
push2(pan.land, nextValue, panEase);
|
|
6130
6147
|
chained = true;
|
|
6131
6148
|
} else {
|
|
6132
6149
|
push2(
|
|
@@ -6142,7 +6159,8 @@ function zoomTrackFromDoc(zoom, segments, style = ZOOM_STYLES[DEFAULT_ZOOM_STYLE
|
|
|
6142
6159
|
function sameVec(a, b) {
|
|
6143
6160
|
return a.length === b.length && a.every((v, i) => Math.abs(v - b[i]) < 1e-6);
|
|
6144
6161
|
}
|
|
6145
|
-
function tiltTrackFromDoc(tilt, segments, motion = {}) {
|
|
6162
|
+
function tiltTrackFromDoc(tilt, segments, motion = {}, opts = {}) {
|
|
6163
|
+
const notBefore = opts.notBefore ?? -Infinity;
|
|
6146
6164
|
const rampInDur = motion.rampIn ?? TILT_RAMP_IN;
|
|
6147
6165
|
const rampOutDur = motion.rampOut ?? TILT_RAMP_OUT;
|
|
6148
6166
|
const chainGap = motion.chainGap ?? TILT_CHAIN_GAP;
|
|
@@ -6160,24 +6178,30 @@ function tiltTrackFromDoc(tilt, segments, motion = {}) {
|
|
|
6160
6178
|
const pose = [clampTiltDeg(z.rx), clampTiltDeg(z.ry)];
|
|
6161
6179
|
const m = transitionMult(z.transition);
|
|
6162
6180
|
if (!chained) {
|
|
6181
|
+
if (tOut <= notBefore + RAMP_FLOOR) continue;
|
|
6163
6182
|
const startWanted = tIn - rampInDur * m;
|
|
6164
|
-
const start = push2(startWanted, rest, "none");
|
|
6183
|
+
const start = push2(Math.max(startWanted, notBefore), rest, "none");
|
|
6165
6184
|
push2(
|
|
6166
6185
|
rampLanding(start, startWanted, rampInDur * m, tOut),
|
|
6167
6186
|
pose,
|
|
6168
6187
|
spanEase(z.ease, TILT_EASE)
|
|
6169
6188
|
);
|
|
6170
6189
|
}
|
|
6171
|
-
|
|
6190
|
+
const arrived = keyframes.at(-1)?.t ?? tIn;
|
|
6172
6191
|
const next = mapped.at(i + 1);
|
|
6173
|
-
|
|
6174
|
-
|
|
6192
|
+
const swing = next && next.tIn - tOut <= chainGap ? connectedWindow({
|
|
6193
|
+
arrived,
|
|
6194
|
+
tOut,
|
|
6195
|
+
landBy: next.tIn,
|
|
6196
|
+
latest: spillLimit(next.tIn, next.tOut),
|
|
6197
|
+
dur: panDur * transitionMult(next.z.transition),
|
|
6198
|
+
floor: RAMP_FLOOR
|
|
6199
|
+
}) : null;
|
|
6200
|
+
push2(swing ? swing.start : tOut, pose, "none");
|
|
6201
|
+
if (next && swing) {
|
|
6175
6202
|
push2(
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
Math.min(tOut + panDur * transitionMult(next.z.transition), next.tIn)
|
|
6179
|
-
),
|
|
6180
|
-
nextPose,
|
|
6203
|
+
swing.land,
|
|
6204
|
+
[clampTiltDeg(next.z.rx), clampTiltDeg(next.z.ry)],
|
|
6181
6205
|
panEase
|
|
6182
6206
|
);
|
|
6183
6207
|
chained = true;
|
|
@@ -6214,14 +6238,19 @@ function camTrackFromDoc(cam, spans, segments, W, H = 1080) {
|
|
|
6214
6238
|
const start = push2(tIn - CAM_RAMP_IN * m, rest, "none");
|
|
6215
6239
|
push2(start + CAM_RAMP_IN * m, pose, spanEase(z.ease, CAM_EASE));
|
|
6216
6240
|
}
|
|
6217
|
-
|
|
6241
|
+
const arrived = keyframes.at(-1)?.t ?? tIn;
|
|
6218
6242
|
const next = mapped.at(i + 1);
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
)
|
|
6243
|
+
const morph = next && next.tIn - tOut <= CAM_CHAIN_GAP ? connectedWindow({
|
|
6244
|
+
arrived,
|
|
6245
|
+
tOut,
|
|
6246
|
+
landBy: next.tIn,
|
|
6247
|
+
latest: spillLimit(next.tIn, next.tOut),
|
|
6248
|
+
dur: CAM_PAN * transitionMult(next.z.transition),
|
|
6249
|
+
floor: 0
|
|
6250
|
+
}) : null;
|
|
6251
|
+
push2(morph ? morph.start : tOut, pose, "none");
|
|
6252
|
+
if (next && morph) {
|
|
6253
|
+
push2(morph.land, poseOf(next.z), panEase);
|
|
6225
6254
|
chained = true;
|
|
6226
6255
|
} else {
|
|
6227
6256
|
push2(tOut + CAM_RAMP_OUT * m, rest, spanEase(z.ease, CAM_EASE));
|
|
@@ -6367,6 +6396,21 @@ var FRAME_STEP_SRC = `
|
|
|
6367
6396
|
}
|
|
6368
6397
|
function stepBg(bgEl, bgT) {
|
|
6369
6398
|
if (!bgEl.paused) bgEl.pause()
|
|
6399
|
+
// Capture pages: the loop's frame by PTS from its own provider, like the
|
|
6400
|
+
// footage. The loop clock only moves forward between wraps, so the walk
|
|
6401
|
+
// stays sequential and a wrap is one re-seek to the keyframe at 0.
|
|
6402
|
+
var bwc = bgEl.__voilaWc
|
|
6403
|
+
if (bwc) {
|
|
6404
|
+
var bwT = Math.min(bgT, bwc.duration || bgT)
|
|
6405
|
+
if (bwc.req !== bwT) {
|
|
6406
|
+
var bwp = bwc.seek(bwT)
|
|
6407
|
+
if (ns.pendingDecodes) {
|
|
6408
|
+
ns.pendingDecodes.add(bwp)
|
|
6409
|
+
bwp.finally(function () { ns.pendingDecodes.delete(bwp) })
|
|
6410
|
+
}
|
|
6411
|
+
}
|
|
6412
|
+
return
|
|
6413
|
+
}
|
|
6370
6414
|
var bgTarget = Math.min(bgT, bgEl.duration || bgT)
|
|
6371
6415
|
if (bgEl.readyState >= 1 && !bgEl.seeking && Math.abs(bgEl.currentTime - bgTarget) > 0.02) {
|
|
6372
6416
|
if (ns.pendingDecodes) {
|
|
@@ -6450,6 +6494,7 @@ var SETUP = `async (ctx) => {
|
|
|
6450
6494
|
// page has a memory budget) and FAIL-OPEN: any fetch trouble degrades to
|
|
6451
6495
|
// the plain network element, never a dead LOAD.
|
|
6452
6496
|
const BLOB_FETCH_MAX = 400 * 1024 * 1024
|
|
6497
|
+
const BG_BLOB_MAX = 64 * 1024 * 1024
|
|
6453
6498
|
const toBlobUrl = async (src) => {
|
|
6454
6499
|
const resp = await fetch(src)
|
|
6455
6500
|
if (!resp.ok) throw new Error('[voila] blob fetch HTTP ' + resp.status)
|
|
@@ -6650,9 +6695,48 @@ var SETUP = `async (ctx) => {
|
|
|
6650
6695
|
if (bgm && bgm.key) {
|
|
6651
6696
|
try {
|
|
6652
6697
|
if (bgm.kind === 'image') await loadImage(bgm.key)
|
|
6653
|
-
else
|
|
6698
|
+
else {
|
|
6699
|
+
const bgV = await load(bgm.key, true)
|
|
6700
|
+
bgV.loop = true
|
|
6701
|
+
// Capture pages: the loop gets its own provider. An element seek
|
|
6702
|
+
// decodes from the previous keyframe on EVERY frame (a baked loop
|
|
6703
|
+
// has one every few seconds), and the capture waits for it; the
|
|
6704
|
+
// sequential walk decodes each packet once. The whole loop is read
|
|
6705
|
+
// into a Blob first when it is small enough (one request instead
|
|
6706
|
+
// of ranged reads against a CDN). FAIL-OPEN to the element at
|
|
6707
|
+
// every step, like the footage.
|
|
6708
|
+
if (ctx.data.videoDecodeMode === 'webcodecs' && !bgV.__voilaWc) {
|
|
6709
|
+
try {
|
|
6710
|
+
if (!(ns.videoBlobs && ns.videoBlobs.get(bgm.key)) && bgm.key.indexOf('blob:') !== 0 && bgm.key.indexOf('data:') !== 0) {
|
|
6711
|
+
try {
|
|
6712
|
+
const bgResp = await fetch(bgm.key)
|
|
6713
|
+
const bgLen = Number(bgResp.headers.get('content-length') || 0)
|
|
6714
|
+
if (bgResp.ok && bgLen <= BG_BLOB_MAX) {
|
|
6715
|
+
;(ns.videoBlobs || (ns.videoBlobs = new Map())).set(bgm.key, await bgResp.blob())
|
|
6716
|
+
} else {
|
|
6717
|
+
try { if (bgResp.body) await bgResp.body.cancel() } catch (e) { void e }
|
|
6718
|
+
}
|
|
6719
|
+
} catch (e) { void e }
|
|
6720
|
+
}
|
|
6721
|
+
const bgWc = await makeWcProvider(bgm.key)
|
|
6722
|
+
if (bgWc && (!bgV.videoWidth || (bgWc.width === bgV.videoWidth && bgWc.height === bgV.videoHeight))) bgV.__voilaWc = bgWc
|
|
6723
|
+
} catch (e) {
|
|
6724
|
+
console.warn('[voila] webcodecs provider unavailable for the background, seeks stay html5', e)
|
|
6725
|
+
}
|
|
6726
|
+
}
|
|
6727
|
+
}
|
|
6654
6728
|
} catch (e) { console.warn('[voila] background media failed to load', e) }
|
|
6655
6729
|
}
|
|
6730
|
+
// Which path decodes what, for a host's telemetry: 'provider' is the
|
|
6731
|
+
// sequential WebCodecs walk, 'element' an HTMLVideoElement seek per frame.
|
|
6732
|
+
ns.voilaDecode = {
|
|
6733
|
+
recording: ctx.data.isImage ? 'none' : video.__voilaWc ? 'provider' : 'element',
|
|
6734
|
+
backdrop: (function () {
|
|
6735
|
+
if (!bgm || !bgm.key || bgm.kind === 'image') return 'none'
|
|
6736
|
+
const bgHit = cache.get(bgm.key)
|
|
6737
|
+
return bgHit && bgHit.__voilaWc ? 'provider' : 'element'
|
|
6738
|
+
})(),
|
|
6739
|
+
}
|
|
6656
6740
|
// Frame prep: a capture harness calls every ns.framePrep hook right after
|
|
6657
6741
|
// seeking the timeline and before the first paint, then awaits
|
|
6658
6742
|
// waitForVideosReady. The footage for the frame is requested HERE, so the
|
|
@@ -7281,7 +7365,14 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
7281
7365
|
// Blur: softens the media behind the card (design px \xD7 s).
|
|
7282
7366
|
var bgBlur = bgm.blur || 0
|
|
7283
7367
|
if (bgBlur > 0 && bgC.filter !== undefined) bgC.filter = 'blur(' + bgBlur * s + 'px)'
|
|
7284
|
-
|
|
7368
|
+
// The loop's provider draws its current sample (paused capture
|
|
7369
|
+
// pages); false \u21D2 the element (playback, or before the first ask).
|
|
7370
|
+
try {
|
|
7371
|
+
var bgWcp = !bgIsImg && !playing ? bgEl.__voilaWc : null
|
|
7372
|
+
if (!(bgWcp && bgWcp.draw(bgC, null, (W - bgDw) / 2 + bgOx, (H - bgDh) / 2 + bgOy, bgDw, bgDh))) {
|
|
7373
|
+
bgC.drawImage(bgEl, (W - bgDw) / 2 + bgOx, (H - bgDh) / 2 + bgOy, bgDw, bgDh)
|
|
7374
|
+
}
|
|
7375
|
+
} catch (e) {}
|
|
7285
7376
|
if (bgBlur > 0 && bgC.filter !== undefined) bgC.filter = 'none'
|
|
7286
7377
|
var bgDim = bgm.dim || 0
|
|
7287
7378
|
if (bgDim > 0) {
|
|
@@ -8369,9 +8460,9 @@ function lowerToComposition(input) {
|
|
|
8369
8460
|
camera,
|
|
8370
8461
|
zoomStyle
|
|
8371
8462
|
);
|
|
8372
|
-
const zoomTrack =
|
|
8373
|
-
|
|
8374
|
-
|
|
8463
|
+
const zoomTrack = withEntrance(
|
|
8464
|
+
entranceZoomKeyframes(cardEnter(doc.frame)),
|
|
8465
|
+
(opts) => zoomTrackFromDoc(zoomSpans, rated, zoomStyle, opts)
|
|
8375
8466
|
);
|
|
8376
8467
|
const pins = resolvePins(doc, layout, camera, zoomTrack);
|
|
8377
8468
|
const pinsData = pinsDataOf(doc, pins);
|
|
@@ -8470,8 +8561,8 @@ function lowerToComposition(input) {
|
|
|
8470
8561
|
transitions,
|
|
8471
8562
|
TILT_SPAN_MIN
|
|
8472
8563
|
) : [];
|
|
8473
|
-
const spans = tilts.length ? tiltTrackFromDoc(tilts, rated, zoomStyle.tilt) : void 0;
|
|
8474
|
-
const track =
|
|
8564
|
+
const spans = tilts.length ? (opts) => tiltTrackFromDoc(tilts, rated, zoomStyle.tilt, opts) : () => void 0;
|
|
8565
|
+
const track = withEntrance(head, spans);
|
|
8475
8566
|
return track ? { tiltTrack: track } : {};
|
|
8476
8567
|
})(),
|
|
8477
8568
|
// The card's pose through its enter and its exit: [scale, dy, opacity]
|
|
@@ -8567,9 +8658,9 @@ function docZoomTrack(input) {
|
|
|
8567
8658
|
camera,
|
|
8568
8659
|
zoomStyle
|
|
8569
8660
|
);
|
|
8570
|
-
return
|
|
8571
|
-
|
|
8572
|
-
|
|
8661
|
+
return withEntrance(
|
|
8662
|
+
entranceZoomKeyframes(cardEnter(doc.frame)),
|
|
8663
|
+
(opts) => zoomTrackFromDoc(spans, rated, zoomStyle, opts)
|
|
8573
8664
|
);
|
|
8574
8665
|
}
|
|
8575
8666
|
function resolvePins(doc, layout, camera, zoomTrack) {
|