coily 0.13.1 → 0.15.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 +76 -40
- package/dist/config-OOMMRdK8.d.ts +312 -0
- package/dist/css.d.ts +175 -0
- package/dist/css.js +294 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +91 -2
- package/dist/nuxt.d.ts +46 -0
- package/dist/nuxt.js +14 -14
- package/dist/solver-CVXOTDkZ.js +235 -0
- package/dist/system-Br_cPnaN.js +2188 -0
- package/dist/system-Du_fXXmO.d.ts +940 -0
- package/dist/vue.d.ts +227 -16
- package/dist/vue.js +84 -42
- package/package.json +2 -1
- package/dist/system-86fsXJN_.d.ts +0 -386
- package/dist/system-Csho09XW.js +0 -1384
|
@@ -0,0 +1,940 @@
|
|
|
1
|
+
import { t as SpringDefinition } from "./config-OOMMRdK8.js";
|
|
2
|
+
//#region src/flush-queue.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Defers callbacks while inside a batch or tick: `request` runs the
|
|
5
|
+
* callback immediately at depth 0 and queues it — deduplicated — until
|
|
6
|
+
* the outermost exit otherwise. Composite springs use it to coalesce
|
|
7
|
+
* per-channel events into composite ones.
|
|
8
|
+
*/
|
|
9
|
+
declare class FlushQueue {
|
|
10
|
+
#private;
|
|
11
|
+
request(callback: () => void): void;
|
|
12
|
+
batch(fn: () => void): void;
|
|
13
|
+
enter(): void;
|
|
14
|
+
exit(): void;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/motion.d.ts
|
|
18
|
+
/**
|
|
19
|
+
* One spring simulation in displacement space: position is measured from
|
|
20
|
+
* the target (0 means settled), so retargeting is a rebase performed by
|
|
21
|
+
* the owning `Spring`. Picks the closed-form solver for the config's
|
|
22
|
+
* damping regime and emits update/start/stop/dispose events.
|
|
23
|
+
*/
|
|
24
|
+
declare class Motion {
|
|
25
|
+
#private;
|
|
26
|
+
/** Monotone creation id: breaks ties wherever motions need a deterministic order. */
|
|
27
|
+
readonly _id: number;
|
|
28
|
+
/** Tick-pass marker written by `MotionSet` so a motion re-added mid-pass isn't ticked twice. */
|
|
29
|
+
_pass: number;
|
|
30
|
+
/**
|
|
31
|
+
* Frame marker written by `MotionSet`: sub-steps share one frame, and
|
|
32
|
+
* the first advance in it queues the motion for the settle sweep.
|
|
33
|
+
*/
|
|
34
|
+
_frame: number;
|
|
35
|
+
/**
|
|
36
|
+
* Dependency rank written by `FollowGraph`: motions the follow graph
|
|
37
|
+
* touches count up from 0, leaders before followers; -1 marks a motion
|
|
38
|
+
* outside the graph.
|
|
39
|
+
*/
|
|
40
|
+
_rank: number;
|
|
41
|
+
/**
|
|
42
|
+
* The edge this motion follows through, or null. Written by
|
|
43
|
+
* `FollowGraph` on edge add/remove so the tick's hot loop reads a
|
|
44
|
+
* field instead of a map.
|
|
45
|
+
*/
|
|
46
|
+
_edge: FollowEdge | null;
|
|
47
|
+
/**
|
|
48
|
+
* A first-order-hold ramp slope in value units per second, armed by a
|
|
49
|
+
* ramped `recouple` immediately before the `_advance` that consumes
|
|
50
|
+
* it (read-and-clear; no user code runs between the two). 0 means the
|
|
51
|
+
* target holds still across the step — every path but a ramped
|
|
52
|
+
* recouple.
|
|
53
|
+
*/
|
|
54
|
+
_ramp: number;
|
|
55
|
+
/**
|
|
56
|
+
* The edges reading this motion, or null when none. Written by
|
|
57
|
+
* `FollowGraph` with the rank cache, so it can lag a mid-pass edge
|
|
58
|
+
* change until the next recompute; the tick tolerates stale entries.
|
|
59
|
+
*/
|
|
60
|
+
_followers: FollowEdge[] | null;
|
|
61
|
+
respectsReducedMotion: boolean;
|
|
62
|
+
constructor(config: SpringDefinition, position: number, velocity: number);
|
|
63
|
+
get position(): number;
|
|
64
|
+
set position(value: number);
|
|
65
|
+
get velocity(): number;
|
|
66
|
+
set velocity(value: number);
|
|
67
|
+
get timeRemaining(): number;
|
|
68
|
+
get isResting(): boolean;
|
|
69
|
+
configure(config: SpringDefinition): void;
|
|
70
|
+
tick(dt: number, emit?: boolean): void;
|
|
71
|
+
/**
|
|
72
|
+
* Advances the simulation and emits nothing. The tick pass advances
|
|
73
|
+
* every motion through this, then delivers the frame's events with
|
|
74
|
+
* `_settleFrame`; the synchronous `tick` wraps the two.
|
|
75
|
+
*
|
|
76
|
+
* A pending `_ramp` integrates the step against a target moving at
|
|
77
|
+
* that slope instead of holding still: one affine transform around
|
|
78
|
+
* the unchanged solver. With the target at `p(t) = p0 + g*t`, the
|
|
79
|
+
* displacement u = x - p(t) obeys the homogeneous equation shifted by
|
|
80
|
+
* the constant u_ss = -(2*zeta/wn)*g = -(damping/tension)*g, so the
|
|
81
|
+
* solver ticks w = u - u_ss exactly and the results shift back.
|
|
82
|
+
* Measuring u from the moving target makes the ramp endpoint and the
|
|
83
|
+
* new target coincide — the armer assigns the target, no rebase
|
|
84
|
+
* arithmetic exists. The ramp is an argument of the step, never
|
|
85
|
+
* persistent solver state: g = 0 takes the plain step below, so a
|
|
86
|
+
* motion that never ramps steps bit-exactly like an isolated spring.
|
|
87
|
+
*/
|
|
88
|
+
_advance(dt: number): void;
|
|
89
|
+
/**
|
|
90
|
+
* Emits the frame's `update`, then reconciles `stop`/`start`. The tick
|
|
91
|
+
* pass calls this in dependency order after every motion has advanced,
|
|
92
|
+
* so update callbacks read frame-final values everywhere.
|
|
93
|
+
*/
|
|
94
|
+
_settleFrame(): void;
|
|
95
|
+
finish(): void;
|
|
96
|
+
/**
|
|
97
|
+
* The sub-step controller's shock signal, read by a follower's `plan`
|
|
98
|
+
* with this motion as its leader: deviation from the quasi-steady
|
|
99
|
+
* tracking manifold x = -(damping/tension) * v, where damping/tension
|
|
100
|
+
* is 2*zeta/wn. Near zero while chasing any smoothly moving target at
|
|
101
|
+
* any speed; the full displacement after a target teleport;
|
|
102
|
+
* (damping/tension) * |v| after a fling.
|
|
103
|
+
*/
|
|
104
|
+
_manifoldDeviation(): number;
|
|
105
|
+
/** Acceleration from current state, for `plan`'s kinematic bound on a shock frame. */
|
|
106
|
+
_acceleration(): number;
|
|
107
|
+
onUpdate(callback: () => void): () => void;
|
|
108
|
+
onStart(callback: () => void): () => void;
|
|
109
|
+
onStop(callback: () => void): () => void;
|
|
110
|
+
onDispose(callback: () => void): () => void;
|
|
111
|
+
dispose(): void;
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/follow-graph.d.ts
|
|
115
|
+
/**
|
|
116
|
+
* One follow relationship, as the system sees it: which motion
|
|
117
|
+
* retargets, which motions it reads, how to re-anchor it, and the
|
|
118
|
+
* sub-step controller's per-edge state. `Spring` registers an edge when
|
|
119
|
+
* a follow is wired to a source with resolvable motions, and
|
|
120
|
+
* unregisters it on unfollow and dispose.
|
|
121
|
+
*/
|
|
122
|
+
interface FollowEdge {
|
|
123
|
+
/** The motion that retargets when its leaders advance. */
|
|
124
|
+
readonly follower: Motion;
|
|
125
|
+
/** The distinct motions behind the followed source, per `resolveLeaderMotions`. */
|
|
126
|
+
readonly leaders: readonly Motion[];
|
|
127
|
+
/**
|
|
128
|
+
* Whether the follower shares a Tarjan SCC with any of its leaders,
|
|
129
|
+
* self-follow included. Written by `FollowGraph` on recompute. Routes
|
|
130
|
+
* `plan` to the ZOH sub-step law: FOH destabilizes cycles that are
|
|
131
|
+
* stable under ZOH, so no ramp may ever arm inside an SCC.
|
|
132
|
+
*/
|
|
133
|
+
_cyclic: boolean;
|
|
134
|
+
/** The follower's target as of the last `plan` call. */
|
|
135
|
+
_prevValue: number;
|
|
136
|
+
/** The followed value's frame delta observed by the last `plan` call. */
|
|
137
|
+
_d1: number;
|
|
138
|
+
/** The frame delta one older than `_d1`; their difference estimates curvature. */
|
|
139
|
+
_d2: number;
|
|
140
|
+
/**
|
|
141
|
+
* Re-anchors the follower to the followed source's current value.
|
|
142
|
+
* `h` is the step the follower is about to advance by, in seconds
|
|
143
|
+
* (the internal tick unit). On an edge where a ramp may arm —
|
|
144
|
+
* acyclic, passthrough arrival, `h > 0`, not a reduced-motion jump —
|
|
145
|
+
* it retargets and arms the follower's `_ramp` with the delta over
|
|
146
|
+
* `h`, so the coming advance integrates against the leader's motion.
|
|
147
|
+
* Every other edge retargets with the exact semantics of the
|
|
148
|
+
* leader-update handler (finite guard, reduced-motion jump).
|
|
149
|
+
*/
|
|
150
|
+
recouple(h: number): void;
|
|
151
|
+
/**
|
|
152
|
+
* Refreshes the estimator from the follower's current target and
|
|
153
|
+
* returns this edge's sub-step demand for a frame of `dt` seconds —
|
|
154
|
+
* unclamped; the caller maxes over edges and clamps. Runs no user
|
|
155
|
+
* code: history is the target trail, freshness reads leader motion
|
|
156
|
+
* state. Call at most once per edge per frame, before any motion
|
|
157
|
+
* advances.
|
|
158
|
+
*/
|
|
159
|
+
plan(dt: number): number;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* The follow graph as a walkable structure: one edge per following
|
|
163
|
+
* motion, and a cached dependency rank over every motion the edges
|
|
164
|
+
* touch. `MotionSet` owns one; springs register and unregister edges as
|
|
165
|
+
* follows are wired and torn down. What the tick reads per motion —
|
|
166
|
+
* `_edge`, `_followers`, `_rank` — lives on the motions themselves;
|
|
167
|
+
* this class is their writer.
|
|
168
|
+
*/
|
|
169
|
+
declare class FollowGraph {
|
|
170
|
+
#private;
|
|
171
|
+
/** Whether no edges are registered, letting the tick skip ordering work entirely. */
|
|
172
|
+
get isEmpty(): boolean;
|
|
173
|
+
/** Every registered edge, valid after `ensureOrder`; the plan pass walks this once per frame. */
|
|
174
|
+
get edges(): readonly FollowEdge[];
|
|
175
|
+
/**
|
|
176
|
+
* Registers `edge`, replacing any edge with the same follower: a
|
|
177
|
+
* spring follows at most one source at a time.
|
|
178
|
+
*/
|
|
179
|
+
addEdge(edge: FollowEdge): void;
|
|
180
|
+
/** Drops the edge whose follower is `motion`, if one is registered. */
|
|
181
|
+
removeEdge(follower: Motion): void;
|
|
182
|
+
/**
|
|
183
|
+
* Recomputes ranks if an edge was added or removed since the last
|
|
184
|
+
* call; clean calls return immediately. Afterward, motions the graph
|
|
185
|
+
* touches hold ranks counting up from 0 with every leader ranked
|
|
186
|
+
* before its followers, members of a cycle rank in ascending creation
|
|
187
|
+
* id, and motions outside the graph hold -1. Ranks are canonical: a
|
|
188
|
+
* function of graph structure and creation order, never of wiring
|
|
189
|
+
* order.
|
|
190
|
+
*/
|
|
191
|
+
ensureOrder(): void;
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/motion-set.d.ts
|
|
195
|
+
/**
|
|
196
|
+
* The set of motions currently moving. Motions leave the set as they
|
|
197
|
+
* rest and re-enter on any write that disturbs them; `onWake` tells the
|
|
198
|
+
* ticker the set became non-empty so it can stop sleeping.
|
|
199
|
+
*/
|
|
200
|
+
declare class MotionSet {
|
|
201
|
+
#private;
|
|
202
|
+
reduced: boolean;
|
|
203
|
+
onWake: (() => void) | null;
|
|
204
|
+
/**
|
|
205
|
+
* The coupling error budget, in value units: the local per-frame error
|
|
206
|
+
* the sub-step controller targets on each follow edge, floored by the
|
|
207
|
+
* follower's resting magnitude. `SpringSystem` exposes it as the
|
|
208
|
+
* `couplingTolerance` option and property; validation lives there.
|
|
209
|
+
*/
|
|
210
|
+
couplingTolerance: number;
|
|
211
|
+
readonly flushes: FlushQueue;
|
|
212
|
+
/** Follow edges registered by following springs, with the dependency rank over their motions. */
|
|
213
|
+
readonly graph: FollowGraph;
|
|
214
|
+
constructor(debug?: boolean);
|
|
215
|
+
get size(): number;
|
|
216
|
+
add(motion: Motion): void;
|
|
217
|
+
remove(motion: Motion): void;
|
|
218
|
+
finishAll(): void;
|
|
219
|
+
tick(dt: number): void;
|
|
220
|
+
}
|
|
221
|
+
//#endregion
|
|
222
|
+
//#region src/spring-source.d.ts
|
|
223
|
+
/**
|
|
224
|
+
* The property key that brands a `SpringSource` and holds the channel its
|
|
225
|
+
* followers read. A registry symbol (`Symbol.for('coily/spring-source')`),
|
|
226
|
+
* so sources from one copy of coily are recognized by another when a
|
|
227
|
+
* bundle duplicates the library.
|
|
228
|
+
*/
|
|
229
|
+
declare const SpringSourceSymbol: unique symbol;
|
|
230
|
+
/**
|
|
231
|
+
* What a source exposes to its followers, held under `SpringSourceSymbol`
|
|
232
|
+
* on the source object. Followers read `value` on every update and
|
|
233
|
+
* detach on dispose.
|
|
234
|
+
*/
|
|
235
|
+
interface SpringSourceApi<T = number> {
|
|
236
|
+
/** The current value, in value units. */
|
|
237
|
+
readonly value: T;
|
|
238
|
+
/** Subscribes to value changes. Returns an unsubscribe function. */
|
|
239
|
+
onUpdate(callback: () => void): () => void;
|
|
240
|
+
/** Subscribes to the source being released. Returns an unsubscribe function. */
|
|
241
|
+
onDispose(callback: () => void): () => void;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* A live value a spring can animate toward or derive from. `T` is the
|
|
245
|
+
* value's type: a scalar source (`T = number`, the default) can be
|
|
246
|
+
* assigned to `Spring.target`, which then tracks it momentum intact.
|
|
247
|
+
*
|
|
248
|
+
* Every `Spring` is a `SpringSource`, every `CompositeSpring` is a
|
|
249
|
+
* `SpringSource` of its value shape, and `mapSpring`, `velocityOf`, and
|
|
250
|
+
* `accelerationOf` derive fresh sources from existing ones. You take
|
|
251
|
+
* sources from those APIs and pass them wherever one is accepted; the
|
|
252
|
+
* type names such a value in your own signatures.
|
|
253
|
+
*/
|
|
254
|
+
interface SpringSource<T = number> {
|
|
255
|
+
readonly [SpringSourceSymbol]: SpringSourceApi<T>;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Compile-time validation of a shape of sources: every leaf must be a
|
|
259
|
+
* `SpringSource`, every branch a plain object or array with at least one
|
|
260
|
+
* leaf. Used as `sources: T & SourceShape<T>` so an invalid leaf errors
|
|
261
|
+
* on that property rather than on the whole argument. Purely structural,
|
|
262
|
+
* and mirrored by the runtime validation for untyped callers. Optional
|
|
263
|
+
* and `undefined`-typed leaves are rejected.
|
|
264
|
+
*/
|
|
265
|
+
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;
|
|
266
|
+
/**
|
|
267
|
+
* The value shape a shape of sources produces: the same nesting with
|
|
268
|
+
* every `SpringSource` leaf replaced by its value — `number` for a
|
|
269
|
+
* scalar spring, the read-only value shape for a composite. What `map`
|
|
270
|
+
* receives when `mapSpring` is given a shape.
|
|
271
|
+
*/
|
|
272
|
+
type SourceValues<T> = T extends SpringSource<infer V> ? V : { readonly [K in keyof T]: SourceValues<T[K]>; };
|
|
273
|
+
/**
|
|
274
|
+
* Derives a source from another by a pure function of its value:
|
|
275
|
+
* `mapSpring(leader, (v) => v + 10)` follows 10 above the leader,
|
|
276
|
+
* `(v) => -v` mirrors it. Maps compose — a mapped source is a
|
|
277
|
+
* `SpringSource` like any other, so it can be mapped again, used as a
|
|
278
|
+
* leaf of a shape map, or followed by several springs at once.
|
|
279
|
+
*
|
|
280
|
+
* The result is a stateless view, not a spring: it holds no
|
|
281
|
+
* subscriptions and needs no disposal, and reads compute `map` of the
|
|
282
|
+
* source's current value on the fly. `map` must be pure — it runs on
|
|
283
|
+
* every read and every source update, and nothing re-evaluates it when
|
|
284
|
+
* anything other than `source` changes. Composition is flat: mapping a
|
|
285
|
+
* mapped source extends its pipeline rather than wrapping it, so chains
|
|
286
|
+
* cost one function call per map however long they grow.
|
|
287
|
+
*/
|
|
288
|
+
declare function mapSpring(source: SpringSource, map: (value: number) => number): SpringSource;
|
|
289
|
+
/**
|
|
290
|
+
* Derives a scalar source from several channels by a pure function of
|
|
291
|
+
* their values. `sources` is a shape — a plain object or array with
|
|
292
|
+
* `SpringSource` leaves, nested arbitrarily — or a single non-scalar
|
|
293
|
+
* source such as a `CompositeSpring`. `map` receives the matching
|
|
294
|
+
* values: each leaf's current number for a shape
|
|
295
|
+
* (`mapSpring({ x, y }, ({ x, y }) => Math.hypot(x, y))`), the
|
|
296
|
+
* live value shape for a composite
|
|
297
|
+
* (`mapSpring(point, ({ x, y }) => Math.hypot(x, y))`). Invalid
|
|
298
|
+
* leaves throw with their path (`position.z`).
|
|
299
|
+
*
|
|
300
|
+
* The result is a stateless view, not a spring: it holds no
|
|
301
|
+
* subscriptions and needs no disposal, and reads compute `map` over the
|
|
302
|
+
* sources' values on the fly. `map` must be pure — it runs on every
|
|
303
|
+
* read and every source update — and must not retain what it receives:
|
|
304
|
+
* every call hands it the same live mirror of the values, refreshed in
|
|
305
|
+
* place. The mapped source is released with the first of its sources:
|
|
306
|
+
* followers detach then, keeping their current target, as they would
|
|
307
|
+
* from a disposed spring.
|
|
308
|
+
*/
|
|
309
|
+
declare function mapSpring<const T extends object>(sources: T & SourceShape<T>, map: (values: SourceValues<T>) => number): SpringSource;
|
|
310
|
+
//#endregion
|
|
311
|
+
//#region src/kinematic-source.d.ts
|
|
312
|
+
/**
|
|
313
|
+
* A `SpringSourceApi` whose value is in motion, so it also reports the
|
|
314
|
+
* value's derivatives: `velocity` (the rate `value` changes, in value
|
|
315
|
+
* units per second) and `acceleration` (the rate `velocity` changes, in
|
|
316
|
+
* value units per second squared). A `Spring` and a `CompositeSpring`
|
|
317
|
+
* carry both exactly — they fall out of the same equation that drives
|
|
318
|
+
* the motion — as does a source bridging a value whose motion it tracks.
|
|
319
|
+
* A value derived with `mapSpring` does not: it holds no motion of its
|
|
320
|
+
* own, so its derivatives would need the derivative of an arbitrary
|
|
321
|
+
* function. `velocityOf` and `accelerationOf` read this slot.
|
|
322
|
+
*/
|
|
323
|
+
interface KinematicSourceApi<T = number> extends SpringSourceApi<T> {
|
|
324
|
+
/** The current velocity, in value units per second. */
|
|
325
|
+
readonly velocity: T;
|
|
326
|
+
/** The current acceleration, in value units per second squared. */
|
|
327
|
+
readonly acceleration: T;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* A `SpringSource` whose value is in motion, so it also carries the
|
|
331
|
+
* value's `velocity` and `acceleration` — every `Spring` and
|
|
332
|
+
* `CompositeSpring` is one. `velocityOf` and `accelerationOf` accept
|
|
333
|
+
* these; a plain `SpringSource` (such as a `mapSpring` result) is not
|
|
334
|
+
* assignable, since a value derivation is not in motion.
|
|
335
|
+
*/
|
|
336
|
+
interface KinematicSource<T = number> extends SpringSource<T> {
|
|
337
|
+
readonly [SpringSourceSymbol]: KinematicSourceApi<T>;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Derives a source from another's velocity — the rate its value changes,
|
|
341
|
+
* in value units per second. `velocityOf(motion)` is a source that reads
|
|
342
|
+
* `motion`'s current velocity, so speed-driven effects fall out of the
|
|
343
|
+
* same follow and `mapSpring` machinery as everything else: a spring can
|
|
344
|
+
* follow it (`blur.target = velocityOf(motion)`) and a map can shape it
|
|
345
|
+
* (`mapSpring(velocityOf(motion), (v) => 1 + Math.abs(v) * 0.001)` for
|
|
346
|
+
* squash and stretch). A scalar source yields a scalar velocity a spring
|
|
347
|
+
* can follow; a `CompositeSpring` or shape yields a velocity of the same
|
|
348
|
+
* shape, mapped to a scalar the way the composite itself is.
|
|
349
|
+
*
|
|
350
|
+
* The result is a stateless view, not a spring: it holds no
|
|
351
|
+
* subscriptions and needs no disposal, and reads report the source's
|
|
352
|
+
* current velocity on the fly. It updates when the source does and is
|
|
353
|
+
* released with it — followers detach then, keeping their current
|
|
354
|
+
* target, as they would from a disposed spring.
|
|
355
|
+
*
|
|
356
|
+
* Only a source in motion qualifies — a `Spring` or a `CompositeSpring`.
|
|
357
|
+
* A value derived with `mapSpring` has no velocity (its rate of change
|
|
358
|
+
* would need the derivative of the map), so it is rejected at the type
|
|
359
|
+
* level and at runtime; take `velocityOf` of the spring the map reads
|
|
360
|
+
* instead.
|
|
361
|
+
*/
|
|
362
|
+
declare function velocityOf<T>(source: KinematicSource<T>): SpringSource<T>;
|
|
363
|
+
/**
|
|
364
|
+
* Derives a source from another's acceleration — the rate its velocity
|
|
365
|
+
* changes, in value units per second squared. `accelerationOf(motion)`
|
|
366
|
+
* spikes when `motion` is pushed hardest and passes through zero at the
|
|
367
|
+
* peak of a swing, so force-driven effects fall out of the same follow
|
|
368
|
+
* and `mapSpring` machinery: a spring can follow it, and a map can turn
|
|
369
|
+
* it into an impact flash or a jelly wobble
|
|
370
|
+
* (`mapSpring(accelerationOf(motion), (a) => Math.min(1, Math.abs(a) * 1e-4))`).
|
|
371
|
+
* A scalar source yields a scalar acceleration; a `CompositeSpring` or
|
|
372
|
+
* shape yields an acceleration of the same shape, mapped to a scalar the
|
|
373
|
+
* way the composite itself is.
|
|
374
|
+
*
|
|
375
|
+
* The result is a stateless view, not a spring: it holds no
|
|
376
|
+
* subscriptions and needs no disposal, and reads report the source's
|
|
377
|
+
* current acceleration on the fly. It updates when the source does and
|
|
378
|
+
* is released with it, followers detaching then as from a disposed
|
|
379
|
+
* spring.
|
|
380
|
+
*
|
|
381
|
+
* Only a source in motion qualifies — a `Spring` or a `CompositeSpring`.
|
|
382
|
+
* A value derived with `mapSpring` has no acceleration, so it is rejected
|
|
383
|
+
* at the type level and at runtime; take `accelerationOf` of the spring
|
|
384
|
+
* the map reads instead.
|
|
385
|
+
*/
|
|
386
|
+
declare function accelerationOf<T>(source: KinematicSource<T>): SpringSource<T>;
|
|
387
|
+
//#endregion
|
|
388
|
+
//#region src/spring.d.ts
|
|
389
|
+
/**
|
|
390
|
+
* What a spring can animate toward: a fixed number, or a `SpringSource`
|
|
391
|
+
* — another spring, or a value derived from one with `mapSpring` —
|
|
392
|
+
* whose live value the spring follows.
|
|
393
|
+
*/
|
|
394
|
+
type SpringTarget = number | SpringSource;
|
|
395
|
+
/**
|
|
396
|
+
* What a spring animates, which decides whether reduced motion applies to
|
|
397
|
+
* it. `'motion'` moves something on screen — position, scale, rotation —
|
|
398
|
+
* and snaps to its target under reduced motion. `'appearance'` changes
|
|
399
|
+
* how something looks without moving it — a cross-fade, a color, a blur —
|
|
400
|
+
* and keeps animating under reduced motion, since it carries no motion to
|
|
401
|
+
* reduce. Fixed when the spring is created; read it back from
|
|
402
|
+
* `Spring.purpose`.
|
|
403
|
+
*/
|
|
404
|
+
type Purpose = 'motion' | 'appearance';
|
|
405
|
+
/**
|
|
406
|
+
* One animated number, driven toward its target with damped spring
|
|
407
|
+
* motion. Create springs with `SpringSystem.createSpring`; the owning
|
|
408
|
+
* system advances them, so a spring only moves while its system runs.
|
|
409
|
+
*
|
|
410
|
+
* Reads return the exact simulated state; nothing is rounded. Numeric
|
|
411
|
+
* writes — `target`, `value`, `velocity`, `jumpTo` — require finite
|
|
412
|
+
* numbers: `NaN` or an infinity throws rather than poisoning the
|
|
413
|
+
* simulation. See
|
|
414
|
+
* https://github.com/tkofh/coily/blob/main/PRECISION.md for the
|
|
415
|
+
* numerical contract.
|
|
416
|
+
*/
|
|
417
|
+
declare class Spring implements KinematicSource {
|
|
418
|
+
#private;
|
|
419
|
+
/** Brands the spring as a `KinematicSource` whose api is the spring itself. */
|
|
420
|
+
get [SpringSourceSymbol](): KinematicSourceApi<number>;
|
|
421
|
+
constructor(motions: MotionSet, value: number, config?: SpringDefinition, purpose?: Purpose);
|
|
422
|
+
/**
|
|
423
|
+
* The value the spring is animating toward. While following a source,
|
|
424
|
+
* reads return the source's value as of its last update.
|
|
425
|
+
*
|
|
426
|
+
* Assignment accepts any `SpringTarget`:
|
|
427
|
+
* - A number retargets the spring. The current value and momentum carry
|
|
428
|
+
* over, so mid-flight retargets stay smooth. Assigning a number while
|
|
429
|
+
* following also stops the following.
|
|
430
|
+
* - A `SpringSource` — a `Spring`, or a value derived with `mapSpring` —
|
|
431
|
+
* makes this spring follow the source's live value.
|
|
432
|
+
*
|
|
433
|
+
* Under reduced motion, retargets apply instantly — unless `purpose` is
|
|
434
|
+
* `'appearance'`, in which case they animate as normal.
|
|
435
|
+
*/
|
|
436
|
+
get target(): number;
|
|
437
|
+
set target(value: SpringTarget);
|
|
438
|
+
/**
|
|
439
|
+
* The current animated value: the target plus the remaining
|
|
440
|
+
* displacement.
|
|
441
|
+
*
|
|
442
|
+
* Writing displaces the spring: it keeps its target and springs back
|
|
443
|
+
* from the written value, notifying update listeners synchronously.
|
|
444
|
+
* Writing the current value is a no-op. Under reduced motion a write
|
|
445
|
+
* jumps the spring — target included — to the written value, unless
|
|
446
|
+
* `purpose` is `'appearance'`, in which case it displaces as normal.
|
|
447
|
+
*/
|
|
448
|
+
get value(): number;
|
|
449
|
+
set value(value: number);
|
|
450
|
+
/**
|
|
451
|
+
* The current velocity, in value units per second.
|
|
452
|
+
*
|
|
453
|
+
* Writing flings the spring: motion continues from the current value
|
|
454
|
+
* with the written velocity, then settles back to the target. Under
|
|
455
|
+
* reduced motion writes are ignored, unless `purpose` is `'appearance'`,
|
|
456
|
+
* in which case the fling applies as normal.
|
|
457
|
+
*/
|
|
458
|
+
get velocity(): number;
|
|
459
|
+
set velocity(value: number);
|
|
460
|
+
/**
|
|
461
|
+
* The current acceleration, in value units per second squared — how
|
|
462
|
+
* fast the velocity is changing. Read-only: acceleration is the
|
|
463
|
+
* spring's stiffness and friction acting on its current displacement
|
|
464
|
+
* and velocity, so it follows from the motion rather than being set.
|
|
465
|
+
* To fling the spring, write `velocity` instead.
|
|
466
|
+
*/
|
|
467
|
+
get acceleration(): number;
|
|
468
|
+
/**
|
|
469
|
+
* What the spring animates — `'motion'` or `'appearance'` — fixed when
|
|
470
|
+
* it was created. An `'appearance'` spring opts out of reduced motion:
|
|
471
|
+
* it keeps animating where a `'motion'` spring snaps to its target. See
|
|
472
|
+
* `Purpose`.
|
|
473
|
+
*/
|
|
474
|
+
get purpose(): Purpose;
|
|
475
|
+
/**
|
|
476
|
+
* The spring's `SpringDefinition`: the one it was created with or last
|
|
477
|
+
* assigned, otherwise `SpringDefinition.default`. Following a source
|
|
478
|
+
* never changes it — how a spring chases its target is the spring's
|
|
479
|
+
* own setting.
|
|
480
|
+
*
|
|
481
|
+
* Assigning a config reconfigures the spring in place — value and
|
|
482
|
+
* velocity are preserved, so mid-flight reconfigures stay smooth.
|
|
483
|
+
* Assigning `null` reverts to the default.
|
|
484
|
+
*/
|
|
485
|
+
get config(): SpringDefinition;
|
|
486
|
+
/** The config's mass. */
|
|
487
|
+
get mass(): number;
|
|
488
|
+
/** The config's tension (stiffness). */
|
|
489
|
+
get tension(): number;
|
|
490
|
+
/** The config's damping (friction). */
|
|
491
|
+
get damping(): number;
|
|
492
|
+
/** The config's damping ratio. */
|
|
493
|
+
get dampingRatio(): number;
|
|
494
|
+
/** The config's resting precision. */
|
|
495
|
+
get precision(): number;
|
|
496
|
+
/** The config's arrival multiplier. */
|
|
497
|
+
get arrival(): number;
|
|
498
|
+
set config(value: SpringDefinition | null);
|
|
499
|
+
/**
|
|
500
|
+
* Milliseconds until the spring rests: 0 while resting, Infinity when
|
|
501
|
+
* the motion never settles. The time is solved from the motion, not
|
|
502
|
+
* estimated — the spring is resting at the first tick at or after it,
|
|
503
|
+
* and a bouncy spring can rest up to one oscillation earlier when a
|
|
504
|
+
* frame samples a low pulse. When the config's `arrival` is 0, it is
|
|
505
|
+
* capped at the exact ms of the first target crossing.
|
|
506
|
+
*/
|
|
507
|
+
get timeRemaining(): number;
|
|
508
|
+
/**
|
|
509
|
+
* Whether the spring's remaining motion is inside its resting
|
|
510
|
+
* threshold. Resting springs cost nothing until the next write. See
|
|
511
|
+
* https://github.com/tkofh/coily/blob/main/PRECISION.md for the rest
|
|
512
|
+
* test.
|
|
513
|
+
*/
|
|
514
|
+
get isResting(): boolean;
|
|
515
|
+
/**
|
|
516
|
+
* A promise that resolves when the spring next comes to rest — already
|
|
517
|
+
* resolved while resting or after dispose. Retargeting mid-flight
|
|
518
|
+
* extends the wait; disposing resolves it.
|
|
519
|
+
*
|
|
520
|
+
* @example
|
|
521
|
+
* ```ts
|
|
522
|
+
* spring.target = 300
|
|
523
|
+
* await spring.settled
|
|
524
|
+
* // the spring is at 300 and resting
|
|
525
|
+
* ```
|
|
526
|
+
*/
|
|
527
|
+
get settled(): Promise<void>;
|
|
528
|
+
/**
|
|
529
|
+
* Snaps the spring to `value` with no animation: target and value both
|
|
530
|
+
* become `value` and velocity clears. Listeners are notified
|
|
531
|
+
* synchronously — `update`, plus `stop` if the spring was moving.
|
|
532
|
+
*/
|
|
533
|
+
jumpTo(value: number): void;
|
|
534
|
+
/**
|
|
535
|
+
* Releases the spring permanently: stops following, detaches followers
|
|
536
|
+
* (each keeps its current target), resolves `settled`, and notifies
|
|
537
|
+
* dispose listeners. Calling it again is a no-op.
|
|
538
|
+
*
|
|
539
|
+
* A disposed spring keeps its final value readable; writes throw.
|
|
540
|
+
*/
|
|
541
|
+
dispose(): void;
|
|
542
|
+
/**
|
|
543
|
+
* Subscribes to value changes: every tick the spring moves, plus
|
|
544
|
+
* synchronous `value` writes and `jumpTo` calls. Returns an unsubscribe
|
|
545
|
+
* function.
|
|
546
|
+
*/
|
|
547
|
+
onUpdate(callback: () => void): () => void;
|
|
548
|
+
/**
|
|
549
|
+
* Subscribes to the spring leaving rest. `start` and `stop` always
|
|
550
|
+
* alternate; retargeting mid-flight fires neither. Returns an
|
|
551
|
+
* unsubscribe function.
|
|
552
|
+
*/
|
|
553
|
+
onStart(callback: () => void): () => void;
|
|
554
|
+
/**
|
|
555
|
+
* Subscribes to the spring coming to rest, whether by settling or by
|
|
556
|
+
* `jumpTo`. Always alternates with `start`. Returns an unsubscribe
|
|
557
|
+
* function.
|
|
558
|
+
*/
|
|
559
|
+
onStop(callback: () => void): () => void;
|
|
560
|
+
/** Subscribes to `dispose`, which fires once. Returns an unsubscribe function. */
|
|
561
|
+
onDispose(callback: () => void): () => void;
|
|
562
|
+
}
|
|
563
|
+
//#endregion
|
|
564
|
+
//#region src/composite-spring.d.ts
|
|
565
|
+
/**
|
|
566
|
+
* Compile-time validation of a value shape: every channel must be a `number`,
|
|
567
|
+
* every branch a plain object or array with at least one channel. Used as
|
|
568
|
+
* `value: T & Shape<T>` so an invalid channel errors on that property rather
|
|
569
|
+
* than on the whole argument. Purely structural — interfaces satisfy it
|
|
570
|
+
* without index signatures — and mirrored by the runtime
|
|
571
|
+
* validation for untyped callers. Optional and `undefined`-typed channels
|
|
572
|
+
* are rejected: a channel that may be absent would make two springs of the
|
|
573
|
+
* same declared shape structurally incompatible at runtime.
|
|
574
|
+
*/
|
|
575
|
+
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;
|
|
576
|
+
/**
|
|
577
|
+
* A partial view of a value shape: the same nesting with any subset of the
|
|
578
|
+
* numeric channels present. Absent (or `undefined`) channels are left alone.
|
|
579
|
+
*/
|
|
580
|
+
type PartialShape<T> = T extends number ? number : { readonly [K in keyof T]?: PartialShape<T[K]> | undefined; };
|
|
581
|
+
/**
|
|
582
|
+
* A deep-readonly view of a value shape. Composite reads (`target`, `value`,
|
|
583
|
+
* `velocity`, `acceleration`) return the spring's live mirror objects —
|
|
584
|
+
* refreshed in place on every read — so their channels are typed read-only.
|
|
585
|
+
*/
|
|
586
|
+
type ReadonlyShape<T> = T extends number ? number : { readonly [K in keyof T]: ReadonlyShape<T[K]>; };
|
|
587
|
+
/**
|
|
588
|
+
* Configuration for a composite spring: a single `SpringDefinition` applied to every
|
|
589
|
+
* channel, or an object mirroring the value shape with configs at any level.
|
|
590
|
+
* A config at a subtree applies to every channel below it.
|
|
591
|
+
* `null` reverts to the default config.
|
|
592
|
+
* Configs are always `SpringDefinition` instances (from `defineSpring`), so a
|
|
593
|
+
* plain object is unambiguously a config shape and any non-config leaf it
|
|
594
|
+
* reaches is an error.
|
|
595
|
+
*/
|
|
596
|
+
type ConfigShape<T> = SpringDefinition | null | (T extends number ? never : { readonly [K in keyof T]?: ConfigShape<T[K]> | undefined; });
|
|
597
|
+
/**
|
|
598
|
+
* What each channel of a composite spring animates: a single `Purpose`
|
|
599
|
+
* for every channel, or a shape mirroring the value with purposes at any
|
|
600
|
+
* level. A purpose at a subtree covers every channel below it, and any
|
|
601
|
+
* channel it doesn't reach defaults to `'motion'`. Fixed when the spring
|
|
602
|
+
* is created. See `Purpose`.
|
|
603
|
+
*/
|
|
604
|
+
type PurposeShape<T> = Purpose | (T extends number ? never : { readonly [K in keyof T]?: PurposeShape<T[K]> | undefined; });
|
|
605
|
+
/**
|
|
606
|
+
* A partial target shape: the same nesting as the value with any subset
|
|
607
|
+
* of the channels present, each taking a number to animate toward or a
|
|
608
|
+
* scalar `SpringSource` to follow. Absent (or `undefined`) channels are
|
|
609
|
+
* left alone.
|
|
610
|
+
*/
|
|
611
|
+
type TargetShape<T> = T extends number ? number | SpringSource : { readonly [K in keyof T]?: TargetShape<T[K]> | undefined; };
|
|
612
|
+
/**
|
|
613
|
+
* What a composite spring can animate toward: a partial shape mixing
|
|
614
|
+
* numbers and scalar `SpringSource`s per channel, or another composite
|
|
615
|
+
* spring of the same shape to follow channel by channel.
|
|
616
|
+
*/
|
|
617
|
+
type CompositeSpringTarget<T extends object> = TargetShape<T> | CompositeSpring<T>;
|
|
618
|
+
/**
|
|
619
|
+
* A composite spring over a fixed numeric shape — a nested plain object
|
|
620
|
+
* or array whose leaves are all numbers. Each leaf runs an independent
|
|
621
|
+
* spring, called a channel, behind one API: targets, values, velocities,
|
|
622
|
+
* and configs read and write as (partial) shapes, and events are
|
|
623
|
+
* coalesced across channels. Create composite springs with
|
|
624
|
+
* `SpringSystem.createSpring`.
|
|
625
|
+
*
|
|
626
|
+
* A composite spring is a `SpringSource` of its value shape: `mapSpring`
|
|
627
|
+
* derives scalar sources from it — alone or at the leaves of a shape —
|
|
628
|
+
* which springs can then follow. Only scalar sources are followable
|
|
629
|
+
* directly.
|
|
630
|
+
*
|
|
631
|
+
* The shape is fixed at construction. Writes naming unknown channels
|
|
632
|
+
* throw with the channel's path (`position.z`), and so do non-finite
|
|
633
|
+
* channel values.
|
|
634
|
+
*/
|
|
635
|
+
declare class CompositeSpring<in out T extends object> implements KinematicSource<ReadonlyShape<T>> {
|
|
636
|
+
#private;
|
|
637
|
+
/** Brands the composite as a `KinematicSource` whose api is the composite itself. */
|
|
638
|
+
get [SpringSourceSymbol](): KinematicSourceApi<ReadonlyShape<T>>;
|
|
639
|
+
constructor(motions: MotionSet, value: T & Shape<T>, config?: ConfigShape<T>, purpose?: PurposeShape<T>);
|
|
640
|
+
/**
|
|
641
|
+
* The value each channel is animating toward, as a read-only mirror of
|
|
642
|
+
* the shape. The mirror object is reused: every read refreshes its
|
|
643
|
+
* numbers in place, so read it fresh rather than holding it across
|
|
644
|
+
* frames.
|
|
645
|
+
*
|
|
646
|
+
* Assignment accepts a `CompositeSpringTarget`:
|
|
647
|
+
* - A partial shape retargets the channels it names and leaves the
|
|
648
|
+
* others alone. Each named channel takes a number, or a scalar
|
|
649
|
+
* `SpringSource` to follow — a `Spring`, or a value derived with
|
|
650
|
+
* `mapSpring`. While following a leader, naming a channel also
|
|
651
|
+
* detaches that channel from it.
|
|
652
|
+
* - A `CompositeSpring` of the same shape follows the leader channel by
|
|
653
|
+
* channel.
|
|
654
|
+
*
|
|
655
|
+
* Unknown channels throw with their path.
|
|
656
|
+
*/
|
|
657
|
+
get target(): ReadonlyShape<T>;
|
|
658
|
+
set target(value: CompositeSpringTarget<T>);
|
|
659
|
+
/**
|
|
660
|
+
* The current animated value of every channel, as a read-only mirror of
|
|
661
|
+
* the shape. The mirror object is reused: every read refreshes its
|
|
662
|
+
* numbers in place, so read it fresh rather than holding it across
|
|
663
|
+
* frames.
|
|
664
|
+
*
|
|
665
|
+
* Assignment takes a partial shape and displaces the channels it names:
|
|
666
|
+
* each keeps its target and springs back from the written value, with
|
|
667
|
+
* one coalesced `update` fired synchronously. Under reduced motion a
|
|
668
|
+
* write jumps the named channels — targets included — except channels
|
|
669
|
+
* whose `purpose` is `'appearance'`, which displace as normal.
|
|
670
|
+
*/
|
|
671
|
+
get value(): ReadonlyShape<T>;
|
|
672
|
+
set value(value: PartialShape<T>);
|
|
673
|
+
/**
|
|
674
|
+
* The current velocity of every channel in value units per second, as a
|
|
675
|
+
* read-only mirror of the shape — reused and refreshed in place on each
|
|
676
|
+
* read.
|
|
677
|
+
*
|
|
678
|
+
* Assignment takes a partial shape and flings the channels it names;
|
|
679
|
+
* the rest are untouched. Under reduced motion writes are ignored,
|
|
680
|
+
* except on channels whose `purpose` is `'appearance'`.
|
|
681
|
+
*/
|
|
682
|
+
get velocity(): ReadonlyShape<T>;
|
|
683
|
+
set velocity(value: PartialShape<T>);
|
|
684
|
+
/**
|
|
685
|
+
* The current acceleration of every channel in value units per second
|
|
686
|
+
* squared, as a read-only mirror of the shape — reused and refreshed in
|
|
687
|
+
* place on each read. Read-only, like each channel's: acceleration
|
|
688
|
+
* follows from the motion. To fling channels, write `velocity`.
|
|
689
|
+
*/
|
|
690
|
+
get acceleration(): ReadonlyShape<T>;
|
|
691
|
+
/**
|
|
692
|
+
* The shared config when every channel resolves to the same
|
|
693
|
+
* `SpringDefinition`, and `null` when they differ.
|
|
694
|
+
*
|
|
695
|
+
* Assignment accepts a `ConfigShape`: one config for every channel,
|
|
696
|
+
* `null` to revert every channel to the default, or a shape mirroring
|
|
697
|
+
* the value with configs at any level — a config at a subtree covers
|
|
698
|
+
* every channel below it. Non-config leaves throw with their path.
|
|
699
|
+
*/
|
|
700
|
+
get config(): SpringDefinition | null;
|
|
701
|
+
set config(value: ConfigShape<T>);
|
|
702
|
+
/**
|
|
703
|
+
* The shared purpose when every channel resolves to the same `Purpose`,
|
|
704
|
+
* and `null` when they differ. Fixed when the spring is created — an
|
|
705
|
+
* `'appearance'` channel opts out of reduced motion. See `Purpose`.
|
|
706
|
+
*/
|
|
707
|
+
get purpose(): Purpose | null;
|
|
708
|
+
/** The largest `timeRemaining` across channels, in milliseconds. */
|
|
709
|
+
get timeRemaining(): number;
|
|
710
|
+
/** Whether every channel is resting. */
|
|
711
|
+
get isResting(): boolean;
|
|
712
|
+
/**
|
|
713
|
+
* A promise that resolves when every channel next rests — already
|
|
714
|
+
* resolved while resting or after dispose. Retargeting any channel
|
|
715
|
+
* mid-flight extends the wait; disposing resolves it.
|
|
716
|
+
*/
|
|
717
|
+
get settled(): Promise<void>;
|
|
718
|
+
/**
|
|
719
|
+
* Snaps the channels the partial shape names to the given values with
|
|
720
|
+
* no animation, notifying listeners synchronously. Channels it leaves
|
|
721
|
+
* out are untouched.
|
|
722
|
+
*/
|
|
723
|
+
jumpTo(value: PartialShape<T>): void;
|
|
724
|
+
/**
|
|
725
|
+
* Releases every channel permanently: resolves `settled` and notifies
|
|
726
|
+
* dispose listeners. Calling it again is a no-op.
|
|
727
|
+
*
|
|
728
|
+
* A disposed composite spring keeps its final values readable; writes
|
|
729
|
+
* throw.
|
|
730
|
+
*/
|
|
731
|
+
dispose(): void;
|
|
732
|
+
/**
|
|
733
|
+
* Subscribes to coalesced value changes: at most one `update` per tick,
|
|
734
|
+
* fired after every channel has advanced, plus one per synchronous
|
|
735
|
+
* write. Returns an unsubscribe function.
|
|
736
|
+
*/
|
|
737
|
+
onUpdate(callback: () => void): () => void;
|
|
738
|
+
/**
|
|
739
|
+
* Subscribes to the composite leaving rest: a channel starts moving
|
|
740
|
+
* while all were resting. Always alternates with `stop`. Returns an
|
|
741
|
+
* unsubscribe function.
|
|
742
|
+
*/
|
|
743
|
+
onStart(callback: () => void): () => void;
|
|
744
|
+
/**
|
|
745
|
+
* Subscribes to the composite coming to rest: every channel resting,
|
|
746
|
+
* fired after that tick's final `update`. Always alternates with
|
|
747
|
+
* `start`. Returns an unsubscribe function.
|
|
748
|
+
*/
|
|
749
|
+
onStop(callback: () => void): () => void;
|
|
750
|
+
/** Subscribes to `dispose`, which fires once. Returns an unsubscribe function. */
|
|
751
|
+
onDispose(callback: () => void): () => void;
|
|
752
|
+
}
|
|
753
|
+
//#endregion
|
|
754
|
+
//#region src/ticker.d.ts
|
|
755
|
+
/** Frame timing options for a spring system. */
|
|
756
|
+
interface TickerOptions {
|
|
757
|
+
/**
|
|
758
|
+
* Frame-rate cap. 0 means uncapped: one tick per displayed frame,
|
|
759
|
+
* whatever rate the screen runs at — 60Hz, 120Hz, or adaptive. Capped
|
|
760
|
+
* ticks are paced to whole display frames, near the requested rate, and
|
|
761
|
+
* each still receives the true elapsed time.
|
|
762
|
+
* @default 0
|
|
763
|
+
*/
|
|
764
|
+
readonly fps?: number | undefined;
|
|
765
|
+
/**
|
|
766
|
+
* Frame gap in milliseconds above which the gap is treated as lag — a
|
|
767
|
+
* backgrounded tab, a blocking task — and replaced with `adjustedLag`,
|
|
768
|
+
* so springs don't teleport when frames resume. 0 disables lag
|
|
769
|
+
* clamping.
|
|
770
|
+
* @default 500
|
|
771
|
+
*/
|
|
772
|
+
readonly lagThreshold?: number | undefined;
|
|
773
|
+
/**
|
|
774
|
+
* The elapsed milliseconds a lagging frame is replaced with. Clamped to
|
|
775
|
+
* at most `lagThreshold`.
|
|
776
|
+
* @default 33
|
|
777
|
+
*/
|
|
778
|
+
readonly adjustedLag?: number | undefined;
|
|
779
|
+
}
|
|
780
|
+
//#endregion
|
|
781
|
+
//#region src/system.d.ts
|
|
782
|
+
/**
|
|
783
|
+
* Per-spring options for `SpringSystem.createSpring`, separate from the
|
|
784
|
+
* physical `config`.
|
|
785
|
+
*/
|
|
786
|
+
interface SpringOptions {
|
|
787
|
+
/**
|
|
788
|
+
* What the spring animates, which decides whether reduced motion applies
|
|
789
|
+
* to it. `'appearance'` — a cross-fade, a color, a blur — keeps
|
|
790
|
+
* animating under reduced motion; `'motion'` snaps to the target. Fixed
|
|
791
|
+
* for the spring's life. See `Purpose`.
|
|
792
|
+
* @default 'motion'
|
|
793
|
+
*/
|
|
794
|
+
purpose?: Purpose | undefined;
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Per-spring options for a composite `SpringSystem.createSpring`, separate
|
|
798
|
+
* from the physical `config`.
|
|
799
|
+
*/
|
|
800
|
+
interface CompositeSpringOptions<T extends object> {
|
|
801
|
+
/**
|
|
802
|
+
* What each channel animates, deciding reduced-motion behavior per
|
|
803
|
+
* channel: a single `Purpose` for every channel, or a shape mirroring
|
|
804
|
+
* the value with purposes at any level — a purpose at a subtree covers
|
|
805
|
+
* every channel below it. Channels it doesn't reach default to
|
|
806
|
+
* `'motion'`. Fixed for the spring's life. See `PurposeShape`.
|
|
807
|
+
* @default 'motion'
|
|
808
|
+
*/
|
|
809
|
+
purpose?: PurposeShape<T> | undefined;
|
|
810
|
+
}
|
|
811
|
+
interface SpringSystemOptions extends TickerOptions {
|
|
812
|
+
/**
|
|
813
|
+
* How far a spring may trail a source it follows within one frame, in
|
|
814
|
+
* the value's own units. A frame whose motion would exceed it is split
|
|
815
|
+
* into internal sub-steps (at most 8), so followed chains stay
|
|
816
|
+
* accurate through slow frames and sudden retargets. Smaller is
|
|
817
|
+
* tighter and costs more solver work; it never goes finer than the
|
|
818
|
+
* follower's resting precision, and listeners still fire once per
|
|
819
|
+
* frame. Springs that follow nothing are unaffected.
|
|
820
|
+
* @default 0.1
|
|
821
|
+
*/
|
|
822
|
+
couplingTolerance?: number | undefined;
|
|
823
|
+
/**
|
|
824
|
+
* Log active motion counts to the console whenever they change.
|
|
825
|
+
* @default false
|
|
826
|
+
*/
|
|
827
|
+
debug?: boolean | undefined;
|
|
828
|
+
/**
|
|
829
|
+
* When springs snap to their targets instead of animating. `'user'`
|
|
830
|
+
* follows the OS prefers-reduced-motion setting, including live changes
|
|
831
|
+
* — switching it on finishes in-flight motion instantly. `'always'` and
|
|
832
|
+
* `'never'` force one behavior.
|
|
833
|
+
* @default 'user'
|
|
834
|
+
*/
|
|
835
|
+
reducedMotion?: 'user' | 'always' | 'never' | undefined;
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Owns springs and advances them over time. Create one with
|
|
839
|
+
* `createSpringSystem`, then either `start()` it to animate on real
|
|
840
|
+
* frames or call `advance` yourself for manual stepping.
|
|
841
|
+
*/
|
|
842
|
+
interface SpringSystem {
|
|
843
|
+
/**
|
|
844
|
+
* Creates a spring at rest at `value`. Without `config`, springs use
|
|
845
|
+
* the default: critically damped, settling in about 500ms. To follow
|
|
846
|
+
* another spring from birth, pass it in place of `value`.
|
|
847
|
+
*
|
|
848
|
+
* `options.purpose` marks what the spring animates: `'appearance'`
|
|
849
|
+
* keeps animating under reduced motion, `'motion'` (the default) snaps.
|
|
850
|
+
*/
|
|
851
|
+
createSpring(value: number, config?: SpringDefinition, options?: SpringOptions): Spring;
|
|
852
|
+
/**
|
|
853
|
+
* Creates a spring already following `source` — a `Spring`, or a value
|
|
854
|
+
* derived with `mapSpring`. It starts at the source's current value,
|
|
855
|
+
* so nothing moves until the source does; equivalent to creating a
|
|
856
|
+
* spring at that value and assigning `source` to its `target`.
|
|
857
|
+
*
|
|
858
|
+
* `options.purpose` marks what the spring animates: `'appearance'`
|
|
859
|
+
* keeps animating under reduced motion, `'motion'` (the default) snaps.
|
|
860
|
+
*/
|
|
861
|
+
createSpring(source: SpringSource, config?: SpringDefinition, options?: SpringOptions): Spring;
|
|
862
|
+
/**
|
|
863
|
+
* Creates a composite spring over a numeric shape: a plain object or
|
|
864
|
+
* array, nested arbitrarily, whose leaves are all numbers. Each leaf
|
|
865
|
+
* becomes an independently sprung channel.
|
|
866
|
+
*
|
|
867
|
+
* `config` applies per channel: a single `SpringDefinition` for every
|
|
868
|
+
* channel, or a shape mirroring the value with configs at any level.
|
|
869
|
+
* `options.purpose` marks reduced-motion behavior the same way, per
|
|
870
|
+
* channel — an `'appearance'` channel keeps animating.
|
|
871
|
+
*/
|
|
872
|
+
createSpring<T extends object>(value: T & Shape<T>, config?: ConfigShape<T>, options?: CompositeSpringOptions<T>): CompositeSpring<T>;
|
|
873
|
+
/**
|
|
874
|
+
* Advances every moving spring by `dt` milliseconds. For manual
|
|
875
|
+
* stepping in place of `start()` — tests, custom loops, offline
|
|
876
|
+
* rendering.
|
|
877
|
+
*/
|
|
878
|
+
advance(dt: number): void;
|
|
879
|
+
/**
|
|
880
|
+
* Begins animating on real frames: one tick per displayed frame, via
|
|
881
|
+
* `requestAnimationFrame` in the browser and a `setTimeout` fallback
|
|
882
|
+
* elsewhere. An idle system sleeps — no frames are scheduled while
|
|
883
|
+
* every spring rests.
|
|
884
|
+
*/
|
|
885
|
+
start(): void;
|
|
886
|
+
/** Stops animating. Springs hold their state until `start` or `advance`. */
|
|
887
|
+
stop(): void;
|
|
888
|
+
/**
|
|
889
|
+
* Whether the system is between `start()` and `stop()`. Sleeping while
|
|
890
|
+
* idle still counts as running.
|
|
891
|
+
*/
|
|
892
|
+
readonly running: boolean;
|
|
893
|
+
/**
|
|
894
|
+
* Whether springs currently snap instead of animating, per the
|
|
895
|
+
* `reducedMotion` option and, in `'user'` mode, the live OS setting.
|
|
896
|
+
* Read it to gate purely decorative effects of your own. Springs
|
|
897
|
+
* created with `purpose: 'appearance'` animate regardless.
|
|
898
|
+
*/
|
|
899
|
+
readonly reducedMotion: boolean;
|
|
900
|
+
/**
|
|
901
|
+
* How far a spring may trail a source it follows within one frame, in
|
|
902
|
+
* the value's own units — see the `couplingTolerance` option.
|
|
903
|
+
* Assignment accepts any finite number >= 0 and applies from the next
|
|
904
|
+
* frame; 0 means as fine as the follower's resting precision allows.
|
|
905
|
+
*/
|
|
906
|
+
couplingTolerance: number;
|
|
907
|
+
/**
|
|
908
|
+
* Frame-rate cap. 0 means uncapped: one tick per displayed frame,
|
|
909
|
+
* whatever rate the screen runs at. Capped ticks land on whole display
|
|
910
|
+
* frames and receive the true elapsed time.
|
|
911
|
+
*/
|
|
912
|
+
fps: number;
|
|
913
|
+
/**
|
|
914
|
+
* Frame gap in milliseconds above which the gap is treated as lag — a
|
|
915
|
+
* backgrounded tab, a blocking task — and replaced with `adjustedLag`,
|
|
916
|
+
* so springs don't teleport when frames resume. 0 disables lag
|
|
917
|
+
* clamping.
|
|
918
|
+
*/
|
|
919
|
+
lagThreshold: number;
|
|
920
|
+
/** The elapsed milliseconds a lagging frame is replaced with. Clamped to at most `lagThreshold`. */
|
|
921
|
+
adjustedLag: number;
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* Creates a spring system: the entry point of the library.
|
|
925
|
+
*
|
|
926
|
+
* @example
|
|
927
|
+
* ```ts
|
|
928
|
+
* const system = createSpringSystem()
|
|
929
|
+
* system.start()
|
|
930
|
+
*
|
|
931
|
+
* const spring = system.createSpring(0)
|
|
932
|
+
* spring.onUpdate(() => {
|
|
933
|
+
* element.style.translate = `${spring.value}px 0`
|
|
934
|
+
* })
|
|
935
|
+
* spring.target = 300
|
|
936
|
+
* ```
|
|
937
|
+
*/
|
|
938
|
+
declare function createSpringSystem(options?: SpringSystemOptions): SpringSystem;
|
|
939
|
+
//#endregion
|
|
940
|
+
export { 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, mapSpring as x, SpringSource as y };
|