@vosjs/studio-core 0.12.0 → 0.13.1
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 +6 -4
- package/dist/index.js +230 -180
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -571,7 +571,7 @@ function entranceSeconds(e) {
|
|
|
571
571
|
function exitSeconds(e) {
|
|
572
572
|
if (!e || e.kind === "none") return 0;
|
|
573
573
|
const house = e.kind === "fade" ? CARD_FADE_SECONDS : END_CARD_RECEDE;
|
|
574
|
-
return Math.max(0.1, Math.min(
|
|
574
|
+
return Math.max(0.1, Math.min(8, e.seconds ?? house));
|
|
575
575
|
}
|
|
576
576
|
function placeFreezes(rated, freezes) {
|
|
577
577
|
const marks = /* @__PURE__ */ new Map();
|
|
@@ -663,8 +663,9 @@ function prependEntrance(track, head) {
|
|
|
663
663
|
return { keyframes: sortKeyframes([...head, ...rest]) };
|
|
664
664
|
}
|
|
665
665
|
function exitPose(e) {
|
|
666
|
-
return e?.kind === "fade" ? [1, 0, 0] : [0.9, -0.02, 0
|
|
666
|
+
return e?.kind === "fade" ? [1, 0, 0] : [0.9, -0.02, 0];
|
|
667
667
|
}
|
|
668
|
+
var RECEDE_MID = [0.91, -0.018, 0.8];
|
|
668
669
|
function cardPoseTrack(enter, exit, footageEnd, outputEnd2 = footageEnd) {
|
|
669
670
|
const keyframes = [];
|
|
670
671
|
const s = entranceSeconds(enter);
|
|
@@ -674,16 +675,36 @@ function cardPoseTrack(enter, exit, footageEnd, outputEnd2 = footageEnd) {
|
|
|
674
675
|
keyframes.push({ t: s, value: [1, 0, 1], ease: "power3.out" });
|
|
675
676
|
}
|
|
676
677
|
const x = exitSeconds(exit);
|
|
678
|
+
let last = [1, 0, 1];
|
|
677
679
|
if (x > 0 && footageEnd > 0) {
|
|
678
|
-
const
|
|
679
|
-
const
|
|
680
|
-
|
|
680
|
+
const t0 = round3(Math.max(s, footageEnd - x));
|
|
681
|
+
const t1 = round3(Math.max(t0 + 0.05, footageEnd));
|
|
682
|
+
last = exitPose(exit);
|
|
681
683
|
keyframes.push({ t: t0, value: [1, 0, 1], ease: "none" });
|
|
682
|
-
|
|
684
|
+
if (exit?.kind !== "fade") {
|
|
685
|
+
keyframes.push({
|
|
686
|
+
t: round3(t0 + (t1 - t0) * 0.45),
|
|
687
|
+
value: [...RECEDE_MID],
|
|
688
|
+
ease: "power2.out"
|
|
689
|
+
});
|
|
690
|
+
keyframes.push({ t: t1, value: last, ease: "power1.in" });
|
|
691
|
+
} else {
|
|
692
|
+
keyframes.push({ t: t1, value: last, ease: "power2.out" });
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
if (outputEnd2 > footageEnd + 1e-6 && footageEnd > 0) {
|
|
696
|
+
if (!keyframes.some((k) => Math.abs(k.t - footageEnd) < 1e-9))
|
|
697
|
+
keyframes.push({ t: footageEnd, value: [...last], ease: "none" });
|
|
698
|
+
keyframes.push({
|
|
699
|
+
t: round3(footageEnd + 1e-3),
|
|
700
|
+
value: [last[0], last[1], 0],
|
|
701
|
+
ease: "none"
|
|
702
|
+
});
|
|
683
703
|
}
|
|
684
704
|
if (!keyframes.length) return void 0;
|
|
685
705
|
return { keyframes: sortKeyframes(keyframes) };
|
|
686
706
|
}
|
|
707
|
+
var round3 = (v) => Math.round(v * 1e3) / 1e3;
|
|
687
708
|
function endCardClips(card, doc, endStart) {
|
|
688
709
|
const seconds = Math.max(1, Math.min(8, card.seconds ?? END_CARD_SECONDS));
|
|
689
710
|
const anim = { enter: "rise", exit: "none" };
|
|
@@ -822,18 +843,25 @@ function migrateMotion(doc) {
|
|
|
822
843
|
const card = doc.endCard;
|
|
823
844
|
if (card && segments.length) {
|
|
824
845
|
const seconds = Math.max(1, Math.min(8, card.seconds ?? END_CARD_SECONDS));
|
|
846
|
+
const segsNow = out.segments ?? segments;
|
|
847
|
+
const lastSeg = segsNow.at(-1);
|
|
848
|
+
const freezesNow = docFreezes({ segments: segsNow, freeze: out.freeze });
|
|
825
849
|
const rated = withFreezes(
|
|
826
|
-
splitBySpeed(
|
|
827
|
-
|
|
850
|
+
splitBySpeed(segsNow, doc.speed ?? []),
|
|
851
|
+
freezesNow
|
|
828
852
|
);
|
|
829
853
|
const endStart = totalDuration(rated);
|
|
854
|
+
const taken = new Set(freezesNow.map((f) => f.id));
|
|
855
|
+
let n = 0;
|
|
856
|
+
while (taken.has(`f${n}`)) n++;
|
|
857
|
+
out.freeze = [
|
|
858
|
+
...freezesNow,
|
|
859
|
+
{ id: `f${n}`, at: lastSeg.out, seconds, from: END_CARD_FROM }
|
|
860
|
+
].sort((a, b) => a.at - b.at);
|
|
830
861
|
nextOverlays = [...nextOverlays, ...endCardClips(card, doc, endStart)];
|
|
831
862
|
nextFrame.anim = {
|
|
832
863
|
...nextFrame.anim ?? {},
|
|
833
|
-
exit: {
|
|
834
|
-
kind: "recede",
|
|
835
|
-
seconds: Math.min(END_CARD_RECEDE, seconds * 0.4)
|
|
836
|
-
}
|
|
864
|
+
exit: { kind: "recede", seconds }
|
|
837
865
|
};
|
|
838
866
|
}
|
|
839
867
|
delete out.endCard;
|
|
@@ -1910,14 +1938,14 @@ function resolveOverlayFx(clip, clipDuration) {
|
|
|
1910
1938
|
const maxTotal = Math.max(dur, clipDuration * 0.9);
|
|
1911
1939
|
st = Math.min(st, Math.max(0, (maxTotal - dur) / (upperN - 1)));
|
|
1912
1940
|
}
|
|
1913
|
-
const
|
|
1941
|
+
const round12 = (v) => Math.round(v * 1e4) / 1e4;
|
|
1914
1942
|
return {
|
|
1915
1943
|
k: spec.fx,
|
|
1916
1944
|
u: unit,
|
|
1917
1945
|
d: FX_DIR[spec.direction ?? "forward"] ?? 0,
|
|
1918
|
-
st:
|
|
1919
|
-
dur:
|
|
1920
|
-
tt:
|
|
1946
|
+
st: round12(st),
|
|
1947
|
+
dur: round12(dur),
|
|
1948
|
+
tt: round12(st * (upperN - 1) + dur),
|
|
1921
1949
|
units,
|
|
1922
1950
|
n
|
|
1923
1951
|
};
|
|
@@ -2132,7 +2160,7 @@ var CURSOR_IDLE_HOLD = 1;
|
|
|
2132
2160
|
var CURSOR_IDLE_FADE_OUT = 0.35;
|
|
2133
2161
|
var CURSOR_IDLE_FADE_IN = 0.18;
|
|
2134
2162
|
var CURSOR_IDLE_EPS_FRAC = 25e-4;
|
|
2135
|
-
var
|
|
2163
|
+
var round4 = (n) => Math.round(n * 1e3) / 1e3;
|
|
2136
2164
|
function cursorIdleFade(track, o) {
|
|
2137
2165
|
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 }));
|
|
2138
2166
|
if (moves.length === 0) return [];
|
|
@@ -2184,7 +2212,7 @@ function emit(keys, s, e) {
|
|
|
2184
2212
|
push(keys, e + CURSOR_IDLE_FADE_IN, 1);
|
|
2185
2213
|
}
|
|
2186
2214
|
function push(keys, t, a) {
|
|
2187
|
-
const rt =
|
|
2215
|
+
const rt = round4(t);
|
|
2188
2216
|
if (keys.length > 0 && rt <= keys[keys.length - 1].t) {
|
|
2189
2217
|
keys[keys.length - 1].a = a;
|
|
2190
2218
|
return;
|
|
@@ -3242,7 +3270,7 @@ function gatedRect(rect, x, y, space) {
|
|
|
3242
3270
|
return null;
|
|
3243
3271
|
const m = RECT_CONTAIN_MARGIN;
|
|
3244
3272
|
const inside = x >= rect.x - m && x <= rect.x + rect.w + m && y >= rect.y - m && y <= rect.y + rect.h + m;
|
|
3245
|
-
return inside ? [
|
|
3273
|
+
return inside ? [round5(rect.x), round5(rect.y), round5(rect.w), round5(rect.h)] : null;
|
|
3246
3274
|
}
|
|
3247
3275
|
function extractClicks(track, segments, opts) {
|
|
3248
3276
|
const out = [];
|
|
@@ -3267,11 +3295,11 @@ function extractClicks(track, segments, opts) {
|
|
|
3267
3295
|
const upSrc = st + Math.max(pressLen, 0.02);
|
|
3268
3296
|
const up = keptOutputEnd(segments, st, upSrc) ?? ot + CLICK_SYNTH_RELEASE;
|
|
3269
3297
|
const click = {
|
|
3270
|
-
ot:
|
|
3271
|
-
up:
|
|
3272
|
-
st:
|
|
3273
|
-
x:
|
|
3274
|
-
y:
|
|
3298
|
+
ot: round5(ot),
|
|
3299
|
+
up: round5(Math.max(up, ot + 0.02)),
|
|
3300
|
+
st: round5(st),
|
|
3301
|
+
x: round5(e.x),
|
|
3302
|
+
y: round5(e.y),
|
|
3275
3303
|
b: button
|
|
3276
3304
|
};
|
|
3277
3305
|
if (opts.rects && e.rect) {
|
|
@@ -3290,7 +3318,7 @@ function hexToRgbTriplet(hex) {
|
|
|
3290
3318
|
const n = parseInt(h, 16);
|
|
3291
3319
|
return [n >> 16, n >> 8 & 255, n & 255];
|
|
3292
3320
|
}
|
|
3293
|
-
function
|
|
3321
|
+
function round5(v) {
|
|
3294
3322
|
return Math.round(v * 1e3) / 1e3;
|
|
3295
3323
|
}
|
|
3296
3324
|
|
|
@@ -3353,7 +3381,7 @@ function trackEmitter() {
|
|
|
3353
3381
|
if (tt <= prev.t + 1e-6 && sameVec(prev.value, value)) return prev.t;
|
|
3354
3382
|
if (tt <= prev.t + 1e-6) tt = prev.t + 1e-3;
|
|
3355
3383
|
}
|
|
3356
|
-
keyframes.push({ t:
|
|
3384
|
+
keyframes.push({ t: round6(tt), value: value.map(round6), ease });
|
|
3357
3385
|
return tt;
|
|
3358
3386
|
};
|
|
3359
3387
|
return { keyframes, push: push2 };
|
|
@@ -4444,13 +4472,16 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
4444
4472
|
// corners, drawn by the clip alone, hid theirs inside the arc.
|
|
4445
4473
|
var shD = ceZs * (cardW + cardH) + 2 * (W + H)
|
|
4446
4474
|
var shX = cardX - shD / ceZs
|
|
4447
|
-
// The card shadow is LAYERED:
|
|
4448
|
-
// while each stays at a low alpha (shadow is the strength they share)
|
|
4449
|
-
//
|
|
4450
|
-
//
|
|
4451
|
-
// a
|
|
4475
|
+
// The card shadow is LAYERED: four shadows whose blur and offset grow
|
|
4476
|
+
// while each stays at a low alpha (shadow is the strength they share):
|
|
4477
|
+
// a hairline that defines the edge, two that ground it, and a WIDE,
|
|
4478
|
+
// faint ambient bloom (120 design px of blur, dropped well below the
|
|
4479
|
+
// card) that is what lets a large card read as lifted off a light
|
|
4480
|
+
// ground instead of outlined on it. One wide layer at the full strength
|
|
4481
|
+
// was the old paint, and at the default 0.4 it read as a dark pool
|
|
4482
|
+
// under the card; three tight layers read as a rim.
|
|
4452
4483
|
if (shadow > 0) {
|
|
4453
|
-
var shL = [[
|
|
4484
|
+
var shL = [[2, 1, 0.1], [12, 4, 0.1], [40, 16, 0.14], [120, 44, 0.3]]
|
|
4454
4485
|
for (var shI = 0; shI < shL.length; shI++) {
|
|
4455
4486
|
c.save()
|
|
4456
4487
|
c.shadowColor = 'rgba(' + shRgb + ',' + +(shadow * shL[shI][2]).toFixed(3) + ')'
|
|
@@ -4849,10 +4880,13 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
4849
4880
|
card.mesh.scale.x = cpv[0]; card.mesh.scale.y = cpv[0]
|
|
4850
4881
|
card.mesh.position.y = cpv[1] * cpH
|
|
4851
4882
|
if (card.mesh.material) card.mesh.material.opacity = cpv[2]
|
|
4852
|
-
|
|
4883
|
+
// Gone past its clip: the mesh leaves the scene, not just its paint.
|
|
4884
|
+
card.mesh.visible = cpv[2] > 0.001
|
|
4885
|
+
} else if (card.mesh.scale && card.mesh.position && ((card.mesh.scale.x !== undefined && card.mesh.scale.x !== 1) || (card.mesh.position.y !== undefined && card.mesh.position.y !== 0) || card.mesh.visible === false)) {
|
|
4853
4886
|
card.mesh.scale.x = 1; card.mesh.scale.y = 1
|
|
4854
4887
|
card.mesh.position.y = 0
|
|
4855
4888
|
if (card.mesh.material) card.mesh.material.opacity = 1
|
|
4889
|
+
card.mesh.visible = true
|
|
4856
4890
|
}
|
|
4857
4891
|
var tilted = rx * rx + ry * ry > 1e-6
|
|
4858
4892
|
if (card.texture && card.texture.generateMipmaps !== tilted) {
|
|
@@ -4884,14 +4918,14 @@ function studioLayerData(layers, duration) {
|
|
|
4884
4918
|
// needs a decoded recording, which a sync lowering can't produce.
|
|
4885
4919
|
audio: (layers.audio ?? []).map((c) => ({
|
|
4886
4920
|
key: c.key,
|
|
4887
|
-
start:
|
|
4888
|
-
in:
|
|
4889
|
-
out:
|
|
4890
|
-
gain:
|
|
4921
|
+
start: round6(c.start),
|
|
4922
|
+
in: round6(c.in),
|
|
4923
|
+
out: round6(c.out),
|
|
4924
|
+
gain: round6(c.gain),
|
|
4891
4925
|
loop: !!c.loop,
|
|
4892
|
-
len:
|
|
4926
|
+
len: round6(clipLength(c)),
|
|
4893
4927
|
duck: !!c.duck,
|
|
4894
|
-
env: clipEnvelope(c).map((p) => ({ t:
|
|
4928
|
+
env: clipEnvelope(c).map((p) => ({ t: round6(p.t), g: round6(p.g) }))
|
|
4895
4929
|
})),
|
|
4896
4930
|
// Object clips: numbers resolved HERE; shapes are the drafted engine spec.
|
|
4897
4931
|
...layers.objects && layers.objects.length ? {
|
|
@@ -4904,17 +4938,17 @@ function studioLayerData(layers, duration) {
|
|
|
4904
4938
|
} : o.asset.kind === "text3d" ? resolveText3dAsset(o.asset) : { kind: "gltf", key: o.asset.key },
|
|
4905
4939
|
...o.span ? {
|
|
4906
4940
|
span: {
|
|
4907
|
-
start:
|
|
4908
|
-
duration:
|
|
4941
|
+
start: round6(o.span.start),
|
|
4942
|
+
duration: round6(o.span.duration)
|
|
4909
4943
|
}
|
|
4910
4944
|
} : {},
|
|
4911
|
-
x:
|
|
4912
|
-
y:
|
|
4913
|
-
z:
|
|
4914
|
-
rx:
|
|
4915
|
-
ry:
|
|
4916
|
-
rz:
|
|
4917
|
-
scale:
|
|
4945
|
+
x: round6(o.transform3d.x),
|
|
4946
|
+
y: round6(o.transform3d.y),
|
|
4947
|
+
z: round6(o.transform3d.z),
|
|
4948
|
+
rx: round6(o.transform3d.rx),
|
|
4949
|
+
ry: round6(o.transform3d.ry),
|
|
4950
|
+
rz: round6(o.transform3d.rz),
|
|
4951
|
+
scale: round6(o.transform3d.scale || OBJECT_DEFAULT_SCALE),
|
|
4918
4952
|
anim: idleKey(o),
|
|
4919
4953
|
// Pose keyframes: clip-local [x,y,z,rx,ry,rz,scale] track,
|
|
4920
4954
|
// sampled at t − span.start. Omitted when absent — parity.
|
|
@@ -4941,12 +4975,12 @@ function studioLayerData(layers, duration) {
|
|
|
4941
4975
|
const base = {
|
|
4942
4976
|
id: o.id,
|
|
4943
4977
|
kind: o.kind,
|
|
4944
|
-
start:
|
|
4945
|
-
dur:
|
|
4946
|
-
x:
|
|
4947
|
-
y:
|
|
4948
|
-
scale:
|
|
4949
|
-
rot:
|
|
4978
|
+
start: round6(o.start),
|
|
4979
|
+
dur: round6(Math.max(OVERLAY_MIN_DURATION, o.duration)),
|
|
4980
|
+
x: round6(o.transform.x),
|
|
4981
|
+
y: round6(o.transform.y),
|
|
4982
|
+
scale: round6(o.transform.scale || 1),
|
|
4983
|
+
rot: round6(o.transform.rotation || 0),
|
|
4950
4984
|
enter: enterKey(o),
|
|
4951
4985
|
exit: exitKey(o),
|
|
4952
4986
|
// Pose keyframes: a CLIP-LOCAL [x, y, scale, rot, opacity]
|
|
@@ -4967,7 +5001,7 @@ function studioLayerData(layers, duration) {
|
|
|
4967
5001
|
return {
|
|
4968
5002
|
...base,
|
|
4969
5003
|
key: o.key,
|
|
4970
|
-
w:
|
|
5004
|
+
w: round6(o.width ?? OVERLAY_MEDIA_DEFAULT_WIDTH),
|
|
4971
5005
|
radius: o.radius ?? OVERLAY_MEDIA_DEFAULT_RADIUS,
|
|
4972
5006
|
opacity: o.opacity ?? 1,
|
|
4973
5007
|
loop: !!o.loop,
|
|
@@ -4977,7 +5011,7 @@ function studioLayerData(layers, duration) {
|
|
|
4977
5011
|
...o.shadow ? { shadow: o.shadow } : {},
|
|
4978
5012
|
...o.border && o.border.width > 0 ? {
|
|
4979
5013
|
border: {
|
|
4980
|
-
width:
|
|
5014
|
+
width: round6(o.border.width),
|
|
4981
5015
|
color: o.border.color
|
|
4982
5016
|
}
|
|
4983
5017
|
} : {}
|
|
@@ -4997,11 +5031,11 @@ function studioLayerData(layers, duration) {
|
|
|
4997
5031
|
// Style-v2 fields bake only when non-default (byte parity for
|
|
4998
5032
|
// older docs); ON_FRAME reads them unconditionally.
|
|
4999
5033
|
...st.fontStyle === "italic" ? { sty: "italic" } : {},
|
|
5000
|
-
...o.maxWidth ? { mw:
|
|
5001
|
-
...st.letterSpacing ? { ls:
|
|
5002
|
-
...st.lineHeight !== OVERLAY_LINE_HEIGHT ? { lh:
|
|
5034
|
+
...o.maxWidth ? { mw: round6(o.maxWidth) } : {},
|
|
5035
|
+
...st.letterSpacing ? { ls: round6(st.letterSpacing) } : {},
|
|
5036
|
+
...st.lineHeight !== OVERLAY_LINE_HEIGHT ? { lh: round6(st.lineHeight) } : {},
|
|
5003
5037
|
...st.align !== "center" ? { align: st.align } : {},
|
|
5004
|
-
...st.stroke ? { stroke: { c: st.stroke.color, w:
|
|
5038
|
+
...st.stroke ? { stroke: { c: st.stroke.color, w: round6(st.stroke.width) } } : {},
|
|
5005
5039
|
// Hosted face behind an override: ON_FRAME lazy-loads it so a
|
|
5006
5040
|
// live family/weight edit paints without a LOAD (SETUP only
|
|
5007
5041
|
// runs on cold load).
|
|
@@ -5014,10 +5048,10 @@ function studioLayerData(layers, duration) {
|
|
|
5014
5048
|
...bx ? {
|
|
5015
5049
|
box: {
|
|
5016
5050
|
c: bx.color,
|
|
5017
|
-
o:
|
|
5018
|
-
px:
|
|
5019
|
-
py:
|
|
5020
|
-
r:
|
|
5051
|
+
o: round6(bx.opacity),
|
|
5052
|
+
px: round6(bx.padX),
|
|
5053
|
+
py: round6(bx.padY),
|
|
5054
|
+
r: round6(bx.radius)
|
|
5021
5055
|
}
|
|
5022
5056
|
} : {},
|
|
5023
5057
|
// Entrance animation: segmentation + timing normalized
|
|
@@ -5092,16 +5126,16 @@ function lowerToComposition(input) {
|
|
|
5092
5126
|
// Rated segments (speed spans pre-intersected): ON_FRAME's mapTime and the
|
|
5093
5127
|
// export's audio splice read the rate straight off each segment.
|
|
5094
5128
|
segments: rated.map((seg) => ({
|
|
5095
|
-
in:
|
|
5096
|
-
out:
|
|
5097
|
-
...seg.rate !== void 0 && seg.rate !== 1 ? { rate:
|
|
5129
|
+
in: round6(seg.in),
|
|
5130
|
+
out: round6(seg.out),
|
|
5131
|
+
...seg.rate !== void 0 && seg.rate !== 1 ? { rate: round6(seg.rate) } : {}
|
|
5098
5132
|
})),
|
|
5099
5133
|
frame: doc.frame,
|
|
5100
5134
|
micGain: doc.micGain ?? 1,
|
|
5101
5135
|
cursor: smoothed.map((p) => ({
|
|
5102
|
-
t:
|
|
5103
|
-
x:
|
|
5104
|
-
y:
|
|
5136
|
+
t: round6(p.t),
|
|
5137
|
+
x: round6(p.x),
|
|
5138
|
+
y: round6(p.y)
|
|
5105
5139
|
})),
|
|
5106
5140
|
cursorStyle: doc.cursor,
|
|
5107
5141
|
cursorSpace: { w: doc.source.meta.width, h: doc.source.meta.height },
|
|
@@ -5186,7 +5220,7 @@ function clickFxData(doc, rated) {
|
|
|
5186
5220
|
}
|
|
5187
5221
|
};
|
|
5188
5222
|
}
|
|
5189
|
-
function
|
|
5223
|
+
function round6(v) {
|
|
5190
5224
|
return Math.round(v * 1e3) / 1e3;
|
|
5191
5225
|
}
|
|
5192
5226
|
|
|
@@ -5276,8 +5310,8 @@ function planAutoSpeed(track, opts) {
|
|
|
5276
5310
|
accepted.sort((a, b) => a.in - b.in);
|
|
5277
5311
|
return accepted.map((c, i) => ({
|
|
5278
5312
|
id: `s${i}`,
|
|
5279
|
-
in:
|
|
5280
|
-
out:
|
|
5313
|
+
in: round7(c.in),
|
|
5314
|
+
out: round7(c.out),
|
|
5281
5315
|
rate: clampSpeedRate(c.rate),
|
|
5282
5316
|
source: "auto"
|
|
5283
5317
|
}));
|
|
@@ -5330,7 +5364,7 @@ function collectRuns(evs, gap, minLen, emit2) {
|
|
|
5330
5364
|
}
|
|
5331
5365
|
flush();
|
|
5332
5366
|
}
|
|
5333
|
-
function
|
|
5367
|
+
function round7(v) {
|
|
5334
5368
|
return Math.round(v * 1e3) / 1e3;
|
|
5335
5369
|
}
|
|
5336
5370
|
|
|
@@ -5507,16 +5541,16 @@ function momentsFromDoc(doc, plan, opts = {}) {
|
|
|
5507
5541
|
return {
|
|
5508
5542
|
id: `m${String(i + 1).padStart(2, "0")}`,
|
|
5509
5543
|
kind: d.kind,
|
|
5510
|
-
source: { in:
|
|
5511
|
-
output: output ? { in:
|
|
5512
|
-
at: d.at === null ? null :
|
|
5513
|
-
outputAt: outAt ?
|
|
5514
|
-
focus: d.focus ? { cx:
|
|
5544
|
+
source: { in: round8(d.in), out: round8(d.out) },
|
|
5545
|
+
output: output ? { in: round8(output.start), out: round8(output.end) } : null,
|
|
5546
|
+
at: d.at === null ? null : round8(d.at),
|
|
5547
|
+
outputAt: outAt ? round8(outAt.start) : null,
|
|
5548
|
+
focus: d.focus ? { cx: round8(d.focus.cx), cy: round8(d.focus.cy) } : null,
|
|
5515
5549
|
rect: d.rect ? {
|
|
5516
|
-
x:
|
|
5517
|
-
y:
|
|
5518
|
-
w:
|
|
5519
|
-
h:
|
|
5550
|
+
x: round8(d.rect.x),
|
|
5551
|
+
y: round8(d.rect.y),
|
|
5552
|
+
w: round8(d.rect.w),
|
|
5553
|
+
h: round8(d.rect.h)
|
|
5520
5554
|
} : null,
|
|
5521
5555
|
...d.clicks !== void 0 ? { clicks: d.clicks } : {},
|
|
5522
5556
|
...d.pings !== void 0 ? { pings: d.pings } : {},
|
|
@@ -5536,7 +5570,7 @@ function activityOf(bins, d) {
|
|
|
5536
5570
|
sum += bins[i];
|
|
5537
5571
|
n++;
|
|
5538
5572
|
}
|
|
5539
|
-
return n ?
|
|
5573
|
+
return n ? round8(sum / n) : null;
|
|
5540
5574
|
}
|
|
5541
5575
|
function saidOver(transcript, d) {
|
|
5542
5576
|
if (!transcript?.length) return null;
|
|
@@ -5545,7 +5579,7 @@ function saidOver(transcript, d) {
|
|
|
5545
5579
|
const text = transcript.filter((s) => s.start < hi && s.end > lo).map((s) => s.text.trim()).filter(Boolean).join(" ");
|
|
5546
5580
|
return text || null;
|
|
5547
5581
|
}
|
|
5548
|
-
function
|
|
5582
|
+
function round8(v) {
|
|
5549
5583
|
return Math.round(v * 1e3) / 1e3;
|
|
5550
5584
|
}
|
|
5551
5585
|
|
|
@@ -5833,12 +5867,14 @@ function clipsFrom(doc, from) {
|
|
|
5833
5867
|
}
|
|
5834
5868
|
function dropTemplate(doc, from) {
|
|
5835
5869
|
const has = clipsFrom(doc, from);
|
|
5836
|
-
|
|
5870
|
+
const freezes = (doc.freeze ?? []).some((f) => f.from === from);
|
|
5871
|
+
if (!has.overlays.length && !has.objects.length && !has.audio.length && !freezes)
|
|
5837
5872
|
return doc;
|
|
5838
5873
|
const out = { ...doc };
|
|
5839
5874
|
if (doc.overlays) out.overlays = doc.overlays.filter((o) => o.from !== from);
|
|
5840
5875
|
if (doc.objects) out.objects = doc.objects.filter((o) => o.from !== from);
|
|
5841
5876
|
out.audio = doc.audio.filter((a) => a.from !== from);
|
|
5877
|
+
if (doc.freeze) out.freeze = doc.freeze.filter((f) => f.from !== from);
|
|
5842
5878
|
return out;
|
|
5843
5879
|
}
|
|
5844
5880
|
function applyTemplate(template, take, opts) {
|
|
@@ -5846,8 +5882,22 @@ function applyTemplate(template, take, opts) {
|
|
|
5846
5882
|
const notes = [];
|
|
5847
5883
|
const base = dropTemplate(take, from);
|
|
5848
5884
|
const doc = structuredClone(base);
|
|
5885
|
+
const tail = trailingFreeze(template);
|
|
5886
|
+
const lastSeg = doc.segments.at(-1);
|
|
5887
|
+
if (tail && opts.at === "end" && lastSeg) {
|
|
5888
|
+
const own2 = (doc.freeze ?? []).filter(
|
|
5889
|
+
(f) => Math.abs(f.at - lastSeg.out) > 1e-9
|
|
5890
|
+
);
|
|
5891
|
+
const taken = new Set(own2.map((f) => f.id));
|
|
5892
|
+
let n = 0;
|
|
5893
|
+
while (taken.has(`f${n}`)) n++;
|
|
5894
|
+
doc.freeze = [
|
|
5895
|
+
...own2,
|
|
5896
|
+
{ id: `f${n}`, at: lastSeg.out, seconds: tail.seconds, from }
|
|
5897
|
+
].sort((a, b) => a.at - b.at);
|
|
5898
|
+
}
|
|
5849
5899
|
const templateEnd = totalDuration4(ratedSegments(template));
|
|
5850
|
-
const takeEnd = totalDuration4(ratedSegments(
|
|
5900
|
+
const takeEnd = totalDuration4(ratedSegments(doc));
|
|
5851
5901
|
const shift = shiftBy(opts.at, templateEnd, takeEnd);
|
|
5852
5902
|
const own = new Map((take.overlays ?? []).map((o) => [o.id, o]));
|
|
5853
5903
|
const overlays = (doc.overlays ?? []).filter(
|
|
@@ -6011,8 +6061,8 @@ function buildDigest(input) {
|
|
|
6011
6061
|
return {
|
|
6012
6062
|
digestVersion: DIGEST_VERSION,
|
|
6013
6063
|
take: {
|
|
6014
|
-
sourceDuration:
|
|
6015
|
-
outputDuration:
|
|
6064
|
+
sourceDuration: round9(meta.durationMs / 1e3),
|
|
6065
|
+
outputDuration: round9(input.outputDuration),
|
|
6016
6066
|
width: meta.width,
|
|
6017
6067
|
height: meta.height,
|
|
6018
6068
|
captureWidth: meta.captureWidth ?? null,
|
|
@@ -6061,7 +6111,7 @@ function buildDigest(input) {
|
|
|
6061
6111
|
function outputDurationOf(doc) {
|
|
6062
6112
|
return docOutputDuration(doc);
|
|
6063
6113
|
}
|
|
6064
|
-
function
|
|
6114
|
+
function round9(v) {
|
|
6065
6115
|
return Math.round(v * 1e3) / 1e3;
|
|
6066
6116
|
}
|
|
6067
6117
|
|
|
@@ -6087,20 +6137,20 @@ function setSpeedInRange(spans, srcIn, srcOut, rate) {
|
|
|
6087
6137
|
continue;
|
|
6088
6138
|
}
|
|
6089
6139
|
if (srcIn - s.in >= MIN_REMAINDER)
|
|
6090
|
-
kept.push({ ...s, out:
|
|
6140
|
+
kept.push({ ...s, out: round10(srcIn), source: "manual" });
|
|
6091
6141
|
if (s.out - srcOut >= MIN_REMAINDER)
|
|
6092
6142
|
kept.push({
|
|
6093
6143
|
...s,
|
|
6094
6144
|
id: mintId(used),
|
|
6095
|
-
in:
|
|
6145
|
+
in: round10(srcOut),
|
|
6096
6146
|
source: "manual"
|
|
6097
6147
|
});
|
|
6098
6148
|
}
|
|
6099
6149
|
if (rate != null)
|
|
6100
6150
|
kept.push({
|
|
6101
6151
|
id: mintId(used),
|
|
6102
|
-
in:
|
|
6103
|
-
out:
|
|
6152
|
+
in: round10(srcIn),
|
|
6153
|
+
out: round10(srcOut),
|
|
6104
6154
|
rate: clampSpeedRate(rate),
|
|
6105
6155
|
source: "manual"
|
|
6106
6156
|
});
|
|
@@ -6116,9 +6166,9 @@ function removeSourceRange(segments, srcIn, srcOut) {
|
|
|
6116
6166
|
next.push(seg);
|
|
6117
6167
|
continue;
|
|
6118
6168
|
}
|
|
6119
|
-
if (srcIn - seg.in >= MIN_SEGMENT) next.push({ ...seg, out:
|
|
6169
|
+
if (srcIn - seg.in >= MIN_SEGMENT) next.push({ ...seg, out: round10(srcIn) });
|
|
6120
6170
|
if (seg.out - srcOut >= MIN_SEGMENT)
|
|
6121
|
-
next.push({ ...seg, in:
|
|
6171
|
+
next.push({ ...seg, in: round10(srcOut) });
|
|
6122
6172
|
}
|
|
6123
6173
|
return next.length ? next : [...segments];
|
|
6124
6174
|
}
|
|
@@ -6136,8 +6186,8 @@ function zoomSpanForRange(zoom, srcIn, srcOut) {
|
|
|
6136
6186
|
while (used.has(`u${n}`)) n++;
|
|
6137
6187
|
return {
|
|
6138
6188
|
id: `u${n}`,
|
|
6139
|
-
in:
|
|
6140
|
-
out:
|
|
6189
|
+
in: round10(start),
|
|
6190
|
+
out: round10(end),
|
|
6141
6191
|
level: DEFAULT_ZOOM_LEVEL,
|
|
6142
6192
|
cx: 0.5,
|
|
6143
6193
|
cy: 0.5,
|
|
@@ -6151,7 +6201,7 @@ function mintId(used) {
|
|
|
6151
6201
|
used.add(id);
|
|
6152
6202
|
return id;
|
|
6153
6203
|
}
|
|
6154
|
-
function
|
|
6204
|
+
function round10(v) {
|
|
6155
6205
|
return Math.round(v * 1e3) / 1e3;
|
|
6156
6206
|
}
|
|
6157
6207
|
|
|
@@ -6822,8 +6872,8 @@ var videoLane = {
|
|
|
6822
6872
|
return segments.map((s, i) => ({
|
|
6823
6873
|
id: `seg-${i}`,
|
|
6824
6874
|
kind: "clip",
|
|
6825
|
-
t:
|
|
6826
|
-
duration:
|
|
6875
|
+
t: round11(starts[i]),
|
|
6876
|
+
duration: round11(
|
|
6827
6877
|
outputLen(s, speeds, freezes, i === 0 || !contiguous(segments, i))
|
|
6828
6878
|
)
|
|
6829
6879
|
}));
|
|
@@ -6906,7 +6956,7 @@ var videoLane = {
|
|
|
6906
6956
|
if (local >= m.t - 1e-9 && local <= m.t + m.duration + 1e-9)
|
|
6907
6957
|
return null;
|
|
6908
6958
|
}
|
|
6909
|
-
const sourceT =
|
|
6959
|
+
const sourceT = round11(
|
|
6910
6960
|
mapTime2(segmentPieces(s, speeds, freezes, leading), local)
|
|
6911
6961
|
);
|
|
6912
6962
|
if (sourceT - s.in < 0.05 || s.out - sourceT < 0.05) return null;
|
|
@@ -6947,7 +6997,7 @@ var videoLane = {
|
|
|
6947
6997
|
n === 1 || !contiguous(segments, n - 1)
|
|
6948
6998
|
)
|
|
6949
6999
|
] : []
|
|
6950
|
-
].map(
|
|
7000
|
+
].map(round11);
|
|
6951
7001
|
}
|
|
6952
7002
|
};
|
|
6953
7003
|
function nextFreezeId(doc) {
|
|
@@ -6974,8 +7024,8 @@ var freezeLane = {
|
|
|
6974
7024
|
{
|
|
6975
7025
|
id: f.id,
|
|
6976
7026
|
kind: "clip",
|
|
6977
|
-
t:
|
|
6978
|
-
duration:
|
|
7027
|
+
t: round11(m.t),
|
|
7028
|
+
duration: round11(m.duration),
|
|
6979
7029
|
label: `${trimZeros(f.seconds)}s`
|
|
6980
7030
|
}
|
|
6981
7031
|
] : [];
|
|
@@ -6997,7 +7047,7 @@ var freezeLane = {
|
|
|
6997
7047
|
if (g.t >= m.t - 1e-9 && g.t <= m.t + m.duration + 1e-9) return null;
|
|
6998
7048
|
}
|
|
6999
7049
|
if (g.t > totalDuration6(rated) + 1e-9) return null;
|
|
7000
|
-
const srcT =
|
|
7050
|
+
const srcT = round11(mapTime2(rated, Math.max(0, g.t)));
|
|
7001
7051
|
if (!kept(srcT) || !clear(srcT)) return null;
|
|
7002
7052
|
const id = nextFreezeId(doc);
|
|
7003
7053
|
return (d) => {
|
|
@@ -7033,7 +7083,7 @@ var freezeLane = {
|
|
|
7033
7083
|
const marks = freezeOutputExtents(splitBySpeed3(segs, speeds), freezes);
|
|
7034
7084
|
const mine = marks.get(f.id);
|
|
7035
7085
|
const endOut = mine ? mine.t + mine.duration : null;
|
|
7036
|
-
const srcT =
|
|
7086
|
+
const srcT = round11(
|
|
7037
7087
|
Math.min(sourceDuration, mapTime2(base, Math.max(0, g.t)))
|
|
7038
7088
|
);
|
|
7039
7089
|
if (!kept(srcT) || !clear(srcT, f.id)) return null;
|
|
@@ -7093,8 +7143,8 @@ var zoomLane = {
|
|
|
7093
7143
|
{
|
|
7094
7144
|
id: z.id,
|
|
7095
7145
|
kind: "clip",
|
|
7096
|
-
t:
|
|
7097
|
-
duration:
|
|
7146
|
+
t: round11(ext.start),
|
|
7147
|
+
duration: round11(ext.end - ext.start),
|
|
7098
7148
|
label: `${z.level.toFixed(2)}\xD7`
|
|
7099
7149
|
}
|
|
7100
7150
|
];
|
|
@@ -7118,8 +7168,8 @@ var zoomLane = {
|
|
|
7118
7168
|
...d.zoom,
|
|
7119
7169
|
{
|
|
7120
7170
|
id,
|
|
7121
|
-
in:
|
|
7122
|
-
out:
|
|
7171
|
+
in: round11(srcT),
|
|
7172
|
+
out: round11(srcT + len),
|
|
7123
7173
|
level: DEFAULT_ZOOM_LEVEL,
|
|
7124
7174
|
cx,
|
|
7125
7175
|
cy,
|
|
@@ -7150,8 +7200,8 @@ var zoomLane = {
|
|
|
7150
7200
|
return (d) => {
|
|
7151
7201
|
const z = d.zoom.find((x) => x.id === g.id);
|
|
7152
7202
|
if (!z) return;
|
|
7153
|
-
z.in =
|
|
7154
|
-
z.out =
|
|
7203
|
+
z.in = round11(newIn);
|
|
7204
|
+
z.out = round11(newIn + len);
|
|
7155
7205
|
z.source = "manual";
|
|
7156
7206
|
d.zoom.sort((a, b) => a.in - b.in);
|
|
7157
7207
|
};
|
|
@@ -7180,8 +7230,8 @@ var zoomLane = {
|
|
|
7180
7230
|
return (d) => {
|
|
7181
7231
|
const z = d.zoom.find((x) => x.id === g.id);
|
|
7182
7232
|
if (!z) return;
|
|
7183
|
-
z.in =
|
|
7184
|
-
z.out =
|
|
7233
|
+
z.in = round11(next.in);
|
|
7234
|
+
z.out = round11(next.out);
|
|
7185
7235
|
z.source = "manual";
|
|
7186
7236
|
};
|
|
7187
7237
|
}
|
|
@@ -7203,8 +7253,8 @@ function cursorFocusAt(doc, srcT) {
|
|
|
7203
7253
|
if (Math.abs(e.t - ms) < Math.abs(best.t - ms)) best = e;
|
|
7204
7254
|
const clamp015 = (v) => Math.max(0, Math.min(1, v));
|
|
7205
7255
|
return {
|
|
7206
|
-
cx:
|
|
7207
|
-
cy:
|
|
7256
|
+
cx: round11(clamp015(best.x / width)),
|
|
7257
|
+
cy: round11(clamp015(best.y / height))
|
|
7208
7258
|
};
|
|
7209
7259
|
}
|
|
7210
7260
|
var tiltLane = {
|
|
@@ -7218,8 +7268,8 @@ var tiltLane = {
|
|
|
7218
7268
|
{
|
|
7219
7269
|
id: z.id,
|
|
7220
7270
|
kind: "clip",
|
|
7221
|
-
t:
|
|
7222
|
-
duration:
|
|
7271
|
+
t: round11(ext.start),
|
|
7272
|
+
duration: round11(ext.end - ext.start),
|
|
7223
7273
|
label: `${formatDeg(z.rx)}\xB0/${formatDeg(z.ry)}\xB0`
|
|
7224
7274
|
}
|
|
7225
7275
|
];
|
|
@@ -7242,8 +7292,8 @@ var tiltLane = {
|
|
|
7242
7292
|
...d.tilt ?? [],
|
|
7243
7293
|
{
|
|
7244
7294
|
id,
|
|
7245
|
-
in:
|
|
7246
|
-
out:
|
|
7295
|
+
in: round11(srcT),
|
|
7296
|
+
out: round11(srcT + len),
|
|
7247
7297
|
rx: DEFAULT_TILT_POSE.rx,
|
|
7248
7298
|
ry: DEFAULT_TILT_POSE.ry,
|
|
7249
7299
|
source: "manual"
|
|
@@ -7273,8 +7323,8 @@ var tiltLane = {
|
|
|
7273
7323
|
return (d) => {
|
|
7274
7324
|
const z = (d.tilt ?? []).find((x) => x.id === g.id);
|
|
7275
7325
|
if (!z || !d.tilt) return;
|
|
7276
|
-
z.in =
|
|
7277
|
-
z.out =
|
|
7326
|
+
z.in = round11(newIn);
|
|
7327
|
+
z.out = round11(newIn + len);
|
|
7278
7328
|
z.source = "manual";
|
|
7279
7329
|
d.tilt.sort((a, b) => a.in - b.in);
|
|
7280
7330
|
};
|
|
@@ -7303,8 +7353,8 @@ var tiltLane = {
|
|
|
7303
7353
|
return (d) => {
|
|
7304
7354
|
const z = (d.tilt ?? []).find((x) => x.id === g.id);
|
|
7305
7355
|
if (!z) return;
|
|
7306
|
-
z.in =
|
|
7307
|
-
z.out =
|
|
7356
|
+
z.in = round11(next.in);
|
|
7357
|
+
z.out = round11(next.out);
|
|
7308
7358
|
z.source = "manual";
|
|
7309
7359
|
};
|
|
7310
7360
|
}
|
|
@@ -7331,8 +7381,8 @@ var camMoveLane = {
|
|
|
7331
7381
|
{
|
|
7332
7382
|
id: z.id,
|
|
7333
7383
|
kind: "clip",
|
|
7334
|
-
t:
|
|
7335
|
-
duration:
|
|
7384
|
+
t: round11(ext.start),
|
|
7385
|
+
duration: round11(ext.end - ext.start),
|
|
7336
7386
|
label: z.size != null ? `${Math.round(z.size * 100)}%` : "Move"
|
|
7337
7387
|
}
|
|
7338
7388
|
];
|
|
@@ -7356,8 +7406,8 @@ var camMoveLane = {
|
|
|
7356
7406
|
...d.camMotion ?? [],
|
|
7357
7407
|
{
|
|
7358
7408
|
id,
|
|
7359
|
-
in:
|
|
7360
|
-
out:
|
|
7409
|
+
in: round11(srcT),
|
|
7410
|
+
out: round11(srcT + len),
|
|
7361
7411
|
...DEFAULT_CAM_POSE,
|
|
7362
7412
|
source: "manual"
|
|
7363
7413
|
}
|
|
@@ -7386,8 +7436,8 @@ var camMoveLane = {
|
|
|
7386
7436
|
return (d) => {
|
|
7387
7437
|
const z = (d.camMotion ?? []).find((x) => x.id === g.id);
|
|
7388
7438
|
if (!z || !d.camMotion) return;
|
|
7389
|
-
z.in =
|
|
7390
|
-
z.out =
|
|
7439
|
+
z.in = round11(newIn);
|
|
7440
|
+
z.out = round11(newIn + len);
|
|
7391
7441
|
z.source = "manual";
|
|
7392
7442
|
d.camMotion.sort((a, b) => a.in - b.in);
|
|
7393
7443
|
};
|
|
@@ -7416,8 +7466,8 @@ var camMoveLane = {
|
|
|
7416
7466
|
return (d) => {
|
|
7417
7467
|
const z = (d.camMotion ?? []).find((x) => x.id === g.id);
|
|
7418
7468
|
if (!z) return;
|
|
7419
|
-
z.in =
|
|
7420
|
-
z.out =
|
|
7469
|
+
z.in = round11(next.in);
|
|
7470
|
+
z.out = round11(next.out);
|
|
7421
7471
|
z.source = "manual";
|
|
7422
7472
|
};
|
|
7423
7473
|
}
|
|
@@ -7450,10 +7500,10 @@ var camLane = {
|
|
|
7450
7500
|
items.push({
|
|
7451
7501
|
id: `cam-${i}`,
|
|
7452
7502
|
kind: "clip",
|
|
7453
|
-
t:
|
|
7503
|
+
t: round11(
|
|
7454
7504
|
starts[i] + outputLen({ in: s.in, out: a }, speeds, freezes, leading)
|
|
7455
7505
|
),
|
|
7456
|
-
duration:
|
|
7506
|
+
duration: round11(
|
|
7457
7507
|
outputLen({ in: a, out: b }, speeds, freezes, a === s.in && leading)
|
|
7458
7508
|
)
|
|
7459
7509
|
});
|
|
@@ -7482,7 +7532,7 @@ var camLane = {
|
|
|
7482
7532
|
Math.max(first.in, last.out - span)
|
|
7483
7533
|
);
|
|
7484
7534
|
return (d) => {
|
|
7485
|
-
d.cam.window = { in:
|
|
7535
|
+
d.cam.window = { in: round11(newIn), out: round11(newIn + span) };
|
|
7486
7536
|
};
|
|
7487
7537
|
}
|
|
7488
7538
|
const overlapping = eff.map((s, i) => ({
|
|
@@ -7495,8 +7545,8 @@ var camLane = {
|
|
|
7495
7545
|
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) };
|
|
7496
7546
|
return (d) => {
|
|
7497
7547
|
d.cam.window = {
|
|
7498
|
-
in:
|
|
7499
|
-
out:
|
|
7548
|
+
in: round11(Math.max(0, next.in)),
|
|
7549
|
+
out: round11(Math.min(sourceDuration, next.out))
|
|
7500
7550
|
};
|
|
7501
7551
|
};
|
|
7502
7552
|
},
|
|
@@ -7516,8 +7566,8 @@ var micLane = {
|
|
|
7516
7566
|
return segments.map((s, i) => ({
|
|
7517
7567
|
id: `mic-${i}`,
|
|
7518
7568
|
kind: "clip",
|
|
7519
|
-
t:
|
|
7520
|
-
duration:
|
|
7569
|
+
t: round11(starts[i]),
|
|
7570
|
+
duration: round11(
|
|
7521
7571
|
outputLen(s, speeds, freezes, i === 0 || !contiguous(segments, i))
|
|
7522
7572
|
)
|
|
7523
7573
|
}));
|
|
@@ -7573,8 +7623,8 @@ var speedLane = {
|
|
|
7573
7623
|
{
|
|
7574
7624
|
id: sp.id,
|
|
7575
7625
|
kind: "clip",
|
|
7576
|
-
t:
|
|
7577
|
-
duration:
|
|
7626
|
+
t: round11(start),
|
|
7627
|
+
duration: round11(end - start),
|
|
7578
7628
|
label: `${sp.rate}\xD7`
|
|
7579
7629
|
}
|
|
7580
7630
|
];
|
|
@@ -7597,8 +7647,8 @@ var speedLane = {
|
|
|
7597
7647
|
...d.speed ?? [],
|
|
7598
7648
|
{
|
|
7599
7649
|
id,
|
|
7600
|
-
in:
|
|
7601
|
-
out:
|
|
7650
|
+
in: round11(srcT),
|
|
7651
|
+
out: round11(srcT + len),
|
|
7602
7652
|
rate: DEFAULT_SPEED_RATE,
|
|
7603
7653
|
source: "manual"
|
|
7604
7654
|
}
|
|
@@ -7628,8 +7678,8 @@ var speedLane = {
|
|
|
7628
7678
|
return (d) => {
|
|
7629
7679
|
const s = d.speed?.find((x) => x.id === g.id);
|
|
7630
7680
|
if (!s) return;
|
|
7631
|
-
s.in =
|
|
7632
|
-
s.out =
|
|
7681
|
+
s.in = round11(newIn);
|
|
7682
|
+
s.out = round11(newIn + len);
|
|
7633
7683
|
s.source = "manual";
|
|
7634
7684
|
d.speed.sort((a, b) => a.in - b.in);
|
|
7635
7685
|
};
|
|
@@ -7658,8 +7708,8 @@ var speedLane = {
|
|
|
7658
7708
|
return (d) => {
|
|
7659
7709
|
const s = d.speed?.find((x) => x.id === g.id);
|
|
7660
7710
|
if (!s) return;
|
|
7661
|
-
s.in =
|
|
7662
|
-
s.out =
|
|
7711
|
+
s.in = round11(next.in);
|
|
7712
|
+
s.out = round11(next.out);
|
|
7663
7713
|
s.source = "manual";
|
|
7664
7714
|
};
|
|
7665
7715
|
}
|
|
@@ -7678,8 +7728,8 @@ var audioLane = {
|
|
|
7678
7728
|
return doc.audio.map((c) => ({
|
|
7679
7729
|
id: c.id,
|
|
7680
7730
|
kind: "clip",
|
|
7681
|
-
t:
|
|
7682
|
-
duration:
|
|
7731
|
+
t: round11(c.start),
|
|
7732
|
+
duration: round11(clipLength(c)),
|
|
7683
7733
|
label: c.name
|
|
7684
7734
|
}));
|
|
7685
7735
|
},
|
|
@@ -7690,7 +7740,7 @@ var audioLane = {
|
|
|
7690
7740
|
const start = Math.max(0, g.t);
|
|
7691
7741
|
return (d) => {
|
|
7692
7742
|
const c = d.audio.find((x) => x.id === g.id);
|
|
7693
|
-
if (c) c.start =
|
|
7743
|
+
if (c) c.start = round11(start);
|
|
7694
7744
|
};
|
|
7695
7745
|
}
|
|
7696
7746
|
if (g.type === "resize") {
|
|
@@ -7703,8 +7753,8 @@ var audioLane = {
|
|
|
7703
7753
|
return (d) => {
|
|
7704
7754
|
const c = d.audio.find((x) => x.id === g.id);
|
|
7705
7755
|
if (!c) return;
|
|
7706
|
-
c.start =
|
|
7707
|
-
c.loopLen =
|
|
7756
|
+
c.start = round11(newStart2);
|
|
7757
|
+
c.loopLen = round11(end - newStart2);
|
|
7708
7758
|
};
|
|
7709
7759
|
}
|
|
7710
7760
|
const delta = g.t - clip.start;
|
|
@@ -7713,22 +7763,22 @@ var audioLane = {
|
|
|
7713
7763
|
return (d) => {
|
|
7714
7764
|
const c = d.audio.find((x) => x.id === g.id);
|
|
7715
7765
|
if (!c) return;
|
|
7716
|
-
c.in =
|
|
7717
|
-
c.start =
|
|
7766
|
+
c.in = round11(newIn);
|
|
7767
|
+
c.start = round11(newStart);
|
|
7718
7768
|
};
|
|
7719
7769
|
}
|
|
7720
7770
|
if (clip.loop) {
|
|
7721
7771
|
const newLen = Math.max(0.1, g.t - clip.start);
|
|
7722
7772
|
return (d) => {
|
|
7723
7773
|
const c = d.audio.find((x) => x.id === g.id);
|
|
7724
|
-
if (c) c.loopLen =
|
|
7774
|
+
if (c) c.loopLen = round11(newLen);
|
|
7725
7775
|
};
|
|
7726
7776
|
}
|
|
7727
7777
|
const span = Math.max(0.05, g.t - clip.start);
|
|
7728
7778
|
const newOut = Math.min(clip.in + span, clip.duration);
|
|
7729
7779
|
return (d) => {
|
|
7730
7780
|
const c = d.audio.find((x) => x.id === g.id);
|
|
7731
|
-
if (c) c.out =
|
|
7781
|
+
if (c) c.out = round11(Math.max(c.in + 0.05, newOut));
|
|
7732
7782
|
};
|
|
7733
7783
|
}
|
|
7734
7784
|
if (g.type === "remove") {
|
|
@@ -7741,8 +7791,8 @@ var audioLane = {
|
|
|
7741
7791
|
},
|
|
7742
7792
|
magnets(doc) {
|
|
7743
7793
|
return doc.audio.flatMap((c) => [
|
|
7744
|
-
|
|
7745
|
-
|
|
7794
|
+
round11(c.start),
|
|
7795
|
+
round11(c.start + clipLength(c))
|
|
7746
7796
|
]);
|
|
7747
7797
|
}
|
|
7748
7798
|
};
|
|
@@ -7760,7 +7810,7 @@ function poseItems(clipId, start, duration, motion) {
|
|
|
7760
7810
|
return (motion ?? []).map((p, i) => ({
|
|
7761
7811
|
id: `${clipId}::k${i}`,
|
|
7762
7812
|
kind: "keyframe",
|
|
7763
|
-
t:
|
|
7813
|
+
t: round11(start + Math.min(Math.max(0, p.at), duration))
|
|
7764
7814
|
}));
|
|
7765
7815
|
}
|
|
7766
7816
|
var overlaysLane = {
|
|
@@ -7771,8 +7821,8 @@ var overlaysLane = {
|
|
|
7771
7821
|
{
|
|
7772
7822
|
id: o.id,
|
|
7773
7823
|
kind: "clip",
|
|
7774
|
-
t:
|
|
7775
|
-
duration:
|
|
7824
|
+
t: round11(o.start),
|
|
7825
|
+
duration: round11(o.duration),
|
|
7776
7826
|
label: o.kind === "text" ? o.text.split("\n")[0].slice(0, 24) || "Text" : o.kind === "image" ? "Image" : "Video"
|
|
7777
7827
|
},
|
|
7778
7828
|
// Pose diamonds render after the clips, so they sit on top.
|
|
@@ -7792,7 +7842,7 @@ var overlaysLane = {
|
|
|
7792
7842
|
return (d) => {
|
|
7793
7843
|
const o = (d.overlays ?? []).find((x) => x.id === kf.clipId);
|
|
7794
7844
|
const p = o?.motion?.[kf.index];
|
|
7795
|
-
if (p) p.at =
|
|
7845
|
+
if (p) p.at = round11(at);
|
|
7796
7846
|
};
|
|
7797
7847
|
}
|
|
7798
7848
|
if (g.type === "remove") {
|
|
@@ -7821,8 +7871,8 @@ var overlaysLane = {
|
|
|
7821
7871
|
{
|
|
7822
7872
|
id,
|
|
7823
7873
|
kind: "text",
|
|
7824
|
-
start:
|
|
7825
|
-
duration:
|
|
7874
|
+
start: round11(start),
|
|
7875
|
+
duration: round11(len),
|
|
7826
7876
|
text: "Title",
|
|
7827
7877
|
preset: "title",
|
|
7828
7878
|
// Frame fractions: centered, lower-third — at any aspect ratio.
|
|
@@ -7837,7 +7887,7 @@ var overlaysLane = {
|
|
|
7837
7887
|
const start = Math.max(0, g.t);
|
|
7838
7888
|
return (d) => {
|
|
7839
7889
|
const o = (d.overlays ?? []).find((x) => x.id === g.id);
|
|
7840
|
-
if (o) o.start =
|
|
7890
|
+
if (o) o.start = round11(start);
|
|
7841
7891
|
};
|
|
7842
7892
|
}
|
|
7843
7893
|
if (g.type === "resize") {
|
|
@@ -7847,14 +7897,14 @@ var overlaysLane = {
|
|
|
7847
7897
|
return (d) => {
|
|
7848
7898
|
const o = (d.overlays ?? []).find((x) => x.id === g.id);
|
|
7849
7899
|
if (!o) return;
|
|
7850
|
-
o.start =
|
|
7851
|
-
o.duration =
|
|
7900
|
+
o.start = round11(newStart);
|
|
7901
|
+
o.duration = round11(end - newStart);
|
|
7852
7902
|
};
|
|
7853
7903
|
}
|
|
7854
7904
|
const newLen = Math.max(OVERLAY_MIN_DURATION, g.t - clip.start);
|
|
7855
7905
|
return (d) => {
|
|
7856
7906
|
const o = (d.overlays ?? []).find((x) => x.id === g.id);
|
|
7857
|
-
if (o) o.duration =
|
|
7907
|
+
if (o) o.duration = round11(newLen);
|
|
7858
7908
|
};
|
|
7859
7909
|
}
|
|
7860
7910
|
return (d) => {
|
|
@@ -7863,8 +7913,8 @@ var overlaysLane = {
|
|
|
7863
7913
|
},
|
|
7864
7914
|
magnets(doc) {
|
|
7865
7915
|
return (doc.overlays ?? []).flatMap((o) => [
|
|
7866
|
-
|
|
7867
|
-
|
|
7916
|
+
round11(o.start),
|
|
7917
|
+
round11(o.start + o.duration)
|
|
7868
7918
|
]);
|
|
7869
7919
|
}
|
|
7870
7920
|
};
|
|
@@ -7877,8 +7927,8 @@ var objectsLane = {
|
|
|
7877
7927
|
{
|
|
7878
7928
|
id: o.id,
|
|
7879
7929
|
kind: "clip",
|
|
7880
|
-
t:
|
|
7881
|
-
duration:
|
|
7930
|
+
t: round11(o.span?.start ?? 0),
|
|
7931
|
+
duration: round11(o.span?.duration ?? outDur),
|
|
7882
7932
|
label: o.asset.kind === "primitive" ? o.asset.shape : o.asset.kind === "text3d" ? o.asset.text : "model"
|
|
7883
7933
|
},
|
|
7884
7934
|
// Pose diamonds: clip-local `at` from the span start (0 span-less).
|
|
@@ -7906,7 +7956,7 @@ var objectsLane = {
|
|
|
7906
7956
|
return (d) => {
|
|
7907
7957
|
const o = (d.objects ?? []).find((x) => x.id === kf.clipId);
|
|
7908
7958
|
const p = o?.motion?.[kf.index];
|
|
7909
|
-
if (p) p.at =
|
|
7959
|
+
if (p) p.at = round11(at);
|
|
7910
7960
|
};
|
|
7911
7961
|
}
|
|
7912
7962
|
if (g.type === "remove") {
|
|
@@ -7927,7 +7977,7 @@ var objectsLane = {
|
|
|
7927
7977
|
const start = Math.max(0, g.t);
|
|
7928
7978
|
return (d) => {
|
|
7929
7979
|
const o = (d.objects ?? []).find((x) => x.id === g.id);
|
|
7930
|
-
if (o?.span) o.span.start =
|
|
7980
|
+
if (o?.span) o.span.start = round11(start);
|
|
7931
7981
|
};
|
|
7932
7982
|
}
|
|
7933
7983
|
if (g.type === "resize") {
|
|
@@ -7938,14 +7988,14 @@ var objectsLane = {
|
|
|
7938
7988
|
return (d) => {
|
|
7939
7989
|
const o = (d.objects ?? []).find((x) => x.id === g.id);
|
|
7940
7990
|
if (!o?.span) return;
|
|
7941
|
-
o.span.start =
|
|
7942
|
-
o.span.duration =
|
|
7991
|
+
o.span.start = round11(newStart);
|
|
7992
|
+
o.span.duration = round11(end - newStart);
|
|
7943
7993
|
};
|
|
7944
7994
|
}
|
|
7945
7995
|
const newLen = Math.max(OVERLAY_MIN_DURATION, g.t - clip.span.start);
|
|
7946
7996
|
return (d) => {
|
|
7947
7997
|
const o = (d.objects ?? []).find((x) => x.id === g.id);
|
|
7948
|
-
if (o?.span) o.span.duration =
|
|
7998
|
+
if (o?.span) o.span.duration = round11(newLen);
|
|
7949
7999
|
};
|
|
7950
8000
|
}
|
|
7951
8001
|
return (d) => {
|
|
@@ -7954,7 +8004,7 @@ var objectsLane = {
|
|
|
7954
8004
|
},
|
|
7955
8005
|
magnets(doc) {
|
|
7956
8006
|
return (doc.objects ?? []).flatMap(
|
|
7957
|
-
(o) => o.span ? [
|
|
8007
|
+
(o) => o.span ? [round11(o.span.start), round11(o.span.start + o.span.duration)] : []
|
|
7958
8008
|
);
|
|
7959
8009
|
}
|
|
7960
8010
|
};
|
|
@@ -7981,7 +8031,7 @@ function nextSpeedId(doc) {
|
|
|
7981
8031
|
function segIndex(id) {
|
|
7982
8032
|
return Number(id.replace("seg-", ""));
|
|
7983
8033
|
}
|
|
7984
|
-
function
|
|
8034
|
+
function round11(v) {
|
|
7985
8035
|
return Math.round(v * 1e3) / 1e3;
|
|
7986
8036
|
}
|
|
7987
8037
|
|