coily 0.10.0 → 0.11.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 +1 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/nuxt.d.ts +6 -0
- package/dist/nuxt.js +44 -0
- package/dist/system-B_kZMcpg.d.ts +276 -0
- package/dist/system-Dxxv4ee7.js +614 -0
- package/dist/vue.d.ts +38 -0
- package/dist/vue.js +121 -0
- package/package.json +46 -28
- package/dist/api.d.mts +0 -110
- package/dist/api.d.ts +0 -110
- package/dist/api.mjs +0 -463
- package/dist/loop.d.mts +0 -5
- package/dist/loop.d.ts +0 -5
- package/dist/loop.mjs +0 -14
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
//#region src/motion-set.ts
|
|
2
|
+
var MotionSet = class {
|
|
3
|
+
#motions = /* @__PURE__ */ new Set();
|
|
4
|
+
add(motion) {
|
|
5
|
+
this.#motions.add(motion);
|
|
6
|
+
}
|
|
7
|
+
remove(motion) {
|
|
8
|
+
this.#motions.delete(motion);
|
|
9
|
+
}
|
|
10
|
+
tick(dt) {
|
|
11
|
+
for (const motion of this.#motions) {
|
|
12
|
+
motion.tick(dt);
|
|
13
|
+
if (motion.resting) this.#motions.delete(motion);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/util.ts
|
|
19
|
+
function invariant(condition, message) {
|
|
20
|
+
if (condition) return;
|
|
21
|
+
throw new Error(message ?? "Invariant Failed");
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/config.ts
|
|
25
|
+
/**
|
|
26
|
+
* Immutable spring configuration.
|
|
27
|
+
*/
|
|
28
|
+
var SpringConfig = class {
|
|
29
|
+
mass;
|
|
30
|
+
tension;
|
|
31
|
+
damping;
|
|
32
|
+
precision;
|
|
33
|
+
naturalFrequency;
|
|
34
|
+
criticalDamping;
|
|
35
|
+
dampingRatio;
|
|
36
|
+
precisionMultiplier;
|
|
37
|
+
restingMagnitude;
|
|
38
|
+
constructor(input) {
|
|
39
|
+
const raw = input;
|
|
40
|
+
const mass = raw.mass;
|
|
41
|
+
const tension = raw.tension;
|
|
42
|
+
const damping = raw.damping;
|
|
43
|
+
const bounce = raw.bounce;
|
|
44
|
+
const duration = raw.duration !== void 0 ? raw.duration / 1e3 : void 0;
|
|
45
|
+
const displacement = raw.displacement ?? 1;
|
|
46
|
+
const precision = raw.precision ?? 2;
|
|
47
|
+
if (mass !== void 0) invariant(mass > 0, "Mass must be greater than 0");
|
|
48
|
+
if (tension !== void 0) invariant(tension > 0, "Tension must be greater than 0");
|
|
49
|
+
if (damping !== void 0) invariant(damping >= 0, "Damping must be greater than or equal to 0");
|
|
50
|
+
if (bounce !== void 0) invariant(bounce >= -1 && bounce <= 1, "Bounce must be between -1 and 1");
|
|
51
|
+
const dampingRatio = raw.dampingRatio ?? (bounce !== void 0 ? Math.max(1e-4, 1 - bounce) : void 0);
|
|
52
|
+
if (dampingRatio !== void 0) invariant(dampingRatio >= 0, "Damping ratio must be greater than or equal to 0");
|
|
53
|
+
if (duration !== void 0) invariant(duration > 0, "Duration must be greater than 0");
|
|
54
|
+
invariant(displacement !== 0, "Displacement must not be 0");
|
|
55
|
+
invariant(precision > 0, "Precision must be greater than 0");
|
|
56
|
+
this.precision = precision;
|
|
57
|
+
this.precisionMultiplier = 10 ** precision;
|
|
58
|
+
this.restingMagnitude = 1 / this.precisionMultiplier;
|
|
59
|
+
const hasM = mass !== void 0;
|
|
60
|
+
const hasK = tension !== void 0;
|
|
61
|
+
const hasC = damping !== void 0;
|
|
62
|
+
const hasZ = dampingRatio !== void 0;
|
|
63
|
+
const hasT = duration !== void 0;
|
|
64
|
+
if (hasK && hasC && !hasZ && !hasT) {
|
|
65
|
+
this.mass = mass ?? 1;
|
|
66
|
+
this.tension = tension;
|
|
67
|
+
this.damping = damping;
|
|
68
|
+
} else if (hasK && hasZ && !hasC && !hasT) {
|
|
69
|
+
this.mass = mass ?? 1;
|
|
70
|
+
this.tension = tension;
|
|
71
|
+
this.damping = 2 * dampingRatio * Math.sqrt(this.mass * tension);
|
|
72
|
+
} else if (hasC && hasZ && !hasK && !hasT) {
|
|
73
|
+
invariant(dampingRatio > 0, "dampingRatio must be > 0 to derive tension");
|
|
74
|
+
this.mass = mass ?? 1;
|
|
75
|
+
this.tension = damping ** 2 / (4 * dampingRatio ** 2 * this.mass);
|
|
76
|
+
this.damping = damping;
|
|
77
|
+
} else if (hasK && hasC && hasZ && !hasT) {
|
|
78
|
+
invariant(dampingRatio > 0, "dampingRatio must be > 0 to derive mass");
|
|
79
|
+
this.mass = damping ** 2 / (4 * dampingRatio ** 2 * tension);
|
|
80
|
+
this.tension = tension;
|
|
81
|
+
this.damping = damping;
|
|
82
|
+
} else if (hasZ && hasT) {
|
|
83
|
+
const threshold = this.restingMagnitude;
|
|
84
|
+
const x0 = Math.abs(displacement);
|
|
85
|
+
invariant(x0 > threshold, "displacement must be greater than the precision threshold");
|
|
86
|
+
let sigmaCoeff;
|
|
87
|
+
if (dampingRatio < 1) sigmaCoeff = dampingRatio;
|
|
88
|
+
else if (dampingRatio === 1) sigmaCoeff = 1;
|
|
89
|
+
else sigmaCoeff = dampingRatio - Math.sqrt(dampingRatio ** 2 - 1);
|
|
90
|
+
invariant(sigmaCoeff > 0, "dampingRatio must be > 0 for duration-based config");
|
|
91
|
+
const wn = 2 * Math.log(x0 / threshold) / (sigmaCoeff * duration);
|
|
92
|
+
if (!hasK && !hasC) {
|
|
93
|
+
this.mass = mass ?? 1;
|
|
94
|
+
this.tension = wn ** 2 * this.mass;
|
|
95
|
+
this.damping = 2 * dampingRatio * this.mass * wn;
|
|
96
|
+
} else if (hasK && !hasM && !hasC) {
|
|
97
|
+
this.mass = tension / wn ** 2;
|
|
98
|
+
this.tension = tension;
|
|
99
|
+
this.damping = 2 * dampingRatio * this.mass * wn;
|
|
100
|
+
} else if (hasC && !hasM && !hasK) {
|
|
101
|
+
this.mass = damping / (2 * dampingRatio * wn);
|
|
102
|
+
this.tension = wn ** 2 * this.mass;
|
|
103
|
+
this.damping = damping;
|
|
104
|
+
} else throw new Error("Invalid spring config: provide one of the supported input shapes.");
|
|
105
|
+
} else throw new Error("Invalid spring config: provide one of the supported input shapes.");
|
|
106
|
+
this.naturalFrequency = Math.sqrt(this.tension / this.mass);
|
|
107
|
+
this.criticalDamping = 2 * this.mass * this.naturalFrequency;
|
|
108
|
+
this.dampingRatio = this.damping / this.criticalDamping;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
function defineSpring(input) {
|
|
112
|
+
return new SpringConfig(input);
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/emitter.ts
|
|
116
|
+
var Emitter = class {
|
|
117
|
+
#update = [];
|
|
118
|
+
#start = [];
|
|
119
|
+
#stop = [];
|
|
120
|
+
on(type, handler) {
|
|
121
|
+
this.#list(type).push(handler);
|
|
122
|
+
return () => {
|
|
123
|
+
this.off(type, handler);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
off(type, handler) {
|
|
127
|
+
const list = this.#list(type);
|
|
128
|
+
if (handler) list.splice(list.indexOf(handler) >>> 0, 1);
|
|
129
|
+
else list.length = 0;
|
|
130
|
+
}
|
|
131
|
+
clear() {
|
|
132
|
+
this.#update.length = 0;
|
|
133
|
+
this.#start.length = 0;
|
|
134
|
+
this.#stop.length = 0;
|
|
135
|
+
}
|
|
136
|
+
emit(type) {
|
|
137
|
+
const list = this.#list(type);
|
|
138
|
+
if (list.length === 1) list[0]();
|
|
139
|
+
else if (list.length > 1) for (const handler of list.slice()) handler();
|
|
140
|
+
}
|
|
141
|
+
#list(type) {
|
|
142
|
+
switch (type) {
|
|
143
|
+
case "update": return this.#update;
|
|
144
|
+
case "start": return this.#start;
|
|
145
|
+
case "stop": return this.#stop;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
//#endregion
|
|
150
|
+
//#region src/state.ts
|
|
151
|
+
var State = class {
|
|
152
|
+
#config;
|
|
153
|
+
#position;
|
|
154
|
+
#velocity;
|
|
155
|
+
constructor(config, position, velocity) {
|
|
156
|
+
this.#config = config;
|
|
157
|
+
this.#position = position;
|
|
158
|
+
this.#velocity = velocity;
|
|
159
|
+
}
|
|
160
|
+
configure(config) {
|
|
161
|
+
this.#config = config;
|
|
162
|
+
}
|
|
163
|
+
/** Returns the position rounded to the configured precision. */
|
|
164
|
+
get position() {
|
|
165
|
+
return Math.round(this.#position * this.#config.precisionMultiplier) / this.#config.precisionMultiplier;
|
|
166
|
+
}
|
|
167
|
+
set position(value) {
|
|
168
|
+
this.#position = value;
|
|
169
|
+
}
|
|
170
|
+
/** Returns the velocity rounded to the configured precision. */
|
|
171
|
+
get velocity() {
|
|
172
|
+
return Math.round(this.#velocity * this.#config.precisionMultiplier) / this.#config.precisionMultiplier;
|
|
173
|
+
}
|
|
174
|
+
set velocity(value) {
|
|
175
|
+
this.#velocity = value;
|
|
176
|
+
}
|
|
177
|
+
/** Uses raw (unrounded) values so resting detection isn't affected by output quantization. */
|
|
178
|
+
get resting() {
|
|
179
|
+
return Math.abs(this.#velocity) < this.#config.restingMagnitude && Math.abs(this.#position) < this.#config.restingMagnitude;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region src/solver.ts
|
|
184
|
+
var UnderdampedSolver = class {
|
|
185
|
+
#state;
|
|
186
|
+
#dampedFrequency = 0;
|
|
187
|
+
#decayRate = 0;
|
|
188
|
+
#t = 0;
|
|
189
|
+
#c1 = 0;
|
|
190
|
+
#c2 = 0;
|
|
191
|
+
constructor(state) {
|
|
192
|
+
this.#state = state;
|
|
193
|
+
}
|
|
194
|
+
configure(config) {
|
|
195
|
+
if (config) {
|
|
196
|
+
this.#decayRate = config.dampingRatio * config.naturalFrequency;
|
|
197
|
+
this.#dampedFrequency = config.naturalFrequency * Math.sqrt(1 - config.dampingRatio ** 2);
|
|
198
|
+
}
|
|
199
|
+
this.#t = 0;
|
|
200
|
+
this.#c1 = this.#state.position;
|
|
201
|
+
this.#c2 = (this.#state.velocity + this.#decayRate * this.#state.position) / this.#dampedFrequency;
|
|
202
|
+
}
|
|
203
|
+
tick(dt) {
|
|
204
|
+
this.#t += dt;
|
|
205
|
+
const sin = Math.sin(this.#dampedFrequency * this.#t);
|
|
206
|
+
const cos = Math.cos(this.#dampedFrequency * this.#t);
|
|
207
|
+
const decay = Math.exp(-this.#decayRate * this.#t);
|
|
208
|
+
const decayVelocity = -this.#decayRate * decay;
|
|
209
|
+
const oscillation = this.#c1 * cos + this.#c2 * sin;
|
|
210
|
+
const oscillationVelocity = -this.#c1 * this.#dampedFrequency * sin + this.#c2 * this.#dampedFrequency * cos;
|
|
211
|
+
this.#state.position = decay * oscillation;
|
|
212
|
+
this.#state.velocity = decay * oscillationVelocity + decayVelocity * oscillation;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
var CriticallyDampedSolver = class {
|
|
216
|
+
#state;
|
|
217
|
+
#naturalFrequency = 0;
|
|
218
|
+
#t = 0;
|
|
219
|
+
#c1 = 0;
|
|
220
|
+
#c2 = 0;
|
|
221
|
+
constructor(state) {
|
|
222
|
+
this.#state = state;
|
|
223
|
+
}
|
|
224
|
+
configure(config) {
|
|
225
|
+
if (config) this.#naturalFrequency = config.naturalFrequency;
|
|
226
|
+
this.#t = 0;
|
|
227
|
+
this.#c1 = this.#state.position;
|
|
228
|
+
this.#c2 = this.#state.velocity + this.#naturalFrequency * this.#state.position;
|
|
229
|
+
}
|
|
230
|
+
tick(dt) {
|
|
231
|
+
this.#t += dt;
|
|
232
|
+
const decay = Math.exp(-this.#naturalFrequency * this.#t);
|
|
233
|
+
const decayVelocity = -this.#naturalFrequency * decay;
|
|
234
|
+
const scale = this.#c1 + this.#c2 * this.#t;
|
|
235
|
+
const scaleVelocity = this.#c2;
|
|
236
|
+
this.#state.position = scale * decay;
|
|
237
|
+
this.#state.velocity = scaleVelocity * decay + decayVelocity * scale;
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
var OverdampedSolver = class {
|
|
241
|
+
#state;
|
|
242
|
+
#dampedFrequency = 0;
|
|
243
|
+
#decayRate = 0;
|
|
244
|
+
#t = 0;
|
|
245
|
+
#c1 = 0;
|
|
246
|
+
#c2 = 0;
|
|
247
|
+
constructor(state) {
|
|
248
|
+
this.#state = state;
|
|
249
|
+
}
|
|
250
|
+
configure(config) {
|
|
251
|
+
if (config) {
|
|
252
|
+
this.#decayRate = config.dampingRatio * config.naturalFrequency;
|
|
253
|
+
this.#dampedFrequency = config.naturalFrequency * Math.sqrt(config.dampingRatio ** 2 - 1);
|
|
254
|
+
}
|
|
255
|
+
this.#t = 0;
|
|
256
|
+
this.#c1 = this.#state.velocity + this.#decayRate * this.#state.position;
|
|
257
|
+
this.#c2 = this.#state.position * this.#dampedFrequency;
|
|
258
|
+
}
|
|
259
|
+
tick(dt) {
|
|
260
|
+
this.#t += dt;
|
|
261
|
+
const decay = Math.exp(-this.#decayRate * this.#t);
|
|
262
|
+
const decayVelocity = -this.#decayRate * decay;
|
|
263
|
+
const clamped = Math.min(this.#dampedFrequency * this.#t, 300);
|
|
264
|
+
const sinh = Math.sinh(clamped);
|
|
265
|
+
const cosh = Math.cosh(clamped);
|
|
266
|
+
const scale = this.#c1 * sinh + this.#c2 * cosh;
|
|
267
|
+
const scaleVelocity = this.#c1 * this.#dampedFrequency * cosh + this.#c2 * this.#dampedFrequency * sinh;
|
|
268
|
+
this.#state.position = scale * decay / this.#dampedFrequency;
|
|
269
|
+
this.#state.velocity = (scale * decayVelocity + scaleVelocity * decay) / this.#dampedFrequency;
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
//#endregion
|
|
273
|
+
//#region src/motion.ts
|
|
274
|
+
var Motion = class {
|
|
275
|
+
#config;
|
|
276
|
+
#state;
|
|
277
|
+
#underdampedSolver = null;
|
|
278
|
+
#criticallyDampedSolver = null;
|
|
279
|
+
#overdampedSolver = null;
|
|
280
|
+
#currentSolver = null;
|
|
281
|
+
#needsUpdate = false;
|
|
282
|
+
#needsReset = false;
|
|
283
|
+
#emitter;
|
|
284
|
+
constructor(config, position, velocity) {
|
|
285
|
+
this.#config = config;
|
|
286
|
+
this.#state = new State(config, position, velocity);
|
|
287
|
+
this.#emitter = new Emitter();
|
|
288
|
+
this.#updateSolver();
|
|
289
|
+
}
|
|
290
|
+
get position() {
|
|
291
|
+
return this.#state.position;
|
|
292
|
+
}
|
|
293
|
+
set position(value) {
|
|
294
|
+
this.#state.position = value;
|
|
295
|
+
this.#needsReset = true;
|
|
296
|
+
if (!this.#state.resting) this.#emitter.emit("start");
|
|
297
|
+
}
|
|
298
|
+
get velocity() {
|
|
299
|
+
return this.#state.velocity;
|
|
300
|
+
}
|
|
301
|
+
set velocity(value) {
|
|
302
|
+
this.#state.velocity = value;
|
|
303
|
+
this.#needsReset = true;
|
|
304
|
+
}
|
|
305
|
+
get resting() {
|
|
306
|
+
return this.#state.resting;
|
|
307
|
+
}
|
|
308
|
+
configure(config) {
|
|
309
|
+
this.#config = config;
|
|
310
|
+
this.#state.configure(config);
|
|
311
|
+
this.#needsUpdate = true;
|
|
312
|
+
}
|
|
313
|
+
tick(dt, emit = true) {
|
|
314
|
+
invariant(this.#currentSolver, "Cannot tick a disposed motion");
|
|
315
|
+
if (this.#needsUpdate) {
|
|
316
|
+
this.#updateSolver();
|
|
317
|
+
this.#needsUpdate = false;
|
|
318
|
+
this.#needsReset = false;
|
|
319
|
+
} else if (this.#needsReset) {
|
|
320
|
+
this.#currentSolver.configure();
|
|
321
|
+
this.#needsReset = false;
|
|
322
|
+
}
|
|
323
|
+
this.#currentSolver.tick(dt);
|
|
324
|
+
if (emit) {
|
|
325
|
+
this.#emitter.emit("update");
|
|
326
|
+
if (this.#state.resting) this.#emitter.emit("stop");
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
onUpdate(callback) {
|
|
330
|
+
return this.#emitter.on("update", callback);
|
|
331
|
+
}
|
|
332
|
+
onStart(callback) {
|
|
333
|
+
return this.#emitter.on("start", callback);
|
|
334
|
+
}
|
|
335
|
+
onStop(callback) {
|
|
336
|
+
return this.#emitter.on("stop", callback);
|
|
337
|
+
}
|
|
338
|
+
dispose() {
|
|
339
|
+
this.#emitter.clear();
|
|
340
|
+
this.#underdampedSolver = null;
|
|
341
|
+
this.#criticallyDampedSolver = null;
|
|
342
|
+
this.#overdampedSolver = null;
|
|
343
|
+
this.#currentSolver = null;
|
|
344
|
+
}
|
|
345
|
+
#updateSolver() {
|
|
346
|
+
if (this.#config.dampingRatio < 1) {
|
|
347
|
+
this.#underdampedSolver ||= new UnderdampedSolver(this.#state);
|
|
348
|
+
this.#currentSolver = this.#underdampedSolver;
|
|
349
|
+
} else if (this.#config.dampingRatio === 1) {
|
|
350
|
+
this.#criticallyDampedSolver ||= new CriticallyDampedSolver(this.#state);
|
|
351
|
+
this.#currentSolver = this.#criticallyDampedSolver;
|
|
352
|
+
} else {
|
|
353
|
+
this.#overdampedSolver ||= new OverdampedSolver(this.#state);
|
|
354
|
+
this.#currentSolver = this.#overdampedSolver;
|
|
355
|
+
}
|
|
356
|
+
this.#currentSolver.configure(this.#config);
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
//#endregion
|
|
360
|
+
//#region src/spring.ts
|
|
361
|
+
var Spring = class {
|
|
362
|
+
#target;
|
|
363
|
+
#config;
|
|
364
|
+
#motion;
|
|
365
|
+
#motions;
|
|
366
|
+
constructor(motions, position, config) {
|
|
367
|
+
let target;
|
|
368
|
+
let value;
|
|
369
|
+
if (typeof position === "number") {
|
|
370
|
+
target = position;
|
|
371
|
+
value = position;
|
|
372
|
+
} else {
|
|
373
|
+
target = position.target ?? position.value ?? 0;
|
|
374
|
+
value = position.value ?? target;
|
|
375
|
+
}
|
|
376
|
+
this.#target = target;
|
|
377
|
+
this.#config = config;
|
|
378
|
+
this.#motion = new Motion(config, value - target, 0);
|
|
379
|
+
this.#motions = motions;
|
|
380
|
+
if (!this.#motion.resting) this.#motions.add(this.#motion);
|
|
381
|
+
}
|
|
382
|
+
get target() {
|
|
383
|
+
return this.#target;
|
|
384
|
+
}
|
|
385
|
+
set target(value) {
|
|
386
|
+
if (value !== this.#target) {
|
|
387
|
+
this.#motions.add(this.#motion);
|
|
388
|
+
const currentValue = this.value;
|
|
389
|
+
this.#target = value;
|
|
390
|
+
this.#motion.position = currentValue - this.#target;
|
|
391
|
+
this.#motion.tick(0);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
get value() {
|
|
395
|
+
return this.#target + this.#motion.position;
|
|
396
|
+
}
|
|
397
|
+
set value(value) {
|
|
398
|
+
const position = value - this.#target;
|
|
399
|
+
if (position !== this.#motion.position) {
|
|
400
|
+
this.#motions.add(this.#motion);
|
|
401
|
+
this.#motion.position = position;
|
|
402
|
+
this.#motion.tick(0);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
get velocity() {
|
|
406
|
+
return this.#motion.velocity;
|
|
407
|
+
}
|
|
408
|
+
set velocity(value) {
|
|
409
|
+
this.#motions.add(this.#motion);
|
|
410
|
+
this.#motion.velocity = value;
|
|
411
|
+
}
|
|
412
|
+
get mass() {
|
|
413
|
+
return this.#config.mass;
|
|
414
|
+
}
|
|
415
|
+
get tension() {
|
|
416
|
+
return this.#config.tension;
|
|
417
|
+
}
|
|
418
|
+
get damping() {
|
|
419
|
+
return this.#config.damping;
|
|
420
|
+
}
|
|
421
|
+
get dampingRatio() {
|
|
422
|
+
return this.#config.dampingRatio;
|
|
423
|
+
}
|
|
424
|
+
get precision() {
|
|
425
|
+
return this.#config.precision;
|
|
426
|
+
}
|
|
427
|
+
get resting() {
|
|
428
|
+
return this.#motion.resting;
|
|
429
|
+
}
|
|
430
|
+
configure(config) {
|
|
431
|
+
this.#config = config;
|
|
432
|
+
this.#motion.configure(config);
|
|
433
|
+
this.#motions.add(this.#motion);
|
|
434
|
+
}
|
|
435
|
+
onUpdate(callback) {
|
|
436
|
+
return this.#motion.onUpdate(callback);
|
|
437
|
+
}
|
|
438
|
+
onStart(callback) {
|
|
439
|
+
return this.#motion.onStart(callback);
|
|
440
|
+
}
|
|
441
|
+
onStop(callback) {
|
|
442
|
+
return this.#motion.onStop(callback);
|
|
443
|
+
}
|
|
444
|
+
jumpTo(value) {
|
|
445
|
+
this.#target = value;
|
|
446
|
+
this.#motion.position = 0;
|
|
447
|
+
this.#motion.velocity = 0;
|
|
448
|
+
this.#motion.tick(0);
|
|
449
|
+
}
|
|
450
|
+
dispose() {
|
|
451
|
+
this.#motions.remove(this.#motion);
|
|
452
|
+
this.#motion.dispose();
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
//#endregion
|
|
456
|
+
//#region src/ticker.ts
|
|
457
|
+
const hasWindow = typeof window !== "undefined";
|
|
458
|
+
const request = hasWindow ? (cb) => window.requestAnimationFrame(cb) : (cb) => setTimeout(cb, 1);
|
|
459
|
+
const cancel = hasWindow ? (id) => window.cancelAnimationFrame(id) : (id) => clearTimeout(id);
|
|
460
|
+
var Ticker = class {
|
|
461
|
+
#fps;
|
|
462
|
+
#gap;
|
|
463
|
+
#lagThreshold;
|
|
464
|
+
#adjustedLag;
|
|
465
|
+
#motion;
|
|
466
|
+
#frame = 0;
|
|
467
|
+
#time = 0;
|
|
468
|
+
#previousTime = 0;
|
|
469
|
+
#delta = 0;
|
|
470
|
+
#nextTime;
|
|
471
|
+
#lastWallTime = 0;
|
|
472
|
+
#id = 0;
|
|
473
|
+
#stopped = true;
|
|
474
|
+
constructor(motions, options) {
|
|
475
|
+
this.#motion = motions;
|
|
476
|
+
const fps = options?.fps ?? 60;
|
|
477
|
+
const lagThreshold = options?.lagThreshold ?? 500;
|
|
478
|
+
const adjustedLag = options?.adjustedLag ?? 33;
|
|
479
|
+
invariant(fps > 0, "FPS must be greater than 0");
|
|
480
|
+
invariant(lagThreshold >= 0, "Lag threshold must be greater than or equal to 0");
|
|
481
|
+
invariant(adjustedLag >= 0, "Adjusted lag must be greater than or equal to 0");
|
|
482
|
+
this.#fps = fps;
|
|
483
|
+
this.#gap = 1e3 / fps;
|
|
484
|
+
this.#lagThreshold = lagThreshold === 0 ? 1e8 : lagThreshold;
|
|
485
|
+
this.#adjustedLag = Math.min(adjustedLag, this.#lagThreshold);
|
|
486
|
+
this.#nextTime = this.#gap;
|
|
487
|
+
}
|
|
488
|
+
get fps() {
|
|
489
|
+
return this.#fps;
|
|
490
|
+
}
|
|
491
|
+
set fps(value) {
|
|
492
|
+
invariant(value > 0, "FPS must be greater than 0");
|
|
493
|
+
this.#fps = value;
|
|
494
|
+
this.#gap = 1e3 / value;
|
|
495
|
+
this.#nextTime = this.#previousTime + this.#gap;
|
|
496
|
+
}
|
|
497
|
+
get lagThreshold() {
|
|
498
|
+
return this.#lagThreshold;
|
|
499
|
+
}
|
|
500
|
+
set lagThreshold(value) {
|
|
501
|
+
invariant(value >= 0, "Lag threshold must be greater than or equal to 0");
|
|
502
|
+
this.#lagThreshold = value === 0 ? 1e8 : value;
|
|
503
|
+
this.#adjustedLag = Math.min(this.#adjustedLag, this.#lagThreshold);
|
|
504
|
+
}
|
|
505
|
+
get adjustedLag() {
|
|
506
|
+
return this.#adjustedLag;
|
|
507
|
+
}
|
|
508
|
+
set adjustedLag(value) {
|
|
509
|
+
invariant(value >= 0, "Adjusted lag must be greater than or equal to 0");
|
|
510
|
+
this.#adjustedLag = Math.min(value, this.#lagThreshold);
|
|
511
|
+
}
|
|
512
|
+
get time() {
|
|
513
|
+
return this.#time;
|
|
514
|
+
}
|
|
515
|
+
get frame() {
|
|
516
|
+
return this.#frame;
|
|
517
|
+
}
|
|
518
|
+
get delta() {
|
|
519
|
+
return this.#delta;
|
|
520
|
+
}
|
|
521
|
+
get deltaRatio() {
|
|
522
|
+
return this.#delta / this.#gap;
|
|
523
|
+
}
|
|
524
|
+
get stopped() {
|
|
525
|
+
return this.#stopped;
|
|
526
|
+
}
|
|
527
|
+
start() {
|
|
528
|
+
if (this.#stopped) {
|
|
529
|
+
this.#stopped = false;
|
|
530
|
+
this.#lastWallTime = performance.now();
|
|
531
|
+
this.#id = request((t) => this.#onFrame(t));
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
stop() {
|
|
535
|
+
if (!this.#stopped) {
|
|
536
|
+
cancel(this.#id);
|
|
537
|
+
this.#stopped = true;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
/** Manually advance one frame. */
|
|
541
|
+
tick() {
|
|
542
|
+
this.#step(this.#gap);
|
|
543
|
+
}
|
|
544
|
+
#onFrame(timestamp) {
|
|
545
|
+
if (this.#stopped) return;
|
|
546
|
+
const wallElapsed = timestamp - this.#lastWallTime;
|
|
547
|
+
this.#lastWallTime = timestamp;
|
|
548
|
+
const elapsed = wallElapsed > this.#lagThreshold ? this.#adjustedLag : wallElapsed;
|
|
549
|
+
this.#time += elapsed;
|
|
550
|
+
if (this.#time - this.#nextTime >= 0) {
|
|
551
|
+
this.#frame++;
|
|
552
|
+
this.#delta = this.#time - this.#previousTime;
|
|
553
|
+
this.#previousTime = this.#time;
|
|
554
|
+
this.#nextTime += this.#gap;
|
|
555
|
+
this.#motion.tick(this.#delta / 1e3);
|
|
556
|
+
}
|
|
557
|
+
this.#id = request((t) => this.#onFrame(t));
|
|
558
|
+
}
|
|
559
|
+
#step(dt) {
|
|
560
|
+
this.#time += dt;
|
|
561
|
+
this.#frame++;
|
|
562
|
+
this.#delta = dt;
|
|
563
|
+
this.#previousTime = this.#time;
|
|
564
|
+
this.#motion.tick(dt / 1e3);
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
//#endregion
|
|
568
|
+
//#region src/system.ts
|
|
569
|
+
var SpringSystemImpl = class {
|
|
570
|
+
#motion;
|
|
571
|
+
#ticker;
|
|
572
|
+
constructor(options) {
|
|
573
|
+
this.#motion = new MotionSet();
|
|
574
|
+
this.#ticker = new Ticker(this.#motion, options);
|
|
575
|
+
}
|
|
576
|
+
createSpring(position, config) {
|
|
577
|
+
return new Spring(this.#motion, position, config);
|
|
578
|
+
}
|
|
579
|
+
advance(dt) {
|
|
580
|
+
this.#motion.tick(dt / 1e3);
|
|
581
|
+
}
|
|
582
|
+
start() {
|
|
583
|
+
this.#ticker.start();
|
|
584
|
+
}
|
|
585
|
+
stop() {
|
|
586
|
+
this.#ticker.stop();
|
|
587
|
+
}
|
|
588
|
+
get running() {
|
|
589
|
+
return !this.#ticker.stopped;
|
|
590
|
+
}
|
|
591
|
+
get fps() {
|
|
592
|
+
return this.#ticker.fps;
|
|
593
|
+
}
|
|
594
|
+
set fps(value) {
|
|
595
|
+
this.#ticker.fps = value;
|
|
596
|
+
}
|
|
597
|
+
get lagThreshold() {
|
|
598
|
+
return this.#ticker.lagThreshold;
|
|
599
|
+
}
|
|
600
|
+
set lagThreshold(value) {
|
|
601
|
+
this.#ticker.lagThreshold = value;
|
|
602
|
+
}
|
|
603
|
+
get adjustedLag() {
|
|
604
|
+
return this.#ticker.adjustedLag;
|
|
605
|
+
}
|
|
606
|
+
set adjustedLag(value) {
|
|
607
|
+
this.#ticker.adjustedLag = value;
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
function createSpringSystem(options) {
|
|
611
|
+
return new SpringSystemImpl(options);
|
|
612
|
+
}
|
|
613
|
+
//#endregion
|
|
614
|
+
export { SpringConfig as n, defineSpring as r, createSpringSystem as t };
|
package/dist/vue.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { o as SpringConfig, s as SpringOptions, t as SpringSystem } from "./system-B_kZMcpg.js";
|
|
2
|
+
import * as vue from "vue";
|
|
3
|
+
import { App, MaybeRefOrGetter, Ref, SlotsType } from "vue";
|
|
4
|
+
|
|
5
|
+
//#region src/vue/spring.d.ts
|
|
6
|
+
interface UseSpringReturn {
|
|
7
|
+
readonly value: Ref<number>;
|
|
8
|
+
readonly velocity: Ref<number>;
|
|
9
|
+
readonly resting: Readonly<Ref<boolean>>;
|
|
10
|
+
readonly jumpTo: (value: number) => void;
|
|
11
|
+
}
|
|
12
|
+
declare function useSpring(target: MaybeRefOrGetter<number>, options?: MaybeRefOrGetter<SpringOptions | SpringConfig>): UseSpringReturn;
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/vue/component.d.ts
|
|
15
|
+
interface SpringValueProps {
|
|
16
|
+
target: number;
|
|
17
|
+
mass?: number;
|
|
18
|
+
tension?: number;
|
|
19
|
+
damping?: number;
|
|
20
|
+
precision?: number;
|
|
21
|
+
}
|
|
22
|
+
type SpringValueEmits = Record<string, never>;
|
|
23
|
+
type SpringValueSlots = SlotsType<{
|
|
24
|
+
default: {
|
|
25
|
+
value: number;
|
|
26
|
+
velocity: number;
|
|
27
|
+
resting: boolean;
|
|
28
|
+
};
|
|
29
|
+
}>;
|
|
30
|
+
declare const SpringValue: vue.DefineSetupFnComponent<SpringValueProps, SpringValueEmits, SpringValueSlots, SpringValueProps & {
|
|
31
|
+
[x: `on${Capitalize<string>}`]: ((...args: unknown[]) => any) | undefined;
|
|
32
|
+
}, vue.PublicProps>;
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/vue/system.d.ts
|
|
35
|
+
declare function provideSpringSystem(system: SpringSystem, app?: App): void;
|
|
36
|
+
declare function useSpringSystem(): void;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { SpringValue, type SpringValueProps, type SpringValueSlots, provideSpringSystem, useSpring, useSpringSystem };
|