saccade 0.0.1 → 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
@@ -1004,11 +1004,12 @@ var _TimelineRecorder = class _TimelineRecorder {
1004
1004
  document.removeEventListener("pointerup", this.onPointerUp, true);
1005
1005
  try {
1006
1006
  for (const anim of document.getAnimations()) {
1007
+ const target = anim.effect?.target;
1008
+ if (target?.closest?.("[data-lapse-panel]")) continue;
1007
1009
  anim.cancel();
1008
1010
  }
1009
1011
  } catch (_) {
1010
1012
  }
1011
- window.requestAnimationFrame = () => 0;
1012
1013
  const noTransitions = document.createElement("style");
1013
1014
  noTransitions.id = "__lapse-no-transitions";
1014
1015
  noTransitions.textContent = "*, *::before, *::after { transition: none !important; animation: none !important; }";
@@ -1020,64 +1021,61 @@ var _TimelineRecorder = class _TimelineRecorder {
1020
1021
  blocker.title = "Clear the timeline to interact with the page";
1021
1022
  document.body.appendChild(blocker);
1022
1023
  this.blockerEl = blocker;
1023
- try {
1024
- const lapseStyle = document.createElement("style");
1025
- lapseStyle.id = "__lapse-state-rules";
1026
- let allCss = "";
1027
- for (const style of document.querySelectorAll("style")) {
1028
- if (style.id === "__lapse-state-rules") continue;
1029
- allCss += style.textContent + "\n";
1030
- }
1031
- for (const sheet of document.styleSheets) {
1032
- try {
1033
- let walk2 = function(rules) {
1034
- for (const rule of rules) {
1035
- if (rule.cssRules) {
1036
- walk2(rule.cssRules);
1037
- continue;
1038
- }
1039
- const t = rule.cssText;
1040
- if (t && (t.includes(":hover") || t.includes(":focus"))) {
1041
- 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
+ }
1042
1041
  }
1043
- }
1044
- };
1045
- var walk = walk2;
1046
- walk2(sheet.cssRules);
1047
- } catch (_) {
1048
- }
1049
- }
1050
- const stateRegex = /([^{}]*(?::hover|:focus-visible|:focus-within|:focus(?!-))[^{}]*)\{([^{}]*)\}/g;
1051
- let match;
1052
- while ((match = stateRegex.exec(allCss)) !== null) {
1053
- const selector = match[1].trim();
1054
- const body = match[2].trim();
1055
- if (!body) continue;
1056
- const newBody = body.replace(
1057
- /([^;:]+):\s*([^;]+)(;|$)/g,
1058
- (m, prop, val, end) => {
1059
- if (val.includes("!important")) return m;
1060
- return prop + ": " + val.trim() + " !important" + end;
1042
+ };
1043
+ walk(sheet.cssRules);
1044
+ } catch (_) {
1061
1045
  }
1062
- );
1063
- if (selector.includes(":hover")) {
1064
- lapseStyle.textContent += selector.replace(/:hover/g, "[data-lapse-hover]") + " { " + newBody + " }\n";
1065
1046
  }
1066
- if (selector.includes(":focus-visible")) {
1067
- lapseStyle.textContent += selector.replace(/:focus-visible/g, "[data-lapse-focus]") + " { " + newBody + " }\n";
1068
- } else if (selector.includes(":focus-within")) {
1069
- lapseStyle.textContent += selector.replace(
1070
- /:focus-within/g,
1071
- ":has([data-lapse-focus])"
1072
- ) + " { " + newBody + " }\n";
1073
- } else if (selector.includes(":focus")) {
1074
- 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
+ }
1075
1072
  }
1073
+ lapseStyle.textContent = parts.join("\n");
1074
+ document.head.appendChild(lapseStyle);
1075
+ this.lapseStyleEl = lapseStyle;
1076
+ } catch (_) {
1076
1077
  }
1077
- document.head.appendChild(lapseStyle);
1078
- this.lapseStyleEl = lapseStyle;
1079
- } catch (_) {
1080
- }
1078
+ }, 0);
1081
1079
  if (this.frames.length > 0) {
1082
1080
  const frame0 = this.frames[0];
1083
1081
  if (frame0.elementSnapshots) {
@@ -1590,7 +1588,7 @@ function formatExportForLLM(exp, detail = "standard") {
1590
1588
  }
1591
1589
 
1592
1590
  // src/core/engine.ts
1593
- var LapseEngine = class {
1591
+ var SaccadeEngine = class {
1594
1592
  constructor() {
1595
1593
  this.timing = new TimingController();
1596
1594
  this.recorder = new TimelineRecorder();
@@ -1632,7 +1630,25 @@ var LapseEngine = class {
1632
1630
  boundingBox: null
1633
1631
  };
1634
1632
  }
1635
- 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
+ }
1636
1652
  this.capture = capture;
1637
1653
  const scrubberState = {
1638
1654
  elements: this.recorder.elements,
@@ -1692,7 +1708,7 @@ var LapseEngine = class {
1692
1708
  }
1693
1709
  };
1694
1710
  export {
1695
- LapseEngine,
1711
+ SaccadeEngine,
1696
1712
  TimelineRecorder,
1697
1713
  TimelineScrubber,
1698
1714
  TimingController,