saccade 0.0.3 → 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 +267 -157
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +63 -11
- package/dist/core.d.ts +63 -11
- package/dist/core.mjs +264 -156
- package/dist/core.mjs.map +1 -1
- package/dist/index.cjs +299 -193
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -11
- package/dist/index.d.ts +37 -11
- package/dist/index.mjs +297 -193
- 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/README.md
CHANGED
|
@@ -27,9 +27,48 @@ function App() {
|
|
|
27
27
|
|
|
28
28
|
A floating panel appears in the corner. Use it to control speed, record, and scrub.
|
|
29
29
|
|
|
30
|
+
## Slowing every animation library
|
|
31
|
+
|
|
32
|
+
Saccade slows anything driven by the standard time sources — CSS transitions,
|
|
33
|
+
CSS `@keyframes`, the Web Animations API, `requestAnimationFrame` loops, video
|
|
34
|
+
and audio, and JS libraries that read `Date.now`/`performance.now`/rAF such as
|
|
35
|
+
**Framer Motion**. To reach them all reliably you need two things:
|
|
36
|
+
|
|
37
|
+
### 1. Install before your app code (recommended)
|
|
38
|
+
|
|
39
|
+
Libraries that cache a time function before saccade patches it never see
|
|
40
|
+
slow-mo. Because `<Saccade>` mounts inside React, its patches go in *after*
|
|
41
|
+
anything imported earlier. Import the side-effect entry **first** in your app
|
|
42
|
+
entry so the timing APIs are patched before any other module runs:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// main.tsx — must be the first import
|
|
46
|
+
import 'saccade/install'
|
|
47
|
+
|
|
48
|
+
import { createRoot } from 'react-dom/client'
|
|
49
|
+
import { App } from './App'
|
|
50
|
+
// …
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
This patches the same shared engine `<Saccade>` uses, so the panel still
|
|
54
|
+
controls everything. It's optional — without it, anything imported before
|
|
55
|
+
`<Saccade>` mounts may not slow down.
|
|
56
|
+
|
|
57
|
+
### 2. Register GSAP (ES-module imports only)
|
|
58
|
+
|
|
59
|
+
GSAP is auto-detected when loaded as a global (UMD/CDN). When you `import` it as
|
|
60
|
+
an ES module, `window.gsap` is undefined, so hand saccade your instance once:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { gsap } from 'gsap'
|
|
64
|
+
import { getSharedEngine } from 'saccade'
|
|
65
|
+
|
|
66
|
+
getSharedEngine().registerGSAP(gsap)
|
|
67
|
+
```
|
|
68
|
+
|
|
30
69
|
## Features
|
|
31
70
|
|
|
32
|
-
- **Speed control** — Slow down or speed up all animations
|
|
71
|
+
- **Speed control** — Slow down or speed up all animations: CSS transitions, CSS `@keyframes`, the Web Animations API, `requestAnimationFrame`, JS timers, video/audio, GSAP, and Framer Motion
|
|
33
72
|
- **Timeline recording** — Record interactions, then scrub through captured frames to inspect mid-transition states
|
|
34
73
|
- **LLM export** — Copy structured animation state (properties, keyframes, easing, progress) as markdown for AI coding agents
|
|
35
74
|
- **Shadow DOM isolation** — Panel styles never leak into your app
|
|
@@ -38,13 +77,14 @@ A floating panel appears in the corner. Use it to control speed, record, and scr
|
|
|
38
77
|
|
|
39
78
|
## How it works
|
|
40
79
|
|
|
41
|
-
Saccade patches timing APIs (`setTimeout`, `setInterval`, `requestAnimationFrame`, `performance.now`, `Date.now`) to scale time by a configurable factor. During recording, it snapshots computed styles, attributes, and animation state every frame. In scrub mode, it replays those snapshots by applying inline styles directly to the DOM.
|
|
80
|
+
Saccade patches timing APIs (`setTimeout`, `setInterval`, `requestAnimationFrame`, `performance.now`, `Date.now`) to scale time by a configurable factor — this covers `requestAnimationFrame` loops and time-reading libraries like Framer Motion. CSS transitions, `@keyframes`, and Web Animations API animations are scaled via their `playbackRate`; GSAP via its global timeline `timeScale`. During recording, it snapshots computed styles, attributes, and animation state every frame. In scrub mode, it replays those snapshots by applying inline styles directly to the DOM.
|
|
42
81
|
|
|
43
82
|
## Props
|
|
44
83
|
|
|
45
84
|
| Prop | Type | Default | Description |
|
|
46
85
|
|------|------|---------|-------------|
|
|
47
86
|
| `position` | `'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right'` | `'bottom-left'` | Panel position |
|
|
87
|
+
| `engine` | `SaccadeEngine` | shared singleton | Engine the panel drives. Defaults to the process-wide shared engine, so app code (via `getSharedEngine()`) and the panel control the same instance. Pass your own only to isolate. |
|
|
48
88
|
|
|
49
89
|
## Core API
|
|
50
90
|
|
|
@@ -59,6 +99,13 @@ const engine = new SaccadeEngine()
|
|
|
59
99
|
engine.setSpeed(0.25) // quarter speed
|
|
60
100
|
engine.getSpeed()
|
|
61
101
|
|
|
102
|
+
// Patch timing APIs now, without changing speed (win the early-load race).
|
|
103
|
+
// setSpeed/startRecording also install on demand, so this is only needed up front.
|
|
104
|
+
engine.install()
|
|
105
|
+
|
|
106
|
+
// Register a module-imported GSAP instance (window.gsap fallback otherwise)
|
|
107
|
+
engine.registerGSAP(gsap)
|
|
108
|
+
|
|
62
109
|
// Recording
|
|
63
110
|
engine.startRecording()
|
|
64
111
|
const capture = engine.stopRecording()
|
|
@@ -74,6 +121,22 @@ const markdown = engine.exportForLLM(500, 'active', 'standard')
|
|
|
74
121
|
engine.destroy()
|
|
75
122
|
```
|
|
76
123
|
|
|
124
|
+
### Shared engine
|
|
125
|
+
|
|
126
|
+
`new SaccadeEngine()` gives you an isolated engine. If you also render
|
|
127
|
+
`<Saccade>` and want app code to drive the same one the panel does, use the
|
|
128
|
+
process-wide singleton instead:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { getSharedEngine } from 'saccade' // or 'saccade/core'
|
|
132
|
+
|
|
133
|
+
const engine = getSharedEngine() // same instance <Saccade> uses by default
|
|
134
|
+
engine.setSpeed(0.5)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`saccade/install` installs this shared engine, so importing it and calling
|
|
138
|
+
`getSharedEngine()` always refer to the same instance.
|
|
139
|
+
|
|
77
140
|
## React Hooks
|
|
78
141
|
|
|
79
142
|
```tsx
|