@vielzeug/necromancer 26.11.4 → 26.11.6

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring.cjs","names":["NecromancerConfigError","shouldReduceMotion","attachAbortSignalListener","require__handle","require_errors","require_motion","DEFAULTS","MAX_FRAME_SECONDS","SUBSTEP_SECONDS","value","name","from","to","stiffness","options","damping","mass","precision","velocity0","disposed","settled","frame","removeAbortListener","result","resolve","animationResult","onUpdate","velocity","lastTime","elapsed","time","remaining","dt","acceleration"],"sources":["../src/spring.ts"],"sourcesContent":["import { attachAbortSignalListener } from './_handle';\nimport { NecromancerConfigError } from './errors';\nimport { shouldReduceMotion } from './motion';\nimport type { AnimationResult, MotionMode } from './types';\n\n/**\n * Physical spring parameters, in the damped-harmonic-oscillator model:\n * `mass * x'' = -stiffness * (x - to) - damping * x'`.\n */\nexport type SpringOptions = Readonly<{\n /** Spring stiffness k. Higher settles faster. Defaults to `170`. */\n readonly stiffness?: number;\n /** Viscous damping c. Lower overshoots more; `2 * sqrt(k * mass)` is critically damped. Defaults to `26`. */\n readonly damping?: number;\n /** Mass m. Defaults to `1`. */\n readonly mass?: number;\n /** Initial velocity in units/s, typically the finger velocity at release. Defaults to `0`. */\n readonly velocity?: number;\n /** Both |x - to| and |velocity| must fall below this to rest. Defaults to `0.1`. */\n readonly precision?: number;\n /** Reduced motion jumps straight to the target. Defaults to `'system'`. */\n readonly motion?: MotionMode;\n /** Disposes the returned handle when aborted. */\n readonly signal?: AbortSignal;\n}>;\n\n/** Called once per frame with the current spring value and velocity (units/s). */\nexport type SpringUpdate = (value: number, velocity: number) => void;\n\n/** A lifecycle-owned spring animation. */\nexport interface SpringHandle {\n /** Stops the spring mid-flight and releases owned listeners. */\n dispose(reason?: unknown): void;\n /** Whether this handle has been disposed. */\n readonly disposed: boolean;\n /** Resolves once the spring rests or is disposed. */\n readonly result: Promise<AnimationResult>;\n /** Calls {@link dispose}. */\n [Symbol.dispose](): void;\n}\n\nconst DEFAULTS = { damping: 26, mass: 1, precision: 0.1, stiffness: 170 } as const;\n\n/** Longest frame integrated in one step; a backgrounded tab resumes without a physics jump. */\nconst MAX_FRAME_SECONDS = 1 / 30;\n\n/** Fixed physics substep; keeps the explicit integrator stable at stiff settings. */\nconst SUBSTEP_SECONDS = 1 / 240;\n\nfunction validate(name: string, value: number): number {\n if (!Number.isFinite(value) || value <= 0) {\n throw new NecromancerConfigError(`${name} must be a positive finite number, got: ${value}`);\n }\n return value;\n}\n\n/**\n * Endpoint validation. Unlike the config knobs, a spring boundary may legitimately be zero or\n * negative (a height animating from `0`, a panel sliding to a negative offset), so only finiteness\n * is enforced. It still has to be checked: the rest test compares against `to`, so a non-finite\n * endpoint can never be satisfied and the spring would request frames forever while emitting NaN.\n */\nfunction validateBound(name: string, value: number): number {\n if (!Number.isFinite(value)) {\n throw new NecromancerConfigError(`${name} must be a finite number, got: ${value}`);\n }\n return value;\n}\n\n/**\n * Animates a scalar value on a physical spring, calling `onUpdate` once per frame.\n *\n * Unlike a fixed-duration easing curve, a spring takes its **initial velocity**\n * from the caller — typically the pointer velocity a gesture reported at release\n * — so a fling continues from the finger's momentum and a slow drag settles\n * without overshoot. The motion is interruptible by design: dispose the handle\n * and start a new spring from the current value and velocity.\n *\n * Under reduced motion the value jumps to the target in a single update.\n */\nexport function spring(from: number, to: number, onUpdate: SpringUpdate, options: SpringOptions = {}): SpringHandle {\n validateBound('from', from);\n validateBound('to', to);\n const stiffness = validate('stiffness', options.stiffness ?? DEFAULTS.stiffness);\n const damping = validate('damping', options.damping ?? DEFAULTS.damping);\n const mass = validate('mass', options.mass ?? DEFAULTS.mass);\n const precision = validate('precision', options.precision ?? DEFAULTS.precision);\n const velocity0 = options.velocity ?? 0;\n if (!Number.isFinite(velocity0)) {\n throw new NecromancerConfigError(`velocity must be a finite number, got: ${velocity0}`);\n }\n options.signal?.throwIfAborted();\n\n let disposed = false;\n let settled = false;\n let frame = 0;\n let removeAbortListener: (() => void) | undefined;\n let settle: (result: AnimationResult) => void = () => undefined;\n\n const result = new Promise<AnimationResult>((resolve) => {\n settle = (animationResult) => {\n settled = true;\n removeAbortListener?.();\n removeAbortListener = undefined;\n resolve(animationResult);\n };\n\n if (shouldReduceMotion(options.motion ?? 'system')) {\n onUpdate(to, 0);\n settle({ status: 'finished' });\n return;\n }\n\n let value = from;\n let velocity = velocity0;\n let lastTime: number | undefined;\n\n const step = (time: number): void => {\n if (disposed) return;\n\n const elapsed = lastTime === undefined ? 0 : Math.min((time - lastTime) / 1000, MAX_FRAME_SECONDS);\n lastTime = time;\n\n let remaining = elapsed;\n while (remaining > 0) {\n const dt = Math.min(remaining, SUBSTEP_SECONDS);\n remaining -= dt;\n // Semi-implicit Euler: update velocity first, then position from it.\n const acceleration = (-stiffness * (value - to) - damping * velocity) / mass;\n velocity += acceleration * dt;\n value += velocity * dt;\n }\n\n if (Math.abs(value - to) < precision && Math.abs(velocity) < precision) {\n onUpdate(to, 0);\n settle({ status: 'finished' });\n return;\n }\n\n onUpdate(value, velocity);\n frame = requestAnimationFrame(step);\n };\n\n frame = requestAnimationFrame(step);\n });\n\n const dispose = (reason?: unknown): void => {\n if (disposed || settled) return;\n\n disposed = true;\n cancelAnimationFrame(frame);\n settle({ reason, status: 'cancelled' });\n };\n\n if (options.signal && !settled) {\n removeAbortListener = attachAbortSignalListener(options.signal, dispose);\n }\n\n return {\n dispose,\n get disposed() {\n return disposed;\n },\n result,\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n"],"mappings":"A,qFAyCA,IAAMM,EAAW,CAAE,QAAS,GAAI,KAAM,EAAG,UAAW,GAAK,UAAW,GAAI,EAGlEC,EAAoB,EAAI,GAGxBC,EAAkB,EAAI,IAE5B,SAAS,SAAS,EAAc,EAAuB,CACrD,GAAI,CAAC,OAAO,SAASC,CAAK,GAAKA,GAAS,EACtC,MAAM,IAAIT,EAAAA,uBAAuB,GAAGU,EAAK,0CAA0CD,GAAO,EAE5F,OAAOA,CACT,CAQA,SAAS,cAAc,EAAc,EAAuB,CAC1D,GAAI,CAAC,OAAO,SAASA,CAAK,EACxB,MAAM,IAAIT,EAAAA,uBAAuB,GAAGU,EAAK,iCAAiCD,GAAO,EAEnF,OAAOA,CACT,CAaA,SAAgB,OAAO,EAAc,EAAY,EAAwB,EAAyB,CAAC,EAAiB,CAClH,cAAc,OAAQE,CAAI,EAC1B,cAAc,KAAMC,CAAE,EACtB,IAAMC,EAAY,SAAS,YAAaC,EAAQ,WAAaR,EAAS,SAAS,EACzES,EAAU,SAAS,UAAWD,EAAQ,SAAWR,EAAS,OAAO,EACjEU,EAAO,SAAS,OAAQF,EAAQ,MAAQR,EAAS,IAAI,EACrDW,EAAY,SAAS,YAAaH,EAAQ,WAAaR,EAAS,SAAS,EACzEY,EAAYJ,EAAQ,UAAY,EACtC,GAAI,CAAC,OAAO,SAASI,CAAS,EAC5B,MAAM,IAAIlB,EAAAA,uBAAuB,0CAA0CkB,GAAW,EAExFJ,EAAQ,QAAQ,eAAe,EAE/B,IAAIK,EAAW,GACXC,EAAU,GACVC,EAAQ,EACRC,EACA,WAAkD,IAAA,GAEhDC,EAAS,IAAI,QAA0B,GAAY,CAQvD,GAPA,OAAU,GAAoB,CAC5B,EAAU,GACVD,IAAsB,EACtB,EAAsB,IAAA,GACtBE,EAAQC,CAAe,CACzB,EAEIxB,EAAAA,mBAAmBa,EAAQ,QAAU,QAAQ,EAAG,CAClDY,EAASd,EAAI,CAAC,EACd,OAAO,CAAE,OAAQ,UAAW,CAAC,EAC7B,MACF,CAEA,IAAIH,EAAQE,EACRgB,EAAWT,EACXU,EAEE,KAAQ,GAAuB,CACnC,GAAIT,EAAU,OAEd,IAAMU,EAAUD,IAAa,IAAA,GAAY,EAAI,KAAK,KAAKE,EAAOF,GAAY,IAAMrB,CAAiB,EACjG,EAAWuB,EAEX,IAAIC,EAAYF,EAChB,KAAOE,EAAY,GAAG,CACpB,IAAMC,EAAK,KAAK,IAAID,EAAWvB,CAAe,EAC9C,GAAawB,EAEb,IAAMC,GAAgB,CAACpB,GAAaJ,EAAQG,GAAMG,EAAUY,GAAYX,EACxE,GAAYiB,EAAeD,EAC3B,GAASL,EAAWK,CACtB,CAEI,KAAK,IAAIvB,EAAQG,CAAE,EAAIK,GAAa,KAAK,IAAIU,CAAQ,EAAIV,GAC3DS,EAASd,EAAI,CAAC,EACd,OAAO,CAAE,OAAQ,UAAW,CAAC,IAI/Bc,EAASjB,EAAOkB,CAAQ,EACxB,EAAQ,sBAAsB,IAAI,EACpC,EAEA,EAAQ,sBAAsB,IAAI,CACpC,CAAC,EAEK,QAAW,GAA2B,CACtCR,GAAYC,IAEhB,EAAW,GACX,qBAAqBC,CAAK,EAC1B,OAAO,CAAE,SAAQ,OAAQ,WAAY,CAAC,EACxC,EAMA,OAJIP,EAAQ,QAAU,CAACM,IACrB,EAAsBlB,EAAAA,0BAA0BY,EAAQ,OAAQ,OAAO,GAGlE,CACL,QACA,IAAI,UAAW,CACb,OAAOK,CACT,EACA,SACA,CAAC,OAAO,UAAW,CACjB,KAAK,QAAQ,CACf,CACF,CACF,C"}
@@ -0,0 +1,47 @@
1
+ import type { AnimationResult, MotionMode } from './types';
2
+ /**
3
+ * Physical spring parameters, in the damped-harmonic-oscillator model:
4
+ * `mass * x'' = -stiffness * (x - to) - damping * x'`.
5
+ */
6
+ export type SpringOptions = Readonly<{
7
+ /** Spring stiffness k. Higher settles faster. Defaults to `170`. */
8
+ readonly stiffness?: number;
9
+ /** Viscous damping c. Lower overshoots more; `2 * sqrt(k * mass)` is critically damped. Defaults to `26`. */
10
+ readonly damping?: number;
11
+ /** Mass m. Defaults to `1`. */
12
+ readonly mass?: number;
13
+ /** Initial velocity in units/s, typically the finger velocity at release. Defaults to `0`. */
14
+ readonly velocity?: number;
15
+ /** Both |x - to| and |velocity| must fall below this to rest. Defaults to `0.1`. */
16
+ readonly precision?: number;
17
+ /** Reduced motion jumps straight to the target. Defaults to `'system'`. */
18
+ readonly motion?: MotionMode;
19
+ /** Disposes the returned handle when aborted. */
20
+ readonly signal?: AbortSignal;
21
+ }>;
22
+ /** Called once per frame with the current spring value and velocity (units/s). */
23
+ export type SpringUpdate = (value: number, velocity: number) => void;
24
+ /** A lifecycle-owned spring animation. */
25
+ export interface SpringHandle {
26
+ /** Stops the spring mid-flight and releases owned listeners. */
27
+ dispose(reason?: unknown): void;
28
+ /** Whether this handle has been disposed. */
29
+ readonly disposed: boolean;
30
+ /** Resolves once the spring rests or is disposed. */
31
+ readonly result: Promise<AnimationResult>;
32
+ /** Calls {@link dispose}. */
33
+ [Symbol.dispose](): void;
34
+ }
35
+ /**
36
+ * Animates a scalar value on a physical spring, calling `onUpdate` once per frame.
37
+ *
38
+ * Unlike a fixed-duration easing curve, a spring takes its **initial velocity**
39
+ * from the caller — typically the pointer velocity a gesture reported at release
40
+ * — so a fling continues from the finger's momentum and a slow drag settles
41
+ * without overshoot. The motion is interruptible by design: dispose the handle
42
+ * and start a new spring from the current value and velocity.
43
+ *
44
+ * Under reduced motion the value jumps to the target in a single update.
45
+ */
46
+ export declare function spring(from: number, to: number, onUpdate: SpringUpdate, options?: SpringOptions): SpringHandle;
47
+ //# sourceMappingURL=spring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring.d.ts","sourceRoot":"","sources":["../src/spring.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE3D;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC;IACnC,oEAAoE;IACpE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,6GAA6G;IAC7G,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,+BAA+B;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,8FAA8F;IAC9F,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,oFAAoF;IACpF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B,iDAAiD;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,CAAC,CAAC;AAEH,kFAAkF;AAClF,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;AAErE,0CAA0C;AAC1C,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,6CAA6C;IAC7C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC1C,6BAA6B;IAC7B,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B;AA8BD;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,GAAE,aAAkB,GAAG,YAAY,CAwFlH"}
package/dist/spring.js ADDED
@@ -0,0 +1,64 @@
1
+ import { attachAbortSignalListener as e } from "./_handle.js";
2
+ import { NecromancerConfigError as t } from "./errors.js";
3
+ import { shouldReduceMotion as n } from "./motion.js";
4
+ // src/spring.ts
5
+ var r = {
6
+ damping: 26,
7
+ mass: 1,
8
+ precision: .1,
9
+ stiffness: 170
10
+ }, i = 1 / 30, a = 1 / 240;
11
+ function validate(e, n) {
12
+ if (!Number.isFinite(n) || n <= 0) throw new t(`${e} must be a positive finite number, got: ${n}`);
13
+ return n;
14
+ }
15
+ function validateBound(e, n) {
16
+ if (!Number.isFinite(n)) throw new t(`${e} must be a finite number, got: ${n}`);
17
+ return n;
18
+ }
19
+ function spring(o, s, c, l = {}) {
20
+ validateBound("from", o), validateBound("to", s);
21
+ let u = validate("stiffness", l.stiffness ?? r.stiffness), d = validate("damping", l.damping ?? r.damping), f = validate("mass", l.mass ?? r.mass), p = validate("precision", l.precision ?? r.precision), m = l.velocity ?? 0;
22
+ if (!Number.isFinite(m)) throw new t(`velocity must be a finite number, got: ${m}`);
23
+ l.signal?.throwIfAborted();
24
+ let h = !1, g = !1, _ = 0, v, settle = () => void 0, y = new Promise((e) => {
25
+ if (settle = (t) => {
26
+ g = !0, v?.(), v = void 0, e(t);
27
+ }, n(l.motion ?? "system")) {
28
+ c(s, 0), settle({ status: "finished" });
29
+ return;
30
+ }
31
+ let t = o, r = m, y, step = (e) => {
32
+ if (h) return;
33
+ let n = y === void 0 ? 0 : Math.min((e - y) / 1e3, i);
34
+ y = e;
35
+ let o = n;
36
+ for (; o > 0;) {
37
+ let e = Math.min(o, a);
38
+ o -= e;
39
+ let n = (-u * (t - s) - d * r) / f;
40
+ r += n * e, t += r * e;
41
+ }
42
+ Math.abs(t - s) < p && Math.abs(r) < p ? (c(s, 0), settle({ status: "finished" })) : (c(t, r), _ = requestAnimationFrame(step));
43
+ };
44
+ _ = requestAnimationFrame(step);
45
+ }), dispose = (e) => {
46
+ h || g || (h = !0, cancelAnimationFrame(_), settle({
47
+ reason: e,
48
+ status: "cancelled"
49
+ }));
50
+ };
51
+ return l.signal && !g && (v = e(l.signal, dispose)), {
52
+ dispose,
53
+ get disposed() {
54
+ return h;
55
+ },
56
+ result: y,
57
+ [Symbol.dispose]() {
58
+ this.dispose();
59
+ }
60
+ };
61
+ }
62
+ export { spring };
63
+
64
+ //# sourceMappingURL=spring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring.js","names":["DEFAULTS","MAX_FRAME_SECONDS","SUBSTEP_SECONDS","value","NecromancerConfigError","name","from","to","stiffness","options","damping","mass","precision","velocity0","disposed","settled","frame","removeAbortListener","result","resolve","animationResult","shouldReduceMotion","onUpdate","velocity","lastTime","elapsed","time","remaining","dt","acceleration","attachAbortSignalListener"],"sources":["../src/spring.ts"],"sourcesContent":["import { attachAbortSignalListener } from './_handle';\nimport { NecromancerConfigError } from './errors';\nimport { shouldReduceMotion } from './motion';\nimport type { AnimationResult, MotionMode } from './types';\n\n/**\n * Physical spring parameters, in the damped-harmonic-oscillator model:\n * `mass * x'' = -stiffness * (x - to) - damping * x'`.\n */\nexport type SpringOptions = Readonly<{\n /** Spring stiffness k. Higher settles faster. Defaults to `170`. */\n readonly stiffness?: number;\n /** Viscous damping c. Lower overshoots more; `2 * sqrt(k * mass)` is critically damped. Defaults to `26`. */\n readonly damping?: number;\n /** Mass m. Defaults to `1`. */\n readonly mass?: number;\n /** Initial velocity in units/s, typically the finger velocity at release. Defaults to `0`. */\n readonly velocity?: number;\n /** Both |x - to| and |velocity| must fall below this to rest. Defaults to `0.1`. */\n readonly precision?: number;\n /** Reduced motion jumps straight to the target. Defaults to `'system'`. */\n readonly motion?: MotionMode;\n /** Disposes the returned handle when aborted. */\n readonly signal?: AbortSignal;\n}>;\n\n/** Called once per frame with the current spring value and velocity (units/s). */\nexport type SpringUpdate = (value: number, velocity: number) => void;\n\n/** A lifecycle-owned spring animation. */\nexport interface SpringHandle {\n /** Stops the spring mid-flight and releases owned listeners. */\n dispose(reason?: unknown): void;\n /** Whether this handle has been disposed. */\n readonly disposed: boolean;\n /** Resolves once the spring rests or is disposed. */\n readonly result: Promise<AnimationResult>;\n /** Calls {@link dispose}. */\n [Symbol.dispose](): void;\n}\n\nconst DEFAULTS = { damping: 26, mass: 1, precision: 0.1, stiffness: 170 } as const;\n\n/** Longest frame integrated in one step; a backgrounded tab resumes without a physics jump. */\nconst MAX_FRAME_SECONDS = 1 / 30;\n\n/** Fixed physics substep; keeps the explicit integrator stable at stiff settings. */\nconst SUBSTEP_SECONDS = 1 / 240;\n\nfunction validate(name: string, value: number): number {\n if (!Number.isFinite(value) || value <= 0) {\n throw new NecromancerConfigError(`${name} must be a positive finite number, got: ${value}`);\n }\n return value;\n}\n\n/**\n * Endpoint validation. Unlike the config knobs, a spring boundary may legitimately be zero or\n * negative (a height animating from `0`, a panel sliding to a negative offset), so only finiteness\n * is enforced. It still has to be checked: the rest test compares against `to`, so a non-finite\n * endpoint can never be satisfied and the spring would request frames forever while emitting NaN.\n */\nfunction validateBound(name: string, value: number): number {\n if (!Number.isFinite(value)) {\n throw new NecromancerConfigError(`${name} must be a finite number, got: ${value}`);\n }\n return value;\n}\n\n/**\n * Animates a scalar value on a physical spring, calling `onUpdate` once per frame.\n *\n * Unlike a fixed-duration easing curve, a spring takes its **initial velocity**\n * from the caller — typically the pointer velocity a gesture reported at release\n * — so a fling continues from the finger's momentum and a slow drag settles\n * without overshoot. The motion is interruptible by design: dispose the handle\n * and start a new spring from the current value and velocity.\n *\n * Under reduced motion the value jumps to the target in a single update.\n */\nexport function spring(from: number, to: number, onUpdate: SpringUpdate, options: SpringOptions = {}): SpringHandle {\n validateBound('from', from);\n validateBound('to', to);\n const stiffness = validate('stiffness', options.stiffness ?? DEFAULTS.stiffness);\n const damping = validate('damping', options.damping ?? DEFAULTS.damping);\n const mass = validate('mass', options.mass ?? DEFAULTS.mass);\n const precision = validate('precision', options.precision ?? DEFAULTS.precision);\n const velocity0 = options.velocity ?? 0;\n if (!Number.isFinite(velocity0)) {\n throw new NecromancerConfigError(`velocity must be a finite number, got: ${velocity0}`);\n }\n options.signal?.throwIfAborted();\n\n let disposed = false;\n let settled = false;\n let frame = 0;\n let removeAbortListener: (() => void) | undefined;\n let settle: (result: AnimationResult) => void = () => undefined;\n\n const result = new Promise<AnimationResult>((resolve) => {\n settle = (animationResult) => {\n settled = true;\n removeAbortListener?.();\n removeAbortListener = undefined;\n resolve(animationResult);\n };\n\n if (shouldReduceMotion(options.motion ?? 'system')) {\n onUpdate(to, 0);\n settle({ status: 'finished' });\n return;\n }\n\n let value = from;\n let velocity = velocity0;\n let lastTime: number | undefined;\n\n const step = (time: number): void => {\n if (disposed) return;\n\n const elapsed = lastTime === undefined ? 0 : Math.min((time - lastTime) / 1000, MAX_FRAME_SECONDS);\n lastTime = time;\n\n let remaining = elapsed;\n while (remaining > 0) {\n const dt = Math.min(remaining, SUBSTEP_SECONDS);\n remaining -= dt;\n // Semi-implicit Euler: update velocity first, then position from it.\n const acceleration = (-stiffness * (value - to) - damping * velocity) / mass;\n velocity += acceleration * dt;\n value += velocity * dt;\n }\n\n if (Math.abs(value - to) < precision && Math.abs(velocity) < precision) {\n onUpdate(to, 0);\n settle({ status: 'finished' });\n return;\n }\n\n onUpdate(value, velocity);\n frame = requestAnimationFrame(step);\n };\n\n frame = requestAnimationFrame(step);\n });\n\n const dispose = (reason?: unknown): void => {\n if (disposed || settled) return;\n\n disposed = true;\n cancelAnimationFrame(frame);\n settle({ reason, status: 'cancelled' });\n };\n\n if (options.signal && !settled) {\n removeAbortListener = attachAbortSignalListener(options.signal, dispose);\n }\n\n return {\n dispose,\n get disposed() {\n return disposed;\n },\n result,\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n}\n"],"mappings":";;;;AAyCA,IAAMA,IAAW;CAAE,SAAS;CAAI,MAAM;CAAG,WAAW;CAAK,WAAW;AAAI,GAGlEC,IAAoB,IAAI,IAGxBC,IAAkB,IAAI;AAE5B,SAAS,SAAS,GAAc,GAAuB;CACrD,IAAI,CAAC,OAAO,SAASC,CAAK,KAAKA,KAAS,GACtC,MAAM,IAAIC,EAAuB,GAAGC,EAAK,0CAA0CF,GAAO;CAE5F,OAAOA;AACT;AAQA,SAAS,cAAc,GAAc,GAAuB;CAC1D,IAAI,CAAC,OAAO,SAASA,CAAK,GACxB,MAAM,IAAIC,EAAuB,GAAGC,EAAK,iCAAiCF,GAAO;CAEnF,OAAOA;AACT;AAaA,SAAgB,OAAO,GAAc,GAAY,GAAwB,IAAyB,CAAC,GAAiB;CAElH,AADA,cAAc,QAAQG,CAAI,GAC1B,cAAc,MAAMC,CAAE;CACtB,IAAMC,IAAY,SAAS,aAAaC,EAAQ,aAAaT,EAAS,SAAS,GACzEU,IAAU,SAAS,WAAWD,EAAQ,WAAWT,EAAS,OAAO,GACjEW,IAAO,SAAS,QAAQF,EAAQ,QAAQT,EAAS,IAAI,GACrDY,IAAY,SAAS,aAAaH,EAAQ,aAAaT,EAAS,SAAS,GACzEa,IAAYJ,EAAQ,YAAY;CACtC,IAAI,CAAC,OAAO,SAASI,CAAS,GAC5B,MAAM,IAAIT,EAAuB,0CAA0CS,GAAW;CAExF,EAAQ,QAAQ,eAAe;CAE/B,IAAIC,IAAW,IACXC,IAAU,IACVC,IAAQ,GACRC,GACA,eAAkD,KAAA,GAEhDC,IAAS,IAAI,SAA0B,MAAY;EAQvD,IAPA,UAAU,MAAoB;GAI5B,AAHA,IAAU,IACVD,IAAsB,GACtB,IAAsB,KAAA,GACtBE,EAAQC,CAAe;EACzB,GAEIC,EAAmBZ,EAAQ,UAAU,QAAQ,GAAG;GAElD,AADAa,EAASf,GAAI,CAAC,GACd,OAAO,EAAE,QAAQ,WAAW,CAAC;GAC7B;EACF;EAEA,IAAIJ,IAAQG,GACRiB,IAAWV,GACXW,GAEE,QAAQ,MAAuB;GACnC,IAAIV,GAAU;GAEd,IAAMW,IAAUD,MAAa,KAAA,IAAY,IAAI,KAAK,KAAKE,IAAOF,KAAY,KAAMvB,CAAiB;GACjG,IAAWyB;GAEX,IAAIC,IAAYF;GAChB,OAAOE,IAAY,IAAG;IACpB,IAAMC,IAAK,KAAK,IAAID,GAAWzB,CAAe;IAC9C,KAAa0B;IAEb,IAAMC,KAAgB,CAACrB,KAAaL,IAAQI,KAAMG,IAAUa,KAAYZ;IAExE,AADA,KAAYkB,IAAeD,GAC3B,KAASL,IAAWK;GACtB;GAEA,AAAI,KAAK,IAAIzB,IAAQI,CAAE,IAAIK,KAAa,KAAK,IAAIW,CAAQ,IAAIX,KAC3DU,EAASf,GAAI,CAAC,GACd,OAAO,EAAE,QAAQ,WAAW,CAAC,MAI/Be,EAASnB,GAAOoB,CAAQ,GACxB,IAAQ,sBAAsB,IAAI;EACpC;EAEA,IAAQ,sBAAsB,IAAI;CACpC,CAAC,GAEK,WAAW,MAA2B;EAC1C,AAAIT,KAAYC,MAEhB,IAAW,IACX,qBAAqBC,CAAK,GAC1B,OAAO;GAAE;GAAQ,QAAQ;EAAY,CAAC;CACxC;CAMA,OAJIP,EAAQ,UAAU,CAACM,MACrB,IAAsBe,EAA0BrB,EAAQ,QAAQ,OAAO,IAGlE;EACL;EACA,IAAI,WAAW;GACb,OAAOK;EACT;EACA;EACA,CAAC,OAAO,WAAW;GACjB,KAAK,QAAQ;EACf;CACF;AACF"}
package/dist/testing.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/testing/index.ts
1
+ // src/testing/index.ts
2
2
  var FakeAnimation = class {
3
3
  #e;
4
4
  #t;
@@ -43,7 +43,6 @@ function installFakeAnimations() {
43
43
  function createRect(e, t, n = 20, r = 20) {
44
44
  return new DOMRect(e, t, n, r);
45
45
  }
46
- //#endregion
47
46
  export { FakeAnimation, createRect, installFakeAnimations };
48
47
 
49
48
  //# sourceMappingURL=testing.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielzeug/necromancer",
3
- "version": "26.11.4",
3
+ "version": "26.11.6",
4
4
  "description": "Lifecycle-owned Web Animations API primitives with native access, per-handle groups, and additive FLIP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -43,22 +43,22 @@
43
43
  "registry": "https://registry.npmjs.org/"
44
44
  },
45
45
  "scripts": {
46
- "build": "vite build && pnpm --silent run build:bundle && pnpm --silent run build:types && pnpm --silent run test:types",
46
+ "build": "vite build && bun run --silent build:bundle && bun run --silent build:types && bun run --silent test:types",
47
47
  "build:bundle": "vite build --config vite.bundle.config.ts",
48
48
  "build:types": "tsc -p tsconfig.declarations.json",
49
49
  "fix": "biome check --write src",
50
50
  "lint": "biome ci src",
51
- "prepublishOnly": "pnpm --silent run build",
51
+ "prepublishOnly": "bun run --silent build",
52
52
  "test": "vitest",
53
- "test:e2e": "pnpm --silent run build && playwright test",
53
+ "test:e2e": "bun run --silent build && playwright test",
54
54
  "test:types": "tsc -p tsconfig.type-tests.json"
55
55
  },
56
56
  "devDependencies": {
57
- "@playwright/test": "^1.64.1",
58
- "@types/node": "^26.6.5",
59
- "jsdom": "^30.1.3",
57
+ "@playwright/test": "^1.65.0",
58
+ "@types/node": "^26.6.6",
59
+ "jsdom": "^31.0.0",
60
60
  "typescript": "^6.0.3",
61
- "vite": "^8.3.4",
62
- "vitest": "^5.0.5"
61
+ "vite": "^8.3.6",
62
+ "vitest": "^5.1.0"
63
63
  }
64
64
  }