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.
- package/README.md +132 -185
- package/dist/index.d.ts +2 -2
- package/dist/index.js +78 -2
- package/dist/nuxt.d.ts +42 -1
- package/dist/nuxt.js +24 -10
- package/dist/system-BXxAHM2a.js +1758 -0
- package/dist/system-Ci-R4RaI.d.ts +1032 -0
- package/dist/vue.d.ts +240 -25
- package/dist/vue.js +166 -270
- package/package.json +16 -16
- package/dist/system-Bzrx4uso.js +0 -976
- package/dist/system-coAFNYnb.d.ts +0 -350
|
@@ -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 };
|