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/dist/core.d.cts CHANGED
@@ -87,15 +87,15 @@ type TimelineExport = {
87
87
  }[];
88
88
  };
89
89
 
90
- type LapseState = 'idle' | 'recording' | 'scrubbing';
91
- declare class LapseEngine {
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(): LapseState;
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, LapseEngine, type LapseState, type OutputDetailLevel, type PropertySnapshot, type Rect, type ScrubberState, type TimelineCapture, type TimelineExport, TimelineRecorder, TimelineScrubber, TimingController, formatExportForLLM, generateExport, getFrameAtTime };
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 LapseState = 'idle' | 'recording' | 'scrubbing';
91
- declare class LapseEngine {
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(): LapseState;
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, LapseEngine, type LapseState, type OutputDetailLevel, type PropertySnapshot, type Rect, type ScrubberState, type TimelineCapture, type TimelineExport, TimelineRecorder, TimelineScrubber, TimingController, formatExportForLLM, generateExport, getFrameAtTime };
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
- try {
1025
- const lapseStyle = document.createElement("style");
1026
- lapseStyle.id = "__lapse-state-rules";
1027
- let allCss = "";
1028
- for (const style of document.querySelectorAll("style")) {
1029
- if (style.id === "__lapse-state-rules") continue;
1030
- allCss += style.textContent + "\n";
1031
- }
1032
- for (const sheet of document.styleSheets) {
1033
- try {
1034
- let walk2 = function(rules) {
1035
- for (const rule of rules) {
1036
- if (rule.cssRules) {
1037
- walk2(rule.cssRules);
1038
- continue;
1039
- }
1040
- const t = rule.cssText;
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
- var walk = walk2;
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
- if (selector.includes(":focus-visible")) {
1068
- lapseStyle.textContent += selector.replace(/:focus-visible/g, "[data-lapse-focus]") + " { " + newBody + " }\n";
1069
- } else if (selector.includes(":focus-within")) {
1070
- lapseStyle.textContent += selector.replace(
1071
- /:focus-within/g,
1072
- ":has([data-lapse-focus])"
1073
- ) + " { " + newBody + " }\n";
1074
- } else if (selector.includes(":focus")) {
1075
- lapseStyle.textContent += selector.replace(/:focus(?!-)/g, "[data-lapse-focus]") + " { " + newBody + " }\n";
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
- document.head.appendChild(lapseStyle);
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 LapseEngine = class {
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
- const capture = this.recorder.stopRecording();
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
- LapseEngine,
1711
+ SaccadeEngine,
1697
1712
  TimelineRecorder,
1698
1713
  TimelineScrubber,
1699
1714
  TimingController,