saccade 0.1.0 → 0.2.0
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 +65 -2
- package/dist/core.cjs +54 -13
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +24 -2
- package/dist/core.d.ts +24 -2
- package/dist/core.mjs +51 -12
- package/dist/core.mjs.map +1 -1
- package/dist/index.cjs +71 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -10
- package/dist/index.d.ts +34 -10
- package/dist/index.mjs +69 -25
- package/dist/index.mjs.map +1 -1
- package/dist/install.cjs +1846 -0
- package/dist/install.cjs.map +1 -0
- package/dist/install.d.cts +129 -0
- package/dist/install.d.ts +129 -0
- package/dist/install.mjs +1819 -0
- package/dist/install.mjs.map +1 -0
- package/package.json +12 -1
package/dist/core.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
type ExportFilter = 'active' | 'all-animations' | 'all-elements';
|
|
2
|
-
type OutputDetailLevel = '
|
|
2
|
+
type OutputDetailLevel = 'brief' | 'moderate' | 'detailed' | 'granular';
|
|
3
3
|
type Rect = {
|
|
4
4
|
x: number;
|
|
5
5
|
y: number;
|
|
@@ -101,6 +101,18 @@ declare class SaccadeEngine {
|
|
|
101
101
|
getCapture(): TimelineCapture | null;
|
|
102
102
|
setSpeed(speed: number): void;
|
|
103
103
|
getSpeed(): number;
|
|
104
|
+
/**
|
|
105
|
+
* Install the timing patches immediately, without changing speed.
|
|
106
|
+
*
|
|
107
|
+
* Call this as early as possible (before app code, GSAP, or Framer Motion
|
|
108
|
+
* run) so they capture the patched time functions rather than the originals.
|
|
109
|
+
* Idempotent and harmless to call more than once. `setSpeed` and
|
|
110
|
+
* `startRecording` also install on demand, so this is only needed to win the
|
|
111
|
+
* early-load race against libraries that cache `Date.now`/`performance.now`.
|
|
112
|
+
*/
|
|
113
|
+
install(): void;
|
|
114
|
+
/** Register a module-imported GSAP instance so saccade can slow it. */
|
|
115
|
+
registerGSAP(gsap: any): void;
|
|
104
116
|
startRecording(boundingBox?: Rect | null): void;
|
|
105
117
|
stopRecording(): TimelineCapture;
|
|
106
118
|
seekTo(timeMs: number): void;
|
|
@@ -112,6 +124,10 @@ declare class SaccadeEngine {
|
|
|
112
124
|
destroy(): void;
|
|
113
125
|
}
|
|
114
126
|
|
|
127
|
+
declare function getSharedEngine(): SaccadeEngine;
|
|
128
|
+
/** Test/teardown hook — drops the singleton so the next get() makes a fresh one. */
|
|
129
|
+
declare function resetSharedEngine(): void;
|
|
130
|
+
|
|
115
131
|
/**
|
|
116
132
|
* Timing controller — patches all JS timing APIs to respect a speed factor.
|
|
117
133
|
*
|
|
@@ -129,6 +145,7 @@ declare class TimingController {
|
|
|
129
145
|
private _origAnimate;
|
|
130
146
|
private installed;
|
|
131
147
|
private animPollId;
|
|
148
|
+
private gsapInstance;
|
|
132
149
|
private trackedAnims;
|
|
133
150
|
private trackedMedia;
|
|
134
151
|
private _raf;
|
|
@@ -155,6 +172,11 @@ declare class TimingController {
|
|
|
155
172
|
private patchAnimations;
|
|
156
173
|
/** Patch playbackRate on all video/audio elements. */
|
|
157
174
|
private patchMedia;
|
|
175
|
+
/**
|
|
176
|
+
* Register a GSAP instance (for ES-module imports where window.gsap is
|
|
177
|
+
* undefined). Applies the current timeScale immediately if speed !== 1.
|
|
178
|
+
*/
|
|
179
|
+
registerGSAP(gsap: any): void;
|
|
158
180
|
/** Sync GSAP's global timeline if present. */
|
|
159
181
|
private patchGSAP;
|
|
160
182
|
/** Restore all patched APIs to originals. */
|
|
@@ -303,4 +325,4 @@ declare function getFrameAtTime(frames: FrameSnapshot[], timeMs: number): FrameS
|
|
|
303
325
|
declare function generateExport(animations: AnimationInfo[], frames: FrameSnapshot[], timeMs: number, filter?: ExportFilter): TimelineExport;
|
|
304
326
|
declare function formatExportForLLM(exp: TimelineExport, detail?: OutputDetailLevel): string;
|
|
305
327
|
|
|
306
|
-
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 SeekableClone, type TimelineCapture, type TimelineExport, TimelineRecorder, TimelineScrubber, TimingController, formatExportForLLM, generateExport, getFrameAtTime };
|
|
328
|
+
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 SeekableClone, type TimelineCapture, type TimelineExport, TimelineRecorder, TimelineScrubber, TimingController, formatExportForLLM, generateExport, getFrameAtTime, getSharedEngine, resetSharedEngine };
|
package/dist/core.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
type ExportFilter = 'active' | 'all-animations' | 'all-elements';
|
|
2
|
-
type OutputDetailLevel = '
|
|
2
|
+
type OutputDetailLevel = 'brief' | 'moderate' | 'detailed' | 'granular';
|
|
3
3
|
type Rect = {
|
|
4
4
|
x: number;
|
|
5
5
|
y: number;
|
|
@@ -101,6 +101,18 @@ declare class SaccadeEngine {
|
|
|
101
101
|
getCapture(): TimelineCapture | null;
|
|
102
102
|
setSpeed(speed: number): void;
|
|
103
103
|
getSpeed(): number;
|
|
104
|
+
/**
|
|
105
|
+
* Install the timing patches immediately, without changing speed.
|
|
106
|
+
*
|
|
107
|
+
* Call this as early as possible (before app code, GSAP, or Framer Motion
|
|
108
|
+
* run) so they capture the patched time functions rather than the originals.
|
|
109
|
+
* Idempotent and harmless to call more than once. `setSpeed` and
|
|
110
|
+
* `startRecording` also install on demand, so this is only needed to win the
|
|
111
|
+
* early-load race against libraries that cache `Date.now`/`performance.now`.
|
|
112
|
+
*/
|
|
113
|
+
install(): void;
|
|
114
|
+
/** Register a module-imported GSAP instance so saccade can slow it. */
|
|
115
|
+
registerGSAP(gsap: any): void;
|
|
104
116
|
startRecording(boundingBox?: Rect | null): void;
|
|
105
117
|
stopRecording(): TimelineCapture;
|
|
106
118
|
seekTo(timeMs: number): void;
|
|
@@ -112,6 +124,10 @@ declare class SaccadeEngine {
|
|
|
112
124
|
destroy(): void;
|
|
113
125
|
}
|
|
114
126
|
|
|
127
|
+
declare function getSharedEngine(): SaccadeEngine;
|
|
128
|
+
/** Test/teardown hook — drops the singleton so the next get() makes a fresh one. */
|
|
129
|
+
declare function resetSharedEngine(): void;
|
|
130
|
+
|
|
115
131
|
/**
|
|
116
132
|
* Timing controller — patches all JS timing APIs to respect a speed factor.
|
|
117
133
|
*
|
|
@@ -129,6 +145,7 @@ declare class TimingController {
|
|
|
129
145
|
private _origAnimate;
|
|
130
146
|
private installed;
|
|
131
147
|
private animPollId;
|
|
148
|
+
private gsapInstance;
|
|
132
149
|
private trackedAnims;
|
|
133
150
|
private trackedMedia;
|
|
134
151
|
private _raf;
|
|
@@ -155,6 +172,11 @@ declare class TimingController {
|
|
|
155
172
|
private patchAnimations;
|
|
156
173
|
/** Patch playbackRate on all video/audio elements. */
|
|
157
174
|
private patchMedia;
|
|
175
|
+
/**
|
|
176
|
+
* Register a GSAP instance (for ES-module imports where window.gsap is
|
|
177
|
+
* undefined). Applies the current timeScale immediately if speed !== 1.
|
|
178
|
+
*/
|
|
179
|
+
registerGSAP(gsap: any): void;
|
|
158
180
|
/** Sync GSAP's global timeline if present. */
|
|
159
181
|
private patchGSAP;
|
|
160
182
|
/** Restore all patched APIs to originals. */
|
|
@@ -303,4 +325,4 @@ declare function getFrameAtTime(frames: FrameSnapshot[], timeMs: number): FrameS
|
|
|
303
325
|
declare function generateExport(animations: AnimationInfo[], frames: FrameSnapshot[], timeMs: number, filter?: ExportFilter): TimelineExport;
|
|
304
326
|
declare function formatExportForLLM(exp: TimelineExport, detail?: OutputDetailLevel): string;
|
|
305
327
|
|
|
306
|
-
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 SeekableClone, type TimelineCapture, type TimelineExport, TimelineRecorder, TimelineScrubber, TimingController, formatExportForLLM, generateExport, getFrameAtTime };
|
|
328
|
+
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 SeekableClone, type TimelineCapture, type TimelineExport, TimelineRecorder, TimelineScrubber, TimingController, formatExportForLLM, generateExport, getFrameAtTime, getSharedEngine, resetSharedEngine };
|
package/dist/core.mjs
CHANGED
|
@@ -11,6 +11,7 @@ var TimingController = class {
|
|
|
11
11
|
this._origAnimate = null;
|
|
12
12
|
this.installed = false;
|
|
13
13
|
this.animPollId = 0;
|
|
14
|
+
this.gsapInstance = null;
|
|
14
15
|
// WeakMap tracking for animations and media
|
|
15
16
|
this.trackedAnims = /* @__PURE__ */ new WeakMap();
|
|
16
17
|
this.trackedMedia = /* @__PURE__ */ new WeakMap();
|
|
@@ -186,13 +187,19 @@ var TimingController = class {
|
|
|
186
187
|
} catch {
|
|
187
188
|
}
|
|
188
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Register a GSAP instance (for ES-module imports where window.gsap is
|
|
192
|
+
* undefined). Applies the current timeScale immediately if speed !== 1.
|
|
193
|
+
*/
|
|
194
|
+
registerGSAP(gsap) {
|
|
195
|
+
this.gsapInstance = gsap;
|
|
196
|
+
if (this.speed !== 1) this.patchGSAP();
|
|
197
|
+
}
|
|
189
198
|
/** Sync GSAP's global timeline if present. */
|
|
190
199
|
patchGSAP() {
|
|
191
200
|
try {
|
|
192
|
-
const gsap = window.gsap;
|
|
193
|
-
|
|
194
|
-
gsap.globalTimeline.timeScale(this.speed || 1e-3);
|
|
195
|
-
}
|
|
201
|
+
const gsap = this.gsapInstance ?? window.gsap;
|
|
202
|
+
gsap?.globalTimeline?.timeScale(this.speed || 1e-3);
|
|
196
203
|
} catch {
|
|
197
204
|
}
|
|
198
205
|
}
|
|
@@ -238,10 +245,11 @@ var TimingController = class {
|
|
|
238
245
|
} catch {
|
|
239
246
|
}
|
|
240
247
|
try {
|
|
241
|
-
const gsap = window.gsap;
|
|
242
|
-
|
|
248
|
+
const gsap = this.gsapInstance ?? window.gsap;
|
|
249
|
+
gsap?.globalTimeline?.timeScale(1);
|
|
243
250
|
} catch {
|
|
244
251
|
}
|
|
252
|
+
this.gsapInstance = null;
|
|
245
253
|
delete window.__LAPSE_ORIGINAL_RAF__;
|
|
246
254
|
delete window.__saccadeInstalled;
|
|
247
255
|
this.installed = false;
|
|
@@ -1516,7 +1524,7 @@ function generateExport(animations, frames, timeMs, filter = "active") {
|
|
|
1516
1524
|
animations: animExports
|
|
1517
1525
|
};
|
|
1518
1526
|
}
|
|
1519
|
-
function formatExportForLLM(exp, detail = "
|
|
1527
|
+
function formatExportForLLM(exp, detail = "moderate") {
|
|
1520
1528
|
const lines = [];
|
|
1521
1529
|
const grouped = /* @__PURE__ */ new Map();
|
|
1522
1530
|
for (const anim of exp.animations) {
|
|
@@ -1531,7 +1539,7 @@ function formatExportForLLM(exp, detail = "standard") {
|
|
|
1531
1539
|
const [from, to] = prop.range.split(" \u2192 ");
|
|
1532
1540
|
return !(from && to && from.trim() === to.trim());
|
|
1533
1541
|
}
|
|
1534
|
-
if (detail === "
|
|
1542
|
+
if (detail === "brief") {
|
|
1535
1543
|
lines.push(`# Animation State at ${exp.timestamp}`);
|
|
1536
1544
|
lines.push("");
|
|
1537
1545
|
for (const [, group] of grouped) {
|
|
@@ -1556,7 +1564,7 @@ function formatExportForLLM(exp, detail = "standard") {
|
|
|
1556
1564
|
}
|
|
1557
1565
|
lines.push(`# Animation State at ${exp.timestamp}`);
|
|
1558
1566
|
lines.push("");
|
|
1559
|
-
if (detail === "
|
|
1567
|
+
if (detail === "granular") {
|
|
1560
1568
|
lines.push("**Environment:**");
|
|
1561
1569
|
lines.push(`- Viewport: ${window.innerWidth}\xD7${window.innerHeight}`);
|
|
1562
1570
|
lines.push(`- URL: ${window.location.href}`);
|
|
@@ -1623,7 +1631,7 @@ function formatExportForLLM(exp, detail = "standard") {
|
|
|
1623
1631
|
lines.push(`Transitions: ${[...transitionSet].join(", ")}`);
|
|
1624
1632
|
lines.push("");
|
|
1625
1633
|
for (const line of cssPropLines) lines.push(line);
|
|
1626
|
-
if (detail === "detailed" || detail === "
|
|
1634
|
+
if (detail === "detailed" || detail === "granular") {
|
|
1627
1635
|
const allVars = {};
|
|
1628
1636
|
for (const anim of cssAnims) {
|
|
1629
1637
|
if (anim.resolvedVars) Object.assign(allVars, anim.resolvedVars);
|
|
@@ -1678,6 +1686,22 @@ var SaccadeEngine = class {
|
|
|
1678
1686
|
getSpeed() {
|
|
1679
1687
|
return this.timing.getSpeed();
|
|
1680
1688
|
}
|
|
1689
|
+
/**
|
|
1690
|
+
* Install the timing patches immediately, without changing speed.
|
|
1691
|
+
*
|
|
1692
|
+
* Call this as early as possible (before app code, GSAP, or Framer Motion
|
|
1693
|
+
* run) so they capture the patched time functions rather than the originals.
|
|
1694
|
+
* Idempotent and harmless to call more than once. `setSpeed` and
|
|
1695
|
+
* `startRecording` also install on demand, so this is only needed to win the
|
|
1696
|
+
* early-load race against libraries that cache `Date.now`/`performance.now`.
|
|
1697
|
+
*/
|
|
1698
|
+
install() {
|
|
1699
|
+
this.timing.install();
|
|
1700
|
+
}
|
|
1701
|
+
/** Register a module-imported GSAP instance so saccade can slow it. */
|
|
1702
|
+
registerGSAP(gsap) {
|
|
1703
|
+
this.timing.registerGSAP(gsap);
|
|
1704
|
+
}
|
|
1681
1705
|
// -- Timeline recording ---------------------------------------------------
|
|
1682
1706
|
startRecording(boundingBox) {
|
|
1683
1707
|
if (this._state !== "idle") return;
|
|
@@ -1752,7 +1776,7 @@ var SaccadeEngine = class {
|
|
|
1752
1776
|
filter
|
|
1753
1777
|
);
|
|
1754
1778
|
}
|
|
1755
|
-
exportForLLM(timeMs, filter = "active", detail = "
|
|
1779
|
+
exportForLLM(timeMs, filter = "active", detail = "moderate") {
|
|
1756
1780
|
const exp = this.generateExport(timeMs, filter);
|
|
1757
1781
|
if (!exp) return "";
|
|
1758
1782
|
return formatExportForLLM(exp, detail);
|
|
@@ -1776,6 +1800,19 @@ var SaccadeEngine = class {
|
|
|
1776
1800
|
this._state = "idle";
|
|
1777
1801
|
}
|
|
1778
1802
|
};
|
|
1803
|
+
|
|
1804
|
+
// src/core/shared.ts
|
|
1805
|
+
var KEY = "__saccadeSharedEngine__";
|
|
1806
|
+
function getSharedEngine() {
|
|
1807
|
+
const g = globalThis;
|
|
1808
|
+
if (!g[KEY]) g[KEY] = new SaccadeEngine();
|
|
1809
|
+
return g[KEY];
|
|
1810
|
+
}
|
|
1811
|
+
function resetSharedEngine() {
|
|
1812
|
+
const g = globalThis;
|
|
1813
|
+
g[KEY]?.destroy();
|
|
1814
|
+
g[KEY] = null;
|
|
1815
|
+
}
|
|
1779
1816
|
export {
|
|
1780
1817
|
SaccadeEngine,
|
|
1781
1818
|
TimelineRecorder,
|
|
@@ -1783,6 +1820,8 @@ export {
|
|
|
1783
1820
|
TimingController,
|
|
1784
1821
|
formatExportForLLM,
|
|
1785
1822
|
generateExport,
|
|
1786
|
-
getFrameAtTime
|
|
1823
|
+
getFrameAtTime,
|
|
1824
|
+
getSharedEngine,
|
|
1825
|
+
resetSharedEngine
|
|
1787
1826
|
};
|
|
1788
1827
|
//# sourceMappingURL=core.mjs.map
|