coily 0.12.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1032 @@
1
+ //#region src/config.d.ts
2
+ /**
3
+ * A spring's instantaneous motion, measured relative to its target.
4
+ * `SpringDefinition.computeTimeRemaining` takes one; build it from a live
5
+ * spring as `{ position: spring.value - spring.target, velocity: spring.velocity }`.
6
+ */
7
+ interface SpringState {
8
+ /** Displacement from the target in value units. 0 means at the target. */
9
+ readonly position: number;
10
+ /** Rate of change of the displacement, in value units per second. */
11
+ readonly velocity: number;
12
+ }
13
+ interface BaseOptions {
14
+ /**
15
+ * Decimal places of the resting threshold. A spring rests once its
16
+ * remaining motion cannot reach half a unit in the last place —
17
+ * `0.5 * 10^-precision`, or 0.005 at the default.
18
+ *
19
+ * Values are never rounded; precision only decides rest. See
20
+ * https://github.com/tkofh/coily/blob/main/PRECISION.md.
21
+ *
22
+ * @default 2
23
+ */
24
+ readonly precision?: number | undefined;
25
+ }
26
+ interface WithMass {
27
+ /**
28
+ * Mass of the moving value. Heavier springs accelerate more slowly and
29
+ * carry more momentum through the target. Must be greater than 0.
30
+ * @default 1
31
+ */
32
+ readonly mass?: number | undefined;
33
+ }
34
+ interface WithoutMass {
35
+ /**
36
+ * Mass is derived from the other parameters in this input shape
37
+ * and cannot be provided.
38
+ */
39
+ readonly mass?: undefined;
40
+ }
41
+ interface WithTension {
42
+ /**
43
+ * Spring stiffness. Higher tension pulls toward the target harder,
44
+ * making the whole motion faster. Must be greater than 0.
45
+ */
46
+ readonly tension: number;
47
+ }
48
+ interface WithDamping {
49
+ /**
50
+ * Friction strength. Higher damping bleeds off velocity faster and
51
+ * reduces bounce; at 0 the spring oscillates forever. Must be greater
52
+ * than or equal to 0.
53
+ */
54
+ readonly damping: number;
55
+ }
56
+ interface WithDampingRatio {
57
+ /**
58
+ * Damping as a fraction of critical damping — the character of the
59
+ * motion, independent of its speed. Below 1 the spring overshoots and
60
+ * bounces. At 1 it settles as fast as possible without overshooting.
61
+ * Above 1 it settles slower, still without overshooting. At 0 it never
62
+ * settles. Must be greater than or equal to 0.
63
+ */
64
+ readonly dampingRatio: number;
65
+ }
66
+ interface WithBounce {
67
+ /**
68
+ * Bounciness, converted to a damping ratio as `1 - bounce`. 0 settles
69
+ * as fast as possible without overshooting. Positive values overshoot
70
+ * and bounce; 1, maximum bounce, is clamped just short of undamped so
71
+ * the spring still settles. Negative values settle without bounce, more
72
+ * slowly. Must be between -1 and 1.
73
+ */
74
+ readonly bounce: number;
75
+ }
76
+ interface WithDuration {
77
+ /**
78
+ * Target settle time in milliseconds. The spring is tuned so its motion
79
+ * decays into the resting threshold within this time, assuming it
80
+ * starts `displacement` away from the target. Actual rest lands at or
81
+ * before the requested duration. Must be greater than 0.
82
+ */
83
+ readonly duration: number;
84
+ }
85
+ interface WithDisplacement {
86
+ /**
87
+ * The initial displacement the duration tuning assumes. Set it to your
88
+ * animation's range — 300 when animating 0 to 300 — so the settle
89
+ * timing holds; timing skews as the real displacement diverges from
90
+ * this value. Must not be 0.
91
+ * @default 1
92
+ */
93
+ readonly displacement?: number | undefined;
94
+ }
95
+ interface DirectOptions extends BaseOptions, WithMass, WithTension, WithDamping {}
96
+ interface TensionRatioOptions extends BaseOptions, WithMass, WithTension, WithDampingRatio {}
97
+ interface TensionBounceOptions extends BaseOptions, WithMass, WithTension, WithBounce {}
98
+ interface DampingRatioOptions extends BaseOptions, WithMass, WithDamping, WithDampingRatio {}
99
+ interface DampingBounceOptions extends BaseOptions, WithMass, WithDamping, WithBounce {}
100
+ interface TensionDampingRatioOptions extends BaseOptions, WithoutMass, WithTension, WithDamping, WithDampingRatio {}
101
+ interface TensionDampingBounceOptions extends BaseOptions, WithoutMass, WithTension, WithDamping, WithBounce {}
102
+ interface DurationOptions extends BaseOptions, WithMass, WithDampingRatio, WithDuration, WithDisplacement {}
103
+ interface BounceDurationOptions extends BaseOptions, WithMass, WithBounce, WithDuration, WithDisplacement {}
104
+ interface TensionDurationOptions extends BaseOptions, WithoutMass, WithTension, WithDampingRatio, WithDuration, WithDisplacement {}
105
+ interface TensionBounceDurationOptions extends BaseOptions, WithoutMass, WithTension, WithBounce, WithDuration, WithDisplacement {}
106
+ interface DampingDurationOptions extends BaseOptions, WithoutMass, WithDamping, WithDampingRatio, WithDuration, WithDisplacement {}
107
+ interface DampingBounceDurationOptions extends BaseOptions, WithoutMass, WithDamping, WithBounce, WithDuration, WithDisplacement {}
108
+ /** Every option key accepted by at least one `defineSpring` input shape. */
109
+ type SpringOptionKeys = 'mass' | 'tension' | 'damping' | 'dampingRatio' | 'bounce' | 'duration' | 'displacement' | 'precision';
110
+ /**
111
+ * Marks every option key foreign to `T` as "absent or undefined", so mixing
112
+ * properties from different input shapes fails to type-check instead of
113
+ * silently resolving to an unintended shape at runtime.
114
+ */
115
+ type Exact<T> = T & { [K in Exclude<SpringOptionKeys, keyof T>]?: undefined; };
116
+ /**
117
+ * Every input `defineSpring` accepts: one of the documented parameter
118
+ * combinations, exactly as written — keys from different combinations
119
+ * don't mix.
120
+ */
121
+ type SpringDefinitionOptions = Exact<DirectOptions> | Exact<TensionRatioOptions> | Exact<TensionBounceOptions> | Exact<DampingRatioOptions> | Exact<DampingBounceOptions> | Exact<TensionDampingRatioOptions> | Exact<TensionDampingBounceOptions> | Exact<DurationOptions> | Exact<BounceDurationOptions> | Exact<TensionDurationOptions> | Exact<TensionBounceDurationOptions> | Exact<DampingDurationOptions> | Exact<DampingBounceDurationOptions>;
122
+ /**
123
+ * Immutable, resolved spring parameters. Whatever `defineSpring` input
124
+ * shape produced it, a config carries concrete `mass`, `tension`,
125
+ * `damping`, and `precision`, plus the quantities derived from them.
126
+ * Instances are frozen and safe to share between springs; to change a
127
+ * spring's behavior, assign a new config via `spring.config`.
128
+ */
129
+ declare class SpringDefinition {
130
+ /** The config for springs created without one: critically damped, settling in about 500ms. */
131
+ static readonly default: SpringDefinition;
132
+ /** Mass of the moving value, as provided or derived. */
133
+ readonly mass: number;
134
+ /** Spring stiffness, as provided or derived. */
135
+ readonly tension: number;
136
+ /** Friction strength, as provided or derived. */
137
+ readonly damping: number;
138
+ /** Decimal places of the resting threshold — see `restingMagnitude`. */
139
+ readonly precision: number;
140
+ /** Oscillation rate with no damping: `sqrt(tension / mass)`, in radians per second. */
141
+ readonly naturalFrequency: number;
142
+ /** The damping at which bounce disappears: `2 * mass * naturalFrequency`. */
143
+ readonly criticalDamping: number;
144
+ /**
145
+ * `damping / criticalDamping`. Below 1 the spring overshoots and
146
+ * bounces, at 1 it settles fastest without overshooting, above 1 it
147
+ * settles slower.
148
+ */
149
+ readonly dampingRatio: number;
150
+ /** Resting threshold in value units: half a unit in the last `precision` place. */
151
+ readonly restingMagnitude: number;
152
+ constructor(input: SpringDefinitionOptions);
153
+ /**
154
+ * Estimates how long a spring with this config takes to come to rest
155
+ * from `state`, in milliseconds.
156
+ *
157
+ * The estimate follows the motion's decay envelope with a 2x safety
158
+ * margin, so actual rest usually lands earlier. Returns 0 when `state`
159
+ * is already inside the resting threshold, and Infinity when the config
160
+ * never settles (a `dampingRatio` of 0).
161
+ */
162
+ computeTimeRemaining(state: SpringState): number;
163
+ }
164
+ /**
165
+ * Creates a config from direct physical parameters: you set stiffness
166
+ * and friction exactly.
167
+ */
168
+ declare function defineSpring(input: Exact<DirectOptions>): SpringDefinition;
169
+ /**
170
+ * Creates a config from stiffness and motion character. Damping is
171
+ * derived as `2 * dampingRatio * sqrt(mass * tension)`.
172
+ */
173
+ declare function defineSpring(input: Exact<TensionRatioOptions>): SpringDefinition;
174
+ /**
175
+ * Creates a config from stiffness and bounciness. Damping is derived to
176
+ * match the requested bounce, from -1 (no bounce, slow settle) to 1
177
+ * (maximum bounce).
178
+ */
179
+ declare function defineSpring(input: Exact<TensionBounceOptions>): SpringDefinition;
180
+ /**
181
+ * Creates a config from friction and motion character. Tension is
182
+ * derived as `damping^2 / (4 * dampingRatio^2 * mass)`; `dampingRatio`
183
+ * must be greater than 0.
184
+ */
185
+ declare function defineSpring(input: Exact<DampingRatioOptions>): SpringDefinition;
186
+ /**
187
+ * Creates a config from friction and bounciness. Tension is derived to
188
+ * match the requested bounce; `bounce` must be less than 1.
189
+ */
190
+ declare function defineSpring(input: Exact<DampingBounceOptions>): SpringDefinition;
191
+ /**
192
+ * Creates a config from all three physical knobs. Mass is derived as
193
+ * `damping^2 / (4 * dampingRatio^2 * tension)` and cannot be provided;
194
+ * `dampingRatio` must be greater than 0.
195
+ */
196
+ declare function defineSpring(input: Exact<TensionDampingRatioOptions>): SpringDefinition;
197
+ /**
198
+ * Creates a config from all three physical knobs. Mass is derived from
199
+ * tension, damping, and the requested bounce, and cannot be provided;
200
+ * `bounce` must be less than 1.
201
+ */
202
+ declare function defineSpring(input: Exact<TensionDampingBounceOptions>): SpringDefinition;
203
+ /**
204
+ * Tunes the spring to settle within `duration` milliseconds, with
205
+ * `dampingRatio` setting the motion's character. Tension and damping are
206
+ * both derived.
207
+ *
208
+ * The timing assumes the motion starts `displacement` (default 1) away
209
+ * from the target — pass a `displacement` matching your animation range
210
+ * for accurate timing.
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * // Tuned for a 300px move; rests within 750ms
215
+ * defineSpring({ duration: 750, dampingRatio: 1, displacement: 300 })
216
+ * ```
217
+ */
218
+ declare function defineSpring(input: Exact<DurationOptions>): SpringDefinition;
219
+ /**
220
+ * Tunes the spring to settle within `duration` milliseconds, with
221
+ * `bounce` setting how oscillatory the settling motion is. Tension and
222
+ * damping are both derived.
223
+ *
224
+ * The timing assumes the motion starts `displacement` (default 1) away
225
+ * from the target — pass a `displacement` matching your animation range
226
+ * for accurate timing.
227
+ */
228
+ declare function defineSpring(input: Exact<BounceDurationOptions>): SpringDefinition;
229
+ /**
230
+ * Tunes a spring of the given stiffness to settle within `duration`
231
+ * milliseconds. Mass is derived from tension and the computed natural
232
+ * frequency, then damping from mass and `dampingRatio`; mass cannot be
233
+ * provided.
234
+ *
235
+ * The timing assumes the motion starts `displacement` (default 1) away
236
+ * from the target — pass a `displacement` matching your animation range
237
+ * for accurate timing.
238
+ */
239
+ declare function defineSpring(input: Exact<TensionDurationOptions>): SpringDefinition;
240
+ /**
241
+ * Tunes a spring of the given stiffness to settle within `duration`
242
+ * milliseconds, with `bounce` setting how oscillatory the settling motion
243
+ * is. Mass is derived from tension and the computed natural frequency,
244
+ * and cannot be provided.
245
+ *
246
+ * The timing assumes the motion starts `displacement` (default 1) away
247
+ * from the target — pass a `displacement` matching your animation range
248
+ * for accurate timing.
249
+ */
250
+ declare function defineSpring(input: Exact<TensionBounceDurationOptions>): SpringDefinition;
251
+ /**
252
+ * Tunes a spring of the given friction to settle within `duration`
253
+ * milliseconds. Mass is derived from damping, `dampingRatio`, and the
254
+ * computed natural frequency, then tension from mass; mass cannot be
255
+ * provided.
256
+ *
257
+ * The timing assumes the motion starts `displacement` (default 1) away
258
+ * from the target — pass a `displacement` matching your animation range
259
+ * for accurate timing.
260
+ */
261
+ declare function defineSpring(input: Exact<DampingDurationOptions>): SpringDefinition;
262
+ /**
263
+ * Tunes a spring of the given friction to settle within `duration`
264
+ * milliseconds, with `bounce` setting how oscillatory the settling motion
265
+ * is. Mass is derived from damping and the computed natural frequency,
266
+ * and cannot be provided.
267
+ *
268
+ * The timing assumes the motion starts `displacement` (default 1) away
269
+ * from the target — pass a `displacement` matching your animation range
270
+ * for accurate timing.
271
+ */
272
+ declare function defineSpring(input: Exact<DampingBounceDurationOptions>): SpringDefinition;
273
+ //#endregion
274
+ //#region src/flush-queue.d.ts
275
+ /**
276
+ * Defers callbacks while inside a batch or tick: `request` runs the
277
+ * callback immediately at depth 0 and queues it — deduplicated — until
278
+ * the outermost exit otherwise. Composite springs use it to coalesce
279
+ * per-channel events into composite ones.
280
+ */
281
+ declare class FlushQueue {
282
+ #private;
283
+ request(callback: () => void): void;
284
+ batch(fn: () => void): void;
285
+ enter(): void;
286
+ exit(): void;
287
+ }
288
+ //#endregion
289
+ //#region src/motion.d.ts
290
+ /**
291
+ * One spring simulation in displacement space: position is measured from
292
+ * the target (0 means settled), so retargeting is a rebase performed by
293
+ * the owning `Spring`. Picks the closed-form solver for the config's
294
+ * damping regime and emits update/start/stop/dispose events.
295
+ */
296
+ declare class Motion {
297
+ #private;
298
+ /** Tick-pass marker written by `MotionSet` so a motion re-added mid-pass isn't ticked twice. */
299
+ _pass: number;
300
+ respectsReducedMotion: boolean;
301
+ constructor(config: SpringDefinition, position: number, velocity: number);
302
+ get position(): number;
303
+ set position(value: number);
304
+ get velocity(): number;
305
+ set velocity(value: number);
306
+ get timeRemaining(): number;
307
+ get isResting(): boolean;
308
+ configure(config: SpringDefinition): void;
309
+ tick(dt: number, emit?: boolean): void;
310
+ finish(): void;
311
+ onUpdate(callback: () => void): () => void;
312
+ onStart(callback: () => void): () => void;
313
+ onStop(callback: () => void): () => void;
314
+ onDispose(callback: () => void): () => void;
315
+ dispose(): void;
316
+ }
317
+ //#endregion
318
+ //#region src/motion-set.d.ts
319
+ /**
320
+ * The set of motions currently moving. Motions leave the set as they
321
+ * rest and re-enter on any write that disturbs them; `onWake` tells the
322
+ * ticker the set became non-empty so it can stop sleeping.
323
+ */
324
+ declare class MotionSet {
325
+ #private;
326
+ reduced: boolean;
327
+ onWake: (() => void) | null;
328
+ readonly flushes: FlushQueue;
329
+ constructor(debug?: boolean);
330
+ get size(): number;
331
+ add(motion: Motion): void;
332
+ remove(motion: Motion): void;
333
+ finishAll(): void;
334
+ tick(dt: number): void;
335
+ }
336
+ //#endregion
337
+ //#region src/spring-source.d.ts
338
+ /**
339
+ * The property key that brands a `SpringSource` and holds the channel its
340
+ * followers read. A registry symbol (`Symbol.for('coily/spring-source')`),
341
+ * so sources from one copy of coily are recognized by another when a
342
+ * bundle duplicates the library.
343
+ */
344
+ declare const SpringSourceSymbol: unique symbol;
345
+ /**
346
+ * What a source exposes to its followers, held under `SpringSourceSymbol`
347
+ * on the source object. Followers read `value` on every update and
348
+ * detach on dispose.
349
+ */
350
+ interface SpringSourceApi<T = number> {
351
+ /** The current value, in value units. */
352
+ readonly value: T;
353
+ /** Subscribes to value changes. Returns an unsubscribe function. */
354
+ onUpdate(callback: () => void): () => void;
355
+ /** Subscribes to the source being released. Returns an unsubscribe function. */
356
+ onDispose(callback: () => void): () => void;
357
+ }
358
+ /**
359
+ * A live value a spring can animate toward or derive from. `T` is the
360
+ * value's type: a scalar source (`T = number`, the default) can be
361
+ * assigned to `Spring.target`, which then tracks it momentum intact.
362
+ *
363
+ * Every `Spring` is a `SpringSource`, every `CompositeSpring` is a
364
+ * `SpringSource` of its value shape, and `mapSpring`, `velocityOf`, and
365
+ * `accelerationOf` derive fresh sources from existing ones. You take
366
+ * sources from those APIs and pass them wherever one is accepted; the
367
+ * type names such a value in your own signatures.
368
+ */
369
+ interface SpringSource<T = number> {
370
+ readonly [SpringSourceSymbol]: SpringSourceApi<T>;
371
+ }
372
+ /**
373
+ * Compile-time validation of a shape of sources: every leaf must be a
374
+ * `SpringSource`, every branch a plain object or array with at least one
375
+ * leaf. Used as `sources: T & SourceShape<T>` so an invalid leaf errors
376
+ * on that property rather than on the whole argument. Purely structural,
377
+ * and mirrored by the runtime validation for untyped callers. Optional
378
+ * and `undefined`-typed leaves are rejected.
379
+ */
380
+ type SourceShape<T> = 0 extends 1 & T ? T : T extends SpringSource<unknown> ? SpringSource<unknown> : T extends ((...args: never) => unknown) | (abstract new (...args: never) => unknown) ? never : T extends readonly never[] ? never : T extends object ? keyof T extends never ? never : { [K in keyof T]-?: 0 extends 1 & T[K] ? T[K] : undefined extends T[K] ? never : SourceShape<T[K]>; } : never;
381
+ /**
382
+ * The value shape a shape of sources produces: the same nesting with
383
+ * every `SpringSource` leaf replaced by its value — `number` for a
384
+ * scalar spring, the read-only value shape for a composite. What `map`
385
+ * receives when `mapSpring` is given a shape.
386
+ */
387
+ type SourceValues<T> = T extends SpringSource<infer V> ? V : { readonly [K in keyof T]: SourceValues<T[K]>; };
388
+ /**
389
+ * Derives a source from another by a pure function of its value:
390
+ * `mapSpring(leader, (v) => v + 10)` follows 10 above the leader,
391
+ * `(v) => -v` mirrors it. Maps compose — a mapped source is a
392
+ * `SpringSource` like any other, so it can be mapped again, used as a
393
+ * leaf of a shape map, or followed by several springs at once.
394
+ *
395
+ * The result is a stateless view, not a spring: it holds no
396
+ * subscriptions and needs no disposal, and reads compute `map` of the
397
+ * source's current value on the fly. `map` must be pure — it runs on
398
+ * every read and every source update, and nothing re-evaluates it when
399
+ * anything other than `source` changes. Composition is flat: mapping a
400
+ * mapped source extends its pipeline rather than wrapping it, so chains
401
+ * cost one function call per map however long they grow.
402
+ */
403
+ declare function mapSpring(source: SpringSource, map: (value: number) => number): SpringSource;
404
+ /**
405
+ * Derives a scalar source from several channels by a pure function of
406
+ * their values. `sources` is a shape — a plain object or array with
407
+ * `SpringSource` leaves, nested arbitrarily — or a single non-scalar
408
+ * source such as a `CompositeSpring`. `map` receives the matching
409
+ * values: each leaf's current number for a shape
410
+ * (`mapSpring({ x, y }, ({ x, y }) => Math.hypot(x, y))`), the
411
+ * live value shape for a composite
412
+ * (`mapSpring(point, ({ x, y }) => Math.hypot(x, y))`). Invalid
413
+ * leaves throw with their path (`position.z`).
414
+ *
415
+ * The result is a stateless view, not a spring: it holds no
416
+ * subscriptions and needs no disposal, and reads compute `map` over the
417
+ * sources' values on the fly. `map` must be pure — it runs on every
418
+ * read and every source update — and must not retain what it receives:
419
+ * every call hands it the same live mirror of the values, refreshed in
420
+ * place. The mapped source is released with the first of its sources:
421
+ * followers detach then, keeping their current target, as they would
422
+ * from a disposed spring.
423
+ */
424
+ declare function mapSpring<const T extends object>(sources: T & SourceShape<T>, map: (values: SourceValues<T>) => number): SpringSource;
425
+ //#endregion
426
+ //#region src/kinematic-source.d.ts
427
+ /**
428
+ * A `SpringSourceApi` whose value is in motion, so it also reports the
429
+ * value's derivatives: `velocity` (the rate `value` changes, in value
430
+ * units per second) and `acceleration` (the rate `velocity` changes, in
431
+ * value units per second squared). A `Spring` and a `CompositeSpring`
432
+ * carry both exactly — they fall out of the same equation that drives
433
+ * the motion — as does a source bridging a value whose motion it tracks.
434
+ * A value derived with `mapSpring` does not: it holds no motion of its
435
+ * own, so its derivatives would need the derivative of an arbitrary
436
+ * function. `velocityOf` and `accelerationOf` read this slot.
437
+ */
438
+ interface KinematicSourceApi<T = number> extends SpringSourceApi<T> {
439
+ /** The current velocity, in value units per second. */
440
+ readonly velocity: T;
441
+ /** The current acceleration, in value units per second squared. */
442
+ readonly acceleration: T;
443
+ }
444
+ /**
445
+ * A `SpringSource` whose value is in motion, so it also carries the
446
+ * value's `velocity` and `acceleration` — every `Spring` and
447
+ * `CompositeSpring` is one. `velocityOf` and `accelerationOf` accept
448
+ * these; a plain `SpringSource` (such as a `mapSpring` result) is not
449
+ * assignable, since a value derivation is not in motion.
450
+ */
451
+ interface KinematicSource<T = number> extends SpringSource<T> {
452
+ readonly [SpringSourceSymbol]: KinematicSourceApi<T>;
453
+ }
454
+ /**
455
+ * Derives a source from another's velocity — the rate its value changes,
456
+ * in value units per second. `velocityOf(motion)` is a source that reads
457
+ * `motion`'s current velocity, so speed-driven effects fall out of the
458
+ * same follow and `mapSpring` machinery as everything else: a spring can
459
+ * follow it (`blur.target = velocityOf(motion)`) and a map can shape it
460
+ * (`mapSpring(velocityOf(motion), (v) => 1 + Math.abs(v) * 0.001)` for
461
+ * squash and stretch). A scalar source yields a scalar velocity a spring
462
+ * can follow; a `CompositeSpring` or shape yields a velocity of the same
463
+ * shape, mapped to a scalar the way the composite itself is.
464
+ *
465
+ * The result is a stateless view, not a spring: it holds no
466
+ * subscriptions and needs no disposal, and reads report the source's
467
+ * current velocity on the fly. It updates when the source does and is
468
+ * released with it — followers detach then, keeping their current
469
+ * target, as they would from a disposed spring.
470
+ *
471
+ * Only a source in motion qualifies — a `Spring` or a `CompositeSpring`.
472
+ * A value derived with `mapSpring` has no velocity (its rate of change
473
+ * would need the derivative of the map), so it is rejected at the type
474
+ * level and at runtime; take `velocityOf` of the spring the map reads
475
+ * instead.
476
+ */
477
+ declare function velocityOf<T>(source: KinematicSource<T>): SpringSource<T>;
478
+ /**
479
+ * Derives a source from another's acceleration — the rate its velocity
480
+ * changes, in value units per second squared. `accelerationOf(motion)`
481
+ * spikes when `motion` is pushed hardest and passes through zero at the
482
+ * peak of a swing, so force-driven effects fall out of the same follow
483
+ * and `mapSpring` machinery: a spring can follow it, and a map can turn
484
+ * it into an impact flash or a jelly wobble
485
+ * (`mapSpring(accelerationOf(motion), (a) => Math.min(1, Math.abs(a) * 1e-4))`).
486
+ * A scalar source yields a scalar acceleration; a `CompositeSpring` or
487
+ * shape yields an acceleration of the same shape, mapped to a scalar the
488
+ * way the composite itself is.
489
+ *
490
+ * The result is a stateless view, not a spring: it holds no
491
+ * subscriptions and needs no disposal, and reads report the source's
492
+ * current acceleration on the fly. It updates when the source does and
493
+ * is released with it, followers detaching then as from a disposed
494
+ * spring.
495
+ *
496
+ * Only a source in motion qualifies — a `Spring` or a `CompositeSpring`.
497
+ * A value derived with `mapSpring` has no acceleration, so it is rejected
498
+ * at the type level and at runtime; take `accelerationOf` of the spring
499
+ * the map reads instead.
500
+ */
501
+ declare function accelerationOf<T>(source: KinematicSource<T>): SpringSource<T>;
502
+ //#endregion
503
+ //#region src/spring.d.ts
504
+ /**
505
+ * What a spring can animate toward: a fixed number, or a `SpringSource`
506
+ * — another spring, or a value derived from one with `mapSpring` —
507
+ * whose live value the spring follows.
508
+ */
509
+ type SpringTarget = number | SpringSource;
510
+ /**
511
+ * What a spring animates, which decides whether reduced motion applies to
512
+ * it. `'motion'` moves something on screen — position, scale, rotation —
513
+ * and snaps to its target under reduced motion. `'appearance'` changes
514
+ * how something looks without moving it — a cross-fade, a color, a blur —
515
+ * and keeps animating under reduced motion, since it carries no motion to
516
+ * reduce. Fixed when the spring is created; read it back from
517
+ * `Spring.purpose`.
518
+ */
519
+ type Purpose = 'motion' | 'appearance';
520
+ /**
521
+ * One animated number, driven toward its target with damped spring
522
+ * motion. Create springs with `SpringSystem.createSpring`; the owning
523
+ * system advances them, so a spring only moves while its system runs.
524
+ *
525
+ * Reads return the exact simulated state; nothing is rounded. Numeric
526
+ * writes — `target`, `value`, `velocity`, `jumpTo` — require finite
527
+ * numbers: `NaN` or an infinity throws rather than poisoning the
528
+ * simulation. See
529
+ * https://github.com/tkofh/coily/blob/main/PRECISION.md for the
530
+ * numerical contract.
531
+ */
532
+ declare class Spring implements KinematicSource {
533
+ #private;
534
+ /** Brands the spring as a `KinematicSource` whose api is the spring itself. */
535
+ get [SpringSourceSymbol](): KinematicSourceApi<number>;
536
+ constructor(motions: MotionSet, value: number, config?: SpringDefinition, purpose?: Purpose);
537
+ /**
538
+ * The value the spring is animating toward. While following a source,
539
+ * reads return the source's value as of its last update.
540
+ *
541
+ * Assignment accepts any `SpringTarget`:
542
+ * - A number retargets the spring. The current value and momentum carry
543
+ * over, so mid-flight retargets stay smooth. Assigning a number while
544
+ * following also stops the following.
545
+ * - A `SpringSource` — a `Spring`, or a value derived with `mapSpring` —
546
+ * makes this spring follow the source's live value.
547
+ *
548
+ * Under reduced motion, retargets apply instantly — unless `purpose` is
549
+ * `'appearance'`, in which case they animate as normal.
550
+ */
551
+ get target(): number;
552
+ set target(value: SpringTarget);
553
+ /**
554
+ * The current animated value: the target plus the remaining
555
+ * displacement.
556
+ *
557
+ * Writing displaces the spring: it keeps its target and springs back
558
+ * from the written value, notifying update listeners synchronously.
559
+ * Writing the current value is a no-op. Under reduced motion a write
560
+ * jumps the spring — target included — to the written value, unless
561
+ * `purpose` is `'appearance'`, in which case it displaces as normal.
562
+ */
563
+ get value(): number;
564
+ set value(value: number);
565
+ /**
566
+ * The current velocity, in value units per second.
567
+ *
568
+ * Writing flings the spring: motion continues from the current value
569
+ * with the written velocity, then settles back to the target. Under
570
+ * reduced motion writes are ignored, unless `purpose` is `'appearance'`,
571
+ * in which case the fling applies as normal.
572
+ */
573
+ get velocity(): number;
574
+ set velocity(value: number);
575
+ /**
576
+ * The current acceleration, in value units per second squared — how
577
+ * fast the velocity is changing. Read-only: acceleration is the
578
+ * spring's stiffness and friction acting on its current displacement
579
+ * and velocity, so it follows from the motion rather than being set.
580
+ * To fling the spring, write `velocity` instead.
581
+ */
582
+ get acceleration(): number;
583
+ /**
584
+ * What the spring animates — `'motion'` or `'appearance'` — fixed when
585
+ * it was created. An `'appearance'` spring opts out of reduced motion:
586
+ * it keeps animating where a `'motion'` spring snaps to its target. See
587
+ * `Purpose`.
588
+ */
589
+ get purpose(): Purpose;
590
+ /**
591
+ * The spring's `SpringDefinition`: the one it was created with or last
592
+ * assigned, otherwise `SpringDefinition.default`. Following a source
593
+ * never changes it — how a spring chases its target is the spring's
594
+ * own setting.
595
+ *
596
+ * Assigning a config reconfigures the spring in place — value and
597
+ * velocity are preserved, so mid-flight reconfigures stay smooth.
598
+ * Assigning `null` reverts to the default.
599
+ */
600
+ get config(): SpringDefinition;
601
+ /** The config's mass. */
602
+ get mass(): number;
603
+ /** The config's tension (stiffness). */
604
+ get tension(): number;
605
+ /** The config's damping (friction). */
606
+ get damping(): number;
607
+ /** The config's damping ratio. */
608
+ get dampingRatio(): number;
609
+ /** The config's resting precision. */
610
+ get precision(): number;
611
+ set config(value: SpringDefinition | null);
612
+ /**
613
+ * Estimated milliseconds until the spring rests: 0 while resting,
614
+ * Infinity when undamped. The estimate carries a safety margin, so
615
+ * actual rest usually lands earlier.
616
+ */
617
+ get timeRemaining(): number;
618
+ /**
619
+ * Whether the spring's remaining motion is inside its resting
620
+ * threshold. Resting springs cost nothing until the next write. See
621
+ * https://github.com/tkofh/coily/blob/main/PRECISION.md for the rest
622
+ * test.
623
+ */
624
+ get isResting(): boolean;
625
+ /**
626
+ * A promise that resolves when the spring next comes to rest — already
627
+ * resolved while resting or after dispose. Retargeting mid-flight
628
+ * extends the wait; disposing resolves it.
629
+ *
630
+ * @example
631
+ * ```ts
632
+ * spring.target = 300
633
+ * await spring.settled
634
+ * // the spring is at 300 and resting
635
+ * ```
636
+ */
637
+ get settled(): Promise<void>;
638
+ /**
639
+ * Snaps the spring to `value` with no animation: target and value both
640
+ * become `value` and velocity clears. Listeners are notified
641
+ * synchronously — `update`, plus `stop` if the spring was moving.
642
+ */
643
+ jumpTo(value: number): void;
644
+ /**
645
+ * Releases the spring permanently: stops following, detaches followers
646
+ * (each keeps its current target), resolves `settled`, and notifies
647
+ * dispose listeners. Calling it again is a no-op.
648
+ *
649
+ * A disposed spring keeps its final value readable; writes throw.
650
+ */
651
+ dispose(): void;
652
+ /**
653
+ * Subscribes to value changes: every tick the spring moves, plus
654
+ * synchronous `value` writes and `jumpTo` calls. Returns an unsubscribe
655
+ * function.
656
+ */
657
+ onUpdate(callback: () => void): () => void;
658
+ /**
659
+ * Subscribes to the spring leaving rest. `start` and `stop` always
660
+ * alternate; retargeting mid-flight fires neither. Returns an
661
+ * unsubscribe function.
662
+ */
663
+ onStart(callback: () => void): () => void;
664
+ /**
665
+ * Subscribes to the spring coming to rest, whether by settling or by
666
+ * `jumpTo`. Always alternates with `start`. Returns an unsubscribe
667
+ * function.
668
+ */
669
+ onStop(callback: () => void): () => void;
670
+ /** Subscribes to `dispose`, which fires once. Returns an unsubscribe function. */
671
+ onDispose(callback: () => void): () => void;
672
+ }
673
+ //#endregion
674
+ //#region src/composite-spring.d.ts
675
+ /**
676
+ * Compile-time validation of a value shape: every channel must be a `number`,
677
+ * every branch a plain object or array with at least one channel. Used as
678
+ * `value: T & Shape<T>` so an invalid channel errors on that property rather
679
+ * than on the whole argument. Purely structural — interfaces satisfy it
680
+ * without index signatures — and mirrored by the runtime
681
+ * validation for untyped callers. Optional and `undefined`-typed channels
682
+ * are rejected: a channel that may be absent would make two springs of the
683
+ * same declared shape structurally incompatible at runtime.
684
+ */
685
+ type Shape<T> = 0 extends 1 & T ? T : T extends number ? number : T extends ((...args: never) => unknown) | (abstract new (...args: never) => unknown) ? never : T extends readonly never[] ? never : T extends object ? keyof T extends never ? never : { [K in keyof T]-?: 0 extends 1 & T[K] ? T[K] : undefined extends T[K] ? never : Shape<T[K]>; } : never;
686
+ /**
687
+ * A partial view of a value shape: the same nesting with any subset of the
688
+ * numeric channels present. Absent (or `undefined`) channels are left alone.
689
+ */
690
+ type PartialShape<T> = T extends number ? number : { readonly [K in keyof T]?: PartialShape<T[K]> | undefined; };
691
+ /**
692
+ * A deep-readonly view of a value shape. Composite reads (`target`, `value`,
693
+ * `velocity`, `acceleration`) return the spring's live mirror objects —
694
+ * refreshed in place on every read — so their channels are typed read-only.
695
+ */
696
+ type ReadonlyShape<T> = T extends number ? number : { readonly [K in keyof T]: ReadonlyShape<T[K]>; };
697
+ /**
698
+ * Configuration for a composite spring: a single `SpringDefinition` applied to every
699
+ * channel, or an object mirroring the value shape with configs at any level.
700
+ * A config at a subtree applies to every channel below it.
701
+ * `null` reverts to the default config.
702
+ * Configs are always `SpringDefinition` instances (from `defineSpring`), so a
703
+ * plain object is unambiguously a config shape and any non-config leaf it
704
+ * reaches is an error.
705
+ */
706
+ type ConfigShape<T> = SpringDefinition | null | (T extends number ? never : { readonly [K in keyof T]?: ConfigShape<T[K]> | undefined; });
707
+ /**
708
+ * What each channel of a composite spring animates: a single `Purpose`
709
+ * for every channel, or a shape mirroring the value with purposes at any
710
+ * level. A purpose at a subtree covers every channel below it, and any
711
+ * channel it doesn't reach defaults to `'motion'`. Fixed when the spring
712
+ * is created. See `Purpose`.
713
+ */
714
+ type PurposeShape<T> = Purpose | (T extends number ? never : { readonly [K in keyof T]?: PurposeShape<T[K]> | undefined; });
715
+ /**
716
+ * A partial target shape: the same nesting as the value with any subset
717
+ * of the channels present, each taking a number to animate toward or a
718
+ * scalar `SpringSource` to follow. Absent (or `undefined`) channels are
719
+ * left alone.
720
+ */
721
+ type TargetShape<T> = T extends number ? number | SpringSource : { readonly [K in keyof T]?: TargetShape<T[K]> | undefined; };
722
+ /**
723
+ * What a composite spring can animate toward: a partial shape mixing
724
+ * numbers and scalar `SpringSource`s per channel, or another composite
725
+ * spring of the same shape to follow channel by channel.
726
+ */
727
+ type CompositeSpringTarget<T extends object> = TargetShape<T> | CompositeSpring<T>;
728
+ /**
729
+ * A composite spring over a fixed numeric shape — a nested plain object
730
+ * or array whose leaves are all numbers. Each leaf runs an independent
731
+ * spring, called a channel, behind one API: targets, values, velocities,
732
+ * and configs read and write as (partial) shapes, and events are
733
+ * coalesced across channels. Create composite springs with
734
+ * `SpringSystem.createSpring`.
735
+ *
736
+ * A composite spring is a `SpringSource` of its value shape: `mapSpring`
737
+ * derives scalar sources from it — alone or at the leaves of a shape —
738
+ * which springs can then follow. Only scalar sources are followable
739
+ * directly.
740
+ *
741
+ * The shape is fixed at construction. Writes naming unknown channels
742
+ * throw with the channel's path (`position.z`), and so do non-finite
743
+ * channel values.
744
+ */
745
+ declare class CompositeSpring<in out T extends object> implements KinematicSource<ReadonlyShape<T>> {
746
+ #private;
747
+ /** Brands the composite as a `KinematicSource` whose api is the composite itself. */
748
+ get [SpringSourceSymbol](): KinematicSourceApi<ReadonlyShape<T>>;
749
+ constructor(motions: MotionSet, value: T & Shape<T>, config?: ConfigShape<T>, purpose?: PurposeShape<T>);
750
+ /**
751
+ * The value each channel is animating toward, as a read-only mirror of
752
+ * the shape. The mirror object is reused: every read refreshes its
753
+ * numbers in place, so read it fresh rather than holding it across
754
+ * frames.
755
+ *
756
+ * Assignment accepts a `CompositeSpringTarget`:
757
+ * - A partial shape retargets the channels it names and leaves the
758
+ * others alone. Each named channel takes a number, or a scalar
759
+ * `SpringSource` to follow — a `Spring`, or a value derived with
760
+ * `mapSpring`. While following a leader, naming a channel also
761
+ * detaches that channel from it.
762
+ * - A `CompositeSpring` of the same shape follows the leader channel by
763
+ * channel.
764
+ *
765
+ * Unknown channels throw with their path.
766
+ */
767
+ get target(): ReadonlyShape<T>;
768
+ set target(value: CompositeSpringTarget<T>);
769
+ /**
770
+ * The current animated value of every channel, as a read-only mirror of
771
+ * the shape. The mirror object is reused: every read refreshes its
772
+ * numbers in place, so read it fresh rather than holding it across
773
+ * frames.
774
+ *
775
+ * Assignment takes a partial shape and displaces the channels it names:
776
+ * each keeps its target and springs back from the written value, with
777
+ * one coalesced `update` fired synchronously. Under reduced motion a
778
+ * write jumps the named channels — targets included — except channels
779
+ * whose `purpose` is `'appearance'`, which displace as normal.
780
+ */
781
+ get value(): ReadonlyShape<T>;
782
+ set value(value: PartialShape<T>);
783
+ /**
784
+ * The current velocity of every channel in value units per second, as a
785
+ * read-only mirror of the shape — reused and refreshed in place on each
786
+ * read.
787
+ *
788
+ * Assignment takes a partial shape and flings the channels it names;
789
+ * the rest are untouched. Under reduced motion writes are ignored,
790
+ * except on channels whose `purpose` is `'appearance'`.
791
+ */
792
+ get velocity(): ReadonlyShape<T>;
793
+ set velocity(value: PartialShape<T>);
794
+ /**
795
+ * The current acceleration of every channel in value units per second
796
+ * squared, as a read-only mirror of the shape — reused and refreshed in
797
+ * place on each read. Read-only, like each channel's: acceleration
798
+ * follows from the motion. To fling channels, write `velocity`.
799
+ */
800
+ get acceleration(): ReadonlyShape<T>;
801
+ /**
802
+ * The shared config when every channel resolves to the same
803
+ * `SpringDefinition`, and `null` when they differ.
804
+ *
805
+ * Assignment accepts a `ConfigShape`: one config for every channel,
806
+ * `null` to revert every channel to the default, or a shape mirroring
807
+ * the value with configs at any level — a config at a subtree covers
808
+ * every channel below it. Non-config leaves throw with their path.
809
+ */
810
+ get config(): SpringDefinition | null;
811
+ set config(value: ConfigShape<T>);
812
+ /**
813
+ * The shared purpose when every channel resolves to the same `Purpose`,
814
+ * and `null` when they differ. Fixed when the spring is created — an
815
+ * `'appearance'` channel opts out of reduced motion. See `Purpose`.
816
+ */
817
+ get purpose(): Purpose | null;
818
+ /** The largest `timeRemaining` across channels, in milliseconds. */
819
+ get timeRemaining(): number;
820
+ /** Whether every channel is resting. */
821
+ get isResting(): boolean;
822
+ /**
823
+ * A promise that resolves when every channel next rests — already
824
+ * resolved while resting or after dispose. Retargeting any channel
825
+ * mid-flight extends the wait; disposing resolves it.
826
+ */
827
+ get settled(): Promise<void>;
828
+ /**
829
+ * Snaps the channels the partial shape names to the given values with
830
+ * no animation, notifying listeners synchronously. Channels it leaves
831
+ * out are untouched.
832
+ */
833
+ jumpTo(value: PartialShape<T>): void;
834
+ /**
835
+ * Releases every channel permanently: resolves `settled` and notifies
836
+ * dispose listeners. Calling it again is a no-op.
837
+ *
838
+ * A disposed composite spring keeps its final values readable; writes
839
+ * throw.
840
+ */
841
+ dispose(): void;
842
+ /**
843
+ * Subscribes to coalesced value changes: at most one `update` per tick,
844
+ * fired after every channel has advanced, plus one per synchronous
845
+ * write. Returns an unsubscribe function.
846
+ */
847
+ onUpdate(callback: () => void): () => void;
848
+ /**
849
+ * Subscribes to the composite leaving rest: a channel starts moving
850
+ * while all were resting. Always alternates with `stop`. Returns an
851
+ * unsubscribe function.
852
+ */
853
+ onStart(callback: () => void): () => void;
854
+ /**
855
+ * Subscribes to the composite coming to rest: every channel resting,
856
+ * fired after that tick's final `update`. Always alternates with
857
+ * `start`. Returns an unsubscribe function.
858
+ */
859
+ onStop(callback: () => void): () => void;
860
+ /** Subscribes to `dispose`, which fires once. Returns an unsubscribe function. */
861
+ onDispose(callback: () => void): () => void;
862
+ }
863
+ //#endregion
864
+ //#region src/ticker.d.ts
865
+ /** Frame timing options for a spring system. */
866
+ interface TickerOptions {
867
+ /**
868
+ * Frame-rate cap. 0 means uncapped: one tick per displayed frame,
869
+ * whatever rate the screen runs at — 60Hz, 120Hz, or adaptive. Capped
870
+ * ticks are paced to whole display frames, near the requested rate, and
871
+ * each still receives the true elapsed time.
872
+ * @default 0
873
+ */
874
+ readonly fps?: number | undefined;
875
+ /**
876
+ * Frame gap in milliseconds above which the gap is treated as lag — a
877
+ * backgrounded tab, a blocking task — and replaced with `adjustedLag`,
878
+ * so springs don't teleport when frames resume. 0 disables lag
879
+ * clamping.
880
+ * @default 500
881
+ */
882
+ readonly lagThreshold?: number | undefined;
883
+ /**
884
+ * The elapsed milliseconds a lagging frame is replaced with. Clamped to
885
+ * at most `lagThreshold`.
886
+ * @default 33
887
+ */
888
+ readonly adjustedLag?: number | undefined;
889
+ }
890
+ //#endregion
891
+ //#region src/system.d.ts
892
+ /**
893
+ * Per-spring options for `SpringSystem.createSpring`, separate from the
894
+ * physical `config`.
895
+ */
896
+ interface SpringOptions {
897
+ /**
898
+ * What the spring animates, which decides whether reduced motion applies
899
+ * to it. `'appearance'` — a cross-fade, a color, a blur — keeps
900
+ * animating under reduced motion; `'motion'` snaps to the target. Fixed
901
+ * for the spring's life. See `Purpose`.
902
+ * @default 'motion'
903
+ */
904
+ purpose?: Purpose | undefined;
905
+ }
906
+ /**
907
+ * Per-spring options for a composite `SpringSystem.createSpring`, separate
908
+ * from the physical `config`.
909
+ */
910
+ interface CompositeSpringOptions<T extends object> {
911
+ /**
912
+ * What each channel animates, deciding reduced-motion behavior per
913
+ * channel: a single `Purpose` for every channel, or a shape mirroring
914
+ * the value with purposes at any level — a purpose at a subtree covers
915
+ * every channel below it. Channels it doesn't reach default to
916
+ * `'motion'`. Fixed for the spring's life. See `PurposeShape`.
917
+ * @default 'motion'
918
+ */
919
+ purpose?: PurposeShape<T> | undefined;
920
+ }
921
+ interface SpringSystemOptions extends TickerOptions {
922
+ /**
923
+ * Log active motion counts to the console whenever they change.
924
+ * @default false
925
+ */
926
+ debug?: boolean | undefined;
927
+ /**
928
+ * When springs snap to their targets instead of animating. `'user'`
929
+ * follows the OS prefers-reduced-motion setting, including live changes
930
+ * — switching it on finishes in-flight motion instantly. `'always'` and
931
+ * `'never'` force one behavior.
932
+ * @default 'user'
933
+ */
934
+ reducedMotion?: 'user' | 'always' | 'never' | undefined;
935
+ }
936
+ /**
937
+ * Owns springs and advances them over time. Create one with
938
+ * `createSpringSystem`, then either `start()` it to animate on real
939
+ * frames or call `advance` yourself for manual stepping.
940
+ */
941
+ interface SpringSystem {
942
+ /**
943
+ * Creates a spring at rest at `value`. Without `config`, springs use
944
+ * the default: critically damped, settling in about 500ms. To follow
945
+ * another spring from birth, pass it in place of `value`.
946
+ *
947
+ * `options.purpose` marks what the spring animates: `'appearance'`
948
+ * keeps animating under reduced motion, `'motion'` (the default) snaps.
949
+ */
950
+ createSpring(value: number, config?: SpringDefinition, options?: SpringOptions): Spring;
951
+ /**
952
+ * Creates a spring already following `source` — a `Spring`, or a value
953
+ * derived with `mapSpring`. It starts at the source's current value,
954
+ * so nothing moves until the source does; equivalent to creating a
955
+ * spring at that value and assigning `source` to its `target`.
956
+ *
957
+ * `options.purpose` marks what the spring animates: `'appearance'`
958
+ * keeps animating under reduced motion, `'motion'` (the default) snaps.
959
+ */
960
+ createSpring(source: SpringSource, config?: SpringDefinition, options?: SpringOptions): Spring;
961
+ /**
962
+ * Creates a composite spring over a numeric shape: a plain object or
963
+ * array, nested arbitrarily, whose leaves are all numbers. Each leaf
964
+ * becomes an independently sprung channel.
965
+ *
966
+ * `config` applies per channel: a single `SpringDefinition` for every
967
+ * channel, or a shape mirroring the value with configs at any level.
968
+ * `options.purpose` marks reduced-motion behavior the same way, per
969
+ * channel — an `'appearance'` channel keeps animating.
970
+ */
971
+ createSpring<T extends object>(value: T & Shape<T>, config?: ConfigShape<T>, options?: CompositeSpringOptions<T>): CompositeSpring<T>;
972
+ /**
973
+ * Advances every moving spring by `dt` milliseconds. For manual
974
+ * stepping in place of `start()` — tests, custom loops, offline
975
+ * rendering.
976
+ */
977
+ advance(dt: number): void;
978
+ /**
979
+ * Begins animating on real frames: one tick per displayed frame, via
980
+ * `requestAnimationFrame` in the browser and a `setTimeout` fallback
981
+ * elsewhere. An idle system sleeps — no frames are scheduled while
982
+ * every spring rests.
983
+ */
984
+ start(): void;
985
+ /** Stops animating. Springs hold their state until `start` or `advance`. */
986
+ stop(): void;
987
+ /**
988
+ * Whether the system is between `start()` and `stop()`. Sleeping while
989
+ * idle still counts as running.
990
+ */
991
+ readonly running: boolean;
992
+ /**
993
+ * Whether springs currently snap instead of animating, per the
994
+ * `reducedMotion` option and, in `'user'` mode, the live OS setting.
995
+ * Read it to gate purely decorative effects of your own. Springs
996
+ * created with `purpose: 'appearance'` animate regardless.
997
+ */
998
+ readonly reducedMotion: boolean;
999
+ /**
1000
+ * Frame-rate cap. 0 means uncapped: one tick per displayed frame,
1001
+ * whatever rate the screen runs at. Capped ticks land on whole display
1002
+ * frames and receive the true elapsed time.
1003
+ */
1004
+ fps: number;
1005
+ /**
1006
+ * Frame gap in milliseconds above which the gap is treated as lag — a
1007
+ * backgrounded tab, a blocking task — and replaced with `adjustedLag`,
1008
+ * so springs don't teleport when frames resume. 0 disables lag
1009
+ * clamping.
1010
+ */
1011
+ lagThreshold: number;
1012
+ /** The elapsed milliseconds a lagging frame is replaced with. Clamped to at most `lagThreshold`. */
1013
+ adjustedLag: number;
1014
+ }
1015
+ /**
1016
+ * Creates a spring system: the entry point of the library.
1017
+ *
1018
+ * @example
1019
+ * ```ts
1020
+ * const system = createSpringSystem()
1021
+ * system.start()
1022
+ *
1023
+ * const spring = system.createSpring(0)
1024
+ * spring.onUpdate(() => {
1025
+ * element.style.translate = `${spring.value}px 0`
1026
+ * })
1027
+ * spring.target = 300
1028
+ * ```
1029
+ */
1030
+ declare function createSpringSystem(options?: SpringSystemOptions): SpringSystem;
1031
+ //#endregion
1032
+ export { SpringDefinitionOptions as C, SpringDefinition as S, defineSpring as T, accelerationOf as _, createSpringSystem as a, SpringSourceSymbol as b, ConfigShape as c, ReadonlyShape as d, Shape as f, KinematicSource as g, SpringTarget as h, SpringSystemOptions as i, PartialShape as l, Spring as m, SpringOptions as n, CompositeSpring as o, Purpose as p, SpringSystem as r, CompositeSpringTarget as s, CompositeSpringOptions as t, PurposeShape as u, velocityOf as v, SpringState as w, mapSpring as x, SpringSource as y };