@vosjs/studio-core 0.30.3 → 0.31.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 +95 -3
- package/dist/index.js +753 -222
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -665,6 +665,527 @@ function projectFromArtifact(artifact, videoUrl, opts = {}) {
|
|
|
665
665
|
return { doc, videoUrl };
|
|
666
666
|
}
|
|
667
667
|
|
|
668
|
+
// src/ingest/traces.ts
|
|
669
|
+
var CLICK_HOLD_MS = 40;
|
|
670
|
+
function traceKindOf(name) {
|
|
671
|
+
const m = /\.([a-z0-9]+)$/i.exec(name);
|
|
672
|
+
const ext = m ? m[1].toLowerCase() : "";
|
|
673
|
+
if (ext === "zip") return "zip";
|
|
674
|
+
if (ext === "csv") return "csv";
|
|
675
|
+
if (ext === "jsonl" || ext === "ndjson") return "jsonl";
|
|
676
|
+
if (ext === "json") return "json";
|
|
677
|
+
if (ext === "trace") return "trace";
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
function cursorFromTrace(name, text, opts = {}) {
|
|
681
|
+
const kind = traceKindOf(name);
|
|
682
|
+
if (kind === "csv") return cursorFromCsv(text, opts);
|
|
683
|
+
if (kind === "trace" || looksLikePlaywright(text))
|
|
684
|
+
return cursorFromPlaywrightTrace(text, opts);
|
|
685
|
+
return cursorFromRecords(text, opts);
|
|
686
|
+
}
|
|
687
|
+
function looksLikePlaywright(text) {
|
|
688
|
+
const head = text.slice(0, 4e3);
|
|
689
|
+
return head.includes('"type":"context-options"') || head.includes('"type":"before"') && head.includes('"callId"');
|
|
690
|
+
}
|
|
691
|
+
function sortEvents(events) {
|
|
692
|
+
return events.map((e, i) => ({ e, i })).sort((a, b) => a.e.t - b.e.t || a.i - b.i).map((x) => x.e);
|
|
693
|
+
}
|
|
694
|
+
function round(n) {
|
|
695
|
+
return Math.round(n * 1e3) / 1e3;
|
|
696
|
+
}
|
|
697
|
+
var PW_PRESS = /* @__PURE__ */ new Set([
|
|
698
|
+
"click",
|
|
699
|
+
"dblclick",
|
|
700
|
+
"tap",
|
|
701
|
+
"check",
|
|
702
|
+
"uncheck",
|
|
703
|
+
"setChecked",
|
|
704
|
+
"selectOption"
|
|
705
|
+
]);
|
|
706
|
+
var PW_TYPE = /* @__PURE__ */ new Set(["fill", "type", "press", "pressSequentially"]);
|
|
707
|
+
function cursorFromPlaywrightTrace(text, opts = {}) {
|
|
708
|
+
const befores = [];
|
|
709
|
+
const afters = /* @__PURE__ */ new Map();
|
|
710
|
+
const inputs = /* @__PURE__ */ new Map();
|
|
711
|
+
let viewport;
|
|
712
|
+
let wallTime;
|
|
713
|
+
let monotonicAtOptions;
|
|
714
|
+
for (const line of text.split("\n")) {
|
|
715
|
+
if (!line.trim()) continue;
|
|
716
|
+
let ev;
|
|
717
|
+
try {
|
|
718
|
+
ev = JSON.parse(line);
|
|
719
|
+
} catch {
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
const type = ev.type;
|
|
723
|
+
if (type === "context-options") {
|
|
724
|
+
const o = ev.options;
|
|
725
|
+
const v = o?.viewport;
|
|
726
|
+
if (v && typeof v.width === "number" && typeof v.height === "number")
|
|
727
|
+
viewport = { width: v.width, height: v.height };
|
|
728
|
+
if (typeof ev.wallTime === "number") wallTime = ev.wallTime;
|
|
729
|
+
if (typeof ev.monotonicTime === "number")
|
|
730
|
+
monotonicAtOptions = ev.monotonicTime;
|
|
731
|
+
} else if (type === "before" && typeof ev.startTime === "number") {
|
|
732
|
+
befores.push({
|
|
733
|
+
callId: String(ev.callId),
|
|
734
|
+
startTime: ev.startTime,
|
|
735
|
+
class: typeof ev.class === "string" ? ev.class : void 0,
|
|
736
|
+
method: typeof ev.method === "string" ? ev.method : void 0,
|
|
737
|
+
params: ev.params && typeof ev.params === "object" ? ev.params : void 0
|
|
738
|
+
});
|
|
739
|
+
} else if (type === "after") {
|
|
740
|
+
afters.set(String(ev.callId), {
|
|
741
|
+
endTime: typeof ev.endTime === "number" ? ev.endTime : void 0,
|
|
742
|
+
point: asPoint(ev.point)
|
|
743
|
+
});
|
|
744
|
+
} else if (type === "input") {
|
|
745
|
+
const p = asPoint(ev.point);
|
|
746
|
+
if (p) inputs.set(String(ev.callId), p);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
const notes = [];
|
|
750
|
+
if (befores.length === 0) {
|
|
751
|
+
return {
|
|
752
|
+
events: [],
|
|
753
|
+
notes: ['not a Playwright trace: no "before" events with a startTime'],
|
|
754
|
+
viewport,
|
|
755
|
+
kind: "playwright",
|
|
756
|
+
placed: 0,
|
|
757
|
+
dropped: 0
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
const newPage = befores.find((b) => b.method === "newPage");
|
|
761
|
+
const origin = newPage?.startTime ?? monotonicAtOptions ?? befores[0].startTime;
|
|
762
|
+
const offset = opts.offsetMs ?? 0;
|
|
763
|
+
const t0 = wallTime !== void 0 && monotonicAtOptions !== void 0 ? Math.round(wallTime + (origin - monotonicAtOptions) - offset) : void 0;
|
|
764
|
+
const at = (ms) => round(ms - origin + offset);
|
|
765
|
+
const events = [];
|
|
766
|
+
const cur = { pos: null };
|
|
767
|
+
let placed = 0;
|
|
768
|
+
let dropped = 0;
|
|
769
|
+
const move2 = (t, p) => {
|
|
770
|
+
if (!cur.pos || cur.pos.x !== p.x || cur.pos.y !== p.y) {
|
|
771
|
+
events.push({ t, x: p.x, y: p.y, type: "move" });
|
|
772
|
+
}
|
|
773
|
+
cur.pos = p;
|
|
774
|
+
};
|
|
775
|
+
const press = (start, end, p, times = 1) => {
|
|
776
|
+
move2(start, p);
|
|
777
|
+
let downAt = Math.max(start, end - CLICK_HOLD_MS);
|
|
778
|
+
for (let i = 0; i < times; i++) {
|
|
779
|
+
events.push({ t: round(downAt), x: p.x, y: p.y, type: "down", button: 0 });
|
|
780
|
+
events.push({
|
|
781
|
+
t: round(downAt + CLICK_HOLD_MS),
|
|
782
|
+
x: p.x,
|
|
783
|
+
y: p.y,
|
|
784
|
+
type: "up",
|
|
785
|
+
button: 0
|
|
786
|
+
});
|
|
787
|
+
downAt += CLICK_HOLD_MS * 2;
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
for (const b of befores) {
|
|
791
|
+
const after = afters.get(b.callId);
|
|
792
|
+
const end = after?.endTime ?? b.startTime;
|
|
793
|
+
const point = after?.point ?? inputs.get(b.callId);
|
|
794
|
+
const method = b.method ?? "";
|
|
795
|
+
const cls = b.class ?? "";
|
|
796
|
+
const start = at(b.startTime);
|
|
797
|
+
const label = `${cls}.${method}`;
|
|
798
|
+
if (cls === "Page" && method === "mouseMove") {
|
|
799
|
+
const p = asPoint(b.params);
|
|
800
|
+
if (!p) {
|
|
801
|
+
notes.push(`${label} at ${start}ms has no x/y`);
|
|
802
|
+
dropped++;
|
|
803
|
+
continue;
|
|
804
|
+
}
|
|
805
|
+
move2(start, p);
|
|
806
|
+
placed++;
|
|
807
|
+
} else if (cls === "Page" && method === "mouseClick") {
|
|
808
|
+
const p = asPoint(b.params) ?? point;
|
|
809
|
+
if (!p) {
|
|
810
|
+
notes.push(`${label} at ${start}ms has no x/y`);
|
|
811
|
+
dropped++;
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
press(start, at(end), p, clickCount(b.params));
|
|
815
|
+
placed++;
|
|
816
|
+
} else if (cls === "Page" && (method === "mouseDown" || method === "mouseUp")) {
|
|
817
|
+
if (!cur.pos) {
|
|
818
|
+
notes.push(`${label} at ${start}ms before any pointer position`);
|
|
819
|
+
dropped++;
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
events.push({
|
|
823
|
+
t: start,
|
|
824
|
+
x: cur.pos.x,
|
|
825
|
+
y: cur.pos.y,
|
|
826
|
+
type: method === "mouseDown" ? "down" : "up",
|
|
827
|
+
button: 0
|
|
828
|
+
});
|
|
829
|
+
placed++;
|
|
830
|
+
} else if (cls === "Page" && method === "mouseWheel") {
|
|
831
|
+
if (!cur.pos) {
|
|
832
|
+
notes.push(`${label} at ${start}ms before any pointer position`);
|
|
833
|
+
dropped++;
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
events.push({ t: start, x: cur.pos.x, y: cur.pos.y, type: "scroll" });
|
|
837
|
+
placed++;
|
|
838
|
+
} else if (cls === "Frame" && method === "hover") {
|
|
839
|
+
if (!point) {
|
|
840
|
+
notes.push(
|
|
841
|
+
`${label} ${selectorOf(b)} at ${start}ms landed nowhere the trace recorded`
|
|
842
|
+
);
|
|
843
|
+
dropped++;
|
|
844
|
+
continue;
|
|
845
|
+
}
|
|
846
|
+
move2(start, point);
|
|
847
|
+
placed++;
|
|
848
|
+
} else if (cls === "Frame" && PW_PRESS.has(method)) {
|
|
849
|
+
if (!point) {
|
|
850
|
+
notes.push(
|
|
851
|
+
`${label} ${selectorOf(b)} at ${start}ms landed nowhere the trace recorded`
|
|
852
|
+
);
|
|
853
|
+
dropped++;
|
|
854
|
+
continue;
|
|
855
|
+
}
|
|
856
|
+
press(start, at(end), point, method === "dblclick" ? 2 : 1);
|
|
857
|
+
placed++;
|
|
858
|
+
} else if (cls === "Frame" && PW_TYPE.has(method)) {
|
|
859
|
+
if (!point && !cur.pos) {
|
|
860
|
+
notes.push(
|
|
861
|
+
`${label} ${selectorOf(b)} at ${start}ms typed into a field the trace never placed`
|
|
862
|
+
);
|
|
863
|
+
dropped++;
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
866
|
+
const p = point ?? cur.pos;
|
|
867
|
+
events.push({ t: start, x: p.x, y: p.y, type: "key" });
|
|
868
|
+
placed++;
|
|
869
|
+
} else if (cls === "Frame" && method === "dragAndDrop") {
|
|
870
|
+
notes.push(
|
|
871
|
+
`${label} at ${start}ms: a drag has two points the trace records as one; not placed`
|
|
872
|
+
);
|
|
873
|
+
dropped++;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
const negative = events.filter((e) => e.t < 0).length;
|
|
877
|
+
if (negative)
|
|
878
|
+
notes.push(`${negative} event(s) before the video's start were dropped`);
|
|
879
|
+
return {
|
|
880
|
+
events: sortEvents(events.filter((e) => e.t >= 0)),
|
|
881
|
+
notes,
|
|
882
|
+
viewport,
|
|
883
|
+
t0,
|
|
884
|
+
kind: "playwright",
|
|
885
|
+
placed,
|
|
886
|
+
dropped
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
function asPoint(v) {
|
|
890
|
+
if (!v || typeof v !== "object") return void 0;
|
|
891
|
+
const o = v;
|
|
892
|
+
return typeof o.x === "number" && typeof o.y === "number" ? { x: o.x, y: o.y } : void 0;
|
|
893
|
+
}
|
|
894
|
+
function clickCount(params) {
|
|
895
|
+
const n = params?.clickCount;
|
|
896
|
+
return typeof n === "number" && n > 1 ? Math.min(3, Math.floor(n)) : 1;
|
|
897
|
+
}
|
|
898
|
+
function selectorOf(b) {
|
|
899
|
+
const s = b.params?.selector;
|
|
900
|
+
return typeof s === "string" ? s : "";
|
|
901
|
+
}
|
|
902
|
+
var CSV_TYPES = /* @__PURE__ */ new Set(["move", "down", "up", "click", "scroll"]);
|
|
903
|
+
function cursorFromCsv(text, opts = {}) {
|
|
904
|
+
const notes = [];
|
|
905
|
+
const events = [];
|
|
906
|
+
const offset = opts.offsetMs ?? 0;
|
|
907
|
+
let placed = 0;
|
|
908
|
+
let dropped = 0;
|
|
909
|
+
const lines = text.split(/\r?\n/);
|
|
910
|
+
let cols = ["t", "x", "y", "type"];
|
|
911
|
+
let start = 0;
|
|
912
|
+
const first = (lines[0] ?? "").split(",").map((c) => c.trim().toLowerCase());
|
|
913
|
+
if (first.length >= 3 && first.some((c) => c !== "" && Number.isNaN(Number(c)))) {
|
|
914
|
+
cols = first;
|
|
915
|
+
start = 1;
|
|
916
|
+
}
|
|
917
|
+
const ti = cols.indexOf("t");
|
|
918
|
+
const xi = cols.indexOf("x");
|
|
919
|
+
const yi = cols.indexOf("y");
|
|
920
|
+
const ki = cols.indexOf("type");
|
|
921
|
+
if (ti < 0 || xi < 0 || yi < 0) {
|
|
922
|
+
return {
|
|
923
|
+
events: [],
|
|
924
|
+
notes: [
|
|
925
|
+
"the CSV needs t, x and y columns (a header row names them; without one the order is t,x,y,type)"
|
|
926
|
+
],
|
|
927
|
+
kind: "csv",
|
|
928
|
+
placed: 0,
|
|
929
|
+
dropped: 0
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
for (let i = start; i < lines.length; i++) {
|
|
933
|
+
const raw = lines[i];
|
|
934
|
+
if (!raw.trim()) continue;
|
|
935
|
+
const cells = raw.split(",").map((c) => c.trim());
|
|
936
|
+
const t = Number(cells[ti]);
|
|
937
|
+
const x = Number(cells[xi]);
|
|
938
|
+
const y = Number(cells[yi]);
|
|
939
|
+
const type = (ki >= 0 ? cells[ki] : "") || "move";
|
|
940
|
+
if (![t, x, y].every(Number.isFinite)) {
|
|
941
|
+
notes.push(`line ${i + 1}: t, x and y must be numbers`);
|
|
942
|
+
dropped++;
|
|
943
|
+
continue;
|
|
944
|
+
}
|
|
945
|
+
if (!CSV_TYPES.has(type)) {
|
|
946
|
+
notes.push(
|
|
947
|
+
`line ${i + 1}: unknown type "${type}" (move, down, up, click, scroll)`
|
|
948
|
+
);
|
|
949
|
+
dropped++;
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
const at = round(t + offset);
|
|
953
|
+
if (type === "click") {
|
|
954
|
+
events.push({ t: at, x, y, type: "move" });
|
|
955
|
+
events.push({ t: at, x, y, type: "down", button: 0 });
|
|
956
|
+
events.push({ t: round(at + CLICK_HOLD_MS), x, y, type: "up", button: 0 });
|
|
957
|
+
} else if (type === "down" || type === "up") {
|
|
958
|
+
events.push({ t: at, x, y, type, button: 0 });
|
|
959
|
+
} else {
|
|
960
|
+
events.push({ t: at, x, y, type });
|
|
961
|
+
}
|
|
962
|
+
placed++;
|
|
963
|
+
}
|
|
964
|
+
return { events: sortEvents(events), notes, kind: "csv", placed, dropped };
|
|
965
|
+
}
|
|
966
|
+
var RECORD_TYPES = {
|
|
967
|
+
move: "move",
|
|
968
|
+
hover: "move",
|
|
969
|
+
down: "down",
|
|
970
|
+
mousedown: "down",
|
|
971
|
+
up: "up",
|
|
972
|
+
mouseup: "up",
|
|
973
|
+
click: "click",
|
|
974
|
+
press: "click",
|
|
975
|
+
scroll: "scroll",
|
|
976
|
+
wheel: "scroll",
|
|
977
|
+
key: "key",
|
|
978
|
+
type: "key",
|
|
979
|
+
fill: "key",
|
|
980
|
+
focus: "focus"
|
|
981
|
+
};
|
|
982
|
+
function cursorFromRecords(input, opts = {}) {
|
|
983
|
+
const notes = [];
|
|
984
|
+
const events = [];
|
|
985
|
+
const offset = opts.offsetMs ?? 0;
|
|
986
|
+
let placed = 0;
|
|
987
|
+
let dropped = 0;
|
|
988
|
+
let records;
|
|
989
|
+
if (typeof input === "string") {
|
|
990
|
+
const trimmed = input.trim();
|
|
991
|
+
if (trimmed.startsWith("[")) {
|
|
992
|
+
try {
|
|
993
|
+
records = JSON.parse(trimmed);
|
|
994
|
+
} catch {
|
|
995
|
+
return {
|
|
996
|
+
events: [],
|
|
997
|
+
notes: ["not JSON: the records file could not be parsed"],
|
|
998
|
+
kind: "records",
|
|
999
|
+
placed: 0,
|
|
1000
|
+
dropped: 0
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
} else {
|
|
1004
|
+
records = [];
|
|
1005
|
+
let n = 0;
|
|
1006
|
+
for (const line of trimmed.split("\n")) {
|
|
1007
|
+
n++;
|
|
1008
|
+
if (!line.trim()) continue;
|
|
1009
|
+
try {
|
|
1010
|
+
records.push(JSON.parse(line));
|
|
1011
|
+
} catch {
|
|
1012
|
+
notes.push(`line ${n}: not JSON`);
|
|
1013
|
+
dropped++;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
} else records = input;
|
|
1018
|
+
let epochZero = null;
|
|
1019
|
+
let sawNoTime = 0;
|
|
1020
|
+
let sawNoPoint = 0;
|
|
1021
|
+
records.forEach((r, i) => {
|
|
1022
|
+
if (!r || typeof r !== "object") {
|
|
1023
|
+
notes.push(`record ${i + 1}: not an object`);
|
|
1024
|
+
dropped++;
|
|
1025
|
+
return;
|
|
1026
|
+
}
|
|
1027
|
+
const o = r;
|
|
1028
|
+
let t = numberOf(o.t ?? o.ts ?? o.time ?? o.timestamp);
|
|
1029
|
+
if (t !== void 0 && t > 1e12) {
|
|
1030
|
+
if (epochZero === null) epochZero = t;
|
|
1031
|
+
t -= epochZero;
|
|
1032
|
+
}
|
|
1033
|
+
const kind = recordKind(o);
|
|
1034
|
+
if (!kind) return;
|
|
1035
|
+
const p = asPoint(o) ?? asPoint(o.point) ?? centerOf(o.rect);
|
|
1036
|
+
if (t === void 0) {
|
|
1037
|
+
sawNoTime++;
|
|
1038
|
+
dropped++;
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
if (!p) {
|
|
1042
|
+
sawNoPoint++;
|
|
1043
|
+
dropped++;
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
const at = round(t + offset);
|
|
1047
|
+
const rect = asRect(o.rect);
|
|
1048
|
+
if (kind === "click") {
|
|
1049
|
+
events.push({ t: at, x: p.x, y: p.y, type: "move" });
|
|
1050
|
+
events.push({
|
|
1051
|
+
t: at,
|
|
1052
|
+
x: p.x,
|
|
1053
|
+
y: p.y,
|
|
1054
|
+
type: "down",
|
|
1055
|
+
button: 0,
|
|
1056
|
+
...rect ? { rect } : {}
|
|
1057
|
+
});
|
|
1058
|
+
events.push({
|
|
1059
|
+
t: round(at + CLICK_HOLD_MS),
|
|
1060
|
+
x: p.x,
|
|
1061
|
+
y: p.y,
|
|
1062
|
+
type: "up",
|
|
1063
|
+
button: 0
|
|
1064
|
+
});
|
|
1065
|
+
} else if (kind === "down" || kind === "up") {
|
|
1066
|
+
events.push({
|
|
1067
|
+
t: at,
|
|
1068
|
+
x: p.x,
|
|
1069
|
+
y: p.y,
|
|
1070
|
+
type: kind,
|
|
1071
|
+
button: 0,
|
|
1072
|
+
...rect ? { rect } : {}
|
|
1073
|
+
});
|
|
1074
|
+
} else {
|
|
1075
|
+
events.push({
|
|
1076
|
+
t: at,
|
|
1077
|
+
x: p.x,
|
|
1078
|
+
y: p.y,
|
|
1079
|
+
type: kind,
|
|
1080
|
+
...rect ? { rect } : {}
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
placed++;
|
|
1084
|
+
});
|
|
1085
|
+
if (sawNoTime)
|
|
1086
|
+
notes.push(
|
|
1087
|
+
`${sawNoTime} gesture record(s) carry no time (t, ts or time, in ms), so they cannot meet the video; agent-browser's own log has none, so stamp one per command when you keep it`
|
|
1088
|
+
);
|
|
1089
|
+
if (sawNoPoint)
|
|
1090
|
+
notes.push(
|
|
1091
|
+
`${sawNoPoint} gesture record(s) carry no point (x/y, point, or rect); a ref alone says which element, not where it was`
|
|
1092
|
+
);
|
|
1093
|
+
return { events: sortEvents(events), notes, kind: "records", placed, dropped };
|
|
1094
|
+
}
|
|
1095
|
+
function recordKind(o) {
|
|
1096
|
+
const explicit = typeof o.type === "string" ? o.type.toLowerCase() : "";
|
|
1097
|
+
if (explicit && explicit in RECORD_TYPES) return RECORD_TYPES[explicit];
|
|
1098
|
+
const cmd = commandWords(o.command ?? o.action ?? o.kind);
|
|
1099
|
+
const verb = cmd[0] === "mouse" ? `${cmd[0]}${cmd[1] ?? ""}` : cmd[0];
|
|
1100
|
+
if (!verb) return null;
|
|
1101
|
+
const key = verb.toLowerCase();
|
|
1102
|
+
if (key in RECORD_TYPES) return RECORD_TYPES[key];
|
|
1103
|
+
if (key === "mousemove") return "move";
|
|
1104
|
+
if (key === "mouseclick") return "click";
|
|
1105
|
+
if (key === "mousedown") return "down";
|
|
1106
|
+
if (key === "mouseup") return "up";
|
|
1107
|
+
if (key === "dblclick") return "click";
|
|
1108
|
+
return null;
|
|
1109
|
+
}
|
|
1110
|
+
function commandWords(v) {
|
|
1111
|
+
if (Array.isArray(v)) return v.map(String);
|
|
1112
|
+
if (typeof v === "string") return v.trim().split(/\s+/);
|
|
1113
|
+
return [];
|
|
1114
|
+
}
|
|
1115
|
+
function numberOf(v) {
|
|
1116
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
1117
|
+
if (typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v)))
|
|
1118
|
+
return Number(v);
|
|
1119
|
+
return void 0;
|
|
1120
|
+
}
|
|
1121
|
+
function asRect(v) {
|
|
1122
|
+
if (!v || typeof v !== "object") return void 0;
|
|
1123
|
+
const o = v;
|
|
1124
|
+
const x = numberOf(o.x);
|
|
1125
|
+
const y = numberOf(o.y);
|
|
1126
|
+
const w = numberOf(o.w ?? o.width);
|
|
1127
|
+
const h = numberOf(o.h ?? o.height);
|
|
1128
|
+
return x !== void 0 && y !== void 0 && w !== void 0 && h !== void 0 ? { x, y, w, h } : void 0;
|
|
1129
|
+
}
|
|
1130
|
+
function centerOf(v) {
|
|
1131
|
+
const r = asRect(v);
|
|
1132
|
+
return r ? { x: r.x + r.w / 2, y: r.y + r.h / 2 } : void 0;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
// src/ingest/zip.ts
|
|
1136
|
+
var EOCD = 101010256;
|
|
1137
|
+
var CENTRAL = 33639248;
|
|
1138
|
+
var LOCAL = 67324752;
|
|
1139
|
+
function zipEntries(bytes) {
|
|
1140
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
1141
|
+
let eocd = -1;
|
|
1142
|
+
for (let i = bytes.length - 22; i >= Math.max(0, bytes.length - 22 - 65535); i--) {
|
|
1143
|
+
if (view.getUint32(i, true) === EOCD) {
|
|
1144
|
+
eocd = i;
|
|
1145
|
+
break;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
if (eocd < 0) throw new Error("not a zip: no end-of-central-directory record");
|
|
1149
|
+
const count = view.getUint16(eocd + 10, true);
|
|
1150
|
+
let p = view.getUint32(eocd + 16, true);
|
|
1151
|
+
const entries = [];
|
|
1152
|
+
const decoder = new TextDecoder();
|
|
1153
|
+
for (let i = 0; i < count; i++) {
|
|
1154
|
+
if (view.getUint32(p, true) !== CENTRAL)
|
|
1155
|
+
throw new Error("not a zip: central directory entry expected");
|
|
1156
|
+
const method = view.getUint16(p + 10, true);
|
|
1157
|
+
const compressedSize = view.getUint32(p + 20, true);
|
|
1158
|
+
const size = view.getUint32(p + 24, true);
|
|
1159
|
+
const nameLen = view.getUint16(p + 28, true);
|
|
1160
|
+
const extraLen = view.getUint16(p + 30, true);
|
|
1161
|
+
const commentLen = view.getUint16(p + 32, true);
|
|
1162
|
+
const local = view.getUint32(p + 42, true);
|
|
1163
|
+
const name = decoder.decode(bytes.subarray(p + 46, p + 46 + nameLen));
|
|
1164
|
+
if (view.getUint32(local, true) !== LOCAL)
|
|
1165
|
+
throw new Error(`not a zip: local header expected for ${name}`);
|
|
1166
|
+
const localNameLen = view.getUint16(local + 26, true);
|
|
1167
|
+
const localExtraLen = view.getUint16(local + 28, true);
|
|
1168
|
+
entries.push({
|
|
1169
|
+
name,
|
|
1170
|
+
method,
|
|
1171
|
+
compressedSize,
|
|
1172
|
+
size,
|
|
1173
|
+
dataOffset: local + 30 + localNameLen + localExtraLen
|
|
1174
|
+
});
|
|
1175
|
+
p += 46 + nameLen + extraLen + commentLen;
|
|
1176
|
+
}
|
|
1177
|
+
return entries;
|
|
1178
|
+
}
|
|
1179
|
+
function zipEntryBytes(bytes, entry) {
|
|
1180
|
+
return bytes.subarray(
|
|
1181
|
+
entry.dataOffset,
|
|
1182
|
+
entry.dataOffset + entry.compressedSize
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
function playwrightTraceEntry(entries) {
|
|
1186
|
+
return entries.find((e) => e.name === "trace.trace") ?? entries.find((e) => /(^|\/)trace\.trace$/.test(e.name)) ?? null;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
668
1189
|
// src/lower/motion.ts
|
|
669
1190
|
import { sortKeyframes } from "@vosjs/timeline";
|
|
670
1191
|
|
|
@@ -1752,7 +2273,7 @@ function planAutoZoom(track, options) {
|
|
|
1752
2273
|
typingMinLevel = style.typingMinLevel,
|
|
1753
2274
|
duration
|
|
1754
2275
|
} = options;
|
|
1755
|
-
const within = (spans2) => duration === void 0 ? spans2 : spans2.map((z) => ({ ...z, out: Math.min(z.out,
|
|
2276
|
+
const within = (spans2) => duration === void 0 ? spans2 : spans2.map((z) => ({ ...z, out: Math.min(z.out, round2(duration)) })).filter((z) => z.out - z.in >= 0.3);
|
|
1756
2277
|
const grouped = groupTrack(track, {
|
|
1757
2278
|
width,
|
|
1758
2279
|
height,
|
|
@@ -1764,17 +2285,17 @@ function planAutoZoom(track, options) {
|
|
|
1764
2285
|
});
|
|
1765
2286
|
const { sessions } = grouped;
|
|
1766
2287
|
const drags = dragsFromTrack(track, width, height);
|
|
1767
|
-
const dragPress = new Set(drags.map((d) =>
|
|
1768
|
-
const withoutDrags = (list) => list.map((cl) => cl.filter((c) => !dragPress.has(
|
|
2288
|
+
const dragPress = new Set(drags.map((d) => round2(d.t0)));
|
|
2289
|
+
const withoutDrags = (list) => list.map((cl) => cl.filter((c) => !dragPress.has(round2(c.t)))).filter((cl) => cl.length > 0);
|
|
1769
2290
|
const clusters = withoutDrags(grouped.clusters);
|
|
1770
2291
|
const surfaces = withoutDrags(grouped.surfaces);
|
|
1771
2292
|
const dragSpans = drags.map((d, i) => ({
|
|
1772
2293
|
id: `g${i}`,
|
|
1773
|
-
in:
|
|
1774
|
-
out:
|
|
2294
|
+
in: round2(Math.max(0, d.t0 - lead)),
|
|
2295
|
+
out: round2(d.t1 + hold),
|
|
1775
2296
|
level: clampZoomLevel(Math.min(Math.max(dragLevel, 1.1), maxLevel)),
|
|
1776
|
-
cx:
|
|
1777
|
-
cy:
|
|
2297
|
+
cx: round2(d.nx),
|
|
2298
|
+
cy: round2(d.ny),
|
|
1778
2299
|
focusMode: "auto",
|
|
1779
2300
|
source: "auto"
|
|
1780
2301
|
}));
|
|
@@ -1851,11 +2372,11 @@ function planAutoZoom(track, options) {
|
|
|
1851
2372
|
typing = typing.filter((t) => t.out - t.in >= 0.3);
|
|
1852
2373
|
const zSpans = clickSpans.filter((s) => !s.dead).sort((a, b) => a.in - b.in).map((s, i) => ({
|
|
1853
2374
|
id: `z${i}`,
|
|
1854
|
-
in:
|
|
1855
|
-
out:
|
|
2375
|
+
in: round2(s.in),
|
|
2376
|
+
out: round2(s.out),
|
|
1856
2377
|
level: clampZoomLevel(s.level),
|
|
1857
|
-
cx:
|
|
1858
|
-
cy:
|
|
2378
|
+
cx: round2(s.cx),
|
|
2379
|
+
cy: round2(s.cy),
|
|
1859
2380
|
// Follow styles ride the cursor through the span (entry + dead-zone
|
|
1860
2381
|
// recenters baked at lowering); typing/dwell spans stay fixed-focus.
|
|
1861
2382
|
...followByDefault ? { focusMode: "auto" } : {},
|
|
@@ -1863,11 +2384,11 @@ function planAutoZoom(track, options) {
|
|
|
1863
2384
|
}));
|
|
1864
2385
|
const kSpans = typing.map((s, i) => ({
|
|
1865
2386
|
id: `k${i}`,
|
|
1866
|
-
in:
|
|
1867
|
-
out:
|
|
2387
|
+
in: round2(s.in),
|
|
2388
|
+
out: round2(s.out),
|
|
1868
2389
|
level: clampZoomLevel(s.level),
|
|
1869
|
-
cx:
|
|
1870
|
-
cy:
|
|
2390
|
+
cx: round2(s.cx),
|
|
2391
|
+
cy: round2(s.cy),
|
|
1871
2392
|
// Never focusMode:'auto': the dot is parked (and fading) while typing —
|
|
1872
2393
|
// the FIELD is the anchor, and a follow would be a no-op at best.
|
|
1873
2394
|
source: "auto"
|
|
@@ -1944,12 +2465,12 @@ function dwellSpans(track, width, height, maxLevel, reserved) {
|
|
|
1944
2465
|
if (taken.some((z) => spanIn < z.out && spanOut > z.in)) continue;
|
|
1945
2466
|
const span = {
|
|
1946
2467
|
id: `d${accepted.length}`,
|
|
1947
|
-
in:
|
|
1948
|
-
out:
|
|
2468
|
+
in: round2(spanIn),
|
|
2469
|
+
out: round2(spanOut),
|
|
1949
2470
|
// No element rect on moves → point zoom at the planner ceiling.
|
|
1950
2471
|
level: clampZoomLevel(maxLevel),
|
|
1951
|
-
cx:
|
|
1952
|
-
cy:
|
|
2472
|
+
cx: round2(clamp012(c.cx)),
|
|
2473
|
+
cy: round2(clamp012(c.cy)),
|
|
1953
2474
|
source: "auto"
|
|
1954
2475
|
};
|
|
1955
2476
|
accepted.push(span);
|
|
@@ -2018,7 +2539,7 @@ function clamp3(v, lo, hi) {
|
|
|
2018
2539
|
function clamp012(v) {
|
|
2019
2540
|
return clamp3(v, 0, 1);
|
|
2020
2541
|
}
|
|
2021
|
-
function
|
|
2542
|
+
function round2(v) {
|
|
2022
2543
|
return Math.round(v * 1e3) / 1e3;
|
|
2023
2544
|
}
|
|
2024
2545
|
|
|
@@ -2858,14 +3379,14 @@ function resolveOverlayFx(clip, clipDuration) {
|
|
|
2858
3379
|
const maxTotal = Math.max(dur, clipDuration * 0.9);
|
|
2859
3380
|
st = Math.min(st, Math.max(0, (maxTotal - dur) / (upperN - 1)));
|
|
2860
3381
|
}
|
|
2861
|
-
const
|
|
3382
|
+
const round14 = (v) => Math.round(v * 1e4) / 1e4;
|
|
2862
3383
|
return {
|
|
2863
3384
|
k: spec.fx,
|
|
2864
3385
|
u: unit,
|
|
2865
3386
|
d: FX_DIR[spec.direction ?? "forward"] ?? 0,
|
|
2866
|
-
st:
|
|
2867
|
-
dur:
|
|
2868
|
-
tt:
|
|
3387
|
+
st: round14(st),
|
|
3388
|
+
dur: round14(dur),
|
|
3389
|
+
tt: round14(st * (upperN - 1) + dur),
|
|
2869
3390
|
units,
|
|
2870
3391
|
n
|
|
2871
3392
|
};
|
|
@@ -3199,10 +3720,10 @@ function followFocusEvents(span, cursor, space, layout, options = {}) {
|
|
|
3199
3720
|
camera
|
|
3200
3721
|
);
|
|
3201
3722
|
pathEvents.push({
|
|
3202
|
-
t:
|
|
3723
|
+
t: round4(at),
|
|
3203
3724
|
path: true,
|
|
3204
|
-
cx:
|
|
3205
|
-
cy:
|
|
3725
|
+
cx: round4(f.cx),
|
|
3726
|
+
cy: round4(f.cy)
|
|
3206
3727
|
});
|
|
3207
3728
|
if (at >= to) break;
|
|
3208
3729
|
}
|
|
@@ -3226,7 +3747,7 @@ function followFocusEvents(span, cursor, space, layout, options = {}) {
|
|
|
3226
3747
|
const target = lookahead > 0 ? sampleAt2(pts, Math.min(p.t + lookahead, span.out)) : p;
|
|
3227
3748
|
const f = clampFocus(target.nx, target.ny, level, layout, camera);
|
|
3228
3749
|
if (Math.abs(f.cx - cx) < 1e-3 && Math.abs(f.cy - cy) < 1e-3) continue;
|
|
3229
|
-
events.push({ t:
|
|
3750
|
+
events.push({ t: round4(p.t), cx: round4(f.cx), cy: round4(f.cy) });
|
|
3230
3751
|
cx = f.cx;
|
|
3231
3752
|
cy = f.cy;
|
|
3232
3753
|
nextAllowed = p.t + recenter;
|
|
@@ -3250,7 +3771,7 @@ function sampleAt2(pts, t) {
|
|
|
3250
3771
|
function clamp014(v) {
|
|
3251
3772
|
return Math.max(0, Math.min(1, v));
|
|
3252
3773
|
}
|
|
3253
|
-
function
|
|
3774
|
+
function round4(v) {
|
|
3254
3775
|
return Math.round(v * 1e3) / 1e3;
|
|
3255
3776
|
}
|
|
3256
3777
|
|
|
@@ -3540,7 +4061,7 @@ function pinPlacement(input) {
|
|
|
3540
4061
|
side,
|
|
3541
4062
|
track: { keyframes: simplify(poses, [W, H, 1, 1, 1]) },
|
|
3542
4063
|
tip: { keyframes: simplify(tips, [W, H]) },
|
|
3543
|
-
clamped:
|
|
4064
|
+
clamped: round5(clamped),
|
|
3544
4065
|
box
|
|
3545
4066
|
};
|
|
3546
4067
|
}
|
|
@@ -3569,13 +4090,13 @@ function simplify(keys, scalePx) {
|
|
|
3569
4090
|
}
|
|
3570
4091
|
}
|
|
3571
4092
|
const last = keys[keys.length - 1];
|
|
3572
|
-
if (out[out.length - 1].t !==
|
|
4093
|
+
if (out[out.length - 1].t !== round5(last.t)) out.push(roundKey(last));
|
|
3573
4094
|
return out;
|
|
3574
4095
|
}
|
|
3575
4096
|
function roundKey(k) {
|
|
3576
|
-
return { t:
|
|
4097
|
+
return { t: round5(k.t), value: k.value.map(round42), ease: k.ease };
|
|
3577
4098
|
}
|
|
3578
|
-
function
|
|
4099
|
+
function round5(v) {
|
|
3579
4100
|
return Math.round(v * 1e3) / 1e3;
|
|
3580
4101
|
}
|
|
3581
4102
|
function round42(v) {
|
|
@@ -3587,7 +4108,7 @@ var CURSOR_IDLE_HOLD = 1;
|
|
|
3587
4108
|
var CURSOR_IDLE_FADE_OUT = 0.35;
|
|
3588
4109
|
var CURSOR_IDLE_FADE_IN = 0.18;
|
|
3589
4110
|
var CURSOR_IDLE_EPS_FRAC = 25e-4;
|
|
3590
|
-
var
|
|
4111
|
+
var round6 = (n) => Math.round(n * 1e3) / 1e3;
|
|
3591
4112
|
function cursorIdleFade(track, o) {
|
|
3592
4113
|
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 }));
|
|
3593
4114
|
if (moves.length === 0) return [];
|
|
@@ -3639,7 +4160,7 @@ function emit(keys, s, e) {
|
|
|
3639
4160
|
push(keys, e + CURSOR_IDLE_FADE_IN, 1);
|
|
3640
4161
|
}
|
|
3641
4162
|
function push(keys, t, a) {
|
|
3642
|
-
const rt =
|
|
4163
|
+
const rt = round6(t);
|
|
3643
4164
|
if (keys.length > 0 && rt <= keys[keys.length - 1].t) {
|
|
3644
4165
|
keys[keys.length - 1].a = a;
|
|
3645
4166
|
return;
|
|
@@ -5147,7 +5668,7 @@ function gatedRect(rect, x, y, space) {
|
|
|
5147
5668
|
return null;
|
|
5148
5669
|
const m = RECT_CONTAIN_MARGIN;
|
|
5149
5670
|
const inside = x >= rect.x - m && x <= rect.x + rect.w + m && y >= rect.y - m && y <= rect.y + rect.h + m;
|
|
5150
|
-
return inside ? [
|
|
5671
|
+
return inside ? [round7(rect.x), round7(rect.y), round7(rect.w), round7(rect.h)] : null;
|
|
5151
5672
|
}
|
|
5152
5673
|
function extractClicks(track, segments, opts) {
|
|
5153
5674
|
const out = [];
|
|
@@ -5172,11 +5693,11 @@ function extractClicks(track, segments, opts) {
|
|
|
5172
5693
|
const upSrc = st + Math.max(pressLen, 0.02);
|
|
5173
5694
|
const up = keptOutputEnd(segments, st, upSrc, opts.media) ?? ot + CLICK_SYNTH_RELEASE;
|
|
5174
5695
|
const click = {
|
|
5175
|
-
ot:
|
|
5176
|
-
up:
|
|
5177
|
-
st:
|
|
5178
|
-
x:
|
|
5179
|
-
y:
|
|
5696
|
+
ot: round7(ot),
|
|
5697
|
+
up: round7(Math.max(up, ot + 0.02)),
|
|
5698
|
+
st: round7(st),
|
|
5699
|
+
x: round7(e.x),
|
|
5700
|
+
y: round7(e.y),
|
|
5180
5701
|
b: button
|
|
5181
5702
|
};
|
|
5182
5703
|
if (opts.rects && e.rect) {
|
|
@@ -5195,7 +5716,7 @@ function hexToRgbTriplet(hex) {
|
|
|
5195
5716
|
const n = parseInt(h, 16);
|
|
5196
5717
|
return [n >> 16, n >> 8 & 255, n & 255];
|
|
5197
5718
|
}
|
|
5198
|
-
function
|
|
5719
|
+
function round7(v) {
|
|
5199
5720
|
return Math.round(v * 1e3) / 1e3;
|
|
5200
5721
|
}
|
|
5201
5722
|
|
|
@@ -5278,7 +5799,7 @@ function trackEmitter() {
|
|
|
5278
5799
|
if (tt <= prev.t + 1e-6 && sameVec(prev.value, value)) return prev.t;
|
|
5279
5800
|
if (tt <= prev.t + 1e-6) tt = prev.t + 1e-3;
|
|
5280
5801
|
}
|
|
5281
|
-
keyframes.push({ t:
|
|
5802
|
+
keyframes.push({ t: round8(tt), value: value.map(round8), ease });
|
|
5282
5803
|
return tt;
|
|
5283
5804
|
};
|
|
5284
5805
|
return { keyframes, push: push2 };
|
|
@@ -7206,24 +7727,25 @@ var ON_FRAME = `(ctx, content, dt) => {
|
|
|
7206
7727
|
var cpH = 2 * ${Math.abs(CARD_Z)} * Math.tan(${CARD_FOV} * Math.PI / 180 / 2)
|
|
7207
7728
|
var cpv = null
|
|
7208
7729
|
if (cpk && cpk.keyframes && cpk.keyframes.length) cpv = TL.sample(cpk, t, TL.lerpArray)
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7730
|
+
// The pose track, then a boundary's enter on top: a slide is an offset
|
|
7731
|
+
// in plane widths and heights, a fade an opacity, a scale both. Outside
|
|
7732
|
+
// both, every term is its rest value.
|
|
7733
|
+
//
|
|
7734
|
+
// EVERY field is written EVERY frame, so the pose is a pure function of
|
|
7735
|
+
// t. A pose restored only when some field looked off-rest kept whatever
|
|
7736
|
+
// the last frame left in the fields it did not look at: a fade moves
|
|
7737
|
+
// opacity alone, so a scrub that jumped out of one mid-window left the
|
|
7738
|
+
// card translucent until something else moved it.
|
|
7739
|
+
var cpS = (cpv ? cpv[0] : 1) * trSc
|
|
7740
|
+
var cpO = (cpv ? cpv[2] : 1) * trOp
|
|
7741
|
+
if (card.mesh.scale) { card.mesh.scale.x = cpS; card.mesh.scale.y = cpS }
|
|
7742
|
+
if (card.mesh.position) {
|
|
7215
7743
|
card.mesh.position.x = trOx * cpH * (W / H)
|
|
7216
7744
|
card.mesh.position.y = ((cpv ? cpv[1] : 0) + trOy) * cpH
|
|
7217
|
-
if (card.mesh.material) card.mesh.material.opacity = cpO
|
|
7218
|
-
// Gone past its clip: the mesh leaves the scene, not just its paint.
|
|
7219
|
-
card.mesh.visible = cpO > 0.001
|
|
7220
|
-
} 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.position.x !== undefined && card.mesh.position.x !== 0) || card.mesh.visible === false)) {
|
|
7221
|
-
card.mesh.scale.x = 1; card.mesh.scale.y = 1
|
|
7222
|
-
card.mesh.position.x = 0
|
|
7223
|
-
card.mesh.position.y = 0
|
|
7224
|
-
if (card.mesh.material) card.mesh.material.opacity = 1
|
|
7225
|
-
card.mesh.visible = true
|
|
7226
7745
|
}
|
|
7746
|
+
if (card.mesh.material) card.mesh.material.opacity = cpO
|
|
7747
|
+
// Gone past its clip: the mesh leaves the scene, not just its paint.
|
|
7748
|
+
card.mesh.visible = cpO > 0.001
|
|
7227
7749
|
var tilted = rx * rx + ry * ry > 1e-6
|
|
7228
7750
|
if (card.texture && card.texture.generateMipmaps !== tilted) {
|
|
7229
7751
|
var THREE2 = ctx.THREE
|
|
@@ -7278,14 +7800,14 @@ function studioLayerData(layers, duration, pins) {
|
|
|
7278
7800
|
// needs a decoded recording, which a sync lowering can't produce.
|
|
7279
7801
|
audio: (layers.audio ?? []).map((c) => ({
|
|
7280
7802
|
key: c.key,
|
|
7281
|
-
start:
|
|
7282
|
-
in:
|
|
7283
|
-
out:
|
|
7284
|
-
gain:
|
|
7803
|
+
start: round8(c.start),
|
|
7804
|
+
in: round8(c.in),
|
|
7805
|
+
out: round8(c.out),
|
|
7806
|
+
gain: round8(c.gain),
|
|
7285
7807
|
loop: !!c.loop,
|
|
7286
|
-
len:
|
|
7808
|
+
len: round8(clipLength(c)),
|
|
7287
7809
|
duck: !!c.duck,
|
|
7288
|
-
env: clipEnvelope(c).map((p) => ({ t:
|
|
7810
|
+
env: clipEnvelope(c).map((p) => ({ t: round8(p.t), g: round8(p.g) }))
|
|
7289
7811
|
})),
|
|
7290
7812
|
// Object clips: numbers resolved HERE; shapes are the drafted engine spec.
|
|
7291
7813
|
...layers.objects && layers.objects.length ? {
|
|
@@ -7298,17 +7820,17 @@ function studioLayerData(layers, duration, pins) {
|
|
|
7298
7820
|
} : o.asset.kind === "text3d" ? resolveText3dAsset(o.asset) : { kind: "gltf", key: o.asset.key },
|
|
7299
7821
|
...o.span ? {
|
|
7300
7822
|
span: {
|
|
7301
|
-
start:
|
|
7302
|
-
duration:
|
|
7823
|
+
start: round8(o.span.start),
|
|
7824
|
+
duration: round8(o.span.duration)
|
|
7303
7825
|
}
|
|
7304
7826
|
} : {},
|
|
7305
|
-
x:
|
|
7306
|
-
y:
|
|
7307
|
-
z:
|
|
7308
|
-
rx:
|
|
7309
|
-
ry:
|
|
7310
|
-
rz:
|
|
7311
|
-
scale:
|
|
7827
|
+
x: round8(o.transform3d.x),
|
|
7828
|
+
y: round8(o.transform3d.y),
|
|
7829
|
+
z: round8(o.transform3d.z),
|
|
7830
|
+
rx: round8(o.transform3d.rx),
|
|
7831
|
+
ry: round8(o.transform3d.ry),
|
|
7832
|
+
rz: round8(o.transform3d.rz),
|
|
7833
|
+
scale: round8(o.transform3d.scale || OBJECT_DEFAULT_SCALE),
|
|
7312
7834
|
anim: idleKey(o),
|
|
7313
7835
|
// Pose keyframes: clip-local [x,y,z,rx,ry,rz,scale] track,
|
|
7314
7836
|
// sampled at t − span.start. Omitted when absent — parity.
|
|
@@ -7335,12 +7857,12 @@ function studioLayerData(layers, duration, pins) {
|
|
|
7335
7857
|
const base = {
|
|
7336
7858
|
id: o.id,
|
|
7337
7859
|
kind: o.kind,
|
|
7338
|
-
start:
|
|
7339
|
-
dur:
|
|
7340
|
-
x:
|
|
7341
|
-
y:
|
|
7342
|
-
scale:
|
|
7343
|
-
rot:
|
|
7860
|
+
start: round8(o.start),
|
|
7861
|
+
dur: round8(Math.max(OVERLAY_MIN_DURATION, o.duration)),
|
|
7862
|
+
x: round8(o.transform.x),
|
|
7863
|
+
y: round8(o.transform.y),
|
|
7864
|
+
scale: round8(o.transform.scale || 1),
|
|
7865
|
+
rot: round8(o.transform.rotation || 0),
|
|
7344
7866
|
enter: enterKey(o),
|
|
7345
7867
|
exit: exitKey(o),
|
|
7346
7868
|
// Pose keyframes: a CLIP-LOCAL [x, y, scale, rot, opacity]
|
|
@@ -7365,10 +7887,10 @@ function studioLayerData(layers, duration, pins) {
|
|
|
7365
7887
|
...base,
|
|
7366
7888
|
kind: "image",
|
|
7367
7889
|
key: hl.key,
|
|
7368
|
-
w:
|
|
7890
|
+
w: round8(hl.width),
|
|
7369
7891
|
radius: 0,
|
|
7370
7892
|
shadow: "none",
|
|
7371
|
-
opacity:
|
|
7893
|
+
opacity: round8(o.opacity ?? 1),
|
|
7372
7894
|
html: hl.html
|
|
7373
7895
|
};
|
|
7374
7896
|
}
|
|
@@ -7385,8 +7907,8 @@ function studioLayerData(layers, duration, pins) {
|
|
|
7385
7907
|
...o.frame.browserBar?.theme ? { theme: o.frame.browserBar.theme } : {}
|
|
7386
7908
|
},
|
|
7387
7909
|
lean: [
|
|
7388
|
-
|
|
7389
|
-
|
|
7910
|
+
round8(o.frame.lean?.rx ?? 0),
|
|
7911
|
+
round8(o.frame.lean?.ry ?? 0)
|
|
7390
7912
|
],
|
|
7391
7913
|
shadow: o.frame.shadow ?? LAYER_CARD_SHADOW,
|
|
7392
7914
|
shadowContact: o.frame.shadowContact ?? 0,
|
|
@@ -7402,17 +7924,17 @@ function studioLayerData(layers, duration, pins) {
|
|
|
7402
7924
|
for (const ev of lm.cursor) {
|
|
7403
7925
|
if (ev.type === "down")
|
|
7404
7926
|
clicks.push({
|
|
7405
|
-
t:
|
|
7406
|
-
x:
|
|
7407
|
-
y:
|
|
7927
|
+
t: round8(ev.t / 1e3),
|
|
7928
|
+
x: round8(ev.x),
|
|
7929
|
+
y: round8(ev.y)
|
|
7408
7930
|
});
|
|
7409
7931
|
}
|
|
7410
7932
|
return {
|
|
7411
7933
|
cur: {
|
|
7412
7934
|
pts: sm.map((p) => ({
|
|
7413
|
-
t:
|
|
7414
|
-
x:
|
|
7415
|
-
y:
|
|
7935
|
+
t: round8(p.t),
|
|
7936
|
+
x: round8(p.x),
|
|
7937
|
+
y: round8(p.y)
|
|
7416
7938
|
})),
|
|
7417
7939
|
space: { w: lm.meta.width, h: lm.meta.height },
|
|
7418
7940
|
size: rec.cursor.size,
|
|
@@ -7427,7 +7949,7 @@ function studioLayerData(layers, duration, pins) {
|
|
|
7427
7949
|
...lm && lm.crop ? { crop: lm.crop } : {},
|
|
7428
7950
|
...lmCard ? { card: lmCard } : {},
|
|
7429
7951
|
...lmFacts,
|
|
7430
|
-
w:
|
|
7952
|
+
w: round8(o.width ?? OVERLAY_MEDIA_DEFAULT_WIDTH),
|
|
7431
7953
|
radius: o.radius ?? OVERLAY_MEDIA_DEFAULT_RADIUS,
|
|
7432
7954
|
opacity: o.opacity ?? 1,
|
|
7433
7955
|
loop: !!o.loop,
|
|
@@ -7437,7 +7959,7 @@ function studioLayerData(layers, duration, pins) {
|
|
|
7437
7959
|
...o.shadow ? { shadow: o.shadow } : {},
|
|
7438
7960
|
...o.border && o.border.width > 0 ? {
|
|
7439
7961
|
border: {
|
|
7440
|
-
width:
|
|
7962
|
+
width: round8(o.border.width),
|
|
7441
7963
|
color: o.border.color
|
|
7442
7964
|
}
|
|
7443
7965
|
} : {}
|
|
@@ -7457,11 +7979,11 @@ function studioLayerData(layers, duration, pins) {
|
|
|
7457
7979
|
// Style-v2 fields bake only when non-default (byte parity for
|
|
7458
7980
|
// older docs); ON_FRAME reads them unconditionally.
|
|
7459
7981
|
...st.fontStyle === "italic" ? { sty: "italic" } : {},
|
|
7460
|
-
...o.maxWidth ? { mw:
|
|
7461
|
-
...st.letterSpacing ? { ls:
|
|
7462
|
-
...st.lineHeight !== OVERLAY_LINE_HEIGHT ? { lh:
|
|
7982
|
+
...o.maxWidth ? { mw: round8(o.maxWidth) } : {},
|
|
7983
|
+
...st.letterSpacing ? { ls: round8(st.letterSpacing) } : {},
|
|
7984
|
+
...st.lineHeight !== OVERLAY_LINE_HEIGHT ? { lh: round8(st.lineHeight) } : {},
|
|
7463
7985
|
...st.align !== "center" ? { align: st.align } : {},
|
|
7464
|
-
...st.stroke ? { stroke: { c: st.stroke.color, w:
|
|
7986
|
+
...st.stroke ? { stroke: { c: st.stroke.color, w: round8(st.stroke.width) } } : {},
|
|
7465
7987
|
// Hosted face behind an override: ON_FRAME lazy-loads it so a
|
|
7466
7988
|
// live family/weight edit paints without a LOAD (SETUP only
|
|
7467
7989
|
// runs on cold load).
|
|
@@ -7474,10 +7996,10 @@ function studioLayerData(layers, duration, pins) {
|
|
|
7474
7996
|
...bx ? {
|
|
7475
7997
|
box: {
|
|
7476
7998
|
c: bx.color,
|
|
7477
|
-
o:
|
|
7478
|
-
px:
|
|
7479
|
-
py:
|
|
7480
|
-
r:
|
|
7999
|
+
o: round8(bx.opacity),
|
|
8000
|
+
px: round8(bx.padX),
|
|
8001
|
+
py: round8(bx.padY),
|
|
8002
|
+
r: round8(bx.radius)
|
|
7481
8003
|
}
|
|
7482
8004
|
} : {},
|
|
7483
8005
|
// Entrance animation: segmentation + timing normalized
|
|
@@ -7549,17 +8071,17 @@ function lowerToComposition(input) {
|
|
|
7549
8071
|
// Rated segments (speed spans pre-intersected): ON_FRAME's mapTime and the
|
|
7550
8072
|
// export's audio splice read the rate straight off each segment.
|
|
7551
8073
|
segments: rated.map((seg) => ({
|
|
7552
|
-
in:
|
|
7553
|
-
out:
|
|
7554
|
-
...seg.rate !== void 0 && seg.rate !== 1 ? { rate:
|
|
8074
|
+
in: round8(seg.in),
|
|
8075
|
+
out: round8(seg.out),
|
|
8076
|
+
...seg.rate !== void 0 && seg.rate !== 1 ? { rate: round8(seg.rate) } : {},
|
|
7555
8077
|
...seg.media ? { media: seg.media } : {}
|
|
7556
8078
|
})),
|
|
7557
8079
|
frame: doc.frame,
|
|
7558
8080
|
micGain: doc.micGain ?? 1,
|
|
7559
8081
|
cursor: smoothed.map((p) => ({
|
|
7560
|
-
t:
|
|
7561
|
-
x:
|
|
7562
|
-
y:
|
|
8082
|
+
t: round8(p.t),
|
|
8083
|
+
x: round8(p.x),
|
|
8084
|
+
y: round8(p.y)
|
|
7563
8085
|
})),
|
|
7564
8086
|
cursorStyle: doc.cursor,
|
|
7565
8087
|
cursorSpace: { w: doc.source.meta.width, h: doc.source.meta.height },
|
|
@@ -7582,9 +8104,9 @@ function lowerToComposition(input) {
|
|
|
7582
8104
|
crop: m.crop ?? null,
|
|
7583
8105
|
hasAudio: !!m.meta.hasAudio,
|
|
7584
8106
|
cursor: sm.map((p) => ({
|
|
7585
|
-
t:
|
|
7586
|
-
x:
|
|
7587
|
-
y:
|
|
8107
|
+
t: round8(p.t),
|
|
8108
|
+
x: round8(p.x),
|
|
8109
|
+
y: round8(p.y)
|
|
7588
8110
|
})),
|
|
7589
8111
|
cursorSpace: { w: m.meta.width, h: m.meta.height },
|
|
7590
8112
|
// The card this media wears (its own placement, bar, corner,
|
|
@@ -7766,8 +8288,8 @@ function pinCandidates(doc, clip) {
|
|
|
7766
8288
|
step: s.id ?? s.step,
|
|
7767
8289
|
do: s.do,
|
|
7768
8290
|
...s.selector ? { selector: s.selector } : {},
|
|
7769
|
-
output: { start:
|
|
7770
|
-
overlap:
|
|
8291
|
+
output: { start: round8(ext.start), end: round8(ext.end) },
|
|
8292
|
+
overlap: round8(overlap)
|
|
7771
8293
|
});
|
|
7772
8294
|
}
|
|
7773
8295
|
return out.sort((x, y) => y.overlap - x.overlap);
|
|
@@ -7798,8 +8320,8 @@ function pinsDataOf(doc, pins) {
|
|
|
7798
8320
|
if (!ref) continue;
|
|
7799
8321
|
out.push({
|
|
7800
8322
|
id: o.id,
|
|
7801
|
-
start:
|
|
7802
|
-
dur:
|
|
8323
|
+
start: round8(o.start),
|
|
8324
|
+
dur: round8(Math.max(OVERLAY_MIN_DURATION, o.duration)),
|
|
7803
8325
|
x: round43(ref.rect.x),
|
|
7804
8326
|
y: round43(ref.rect.y),
|
|
7805
8327
|
w: round43(ref.rect.w),
|
|
@@ -7812,8 +8334,8 @@ function pinsDataOf(doc, pins) {
|
|
|
7812
8334
|
// leader's end with the pointer through [t0, t1], source seconds.
|
|
7813
8335
|
...ref.carry ? {
|
|
7814
8336
|
carry: {
|
|
7815
|
-
t0:
|
|
7816
|
-
t1:
|
|
8337
|
+
t0: round8(ref.carry.t0),
|
|
8338
|
+
t1: round8(ref.carry.t1),
|
|
7817
8339
|
x0: round43(ref.carry.x0),
|
|
7818
8340
|
y0: round43(ref.carry.y0)
|
|
7819
8341
|
}
|
|
@@ -7860,7 +8382,7 @@ function clickFxData(doc, rated) {
|
|
|
7860
8382
|
}
|
|
7861
8383
|
};
|
|
7862
8384
|
}
|
|
7863
|
-
function
|
|
8385
|
+
function round8(v) {
|
|
7864
8386
|
return Math.round(v * 1e3) / 1e3;
|
|
7865
8387
|
}
|
|
7866
8388
|
|
|
@@ -7950,8 +8472,8 @@ function planAutoSpeed(track, opts) {
|
|
|
7950
8472
|
accepted.sort((a, b) => a.in - b.in);
|
|
7951
8473
|
return accepted.map((c, i) => ({
|
|
7952
8474
|
id: `s${i}`,
|
|
7953
|
-
in:
|
|
7954
|
-
out:
|
|
8475
|
+
in: round9(c.in),
|
|
8476
|
+
out: round9(c.out),
|
|
7955
8477
|
rate: clampSpeedRate(c.rate),
|
|
7956
8478
|
source: "auto"
|
|
7957
8479
|
}));
|
|
@@ -8004,7 +8526,7 @@ function collectRuns(evs, gap, minLen, emit2) {
|
|
|
8004
8526
|
}
|
|
8005
8527
|
flush();
|
|
8006
8528
|
}
|
|
8007
|
-
function
|
|
8529
|
+
function round9(v) {
|
|
8008
8530
|
return Math.round(v * 1e3) / 1e3;
|
|
8009
8531
|
}
|
|
8010
8532
|
|
|
@@ -8186,16 +8708,16 @@ function momentsFromDoc(doc, plan, opts = {}) {
|
|
|
8186
8708
|
return {
|
|
8187
8709
|
id: `m${String(i + 1).padStart(2, "0")}`,
|
|
8188
8710
|
kind: d.kind,
|
|
8189
|
-
source: { in:
|
|
8190
|
-
output: output ? { in:
|
|
8191
|
-
at: d.at === null ? null :
|
|
8192
|
-
outputAt: outAt ?
|
|
8193
|
-
focus: d.focus ? { cx:
|
|
8711
|
+
source: { in: round10(d.in), out: round10(d.out) },
|
|
8712
|
+
output: output ? { in: round10(output.start), out: round10(output.end) } : null,
|
|
8713
|
+
at: d.at === null ? null : round10(d.at),
|
|
8714
|
+
outputAt: outAt ? round10(outAt.start) : null,
|
|
8715
|
+
focus: d.focus ? { cx: round10(d.focus.cx), cy: round10(d.focus.cy) } : null,
|
|
8194
8716
|
rect: d.rect ? {
|
|
8195
|
-
x:
|
|
8196
|
-
y:
|
|
8197
|
-
w:
|
|
8198
|
-
h:
|
|
8717
|
+
x: round10(d.rect.x),
|
|
8718
|
+
y: round10(d.rect.y),
|
|
8719
|
+
w: round10(d.rect.w),
|
|
8720
|
+
h: round10(d.rect.h)
|
|
8199
8721
|
} : null,
|
|
8200
8722
|
...d.clicks !== void 0 ? { clicks: d.clicks } : {},
|
|
8201
8723
|
...d.surface ? { surface: true } : {},
|
|
@@ -8216,7 +8738,7 @@ function activityOf(bins, d) {
|
|
|
8216
8738
|
sum += bins[i];
|
|
8217
8739
|
n++;
|
|
8218
8740
|
}
|
|
8219
|
-
return n ?
|
|
8741
|
+
return n ? round10(sum / n) : null;
|
|
8220
8742
|
}
|
|
8221
8743
|
function saidOver(transcript, d) {
|
|
8222
8744
|
if (!transcript?.length) return null;
|
|
@@ -8225,7 +8747,7 @@ function saidOver(transcript, d) {
|
|
|
8225
8747
|
const text = transcript.filter((s) => s.start < hi && s.end > lo).map((s) => s.text.trim()).filter(Boolean).join(" ");
|
|
8226
8748
|
return text || null;
|
|
8227
8749
|
}
|
|
8228
|
-
function
|
|
8750
|
+
function round10(v) {
|
|
8229
8751
|
return Math.round(v * 1e3) / 1e3;
|
|
8230
8752
|
}
|
|
8231
8753
|
|
|
@@ -8732,8 +9254,8 @@ function buildDigest(input) {
|
|
|
8732
9254
|
return {
|
|
8733
9255
|
digestVersion: DIGEST_VERSION,
|
|
8734
9256
|
take: {
|
|
8735
|
-
sourceDuration:
|
|
8736
|
-
outputDuration:
|
|
9257
|
+
sourceDuration: round11(meta.durationMs / 1e3),
|
|
9258
|
+
outputDuration: round11(input.outputDuration),
|
|
8737
9259
|
width: meta.width,
|
|
8738
9260
|
height: meta.height,
|
|
8739
9261
|
captureWidth: meta.captureWidth ?? null,
|
|
@@ -8785,7 +9307,7 @@ function buildDigest(input) {
|
|
|
8785
9307
|
function outputDurationOf(doc) {
|
|
8786
9308
|
return docOutputDuration(doc);
|
|
8787
9309
|
}
|
|
8788
|
-
function
|
|
9310
|
+
function round11(v) {
|
|
8789
9311
|
return Math.round(v * 1e3) / 1e3;
|
|
8790
9312
|
}
|
|
8791
9313
|
|
|
@@ -8811,20 +9333,20 @@ function setSpeedInRange(spans, srcIn, srcOut, rate) {
|
|
|
8811
9333
|
continue;
|
|
8812
9334
|
}
|
|
8813
9335
|
if (srcIn - s.in >= MIN_REMAINDER)
|
|
8814
|
-
kept.push({ ...s, out:
|
|
9336
|
+
kept.push({ ...s, out: round12(srcIn), source: "manual" });
|
|
8815
9337
|
if (s.out - srcOut >= MIN_REMAINDER)
|
|
8816
9338
|
kept.push({
|
|
8817
9339
|
...s,
|
|
8818
9340
|
id: mintId(used),
|
|
8819
|
-
in:
|
|
9341
|
+
in: round12(srcOut),
|
|
8820
9342
|
source: "manual"
|
|
8821
9343
|
});
|
|
8822
9344
|
}
|
|
8823
9345
|
if (rate != null)
|
|
8824
9346
|
kept.push({
|
|
8825
9347
|
id: mintId(used),
|
|
8826
|
-
in:
|
|
8827
|
-
out:
|
|
9348
|
+
in: round12(srcIn),
|
|
9349
|
+
out: round12(srcOut),
|
|
8828
9350
|
rate: clampSpeedRate(rate),
|
|
8829
9351
|
source: "manual"
|
|
8830
9352
|
});
|
|
@@ -8840,9 +9362,9 @@ function removeSourceRange(segments, srcIn, srcOut) {
|
|
|
8840
9362
|
next.push(seg);
|
|
8841
9363
|
continue;
|
|
8842
9364
|
}
|
|
8843
|
-
if (srcIn - seg.in >= MIN_SEGMENT) next.push({ ...seg, out:
|
|
9365
|
+
if (srcIn - seg.in >= MIN_SEGMENT) next.push({ ...seg, out: round12(srcIn) });
|
|
8844
9366
|
if (seg.out - srcOut >= MIN_SEGMENT)
|
|
8845
|
-
next.push({ ...seg, in:
|
|
9367
|
+
next.push({ ...seg, in: round12(srcOut) });
|
|
8846
9368
|
}
|
|
8847
9369
|
return next.length ? next : [...segments];
|
|
8848
9370
|
}
|
|
@@ -8860,8 +9382,8 @@ function zoomSpanForRange(zoom, srcIn, srcOut) {
|
|
|
8860
9382
|
while (used.has(`u${n}`)) n++;
|
|
8861
9383
|
return {
|
|
8862
9384
|
id: `u${n}`,
|
|
8863
|
-
in:
|
|
8864
|
-
out:
|
|
9385
|
+
in: round12(start),
|
|
9386
|
+
out: round12(end),
|
|
8865
9387
|
level: DEFAULT_ZOOM_LEVEL,
|
|
8866
9388
|
cx: 0.5,
|
|
8867
9389
|
cy: 0.5,
|
|
@@ -8875,7 +9397,7 @@ function mintId(used) {
|
|
|
8875
9397
|
used.add(id);
|
|
8876
9398
|
return id;
|
|
8877
9399
|
}
|
|
8878
|
-
function
|
|
9400
|
+
function round12(v) {
|
|
8879
9401
|
return Math.round(v * 1e3) / 1e3;
|
|
8880
9402
|
}
|
|
8881
9403
|
|
|
@@ -9586,8 +10108,8 @@ var videoLane = {
|
|
|
9586
10108
|
return segments.map((s, i) => ({
|
|
9587
10109
|
id: `seg-${i}`,
|
|
9588
10110
|
kind: "clip",
|
|
9589
|
-
t:
|
|
9590
|
-
duration:
|
|
10111
|
+
t: round13(starts[i]),
|
|
10112
|
+
duration: round13(
|
|
9591
10113
|
outputLen(s, speeds, freezes, i === 0 || !contiguous(segments, i))
|
|
9592
10114
|
)
|
|
9593
10115
|
}));
|
|
@@ -9670,7 +10192,7 @@ var videoLane = {
|
|
|
9670
10192
|
if (local >= m.t - 1e-9 && local <= m.t + m.duration + 1e-9)
|
|
9671
10193
|
return null;
|
|
9672
10194
|
}
|
|
9673
|
-
const sourceT =
|
|
10195
|
+
const sourceT = round13(
|
|
9674
10196
|
mapTime3(segmentPieces(s, speeds, freezes, leading), local)
|
|
9675
10197
|
);
|
|
9676
10198
|
if (sourceT - s.in < 0.05 || s.out - sourceT < 0.05) return null;
|
|
@@ -9711,7 +10233,7 @@ var videoLane = {
|
|
|
9711
10233
|
n === 1 || !contiguous(segments, n - 1)
|
|
9712
10234
|
)
|
|
9713
10235
|
] : []
|
|
9714
|
-
].map(
|
|
10236
|
+
].map(round13);
|
|
9715
10237
|
}
|
|
9716
10238
|
};
|
|
9717
10239
|
function nextFreezeId(doc) {
|
|
@@ -9738,8 +10260,8 @@ var freezeLane = {
|
|
|
9738
10260
|
{
|
|
9739
10261
|
id: f.id,
|
|
9740
10262
|
kind: "clip",
|
|
9741
|
-
t:
|
|
9742
|
-
duration:
|
|
10263
|
+
t: round13(m.t),
|
|
10264
|
+
duration: round13(m.duration),
|
|
9743
10265
|
label: `${trimZeros(f.seconds)}s`
|
|
9744
10266
|
}
|
|
9745
10267
|
] : [];
|
|
@@ -9761,7 +10283,7 @@ var freezeLane = {
|
|
|
9761
10283
|
if (g.t >= m.t - 1e-9 && g.t <= m.t + m.duration + 1e-9) return null;
|
|
9762
10284
|
}
|
|
9763
10285
|
if (g.t > totalDuration7(rated) + 1e-9) return null;
|
|
9764
|
-
const srcT =
|
|
10286
|
+
const srcT = round13(mapTime3(rated, Math.max(0, g.t)));
|
|
9765
10287
|
if (!kept(srcT) || !clear(srcT)) return null;
|
|
9766
10288
|
const id = nextFreezeId(doc);
|
|
9767
10289
|
const mediaHere = mediaAtOutput(rated, Math.max(0, g.t));
|
|
@@ -9803,7 +10325,7 @@ var freezeLane = {
|
|
|
9803
10325
|
const marks = freezeOutputExtents(splitBySpeed4(segs, speeds), freezes);
|
|
9804
10326
|
const mine = marks.get(f.id);
|
|
9805
10327
|
const endOut = mine ? mine.t + mine.duration : null;
|
|
9806
|
-
const srcT =
|
|
10328
|
+
const srcT = round13(
|
|
9807
10329
|
Math.min(sourceDuration, mapTime3(base, Math.max(0, g.t)))
|
|
9808
10330
|
);
|
|
9809
10331
|
if (!kept(srcT) || !clear(srcT, f.id)) return null;
|
|
@@ -9863,8 +10385,8 @@ var zoomLane = {
|
|
|
9863
10385
|
{
|
|
9864
10386
|
id: z.id,
|
|
9865
10387
|
kind: "clip",
|
|
9866
|
-
t:
|
|
9867
|
-
duration:
|
|
10388
|
+
t: round13(ext.start),
|
|
10389
|
+
duration: round13(ext.end - ext.start),
|
|
9868
10390
|
label: `${z.level.toFixed(2)}\xD7`
|
|
9869
10391
|
}
|
|
9870
10392
|
];
|
|
@@ -9891,8 +10413,8 @@ var zoomLane = {
|
|
|
9891
10413
|
...d.zoom,
|
|
9892
10414
|
{
|
|
9893
10415
|
id,
|
|
9894
|
-
in:
|
|
9895
|
-
out:
|
|
10416
|
+
in: round13(srcT),
|
|
10417
|
+
out: round13(srcT + len),
|
|
9896
10418
|
level: DEFAULT_ZOOM_LEVEL,
|
|
9897
10419
|
cx,
|
|
9898
10420
|
cy,
|
|
@@ -9924,8 +10446,8 @@ var zoomLane = {
|
|
|
9924
10446
|
return (d) => {
|
|
9925
10447
|
const z = d.zoom.find((x) => x.id === g.id);
|
|
9926
10448
|
if (!z) return;
|
|
9927
|
-
z.in =
|
|
9928
|
-
z.out =
|
|
10449
|
+
z.in = round13(newIn);
|
|
10450
|
+
z.out = round13(newIn + len);
|
|
9929
10451
|
z.source = "manual";
|
|
9930
10452
|
d.zoom.sort((a, b) => a.in - b.in);
|
|
9931
10453
|
};
|
|
@@ -9954,8 +10476,8 @@ var zoomLane = {
|
|
|
9954
10476
|
return (d) => {
|
|
9955
10477
|
const z = d.zoom.find((x) => x.id === g.id);
|
|
9956
10478
|
if (!z) return;
|
|
9957
|
-
z.in =
|
|
9958
|
-
z.out =
|
|
10479
|
+
z.in = round13(next.in);
|
|
10480
|
+
z.out = round13(next.out);
|
|
9959
10481
|
z.source = "manual";
|
|
9960
10482
|
};
|
|
9961
10483
|
}
|
|
@@ -9977,8 +10499,8 @@ function cursorFocusAt(doc, srcT) {
|
|
|
9977
10499
|
if (Math.abs(e.t - ms) < Math.abs(best.t - ms)) best = e;
|
|
9978
10500
|
const clamp015 = (v) => Math.max(0, Math.min(1, v));
|
|
9979
10501
|
return {
|
|
9980
|
-
cx:
|
|
9981
|
-
cy:
|
|
10502
|
+
cx: round13(clamp015(best.x / width)),
|
|
10503
|
+
cy: round13(clamp015(best.y / height))
|
|
9982
10504
|
};
|
|
9983
10505
|
}
|
|
9984
10506
|
var tiltLane = {
|
|
@@ -9992,8 +10514,8 @@ var tiltLane = {
|
|
|
9992
10514
|
{
|
|
9993
10515
|
id: z.id,
|
|
9994
10516
|
kind: "clip",
|
|
9995
|
-
t:
|
|
9996
|
-
duration:
|
|
10517
|
+
t: round13(ext.start),
|
|
10518
|
+
duration: round13(ext.end - ext.start),
|
|
9997
10519
|
label: `${formatDeg(z.rx)}\xB0/${formatDeg(z.ry)}\xB0`
|
|
9998
10520
|
}
|
|
9999
10521
|
];
|
|
@@ -10019,8 +10541,8 @@ var tiltLane = {
|
|
|
10019
10541
|
...d.tilt ?? [],
|
|
10020
10542
|
{
|
|
10021
10543
|
id,
|
|
10022
|
-
in:
|
|
10023
|
-
out:
|
|
10544
|
+
in: round13(srcT),
|
|
10545
|
+
out: round13(srcT + len),
|
|
10024
10546
|
rx: DEFAULT_TILT_POSE.rx,
|
|
10025
10547
|
ry: DEFAULT_TILT_POSE.ry,
|
|
10026
10548
|
source: "manual",
|
|
@@ -10051,8 +10573,8 @@ var tiltLane = {
|
|
|
10051
10573
|
return (d) => {
|
|
10052
10574
|
const z = (d.tilt ?? []).find((x) => x.id === g.id);
|
|
10053
10575
|
if (!z || !d.tilt) return;
|
|
10054
|
-
z.in =
|
|
10055
|
-
z.out =
|
|
10576
|
+
z.in = round13(newIn);
|
|
10577
|
+
z.out = round13(newIn + len);
|
|
10056
10578
|
z.source = "manual";
|
|
10057
10579
|
d.tilt.sort((a, b) => a.in - b.in);
|
|
10058
10580
|
};
|
|
@@ -10081,8 +10603,8 @@ var tiltLane = {
|
|
|
10081
10603
|
return (d) => {
|
|
10082
10604
|
const z = (d.tilt ?? []).find((x) => x.id === g.id);
|
|
10083
10605
|
if (!z) return;
|
|
10084
|
-
z.in =
|
|
10085
|
-
z.out =
|
|
10606
|
+
z.in = round13(next.in);
|
|
10607
|
+
z.out = round13(next.out);
|
|
10086
10608
|
z.source = "manual";
|
|
10087
10609
|
};
|
|
10088
10610
|
}
|
|
@@ -10109,8 +10631,8 @@ var camMoveLane = {
|
|
|
10109
10631
|
{
|
|
10110
10632
|
id: z.id,
|
|
10111
10633
|
kind: "clip",
|
|
10112
|
-
t:
|
|
10113
|
-
duration:
|
|
10634
|
+
t: round13(ext.start),
|
|
10635
|
+
duration: round13(ext.end - ext.start),
|
|
10114
10636
|
label: z.size != null ? `${Math.round(z.size * 100)}%` : "Move"
|
|
10115
10637
|
}
|
|
10116
10638
|
];
|
|
@@ -10134,8 +10656,8 @@ var camMoveLane = {
|
|
|
10134
10656
|
...d.camMotion ?? [],
|
|
10135
10657
|
{
|
|
10136
10658
|
id,
|
|
10137
|
-
in:
|
|
10138
|
-
out:
|
|
10659
|
+
in: round13(srcT),
|
|
10660
|
+
out: round13(srcT + len),
|
|
10139
10661
|
...DEFAULT_CAM_POSE,
|
|
10140
10662
|
source: "manual"
|
|
10141
10663
|
}
|
|
@@ -10164,8 +10686,8 @@ var camMoveLane = {
|
|
|
10164
10686
|
return (d) => {
|
|
10165
10687
|
const z = (d.camMotion ?? []).find((x) => x.id === g.id);
|
|
10166
10688
|
if (!z || !d.camMotion) return;
|
|
10167
|
-
z.in =
|
|
10168
|
-
z.out =
|
|
10689
|
+
z.in = round13(newIn);
|
|
10690
|
+
z.out = round13(newIn + len);
|
|
10169
10691
|
z.source = "manual";
|
|
10170
10692
|
d.camMotion.sort((a, b) => a.in - b.in);
|
|
10171
10693
|
};
|
|
@@ -10194,8 +10716,8 @@ var camMoveLane = {
|
|
|
10194
10716
|
return (d) => {
|
|
10195
10717
|
const z = (d.camMotion ?? []).find((x) => x.id === g.id);
|
|
10196
10718
|
if (!z) return;
|
|
10197
|
-
z.in =
|
|
10198
|
-
z.out =
|
|
10719
|
+
z.in = round13(next.in);
|
|
10720
|
+
z.out = round13(next.out);
|
|
10199
10721
|
z.source = "manual";
|
|
10200
10722
|
};
|
|
10201
10723
|
}
|
|
@@ -10228,10 +10750,10 @@ var camLane = {
|
|
|
10228
10750
|
items.push({
|
|
10229
10751
|
id: `cam-${i}`,
|
|
10230
10752
|
kind: "clip",
|
|
10231
|
-
t:
|
|
10753
|
+
t: round13(
|
|
10232
10754
|
starts[i] + outputLen({ in: s.in, out: a }, speeds, freezes, leading)
|
|
10233
10755
|
),
|
|
10234
|
-
duration:
|
|
10756
|
+
duration: round13(
|
|
10235
10757
|
outputLen({ in: a, out: b }, speeds, freezes, a === s.in && leading)
|
|
10236
10758
|
)
|
|
10237
10759
|
});
|
|
@@ -10260,7 +10782,7 @@ var camLane = {
|
|
|
10260
10782
|
Math.max(first.in, last.out - span)
|
|
10261
10783
|
);
|
|
10262
10784
|
return (d) => {
|
|
10263
|
-
d.cam.window = { in:
|
|
10785
|
+
d.cam.window = { in: round13(newIn), out: round13(newIn + span) };
|
|
10264
10786
|
};
|
|
10265
10787
|
}
|
|
10266
10788
|
const overlapping = eff.map((s, i) => ({
|
|
@@ -10273,8 +10795,8 @@ var camLane = {
|
|
|
10273
10795
|
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) };
|
|
10274
10796
|
return (d) => {
|
|
10275
10797
|
d.cam.window = {
|
|
10276
|
-
in:
|
|
10277
|
-
out:
|
|
10798
|
+
in: round13(Math.max(0, next.in)),
|
|
10799
|
+
out: round13(Math.min(sourceDuration, next.out))
|
|
10278
10800
|
};
|
|
10279
10801
|
};
|
|
10280
10802
|
},
|
|
@@ -10294,8 +10816,8 @@ var micLane = {
|
|
|
10294
10816
|
return segments.map((s, i) => ({
|
|
10295
10817
|
id: `mic-${i}`,
|
|
10296
10818
|
kind: "clip",
|
|
10297
|
-
t:
|
|
10298
|
-
duration:
|
|
10819
|
+
t: round13(starts[i]),
|
|
10820
|
+
duration: round13(
|
|
10299
10821
|
outputLen(s, speeds, freezes, i === 0 || !contiguous(segments, i))
|
|
10300
10822
|
)
|
|
10301
10823
|
}));
|
|
@@ -10351,8 +10873,8 @@ var speedLane = {
|
|
|
10351
10873
|
{
|
|
10352
10874
|
id: sp.id,
|
|
10353
10875
|
kind: "clip",
|
|
10354
|
-
t:
|
|
10355
|
-
duration:
|
|
10876
|
+
t: round13(start),
|
|
10877
|
+
duration: round13(end - start),
|
|
10356
10878
|
label: `${sp.rate}\xD7`
|
|
10357
10879
|
}
|
|
10358
10880
|
];
|
|
@@ -10376,8 +10898,8 @@ var speedLane = {
|
|
|
10376
10898
|
...d.speed ?? [],
|
|
10377
10899
|
{
|
|
10378
10900
|
id,
|
|
10379
|
-
in:
|
|
10380
|
-
out:
|
|
10901
|
+
in: round13(srcT),
|
|
10902
|
+
out: round13(srcT + len),
|
|
10381
10903
|
rate: DEFAULT_SPEED_RATE,
|
|
10382
10904
|
source: "manual",
|
|
10383
10905
|
...mediaHere ? { media: mediaHere } : {}
|
|
@@ -10408,8 +10930,8 @@ var speedLane = {
|
|
|
10408
10930
|
return (d) => {
|
|
10409
10931
|
const s = d.speed?.find((x) => x.id === g.id);
|
|
10410
10932
|
if (!s) return;
|
|
10411
|
-
s.in =
|
|
10412
|
-
s.out =
|
|
10933
|
+
s.in = round13(newIn);
|
|
10934
|
+
s.out = round13(newIn + len);
|
|
10413
10935
|
s.source = "manual";
|
|
10414
10936
|
d.speed.sort((a, b) => a.in - b.in);
|
|
10415
10937
|
};
|
|
@@ -10438,8 +10960,8 @@ var speedLane = {
|
|
|
10438
10960
|
return (d) => {
|
|
10439
10961
|
const s = d.speed?.find((x) => x.id === g.id);
|
|
10440
10962
|
if (!s) return;
|
|
10441
|
-
s.in =
|
|
10442
|
-
s.out =
|
|
10963
|
+
s.in = round13(next.in);
|
|
10964
|
+
s.out = round13(next.out);
|
|
10443
10965
|
s.source = "manual";
|
|
10444
10966
|
};
|
|
10445
10967
|
}
|
|
@@ -10458,8 +10980,8 @@ var audioLane = {
|
|
|
10458
10980
|
return doc.audio.map((c) => ({
|
|
10459
10981
|
id: c.id,
|
|
10460
10982
|
kind: "clip",
|
|
10461
|
-
t:
|
|
10462
|
-
duration:
|
|
10983
|
+
t: round13(c.start),
|
|
10984
|
+
duration: round13(clipLength(c)),
|
|
10463
10985
|
label: c.name
|
|
10464
10986
|
}));
|
|
10465
10987
|
},
|
|
@@ -10470,7 +10992,7 @@ var audioLane = {
|
|
|
10470
10992
|
const start = Math.max(0, g.t);
|
|
10471
10993
|
return (d) => {
|
|
10472
10994
|
const c = d.audio.find((x) => x.id === g.id);
|
|
10473
|
-
if (c) c.start =
|
|
10995
|
+
if (c) c.start = round13(start);
|
|
10474
10996
|
};
|
|
10475
10997
|
}
|
|
10476
10998
|
if (g.type === "resize") {
|
|
@@ -10483,8 +11005,8 @@ var audioLane = {
|
|
|
10483
11005
|
return (d) => {
|
|
10484
11006
|
const c = d.audio.find((x) => x.id === g.id);
|
|
10485
11007
|
if (!c) return;
|
|
10486
|
-
c.start =
|
|
10487
|
-
c.loopLen =
|
|
11008
|
+
c.start = round13(newStart2);
|
|
11009
|
+
c.loopLen = round13(end - newStart2);
|
|
10488
11010
|
};
|
|
10489
11011
|
}
|
|
10490
11012
|
const delta = g.t - clip.start;
|
|
@@ -10493,22 +11015,22 @@ var audioLane = {
|
|
|
10493
11015
|
return (d) => {
|
|
10494
11016
|
const c = d.audio.find((x) => x.id === g.id);
|
|
10495
11017
|
if (!c) return;
|
|
10496
|
-
c.in =
|
|
10497
|
-
c.start =
|
|
11018
|
+
c.in = round13(newIn);
|
|
11019
|
+
c.start = round13(newStart);
|
|
10498
11020
|
};
|
|
10499
11021
|
}
|
|
10500
11022
|
if (clip.loop) {
|
|
10501
11023
|
const newLen = Math.max(0.1, g.t - clip.start);
|
|
10502
11024
|
return (d) => {
|
|
10503
11025
|
const c = d.audio.find((x) => x.id === g.id);
|
|
10504
|
-
if (c) c.loopLen =
|
|
11026
|
+
if (c) c.loopLen = round13(newLen);
|
|
10505
11027
|
};
|
|
10506
11028
|
}
|
|
10507
11029
|
const span = Math.max(0.05, g.t - clip.start);
|
|
10508
11030
|
const newOut = Math.min(clip.in + span, clip.duration);
|
|
10509
11031
|
return (d) => {
|
|
10510
11032
|
const c = d.audio.find((x) => x.id === g.id);
|
|
10511
|
-
if (c) c.out =
|
|
11033
|
+
if (c) c.out = round13(Math.max(c.in + 0.05, newOut));
|
|
10512
11034
|
};
|
|
10513
11035
|
}
|
|
10514
11036
|
if (g.type === "remove") {
|
|
@@ -10521,8 +11043,8 @@ var audioLane = {
|
|
|
10521
11043
|
},
|
|
10522
11044
|
magnets(doc) {
|
|
10523
11045
|
return doc.audio.flatMap((c) => [
|
|
10524
|
-
|
|
10525
|
-
|
|
11046
|
+
round13(c.start),
|
|
11047
|
+
round13(c.start + clipLength(c))
|
|
10526
11048
|
]);
|
|
10527
11049
|
}
|
|
10528
11050
|
};
|
|
@@ -10540,7 +11062,7 @@ function poseItems(clipId, start, duration, motion) {
|
|
|
10540
11062
|
return (motion ?? []).map((p, i) => ({
|
|
10541
11063
|
id: `${clipId}::k${i}`,
|
|
10542
11064
|
kind: "keyframe",
|
|
10543
|
-
t:
|
|
11065
|
+
t: round13(start + Math.min(Math.max(0, p.at), duration))
|
|
10544
11066
|
}));
|
|
10545
11067
|
}
|
|
10546
11068
|
var overlaysLane = {
|
|
@@ -10551,8 +11073,8 @@ var overlaysLane = {
|
|
|
10551
11073
|
{
|
|
10552
11074
|
id: o.id,
|
|
10553
11075
|
kind: "clip",
|
|
10554
|
-
t:
|
|
10555
|
-
duration:
|
|
11076
|
+
t: round13(o.start),
|
|
11077
|
+
duration: round13(o.duration),
|
|
10556
11078
|
label: o.kind === "text" ? o.text.split("\n")[0].slice(0, 24) || "Text" : o.kind === "html" ? htmlLayerLabel(o) : o.kind === "image" ? "Image" : "Video"
|
|
10557
11079
|
},
|
|
10558
11080
|
// Pose diamonds render after the clips, so they sit on top.
|
|
@@ -10572,7 +11094,7 @@ var overlaysLane = {
|
|
|
10572
11094
|
return (d) => {
|
|
10573
11095
|
const o = (d.overlays ?? []).find((x) => x.id === kf.clipId);
|
|
10574
11096
|
const p = o?.motion?.[kf.index];
|
|
10575
|
-
if (p) p.at =
|
|
11097
|
+
if (p) p.at = round13(at);
|
|
10576
11098
|
};
|
|
10577
11099
|
}
|
|
10578
11100
|
if (g.type === "remove") {
|
|
@@ -10601,8 +11123,8 @@ var overlaysLane = {
|
|
|
10601
11123
|
{
|
|
10602
11124
|
id,
|
|
10603
11125
|
kind: "text",
|
|
10604
|
-
start:
|
|
10605
|
-
duration:
|
|
11126
|
+
start: round13(start),
|
|
11127
|
+
duration: round13(len),
|
|
10606
11128
|
text: "Title",
|
|
10607
11129
|
preset: "title",
|
|
10608
11130
|
// Frame fractions: centered, lower-third — at any aspect ratio.
|
|
@@ -10617,7 +11139,7 @@ var overlaysLane = {
|
|
|
10617
11139
|
const start = Math.max(0, g.t);
|
|
10618
11140
|
return (d) => {
|
|
10619
11141
|
const o = (d.overlays ?? []).find((x) => x.id === g.id);
|
|
10620
|
-
if (o) o.start =
|
|
11142
|
+
if (o) o.start = round13(start);
|
|
10621
11143
|
};
|
|
10622
11144
|
}
|
|
10623
11145
|
if (g.type === "resize") {
|
|
@@ -10627,14 +11149,14 @@ var overlaysLane = {
|
|
|
10627
11149
|
return (d) => {
|
|
10628
11150
|
const o = (d.overlays ?? []).find((x) => x.id === g.id);
|
|
10629
11151
|
if (!o) return;
|
|
10630
|
-
o.start =
|
|
10631
|
-
o.duration =
|
|
11152
|
+
o.start = round13(newStart);
|
|
11153
|
+
o.duration = round13(end - newStart);
|
|
10632
11154
|
};
|
|
10633
11155
|
}
|
|
10634
11156
|
const newLen = Math.max(OVERLAY_MIN_DURATION, g.t - clip.start);
|
|
10635
11157
|
return (d) => {
|
|
10636
11158
|
const o = (d.overlays ?? []).find((x) => x.id === g.id);
|
|
10637
|
-
if (o) o.duration =
|
|
11159
|
+
if (o) o.duration = round13(newLen);
|
|
10638
11160
|
};
|
|
10639
11161
|
}
|
|
10640
11162
|
return (d) => {
|
|
@@ -10643,8 +11165,8 @@ var overlaysLane = {
|
|
|
10643
11165
|
},
|
|
10644
11166
|
magnets(doc) {
|
|
10645
11167
|
return (doc.overlays ?? []).flatMap((o) => [
|
|
10646
|
-
|
|
10647
|
-
|
|
11168
|
+
round13(o.start),
|
|
11169
|
+
round13(o.start + o.duration)
|
|
10648
11170
|
]);
|
|
10649
11171
|
}
|
|
10650
11172
|
};
|
|
@@ -10657,8 +11179,8 @@ var objectsLane = {
|
|
|
10657
11179
|
{
|
|
10658
11180
|
id: o.id,
|
|
10659
11181
|
kind: "clip",
|
|
10660
|
-
t:
|
|
10661
|
-
duration:
|
|
11182
|
+
t: round13(o.span?.start ?? 0),
|
|
11183
|
+
duration: round13(o.span?.duration ?? outDur),
|
|
10662
11184
|
label: o.asset.kind === "primitive" ? o.asset.shape : o.asset.kind === "text3d" ? o.asset.text : "model"
|
|
10663
11185
|
},
|
|
10664
11186
|
// Pose diamonds: clip-local `at` from the span start (0 span-less).
|
|
@@ -10686,7 +11208,7 @@ var objectsLane = {
|
|
|
10686
11208
|
return (d) => {
|
|
10687
11209
|
const o = (d.objects ?? []).find((x) => x.id === kf.clipId);
|
|
10688
11210
|
const p = o?.motion?.[kf.index];
|
|
10689
|
-
if (p) p.at =
|
|
11211
|
+
if (p) p.at = round13(at);
|
|
10690
11212
|
};
|
|
10691
11213
|
}
|
|
10692
11214
|
if (g.type === "remove") {
|
|
@@ -10707,7 +11229,7 @@ var objectsLane = {
|
|
|
10707
11229
|
const start = Math.max(0, g.t);
|
|
10708
11230
|
return (d) => {
|
|
10709
11231
|
const o = (d.objects ?? []).find((x) => x.id === g.id);
|
|
10710
|
-
if (o?.span) o.span.start =
|
|
11232
|
+
if (o?.span) o.span.start = round13(start);
|
|
10711
11233
|
};
|
|
10712
11234
|
}
|
|
10713
11235
|
if (g.type === "resize") {
|
|
@@ -10718,14 +11240,14 @@ var objectsLane = {
|
|
|
10718
11240
|
return (d) => {
|
|
10719
11241
|
const o = (d.objects ?? []).find((x) => x.id === g.id);
|
|
10720
11242
|
if (!o?.span) return;
|
|
10721
|
-
o.span.start =
|
|
10722
|
-
o.span.duration =
|
|
11243
|
+
o.span.start = round13(newStart);
|
|
11244
|
+
o.span.duration = round13(end - newStart);
|
|
10723
11245
|
};
|
|
10724
11246
|
}
|
|
10725
11247
|
const newLen = Math.max(OVERLAY_MIN_DURATION, g.t - clip.span.start);
|
|
10726
11248
|
return (d) => {
|
|
10727
11249
|
const o = (d.objects ?? []).find((x) => x.id === g.id);
|
|
10728
|
-
if (o?.span) o.span.duration =
|
|
11250
|
+
if (o?.span) o.span.duration = round13(newLen);
|
|
10729
11251
|
};
|
|
10730
11252
|
}
|
|
10731
11253
|
return (d) => {
|
|
@@ -10734,7 +11256,7 @@ var objectsLane = {
|
|
|
10734
11256
|
},
|
|
10735
11257
|
magnets(doc) {
|
|
10736
11258
|
return (doc.objects ?? []).flatMap(
|
|
10737
|
-
(o) => o.span ? [
|
|
11259
|
+
(o) => o.span ? [round13(o.span.start), round13(o.span.start + o.span.duration)] : []
|
|
10738
11260
|
);
|
|
10739
11261
|
}
|
|
10740
11262
|
};
|
|
@@ -10761,7 +11283,7 @@ function nextSpeedId(doc) {
|
|
|
10761
11283
|
function segIndex(id) {
|
|
10762
11284
|
return Number(id.replace("seg-", ""));
|
|
10763
11285
|
}
|
|
10764
|
-
function
|
|
11286
|
+
function round13(v) {
|
|
10765
11287
|
return Math.round(v * 1e3) / 1e3;
|
|
10766
11288
|
}
|
|
10767
11289
|
|
|
@@ -10929,6 +11451,7 @@ export {
|
|
|
10929
11451
|
CLICK_FX_INTENSITY,
|
|
10930
11452
|
CLICK_FX_PRE,
|
|
10931
11453
|
CLICK_HIGHLIGHT_FADE,
|
|
11454
|
+
CLICK_HOLD_MS,
|
|
10932
11455
|
CLICK_PAIR_MAX,
|
|
10933
11456
|
CLICK_PULSE_DUR,
|
|
10934
11457
|
CLICK_RECT_MAX_FRAC,
|
|
@@ -11111,6 +11634,10 @@ export {
|
|
|
11111
11634
|
cropBox,
|
|
11112
11635
|
cssFamilies,
|
|
11113
11636
|
cssWeights,
|
|
11637
|
+
cursorFromCsv,
|
|
11638
|
+
cursorFromPlaywrightTrace,
|
|
11639
|
+
cursorFromRecords,
|
|
11640
|
+
cursorFromTrace,
|
|
11114
11641
|
cursorIdleFade,
|
|
11115
11642
|
deltaE,
|
|
11116
11643
|
deriveViewportCrop,
|
|
@@ -11239,6 +11766,7 @@ export {
|
|
|
11239
11766
|
planForDigest,
|
|
11240
11767
|
planeSizeAtDepth,
|
|
11241
11768
|
platformBarKind,
|
|
11769
|
+
playwrightTraceEntry,
|
|
11242
11770
|
programDuration,
|
|
11243
11771
|
projectFromArtifact,
|
|
11244
11772
|
pumpFreeChainGap,
|
|
@@ -11274,6 +11802,7 @@ export {
|
|
|
11274
11802
|
studioLayerData,
|
|
11275
11803
|
tiltLane,
|
|
11276
11804
|
tiltTrackFromDoc,
|
|
11805
|
+
traceKindOf,
|
|
11277
11806
|
transitionMult,
|
|
11278
11807
|
transitionSeconds,
|
|
11279
11808
|
unionFitLevel,
|
|
@@ -11286,6 +11815,8 @@ export {
|
|
|
11286
11815
|
withHolds,
|
|
11287
11816
|
withoutRejected,
|
|
11288
11817
|
wrapProgramLength,
|
|
11818
|
+
zipEntries,
|
|
11819
|
+
zipEntryBytes,
|
|
11289
11820
|
zoomCoversRect,
|
|
11290
11821
|
zoomLane,
|
|
11291
11822
|
zoomSpanForRange,
|