@vosjs/studio-core 0.23.1 → 0.24.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 +158 -2
- package/dist/index.js +702 -212
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1828,8 +1828,8 @@ function round(v) {
|
|
|
1828
1828
|
// src/lower/lowerToComposition.ts
|
|
1829
1829
|
import {
|
|
1830
1830
|
EASINGS,
|
|
1831
|
-
lerpArray,
|
|
1832
|
-
sample,
|
|
1831
|
+
lerpArray as lerpArray2,
|
|
1832
|
+
sample as sample2,
|
|
1833
1833
|
segmentRate as segmentRate2,
|
|
1834
1834
|
sortKeyframes as sortKeyframes2,
|
|
1835
1835
|
sourceToTimeline,
|
|
@@ -2661,14 +2661,14 @@ function resolveOverlayFx(clip, clipDuration) {
|
|
|
2661
2661
|
const maxTotal = Math.max(dur, clipDuration * 0.9);
|
|
2662
2662
|
st = Math.min(st, Math.max(0, (maxTotal - dur) / (upperN - 1)));
|
|
2663
2663
|
}
|
|
2664
|
-
const
|
|
2664
|
+
const round13 = (v) => Math.round(v * 1e4) / 1e4;
|
|
2665
2665
|
return {
|
|
2666
2666
|
k: spec.fx,
|
|
2667
2667
|
u: unit,
|
|
2668
2668
|
d: FX_DIR[spec.direction ?? "forward"] ?? 0,
|
|
2669
|
-
st:
|
|
2670
|
-
dur:
|
|
2671
|
-
tt:
|
|
2669
|
+
st: round13(st),
|
|
2670
|
+
dur: round13(dur),
|
|
2671
|
+
tt: round13(st * (upperN - 1) + dur),
|
|
2672
2672
|
units,
|
|
2673
2673
|
n
|
|
2674
2674
|
};
|
|
@@ -3057,12 +3057,280 @@ function round2(v) {
|
|
|
3057
3057
|
return Math.round(v * 1e3) / 1e3;
|
|
3058
3058
|
}
|
|
3059
3059
|
|
|
3060
|
+
// src/lower/pin.ts
|
|
3061
|
+
import { lerpArray, sample } from "@vosjs/timeline";
|
|
3062
|
+
var PIN_GAP = 24;
|
|
3063
|
+
var PIN_MARGIN = 24;
|
|
3064
|
+
var PIN_SAMPLE_HZ = 30;
|
|
3065
|
+
var PIN_SIMPLIFY_PX = 0.5;
|
|
3066
|
+
var PIN_EDGE_S = 0.35;
|
|
3067
|
+
var PIN_PRESS_WINDOW_S = 0.5;
|
|
3068
|
+
var PIN_TEXT_ADVANCE = 0.55;
|
|
3069
|
+
var SIDE_ORDER = ["right", "left", "below", "above"];
|
|
3070
|
+
function pinReferent(doc, pin) {
|
|
3071
|
+
const meta = doc.source.meta;
|
|
3072
|
+
const w = meta.width || 0;
|
|
3073
|
+
const h = meta.height || 0;
|
|
3074
|
+
if (pin.rect && validRect(pin.rect)) {
|
|
3075
|
+
return { rect: { ...pin.rect }, by: "rect", at: null };
|
|
3076
|
+
}
|
|
3077
|
+
if (pin.step !== void 0) {
|
|
3078
|
+
const step = findStep(meta.steps ?? [], pin.step);
|
|
3079
|
+
if (!step || step.skipped) return null;
|
|
3080
|
+
if (step.rect && validRect(step.rect) && w > 0 && h > 0) {
|
|
3081
|
+
return {
|
|
3082
|
+
rect: normRect(step.rect, w, h),
|
|
3083
|
+
by: "step",
|
|
3084
|
+
step,
|
|
3085
|
+
at: step.tStart
|
|
3086
|
+
};
|
|
3087
|
+
}
|
|
3088
|
+
const union = unionRects(
|
|
3089
|
+
pressRects(doc, step.tStart - 0.05, step.tEnd + 0.05)
|
|
3090
|
+
);
|
|
3091
|
+
if (!union || w <= 0 || h <= 0) return null;
|
|
3092
|
+
return { rect: normRect(union, w, h), by: "step", step, at: step.tStart };
|
|
3093
|
+
}
|
|
3094
|
+
if (pin.press !== void 0 && Number.isFinite(pin.press)) {
|
|
3095
|
+
let best = null;
|
|
3096
|
+
for (const e of doc.source.cursor) {
|
|
3097
|
+
if (e.type !== "down" || !e.rect || !validRect(e.rect)) continue;
|
|
3098
|
+
const t = e.t / 1e3;
|
|
3099
|
+
const d = Math.abs(t - pin.press);
|
|
3100
|
+
if (d > PIN_PRESS_WINDOW_S) continue;
|
|
3101
|
+
if (!best || d < Math.abs(best.t - pin.press)) best = { t, rect: e.rect };
|
|
3102
|
+
}
|
|
3103
|
+
if (!best || w <= 0 || h <= 0) return null;
|
|
3104
|
+
return { rect: normRect(best.rect, w, h), by: "press", at: best.t };
|
|
3105
|
+
}
|
|
3106
|
+
return null;
|
|
3107
|
+
}
|
|
3108
|
+
function findStep(steps, ref) {
|
|
3109
|
+
const byId = steps.find((s) => s.id !== void 0 && s.id === ref);
|
|
3110
|
+
if (byId) return byId;
|
|
3111
|
+
const idx = typeof ref === "number" ? ref : Number(ref);
|
|
3112
|
+
if (!Number.isInteger(idx)) return void 0;
|
|
3113
|
+
return steps.find((s) => s.step === idx);
|
|
3114
|
+
}
|
|
3115
|
+
function pressRects(doc, from, to) {
|
|
3116
|
+
const out = [];
|
|
3117
|
+
for (const e of doc.source.cursor) {
|
|
3118
|
+
if (e.type !== "down" && e.type !== "key") continue;
|
|
3119
|
+
if (!e.rect || !validRect(e.rect)) continue;
|
|
3120
|
+
const t = e.t / 1e3;
|
|
3121
|
+
if (t < from || t > to) continue;
|
|
3122
|
+
out.push(e.rect);
|
|
3123
|
+
}
|
|
3124
|
+
return out;
|
|
3125
|
+
}
|
|
3126
|
+
function unionRects(rects) {
|
|
3127
|
+
if (!rects.length) return null;
|
|
3128
|
+
let x0 = Infinity;
|
|
3129
|
+
let y0 = Infinity;
|
|
3130
|
+
let x1 = -Infinity;
|
|
3131
|
+
let y1 = -Infinity;
|
|
3132
|
+
for (const r of rects) {
|
|
3133
|
+
x0 = Math.min(x0, r.x);
|
|
3134
|
+
y0 = Math.min(y0, r.y);
|
|
3135
|
+
x1 = Math.max(x1, r.x + r.w);
|
|
3136
|
+
y1 = Math.max(y1, r.y + r.h);
|
|
3137
|
+
}
|
|
3138
|
+
return { x: x0, y: y0, w: x1 - x0, h: y1 - y0 };
|
|
3139
|
+
}
|
|
3140
|
+
function validRect(r) {
|
|
3141
|
+
return Number.isFinite(r.x) && Number.isFinite(r.y) && Number.isFinite(r.w) && Number.isFinite(r.h) && r.w > 0 && r.h > 0;
|
|
3142
|
+
}
|
|
3143
|
+
function normRect(r, w, h) {
|
|
3144
|
+
return { x: r.x / w, y: r.y / h, w: r.w / w, h: r.h / h };
|
|
3145
|
+
}
|
|
3146
|
+
function pinBox(clip, layout) {
|
|
3147
|
+
const scale = clip.transform.scale || 1;
|
|
3148
|
+
if (clip.kind === "html") {
|
|
3149
|
+
const pb = htmlLayerPictureBox(clip);
|
|
3150
|
+
const wPic = htmlLayerWidth(clip) * layout.W * scale;
|
|
3151
|
+
const unit = wPic / pb.width;
|
|
3152
|
+
return { w: clip.box.width * unit, h: clip.box.height * unit };
|
|
3153
|
+
}
|
|
3154
|
+
if (clip.kind !== "text") {
|
|
3155
|
+
const w = (clip.width ?? OVERLAY_MEDIA_DEFAULT_WIDTH) * layout.W * scale;
|
|
3156
|
+
return { w, h: w / (16 / 9) };
|
|
3157
|
+
}
|
|
3158
|
+
const r = overlayRect(clip, estimateMeasure, layout.W, layout.H);
|
|
3159
|
+
return { w: r.w, h: r.h };
|
|
3160
|
+
}
|
|
3161
|
+
function estimateMeasure(text, font, letterSpacingPx = 0) {
|
|
3162
|
+
const m = /(\d+(?:\.\d+)?)px/.exec(font);
|
|
3163
|
+
const px = m ? Number(m[1]) : 16;
|
|
3164
|
+
return text.length * (px * PIN_TEXT_ADVANCE + letterSpacingPx);
|
|
3165
|
+
}
|
|
3166
|
+
function pinRectOnScreen(rect, t, layout, camera, zoomTrack) {
|
|
3167
|
+
let level = 1;
|
|
3168
|
+
let cx = 0.5;
|
|
3169
|
+
let cy = 0.5;
|
|
3170
|
+
let centring;
|
|
3171
|
+
if (zoomTrack && zoomTrack.keyframes.length) {
|
|
3172
|
+
const z = sample(zoomTrack, t, lerpArray);
|
|
3173
|
+
level = z[0];
|
|
3174
|
+
cx = z[1];
|
|
3175
|
+
cy = z[2];
|
|
3176
|
+
if (z.length > 3) centring = z[3];
|
|
3177
|
+
}
|
|
3178
|
+
const v = zoomView(level, cx, cy, layout, camera, centring);
|
|
3179
|
+
const map = (nx, ny) => {
|
|
3180
|
+
const px = layout.dx + nx * layout.dw;
|
|
3181
|
+
const py = layout.dy + ny * layout.dh;
|
|
3182
|
+
return {
|
|
3183
|
+
x: v.ox + (px - v.wcx) * v.level,
|
|
3184
|
+
y: v.oy + (py - v.wcy) * v.level
|
|
3185
|
+
};
|
|
3186
|
+
};
|
|
3187
|
+
const a = map(rect.x, rect.y);
|
|
3188
|
+
const b = map(rect.x + rect.w, rect.y + rect.h);
|
|
3189
|
+
return { x: a.x, y: a.y, w: b.x - a.x, h: b.y - a.y };
|
|
3190
|
+
}
|
|
3191
|
+
function pinPlacement(input) {
|
|
3192
|
+
const { clip, referent, layout, camera, zoomTrack, base, motion } = input;
|
|
3193
|
+
const dur = Math.max(1e-3, clip.duration);
|
|
3194
|
+
const gap = clip.pin?.gap ?? PIN_GAP;
|
|
3195
|
+
const box = pinBox(clip, layout);
|
|
3196
|
+
const W = layout.W;
|
|
3197
|
+
const H = layout.H;
|
|
3198
|
+
const refAt = (local) => pinRectOnScreen(referent, clip.start + local, layout, camera, zoomTrack);
|
|
3199
|
+
const centreFor = (r, side2) => {
|
|
3200
|
+
switch (side2) {
|
|
3201
|
+
case "right":
|
|
3202
|
+
return { x: r.x + r.w + gap + box.w / 2, y: r.y + r.h / 2 };
|
|
3203
|
+
case "left":
|
|
3204
|
+
return { x: r.x - gap - box.w / 2, y: r.y + r.h / 2 };
|
|
3205
|
+
case "below":
|
|
3206
|
+
return { x: r.x + r.w / 2, y: r.y + r.h + gap + box.h / 2 };
|
|
3207
|
+
case "above":
|
|
3208
|
+
return { x: r.x + r.w / 2, y: r.y - gap - box.h / 2 };
|
|
3209
|
+
}
|
|
3210
|
+
};
|
|
3211
|
+
const fits = (c) => c.x - box.w / 2 >= PIN_MARGIN && c.x + box.w / 2 <= W - PIN_MARGIN && c.y - box.h / 2 >= PIN_MARGIN && c.y + box.h / 2 <= H - PIN_MARGIN;
|
|
3212
|
+
const room = (c) => {
|
|
3213
|
+
const x0 = Math.max(PIN_MARGIN, c.x - box.w / 2);
|
|
3214
|
+
const x1 = Math.min(W - PIN_MARGIN, c.x + box.w / 2);
|
|
3215
|
+
const y0 = Math.max(PIN_MARGIN, c.y - box.h / 2);
|
|
3216
|
+
const y1 = Math.min(H - PIN_MARGIN, c.y + box.h / 2);
|
|
3217
|
+
return Math.max(0, x1 - x0) * Math.max(0, y1 - y0);
|
|
3218
|
+
};
|
|
3219
|
+
let side;
|
|
3220
|
+
const asked = clip.pin?.side ?? "auto";
|
|
3221
|
+
if (asked !== "auto") side = asked;
|
|
3222
|
+
else {
|
|
3223
|
+
const edge = Math.min(PIN_EDGE_S, dur / 3);
|
|
3224
|
+
const probes = [edge, dur / 2, dur - edge].map(refAt);
|
|
3225
|
+
const fitting = SIDE_ORDER.find(
|
|
3226
|
+
(s) => probes.every((r) => fits(centreFor(r, s)))
|
|
3227
|
+
);
|
|
3228
|
+
if (fitting) side = fitting;
|
|
3229
|
+
else {
|
|
3230
|
+
let best = SIDE_ORDER[0];
|
|
3231
|
+
let bestRoom = -1;
|
|
3232
|
+
for (const s of SIDE_ORDER) {
|
|
3233
|
+
const total = probes.reduce((acc, r) => acc + room(centreFor(r, s)), 0);
|
|
3234
|
+
if (total > bestRoom) {
|
|
3235
|
+
bestRoom = total;
|
|
3236
|
+
best = s;
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
side = best;
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3242
|
+
const clampC = (c) => {
|
|
3243
|
+
const minX = Math.min(W / 2, PIN_MARGIN + box.w / 2);
|
|
3244
|
+
const maxX = Math.max(W / 2, W - PIN_MARGIN - box.w / 2);
|
|
3245
|
+
const minY = Math.min(H / 2, PIN_MARGIN + box.h / 2);
|
|
3246
|
+
const maxY = Math.max(H / 2, H - PIN_MARGIN - box.h / 2);
|
|
3247
|
+
return {
|
|
3248
|
+
x: Math.max(minX, Math.min(maxX, c.x)),
|
|
3249
|
+
y: Math.max(minY, Math.min(maxY, c.y))
|
|
3250
|
+
};
|
|
3251
|
+
};
|
|
3252
|
+
const tipFor = (c) => {
|
|
3253
|
+
switch (side) {
|
|
3254
|
+
case "right":
|
|
3255
|
+
return { x: c.x - box.w / 2, y: c.y };
|
|
3256
|
+
case "left":
|
|
3257
|
+
return { x: c.x + box.w / 2, y: c.y };
|
|
3258
|
+
case "below":
|
|
3259
|
+
return { x: c.x, y: c.y - box.h / 2 };
|
|
3260
|
+
case "above":
|
|
3261
|
+
return { x: c.x, y: c.y + box.h / 2 };
|
|
3262
|
+
}
|
|
3263
|
+
};
|
|
3264
|
+
const n = Math.max(1, Math.ceil(dur * PIN_SAMPLE_HZ));
|
|
3265
|
+
const poses = [];
|
|
3266
|
+
const tips = [];
|
|
3267
|
+
let clamped = 0;
|
|
3268
|
+
for (let i = 0; i <= n; i++) {
|
|
3269
|
+
const local = i === n ? dur : i / PIN_SAMPLE_HZ;
|
|
3270
|
+
const want = centreFor(refAt(local), side);
|
|
3271
|
+
const c = clampC(want);
|
|
3272
|
+
clamped = Math.max(clamped, Math.hypot(c.x - want.x, c.y - want.y));
|
|
3273
|
+
const pose = motion?.keyframes.length ? sample(motion, local, lerpArray) : base;
|
|
3274
|
+
poses.push({
|
|
3275
|
+
t: local,
|
|
3276
|
+
value: [c.x / W, c.y / H, pose[2], pose[3], pose[4]],
|
|
3277
|
+
ease: "linear"
|
|
3278
|
+
});
|
|
3279
|
+
const tp = tipFor(c);
|
|
3280
|
+
tips.push({ t: local, value: [tp.x / W, tp.y / H], ease: "linear" });
|
|
3281
|
+
}
|
|
3282
|
+
return {
|
|
3283
|
+
side,
|
|
3284
|
+
track: { keyframes: simplify(poses, [W, H, 1, 1, 1]) },
|
|
3285
|
+
tip: { keyframes: simplify(tips, [W, H]) },
|
|
3286
|
+
clamped: round4(clamped),
|
|
3287
|
+
box
|
|
3288
|
+
};
|
|
3289
|
+
}
|
|
3290
|
+
function simplify(keys, scalePx) {
|
|
3291
|
+
if (keys.length <= 2) return keys.map(roundKey);
|
|
3292
|
+
const out = [roundKey(keys[0])];
|
|
3293
|
+
let a = 0;
|
|
3294
|
+
for (let i = 2; i <= keys.length - 1; i++) {
|
|
3295
|
+
const ka = keys[a];
|
|
3296
|
+
const ki = keys[i];
|
|
3297
|
+
let ok = true;
|
|
3298
|
+
for (let j = a + 1; j < i && ok; j++) {
|
|
3299
|
+
const kj = keys[j];
|
|
3300
|
+
const u = (kj.t - ka.t) / (ki.t - ka.t || 1);
|
|
3301
|
+
for (let k = 0; k < kj.value.length; k++) {
|
|
3302
|
+
const pred = ka.value[k] + (ki.value[k] - ka.value[k]) * u;
|
|
3303
|
+
if (Math.abs(pred - kj.value[k]) * (scalePx[k] ?? 1) > PIN_SIMPLIFY_PX) {
|
|
3304
|
+
ok = false;
|
|
3305
|
+
break;
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3309
|
+
if (!ok) {
|
|
3310
|
+
a = i - 1;
|
|
3311
|
+
out.push(roundKey(keys[a]));
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
const last = keys[keys.length - 1];
|
|
3315
|
+
if (out[out.length - 1].t !== round4(last.t)) out.push(roundKey(last));
|
|
3316
|
+
return out;
|
|
3317
|
+
}
|
|
3318
|
+
function roundKey(k) {
|
|
3319
|
+
return { t: round4(k.t), value: k.value.map(round42), ease: k.ease };
|
|
3320
|
+
}
|
|
3321
|
+
function round4(v) {
|
|
3322
|
+
return Math.round(v * 1e3) / 1e3;
|
|
3323
|
+
}
|
|
3324
|
+
function round42(v) {
|
|
3325
|
+
return Math.round(v * 1e5) / 1e5;
|
|
3326
|
+
}
|
|
3327
|
+
|
|
3060
3328
|
// src/lower/cursorIdle.ts
|
|
3061
3329
|
var CURSOR_IDLE_HOLD = 1;
|
|
3062
3330
|
var CURSOR_IDLE_FADE_OUT = 0.35;
|
|
3063
3331
|
var CURSOR_IDLE_FADE_IN = 0.18;
|
|
3064
3332
|
var CURSOR_IDLE_EPS_FRAC = 25e-4;
|
|
3065
|
-
var
|
|
3333
|
+
var round5 = (n) => Math.round(n * 1e3) / 1e3;
|
|
3066
3334
|
function cursorIdleFade(track, o) {
|
|
3067
3335
|
const moves = track.filter((e) => e.type === "move" || e.type === "down" || e.type === "up").map((e) => ({ t: e.t / 1e3, x: e.x, y: e.y }));
|
|
3068
3336
|
if (moves.length === 0) return [];
|
|
@@ -3114,7 +3382,7 @@ function emit(keys, s, e) {
|
|
|
3114
3382
|
push(keys, e + CURSOR_IDLE_FADE_IN, 1);
|
|
3115
3383
|
}
|
|
3116
3384
|
function push(keys, t, a) {
|
|
3117
|
-
const rt =
|
|
3385
|
+
const rt = round5(t);
|
|
3118
3386
|
if (keys.length > 0 && rt <= keys[keys.length - 1].t) {
|
|
3119
3387
|
keys[keys.length - 1].a = a;
|
|
3120
3388
|
return;
|
|
@@ -4622,7 +4890,7 @@ function gatedRect(rect, x, y, space) {
|
|
|
4622
4890
|
return null;
|
|
4623
4891
|
const m = RECT_CONTAIN_MARGIN;
|
|
4624
4892
|
const inside = x >= rect.x - m && x <= rect.x + rect.w + m && y >= rect.y - m && y <= rect.y + rect.h + m;
|
|
4625
|
-
return inside ? [
|
|
4893
|
+
return inside ? [round6(rect.x), round6(rect.y), round6(rect.w), round6(rect.h)] : null;
|
|
4626
4894
|
}
|
|
4627
4895
|
function extractClicks(track, segments, opts) {
|
|
4628
4896
|
const out = [];
|
|
@@ -4647,11 +4915,11 @@ function extractClicks(track, segments, opts) {
|
|
|
4647
4915
|
const upSrc = st + Math.max(pressLen, 0.02);
|
|
4648
4916
|
const up = keptOutputEnd(segments, st, upSrc, opts.media) ?? ot + CLICK_SYNTH_RELEASE;
|
|
4649
4917
|
const click = {
|
|
4650
|
-
ot:
|
|
4651
|
-
up:
|
|
4652
|
-
st:
|
|
4653
|
-
x:
|
|
4654
|
-
y:
|
|
4918
|
+
ot: round6(ot),
|
|
4919
|
+
up: round6(Math.max(up, ot + 0.02)),
|
|
4920
|
+
st: round6(st),
|
|
4921
|
+
x: round6(e.x),
|
|
4922
|
+
y: round6(e.y),
|
|
4655
4923
|
b: button
|
|
4656
4924
|
};
|
|
4657
4925
|
if (opts.rects && e.rect) {
|
|
@@ -4670,7 +4938,7 @@ function hexToRgbTriplet(hex) {
|
|
|
4670
4938
|
const n = parseInt(h, 16);
|
|
4671
4939
|
return [n >> 16, n >> 8 & 255, n & 255];
|
|
4672
4940
|
}
|
|
4673
|
-
function
|
|
4941
|
+
function round6(v) {
|
|
4674
4942
|
return Math.round(v * 1e3) / 1e3;
|
|
4675
4943
|
}
|
|
4676
4944
|
|
|
@@ -4746,7 +5014,7 @@ function trackEmitter() {
|
|
|
4746
5014
|
if (tt <= prev.t + 1e-6 && sameVec(prev.value, value)) return prev.t;
|
|
4747
5015
|
if (tt <= prev.t + 1e-6) tt = prev.t + 1e-3;
|
|
4748
5016
|
}
|
|
4749
|
-
keyframes.push({ t:
|
|
5017
|
+
keyframes.push({ t: round7(tt), value: value.map(round7), ease });
|
|
4750
5018
|
return tt;
|
|
4751
5019
|
};
|
|
4752
5020
|
return { keyframes, push: push2 };
|
|
@@ -4923,7 +5191,7 @@ function camBubbleRectAt(doc, t) {
|
|
|
4923
5191
|
H
|
|
4924
5192
|
);
|
|
4925
5193
|
if (!track.keyframes.length) return camBubbleRect(doc.cam, W, H);
|
|
4926
|
-
return camRectFromPose(
|
|
5194
|
+
return camRectFromPose(sample2(track, t, lerpArray2), doc.cam, W, H);
|
|
4927
5195
|
}
|
|
4928
5196
|
function motionTrack(base, keys, dur) {
|
|
4929
5197
|
const sorted = keys.filter((k) => Number.isFinite(k.at)).sort((a, b) => a.at - b.at);
|
|
@@ -4971,7 +5239,7 @@ function overlayMotionPoseAt(o, t) {
|
|
|
4971
5239
|
Math.max(OVERLAY_MIN_DURATION, o.duration)
|
|
4972
5240
|
);
|
|
4973
5241
|
if (!track.keyframes.length) return null;
|
|
4974
|
-
return [...
|
|
5242
|
+
return [...sample2(track, t, lerpArray2)];
|
|
4975
5243
|
}
|
|
4976
5244
|
function objectMotionBase(o) {
|
|
4977
5245
|
const t = o.transform3d;
|
|
@@ -5001,7 +5269,7 @@ function objectMotionPoseAt(o, t, clipDur) {
|
|
|
5001
5269
|
o.span?.duration ?? clipDur
|
|
5002
5270
|
);
|
|
5003
5271
|
if (!track.keyframes.length) return null;
|
|
5004
|
-
return [...
|
|
5272
|
+
return [...sample2(track, t, lerpArray2)];
|
|
5005
5273
|
}
|
|
5006
5274
|
var FRAME_STEP_SRC = `
|
|
5007
5275
|
function stepPaused(vid, srcT) {
|
|
@@ -6383,6 +6651,50 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
6383
6651
|
}
|
|
6384
6652
|
}
|
|
6385
6653
|
|
|
6654
|
+
// pinned layers' marks \u2014 a standing ring or underline on a layer's
|
|
6655
|
+
// REFERENT for the layer's life (d.pins: OUTPUT-anchored records baked at
|
|
6656
|
+
// lowering, the referent in normalised video fractions). Painted inside the
|
|
6657
|
+
// zoom transform so the mark sits on the element under any level or pose,
|
|
6658
|
+
// at a constant on-screen weight (\xF7 ceZs), with the layer's own entrance
|
|
6659
|
+
// and exit. Locals are pn-prefixed (one var scope). Skipped on the ghost
|
|
6660
|
+
// pass like the effects.
|
|
6661
|
+
var pns = d.pins || []
|
|
6662
|
+
if (pns.length && !tpG) {
|
|
6663
|
+
for (var pi = 0; pi < pns.length; pi++) {
|
|
6664
|
+
var pn = pns[pi]
|
|
6665
|
+
if (!pn.mark || pn.mark === 'none') continue
|
|
6666
|
+
var pnT = t - pn.start
|
|
6667
|
+
if (pnT < 0 || pnT > pn.dur) continue
|
|
6668
|
+
var pnA = 1
|
|
6669
|
+
if (pnT < 0.35) { var pnU = pnT / 0.35; pnA = 1 - Math.pow(1 - pnU, 3) }
|
|
6670
|
+
if (pn.dur - pnT < 0.35) { var pnV = (pn.dur - pnT) / 0.35; pnA = Math.min(pnA, 1 - Math.pow(1 - pnV, 3)) }
|
|
6671
|
+
if (pnA <= 0.004) continue
|
|
6672
|
+
var pnX = dx + pn.x * dw, pnY = dy + pn.y * dh, pnW = pn.w * dw, pnH = pn.h * dh
|
|
6673
|
+
var pnLw = 2 * s2 / ceZs, pnPad = 6 * s2 / ceZs
|
|
6674
|
+
var pnCol = pn.color || 'rgba(255,255,255,0.95)'
|
|
6675
|
+
c.save()
|
|
6676
|
+
c.globalAlpha = pnA
|
|
6677
|
+
if (pn.mark === 'underline') {
|
|
6678
|
+
// a bar under the referent: dark rim, then the ink
|
|
6679
|
+
var pnBy = pnY + pnH + pnPad * 0.5
|
|
6680
|
+
c.fillStyle = 'rgba(0,0,0,0.35)'
|
|
6681
|
+
c.fillRect(pnX - pnLw, pnBy - pnLw, pnW + pnLw * 2, pnLw * 1.5 + pnLw * 2)
|
|
6682
|
+
c.fillStyle = pnCol
|
|
6683
|
+
c.fillRect(pnX, pnBy, pnW, pnLw * 1.5)
|
|
6684
|
+
} else {
|
|
6685
|
+
// a ring around the referent: the cursor's dual stroke, a dark rim
|
|
6686
|
+
// under the ink, legible on any content
|
|
6687
|
+
c.lineWidth = pnLw + 2 * s2 / ceZs
|
|
6688
|
+
c.strokeStyle = 'rgba(0,0,0,0.35)'
|
|
6689
|
+
rr(pnX - pnPad, pnY - pnPad, pnW + pnPad * 2, pnH + pnPad * 2, pnPad, c); c.stroke()
|
|
6690
|
+
c.lineWidth = pnLw
|
|
6691
|
+
c.strokeStyle = pnCol
|
|
6692
|
+
rr(pnX - pnPad, pnY - pnPad, pnW + pnPad * 2, pnH + pnPad * 2, pnPad, c); c.stroke()
|
|
6693
|
+
}
|
|
6694
|
+
c.restore()
|
|
6695
|
+
}
|
|
6696
|
+
}
|
|
6697
|
+
|
|
6386
6698
|
// cursor (SOURCE-anchored samples, read at the on-screen source moment).
|
|
6387
6699
|
// The dot is the only thing cursorStyle.visible hides \u2014 the track still drives
|
|
6388
6700
|
// cursor-follow zoom, and click effects draw above on their own switch.
|
|
@@ -6445,8 +6757,15 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
6445
6757
|
// Wait only for the FIRST decoded frame, then keep drawing through seeks.
|
|
6446
6758
|
if (camV && camV.readyState >= 2) r.camHasFrame = true
|
|
6447
6759
|
var camActiveNow = !!(camV && camOn && camS.visible !== false && r.camHasFrame)
|
|
6760
|
+
// A pinned layer's leader is live for the layer's life: the overlay layer
|
|
6761
|
+
// repaints while one is up (the referent moves with the camera).
|
|
6762
|
+
var pqs = d.pins || [], pqLive = false
|
|
6763
|
+
for (var pl = 0; pl < pqs.length; pl++) {
|
|
6764
|
+
var pq0 = pqs[pl]
|
|
6765
|
+
if (pq0.leader && t >= pq0.start && t <= pq0.start + pq0.dur) { pqLive = true; break }
|
|
6766
|
+
}
|
|
6448
6767
|
var ovSig = W + 'x' + H
|
|
6449
|
-
var ovDirty = ov.sig !== ovSig || camActiveNow || ov.active || !!trOut
|
|
6768
|
+
var ovDirty = ov.sig !== ovSig || camActiveNow || ov.active || !!trOut || pqLive
|
|
6450
6769
|
if (ovDirty) {
|
|
6451
6770
|
ovC.clearRect(0, 0, W, H)
|
|
6452
6771
|
// webcam bubble \u2014 pinned to the frame corner regardless of card tilt/zoom.
|
|
@@ -6496,6 +6815,57 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
6496
6815
|
ovC.restore()
|
|
6497
6816
|
}
|
|
6498
6817
|
}
|
|
6818
|
+
// pinned layers' leaders \u2014 a hairline from the layer's near edge (the
|
|
6819
|
+
// baked tip track, clip-local frame fractions) to the referent's near
|
|
6820
|
+
// edge, the referent mapped through the camera the way the boundary dot
|
|
6821
|
+
// is, with a dot at the referent. Fades with the layer; rides the rise
|
|
6822
|
+
// entrance so the line meets the card as it lands.
|
|
6823
|
+
if (pqLive) {
|
|
6824
|
+
for (var pj = 0; pj < pqs.length; pj++) {
|
|
6825
|
+
var pq = pqs[pj]
|
|
6826
|
+
if (!pq.leader) continue
|
|
6827
|
+
var pqT = t - pq.start
|
|
6828
|
+
if (pqT < 0 || pqT > pq.dur) continue
|
|
6829
|
+
var pqA = 1, pqRise = 0
|
|
6830
|
+
if (pqT < 0.35) {
|
|
6831
|
+
var pqU = 1 - Math.pow(1 - pqT / 0.35, 3)
|
|
6832
|
+
pqA = pqU
|
|
6833
|
+
if (pq.enter === 'rise') pqRise = (1 - pqU) * 24 * s
|
|
6834
|
+
}
|
|
6835
|
+
if (pq.dur - pqT < 0.35) { var pqV = (pq.dur - pqT) / 0.35; pqA = Math.min(pqA, 1 - Math.pow(1 - pqV, 3)) }
|
|
6836
|
+
if (pqA <= 0.004 || !pq.tip || !pq.tip.keyframes || !pq.tip.keyframes.length) continue
|
|
6837
|
+
var pqTip = TL.sample(pq.tip, pqT, TL.lerpArray)
|
|
6838
|
+
var pqTx = pqTip[0] * W, pqTy = pqTip[1] * H + pqRise
|
|
6839
|
+
// the referent's corners in frame space under the live camera
|
|
6840
|
+
var pqAx = dx + pq.x * dw, pqAy = dy + pq.y * dh
|
|
6841
|
+
var pqBx = dx + (pq.x + pq.w) * dw, pqBy = dy + (pq.y + pq.h) * dh
|
|
6842
|
+
if (lvl > 1.001 && !d.zoomSuppressed) {
|
|
6843
|
+
if (camStage) {
|
|
6844
|
+
pqAx = W / 2 + (pqAx - wcx) * lvl; pqAy = H / 2 + (pqAy - wcy) * lvl
|
|
6845
|
+
pqBx = W / 2 + (pqBx - wcx) * lvl; pqBy = H / 2 + (pqBy - wcy) * lvl
|
|
6846
|
+
} else {
|
|
6847
|
+
pqAx = fx + (pqAx - fx) * lvl; pqAy = fy + (pqAy - fy) * lvl
|
|
6848
|
+
pqBx = fx + (pqBx - fx) * lvl; pqBy = fy + (pqBy - fy) * lvl
|
|
6849
|
+
}
|
|
6850
|
+
}
|
|
6851
|
+
var pqRx = pq.side === 'right' ? pqBx : pq.side === 'left' ? pqAx : (pqAx + pqBx) / 2
|
|
6852
|
+
var pqRy = pq.side === 'below' ? pqBy : pq.side === 'above' ? pqAy : (pqAy + pqBy) / 2
|
|
6853
|
+
var pqCol = pq.color || 'rgba(255,255,255,0.95)'
|
|
6854
|
+
var pqLw = 2 * s
|
|
6855
|
+
ovC.save()
|
|
6856
|
+
ovC.globalAlpha = pqA
|
|
6857
|
+
ovC.lineCap = 'round'
|
|
6858
|
+
ovC.strokeStyle = 'rgba(0,0,0,0.35)'; ovC.lineWidth = pqLw + 2 * s
|
|
6859
|
+
ovC.beginPath(); ovC.moveTo(pqTx, pqTy); ovC.lineTo(pqRx, pqRy); ovC.stroke()
|
|
6860
|
+
ovC.strokeStyle = pqCol; ovC.lineWidth = pqLw
|
|
6861
|
+
ovC.beginPath(); ovC.moveTo(pqTx, pqTy); ovC.lineTo(pqRx, pqRy); ovC.stroke()
|
|
6862
|
+
ovC.fillStyle = 'rgba(0,0,0,0.35)'
|
|
6863
|
+
ovC.beginPath(); ovC.arc(pqRx, pqRy, 5 * s, 0, Math.PI * 2); ovC.fill()
|
|
6864
|
+
ovC.fillStyle = pqCol
|
|
6865
|
+
ovC.beginPath(); ovC.arc(pqRx, pqRy, 4 * s, 0, Math.PI * 2); ovC.fill()
|
|
6866
|
+
ovC.restore()
|
|
6867
|
+
}
|
|
6868
|
+
}
|
|
6499
6869
|
// The boundary dot: the outgoing card's last cursor point and the
|
|
6500
6870
|
// incoming's current one, each carried by its card's move, one dot on
|
|
6501
6871
|
// the eased lerp between them (the idle fade never fires across a page
|
|
@@ -6510,7 +6880,7 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
6510
6880
|
drawCur(ovC, tqX2, tqY2, tqR, 1, 2 * (trQw || s))
|
|
6511
6881
|
}
|
|
6512
6882
|
ov.sig = ovSig
|
|
6513
|
-
ov.active = camActiveNow || !!trOut
|
|
6883
|
+
ov.active = camActiveNow || !!trOut || pqLive
|
|
6514
6884
|
if (ov.texture) ov.texture.needsUpdate = true
|
|
6515
6885
|
}
|
|
6516
6886
|
|
|
@@ -6604,7 +6974,7 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
6604
6974
|
window.__voilaDebug = { cv: cv, bgCv: bg.canvas, ovCv: ov.canvas, W: W, H: H, glW: gl && gl.width, glH: gl && gl.height, t: t, canvases: document.querySelectorAll('canvas').length }
|
|
6605
6975
|
}
|
|
6606
6976
|
}`;
|
|
6607
|
-
function studioLayerData(layers, duration) {
|
|
6977
|
+
function studioLayerData(layers, duration, pins) {
|
|
6608
6978
|
const rec = "source" in layers ? layers : null;
|
|
6609
6979
|
return {
|
|
6610
6980
|
// Music/SFX clips with their gain envelopes baked (shared truth for the
|
|
@@ -6613,14 +6983,14 @@ function studioLayerData(layers, duration) {
|
|
|
6613
6983
|
// needs a decoded recording, which a sync lowering can't produce.
|
|
6614
6984
|
audio: (layers.audio ?? []).map((c) => ({
|
|
6615
6985
|
key: c.key,
|
|
6616
|
-
start:
|
|
6617
|
-
in:
|
|
6618
|
-
out:
|
|
6619
|
-
gain:
|
|
6986
|
+
start: round7(c.start),
|
|
6987
|
+
in: round7(c.in),
|
|
6988
|
+
out: round7(c.out),
|
|
6989
|
+
gain: round7(c.gain),
|
|
6620
6990
|
loop: !!c.loop,
|
|
6621
|
-
len:
|
|
6991
|
+
len: round7(clipLength(c)),
|
|
6622
6992
|
duck: !!c.duck,
|
|
6623
|
-
env: clipEnvelope(c).map((p) => ({ t:
|
|
6993
|
+
env: clipEnvelope(c).map((p) => ({ t: round7(p.t), g: round7(p.g) }))
|
|
6624
6994
|
})),
|
|
6625
6995
|
// Object clips: numbers resolved HERE; shapes are the drafted engine spec.
|
|
6626
6996
|
...layers.objects && layers.objects.length ? {
|
|
@@ -6633,17 +7003,17 @@ function studioLayerData(layers, duration) {
|
|
|
6633
7003
|
} : o.asset.kind === "text3d" ? resolveText3dAsset(o.asset) : { kind: "gltf", key: o.asset.key },
|
|
6634
7004
|
...o.span ? {
|
|
6635
7005
|
span: {
|
|
6636
|
-
start:
|
|
6637
|
-
duration:
|
|
7006
|
+
start: round7(o.span.start),
|
|
7007
|
+
duration: round7(o.span.duration)
|
|
6638
7008
|
}
|
|
6639
7009
|
} : {},
|
|
6640
|
-
x:
|
|
6641
|
-
y:
|
|
6642
|
-
z:
|
|
6643
|
-
rx:
|
|
6644
|
-
ry:
|
|
6645
|
-
rz:
|
|
6646
|
-
scale:
|
|
7010
|
+
x: round7(o.transform3d.x),
|
|
7011
|
+
y: round7(o.transform3d.y),
|
|
7012
|
+
z: round7(o.transform3d.z),
|
|
7013
|
+
rx: round7(o.transform3d.rx),
|
|
7014
|
+
ry: round7(o.transform3d.ry),
|
|
7015
|
+
rz: round7(o.transform3d.rz),
|
|
7016
|
+
scale: round7(o.transform3d.scale || OBJECT_DEFAULT_SCALE),
|
|
6647
7017
|
anim: idleKey(o),
|
|
6648
7018
|
// Pose keyframes: clip-local [x,y,z,rx,ry,rz,scale] track,
|
|
6649
7019
|
// sampled at t − span.start. Omitted when absent — parity.
|
|
@@ -6670,18 +7040,20 @@ function studioLayerData(layers, duration) {
|
|
|
6670
7040
|
const base = {
|
|
6671
7041
|
id: o.id,
|
|
6672
7042
|
kind: o.kind,
|
|
6673
|
-
start:
|
|
6674
|
-
dur:
|
|
6675
|
-
x:
|
|
6676
|
-
y:
|
|
6677
|
-
scale:
|
|
6678
|
-
rot:
|
|
7043
|
+
start: round7(o.start),
|
|
7044
|
+
dur: round7(Math.max(OVERLAY_MIN_DURATION, o.duration)),
|
|
7045
|
+
x: round7(o.transform.x),
|
|
7046
|
+
y: round7(o.transform.y),
|
|
7047
|
+
scale: round7(o.transform.scale || 1),
|
|
7048
|
+
rot: round7(o.transform.rotation || 0),
|
|
6679
7049
|
enter: enterKey(o),
|
|
6680
7050
|
exit: exitKey(o),
|
|
6681
7051
|
// Pose keyframes: a CLIP-LOCAL [x, y, scale, rot, opacity]
|
|
6682
7052
|
// track, sampled in ON_FRAME at t − start. Omitted when the clip
|
|
6683
7053
|
// has no motion — data byte parity.
|
|
6684
7054
|
...(() => {
|
|
7055
|
+
const pinned = pins?.get(o.id);
|
|
7056
|
+
if (pinned) return { track: pinned.track };
|
|
6685
7057
|
if (!o.motion || !o.motion.length) return {};
|
|
6686
7058
|
const mb = overlayMotionBase(o);
|
|
6687
7059
|
const track = motionTrack(
|
|
@@ -6698,10 +7070,10 @@ function studioLayerData(layers, duration) {
|
|
|
6698
7070
|
...base,
|
|
6699
7071
|
kind: "image",
|
|
6700
7072
|
key: hl.key,
|
|
6701
|
-
w:
|
|
7073
|
+
w: round7(hl.width),
|
|
6702
7074
|
radius: 0,
|
|
6703
7075
|
shadow: "none",
|
|
6704
|
-
opacity:
|
|
7076
|
+
opacity: round7(o.opacity ?? 1),
|
|
6705
7077
|
html: hl.html
|
|
6706
7078
|
};
|
|
6707
7079
|
}
|
|
@@ -6718,8 +7090,8 @@ function studioLayerData(layers, duration) {
|
|
|
6718
7090
|
...o.frame.browserBar?.theme ? { theme: o.frame.browserBar.theme } : {}
|
|
6719
7091
|
},
|
|
6720
7092
|
lean: [
|
|
6721
|
-
|
|
6722
|
-
|
|
7093
|
+
round7(o.frame.lean?.rx ?? 0),
|
|
7094
|
+
round7(o.frame.lean?.ry ?? 0)
|
|
6723
7095
|
],
|
|
6724
7096
|
shadow: o.frame.shadow ?? LAYER_CARD_SHADOW,
|
|
6725
7097
|
shadowContact: o.frame.shadowContact ?? 0,
|
|
@@ -6735,17 +7107,17 @@ function studioLayerData(layers, duration) {
|
|
|
6735
7107
|
for (const ev of lm.cursor) {
|
|
6736
7108
|
if (ev.type === "down")
|
|
6737
7109
|
clicks.push({
|
|
6738
|
-
t:
|
|
6739
|
-
x:
|
|
6740
|
-
y:
|
|
7110
|
+
t: round7(ev.t / 1e3),
|
|
7111
|
+
x: round7(ev.x),
|
|
7112
|
+
y: round7(ev.y)
|
|
6741
7113
|
});
|
|
6742
7114
|
}
|
|
6743
7115
|
return {
|
|
6744
7116
|
cur: {
|
|
6745
7117
|
pts: sm.map((p) => ({
|
|
6746
|
-
t:
|
|
6747
|
-
x:
|
|
6748
|
-
y:
|
|
7118
|
+
t: round7(p.t),
|
|
7119
|
+
x: round7(p.x),
|
|
7120
|
+
y: round7(p.y)
|
|
6749
7121
|
})),
|
|
6750
7122
|
space: { w: lm.meta.width, h: lm.meta.height },
|
|
6751
7123
|
size: rec.cursor.size,
|
|
@@ -6760,7 +7132,7 @@ function studioLayerData(layers, duration) {
|
|
|
6760
7132
|
...lm && lm.crop ? { crop: lm.crop } : {},
|
|
6761
7133
|
...lmCard ? { card: lmCard } : {},
|
|
6762
7134
|
...lmFacts,
|
|
6763
|
-
w:
|
|
7135
|
+
w: round7(o.width ?? OVERLAY_MEDIA_DEFAULT_WIDTH),
|
|
6764
7136
|
radius: o.radius ?? OVERLAY_MEDIA_DEFAULT_RADIUS,
|
|
6765
7137
|
opacity: o.opacity ?? 1,
|
|
6766
7138
|
loop: !!o.loop,
|
|
@@ -6770,7 +7142,7 @@ function studioLayerData(layers, duration) {
|
|
|
6770
7142
|
...o.shadow ? { shadow: o.shadow } : {},
|
|
6771
7143
|
...o.border && o.border.width > 0 ? {
|
|
6772
7144
|
border: {
|
|
6773
|
-
width:
|
|
7145
|
+
width: round7(o.border.width),
|
|
6774
7146
|
color: o.border.color
|
|
6775
7147
|
}
|
|
6776
7148
|
} : {}
|
|
@@ -6790,11 +7162,11 @@ function studioLayerData(layers, duration) {
|
|
|
6790
7162
|
// Style-v2 fields bake only when non-default (byte parity for
|
|
6791
7163
|
// older docs); ON_FRAME reads them unconditionally.
|
|
6792
7164
|
...st.fontStyle === "italic" ? { sty: "italic" } : {},
|
|
6793
|
-
...o.maxWidth ? { mw:
|
|
6794
|
-
...st.letterSpacing ? { ls:
|
|
6795
|
-
...st.lineHeight !== OVERLAY_LINE_HEIGHT ? { lh:
|
|
7165
|
+
...o.maxWidth ? { mw: round7(o.maxWidth) } : {},
|
|
7166
|
+
...st.letterSpacing ? { ls: round7(st.letterSpacing) } : {},
|
|
7167
|
+
...st.lineHeight !== OVERLAY_LINE_HEIGHT ? { lh: round7(st.lineHeight) } : {},
|
|
6796
7168
|
...st.align !== "center" ? { align: st.align } : {},
|
|
6797
|
-
...st.stroke ? { stroke: { c: st.stroke.color, w:
|
|
7169
|
+
...st.stroke ? { stroke: { c: st.stroke.color, w: round7(st.stroke.width) } } : {},
|
|
6798
7170
|
// Hosted face behind an override: ON_FRAME lazy-loads it so a
|
|
6799
7171
|
// live family/weight edit paints without a LOAD (SETUP only
|
|
6800
7172
|
// runs on cold load).
|
|
@@ -6807,10 +7179,10 @@ function studioLayerData(layers, duration) {
|
|
|
6807
7179
|
...bx ? {
|
|
6808
7180
|
box: {
|
|
6809
7181
|
c: bx.color,
|
|
6810
|
-
o:
|
|
6811
|
-
px:
|
|
6812
|
-
py:
|
|
6813
|
-
r:
|
|
7182
|
+
o: round7(bx.opacity),
|
|
7183
|
+
px: round7(bx.padX),
|
|
7184
|
+
py: round7(bx.padY),
|
|
7185
|
+
r: round7(bx.radius)
|
|
6814
7186
|
}
|
|
6815
7187
|
} : {},
|
|
6816
7188
|
// Entrance animation: segmentation + timing normalized
|
|
@@ -6844,36 +7216,22 @@ function lowerToComposition(input) {
|
|
|
6844
7216
|
sourceDuration: (doc.source.meta.durationMs || 0) / 1e3
|
|
6845
7217
|
}) : [];
|
|
6846
7218
|
const layout = docCardLayout(doc);
|
|
6847
|
-
const meta = doc.source.meta;
|
|
6848
7219
|
const zoomStyle = resolveZoomStyle(doc.zoomStyle, doc.zoomParams);
|
|
6849
7220
|
const camera = cameraModel(doc.frame);
|
|
6850
|
-
const zoomSpans =
|
|
6851
|
-
doc
|
|
7221
|
+
const zoomSpans = loweredZoomSpans(
|
|
7222
|
+
doc,
|
|
6852
7223
|
rated,
|
|
6853
7224
|
transitions,
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
recenter: zoomStyle.followRecenter,
|
|
6865
|
-
lookahead: zoomStyle.followLookahead,
|
|
6866
|
-
camera
|
|
6867
|
-
}
|
|
6868
|
-
);
|
|
6869
|
-
if (f.entry)
|
|
6870
|
-
return { ...z, cx: f.entry.cx, cy: f.entry.cy, followEvents: f.events };
|
|
6871
|
-
}
|
|
6872
|
-
return {
|
|
6873
|
-
...z,
|
|
6874
|
-
...clampFocus(z.cx, z.cy, clampZoomLevel(z.level), layout, camera)
|
|
6875
|
-
};
|
|
6876
|
-
});
|
|
7225
|
+
layout,
|
|
7226
|
+
camera,
|
|
7227
|
+
zoomStyle
|
|
7228
|
+
);
|
|
7229
|
+
const zoomTrack = prependEntrance(
|
|
7230
|
+
zoomTrackFromDoc(zoomSpans, rated, zoomStyle),
|
|
7231
|
+
entranceZoomKeyframes(cardEnter(doc.frame))
|
|
7232
|
+
);
|
|
7233
|
+
const pins = resolvePins(doc, layout, camera, zoomTrack);
|
|
7234
|
+
const pinsData = pinsDataOf(doc, pins);
|
|
6877
7235
|
const data = {
|
|
6878
7236
|
videoSrc: doc.source.videoKey,
|
|
6879
7237
|
isImage: doc.source.sourceKind === "image",
|
|
@@ -6896,17 +7254,17 @@ function lowerToComposition(input) {
|
|
|
6896
7254
|
// Rated segments (speed spans pre-intersected): ON_FRAME's mapTime and the
|
|
6897
7255
|
// export's audio splice read the rate straight off each segment.
|
|
6898
7256
|
segments: rated.map((seg) => ({
|
|
6899
|
-
in:
|
|
6900
|
-
out:
|
|
6901
|
-
...seg.rate !== void 0 && seg.rate !== 1 ? { rate:
|
|
7257
|
+
in: round7(seg.in),
|
|
7258
|
+
out: round7(seg.out),
|
|
7259
|
+
...seg.rate !== void 0 && seg.rate !== 1 ? { rate: round7(seg.rate) } : {},
|
|
6902
7260
|
...seg.media ? { media: seg.media } : {}
|
|
6903
7261
|
})),
|
|
6904
7262
|
frame: doc.frame,
|
|
6905
7263
|
micGain: doc.micGain ?? 1,
|
|
6906
7264
|
cursor: smoothed.map((p) => ({
|
|
6907
|
-
t:
|
|
6908
|
-
x:
|
|
6909
|
-
y:
|
|
7265
|
+
t: round7(p.t),
|
|
7266
|
+
x: round7(p.x),
|
|
7267
|
+
y: round7(p.y)
|
|
6910
7268
|
})),
|
|
6911
7269
|
cursorStyle: doc.cursor,
|
|
6912
7270
|
cursorSpace: { w: doc.source.meta.width, h: doc.source.meta.height },
|
|
@@ -6929,9 +7287,9 @@ function lowerToComposition(input) {
|
|
|
6929
7287
|
crop: m.crop ?? null,
|
|
6930
7288
|
hasAudio: !!m.meta.hasAudio,
|
|
6931
7289
|
cursor: sm.map((p) => ({
|
|
6932
|
-
t:
|
|
6933
|
-
x:
|
|
6934
|
-
y:
|
|
7290
|
+
t: round7(p.t),
|
|
7291
|
+
x: round7(p.x),
|
|
7292
|
+
y: round7(p.y)
|
|
6935
7293
|
})),
|
|
6936
7294
|
cursorSpace: { w: m.meta.width, h: m.meta.height },
|
|
6937
7295
|
// The card this media wears (its own placement, bar, corner,
|
|
@@ -6950,11 +7308,11 @@ function lowerToComposition(input) {
|
|
|
6950
7308
|
// intensities/colors become numbers HERE — ON_FRAME reads no registry).
|
|
6951
7309
|
...clickFxData(doc, rated),
|
|
6952
7310
|
// Rated segments so zoom spans land at their speed-adjusted output times.
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
7311
|
+
zoomTrack,
|
|
7312
|
+
// Pinned layers' marks and leaders: the referent (normalised video
|
|
7313
|
+
// fractions) plus the leader's tip track, painted by ON_FRAME beside the
|
|
7314
|
+
// camera. Absent when no pinned layer asks for either — byte parity.
|
|
7315
|
+
...pinsData.length ? { pins: pinsData } : {},
|
|
6958
7316
|
// Tilt spans: OUTPUT-time [rx, ry] degree track. The rest pose is
|
|
6959
7317
|
// FLAT — there is no static card tilt any more — and the motion constants
|
|
6960
7318
|
// come from the camera style's tilt personality ('drift' slows its
|
|
@@ -6987,7 +7345,7 @@ function lowerToComposition(input) {
|
|
|
6987
7345
|
};
|
|
6988
7346
|
const entryData = {
|
|
6989
7347
|
lights: true,
|
|
6990
|
-
...studioLayerData(doc, duration)
|
|
7348
|
+
...studioLayerData(doc, duration, pins)
|
|
6991
7349
|
};
|
|
6992
7350
|
const config = {
|
|
6993
7351
|
version: 2,
|
|
@@ -7013,6 +7371,128 @@ function lowerToComposition(input) {
|
|
|
7013
7371
|
};
|
|
7014
7372
|
return { config, data, stack: { [STUDIO_ENTRY_ID]: entryData }, duration };
|
|
7015
7373
|
}
|
|
7374
|
+
function loweredZoomSpans(doc, rated, transitions, layout, camera, zoomStyle) {
|
|
7375
|
+
const meta = doc.source.meta;
|
|
7376
|
+
return restSpansThroughTransitions(
|
|
7377
|
+
doc.zoom,
|
|
7378
|
+
rated,
|
|
7379
|
+
transitions,
|
|
7380
|
+
ZOOM_SPAN_MIN
|
|
7381
|
+
).map((z) => {
|
|
7382
|
+
if (z.focusMode === "auto") {
|
|
7383
|
+
const f = followFocusEvents(
|
|
7384
|
+
z,
|
|
7385
|
+
doc.source.cursor,
|
|
7386
|
+
{ w: meta.width, h: meta.height },
|
|
7387
|
+
layout,
|
|
7388
|
+
{
|
|
7389
|
+
safeRatio: zoomStyle.followSafeRatio,
|
|
7390
|
+
recenter: zoomStyle.followRecenter,
|
|
7391
|
+
lookahead: zoomStyle.followLookahead,
|
|
7392
|
+
camera
|
|
7393
|
+
}
|
|
7394
|
+
);
|
|
7395
|
+
if (f.entry)
|
|
7396
|
+
return { ...z, cx: f.entry.cx, cy: f.entry.cy, followEvents: f.events };
|
|
7397
|
+
}
|
|
7398
|
+
return {
|
|
7399
|
+
...z,
|
|
7400
|
+
...clampFocus(z.cx, z.cy, clampZoomLevel(z.level), layout, camera)
|
|
7401
|
+
};
|
|
7402
|
+
});
|
|
7403
|
+
}
|
|
7404
|
+
function docZoomTrack(input) {
|
|
7405
|
+
const doc = migrateMotion(input);
|
|
7406
|
+
const rated = ratedSegments(doc);
|
|
7407
|
+
const transitions = docTransitions(doc);
|
|
7408
|
+
const layout = docCardLayout(doc);
|
|
7409
|
+
const camera = cameraModel(doc.frame);
|
|
7410
|
+
const zoomStyle = resolveZoomStyle(doc.zoomStyle, doc.zoomParams);
|
|
7411
|
+
const spans = loweredZoomSpans(
|
|
7412
|
+
doc,
|
|
7413
|
+
rated,
|
|
7414
|
+
transitions,
|
|
7415
|
+
layout,
|
|
7416
|
+
camera,
|
|
7417
|
+
zoomStyle
|
|
7418
|
+
);
|
|
7419
|
+
return prependEntrance(
|
|
7420
|
+
zoomTrackFromDoc(spans, rated, zoomStyle),
|
|
7421
|
+
entranceZoomKeyframes(cardEnter(doc.frame))
|
|
7422
|
+
);
|
|
7423
|
+
}
|
|
7424
|
+
function resolvePins(doc, layout, camera, zoomTrack) {
|
|
7425
|
+
const out = /* @__PURE__ */ new Map();
|
|
7426
|
+
for (const o of doc.overlays ?? []) {
|
|
7427
|
+
if (!o.pin) continue;
|
|
7428
|
+
const ref = pinReferent(doc, o.pin);
|
|
7429
|
+
if (!ref) continue;
|
|
7430
|
+
const base = overlayMotionBase(o);
|
|
7431
|
+
const motion = o.motion && o.motion.length ? motionTrack(
|
|
7432
|
+
base,
|
|
7433
|
+
overlayMotionKeys(o, base),
|
|
7434
|
+
Math.max(OVERLAY_MIN_DURATION, o.duration)
|
|
7435
|
+
) : null;
|
|
7436
|
+
out.set(
|
|
7437
|
+
o.id,
|
|
7438
|
+
pinPlacement({
|
|
7439
|
+
clip: o,
|
|
7440
|
+
referent: ref.rect,
|
|
7441
|
+
layout,
|
|
7442
|
+
camera,
|
|
7443
|
+
zoomTrack,
|
|
7444
|
+
base,
|
|
7445
|
+
motion
|
|
7446
|
+
})
|
|
7447
|
+
);
|
|
7448
|
+
}
|
|
7449
|
+
return out;
|
|
7450
|
+
}
|
|
7451
|
+
function overlayPinPoseAt(doc, o, t) {
|
|
7452
|
+
if (!o.pin) return null;
|
|
7453
|
+
const layout = docCardLayout(doc);
|
|
7454
|
+
const camera = cameraModel(doc.frame);
|
|
7455
|
+
const pins = resolvePins(
|
|
7456
|
+
{ ...doc, overlays: [o] },
|
|
7457
|
+
layout,
|
|
7458
|
+
camera,
|
|
7459
|
+
docZoomTrack(doc)
|
|
7460
|
+
);
|
|
7461
|
+
const p = pins.get(o.id);
|
|
7462
|
+
if (!p) return null;
|
|
7463
|
+
return [...sample2(p.track, t, lerpArray2)];
|
|
7464
|
+
}
|
|
7465
|
+
function pinsDataOf(doc, pins) {
|
|
7466
|
+
const out = [];
|
|
7467
|
+
for (const o of doc.overlays ?? []) {
|
|
7468
|
+
const p = o.pin;
|
|
7469
|
+
const placed = p ? pins.get(o.id) : void 0;
|
|
7470
|
+
if (!p || !placed) continue;
|
|
7471
|
+
const mark = p.mark ?? "none";
|
|
7472
|
+
if (mark === "none" && !p.leader) continue;
|
|
7473
|
+
const ref = pinReferent(doc, p);
|
|
7474
|
+
if (!ref) continue;
|
|
7475
|
+
out.push({
|
|
7476
|
+
id: o.id,
|
|
7477
|
+
start: round7(o.start),
|
|
7478
|
+
dur: round7(Math.max(OVERLAY_MIN_DURATION, o.duration)),
|
|
7479
|
+
x: round43(ref.rect.x),
|
|
7480
|
+
y: round43(ref.rect.y),
|
|
7481
|
+
w: round43(ref.rect.w),
|
|
7482
|
+
h: round43(ref.rect.h),
|
|
7483
|
+
side: placed.side,
|
|
7484
|
+
mark,
|
|
7485
|
+
leader: !!p.leader,
|
|
7486
|
+
...p.color ? { color: p.color } : {},
|
|
7487
|
+
enter: enterKey(o),
|
|
7488
|
+
tip: placed.tip
|
|
7489
|
+
});
|
|
7490
|
+
}
|
|
7491
|
+
return out;
|
|
7492
|
+
}
|
|
7493
|
+
function round43(v) {
|
|
7494
|
+
return Math.round(v * 1e5) / 1e5;
|
|
7495
|
+
}
|
|
7016
7496
|
function clickFxData(doc, rated) {
|
|
7017
7497
|
const fx = doc.cursor.clickFx;
|
|
7018
7498
|
const on = fx.style !== "none" || fx.press;
|
|
@@ -7046,7 +7526,7 @@ function clickFxData(doc, rated) {
|
|
|
7046
7526
|
}
|
|
7047
7527
|
};
|
|
7048
7528
|
}
|
|
7049
|
-
function
|
|
7529
|
+
function round7(v) {
|
|
7050
7530
|
return Math.round(v * 1e3) / 1e3;
|
|
7051
7531
|
}
|
|
7052
7532
|
|
|
@@ -7136,8 +7616,8 @@ function planAutoSpeed(track, opts) {
|
|
|
7136
7616
|
accepted.sort((a, b) => a.in - b.in);
|
|
7137
7617
|
return accepted.map((c, i) => ({
|
|
7138
7618
|
id: `s${i}`,
|
|
7139
|
-
in:
|
|
7140
|
-
out:
|
|
7619
|
+
in: round8(c.in),
|
|
7620
|
+
out: round8(c.out),
|
|
7141
7621
|
rate: clampSpeedRate(c.rate),
|
|
7142
7622
|
source: "auto"
|
|
7143
7623
|
}));
|
|
@@ -7190,7 +7670,7 @@ function collectRuns(evs, gap, minLen, emit2) {
|
|
|
7190
7670
|
}
|
|
7191
7671
|
flush();
|
|
7192
7672
|
}
|
|
7193
|
-
function
|
|
7673
|
+
function round8(v) {
|
|
7194
7674
|
return Math.round(v * 1e3) / 1e3;
|
|
7195
7675
|
}
|
|
7196
7676
|
|
|
@@ -7371,16 +7851,16 @@ function momentsFromDoc(doc, plan, opts = {}) {
|
|
|
7371
7851
|
return {
|
|
7372
7852
|
id: `m${String(i + 1).padStart(2, "0")}`,
|
|
7373
7853
|
kind: d.kind,
|
|
7374
|
-
source: { in:
|
|
7375
|
-
output: output ? { in:
|
|
7376
|
-
at: d.at === null ? null :
|
|
7377
|
-
outputAt: outAt ?
|
|
7378
|
-
focus: d.focus ? { cx:
|
|
7854
|
+
source: { in: round9(d.in), out: round9(d.out) },
|
|
7855
|
+
output: output ? { in: round9(output.start), out: round9(output.end) } : null,
|
|
7856
|
+
at: d.at === null ? null : round9(d.at),
|
|
7857
|
+
outputAt: outAt ? round9(outAt.start) : null,
|
|
7858
|
+
focus: d.focus ? { cx: round9(d.focus.cx), cy: round9(d.focus.cy) } : null,
|
|
7379
7859
|
rect: d.rect ? {
|
|
7380
|
-
x:
|
|
7381
|
-
y:
|
|
7382
|
-
w:
|
|
7383
|
-
h:
|
|
7860
|
+
x: round9(d.rect.x),
|
|
7861
|
+
y: round9(d.rect.y),
|
|
7862
|
+
w: round9(d.rect.w),
|
|
7863
|
+
h: round9(d.rect.h)
|
|
7384
7864
|
} : null,
|
|
7385
7865
|
...d.clicks !== void 0 ? { clicks: d.clicks } : {},
|
|
7386
7866
|
...d.surface ? { surface: true } : {},
|
|
@@ -7401,7 +7881,7 @@ function activityOf(bins, d) {
|
|
|
7401
7881
|
sum += bins[i];
|
|
7402
7882
|
n++;
|
|
7403
7883
|
}
|
|
7404
|
-
return n ?
|
|
7884
|
+
return n ? round9(sum / n) : null;
|
|
7405
7885
|
}
|
|
7406
7886
|
function saidOver(transcript, d) {
|
|
7407
7887
|
if (!transcript?.length) return null;
|
|
@@ -7410,7 +7890,7 @@ function saidOver(transcript, d) {
|
|
|
7410
7890
|
const text = transcript.filter((s) => s.start < hi && s.end > lo).map((s) => s.text.trim()).filter(Boolean).join(" ");
|
|
7411
7891
|
return text || null;
|
|
7412
7892
|
}
|
|
7413
|
-
function
|
|
7893
|
+
function round9(v) {
|
|
7414
7894
|
return Math.round(v * 1e3) / 1e3;
|
|
7415
7895
|
}
|
|
7416
7896
|
|
|
@@ -7904,8 +8384,8 @@ function buildDigest(input) {
|
|
|
7904
8384
|
return {
|
|
7905
8385
|
digestVersion: DIGEST_VERSION,
|
|
7906
8386
|
take: {
|
|
7907
|
-
sourceDuration:
|
|
7908
|
-
outputDuration:
|
|
8387
|
+
sourceDuration: round10(meta.durationMs / 1e3),
|
|
8388
|
+
outputDuration: round10(input.outputDuration),
|
|
7909
8389
|
width: meta.width,
|
|
7910
8390
|
height: meta.height,
|
|
7911
8391
|
captureWidth: meta.captureWidth ?? null,
|
|
@@ -7954,7 +8434,7 @@ function buildDigest(input) {
|
|
|
7954
8434
|
function outputDurationOf(doc) {
|
|
7955
8435
|
return docOutputDuration(doc);
|
|
7956
8436
|
}
|
|
7957
|
-
function
|
|
8437
|
+
function round10(v) {
|
|
7958
8438
|
return Math.round(v * 1e3) / 1e3;
|
|
7959
8439
|
}
|
|
7960
8440
|
|
|
@@ -7980,20 +8460,20 @@ function setSpeedInRange(spans, srcIn, srcOut, rate) {
|
|
|
7980
8460
|
continue;
|
|
7981
8461
|
}
|
|
7982
8462
|
if (srcIn - s.in >= MIN_REMAINDER)
|
|
7983
|
-
kept.push({ ...s, out:
|
|
8463
|
+
kept.push({ ...s, out: round11(srcIn), source: "manual" });
|
|
7984
8464
|
if (s.out - srcOut >= MIN_REMAINDER)
|
|
7985
8465
|
kept.push({
|
|
7986
8466
|
...s,
|
|
7987
8467
|
id: mintId(used),
|
|
7988
|
-
in:
|
|
8468
|
+
in: round11(srcOut),
|
|
7989
8469
|
source: "manual"
|
|
7990
8470
|
});
|
|
7991
8471
|
}
|
|
7992
8472
|
if (rate != null)
|
|
7993
8473
|
kept.push({
|
|
7994
8474
|
id: mintId(used),
|
|
7995
|
-
in:
|
|
7996
|
-
out:
|
|
8475
|
+
in: round11(srcIn),
|
|
8476
|
+
out: round11(srcOut),
|
|
7997
8477
|
rate: clampSpeedRate(rate),
|
|
7998
8478
|
source: "manual"
|
|
7999
8479
|
});
|
|
@@ -8009,9 +8489,9 @@ function removeSourceRange(segments, srcIn, srcOut) {
|
|
|
8009
8489
|
next.push(seg);
|
|
8010
8490
|
continue;
|
|
8011
8491
|
}
|
|
8012
|
-
if (srcIn - seg.in >= MIN_SEGMENT) next.push({ ...seg, out:
|
|
8492
|
+
if (srcIn - seg.in >= MIN_SEGMENT) next.push({ ...seg, out: round11(srcIn) });
|
|
8013
8493
|
if (seg.out - srcOut >= MIN_SEGMENT)
|
|
8014
|
-
next.push({ ...seg, in:
|
|
8494
|
+
next.push({ ...seg, in: round11(srcOut) });
|
|
8015
8495
|
}
|
|
8016
8496
|
return next.length ? next : [...segments];
|
|
8017
8497
|
}
|
|
@@ -8029,8 +8509,8 @@ function zoomSpanForRange(zoom, srcIn, srcOut) {
|
|
|
8029
8509
|
while (used.has(`u${n}`)) n++;
|
|
8030
8510
|
return {
|
|
8031
8511
|
id: `u${n}`,
|
|
8032
|
-
in:
|
|
8033
|
-
out:
|
|
8512
|
+
in: round11(start),
|
|
8513
|
+
out: round11(end),
|
|
8034
8514
|
level: DEFAULT_ZOOM_LEVEL,
|
|
8035
8515
|
cx: 0.5,
|
|
8036
8516
|
cy: 0.5,
|
|
@@ -8044,7 +8524,7 @@ function mintId(used) {
|
|
|
8044
8524
|
used.add(id);
|
|
8045
8525
|
return id;
|
|
8046
8526
|
}
|
|
8047
|
-
function
|
|
8527
|
+
function round11(v) {
|
|
8048
8528
|
return Math.round(v * 1e3) / 1e3;
|
|
8049
8529
|
}
|
|
8050
8530
|
|
|
@@ -8748,8 +9228,8 @@ var videoLane = {
|
|
|
8748
9228
|
return segments.map((s, i) => ({
|
|
8749
9229
|
id: `seg-${i}`,
|
|
8750
9230
|
kind: "clip",
|
|
8751
|
-
t:
|
|
8752
|
-
duration:
|
|
9231
|
+
t: round12(starts[i]),
|
|
9232
|
+
duration: round12(
|
|
8753
9233
|
outputLen(s, speeds, freezes, i === 0 || !contiguous(segments, i))
|
|
8754
9234
|
)
|
|
8755
9235
|
}));
|
|
@@ -8832,7 +9312,7 @@ var videoLane = {
|
|
|
8832
9312
|
if (local >= m.t - 1e-9 && local <= m.t + m.duration + 1e-9)
|
|
8833
9313
|
return null;
|
|
8834
9314
|
}
|
|
8835
|
-
const sourceT =
|
|
9315
|
+
const sourceT = round12(
|
|
8836
9316
|
mapTime2(segmentPieces(s, speeds, freezes, leading), local)
|
|
8837
9317
|
);
|
|
8838
9318
|
if (sourceT - s.in < 0.05 || s.out - sourceT < 0.05) return null;
|
|
@@ -8873,7 +9353,7 @@ var videoLane = {
|
|
|
8873
9353
|
n === 1 || !contiguous(segments, n - 1)
|
|
8874
9354
|
)
|
|
8875
9355
|
] : []
|
|
8876
|
-
].map(
|
|
9356
|
+
].map(round12);
|
|
8877
9357
|
}
|
|
8878
9358
|
};
|
|
8879
9359
|
function nextFreezeId(doc) {
|
|
@@ -8900,8 +9380,8 @@ var freezeLane = {
|
|
|
8900
9380
|
{
|
|
8901
9381
|
id: f.id,
|
|
8902
9382
|
kind: "clip",
|
|
8903
|
-
t:
|
|
8904
|
-
duration:
|
|
9383
|
+
t: round12(m.t),
|
|
9384
|
+
duration: round12(m.duration),
|
|
8905
9385
|
label: `${trimZeros(f.seconds)}s`
|
|
8906
9386
|
}
|
|
8907
9387
|
] : [];
|
|
@@ -8923,7 +9403,7 @@ var freezeLane = {
|
|
|
8923
9403
|
if (g.t >= m.t - 1e-9 && g.t <= m.t + m.duration + 1e-9) return null;
|
|
8924
9404
|
}
|
|
8925
9405
|
if (g.t > totalDuration7(rated) + 1e-9) return null;
|
|
8926
|
-
const srcT =
|
|
9406
|
+
const srcT = round12(mapTime2(rated, Math.max(0, g.t)));
|
|
8927
9407
|
if (!kept(srcT) || !clear(srcT)) return null;
|
|
8928
9408
|
const id = nextFreezeId(doc);
|
|
8929
9409
|
const mediaHere = mediaAtOutput(rated, Math.max(0, g.t));
|
|
@@ -8965,7 +9445,7 @@ var freezeLane = {
|
|
|
8965
9445
|
const marks = freezeOutputExtents(splitBySpeed4(segs, speeds), freezes);
|
|
8966
9446
|
const mine = marks.get(f.id);
|
|
8967
9447
|
const endOut = mine ? mine.t + mine.duration : null;
|
|
8968
|
-
const srcT =
|
|
9448
|
+
const srcT = round12(
|
|
8969
9449
|
Math.min(sourceDuration, mapTime2(base, Math.max(0, g.t)))
|
|
8970
9450
|
);
|
|
8971
9451
|
if (!kept(srcT) || !clear(srcT, f.id)) return null;
|
|
@@ -9025,8 +9505,8 @@ var zoomLane = {
|
|
|
9025
9505
|
{
|
|
9026
9506
|
id: z.id,
|
|
9027
9507
|
kind: "clip",
|
|
9028
|
-
t:
|
|
9029
|
-
duration:
|
|
9508
|
+
t: round12(ext.start),
|
|
9509
|
+
duration: round12(ext.end - ext.start),
|
|
9030
9510
|
label: `${z.level.toFixed(2)}\xD7`
|
|
9031
9511
|
}
|
|
9032
9512
|
];
|
|
@@ -9053,8 +9533,8 @@ var zoomLane = {
|
|
|
9053
9533
|
...d.zoom,
|
|
9054
9534
|
{
|
|
9055
9535
|
id,
|
|
9056
|
-
in:
|
|
9057
|
-
out:
|
|
9536
|
+
in: round12(srcT),
|
|
9537
|
+
out: round12(srcT + len),
|
|
9058
9538
|
level: DEFAULT_ZOOM_LEVEL,
|
|
9059
9539
|
cx,
|
|
9060
9540
|
cy,
|
|
@@ -9086,8 +9566,8 @@ var zoomLane = {
|
|
|
9086
9566
|
return (d) => {
|
|
9087
9567
|
const z = d.zoom.find((x) => x.id === g.id);
|
|
9088
9568
|
if (!z) return;
|
|
9089
|
-
z.in =
|
|
9090
|
-
z.out =
|
|
9569
|
+
z.in = round12(newIn);
|
|
9570
|
+
z.out = round12(newIn + len);
|
|
9091
9571
|
z.source = "manual";
|
|
9092
9572
|
d.zoom.sort((a, b) => a.in - b.in);
|
|
9093
9573
|
};
|
|
@@ -9116,8 +9596,8 @@ var zoomLane = {
|
|
|
9116
9596
|
return (d) => {
|
|
9117
9597
|
const z = d.zoom.find((x) => x.id === g.id);
|
|
9118
9598
|
if (!z) return;
|
|
9119
|
-
z.in =
|
|
9120
|
-
z.out =
|
|
9599
|
+
z.in = round12(next.in);
|
|
9600
|
+
z.out = round12(next.out);
|
|
9121
9601
|
z.source = "manual";
|
|
9122
9602
|
};
|
|
9123
9603
|
}
|
|
@@ -9139,8 +9619,8 @@ function cursorFocusAt(doc, srcT) {
|
|
|
9139
9619
|
if (Math.abs(e.t - ms) < Math.abs(best.t - ms)) best = e;
|
|
9140
9620
|
const clamp015 = (v) => Math.max(0, Math.min(1, v));
|
|
9141
9621
|
return {
|
|
9142
|
-
cx:
|
|
9143
|
-
cy:
|
|
9622
|
+
cx: round12(clamp015(best.x / width)),
|
|
9623
|
+
cy: round12(clamp015(best.y / height))
|
|
9144
9624
|
};
|
|
9145
9625
|
}
|
|
9146
9626
|
var tiltLane = {
|
|
@@ -9154,8 +9634,8 @@ var tiltLane = {
|
|
|
9154
9634
|
{
|
|
9155
9635
|
id: z.id,
|
|
9156
9636
|
kind: "clip",
|
|
9157
|
-
t:
|
|
9158
|
-
duration:
|
|
9637
|
+
t: round12(ext.start),
|
|
9638
|
+
duration: round12(ext.end - ext.start),
|
|
9159
9639
|
label: `${formatDeg(z.rx)}\xB0/${formatDeg(z.ry)}\xB0`
|
|
9160
9640
|
}
|
|
9161
9641
|
];
|
|
@@ -9181,8 +9661,8 @@ var tiltLane = {
|
|
|
9181
9661
|
...d.tilt ?? [],
|
|
9182
9662
|
{
|
|
9183
9663
|
id,
|
|
9184
|
-
in:
|
|
9185
|
-
out:
|
|
9664
|
+
in: round12(srcT),
|
|
9665
|
+
out: round12(srcT + len),
|
|
9186
9666
|
rx: DEFAULT_TILT_POSE.rx,
|
|
9187
9667
|
ry: DEFAULT_TILT_POSE.ry,
|
|
9188
9668
|
source: "manual",
|
|
@@ -9213,8 +9693,8 @@ var tiltLane = {
|
|
|
9213
9693
|
return (d) => {
|
|
9214
9694
|
const z = (d.tilt ?? []).find((x) => x.id === g.id);
|
|
9215
9695
|
if (!z || !d.tilt) return;
|
|
9216
|
-
z.in =
|
|
9217
|
-
z.out =
|
|
9696
|
+
z.in = round12(newIn);
|
|
9697
|
+
z.out = round12(newIn + len);
|
|
9218
9698
|
z.source = "manual";
|
|
9219
9699
|
d.tilt.sort((a, b) => a.in - b.in);
|
|
9220
9700
|
};
|
|
@@ -9243,8 +9723,8 @@ var tiltLane = {
|
|
|
9243
9723
|
return (d) => {
|
|
9244
9724
|
const z = (d.tilt ?? []).find((x) => x.id === g.id);
|
|
9245
9725
|
if (!z) return;
|
|
9246
|
-
z.in =
|
|
9247
|
-
z.out =
|
|
9726
|
+
z.in = round12(next.in);
|
|
9727
|
+
z.out = round12(next.out);
|
|
9248
9728
|
z.source = "manual";
|
|
9249
9729
|
};
|
|
9250
9730
|
}
|
|
@@ -9271,8 +9751,8 @@ var camMoveLane = {
|
|
|
9271
9751
|
{
|
|
9272
9752
|
id: z.id,
|
|
9273
9753
|
kind: "clip",
|
|
9274
|
-
t:
|
|
9275
|
-
duration:
|
|
9754
|
+
t: round12(ext.start),
|
|
9755
|
+
duration: round12(ext.end - ext.start),
|
|
9276
9756
|
label: z.size != null ? `${Math.round(z.size * 100)}%` : "Move"
|
|
9277
9757
|
}
|
|
9278
9758
|
];
|
|
@@ -9296,8 +9776,8 @@ var camMoveLane = {
|
|
|
9296
9776
|
...d.camMotion ?? [],
|
|
9297
9777
|
{
|
|
9298
9778
|
id,
|
|
9299
|
-
in:
|
|
9300
|
-
out:
|
|
9779
|
+
in: round12(srcT),
|
|
9780
|
+
out: round12(srcT + len),
|
|
9301
9781
|
...DEFAULT_CAM_POSE,
|
|
9302
9782
|
source: "manual"
|
|
9303
9783
|
}
|
|
@@ -9326,8 +9806,8 @@ var camMoveLane = {
|
|
|
9326
9806
|
return (d) => {
|
|
9327
9807
|
const z = (d.camMotion ?? []).find((x) => x.id === g.id);
|
|
9328
9808
|
if (!z || !d.camMotion) return;
|
|
9329
|
-
z.in =
|
|
9330
|
-
z.out =
|
|
9809
|
+
z.in = round12(newIn);
|
|
9810
|
+
z.out = round12(newIn + len);
|
|
9331
9811
|
z.source = "manual";
|
|
9332
9812
|
d.camMotion.sort((a, b) => a.in - b.in);
|
|
9333
9813
|
};
|
|
@@ -9356,8 +9836,8 @@ var camMoveLane = {
|
|
|
9356
9836
|
return (d) => {
|
|
9357
9837
|
const z = (d.camMotion ?? []).find((x) => x.id === g.id);
|
|
9358
9838
|
if (!z) return;
|
|
9359
|
-
z.in =
|
|
9360
|
-
z.out =
|
|
9839
|
+
z.in = round12(next.in);
|
|
9840
|
+
z.out = round12(next.out);
|
|
9361
9841
|
z.source = "manual";
|
|
9362
9842
|
};
|
|
9363
9843
|
}
|
|
@@ -9390,10 +9870,10 @@ var camLane = {
|
|
|
9390
9870
|
items.push({
|
|
9391
9871
|
id: `cam-${i}`,
|
|
9392
9872
|
kind: "clip",
|
|
9393
|
-
t:
|
|
9873
|
+
t: round12(
|
|
9394
9874
|
starts[i] + outputLen({ in: s.in, out: a }, speeds, freezes, leading)
|
|
9395
9875
|
),
|
|
9396
|
-
duration:
|
|
9876
|
+
duration: round12(
|
|
9397
9877
|
outputLen({ in: a, out: b }, speeds, freezes, a === s.in && leading)
|
|
9398
9878
|
)
|
|
9399
9879
|
});
|
|
@@ -9422,7 +9902,7 @@ var camLane = {
|
|
|
9422
9902
|
Math.max(first.in, last.out - span)
|
|
9423
9903
|
);
|
|
9424
9904
|
return (d) => {
|
|
9425
|
-
d.cam.window = { in:
|
|
9905
|
+
d.cam.window = { in: round12(newIn), out: round12(newIn + span) };
|
|
9426
9906
|
};
|
|
9427
9907
|
}
|
|
9428
9908
|
const overlapping = eff.map((s, i) => ({
|
|
@@ -9435,8 +9915,8 @@ var camLane = {
|
|
|
9435
9915
|
const next = g.edge === "start" ? { in: Math.min(sourceT, current.out - 0.05), out: current.out } : { in: current.in, out: Math.max(sourceT, current.in + 0.05) };
|
|
9436
9916
|
return (d) => {
|
|
9437
9917
|
d.cam.window = {
|
|
9438
|
-
in:
|
|
9439
|
-
out:
|
|
9918
|
+
in: round12(Math.max(0, next.in)),
|
|
9919
|
+
out: round12(Math.min(sourceDuration, next.out))
|
|
9440
9920
|
};
|
|
9441
9921
|
};
|
|
9442
9922
|
},
|
|
@@ -9456,8 +9936,8 @@ var micLane = {
|
|
|
9456
9936
|
return segments.map((s, i) => ({
|
|
9457
9937
|
id: `mic-${i}`,
|
|
9458
9938
|
kind: "clip",
|
|
9459
|
-
t:
|
|
9460
|
-
duration:
|
|
9939
|
+
t: round12(starts[i]),
|
|
9940
|
+
duration: round12(
|
|
9461
9941
|
outputLen(s, speeds, freezes, i === 0 || !contiguous(segments, i))
|
|
9462
9942
|
)
|
|
9463
9943
|
}));
|
|
@@ -9513,8 +9993,8 @@ var speedLane = {
|
|
|
9513
9993
|
{
|
|
9514
9994
|
id: sp.id,
|
|
9515
9995
|
kind: "clip",
|
|
9516
|
-
t:
|
|
9517
|
-
duration:
|
|
9996
|
+
t: round12(start),
|
|
9997
|
+
duration: round12(end - start),
|
|
9518
9998
|
label: `${sp.rate}\xD7`
|
|
9519
9999
|
}
|
|
9520
10000
|
];
|
|
@@ -9538,8 +10018,8 @@ var speedLane = {
|
|
|
9538
10018
|
...d.speed ?? [],
|
|
9539
10019
|
{
|
|
9540
10020
|
id,
|
|
9541
|
-
in:
|
|
9542
|
-
out:
|
|
10021
|
+
in: round12(srcT),
|
|
10022
|
+
out: round12(srcT + len),
|
|
9543
10023
|
rate: DEFAULT_SPEED_RATE,
|
|
9544
10024
|
source: "manual",
|
|
9545
10025
|
...mediaHere ? { media: mediaHere } : {}
|
|
@@ -9570,8 +10050,8 @@ var speedLane = {
|
|
|
9570
10050
|
return (d) => {
|
|
9571
10051
|
const s = d.speed?.find((x) => x.id === g.id);
|
|
9572
10052
|
if (!s) return;
|
|
9573
|
-
s.in =
|
|
9574
|
-
s.out =
|
|
10053
|
+
s.in = round12(newIn);
|
|
10054
|
+
s.out = round12(newIn + len);
|
|
9575
10055
|
s.source = "manual";
|
|
9576
10056
|
d.speed.sort((a, b) => a.in - b.in);
|
|
9577
10057
|
};
|
|
@@ -9600,8 +10080,8 @@ var speedLane = {
|
|
|
9600
10080
|
return (d) => {
|
|
9601
10081
|
const s = d.speed?.find((x) => x.id === g.id);
|
|
9602
10082
|
if (!s) return;
|
|
9603
|
-
s.in =
|
|
9604
|
-
s.out =
|
|
10083
|
+
s.in = round12(next.in);
|
|
10084
|
+
s.out = round12(next.out);
|
|
9605
10085
|
s.source = "manual";
|
|
9606
10086
|
};
|
|
9607
10087
|
}
|
|
@@ -9620,8 +10100,8 @@ var audioLane = {
|
|
|
9620
10100
|
return doc.audio.map((c) => ({
|
|
9621
10101
|
id: c.id,
|
|
9622
10102
|
kind: "clip",
|
|
9623
|
-
t:
|
|
9624
|
-
duration:
|
|
10103
|
+
t: round12(c.start),
|
|
10104
|
+
duration: round12(clipLength(c)),
|
|
9625
10105
|
label: c.name
|
|
9626
10106
|
}));
|
|
9627
10107
|
},
|
|
@@ -9632,7 +10112,7 @@ var audioLane = {
|
|
|
9632
10112
|
const start = Math.max(0, g.t);
|
|
9633
10113
|
return (d) => {
|
|
9634
10114
|
const c = d.audio.find((x) => x.id === g.id);
|
|
9635
|
-
if (c) c.start =
|
|
10115
|
+
if (c) c.start = round12(start);
|
|
9636
10116
|
};
|
|
9637
10117
|
}
|
|
9638
10118
|
if (g.type === "resize") {
|
|
@@ -9645,8 +10125,8 @@ var audioLane = {
|
|
|
9645
10125
|
return (d) => {
|
|
9646
10126
|
const c = d.audio.find((x) => x.id === g.id);
|
|
9647
10127
|
if (!c) return;
|
|
9648
|
-
c.start =
|
|
9649
|
-
c.loopLen =
|
|
10128
|
+
c.start = round12(newStart2);
|
|
10129
|
+
c.loopLen = round12(end - newStart2);
|
|
9650
10130
|
};
|
|
9651
10131
|
}
|
|
9652
10132
|
const delta = g.t - clip.start;
|
|
@@ -9655,22 +10135,22 @@ var audioLane = {
|
|
|
9655
10135
|
return (d) => {
|
|
9656
10136
|
const c = d.audio.find((x) => x.id === g.id);
|
|
9657
10137
|
if (!c) return;
|
|
9658
|
-
c.in =
|
|
9659
|
-
c.start =
|
|
10138
|
+
c.in = round12(newIn);
|
|
10139
|
+
c.start = round12(newStart);
|
|
9660
10140
|
};
|
|
9661
10141
|
}
|
|
9662
10142
|
if (clip.loop) {
|
|
9663
10143
|
const newLen = Math.max(0.1, g.t - clip.start);
|
|
9664
10144
|
return (d) => {
|
|
9665
10145
|
const c = d.audio.find((x) => x.id === g.id);
|
|
9666
|
-
if (c) c.loopLen =
|
|
10146
|
+
if (c) c.loopLen = round12(newLen);
|
|
9667
10147
|
};
|
|
9668
10148
|
}
|
|
9669
10149
|
const span = Math.max(0.05, g.t - clip.start);
|
|
9670
10150
|
const newOut = Math.min(clip.in + span, clip.duration);
|
|
9671
10151
|
return (d) => {
|
|
9672
10152
|
const c = d.audio.find((x) => x.id === g.id);
|
|
9673
|
-
if (c) c.out =
|
|
10153
|
+
if (c) c.out = round12(Math.max(c.in + 0.05, newOut));
|
|
9674
10154
|
};
|
|
9675
10155
|
}
|
|
9676
10156
|
if (g.type === "remove") {
|
|
@@ -9683,8 +10163,8 @@ var audioLane = {
|
|
|
9683
10163
|
},
|
|
9684
10164
|
magnets(doc) {
|
|
9685
10165
|
return doc.audio.flatMap((c) => [
|
|
9686
|
-
|
|
9687
|
-
|
|
10166
|
+
round12(c.start),
|
|
10167
|
+
round12(c.start + clipLength(c))
|
|
9688
10168
|
]);
|
|
9689
10169
|
}
|
|
9690
10170
|
};
|
|
@@ -9702,7 +10182,7 @@ function poseItems(clipId, start, duration, motion) {
|
|
|
9702
10182
|
return (motion ?? []).map((p, i) => ({
|
|
9703
10183
|
id: `${clipId}::k${i}`,
|
|
9704
10184
|
kind: "keyframe",
|
|
9705
|
-
t:
|
|
10185
|
+
t: round12(start + Math.min(Math.max(0, p.at), duration))
|
|
9706
10186
|
}));
|
|
9707
10187
|
}
|
|
9708
10188
|
var overlaysLane = {
|
|
@@ -9713,8 +10193,8 @@ var overlaysLane = {
|
|
|
9713
10193
|
{
|
|
9714
10194
|
id: o.id,
|
|
9715
10195
|
kind: "clip",
|
|
9716
|
-
t:
|
|
9717
|
-
duration:
|
|
10196
|
+
t: round12(o.start),
|
|
10197
|
+
duration: round12(o.duration),
|
|
9718
10198
|
label: o.kind === "text" ? o.text.split("\n")[0].slice(0, 24) || "Text" : o.kind === "html" ? htmlLayerLabel(o) : o.kind === "image" ? "Image" : "Video"
|
|
9719
10199
|
},
|
|
9720
10200
|
// Pose diamonds render after the clips, so they sit on top.
|
|
@@ -9734,7 +10214,7 @@ var overlaysLane = {
|
|
|
9734
10214
|
return (d) => {
|
|
9735
10215
|
const o = (d.overlays ?? []).find((x) => x.id === kf.clipId);
|
|
9736
10216
|
const p = o?.motion?.[kf.index];
|
|
9737
|
-
if (p) p.at =
|
|
10217
|
+
if (p) p.at = round12(at);
|
|
9738
10218
|
};
|
|
9739
10219
|
}
|
|
9740
10220
|
if (g.type === "remove") {
|
|
@@ -9763,8 +10243,8 @@ var overlaysLane = {
|
|
|
9763
10243
|
{
|
|
9764
10244
|
id,
|
|
9765
10245
|
kind: "text",
|
|
9766
|
-
start:
|
|
9767
|
-
duration:
|
|
10246
|
+
start: round12(start),
|
|
10247
|
+
duration: round12(len),
|
|
9768
10248
|
text: "Title",
|
|
9769
10249
|
preset: "title",
|
|
9770
10250
|
// Frame fractions: centered, lower-third — at any aspect ratio.
|
|
@@ -9779,7 +10259,7 @@ var overlaysLane = {
|
|
|
9779
10259
|
const start = Math.max(0, g.t);
|
|
9780
10260
|
return (d) => {
|
|
9781
10261
|
const o = (d.overlays ?? []).find((x) => x.id === g.id);
|
|
9782
|
-
if (o) o.start =
|
|
10262
|
+
if (o) o.start = round12(start);
|
|
9783
10263
|
};
|
|
9784
10264
|
}
|
|
9785
10265
|
if (g.type === "resize") {
|
|
@@ -9789,14 +10269,14 @@ var overlaysLane = {
|
|
|
9789
10269
|
return (d) => {
|
|
9790
10270
|
const o = (d.overlays ?? []).find((x) => x.id === g.id);
|
|
9791
10271
|
if (!o) return;
|
|
9792
|
-
o.start =
|
|
9793
|
-
o.duration =
|
|
10272
|
+
o.start = round12(newStart);
|
|
10273
|
+
o.duration = round12(end - newStart);
|
|
9794
10274
|
};
|
|
9795
10275
|
}
|
|
9796
10276
|
const newLen = Math.max(OVERLAY_MIN_DURATION, g.t - clip.start);
|
|
9797
10277
|
return (d) => {
|
|
9798
10278
|
const o = (d.overlays ?? []).find((x) => x.id === g.id);
|
|
9799
|
-
if (o) o.duration =
|
|
10279
|
+
if (o) o.duration = round12(newLen);
|
|
9800
10280
|
};
|
|
9801
10281
|
}
|
|
9802
10282
|
return (d) => {
|
|
@@ -9805,8 +10285,8 @@ var overlaysLane = {
|
|
|
9805
10285
|
},
|
|
9806
10286
|
magnets(doc) {
|
|
9807
10287
|
return (doc.overlays ?? []).flatMap((o) => [
|
|
9808
|
-
|
|
9809
|
-
|
|
10288
|
+
round12(o.start),
|
|
10289
|
+
round12(o.start + o.duration)
|
|
9810
10290
|
]);
|
|
9811
10291
|
}
|
|
9812
10292
|
};
|
|
@@ -9819,8 +10299,8 @@ var objectsLane = {
|
|
|
9819
10299
|
{
|
|
9820
10300
|
id: o.id,
|
|
9821
10301
|
kind: "clip",
|
|
9822
|
-
t:
|
|
9823
|
-
duration:
|
|
10302
|
+
t: round12(o.span?.start ?? 0),
|
|
10303
|
+
duration: round12(o.span?.duration ?? outDur),
|
|
9824
10304
|
label: o.asset.kind === "primitive" ? o.asset.shape : o.asset.kind === "text3d" ? o.asset.text : "model"
|
|
9825
10305
|
},
|
|
9826
10306
|
// Pose diamonds: clip-local `at` from the span start (0 span-less).
|
|
@@ -9848,7 +10328,7 @@ var objectsLane = {
|
|
|
9848
10328
|
return (d) => {
|
|
9849
10329
|
const o = (d.objects ?? []).find((x) => x.id === kf.clipId);
|
|
9850
10330
|
const p = o?.motion?.[kf.index];
|
|
9851
|
-
if (p) p.at =
|
|
10331
|
+
if (p) p.at = round12(at);
|
|
9852
10332
|
};
|
|
9853
10333
|
}
|
|
9854
10334
|
if (g.type === "remove") {
|
|
@@ -9869,7 +10349,7 @@ var objectsLane = {
|
|
|
9869
10349
|
const start = Math.max(0, g.t);
|
|
9870
10350
|
return (d) => {
|
|
9871
10351
|
const o = (d.objects ?? []).find((x) => x.id === g.id);
|
|
9872
|
-
if (o?.span) o.span.start =
|
|
10352
|
+
if (o?.span) o.span.start = round12(start);
|
|
9873
10353
|
};
|
|
9874
10354
|
}
|
|
9875
10355
|
if (g.type === "resize") {
|
|
@@ -9880,14 +10360,14 @@ var objectsLane = {
|
|
|
9880
10360
|
return (d) => {
|
|
9881
10361
|
const o = (d.objects ?? []).find((x) => x.id === g.id);
|
|
9882
10362
|
if (!o?.span) return;
|
|
9883
|
-
o.span.start =
|
|
9884
|
-
o.span.duration =
|
|
10363
|
+
o.span.start = round12(newStart);
|
|
10364
|
+
o.span.duration = round12(end - newStart);
|
|
9885
10365
|
};
|
|
9886
10366
|
}
|
|
9887
10367
|
const newLen = Math.max(OVERLAY_MIN_DURATION, g.t - clip.span.start);
|
|
9888
10368
|
return (d) => {
|
|
9889
10369
|
const o = (d.objects ?? []).find((x) => x.id === g.id);
|
|
9890
|
-
if (o?.span) o.span.duration =
|
|
10370
|
+
if (o?.span) o.span.duration = round12(newLen);
|
|
9891
10371
|
};
|
|
9892
10372
|
}
|
|
9893
10373
|
return (d) => {
|
|
@@ -9896,7 +10376,7 @@ var objectsLane = {
|
|
|
9896
10376
|
},
|
|
9897
10377
|
magnets(doc) {
|
|
9898
10378
|
return (doc.objects ?? []).flatMap(
|
|
9899
|
-
(o) => o.span ? [
|
|
10379
|
+
(o) => o.span ? [round12(o.span.start), round12(o.span.start + o.span.duration)] : []
|
|
9900
10380
|
);
|
|
9901
10381
|
}
|
|
9902
10382
|
};
|
|
@@ -9923,7 +10403,7 @@ function nextSpeedId(doc) {
|
|
|
9923
10403
|
function segIndex(id) {
|
|
9924
10404
|
return Number(id.replace("seg-", ""));
|
|
9925
10405
|
}
|
|
9926
|
-
function
|
|
10406
|
+
function round12(v) {
|
|
9927
10407
|
return Math.round(v * 1e3) / 1e3;
|
|
9928
10408
|
}
|
|
9929
10409
|
|
|
@@ -10164,6 +10644,8 @@ export {
|
|
|
10164
10644
|
OVERLAY_SIZE_MIN,
|
|
10165
10645
|
OVERLAY_TRANSITION_DUR,
|
|
10166
10646
|
OVERLAY_Z,
|
|
10647
|
+
PIN_GAP,
|
|
10648
|
+
PIN_MARGIN,
|
|
10167
10649
|
PLATE_GROUND,
|
|
10168
10650
|
PLAYBACK_ACTIVITY,
|
|
10169
10651
|
PRIMARY_MEDIA,
|
|
@@ -10272,6 +10754,7 @@ export {
|
|
|
10272
10754
|
docToCropSpace,
|
|
10273
10755
|
docToFullSpace,
|
|
10274
10756
|
docTransitions,
|
|
10757
|
+
docZoomTrack,
|
|
10275
10758
|
dragsFromTrack,
|
|
10276
10759
|
dropTemplate,
|
|
10277
10760
|
duckCurve,
|
|
@@ -10289,6 +10772,7 @@ export {
|
|
|
10289
10772
|
expectedFrameSize,
|
|
10290
10773
|
exportSizeFor,
|
|
10291
10774
|
extractClicks,
|
|
10775
|
+
findStep,
|
|
10292
10776
|
focusBounds,
|
|
10293
10777
|
focusForViewportCentre,
|
|
10294
10778
|
followFocusEvents,
|
|
@@ -10360,12 +10844,17 @@ export {
|
|
|
10360
10844
|
overlayLines,
|
|
10361
10845
|
overlayMotionBase,
|
|
10362
10846
|
overlayMotionPoseAt,
|
|
10847
|
+
overlayPinPoseAt,
|
|
10363
10848
|
overlayRect,
|
|
10364
10849
|
overlaysLane,
|
|
10365
10850
|
ownFreezes,
|
|
10366
10851
|
pageDisplayUrl,
|
|
10367
10852
|
parsePoseId,
|
|
10368
10853
|
pickStyle,
|
|
10854
|
+
pinBox,
|
|
10855
|
+
pinPlacement,
|
|
10856
|
+
pinRectOnScreen,
|
|
10857
|
+
pinReferent,
|
|
10369
10858
|
placeFreezes,
|
|
10370
10859
|
planAutoSpeed,
|
|
10371
10860
|
planAutoTilt,
|
|
@@ -10384,6 +10873,7 @@ export {
|
|
|
10384
10873
|
resolveExportSize,
|
|
10385
10874
|
resolveOverlayBox,
|
|
10386
10875
|
resolveOverlayStyle,
|
|
10876
|
+
resolvePins,
|
|
10387
10877
|
resolveText3dAsset,
|
|
10388
10878
|
resolveZoomStyle,
|
|
10389
10879
|
restLeanOf,
|