saccade 0.0.2 → 0.0.3
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/README.md +6 -6
- package/dist/core.cjs +72 -57
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +4 -4
- package/dist/core.d.ts +4 -4
- package/dist/core.mjs +71 -56
- package/dist/core.mjs.map +1 -1
- package/dist/index.cjs +103 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -11
- package/dist/index.d.ts +11 -11
- package/dist/index.mjs +99 -80
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/core.d.cts
CHANGED
|
@@ -87,15 +87,15 @@ type TimelineExport = {
|
|
|
87
87
|
}[];
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
-
type
|
|
91
|
-
declare class
|
|
90
|
+
type SaccadeState = 'idle' | 'recording' | 'scrubbing';
|
|
91
|
+
declare class SaccadeEngine {
|
|
92
92
|
private timing;
|
|
93
93
|
private recorder;
|
|
94
94
|
private scrubber;
|
|
95
95
|
private capture;
|
|
96
96
|
private _state;
|
|
97
97
|
private listeners;
|
|
98
|
-
get state():
|
|
98
|
+
get state(): SaccadeState;
|
|
99
99
|
getCapture(): TimelineCapture | null;
|
|
100
100
|
setSpeed(speed: number): void;
|
|
101
101
|
getSpeed(): number;
|
|
@@ -273,4 +273,4 @@ declare function getFrameAtTime(frames: FrameSnapshot[], timeMs: number): FrameS
|
|
|
273
273
|
declare function generateExport(animations: AnimationInfo[], frames: FrameSnapshot[], timeMs: number, filter?: ExportFilter): TimelineExport;
|
|
274
274
|
declare function formatExportForLLM(exp: TimelineExport, detail?: OutputDetailLevel): string;
|
|
275
275
|
|
|
276
|
-
export { type AnimationInfo, type ElementSnapshot, type ExportFilter, type FrameAnimation, type FrameSnapshot, type InterceptedAnimation,
|
|
276
|
+
export { type AnimationInfo, type ElementSnapshot, type ExportFilter, type FrameAnimation, type FrameSnapshot, type InterceptedAnimation, type OutputDetailLevel, type PropertySnapshot, type Rect, SaccadeEngine, type SaccadeState, type ScrubberState, type TimelineCapture, type TimelineExport, TimelineRecorder, TimelineScrubber, TimingController, formatExportForLLM, generateExport, getFrameAtTime };
|
package/dist/core.d.ts
CHANGED
|
@@ -87,15 +87,15 @@ type TimelineExport = {
|
|
|
87
87
|
}[];
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
-
type
|
|
91
|
-
declare class
|
|
90
|
+
type SaccadeState = 'idle' | 'recording' | 'scrubbing';
|
|
91
|
+
declare class SaccadeEngine {
|
|
92
92
|
private timing;
|
|
93
93
|
private recorder;
|
|
94
94
|
private scrubber;
|
|
95
95
|
private capture;
|
|
96
96
|
private _state;
|
|
97
97
|
private listeners;
|
|
98
|
-
get state():
|
|
98
|
+
get state(): SaccadeState;
|
|
99
99
|
getCapture(): TimelineCapture | null;
|
|
100
100
|
setSpeed(speed: number): void;
|
|
101
101
|
getSpeed(): number;
|
|
@@ -273,4 +273,4 @@ declare function getFrameAtTime(frames: FrameSnapshot[], timeMs: number): FrameS
|
|
|
273
273
|
declare function generateExport(animations: AnimationInfo[], frames: FrameSnapshot[], timeMs: number, filter?: ExportFilter): TimelineExport;
|
|
274
274
|
declare function formatExportForLLM(exp: TimelineExport, detail?: OutputDetailLevel): string;
|
|
275
275
|
|
|
276
|
-
export { type AnimationInfo, type ElementSnapshot, type ExportFilter, type FrameAnimation, type FrameSnapshot, type InterceptedAnimation,
|
|
276
|
+
export { type AnimationInfo, type ElementSnapshot, type ExportFilter, type FrameAnimation, type FrameSnapshot, type InterceptedAnimation, type OutputDetailLevel, type PropertySnapshot, type Rect, SaccadeEngine, type SaccadeState, type ScrubberState, type TimelineCapture, type TimelineExport, TimelineRecorder, TimelineScrubber, TimingController, formatExportForLLM, generateExport, getFrameAtTime };
|
package/dist/core.mjs
CHANGED
|
@@ -1021,64 +1021,61 @@ var _TimelineRecorder = class _TimelineRecorder {
|
|
|
1021
1021
|
blocker.title = "Clear the timeline to interact with the page";
|
|
1022
1022
|
document.body.appendChild(blocker);
|
|
1023
1023
|
this.blockerEl = blocker;
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
if (t && (t.includes(":hover") || t.includes(":focus"))) {
|
|
1042
|
-
allCss += t + "\n";
|
|
1024
|
+
setTimeout(() => {
|
|
1025
|
+
try {
|
|
1026
|
+
const lapseStyle = document.createElement("style");
|
|
1027
|
+
lapseStyle.id = "__lapse-state-rules";
|
|
1028
|
+
const hoverFocusRules = [];
|
|
1029
|
+
for (const sheet of document.styleSheets) {
|
|
1030
|
+
try {
|
|
1031
|
+
const walk = (rules) => {
|
|
1032
|
+
for (const rule of rules) {
|
|
1033
|
+
if (rule.cssRules) {
|
|
1034
|
+
walk(rule.cssRules);
|
|
1035
|
+
continue;
|
|
1036
|
+
}
|
|
1037
|
+
const t = rule.cssText;
|
|
1038
|
+
if (t && (t.includes(":hover") || t.includes(":focus"))) {
|
|
1039
|
+
hoverFocusRules.push(t);
|
|
1040
|
+
}
|
|
1043
1041
|
}
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
walk2(sheet.cssRules);
|
|
1048
|
-
} catch (_) {
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
const stateRegex = /([^{}]*(?::hover|:focus-visible|:focus-within|:focus(?!-))[^{}]*)\{([^{}]*)\}/g;
|
|
1052
|
-
let match;
|
|
1053
|
-
while ((match = stateRegex.exec(allCss)) !== null) {
|
|
1054
|
-
const selector = match[1].trim();
|
|
1055
|
-
const body = match[2].trim();
|
|
1056
|
-
if (!body) continue;
|
|
1057
|
-
const newBody = body.replace(
|
|
1058
|
-
/([^;:]+):\s*([^;]+)(;|$)/g,
|
|
1059
|
-
(m, prop, val, end) => {
|
|
1060
|
-
if (val.includes("!important")) return m;
|
|
1061
|
-
return prop + ": " + val.trim() + " !important" + end;
|
|
1042
|
+
};
|
|
1043
|
+
walk(sheet.cssRules);
|
|
1044
|
+
} catch (_) {
|
|
1062
1045
|
}
|
|
1063
|
-
);
|
|
1064
|
-
if (selector.includes(":hover")) {
|
|
1065
|
-
lapseStyle.textContent += selector.replace(/:hover/g, "[data-lapse-hover]") + " { " + newBody + " }\n";
|
|
1066
1046
|
}
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1047
|
+
const parts = [];
|
|
1048
|
+
for (const ruleText of hoverFocusRules) {
|
|
1049
|
+
const braceIdx = ruleText.indexOf("{");
|
|
1050
|
+
if (braceIdx === -1) continue;
|
|
1051
|
+
const selector = ruleText.slice(0, braceIdx).trim();
|
|
1052
|
+
const bodyEnd = ruleText.lastIndexOf("}");
|
|
1053
|
+
const body = ruleText.slice(braceIdx + 1, bodyEnd).trim();
|
|
1054
|
+
if (!body) continue;
|
|
1055
|
+
const newBody = body.replace(
|
|
1056
|
+
/([^;:]+):\s*([^;]+)(;|$)/g,
|
|
1057
|
+
(m, prop, val, end) => {
|
|
1058
|
+
if (val.includes("!important")) return m;
|
|
1059
|
+
return prop + ": " + val.trim() + " !important" + end;
|
|
1060
|
+
}
|
|
1061
|
+
);
|
|
1062
|
+
if (selector.includes(":hover")) {
|
|
1063
|
+
parts.push(selector.replace(/:hover/g, "[data-lapse-hover]") + " { " + newBody + " }");
|
|
1064
|
+
}
|
|
1065
|
+
if (selector.includes(":focus-visible")) {
|
|
1066
|
+
parts.push(selector.replace(/:focus-visible/g, "[data-lapse-focus]") + " { " + newBody + " }");
|
|
1067
|
+
} else if (selector.includes(":focus-within")) {
|
|
1068
|
+
parts.push(selector.replace(/:focus-within/g, ":has([data-lapse-focus])") + " { " + newBody + " }");
|
|
1069
|
+
} else if (selector.includes(":focus")) {
|
|
1070
|
+
parts.push(selector.replace(/:focus(?!-)/g, "[data-lapse-focus]") + " { " + newBody + " }");
|
|
1071
|
+
}
|
|
1076
1072
|
}
|
|
1073
|
+
lapseStyle.textContent = parts.join("\n");
|
|
1074
|
+
document.head.appendChild(lapseStyle);
|
|
1075
|
+
this.lapseStyleEl = lapseStyle;
|
|
1076
|
+
} catch (_) {
|
|
1077
1077
|
}
|
|
1078
|
-
|
|
1079
|
-
this.lapseStyleEl = lapseStyle;
|
|
1080
|
-
} catch (_) {
|
|
1081
|
-
}
|
|
1078
|
+
}, 0);
|
|
1082
1079
|
if (this.frames.length > 0) {
|
|
1083
1080
|
const frame0 = this.frames[0];
|
|
1084
1081
|
if (frame0.elementSnapshots) {
|
|
@@ -1591,7 +1588,7 @@ function formatExportForLLM(exp, detail = "standard") {
|
|
|
1591
1588
|
}
|
|
1592
1589
|
|
|
1593
1590
|
// src/core/engine.ts
|
|
1594
|
-
var
|
|
1591
|
+
var SaccadeEngine = class {
|
|
1595
1592
|
constructor() {
|
|
1596
1593
|
this.timing = new TimingController();
|
|
1597
1594
|
this.recorder = new TimelineRecorder();
|
|
@@ -1633,7 +1630,25 @@ var LapseEngine = class {
|
|
|
1633
1630
|
boundingBox: null
|
|
1634
1631
|
};
|
|
1635
1632
|
}
|
|
1636
|
-
|
|
1633
|
+
let capture;
|
|
1634
|
+
try {
|
|
1635
|
+
capture = this.recorder.stopRecording();
|
|
1636
|
+
} catch (e) {
|
|
1637
|
+
console.error("[Saccade] stopRecording failed:", e);
|
|
1638
|
+
document.getElementById("__lapse-scrub-blocker")?.remove();
|
|
1639
|
+
document.getElementById("__lapse-no-transitions")?.remove();
|
|
1640
|
+
document.getElementById("__lapse-state-rules")?.remove();
|
|
1641
|
+
this._state = "idle";
|
|
1642
|
+
this.notify();
|
|
1643
|
+
return {
|
|
1644
|
+
startTime: 0,
|
|
1645
|
+
endTime: 0,
|
|
1646
|
+
duration: 0,
|
|
1647
|
+
animations: [],
|
|
1648
|
+
frames: [],
|
|
1649
|
+
boundingBox: null
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1637
1652
|
this.capture = capture;
|
|
1638
1653
|
const scrubberState = {
|
|
1639
1654
|
elements: this.recorder.elements,
|
|
@@ -1693,7 +1708,7 @@ var LapseEngine = class {
|
|
|
1693
1708
|
}
|
|
1694
1709
|
};
|
|
1695
1710
|
export {
|
|
1696
|
-
|
|
1711
|
+
SaccadeEngine,
|
|
1697
1712
|
TimelineRecorder,
|
|
1698
1713
|
TimelineScrubber,
|
|
1699
1714
|
TimingController,
|