@sigx/lynx-motion 0.1.2 → 0.4.1
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/animate.js +234 -0
- package/dist/animate.js.map +1 -0
- package/dist/easings.js +67 -0
- package/dist/easings.js.map +1 -0
- package/dist/index.js +16 -154
- package/dist/index.js.map +1 -1
- package/dist/spring.js +130 -0
- package/dist/spring.js.map +1 -0
- package/dist/with-spring.js +11 -0
- package/dist/with-spring.js.map +1 -0
- package/dist/with-timing.js +13 -0
- package/dist/with-timing.js.map +1 -0
- package/package.json +9 -8
package/dist/animate.js
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation orchestration ported from `@lynx-js/motion/dist/mini/core/animate.js`
|
|
3
|
+
* v0.0.3 (Apache-2.0). Spring solver + easeOut math from
|
|
4
|
+
* `motion-dom` v12.23.12 + `motion-utils` v12.23.6 (also Apache-2.0),
|
|
5
|
+
* inlined directly inside the worklet body.
|
|
6
|
+
*
|
|
7
|
+
* Why everything is inlined inside the function: SWC's worklet transform
|
|
8
|
+
* captures any free identifier referenced by the worklet body into the
|
|
9
|
+
* `_c` map. Plain JS function references at module scope (or sibling
|
|
10
|
+
* imports) don't survive JSON serialization across the MT/BG bridge — they
|
|
11
|
+
* arrive on MT as undefined or stringified placeholders. Upstream
|
|
12
|
+
* motion-mini sidesteps this by making every helper its own `'main thread'`
|
|
13
|
+
* worklet (so the placeholder objects survive). For Phase 2.7 we keep the
|
|
14
|
+
* port simpler by inlining the math straight into the `animate` worklet
|
|
15
|
+
* body, with `inflight` cancellation state tucked on `globalThis` so it's
|
|
16
|
+
* not a free-identifier capture.
|
|
17
|
+
*
|
|
18
|
+
* Sigx-specific adaptations:
|
|
19
|
+
* - Operates on sigx's `SharedValue<number>` (writes `sv.current.value`)
|
|
20
|
+
* instead of motion's `MotionValue`.
|
|
21
|
+
* - Per-SharedValue cancellation tracking via `globalThis.__sigxMotionInflight`.
|
|
22
|
+
* - Uses `globalThis.requestAnimationFrame` (installed by upstream's
|
|
23
|
+
* worklet-runtime IIFE on MT, Lynx SDK ≥ 2.16); falls back to
|
|
24
|
+
* `setTimeout(cb, 16)` otherwise.
|
|
25
|
+
*
|
|
26
|
+
* The standalone modules `easings.ts` and `spring.ts` still ship as a
|
|
27
|
+
* pure-math API for non-worklet callers (tests, BG-side debugging). They
|
|
28
|
+
* are NOT imported by this worklet.
|
|
29
|
+
*/
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Public API — all math inlined inside the worklet body.
|
|
32
|
+
// ============================================================================
|
|
33
|
+
/**
|
|
34
|
+
* Animate a `SharedValue<number>` toward `target`. Returns
|
|
35
|
+
* `{ stop, finished }`. Default is spring; pass `type: 'tween'` or
|
|
36
|
+
* `{ duration }` to use a tween with `easeOut`.
|
|
37
|
+
*/
|
|
38
|
+
export function animate(sv, target, options = {}) {
|
|
39
|
+
'main thread';
|
|
40
|
+
// ─── Inlined: in-flight cancellation map (per-SharedValue) ──────────
|
|
41
|
+
// Stash on globalThis so SWC doesn't capture a module-scope reference
|
|
42
|
+
// into _c. The map persists across animate() calls on MT.
|
|
43
|
+
const g = globalThis;
|
|
44
|
+
if (!g.__sigxMotionInflight)
|
|
45
|
+
g.__sigxMotionInflight = new Map();
|
|
46
|
+
const inflight = g.__sigxMotionInflight;
|
|
47
|
+
const prev = inflight.get(sv._wvid);
|
|
48
|
+
if (prev)
|
|
49
|
+
prev();
|
|
50
|
+
const startValue = sv.current.value;
|
|
51
|
+
const isSpring = options.type === 'spring' ||
|
|
52
|
+
(options.type !== 'tween' && options.duration == null);
|
|
53
|
+
// ─── Inlined: spring solver (motion-dom port, Apache-2.0) ────────────
|
|
54
|
+
// Returns { next(elapsedMs): { done, value } }. Only built when isSpring.
|
|
55
|
+
const buildSolver = () => {
|
|
56
|
+
if (!isSpring)
|
|
57
|
+
return null;
|
|
58
|
+
const stiffness = options.stiffness ?? 100;
|
|
59
|
+
const damping = options.damping ?? 10;
|
|
60
|
+
const mass = options.mass ?? 1;
|
|
61
|
+
const initialVelocity = -((options.velocity ?? 0) / 1000); // ms→s, sign convention
|
|
62
|
+
const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
|
|
63
|
+
const initialDelta = target - startValue;
|
|
64
|
+
const undampedAngularFreq = Math.sqrt(stiffness / mass) / 1000;
|
|
65
|
+
const isGranularScale = Math.abs(initialDelta) < 5;
|
|
66
|
+
const restSpeed = options.restSpeed ?? (isGranularScale ? 0.01 : 2);
|
|
67
|
+
const restDelta = options.restDelta ?? (isGranularScale ? 0.005 : 0.5);
|
|
68
|
+
let resolveSpring;
|
|
69
|
+
if (dampingRatio < 1) {
|
|
70
|
+
const angularFreq = undampedAngularFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
|
|
71
|
+
resolveSpring = (t) => {
|
|
72
|
+
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
|
73
|
+
return target - envelope *
|
|
74
|
+
(((initialVelocity + dampingRatio * undampedAngularFreq * initialDelta) / angularFreq) *
|
|
75
|
+
Math.sin(angularFreq * t) +
|
|
76
|
+
initialDelta * Math.cos(angularFreq * t));
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
else if (dampingRatio === 1) {
|
|
80
|
+
resolveSpring = (t) => target - Math.exp(-undampedAngularFreq * t) *
|
|
81
|
+
(initialDelta + (initialVelocity + undampedAngularFreq * initialDelta) * t);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);
|
|
85
|
+
resolveSpring = (t) => {
|
|
86
|
+
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
|
87
|
+
const freqForT = Math.min(dampedAngularFreq * t, 300);
|
|
88
|
+
return target - (envelope *
|
|
89
|
+
((initialVelocity + dampingRatio * undampedAngularFreq * initialDelta) * Math.sinh(freqForT) +
|
|
90
|
+
dampedAngularFreq * initialDelta * Math.cosh(freqForT))) / dampedAngularFreq;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
// Velocity sample: 5ms-window finite-difference of resolveSpring.
|
|
94
|
+
const calcVelocity = (t, current) => {
|
|
95
|
+
const prevT = Math.max(t - 5, 0);
|
|
96
|
+
const prevVal = resolveSpring(prevT);
|
|
97
|
+
const dt = t - prevT;
|
|
98
|
+
return dt ? (current - prevVal) * (1000 / dt) : 0;
|
|
99
|
+
};
|
|
100
|
+
return (t) => {
|
|
101
|
+
const current = resolveSpring(t);
|
|
102
|
+
let currentVelocity = t === 0 ? initialVelocity : 0;
|
|
103
|
+
if (dampingRatio < 1) {
|
|
104
|
+
currentVelocity = t === 0 ? initialVelocity * 1000 : calcVelocity(t, current);
|
|
105
|
+
}
|
|
106
|
+
const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;
|
|
107
|
+
const isBelowDisplacementThreshold = Math.abs(target - current) <= restDelta;
|
|
108
|
+
const done = isBelowVelocityThreshold && isBelowDisplacementThreshold;
|
|
109
|
+
return { done, value: done ? target : current };
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
const solverNext = buildSolver();
|
|
113
|
+
// ─── Inlined: easeOut (cubicBezier(0, 0, 0.58, 1)) ────────────────────
|
|
114
|
+
const calcBezier = (t, a1, a2) => (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) * t;
|
|
115
|
+
const binarySubdivide = (x, mX1, mX2) => {
|
|
116
|
+
let lo = 0, hi = 1, cT = 0, cX, i = 0;
|
|
117
|
+
do {
|
|
118
|
+
cT = lo + (hi - lo) / 2;
|
|
119
|
+
cX = calcBezier(cT, mX1, mX2) - x;
|
|
120
|
+
if (cX > 0)
|
|
121
|
+
hi = cT;
|
|
122
|
+
else
|
|
123
|
+
lo = cT;
|
|
124
|
+
} while (Math.abs(cX) > 1e-7 && ++i < 12);
|
|
125
|
+
return cT;
|
|
126
|
+
};
|
|
127
|
+
const easeOutDefault = (t) => {
|
|
128
|
+
if (t === 0 || t === 1)
|
|
129
|
+
return t;
|
|
130
|
+
return calcBezier(binarySubdivide(t, 0, 0.58), 0, 1);
|
|
131
|
+
};
|
|
132
|
+
const duration = options.duration ?? 0.3;
|
|
133
|
+
const startTime = Date.now();
|
|
134
|
+
let canceled = false;
|
|
135
|
+
let resolvePromise;
|
|
136
|
+
let settled = false;
|
|
137
|
+
const finished = new Promise((resolve) => { resolvePromise = resolve; });
|
|
138
|
+
const settle = () => {
|
|
139
|
+
if (settled)
|
|
140
|
+
return;
|
|
141
|
+
settled = true;
|
|
142
|
+
if (inflight.get(sv._wvid) === stop)
|
|
143
|
+
inflight.delete(sv._wvid);
|
|
144
|
+
resolvePromise?.();
|
|
145
|
+
};
|
|
146
|
+
const stop = () => {
|
|
147
|
+
if (canceled)
|
|
148
|
+
return;
|
|
149
|
+
canceled = true;
|
|
150
|
+
settle();
|
|
151
|
+
};
|
|
152
|
+
inflight.set(sv._wvid, stop);
|
|
153
|
+
// ─── Inlined: tick scheduler ──────────────────────────────────────────
|
|
154
|
+
// `globalThis.requestAnimationFrame` is installed by upstream's
|
|
155
|
+
// worklet-runtime IIFE on MT; falls back to `setTimeout(cb, 16)` when
|
|
156
|
+
// unavailable (older SDKs, test environments).
|
|
157
|
+
const rafGlobal = globalThis;
|
|
158
|
+
const scheduleNext = (cb) => {
|
|
159
|
+
if (typeof rafGlobal.requestAnimationFrame === 'function') {
|
|
160
|
+
rafGlobal.requestAnimationFrame(cb);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
setTimeout(cb, 16);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
// ─── Flush trigger (microtask-debounced) ─────────────────────────────
|
|
167
|
+
// Writing `sv.current.value` is a plain ref mutation — it doesn't
|
|
168
|
+
// schedule the native flush by itself. Without a flush, the SharedValue
|
|
169
|
+
// bridge never publishes the new value to BG and `useAnimatedStyle`
|
|
170
|
+
// bindings never apply.
|
|
171
|
+
//
|
|
172
|
+
// We coalesce calls via a `globalThis.__sigxMotionFlushScheduled` flag:
|
|
173
|
+
// multiple ticks across multiple concurrent animations within the same
|
|
174
|
+
// microtask boundary all set the flag, the first one schedules the
|
|
175
|
+
// microtask, the rest see the flag and bail. End result: ONE flush per
|
|
176
|
+
// microtask regardless of how many animations are live. Same pattern
|
|
177
|
+
// upstream's `MTElementWrapper.flushElementTree` uses.
|
|
178
|
+
const flushTree = () => {
|
|
179
|
+
const g = globalThis;
|
|
180
|
+
if (g['__sigxMotionFlushScheduled'])
|
|
181
|
+
return;
|
|
182
|
+
g['__sigxMotionFlushScheduled'] = true;
|
|
183
|
+
Promise.resolve().then(() => {
|
|
184
|
+
g['__sigxMotionFlushScheduled'] = false;
|
|
185
|
+
const fn = g['__FlushElementTree'];
|
|
186
|
+
if (fn)
|
|
187
|
+
fn();
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
const tick = () => {
|
|
191
|
+
if (canceled)
|
|
192
|
+
return;
|
|
193
|
+
const now = Date.now();
|
|
194
|
+
const elapsedMs = now - startTime;
|
|
195
|
+
const elapsedSec = elapsedMs / 1000;
|
|
196
|
+
let current;
|
|
197
|
+
let done;
|
|
198
|
+
if (solverNext) {
|
|
199
|
+
const state = solverNext(elapsedMs);
|
|
200
|
+
current = state.value;
|
|
201
|
+
done = state.done;
|
|
202
|
+
}
|
|
203
|
+
else if (elapsedSec >= duration) {
|
|
204
|
+
current = target;
|
|
205
|
+
done = true;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
const p = elapsedSec / duration;
|
|
209
|
+
current = startValue + (target - startValue) * easeOutDefault(p);
|
|
210
|
+
done = false;
|
|
211
|
+
}
|
|
212
|
+
sv.current.value = current;
|
|
213
|
+
flushTree();
|
|
214
|
+
if (done) {
|
|
215
|
+
if (!solverNext && sv.current.value !== target) {
|
|
216
|
+
sv.current.value = target;
|
|
217
|
+
flushTree();
|
|
218
|
+
}
|
|
219
|
+
settle();
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
scheduleNext(tick);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
scheduleNext(tick);
|
|
226
|
+
return { stop, finished };
|
|
227
|
+
}
|
|
228
|
+
/** Test hook — clear the in-flight map. Not part of the public API. */
|
|
229
|
+
export function _resetInflight() {
|
|
230
|
+
const g = globalThis;
|
|
231
|
+
if (g.__sigxMotionInflight)
|
|
232
|
+
g.__sigxMotionInflight.clear();
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=animate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animate.js","sourceRoot":"","sources":["../src/animate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAyCH,+EAA+E;AAC/E,yDAAyD;AACzD,+EAA+E;AAE/E;;;;GAIG;AACH,MAAM,UAAU,OAAO,CACrB,EAAuB,EACvB,MAAc,EACd,OAAO,GAAmB,EAAE;IAE5B,aAAa,CAAC;IAEd,uEAAuE;IACvE,sEAAsE;IACtE,0DAA0D;IAC1D,MAAM,CAAC,GAAG,UAAgE,CAAC;IAC3E,IAAI,CAAC,CAAC,CAAC,oBAAoB;QAAE,CAAC,CAAC,oBAAoB,GAAG,IAAI,GAAG,EAAE,CAAC;IAChE,MAAM,QAAQ,GAAG,CAAC,CAAC,oBAAoB,CAAC;IAExC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,IAAI;QAAE,IAAI,EAAE,CAAC;IAEjB,MAAM,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAEpC,MAAM,QAAQ,GACZ,OAAO,CAAC,IAAI,KAAK,QAAQ;QACzB,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC;IAEzD,wEAAwE;IACxE,0EAA0E;IAC1E,MAAM,WAAW,GAAG,GAA6D,EAAE;QACjF,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAE3B,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,GAAG,CAAC;QAC3C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;QAC/B,MAAM,eAAe,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,wBAAwB;QAEnF,MAAM,YAAY,GAAG,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC;QACjE,MAAM,YAAY,GAAG,MAAM,GAAG,UAAU,CAAC;QACzC,MAAM,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;QAE/D,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAEvE,IAAI,aAAoC,CAAC;QAEzC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,WAAW,GAAG,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC;YACrF,aAAa,GAAG,CAAC,CAAC,EAAE,EAAE;gBACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,YAAY,GAAG,mBAAmB,GAAG,CAAC,CAAC,CAAC;gBACnE,OAAO,MAAM,GAAG,QAAQ;oBACtB,CAAC,CAAC,CAAC,eAAe,GAAG,YAAY,GAAG,mBAAmB,GAAG,YAAY,CAAC,GAAG,WAAW,CAAC;wBACpF,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC;wBACzB,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC;YAChD,CAAC,CAAC;QACJ,CAAC;aAAM,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;YAC9B,aAAa,GAAG,CAAC,CAAC,EAAE,EAAE,CACpB,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,mBAAmB,GAAG,CAAC,CAAC;gBACzC,CAAC,YAAY,GAAG,CAAC,eAAe,GAAG,mBAAmB,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QAClF,CAAC;aAAM,CAAC;YACN,MAAM,iBAAiB,GAAG,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC;YAC3F,aAAa,GAAG,CAAC,CAAC,EAAE,EAAE;gBACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,YAAY,GAAG,mBAAmB,GAAG,CAAC,CAAC,CAAC;gBACnE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;gBACtD,OAAO,MAAM,GAAG,CAAC,QAAQ;oBACvB,CAAC,CAAC,eAAe,GAAG,YAAY,GAAG,mBAAmB,GAAG,YAAY,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;wBAC1F,iBAAiB,GAAG,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC;YACnF,CAAC,CAAC;QACJ,CAAC;QAED,kEAAkE;QAClE,MAAM,YAAY,GAAG,CAAC,CAAS,EAAE,OAAe,EAAU,EAAE;YAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YACjC,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;YACrC,MAAM,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC;YACrB,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,CAAC,CAAC;QAEF,OAAO,CAAC,CAAS,EAAE,EAAE;YACnB,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YACjC,IAAI,eAAe,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;YACpD,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;gBACrB,eAAe,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YAChF,CAAC;YACD,MAAM,wBAAwB,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,SAAS,CAAC;YACxE,MAAM,4BAA4B,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,IAAI,SAAS,CAAC;YAC7E,MAAM,IAAI,GAAG,wBAAwB,IAAI,4BAA4B,CAAC;YACtE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QAClD,CAAC,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,WAAW,EAAE,CAAC;IAEjC,yEAAyE;IACzE,MAAM,UAAU,GAAG,CAAC,CAAS,EAAE,EAAU,EAAE,EAAU,EAAU,EAAE,CAC/D,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IAEjF,MAAM,eAAe,GAAG,CAAC,CAAS,EAAE,GAAW,EAAE,GAAW,EAAU,EAAE;QACtE,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAU,EAAE,CAAC,GAAG,CAAC,CAAC;QAC9C,GAAG,CAAC;YACF,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;YACxB,EAAE,GAAG,UAAU,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,EAAE,GAAG,CAAC;gBAAE,EAAE,GAAG,EAAE,CAAC;;gBAAM,EAAE,GAAG,EAAE,CAAC;QACpC,CAAC,QAAQ,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE;QAC1C,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;IAEF,MAAM,cAAc,GAAG,CAAC,CAAS,EAAU,EAAE;QAC3C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QACjC,OAAO,UAAU,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACvD,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,GAAG,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,cAAwC,CAAC;IAC7C,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,GAAG,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/E,MAAM,MAAM,GAAG,GAAS,EAAE;QACxB,IAAI,OAAO;YAAE,OAAO;QACpB,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI;YAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;QAC/D,cAAc,EAAE,EAAE,CAAC;IACrB,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,GAAS,EAAE;QACtB,IAAI,QAAQ;YAAE,OAAO;QACrB,QAAQ,GAAG,IAAI,CAAC;QAChB,MAAM,EAAE,CAAC;IACX,CAAC,CAAC;IAEF,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAE7B,yEAAyE;IACzE,gEAAgE;IAChE,sEAAsE;IACtE,+CAA+C;IAC/C,MAAM,SAAS,GAAG,UAAkE,CAAC;IACrF,MAAM,YAAY,GAAG,CAAC,EAAc,EAAQ,EAAE;QAC5C,IAAI,OAAO,SAAS,CAAC,qBAAqB,KAAK,UAAU,EAAE,CAAC;YAC1D,SAAS,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC;IAEF,wEAAwE;IACxE,kEAAkE;IAClE,wEAAwE;IACxE,oEAAoE;IACpE,wBAAwB;IACxB,EAAE;IACF,wEAAwE;IACxE,uEAAuE;IACvE,mEAAmE;IACnE,uEAAuE;IACvE,qEAAqE;IACrE,uDAAuD;IACvD,MAAM,SAAS,GAAG,GAAS,EAAE;QAC3B,MAAM,CAAC,GAAG,UAAqC,CAAC;QAChD,IAAI,CAAC,CAAC,4BAA4B,CAAC;YAAE,OAAO;QAC5C,CAAC,CAAC,4BAA4B,CAAC,GAAG,IAAI,CAAC;QACvC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;YAC1B,CAAC,CAAC,4BAA4B,CAAC,GAAG,KAAK,CAAC;YACxC,MAAM,EAAE,GAAG,CAAC,CAAC,oBAAoB,CAA6B,CAAC;YAC/D,IAAI,EAAE;gBAAE,EAAE,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,GAAS,EAAE;QACtB,IAAI,QAAQ;YAAE,OAAO;QAErB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,SAAS,GAAG,GAAG,GAAG,SAAS,CAAC;QAClC,MAAM,UAAU,GAAG,SAAS,GAAG,IAAI,CAAC;QAEpC,IAAI,OAAe,CAAC;QACpB,IAAI,IAAa,CAAC;QAElB,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;YACpC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC;YACtB,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACpB,CAAC;aAAM,IAAI,UAAU,IAAI,QAAQ,EAAE,CAAC;YAClC,OAAO,GAAG,MAAM,CAAC;YACjB,IAAI,GAAG,IAAI,CAAC;QACd,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,UAAU,GAAG,QAAQ,CAAC;YAChC,OAAO,GAAG,UAAU,GAAG,CAAC,MAAM,GAAG,UAAU,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;YACjE,IAAI,GAAG,KAAK,CAAC;QACf,CAAC;QAED,EAAE,CAAC,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC;QAC3B,SAAS,EAAE,CAAC;QAEZ,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;gBAC/C,EAAE,CAAC,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC;gBAC1B,SAAS,EAAE,CAAC;YACd,CAAC;YACD,MAAM,EAAE,CAAC;QACX,CAAC;aAAM,CAAC;YACN,YAAY,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC;IAEF,YAAY,CAAC,IAAI,CAAC,CAAC;IAEnB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,cAAc;IAC5B,MAAM,CAAC,GAAG,UAAgE,CAAC;IAC3E,IAAI,CAAC,CAAC,oBAAoB;QAAE,CAAC,CAAC,oBAAoB,CAAC,KAAK,EAAE,CAAC;AAC7D,CAAC"}
|
package/dist/easings.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Easing functions ported from `motion-utils` v12.23.6 (Apache-2.0).
|
|
3
|
+
* Upstream: https://github.com/motiondivision/motion/tree/main/packages/motion-utils/src/easing
|
|
4
|
+
*
|
|
5
|
+
* Sigx adaptation:
|
|
6
|
+
* - Inlined into a single file (cubic-bezier + modifiers + named easings).
|
|
7
|
+
* - No `'main thread'` directive; these are pure math functions safe to
|
|
8
|
+
* call from BG or MT context. Sigx's tween path on MT calls them
|
|
9
|
+
* directly inside the worklet body.
|
|
10
|
+
*
|
|
11
|
+
* Reference for individual implementations:
|
|
12
|
+
* - cubicBezier: motion-utils/src/easing/cubic-bezier.ts (modified from
|
|
13
|
+
* Gaëtan Renaudeau's BezierEasing — https://github.com/gre/bezier-easing,
|
|
14
|
+
* MIT-licensed)
|
|
15
|
+
* - ease.ts, back.ts, circ.ts, anticipate.ts, modifiers/{mirror,reverse}.ts
|
|
16
|
+
*
|
|
17
|
+
* Verbatim translation; any divergence from upstream is a bug.
|
|
18
|
+
*/
|
|
19
|
+
// noop — identity; serves as `linear` and as the cubic-bezier shortcut when
|
|
20
|
+
// (mX1, mY1) === (mX2, mY2).
|
|
21
|
+
const noop = (t) => t;
|
|
22
|
+
// ---- cubic bezier ---------------------------------------------------------
|
|
23
|
+
const calcBezier = (t, a1, a2) => (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) *
|
|
24
|
+
t;
|
|
25
|
+
const subdivisionPrecision = 0.0000001;
|
|
26
|
+
const subdivisionMaxIterations = 12;
|
|
27
|
+
function binarySubdivide(x, lowerBound, upperBound, mX1, mX2) {
|
|
28
|
+
let currentX;
|
|
29
|
+
let currentT = 0;
|
|
30
|
+
let i = 0;
|
|
31
|
+
do {
|
|
32
|
+
currentT = lowerBound + (upperBound - lowerBound) / 2.0;
|
|
33
|
+
currentX = calcBezier(currentT, mX1, mX2) - x;
|
|
34
|
+
if (currentX > 0.0) {
|
|
35
|
+
upperBound = currentT;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
lowerBound = currentT;
|
|
39
|
+
}
|
|
40
|
+
} while (Math.abs(currentX) > subdivisionPrecision &&
|
|
41
|
+
++i < subdivisionMaxIterations);
|
|
42
|
+
return currentT;
|
|
43
|
+
}
|
|
44
|
+
export function cubicBezier(mX1, mY1, mX2, mY2) {
|
|
45
|
+
if (mX1 === mY1 && mX2 === mY2)
|
|
46
|
+
return noop;
|
|
47
|
+
const getTForX = (aX) => binarySubdivide(aX, 0, 1, mX1, mX2);
|
|
48
|
+
return (t) => (t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2));
|
|
49
|
+
}
|
|
50
|
+
// ---- modifiers ------------------------------------------------------------
|
|
51
|
+
/** Reverses an easing — turns easeIn into easeOut. */
|
|
52
|
+
export const reverseEasing = (easing) => (p) => 1 - easing(1 - p);
|
|
53
|
+
/** Mirrors an easing across the midpoint — turns easeIn into easeInOut. */
|
|
54
|
+
export const mirrorEasing = (easing) => (p) => p <= 0.5 ? easing(2 * p) / 2 : (2 - easing(2 * (1 - p))) / 2;
|
|
55
|
+
// ---- named easings --------------------------------------------------------
|
|
56
|
+
export const linear = noop;
|
|
57
|
+
export const easeIn = cubicBezier(0.42, 0, 1, 1);
|
|
58
|
+
export const easeOut = cubicBezier(0, 0, 0.58, 1);
|
|
59
|
+
export const easeInOut = cubicBezier(0.42, 0, 0.58, 1);
|
|
60
|
+
export const circIn = (p) => 1 - Math.sin(Math.acos(p));
|
|
61
|
+
export const circOut = reverseEasing(circIn);
|
|
62
|
+
export const circInOut = mirrorEasing(circIn);
|
|
63
|
+
export const backOut = cubicBezier(0.33, 1.53, 0.69, 0.99);
|
|
64
|
+
export const backIn = reverseEasing(backOut);
|
|
65
|
+
export const backInOut = mirrorEasing(backIn);
|
|
66
|
+
export const anticipate = (p) => (p *= 2) < 1 ? 0.5 * backIn(p) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
|
|
67
|
+
//# sourceMappingURL=easings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"easings.js","sourceRoot":"","sources":["../src/easings.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,155 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
m = (n) => {
|
|
18
|
-
let r = Math.exp(-c * u * n), i = Math.min(e * n, 300);
|
|
19
|
-
return t - r * ((a + c * u * l) * Math.sinh(i) + e * l * Math.cosh(i)) / e;
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
let h = (e, t) => {
|
|
23
|
-
let n = Math.max(e - 5, 0), r = m(n), i = e - n;
|
|
24
|
-
return i ? (t - r) * (1e3 / i) : 0;
|
|
25
|
-
};
|
|
26
|
-
return (e) => {
|
|
27
|
-
let n = m(e), r = e === 0 ? a : 0;
|
|
28
|
-
c < 1 && (r = e === 0 ? a * 1e3 : h(e, n));
|
|
29
|
-
let i = Math.abs(r) <= f, o = Math.abs(t - n) <= p, s = i && o;
|
|
30
|
-
return {
|
|
31
|
-
done: s,
|
|
32
|
-
value: s ? t : n
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
})(), l = (e, t, n) => (((1 - 3 * n + 3 * t) * e + (3 * n - 6 * t)) * e + 3 * t) * e, u = (e, t, n) => {
|
|
36
|
-
let r = 0, i = 1, a = 0, o, s = 0;
|
|
37
|
-
do
|
|
38
|
-
a = r + (i - r) / 2, o = l(a, t, n) - e, o > 0 ? i = a : r = a;
|
|
39
|
-
while (Math.abs(o) > 1e-7 && ++s < 12);
|
|
40
|
-
return a;
|
|
41
|
-
}, d = (e) => e === 0 || e === 1 ? e : l(u(e, 0, .58), 0, 1), f = n.duration ?? .3, p = Date.now(), m = !1, h, g = !1, _ = new Promise((e) => {
|
|
42
|
-
h = e;
|
|
43
|
-
}), v = () => {
|
|
44
|
-
g || (g = !0, i.get(e._wvid) === y && i.delete(e._wvid), h?.());
|
|
45
|
-
}, y = () => {
|
|
46
|
-
m || (m = !0, v());
|
|
47
|
-
};
|
|
48
|
-
i.set(e._wvid, y);
|
|
49
|
-
let b = globalThis, x = (e) => {
|
|
50
|
-
typeof b.requestAnimationFrame == "function" ? b.requestAnimationFrame(e) : setTimeout(e, 16);
|
|
51
|
-
}, S = () => {
|
|
52
|
-
let e = globalThis;
|
|
53
|
-
e.__sigxMotionFlushScheduled || (e.__sigxMotionFlushScheduled = !0, Promise.resolve().then(() => {
|
|
54
|
-
e.__sigxMotionFlushScheduled = !1;
|
|
55
|
-
let t = e.__FlushElementTree;
|
|
56
|
-
t && t();
|
|
57
|
-
}));
|
|
58
|
-
}, C = () => {
|
|
59
|
-
if (m) return;
|
|
60
|
-
let n = Date.now() - p, r = n / 1e3, i, a;
|
|
61
|
-
if (c) {
|
|
62
|
-
let e = c(n);
|
|
63
|
-
i = e.value, a = e.done;
|
|
64
|
-
} else if (r >= f) i = t, a = !0;
|
|
65
|
-
else {
|
|
66
|
-
let e = r / f;
|
|
67
|
-
i = o + (t - o) * d(e), a = !1;
|
|
68
|
-
}
|
|
69
|
-
e.current.value = i, S(), a ? (!c && e.current.value !== t && (e.current.value = t, S()), v()) : x(C);
|
|
70
|
-
};
|
|
71
|
-
return x(C), {
|
|
72
|
-
stop: y,
|
|
73
|
-
finished: _
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
//#endregion
|
|
77
|
-
//#region src/with-spring.ts
|
|
78
|
-
function t(t, n, r = {}) {
|
|
79
|
-
"main thread";
|
|
80
|
-
return e(t, n, {
|
|
81
|
-
...r,
|
|
82
|
-
type: "spring"
|
|
83
|
-
}).finished;
|
|
84
|
-
}
|
|
85
|
-
//#endregion
|
|
86
|
-
//#region src/with-timing.ts
|
|
87
|
-
function n(t, n, r = {}) {
|
|
88
|
-
"main thread";
|
|
89
|
-
return e(t, n, {
|
|
90
|
-
...r,
|
|
91
|
-
type: "tween"
|
|
92
|
-
}).finished;
|
|
93
|
-
}
|
|
94
|
-
//#endregion
|
|
95
|
-
//#region src/spring.ts
|
|
96
|
-
var r = (e, t, n) => n > t ? t : n < e ? e : n, i = (e) => e / 1e3, a = (e) => e * 1e3, o = (e, t) => t ? 1e3 / t * e : 0, s = 5, c = (e, t, n) => {
|
|
97
|
-
let r = Math.max(t - s, 0);
|
|
98
|
-
return o(n - e(r), t - r);
|
|
99
|
-
}, l = {
|
|
100
|
-
stiffness: 100,
|
|
101
|
-
damping: 10,
|
|
102
|
-
mass: 1,
|
|
103
|
-
velocity: 0,
|
|
104
|
-
restSpeed: {
|
|
105
|
-
granular: .01,
|
|
106
|
-
default: 2
|
|
107
|
-
},
|
|
108
|
-
restDelta: {
|
|
109
|
-
granular: .005,
|
|
110
|
-
default: .5
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
function u(e) {
|
|
114
|
-
let t = e.keyframes[0], n = e.keyframes[1], r = {
|
|
115
|
-
done: !1,
|
|
116
|
-
value: t
|
|
117
|
-
}, o = e.stiffness ?? l.stiffness, s = e.damping ?? l.damping, u = e.mass ?? l.mass, d = -i(e.velocity ?? 0), f = s / (2 * Math.sqrt(o * u)), p = n - t, m = i(Math.sqrt(o / u)), h = Math.abs(p) < 5, g = e.restSpeed ?? (h ? l.restSpeed.granular : l.restSpeed.default), _ = e.restDelta ?? (h ? l.restDelta.granular : l.restDelta.default), v;
|
|
118
|
-
if (f < 1) {
|
|
119
|
-
let e = m * Math.sqrt(1 - f * f);
|
|
120
|
-
v = (t) => n - Math.exp(-f * m * t) * ((d + f * m * p) / e * Math.sin(e * t) + p * Math.cos(e * t));
|
|
121
|
-
} else if (f === 1) v = (e) => n - Math.exp(-m * e) * (p + (d + m * p) * e);
|
|
122
|
-
else {
|
|
123
|
-
let e = m * Math.sqrt(f * f - 1);
|
|
124
|
-
v = (t) => {
|
|
125
|
-
let r = Math.exp(-f * m * t), i = Math.min(e * t, 300);
|
|
126
|
-
return n - r * ((d + f * m * p) * Math.sinh(i) + e * p * Math.cosh(i)) / e;
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
return { next(e) {
|
|
130
|
-
let t = v(e), i = e === 0 ? d : 0;
|
|
131
|
-
f < 1 && (i = e === 0 ? a(d) : c(v, e, t));
|
|
132
|
-
let o = Math.abs(i) <= g, s = Math.abs(n - t) <= _;
|
|
133
|
-
return r.done = o && s, r.value = r.done ? n : t, r;
|
|
134
|
-
} };
|
|
135
|
-
}
|
|
136
|
-
//#endregion
|
|
137
|
-
//#region src/easings.ts
|
|
138
|
-
var d = (e) => e, f = (e, t, n) => (((1 - 3 * n + 3 * t) * e + (3 * n - 6 * t)) * e + 3 * t) * e, p = 1e-7, m = 12;
|
|
139
|
-
function h(e, t, n, r, i) {
|
|
140
|
-
let a, o = 0, s = 0;
|
|
141
|
-
do
|
|
142
|
-
o = t + (n - t) / 2, a = f(o, r, i) - e, a > 0 ? n = o : t = o;
|
|
143
|
-
while (Math.abs(a) > p && ++s < m);
|
|
144
|
-
return o;
|
|
145
|
-
}
|
|
146
|
-
function g(e, t, n, r) {
|
|
147
|
-
if (e === t && n === r) return d;
|
|
148
|
-
let i = (t) => h(t, 0, 1, e, n);
|
|
149
|
-
return (e) => e === 0 || e === 1 ? e : f(i(e), t, r);
|
|
150
|
-
}
|
|
151
|
-
var _ = (e) => (t) => 1 - e(1 - t), v = (e) => (t) => t <= .5 ? e(2 * t) / 2 : (2 - e(2 * (1 - t))) / 2, y = d, b = g(.42, 0, 1, 1), x = g(0, 0, .58, 1), S = g(.42, 0, .58, 1), C = (e) => 1 - Math.sin(Math.acos(e)), w = _(C), T = v(C), E = g(.33, 1.53, .69, .99), D = _(E), O = v(D), k = (e) => (e *= 2) < 1 ? .5 * D(e) : .5 * (2 - 2 ** (-10 * (e - 1)));
|
|
152
|
-
//#endregion
|
|
153
|
-
export { e as animate, k as anticipate, D as backIn, O as backInOut, E as backOut, C as circIn, T as circInOut, w as circOut, r as clamp, g as cubicBezier, b as easeIn, S as easeInOut, x as easeOut, y as linear, v as mirrorEasing, _ as reverseEasing, u as spring, t as withSpring, n as withTiming };
|
|
154
|
-
|
|
1
|
+
// Animation orchestration ('main thread' worklets that operate on SharedValue)
|
|
2
|
+
export { animate } from './animate.js';
|
|
3
|
+
// Convenience wrappers
|
|
4
|
+
export { withSpring } from './with-spring.js';
|
|
5
|
+
export { withTiming } from './with-timing.js';
|
|
6
|
+
// Spring solver — pure-math API for non-worklet callers (tests, BG-side
|
|
7
|
+
// debugging, future scroll-driven derived values). NOT used by the worklet
|
|
8
|
+
// path: `animate()` has its own inlined copy of the solver to avoid
|
|
9
|
+
// cross-file `_c` capture of plain function references that don't survive
|
|
10
|
+
// JSON serialization across the MT/BG bridge.
|
|
11
|
+
export { spring, clamp } from './spring.js';
|
|
12
|
+
// Easings — same story as spring: pure-math API for non-worklet uses; the
|
|
13
|
+
// `animate()` worklet has its own inlined `easeOut`. Custom easings passed
|
|
14
|
+
// via `animate(sv, target, { ease: customFn })` will not survive worklet
|
|
15
|
+
// capture and is documented as out-of-scope for v0.1.
|
|
16
|
+
export { cubicBezier, reverseEasing, mirrorEasing, linear, easeIn, easeOut, easeInOut, circIn, circOut, circInOut, backIn, backOut, backInOut, anticipate, } from './easings.js';
|
|
155
17
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/animate.ts","../src/with-spring.ts","../src/with-timing.ts","../src/spring.ts","../src/easings.ts"],"sourcesContent":["/**\n * Animation orchestration ported from `@lynx-js/motion/dist/mini/core/animate.js`\n * v0.0.3 (Apache-2.0). Spring solver + easeOut math from\n * `motion-dom` v12.23.12 + `motion-utils` v12.23.6 (also Apache-2.0),\n * inlined directly inside the worklet body.\n *\n * Why everything is inlined inside the function: SWC's worklet transform\n * captures any free identifier referenced by the worklet body into the\n * `_c` map. Plain JS function references at module scope (or sibling\n * imports) don't survive JSON serialization across the MT/BG bridge — they\n * arrive on MT as undefined or stringified placeholders. Upstream\n * motion-mini sidesteps this by making every helper its own `'main thread'`\n * worklet (so the placeholder objects survive). For Phase 2.7 we keep the\n * port simpler by inlining the math straight into the `animate` worklet\n * body, with `inflight` cancellation state tucked on `globalThis` so it's\n * not a free-identifier capture.\n *\n * Sigx-specific adaptations:\n * - Operates on sigx's `SharedValue<number>` (writes `sv.current.value`)\n * instead of motion's `MotionValue`.\n * - Per-SharedValue cancellation tracking via `globalThis.__sigxMotionInflight`.\n * - Uses `globalThis.requestAnimationFrame` (installed by upstream's\n * worklet-runtime IIFE on MT, Lynx SDK ≥ 2.16); falls back to\n * `setTimeout(cb, 16)` otherwise.\n *\n * The standalone modules `easings.ts` and `spring.ts` still ship as a\n * pure-math API for non-worklet callers (tests, BG-side debugging). They\n * are NOT imported by this worklet.\n */\n\nimport type { SharedValue } from '@sigx/lynx';\n\n// ============================================================================\n// Public types\n// ============================================================================\n\nexport interface SpringOptions {\n stiffness?: number;\n damping?: number;\n mass?: number;\n velocity?: number;\n restSpeed?: number;\n restDelta?: number;\n}\n\nexport interface TimingOptions {\n /** Tween duration in seconds. Default 0.3. */\n duration?: number;\n}\n\nexport interface AnimateOptions extends SpringOptions, TimingOptions {\n type?: 'spring' | 'tween';\n}\n\n// Note: motion-style `onUpdate` / `onComplete` / custom `ease` callbacks are\n// intentionally NOT in this surface. Function references don't survive\n// worklet `_c` capture across the MT/BG bridge — they'd be silent footguns.\n// Sigx-native equivalents (zero extra wiring, integrate with reactivity):\n// onUpdate(v) → BG: `effect(() => doX(sv.value))`\n// onComplete() → `await withSpring(sv, target); doNext()`\n// ease: customFn → use a built-in (`linear`, `easeIn`, `easeOut`, etc.);\n// custom curves are rare and would need a `registerEasing(name, fn)`\n// pattern (deferred follow-up).\n\nexport interface AnimateControls {\n stop(): void;\n finished: Promise<void>;\n}\n\n// ============================================================================\n// Public API — all math inlined inside the worklet body.\n// ============================================================================\n\n/**\n * Animate a `SharedValue<number>` toward `target`. Returns\n * `{ stop, finished }`. Default is spring; pass `type: 'tween'` or\n * `{ duration }` to use a tween with `easeOut`.\n */\nexport function animate(\n sv: SharedValue<number>,\n target: number,\n options: AnimateOptions = {},\n): AnimateControls {\n 'main thread';\n\n // ─── Inlined: in-flight cancellation map (per-SharedValue) ──────────\n // Stash on globalThis so SWC doesn't capture a module-scope reference\n // into _c. The map persists across animate() calls on MT.\n const g = globalThis as { __sigxMotionInflight?: Map<number, () => void> };\n if (!g.__sigxMotionInflight) g.__sigxMotionInflight = new Map();\n const inflight = g.__sigxMotionInflight;\n\n const prev = inflight.get(sv._wvid);\n if (prev) prev();\n\n const startValue = sv.current.value;\n\n const isSpring =\n options.type === 'spring' ||\n (options.type !== 'tween' && options.duration == null);\n\n // ─── Inlined: spring solver (motion-dom port, Apache-2.0) ────────────\n // Returns { next(elapsedMs): { done, value } }. Only built when isSpring.\n const buildSolver = (): ((t: number) => { done: boolean; value: number }) | null => {\n if (!isSpring) return null;\n\n const stiffness = options.stiffness ?? 100;\n const damping = options.damping ?? 10;\n const mass = options.mass ?? 1;\n const initialVelocity = -((options.velocity ?? 0) / 1000); // ms→s, sign convention\n\n const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));\n const initialDelta = target - startValue;\n const undampedAngularFreq = Math.sqrt(stiffness / mass) / 1000;\n\n const isGranularScale = Math.abs(initialDelta) < 5;\n const restSpeed = options.restSpeed ?? (isGranularScale ? 0.01 : 2);\n const restDelta = options.restDelta ?? (isGranularScale ? 0.005 : 0.5);\n\n let resolveSpring: (t: number) => number;\n\n if (dampingRatio < 1) {\n const angularFreq = undampedAngularFreq * Math.sqrt(1 - dampingRatio * dampingRatio);\n resolveSpring = (t) => {\n const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);\n return target - envelope *\n (((initialVelocity + dampingRatio * undampedAngularFreq * initialDelta) / angularFreq) *\n Math.sin(angularFreq * t) +\n initialDelta * Math.cos(angularFreq * t));\n };\n } else if (dampingRatio === 1) {\n resolveSpring = (t) =>\n target - Math.exp(-undampedAngularFreq * t) *\n (initialDelta + (initialVelocity + undampedAngularFreq * initialDelta) * t);\n } else {\n const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);\n resolveSpring = (t) => {\n const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);\n const freqForT = Math.min(dampedAngularFreq * t, 300);\n return target - (envelope *\n ((initialVelocity + dampingRatio * undampedAngularFreq * initialDelta) * Math.sinh(freqForT) +\n dampedAngularFreq * initialDelta * Math.cosh(freqForT))) / dampedAngularFreq;\n };\n }\n\n // Velocity sample: 5ms-window finite-difference of resolveSpring.\n const calcVelocity = (t: number, current: number): number => {\n const prevT = Math.max(t - 5, 0);\n const prevVal = resolveSpring(prevT);\n const dt = t - prevT;\n return dt ? (current - prevVal) * (1000 / dt) : 0;\n };\n\n return (t: number) => {\n const current = resolveSpring(t);\n let currentVelocity = t === 0 ? initialVelocity : 0;\n if (dampingRatio < 1) {\n currentVelocity = t === 0 ? initialVelocity * 1000 : calcVelocity(t, current);\n }\n const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;\n const isBelowDisplacementThreshold = Math.abs(target - current) <= restDelta;\n const done = isBelowVelocityThreshold && isBelowDisplacementThreshold;\n return { done, value: done ? target : current };\n };\n };\n\n const solverNext = buildSolver();\n\n // ─── Inlined: easeOut (cubicBezier(0, 0, 0.58, 1)) ────────────────────\n const calcBezier = (t: number, a1: number, a2: number): number =>\n (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) * t;\n\n const binarySubdivide = (x: number, mX1: number, mX2: number): number => {\n let lo = 0, hi = 1, cT = 0, cX: number, i = 0;\n do {\n cT = lo + (hi - lo) / 2;\n cX = calcBezier(cT, mX1, mX2) - x;\n if (cX > 0) hi = cT; else lo = cT;\n } while (Math.abs(cX) > 1e-7 && ++i < 12);\n return cT;\n };\n\n const easeOutDefault = (t: number): number => {\n if (t === 0 || t === 1) return t;\n return calcBezier(binarySubdivide(t, 0, 0.58), 0, 1);\n };\n\n const duration = options.duration ?? 0.3;\n const startTime = Date.now();\n\n let canceled = false;\n let resolvePromise: (() => void) | undefined;\n let settled = false;\n const finished = new Promise<void>((resolve) => { resolvePromise = resolve; });\n\n const settle = (): void => {\n if (settled) return;\n settled = true;\n if (inflight.get(sv._wvid) === stop) inflight.delete(sv._wvid);\n resolvePromise?.();\n };\n\n const stop = (): void => {\n if (canceled) return;\n canceled = true;\n settle();\n };\n\n inflight.set(sv._wvid, stop);\n\n // ─── Inlined: tick scheduler ──────────────────────────────────────────\n // `globalThis.requestAnimationFrame` is installed by upstream's\n // worklet-runtime IIFE on MT; falls back to `setTimeout(cb, 16)` when\n // unavailable (older SDKs, test environments).\n const rafGlobal = globalThis as { requestAnimationFrame?: (cb: () => void) => void };\n const scheduleNext = (cb: () => void): void => {\n if (typeof rafGlobal.requestAnimationFrame === 'function') {\n rafGlobal.requestAnimationFrame(cb);\n } else {\n setTimeout(cb, 16);\n }\n };\n\n // ─── Flush trigger (microtask-debounced) ─────────────────────────────\n // Writing `sv.current.value` is a plain ref mutation — it doesn't\n // schedule the native flush by itself. Without a flush, the SharedValue\n // bridge never publishes the new value to BG and `useAnimatedStyle`\n // bindings never apply.\n //\n // We coalesce calls via a `globalThis.__sigxMotionFlushScheduled` flag:\n // multiple ticks across multiple concurrent animations within the same\n // microtask boundary all set the flag, the first one schedules the\n // microtask, the rest see the flag and bail. End result: ONE flush per\n // microtask regardless of how many animations are live. Same pattern\n // upstream's `MTElementWrapper.flushElementTree` uses.\n const flushTree = (): void => {\n const g = globalThis as Record<string, unknown>;\n if (g['__sigxMotionFlushScheduled']) return;\n g['__sigxMotionFlushScheduled'] = true;\n Promise.resolve().then(() => {\n g['__sigxMotionFlushScheduled'] = false;\n const fn = g['__FlushElementTree'] as (() => void) | undefined;\n if (fn) fn();\n });\n };\n\n const tick = (): void => {\n if (canceled) return;\n\n const now = Date.now();\n const elapsedMs = now - startTime;\n const elapsedSec = elapsedMs / 1000;\n\n let current: number;\n let done: boolean;\n\n if (solverNext) {\n const state = solverNext(elapsedMs);\n current = state.value;\n done = state.done;\n } else if (elapsedSec >= duration) {\n current = target;\n done = true;\n } else {\n const p = elapsedSec / duration;\n current = startValue + (target - startValue) * easeOutDefault(p);\n done = false;\n }\n\n sv.current.value = current;\n flushTree();\n\n if (done) {\n if (!solverNext && sv.current.value !== target) {\n sv.current.value = target;\n flushTree();\n }\n settle();\n } else {\n scheduleNext(tick);\n }\n };\n\n scheduleNext(tick);\n\n return { stop, finished };\n}\n\n/** Test hook — clear the in-flight map. Not part of the public API. */\nexport function _resetInflight(): void {\n const g = globalThis as { __sigxMotionInflight?: Map<number, () => void> };\n if (g.__sigxMotionInflight) g.__sigxMotionInflight.clear();\n}\n","/**\n * Convenience wrapper: animate(sv, target, { type: 'spring', ...opts }).\n * Returns the completion promise rather than the full controls handle —\n * use `animate()` directly if you need cancellation.\n */\n\nimport type { SharedValue } from '@sigx/lynx';\n\nimport { animate, type SpringOptions } from './animate.js';\n\nexport function withSpring(\n sv: SharedValue<number>,\n target: number,\n options: SpringOptions = {},\n): Promise<void> {\n 'main thread';\n return animate(sv, target, { ...options, type: 'spring' }).finished;\n}\n","/**\n * Convenience wrapper: animate(sv, target, { type: 'tween', ...opts }).\n * Returns the completion promise rather than the full controls handle —\n * use `animate()` directly if you need cancellation.\n *\n * Duration is in seconds (default 0.3). Ease defaults to `easeOut`.\n */\n\nimport type { SharedValue } from '@sigx/lynx';\n\nimport { animate, type TimingOptions } from './animate.js';\n\nexport function withTiming(\n sv: SharedValue<number>,\n target: number,\n options: TimingOptions = {},\n): Promise<void> {\n 'main thread';\n return animate(sv, target, { ...options, type: 'tween' }).finished;\n}\n","/**\n * Spring solver ported from `motion-dom` v12.23.12 + `motion-utils` v12.23.6\n * (both Apache-2.0).\n * Upstream:\n * - https://github.com/motiondivision/motion/tree/main/packages/motion-dom/src/animation/generators/spring\n * - https://github.com/motiondivision/motion/tree/main/packages/motion-utils/src\n *\n * Sigx adaptation:\n * - Inlined the motion-utils helpers we depend on (`clamp`,\n * `millisecondsToSeconds`, `secondsToMilliseconds`, `velocityPerSecond`)\n * and the velocity calculator from `motion-dom/animation/generators/utils`.\n * These are tiny pure functions; inlining keeps `@sigx/lynx-motion` zero-deps\n * beyond the sigx workspace.\n * - Skipped the duration→physics resolution path (motion's `findSpring`).\n * Phase 2.7 ships only physics-based options (stiffness/damping/mass).\n * If a future user wants `withSpring(av, target, { duration, bounce })`,\n * add `findSpring` then.\n * - `calculatedDuration` and `toString()` / `toTransition()` from upstream\n * are dropped; they're for WAAPI integration which Lynx doesn't use.\n *\n * Verbatim translation of the integrator math; any divergence is a bug.\n */\n\n// ---- inlined helpers ------------------------------------------------------\n\nconst clamp = (min: number, max: number, v: number): number =>\n v > max ? max : v < min ? min : v;\n\nconst millisecondsToSeconds = (ms: number): number => ms / 1000;\nconst secondsToMilliseconds = (s: number): number => s * 1000;\n\nconst velocityPerSecond = (velocity: number, frameDuration: number): number =>\n frameDuration ? velocity * (1000 / frameDuration) : 0;\n\nconst velocitySampleDuration = 5; // ms\nconst calcGeneratorVelocity = (\n resolveValue: (t: number) => number,\n t: number,\n current: number,\n): number => {\n const prevT = Math.max(t - velocitySampleDuration, 0);\n return velocityPerSecond(current - resolveValue(prevT), t - prevT);\n};\n\n// ---- defaults -------------------------------------------------------------\n\nconst springDefaults = {\n stiffness: 100,\n damping: 10,\n mass: 1.0,\n velocity: 0.0,\n restSpeed: { granular: 0.01, default: 2 },\n restDelta: { granular: 0.005, default: 0.5 },\n};\n\n// ---- public API -----------------------------------------------------------\n\nexport interface SpringOptions {\n /** Spring physics. Default 100. */\n stiffness?: number;\n /** Spring damping. Default 10. */\n damping?: number;\n /** Mass of the spring object. Default 1. */\n mass?: number;\n /** Initial velocity in units/sec. Default 0. */\n velocity?: number;\n /** Threshold below which the spring is considered at rest. */\n restSpeed?: number;\n restDelta?: number;\n}\n\nexport interface SpringStep {\n done: boolean;\n value: number;\n}\n\nexport interface SpringSolver {\n /**\n * Advance the spring to `t` ms after `t=0`. Returns the integrated value\n * and a `done` flag set when the spring is below the rest thresholds.\n */\n next(t: number): SpringStep;\n}\n\nexport interface SpringSolverOptions extends SpringOptions {\n /** Required: `[origin, target]`. Pinned to a 2-element keyframes shape. */\n keyframes: [number, number];\n}\n\n/**\n * Build a spring solver. Call `.next(elapsedMs)` repeatedly to step the\n * animation. The solver owns no time state — call `.next` with the current\n * elapsed time each tick (motion's pattern).\n */\nexport function spring(options: SpringSolverOptions): SpringSolver {\n const origin = options.keyframes[0];\n const target = options.keyframes[1];\n\n const state: SpringStep = { done: false, value: origin };\n\n const stiffness = options.stiffness ?? springDefaults.stiffness;\n const damping = options.damping ?? springDefaults.damping;\n const mass = options.mass ?? springDefaults.mass;\n // Negate to match motion's convention: positive velocity moves toward\n // target, but the integrator expects velocity in source-units convention.\n const initialVelocity = -millisecondsToSeconds(options.velocity ?? 0);\n\n const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));\n const initialDelta = target - origin;\n const undampedAngularFreq = millisecondsToSeconds(\n Math.sqrt(stiffness / mass),\n );\n\n const isGranularScale = Math.abs(initialDelta) < 5;\n const restSpeed =\n options.restSpeed ??\n (isGranularScale\n ? springDefaults.restSpeed.granular\n : springDefaults.restSpeed.default);\n const restDelta =\n options.restDelta ??\n (isGranularScale\n ? springDefaults.restDelta.granular\n : springDefaults.restDelta.default);\n\n let resolveSpring: (t: number) => number;\n\n if (dampingRatio < 1) {\n // Underdamped — oscillates while decaying.\n const angularFreq =\n undampedAngularFreq * Math.sqrt(1 - dampingRatio * dampingRatio);\n resolveSpring = (t) => {\n const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);\n return (\n target -\n envelope *\n (((initialVelocity +\n dampingRatio * undampedAngularFreq * initialDelta) /\n angularFreq) *\n Math.sin(angularFreq * t) +\n initialDelta * Math.cos(angularFreq * t))\n );\n };\n } else if (dampingRatio === 1) {\n // Critically damped — fastest non-oscillating return.\n resolveSpring = (t) =>\n target -\n Math.exp(-undampedAngularFreq * t) *\n (initialDelta +\n (initialVelocity + undampedAngularFreq * initialDelta) * t);\n } else {\n // Overdamped — slow non-oscillating return.\n const dampedAngularFreq =\n undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);\n resolveSpring = (t) => {\n const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);\n // Cap freq*t to keep sinh/cosh from hitting Infinity.\n const freqForT = Math.min(dampedAngularFreq * t, 300);\n return (\n target -\n (envelope *\n ((initialVelocity +\n dampingRatio * undampedAngularFreq * initialDelta) *\n Math.sinh(freqForT) +\n dampedAngularFreq * initialDelta * Math.cosh(freqForT))) /\n dampedAngularFreq\n );\n };\n }\n\n return {\n next(t: number): SpringStep {\n const current = resolveSpring(t);\n\n let currentVelocity = t === 0 ? initialVelocity : 0.0;\n // Velocity calc only needed for underdamped — over/critically-damped\n // can't overshoot, so position alone tells us we're done.\n if (dampingRatio < 1) {\n currentVelocity =\n t === 0\n ? secondsToMilliseconds(initialVelocity)\n : calcGeneratorVelocity(resolveSpring, t, current);\n }\n\n const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;\n const isBelowDisplacementThreshold =\n Math.abs(target - current) <= restDelta;\n\n state.done = isBelowVelocityThreshold && isBelowDisplacementThreshold;\n state.value = state.done ? target : current;\n return state;\n },\n };\n}\n\n// Re-export `clamp` because it's small and useful for animation math, and\n// motion-mini exports it from its mini surface.\nexport { clamp };\n","/**\n * Easing functions ported from `motion-utils` v12.23.6 (Apache-2.0).\n * Upstream: https://github.com/motiondivision/motion/tree/main/packages/motion-utils/src/easing\n *\n * Sigx adaptation:\n * - Inlined into a single file (cubic-bezier + modifiers + named easings).\n * - No `'main thread'` directive; these are pure math functions safe to\n * call from BG or MT context. Sigx's tween path on MT calls them\n * directly inside the worklet body.\n *\n * Reference for individual implementations:\n * - cubicBezier: motion-utils/src/easing/cubic-bezier.ts (modified from\n * Gaëtan Renaudeau's BezierEasing — https://github.com/gre/bezier-easing,\n * MIT-licensed)\n * - ease.ts, back.ts, circ.ts, anticipate.ts, modifiers/{mirror,reverse}.ts\n *\n * Verbatim translation; any divergence from upstream is a bug.\n */\n\nexport type Easing = (t: number) => number;\n\n// noop — identity; serves as `linear` and as the cubic-bezier shortcut when\n// (mX1, mY1) === (mX2, mY2).\nconst noop: Easing = (t) => t;\n\n// ---- cubic bezier ---------------------------------------------------------\n\nconst calcBezier = (t: number, a1: number, a2: number): number =>\n (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) *\n t;\n\nconst subdivisionPrecision = 0.0000001;\nconst subdivisionMaxIterations = 12;\n\nfunction binarySubdivide(\n x: number,\n lowerBound: number,\n upperBound: number,\n mX1: number,\n mX2: number,\n): number {\n let currentX: number;\n let currentT: number = 0;\n let i = 0;\n do {\n currentT = lowerBound + (upperBound - lowerBound) / 2.0;\n currentX = calcBezier(currentT, mX1, mX2) - x;\n if (currentX > 0.0) {\n upperBound = currentT;\n } else {\n lowerBound = currentT;\n }\n } while (\n Math.abs(currentX) > subdivisionPrecision &&\n ++i < subdivisionMaxIterations\n );\n return currentT;\n}\n\nexport function cubicBezier(\n mX1: number,\n mY1: number,\n mX2: number,\n mY2: number,\n): Easing {\n if (mX1 === mY1 && mX2 === mY2) return noop;\n const getTForX = (aX: number) => binarySubdivide(aX, 0, 1, mX1, mX2);\n return (t) => (t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2));\n}\n\n// ---- modifiers ------------------------------------------------------------\n\n/** Reverses an easing — turns easeIn into easeOut. */\nexport const reverseEasing = (easing: Easing): Easing => (p) =>\n 1 - easing(1 - p);\n\n/** Mirrors an easing across the midpoint — turns easeIn into easeInOut. */\nexport const mirrorEasing = (easing: Easing): Easing => (p) =>\n p <= 0.5 ? easing(2 * p) / 2 : (2 - easing(2 * (1 - p))) / 2;\n\n// ---- named easings --------------------------------------------------------\n\nexport const linear: Easing = noop;\n\nexport const easeIn: Easing = cubicBezier(0.42, 0, 1, 1);\nexport const easeOut: Easing = cubicBezier(0, 0, 0.58, 1);\nexport const easeInOut: Easing = cubicBezier(0.42, 0, 0.58, 1);\n\nexport const circIn: Easing = (p) => 1 - Math.sin(Math.acos(p));\nexport const circOut: Easing = reverseEasing(circIn);\nexport const circInOut: Easing = mirrorEasing(circIn);\n\nexport const backOut: Easing = cubicBezier(0.33, 1.53, 0.69, 0.99);\nexport const backIn: Easing = reverseEasing(backOut);\nexport const backInOut: Easing = mirrorEasing(backIn);\n\nexport const anticipate: Easing = (p) =>\n (p *= 2) < 1 ? 0.5 * backIn(p) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));\n"],"mappings":";AA8EA,SAAgB,EACd,GACA,GACA,IAA0B,EAAE,EACX;AACjB;CAKA,IAAM,IAAI;CACV,AAA6B,EAAE,yCAAuB,IAAI,KAAK;CAC/D,IAAM,IAAW,EAAE,sBAEb,IAAO,EAAS,IAAI,EAAG,MAAM;CACnC,AAAI,KAAM,GAAM;CAEhB,IAAM,IAAa,EAAG,QAAQ,OAExB,IACJ,EAAQ,SAAS,YAChB,EAAQ,SAAS,WAAW,EAAQ,YAAY,MAmE7C,WA/D8E;EAClF,IAAI,CAAC,GAAU,OAAO;EAEtB,IAAM,IAAY,EAAQ,aAAa,KACjC,IAAU,EAAQ,WAAW,IAC7B,IAAO,EAAQ,QAAQ,GACvB,IAAkB,GAAG,EAAQ,YAAY,KAAK,MAE9C,IAAe,KAAW,IAAI,KAAK,KAAK,IAAY,EAAK,GACzD,IAAe,IAAS,GACxB,IAAsB,KAAK,KAAK,IAAY,EAAK,GAAG,KAEpD,IAAkB,KAAK,IAAI,EAAa,GAAG,GAC3C,IAAY,EAAQ,cAAc,IAAkB,MAAO,IAC3D,IAAY,EAAQ,cAAc,IAAkB,OAAQ,KAE9D;EAEJ,IAAI,IAAe,GAAG;GACpB,IAAM,IAAc,IAAsB,KAAK,KAAK,IAAI,IAAe,EAAa;GACpF,KAAiB,MAER,IADU,KAAK,IAAI,CAAC,IAAe,IAAsB,EAChD,KACX,IAAkB,IAAe,IAAsB,KAAgB,IACxE,KAAK,IAAI,IAAc,EAAE,GACzB,IAAe,KAAK,IAAI,IAAc,EAAE;SAEzC,IAAI,MAAiB,GAC1B,KAAiB,MACf,IAAS,KAAK,IAAI,CAAC,IAAsB,EAAE,IACxC,KAAgB,IAAkB,IAAsB,KAAgB;OACxE;GACL,IAAM,IAAoB,IAAsB,KAAK,KAAK,IAAe,IAAe,EAAE;GAC1F,KAAiB,MAAM;IACrB,IAAM,IAAW,KAAK,IAAI,CAAC,IAAe,IAAsB,EAAE,EAC5D,IAAW,KAAK,IAAI,IAAoB,GAAG,IAAI;IACrD,OAAO,IAAU,MACb,IAAkB,IAAe,IAAsB,KAAgB,KAAK,KAAK,EAAS,GAC1F,IAAoB,IAAe,KAAK,KAAK,EAAS,IAAK;;;EAKnE,IAAM,KAAgB,GAAW,MAA4B;GAC3D,IAAM,IAAQ,KAAK,IAAI,IAAI,GAAG,EAAE,EAC1B,IAAU,EAAc,EAAM,EAC9B,IAAK,IAAI;GACf,OAAO,KAAM,IAAU,MAAY,MAAO,KAAM;;EAGlD,QAAQ,MAAc;GACpB,IAAM,IAAU,EAAc,EAAE,EAC5B,IAAkB,MAAM,IAAI,IAAkB;GAClD,AAAI,IAAe,MACjB,IAAkB,MAAM,IAAI,IAAkB,MAAO,EAAa,GAAG,EAAQ;GAE/E,IAAM,IAA2B,KAAK,IAAI,EAAgB,IAAI,GACxD,IAA+B,KAAK,IAAI,IAAS,EAAQ,IAAI,GAC7D,IAAO,KAA4B;GACzC,OAAO;IAAE;IAAM,OAAO,IAAO,IAAS;IAAS;;KAInB,EAG1B,KAAc,GAAW,GAAY,SACtC,IAAM,IAAM,IAAK,IAAM,KAAM,KAAK,IAAM,IAAK,IAAM,MAAO,IAAI,IAAM,KAAM,GAEzE,KAAmB,GAAW,GAAa,MAAwB;EACvE,IAAI,IAAK,GAAG,IAAK,GAAG,IAAK,GAAG,GAAY,IAAI;EAC5C;GAGE,AAFA,IAAK,KAAM,IAAK,KAAM,GACtB,IAAK,EAAW,GAAI,GAAK,EAAI,GAAG,GAC5B,IAAK,IAAG,IAAK,IAAS,IAAK;SACxB,KAAK,IAAI,EAAG,GAAG,QAAQ,EAAE,IAAI;EACtC,OAAO;IAGH,KAAkB,MAClB,MAAM,KAAK,MAAM,IAAU,IACxB,EAAW,EAAgB,GAAG,GAAG,IAAK,EAAE,GAAG,EAAE,EAGhD,IAAW,EAAQ,YAAY,IAC/B,IAAY,KAAK,KAAK,EAExB,IAAW,IACX,GACA,IAAU,IACR,IAAW,IAAI,SAAe,MAAY;EAAE,IAAiB;GAAW,EAExE,UAAqB;EACrB,MACJ,IAAU,IACN,EAAS,IAAI,EAAG,MAAM,KAAK,KAAM,EAAS,OAAO,EAAG,MAAM,EAC9D,KAAkB;IAGd,UAAmB;EACnB,MACJ,IAAW,IACX,GAAQ;;CAGV,EAAS,IAAI,EAAG,OAAO,EAAK;CAM5B,IAAM,IAAY,YACZ,KAAgB,MAAyB;EAC7C,AAAI,OAAO,EAAU,yBAA0B,aAC7C,EAAU,sBAAsB,EAAG,GAEnC,WAAW,GAAI,GAAG;IAgBhB,UAAwB;EAC5B,IAAM,IAAI;EACN,EAAE,+BACN,EAAE,6BAAgC,IAClC,QAAQ,SAAS,CAAC,WAAW;GAC3B,EAAE,6BAAgC;GAClC,IAAM,IAAK,EAAE;GACb,AAAI,KAAI,GAAI;IACZ;IAGE,UAAmB;EACvB,IAAI,GAAU;EAGd,IAAM,IADM,KAAK,KACC,GAAM,GAClB,IAAa,IAAY,KAE3B,GACA;EAEJ,IAAI,GAAY;GACd,IAAM,IAAQ,EAAW,EAAU;GAEnC,AADA,IAAU,EAAM,OAChB,IAAO,EAAM;SACR,IAAI,KAAc,GAEvB,AADA,IAAU,GACV,IAAO;OACF;GACL,IAAM,IAAI,IAAa;GAEvB,AADA,IAAU,KAAc,IAAS,KAAc,EAAe,EAAE,EAChE,IAAO;;EAMT,AAHA,EAAG,QAAQ,QAAQ,GACnB,GAAW,EAEP,KACE,CAAC,KAAc,EAAG,QAAQ,UAAU,MACtC,EAAG,QAAQ,QAAQ,GACnB,GAAW,GAEb,GAAQ,IAER,EAAa,EAAK;;CAMtB,OAFA,EAAa,EAAK,EAEX;EAAE;EAAM;EAAU;;;;ACnR3B,SAAgB,EACd,GACA,GACA,IAAyB,EAAE,EACZ;AACf;CACA,OAAO,EAAQ,GAAI,GAAQ;EAAE,GAAG;EAAS,MAAM;EAAU,CAAC,CAAC;;;;ACJ7D,SAAgB,EACd,GACA,GACA,IAAyB,EAAE,EACZ;AACf;CACA,OAAO,EAAQ,GAAI,GAAQ;EAAE,GAAG;EAAS,MAAM;EAAS,CAAC,CAAC;;;;ACO5D,IAAM,KAAS,GAAa,GAAa,MACvC,IAAI,IAAM,IAAM,IAAI,IAAM,IAAM,GAE5B,KAAyB,MAAuB,IAAK,KACrD,KAAyB,MAAsB,IAAI,KAEnD,KAAqB,GAAkB,MAC3C,IAA4B,MAAO,IAAnB,IAAoC,GAEhD,IAAyB,GACzB,KACJ,GACA,GACA,MACW;CACX,IAAM,IAAQ,KAAK,IAAI,IAAI,GAAwB,EAAE;CACrD,OAAO,EAAkB,IAAU,EAAa,EAAM,EAAE,IAAI,EAAM;GAK9D,IAAiB;CACrB,WAAW;CACX,SAAS;CACT,MAAM;CACN,UAAU;CACV,WAAW;EAAE,UAAU;EAAM,SAAS;EAAG;CACzC,WAAW;EAAE,UAAU;EAAO,SAAS;EAAK;CAC7C;AAyCD,SAAgB,EAAO,GAA4C;CACjE,IAAM,IAAS,EAAQ,UAAU,IAC3B,IAAS,EAAQ,UAAU,IAE3B,IAAoB;EAAE,MAAM;EAAO,OAAO;EAAQ,EAElD,IAAY,EAAQ,aAAa,EAAe,WAChD,IAAU,EAAQ,WAAW,EAAe,SAC5C,IAAO,EAAQ,QAAQ,EAAe,MAGtC,IAAkB,CAAC,EAAsB,EAAQ,YAAY,EAAE,EAE/D,IAAe,KAAW,IAAI,KAAK,KAAK,IAAY,EAAK,GACzD,IAAe,IAAS,GACxB,IAAsB,EAC1B,KAAK,KAAK,IAAY,EAAK,CAC5B,EAEK,IAAkB,KAAK,IAAI,EAAa,GAAG,GAC3C,IACJ,EAAQ,cACP,IACG,EAAe,UAAU,WACzB,EAAe,UAAU,UACzB,IACJ,EAAQ,cACP,IACG,EAAe,UAAU,WACzB,EAAe,UAAU,UAE3B;CAEJ,IAAI,IAAe,GAAG;EAEpB,IAAM,IACJ,IAAsB,KAAK,KAAK,IAAI,IAAe,EAAa;EAClE,KAAiB,MAGb,IAFe,KAAK,IAAI,CAAC,IAAe,IAAsB,EAG9D,KACK,IACD,IAAe,IAAsB,KACrC,IACA,KAAK,IAAI,IAAc,EAAE,GACzB,IAAe,KAAK,IAAI,IAAc,EAAE;QAG3C,IAAI,MAAiB,GAE1B,KAAiB,MACf,IACA,KAAK,IAAI,CAAC,IAAsB,EAAE,IAC/B,KACE,IAAkB,IAAsB,KAAgB;MAC1D;EAEL,IAAM,IACJ,IAAsB,KAAK,KAAK,IAAe,IAAe,EAAE;EAClE,KAAiB,MAAM;GACrB,IAAM,IAAW,KAAK,IAAI,CAAC,IAAe,IAAsB,EAAE,EAE5D,IAAW,KAAK,IAAI,IAAoB,GAAG,IAAI;GACrD,OACE,IACC,MACG,IACA,IAAe,IAAsB,KACrC,KAAK,KAAK,EAAS,GACnB,IAAoB,IAAe,KAAK,KAAK,EAAS,IACxD;;;CAKR,OAAO,EACL,KAAK,GAAuB;EAC1B,IAAM,IAAU,EAAc,EAAE,EAE5B,IAAkB,MAAM,IAAI,IAAkB;EAGlD,AAAI,IAAe,MACjB,IACE,MAAM,IACF,EAAsB,EAAgB,GACtC,EAAsB,GAAe,GAAG,EAAQ;EAGxD,IAAM,IAA2B,KAAK,IAAI,EAAgB,IAAI,GACxD,IACJ,KAAK,IAAI,IAAS,EAAQ,IAAI;EAIhC,OAFA,EAAM,OAAO,KAA4B,GACzC,EAAM,QAAQ,EAAM,OAAO,IAAS,GAC7B;IAEV;;;;ACzKH,IAAM,KAAgB,MAAM,GAItB,KAAc,GAAW,GAAY,SACtC,IAAM,IAAM,IAAK,IAAM,KAAM,KAAK,IAAM,IAAK,IAAM,MAAO,IAAI,IAAM,KACvE,GAEI,IAAuB,MACvB,IAA2B;AAEjC,SAAS,EACP,GACA,GACA,GACA,GACA,GACQ;CACR,IAAI,GACA,IAAmB,GACnB,IAAI;CACR;EAGE,AAFA,IAAW,KAAc,IAAa,KAAc,GACpD,IAAW,EAAW,GAAU,GAAK,EAAI,GAAG,GACxC,IAAW,IACb,IAAa,IAEb,IAAa;QAGf,KAAK,IAAI,EAAS,GAAG,KACrB,EAAE,IAAI;CAER,OAAO;;AAGT,SAAgB,EACd,GACA,GACA,GACA,GACQ;CACR,IAAI,MAAQ,KAAO,MAAQ,GAAK,OAAO;CACvC,IAAM,KAAY,MAAe,EAAgB,GAAI,GAAG,GAAG,GAAK,EAAI;CACpE,QAAQ,MAAO,MAAM,KAAK,MAAM,IAAI,IAAI,EAAW,EAAS,EAAE,EAAE,GAAK,EAAI;;AAM3E,IAAa,KAAiB,OAA4B,MACxD,IAAI,EAAO,IAAI,EAAE,EAGN,KAAgB,OAA4B,MACvD,KAAK,KAAM,EAAO,IAAI,EAAE,GAAG,KAAK,IAAI,EAAO,KAAK,IAAI,GAAG,IAAI,GAIhD,IAAiB,GAEjB,IAAiB,EAAY,KAAM,GAAG,GAAG,EAAE,EAC3C,IAAkB,EAAY,GAAG,GAAG,KAAM,EAAE,EAC5C,IAAoB,EAAY,KAAM,GAAG,KAAM,EAAE,EAEjD,KAAkB,MAAM,IAAI,KAAK,IAAI,KAAK,KAAK,EAAE,CAAC,EAClD,IAAkB,EAAc,EAAO,EACvC,IAAoB,EAAa,EAAO,EAExC,IAAkB,EAAY,KAAM,MAAM,KAAM,IAAK,EACrD,IAAiB,EAAc,EAAQ,EACvC,IAAoB,EAAa,EAAO,EAExC,KAAsB,OAChC,KAAK,KAAK,IAAI,KAAM,EAAO,EAAE,GAAG,MAAO,IAAa,MAAG,OAAO,IAAI"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAQvC,uBAAuB;AACvB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,wEAAwE;AACxE,2EAA2E;AAC3E,oEAAoE;AACpE,0EAA0E;AAC1E,8CAA8C;AAC9C,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAO5C,0EAA0E;AAC1E,2EAA2E;AAC3E,yEAAyE;AACzE,sDAAsD;AACtD,OAAO,EACL,WAAW,EACX,aAAa,EACb,YAAY,EACZ,MAAM,EACN,MAAM,EACN,OAAO,EACP,SAAS,EACT,MAAM,EACN,OAAO,EACP,SAAS,EACT,MAAM,EACN,OAAO,EACP,SAAS,EACT,UAAU,GACX,MAAM,cAAc,CAAC"}
|
package/dist/spring.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spring solver ported from `motion-dom` v12.23.12 + `motion-utils` v12.23.6
|
|
3
|
+
* (both Apache-2.0).
|
|
4
|
+
* Upstream:
|
|
5
|
+
* - https://github.com/motiondivision/motion/tree/main/packages/motion-dom/src/animation/generators/spring
|
|
6
|
+
* - https://github.com/motiondivision/motion/tree/main/packages/motion-utils/src
|
|
7
|
+
*
|
|
8
|
+
* Sigx adaptation:
|
|
9
|
+
* - Inlined the motion-utils helpers we depend on (`clamp`,
|
|
10
|
+
* `millisecondsToSeconds`, `secondsToMilliseconds`, `velocityPerSecond`)
|
|
11
|
+
* and the velocity calculator from `motion-dom/animation/generators/utils`.
|
|
12
|
+
* These are tiny pure functions; inlining keeps `@sigx/lynx-motion` zero-deps
|
|
13
|
+
* beyond the sigx workspace.
|
|
14
|
+
* - Skipped the duration→physics resolution path (motion's `findSpring`).
|
|
15
|
+
* Phase 2.7 ships only physics-based options (stiffness/damping/mass).
|
|
16
|
+
* If a future user wants `withSpring(av, target, { duration, bounce })`,
|
|
17
|
+
* add `findSpring` then.
|
|
18
|
+
* - `calculatedDuration` and `toString()` / `toTransition()` from upstream
|
|
19
|
+
* are dropped; they're for WAAPI integration which Lynx doesn't use.
|
|
20
|
+
*
|
|
21
|
+
* Verbatim translation of the integrator math; any divergence is a bug.
|
|
22
|
+
*/
|
|
23
|
+
// ---- inlined helpers ------------------------------------------------------
|
|
24
|
+
const clamp = (min, max, v) => v > max ? max : v < min ? min : v;
|
|
25
|
+
const millisecondsToSeconds = (ms) => ms / 1000;
|
|
26
|
+
const secondsToMilliseconds = (s) => s * 1000;
|
|
27
|
+
const velocityPerSecond = (velocity, frameDuration) => frameDuration ? velocity * (1000 / frameDuration) : 0;
|
|
28
|
+
const velocitySampleDuration = 5; // ms
|
|
29
|
+
const calcGeneratorVelocity = (resolveValue, t, current) => {
|
|
30
|
+
const prevT = Math.max(t - velocitySampleDuration, 0);
|
|
31
|
+
return velocityPerSecond(current - resolveValue(prevT), t - prevT);
|
|
32
|
+
};
|
|
33
|
+
// ---- defaults -------------------------------------------------------------
|
|
34
|
+
const springDefaults = {
|
|
35
|
+
stiffness: 100,
|
|
36
|
+
damping: 10,
|
|
37
|
+
mass: 1.0,
|
|
38
|
+
velocity: 0.0,
|
|
39
|
+
restSpeed: { granular: 0.01, default: 2 },
|
|
40
|
+
restDelta: { granular: 0.005, default: 0.5 },
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Build a spring solver. Call `.next(elapsedMs)` repeatedly to step the
|
|
44
|
+
* animation. The solver owns no time state — call `.next` with the current
|
|
45
|
+
* elapsed time each tick (motion's pattern).
|
|
46
|
+
*/
|
|
47
|
+
export function spring(options) {
|
|
48
|
+
const origin = options.keyframes[0];
|
|
49
|
+
const target = options.keyframes[1];
|
|
50
|
+
const state = { done: false, value: origin };
|
|
51
|
+
const stiffness = options.stiffness ?? springDefaults.stiffness;
|
|
52
|
+
const damping = options.damping ?? springDefaults.damping;
|
|
53
|
+
const mass = options.mass ?? springDefaults.mass;
|
|
54
|
+
// Negate to match motion's convention: positive velocity moves toward
|
|
55
|
+
// target, but the integrator expects velocity in source-units convention.
|
|
56
|
+
const initialVelocity = -millisecondsToSeconds(options.velocity ?? 0);
|
|
57
|
+
const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
|
|
58
|
+
const initialDelta = target - origin;
|
|
59
|
+
const undampedAngularFreq = millisecondsToSeconds(Math.sqrt(stiffness / mass));
|
|
60
|
+
const isGranularScale = Math.abs(initialDelta) < 5;
|
|
61
|
+
const restSpeed = options.restSpeed ??
|
|
62
|
+
(isGranularScale
|
|
63
|
+
? springDefaults.restSpeed.granular
|
|
64
|
+
: springDefaults.restSpeed.default);
|
|
65
|
+
const restDelta = options.restDelta ??
|
|
66
|
+
(isGranularScale
|
|
67
|
+
? springDefaults.restDelta.granular
|
|
68
|
+
: springDefaults.restDelta.default);
|
|
69
|
+
let resolveSpring;
|
|
70
|
+
if (dampingRatio < 1) {
|
|
71
|
+
// Underdamped — oscillates while decaying.
|
|
72
|
+
const angularFreq = undampedAngularFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
|
|
73
|
+
resolveSpring = (t) => {
|
|
74
|
+
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
|
75
|
+
return (target -
|
|
76
|
+
envelope *
|
|
77
|
+
(((initialVelocity +
|
|
78
|
+
dampingRatio * undampedAngularFreq * initialDelta) /
|
|
79
|
+
angularFreq) *
|
|
80
|
+
Math.sin(angularFreq * t) +
|
|
81
|
+
initialDelta * Math.cos(angularFreq * t)));
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
else if (dampingRatio === 1) {
|
|
85
|
+
// Critically damped — fastest non-oscillating return.
|
|
86
|
+
resolveSpring = (t) => target -
|
|
87
|
+
Math.exp(-undampedAngularFreq * t) *
|
|
88
|
+
(initialDelta +
|
|
89
|
+
(initialVelocity + undampedAngularFreq * initialDelta) * t);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// Overdamped — slow non-oscillating return.
|
|
93
|
+
const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);
|
|
94
|
+
resolveSpring = (t) => {
|
|
95
|
+
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
|
96
|
+
// Cap freq*t to keep sinh/cosh from hitting Infinity.
|
|
97
|
+
const freqForT = Math.min(dampedAngularFreq * t, 300);
|
|
98
|
+
return (target -
|
|
99
|
+
(envelope *
|
|
100
|
+
((initialVelocity +
|
|
101
|
+
dampingRatio * undampedAngularFreq * initialDelta) *
|
|
102
|
+
Math.sinh(freqForT) +
|
|
103
|
+
dampedAngularFreq * initialDelta * Math.cosh(freqForT))) /
|
|
104
|
+
dampedAngularFreq);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
next(t) {
|
|
109
|
+
const current = resolveSpring(t);
|
|
110
|
+
let currentVelocity = t === 0 ? initialVelocity : 0.0;
|
|
111
|
+
// Velocity calc only needed for underdamped — over/critically-damped
|
|
112
|
+
// can't overshoot, so position alone tells us we're done.
|
|
113
|
+
if (dampingRatio < 1) {
|
|
114
|
+
currentVelocity =
|
|
115
|
+
t === 0
|
|
116
|
+
? secondsToMilliseconds(initialVelocity)
|
|
117
|
+
: calcGeneratorVelocity(resolveSpring, t, current);
|
|
118
|
+
}
|
|
119
|
+
const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;
|
|
120
|
+
const isBelowDisplacementThreshold = Math.abs(target - current) <= restDelta;
|
|
121
|
+
state.done = isBelowVelocityThreshold && isBelowDisplacementThreshold;
|
|
122
|
+
state.value = state.done ? target : current;
|
|
123
|
+
return state;
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// Re-export `clamp` because it's small and useful for animation math, and
|
|
128
|
+
// motion-mini exports it from its mini surface.
|
|
129
|
+
export { clamp };
|
|
130
|
+
//# sourceMappingURL=spring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spring.js","sourceRoot":"","sources":["../src/spring.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convenience wrapper: animate(sv, target, { type: 'spring', ...opts }).
|
|
3
|
+
* Returns the completion promise rather than the full controls handle —
|
|
4
|
+
* use `animate()` directly if you need cancellation.
|
|
5
|
+
*/
|
|
6
|
+
import { animate } from './animate.js';
|
|
7
|
+
export function withSpring(sv, target, options = {}) {
|
|
8
|
+
'main thread';
|
|
9
|
+
return animate(sv, target, { ...options, type: 'spring' }).finished;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=with-spring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-spring.js","sourceRoot":"","sources":["../src/with-spring.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,OAAO,EAAsB,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,UAAU,CACxB,EAAuB,EACvB,MAAc,EACd,OAAO,GAAkB,EAAE;IAE3B,aAAa,CAAC;IACd,OAAO,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convenience wrapper: animate(sv, target, { type: 'tween', ...opts }).
|
|
3
|
+
* Returns the completion promise rather than the full controls handle —
|
|
4
|
+
* use `animate()` directly if you need cancellation.
|
|
5
|
+
*
|
|
6
|
+
* Duration is in seconds (default 0.3). Ease defaults to `easeOut`.
|
|
7
|
+
*/
|
|
8
|
+
import { animate } from './animate.js';
|
|
9
|
+
export function withTiming(sv, target, options = {}) {
|
|
10
|
+
'main thread';
|
|
11
|
+
return animate(sv, target, { ...options, type: 'tween' }).finished;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=with-timing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-timing.js","sourceRoot":"","sources":["../src/with-timing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAE,OAAO,EAAsB,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,UAAU,CACxB,EAAuB,EACvB,MAAc,EACd,OAAO,GAAkB,EAAE;IAE3B,aAAa,CAAC;IACd,OAAO,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC;AACrE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sigx/lynx-motion",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Animation primitives for sigx-lynx — spring/tween drivers built on SharedValue",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -26,14 +26,14 @@
|
|
|
26
26
|
"author": "Andreas Ekdahl",
|
|
27
27
|
"license": "(MIT AND Apache-2.0)",
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@sigx/lynx": "^0.1
|
|
29
|
+
"@sigx/lynx": "^0.4.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@lynx-js/react": "^0.
|
|
32
|
+
"@lynx-js/react": "^0.121.0",
|
|
33
|
+
"@typescript/native-preview": "7.0.0-dev.20260511.1",
|
|
33
34
|
"typescript": "^6.0.3",
|
|
34
|
-
"
|
|
35
|
-
"@sigx/lynx-
|
|
36
|
-
"@sigx/lynx-plugin": "^0.2.7"
|
|
35
|
+
"@sigx/lynx-runtime-main": "^0.4.1",
|
|
36
|
+
"@sigx/lynx-plugin": "^0.4.1"
|
|
37
37
|
},
|
|
38
38
|
"repository": {
|
|
39
39
|
"type": "git",
|
|
@@ -48,7 +48,8 @@
|
|
|
48
48
|
"access": "public"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
|
-
"build": "
|
|
52
|
-
"dev": "
|
|
51
|
+
"build": "node ../../scripts/clean.mjs dist && tsgo",
|
|
52
|
+
"dev": "tsgo --watch",
|
|
53
|
+
"clean": "node ../../scripts/clean.mjs dist .turbo"
|
|
53
54
|
}
|
|
54
55
|
}
|