coily 0.11.0 → 0.12.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/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/nuxt.d.ts +4 -1
- package/dist/nuxt.js +36 -11
- package/dist/{system-Dxxv4ee7.js → system-DPaqec-Z.js} +418 -39
- package/dist/{system-B_kZMcpg.d.ts → system-Do5rE0j7.d.ts} +111 -31
- package/dist/vue.d.ts +27 -16
- package/dist/vue.js +295 -49
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { type Spring, type SpringConfig, type SpringOptions, type SpringPosition, type SpringSystem, type TickerOptions, createSpringSystem, defineSpring };
|
|
1
|
+
import { _ as defineSpring, a as Spring2D, c as Spring2DWithOffset, d as SpringPosition, f as SpringTarget, g as SpringState, h as SpringOptions, i as TickerOptions, l as Vector2, m as SpringConfig, n as SpringSystemOptions, o as Spring2DPosition, p as SpringWithOffset, r as createSpringSystem, s as Spring2DTarget, t as SpringSystem, u as Spring } from "./system-Do5rE0j7.js";
|
|
2
|
+
export { type Spring, type Spring2D, type Spring2DPosition, type Spring2DTarget, type Spring2DWithOffset, type SpringConfig, type SpringOptions, type SpringPosition, type SpringState, type SpringSystem, type SpringSystemOptions, type SpringTarget, type SpringWithOffset, type TickerOptions, type Vector2, createSpringSystem, defineSpring };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { r as defineSpring, t as createSpringSystem } from "./system-
|
|
1
|
+
import { r as defineSpring, t as createSpringSystem } from "./system-DPaqec-Z.js";
|
|
2
2
|
export { createSpringSystem, defineSpring };
|
package/dist/nuxt.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { NuxtModule } from "@nuxt/schema";
|
|
2
2
|
|
|
3
3
|
//#region src/vue/nuxt.d.ts
|
|
4
|
+
interface CoilyModuleOptions {
|
|
5
|
+
debug?: boolean;
|
|
6
|
+
}
|
|
4
7
|
declare const coilyModule: NuxtModule;
|
|
5
8
|
//#endregion
|
|
6
|
-
export { coilyModule as default };
|
|
9
|
+
export { CoilyModuleOptions, coilyModule as default };
|
package/dist/nuxt.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { addComponent, addImports, addPluginTemplate, defineNuxtModule } from "@nuxt/kit";
|
|
2
2
|
//#region src/vue/nuxt.ts
|
|
3
|
-
|
|
3
|
+
function getPluginTemplate(options) {
|
|
4
|
+
return `import { createSpringSystem } from 'coily'
|
|
4
5
|
import { provideSpringSystem } from 'coily/vue'
|
|
5
6
|
|
|
6
7
|
export default defineNuxtPlugin((nuxtApp) => {
|
|
7
8
|
nuxtApp.hook('app:created', (vueApp) => {
|
|
8
|
-
const system = createSpringSystem()
|
|
9
|
+
const system = createSpringSystem(${options.debug ? "{ debug: true }" : ""})
|
|
9
10
|
provideSpringSystem(system, vueApp)
|
|
10
11
|
|
|
11
12
|
if(import.meta.client) {
|
|
@@ -13,25 +14,49 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
13
14
|
}
|
|
14
15
|
})
|
|
15
16
|
})`;
|
|
17
|
+
}
|
|
16
18
|
const coilyModule = defineNuxtModule({
|
|
17
19
|
meta: {
|
|
18
20
|
name: "coily",
|
|
19
21
|
configKey: "coily"
|
|
20
22
|
},
|
|
21
|
-
|
|
23
|
+
defaults: { debug: false },
|
|
24
|
+
async setup(_options) {
|
|
22
25
|
addPluginTemplate({
|
|
23
26
|
name: "coily",
|
|
24
27
|
filename: "coily.plugin.mjs",
|
|
25
28
|
mode: "all",
|
|
26
|
-
getContents: () =>
|
|
29
|
+
getContents: () => getPluginTemplate(_options)
|
|
27
30
|
});
|
|
28
|
-
addImports([
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
addImports([
|
|
32
|
+
{
|
|
33
|
+
from: "coily/vue",
|
|
34
|
+
name: "useSpring"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
from: "coily/vue",
|
|
38
|
+
name: "useSpring2D"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
from: "coily/vue",
|
|
42
|
+
name: "SpringRef",
|
|
43
|
+
type: true
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
from: "coily/vue",
|
|
47
|
+
name: "SpringRef2D",
|
|
48
|
+
type: true
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
from: "coily",
|
|
52
|
+
name: "defineSpring"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
from: "coily",
|
|
56
|
+
name: "SpringConfig",
|
|
57
|
+
type: true
|
|
58
|
+
}
|
|
59
|
+
]);
|
|
35
60
|
addComponent({
|
|
36
61
|
name: "SpringValue",
|
|
37
62
|
filePath: "coily/vue",
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
//#region src/motion-set.ts
|
|
2
2
|
var MotionSet = class {
|
|
3
3
|
#motions = /* @__PURE__ */ new Set();
|
|
4
|
+
#debug;
|
|
5
|
+
#lastSize = 0;
|
|
6
|
+
constructor(debug = false) {
|
|
7
|
+
this.#debug = debug;
|
|
8
|
+
}
|
|
4
9
|
add(motion) {
|
|
5
10
|
this.#motions.add(motion);
|
|
6
11
|
}
|
|
@@ -10,7 +15,11 @@ var MotionSet = class {
|
|
|
10
15
|
tick(dt) {
|
|
11
16
|
for (const motion of this.#motions) {
|
|
12
17
|
motion.tick(dt);
|
|
13
|
-
if (motion.
|
|
18
|
+
if (motion.isResting) this.#motions.delete(motion);
|
|
19
|
+
}
|
|
20
|
+
if (this.#debug && this.#motions.size !== this.#lastSize) {
|
|
21
|
+
this.#lastSize = this.#motions.size;
|
|
22
|
+
console.log(`coily: ${this.#lastSize} active motions`);
|
|
14
23
|
}
|
|
15
24
|
}
|
|
16
25
|
};
|
|
@@ -25,7 +34,10 @@ function invariant(condition, message) {
|
|
|
25
34
|
/**
|
|
26
35
|
* Immutable spring configuration.
|
|
27
36
|
*/
|
|
37
|
+
let globalConfigVersion = 0;
|
|
28
38
|
var SpringConfig = class {
|
|
39
|
+
/** @internal Incremented by `SpringConfig.assign` to signal mutations. */
|
|
40
|
+
#version = 0;
|
|
29
41
|
mass;
|
|
30
42
|
tension;
|
|
31
43
|
damping;
|
|
@@ -52,10 +64,10 @@ var SpringConfig = class {
|
|
|
52
64
|
if (dampingRatio !== void 0) invariant(dampingRatio >= 0, "Damping ratio must be greater than or equal to 0");
|
|
53
65
|
if (duration !== void 0) invariant(duration > 0, "Duration must be greater than 0");
|
|
54
66
|
invariant(displacement !== 0, "Displacement must not be 0");
|
|
55
|
-
invariant(precision
|
|
67
|
+
invariant(precision >= 0, "Precision must be greater than or equal to 0");
|
|
56
68
|
this.precision = precision;
|
|
57
69
|
this.precisionMultiplier = 10 ** precision;
|
|
58
|
-
this.restingMagnitude =
|
|
70
|
+
this.restingMagnitude = .5 / this.precisionMultiplier;
|
|
59
71
|
const hasM = mass !== void 0;
|
|
60
72
|
const hasK = tension !== void 0;
|
|
61
73
|
const hasC = damping !== void 0;
|
|
@@ -80,7 +92,7 @@ var SpringConfig = class {
|
|
|
80
92
|
this.tension = tension;
|
|
81
93
|
this.damping = damping;
|
|
82
94
|
} else if (hasZ && hasT) {
|
|
83
|
-
const threshold =
|
|
95
|
+
const threshold = .005;
|
|
84
96
|
const x0 = Math.abs(displacement);
|
|
85
97
|
invariant(x0 > threshold, "displacement must be greater than the precision threshold");
|
|
86
98
|
let sigmaCoeff;
|
|
@@ -107,6 +119,56 @@ var SpringConfig = class {
|
|
|
107
119
|
this.criticalDamping = 2 * this.mass * this.naturalFrequency;
|
|
108
120
|
this.dampingRatio = this.damping / this.criticalDamping;
|
|
109
121
|
}
|
|
122
|
+
static get globalVersion() {
|
|
123
|
+
return globalConfigVersion;
|
|
124
|
+
}
|
|
125
|
+
static version(config) {
|
|
126
|
+
return config.#version;
|
|
127
|
+
}
|
|
128
|
+
static assign(target, source) {
|
|
129
|
+
globalConfigVersion++;
|
|
130
|
+
target.#version++;
|
|
131
|
+
const t = target;
|
|
132
|
+
t.mass = source.mass;
|
|
133
|
+
t.tension = source.tension;
|
|
134
|
+
t.damping = source.damping;
|
|
135
|
+
t.precision = source.precision;
|
|
136
|
+
t.naturalFrequency = source.naturalFrequency;
|
|
137
|
+
t.criticalDamping = source.criticalDamping;
|
|
138
|
+
t.dampingRatio = source.dampingRatio;
|
|
139
|
+
t.precisionMultiplier = source.precisionMultiplier;
|
|
140
|
+
t.restingMagnitude = source.restingMagnitude;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Analytically estimates the time remaining for a spring to come to rest,
|
|
144
|
+
* given the current displacement and velocity.
|
|
145
|
+
*
|
|
146
|
+
* Uses the exponential decay envelope common to all three damping regimes.
|
|
147
|
+
* The decay rate depends on the regime:
|
|
148
|
+
* - Underdamped (ζ < 1): σ = ζωₙ
|
|
149
|
+
* - Critically damped (ζ = 1): σ = ωₙ
|
|
150
|
+
* - Overdamped (ζ > 1): σ = (ζ - √(ζ²-1))ωₙ (the slower eigenvalue)
|
|
151
|
+
*
|
|
152
|
+
* The effective initial amplitude accounts for both displacement and velocity,
|
|
153
|
+
* since kinetic energy can convert to additional displacement:
|
|
154
|
+
* A₀ = |x₀| + |v₀| / ωₙ
|
|
155
|
+
*
|
|
156
|
+
* Settling time: t = ln(A₀ / threshold) / σ, with a 2× safety factor
|
|
157
|
+
* to account for polynomial terms in the critically damped solution.
|
|
158
|
+
*
|
|
159
|
+
* Returns the estimated time in milliseconds.
|
|
160
|
+
*/
|
|
161
|
+
computeTimeRemaining(state) {
|
|
162
|
+
const { position, velocity } = state;
|
|
163
|
+
const a0 = Math.abs(position) + Math.abs(velocity) / this.naturalFrequency;
|
|
164
|
+
if (a0 <= this.restingMagnitude) return 0;
|
|
165
|
+
let sigma;
|
|
166
|
+
if (this.dampingRatio < 1) sigma = this.dampingRatio * this.naturalFrequency;
|
|
167
|
+
else if (this.dampingRatio === 1) sigma = this.naturalFrequency;
|
|
168
|
+
else sigma = (this.dampingRatio - Math.sqrt(this.dampingRatio * this.dampingRatio - 1)) * this.naturalFrequency;
|
|
169
|
+
if (sigma <= 0) return Infinity;
|
|
170
|
+
return 2 * Math.log(a0 / this.restingMagnitude) / sigma * 1e3;
|
|
171
|
+
}
|
|
110
172
|
};
|
|
111
173
|
function defineSpring(input) {
|
|
112
174
|
return new SpringConfig(input);
|
|
@@ -174,9 +236,9 @@ var State = class {
|
|
|
174
236
|
set velocity(value) {
|
|
175
237
|
this.#velocity = value;
|
|
176
238
|
}
|
|
177
|
-
/**
|
|
178
|
-
get
|
|
179
|
-
return
|
|
239
|
+
/** A spring is resting when its rounded position and velocity are both zero. */
|
|
240
|
+
get isResting() {
|
|
241
|
+
return this.position === 0 && this.velocity === 0;
|
|
180
242
|
}
|
|
181
243
|
};
|
|
182
244
|
//#endregion
|
|
@@ -280,12 +342,16 @@ var Motion = class {
|
|
|
280
342
|
#currentSolver = null;
|
|
281
343
|
#needsUpdate = false;
|
|
282
344
|
#needsReset = false;
|
|
345
|
+
#configVersion = 0;
|
|
346
|
+
#globalConfigVersion = 0;
|
|
347
|
+
#timeRemaining = 0;
|
|
283
348
|
#emitter;
|
|
284
349
|
constructor(config, position, velocity) {
|
|
285
350
|
this.#config = config;
|
|
286
351
|
this.#state = new State(config, position, velocity);
|
|
287
352
|
this.#emitter = new Emitter();
|
|
288
353
|
this.#updateSolver();
|
|
354
|
+
this.#timeRemaining = this.#config.computeTimeRemaining(this.#state);
|
|
289
355
|
}
|
|
290
356
|
get position() {
|
|
291
357
|
return this.#state.position;
|
|
@@ -293,7 +359,7 @@ var Motion = class {
|
|
|
293
359
|
set position(value) {
|
|
294
360
|
this.#state.position = value;
|
|
295
361
|
this.#needsReset = true;
|
|
296
|
-
if (!this.#state.
|
|
362
|
+
if (!this.#state.isResting) this.#emitter.emit("start");
|
|
297
363
|
}
|
|
298
364
|
get velocity() {
|
|
299
365
|
return this.#state.velocity;
|
|
@@ -302,16 +368,31 @@ var Motion = class {
|
|
|
302
368
|
this.#state.velocity = value;
|
|
303
369
|
this.#needsReset = true;
|
|
304
370
|
}
|
|
305
|
-
get
|
|
306
|
-
return this.#
|
|
371
|
+
get timeRemaining() {
|
|
372
|
+
return this.#timeRemaining;
|
|
373
|
+
}
|
|
374
|
+
get isResting() {
|
|
375
|
+
return this.#state.isResting;
|
|
307
376
|
}
|
|
308
377
|
configure(config) {
|
|
309
378
|
this.#config = config;
|
|
310
379
|
this.#state.configure(config);
|
|
380
|
+
this.#configVersion = SpringConfig.version(config);
|
|
381
|
+
this.#globalConfigVersion = SpringConfig.globalVersion;
|
|
311
382
|
this.#needsUpdate = true;
|
|
312
383
|
}
|
|
313
384
|
tick(dt, emit = true) {
|
|
314
385
|
invariant(this.#currentSolver, "Cannot tick a disposed motion");
|
|
386
|
+
const gv = SpringConfig.globalVersion;
|
|
387
|
+
if (gv !== this.#globalConfigVersion) {
|
|
388
|
+
this.#globalConfigVersion = gv;
|
|
389
|
+
if (SpringConfig.version(this.#config) !== this.#configVersion) {
|
|
390
|
+
this.#state.configure(this.#config);
|
|
391
|
+
this.#configVersion = SpringConfig.version(this.#config);
|
|
392
|
+
this.#needsUpdate = true;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
const needsTimeRemaining = this.#needsUpdate || this.#needsReset;
|
|
315
396
|
if (this.#needsUpdate) {
|
|
316
397
|
this.#updateSolver();
|
|
317
398
|
this.#needsUpdate = false;
|
|
@@ -320,10 +401,15 @@ var Motion = class {
|
|
|
320
401
|
this.#currentSolver.configure();
|
|
321
402
|
this.#needsReset = false;
|
|
322
403
|
}
|
|
404
|
+
if (needsTimeRemaining) this.#timeRemaining = this.#config.computeTimeRemaining(this.#state);
|
|
323
405
|
this.#currentSolver.tick(dt);
|
|
406
|
+
this.#timeRemaining = Math.max(0, this.#timeRemaining - dt * 1e3);
|
|
324
407
|
if (emit) {
|
|
325
408
|
this.#emitter.emit("update");
|
|
326
|
-
if (this.#state.
|
|
409
|
+
if (this.#state.isResting) {
|
|
410
|
+
this.#timeRemaining = 0;
|
|
411
|
+
this.#emitter.emit("stop");
|
|
412
|
+
}
|
|
327
413
|
}
|
|
328
414
|
}
|
|
329
415
|
onUpdate(callback) {
|
|
@@ -358,37 +444,69 @@ var Motion = class {
|
|
|
358
444
|
};
|
|
359
445
|
//#endregion
|
|
360
446
|
//#region src/spring.ts
|
|
361
|
-
|
|
447
|
+
function normalizeTarget(target) {
|
|
448
|
+
if (target instanceof Spring) return {
|
|
449
|
+
spring: target,
|
|
450
|
+
offset: 0
|
|
451
|
+
};
|
|
452
|
+
if (typeof target === "object" && target !== null && "spring" in target && target.spring instanceof Spring) return {
|
|
453
|
+
spring: target.spring,
|
|
454
|
+
offset: target.offset ?? 0
|
|
455
|
+
};
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
var Spring = class Spring {
|
|
362
459
|
#target;
|
|
363
460
|
#config;
|
|
364
461
|
#motion;
|
|
365
462
|
#motions;
|
|
463
|
+
#leader = null;
|
|
464
|
+
#offset = 0;
|
|
465
|
+
#hasConfigOverride;
|
|
466
|
+
#unsubLeader = null;
|
|
366
467
|
constructor(motions, position, config) {
|
|
367
|
-
|
|
468
|
+
this.#motions = motions;
|
|
469
|
+
let numericTarget;
|
|
368
470
|
let value;
|
|
471
|
+
let normalized = null;
|
|
369
472
|
if (typeof position === "number") {
|
|
370
|
-
|
|
473
|
+
numericTarget = position;
|
|
371
474
|
value = position;
|
|
372
475
|
} else {
|
|
373
|
-
|
|
374
|
-
|
|
476
|
+
normalized = normalizeTarget(position.target);
|
|
477
|
+
if (normalized) {
|
|
478
|
+
numericTarget = Spring.#rawValue(normalized.spring) + normalized.offset;
|
|
479
|
+
value = position.value ?? numericTarget;
|
|
480
|
+
} else {
|
|
481
|
+
numericTarget = position.target ?? position.value ?? 0;
|
|
482
|
+
value = position.value ?? numericTarget;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
const hasOverride = config !== void 0;
|
|
486
|
+
this.#hasConfigOverride = hasOverride || !normalized;
|
|
487
|
+
if (normalized && !hasOverride) this.#config = normalized.spring.#config;
|
|
488
|
+
else this.#config = config;
|
|
489
|
+
this.#target = numericTarget;
|
|
490
|
+
this.#motion = new Motion(this.#config, value - numericTarget, 0);
|
|
491
|
+
if (!this.#motion.isResting) this.#motions.add(this.#motion);
|
|
492
|
+
if (normalized) {
|
|
493
|
+
this.#leader = normalized.spring;
|
|
494
|
+
this.#offset = normalized.offset;
|
|
495
|
+
this.#unsubLeader = normalized.spring.onUpdate(() => {
|
|
496
|
+
this.#setTarget(Spring.#rawValue(this.#leader) + this.#offset);
|
|
497
|
+
});
|
|
375
498
|
}
|
|
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
499
|
}
|
|
382
500
|
get target() {
|
|
383
501
|
return this.#target;
|
|
384
502
|
}
|
|
385
503
|
set target(value) {
|
|
386
|
-
if (value
|
|
387
|
-
this.#
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
this.#
|
|
504
|
+
if (typeof value === "number") {
|
|
505
|
+
this.#unfollow();
|
|
506
|
+
this.#setTarget(value);
|
|
507
|
+
} else {
|
|
508
|
+
const normalized = normalizeTarget(value);
|
|
509
|
+
this.#follow(normalized.spring, normalized.offset);
|
|
392
510
|
}
|
|
393
511
|
}
|
|
394
512
|
get value() {
|
|
@@ -409,6 +527,9 @@ var Spring = class {
|
|
|
409
527
|
this.#motions.add(this.#motion);
|
|
410
528
|
this.#motion.velocity = value;
|
|
411
529
|
}
|
|
530
|
+
get config() {
|
|
531
|
+
return this.#config;
|
|
532
|
+
}
|
|
412
533
|
get mass() {
|
|
413
534
|
return this.#config.mass;
|
|
414
535
|
}
|
|
@@ -424,22 +545,32 @@ var Spring = class {
|
|
|
424
545
|
get precision() {
|
|
425
546
|
return this.#config.precision;
|
|
426
547
|
}
|
|
427
|
-
get resting() {
|
|
428
|
-
return this.#motion.resting;
|
|
429
|
-
}
|
|
430
548
|
configure(config) {
|
|
431
|
-
this.#
|
|
432
|
-
|
|
549
|
+
if (this.#leader && !this.#hasConfigOverride) {
|
|
550
|
+
this.#hasConfigOverride = true;
|
|
551
|
+
this.#config = new SpringConfig({
|
|
552
|
+
tension: config.tension,
|
|
553
|
+
damping: config.damping,
|
|
554
|
+
mass: config.mass,
|
|
555
|
+
precision: config.precision
|
|
556
|
+
});
|
|
557
|
+
this.#motion.configure(this.#config);
|
|
558
|
+
} else SpringConfig.assign(this.#config, config);
|
|
433
559
|
this.#motions.add(this.#motion);
|
|
434
560
|
}
|
|
435
|
-
|
|
436
|
-
|
|
561
|
+
clearConfigOverride() {
|
|
562
|
+
if (this.#leader && this.#hasConfigOverride) {
|
|
563
|
+
this.#hasConfigOverride = false;
|
|
564
|
+
this.#config = this.#leader.#config;
|
|
565
|
+
this.#motion.configure(this.#config);
|
|
566
|
+
this.#motions.add(this.#motion);
|
|
567
|
+
}
|
|
437
568
|
}
|
|
438
|
-
|
|
439
|
-
return this.#motion.
|
|
569
|
+
get timeRemaining() {
|
|
570
|
+
return this.#motion.timeRemaining;
|
|
440
571
|
}
|
|
441
|
-
|
|
442
|
-
return this.#motion.
|
|
572
|
+
get isResting() {
|
|
573
|
+
return this.#motion.isResting;
|
|
443
574
|
}
|
|
444
575
|
jumpTo(value) {
|
|
445
576
|
this.#target = value;
|
|
@@ -448,9 +579,254 @@ var Spring = class {
|
|
|
448
579
|
this.#motion.tick(0);
|
|
449
580
|
}
|
|
450
581
|
dispose() {
|
|
582
|
+
if (this.#unsubLeader) {
|
|
583
|
+
this.#unsubLeader();
|
|
584
|
+
this.#unsubLeader = null;
|
|
585
|
+
}
|
|
451
586
|
this.#motions.remove(this.#motion);
|
|
452
587
|
this.#motion.dispose();
|
|
453
588
|
}
|
|
589
|
+
onUpdate(callback) {
|
|
590
|
+
return this.#motion.onUpdate(callback);
|
|
591
|
+
}
|
|
592
|
+
onStart(callback) {
|
|
593
|
+
return this.#motion.onStart(callback);
|
|
594
|
+
}
|
|
595
|
+
onStop(callback) {
|
|
596
|
+
return this.#motion.onStop(callback);
|
|
597
|
+
}
|
|
598
|
+
static #rawValue(spring) {
|
|
599
|
+
return spring.#target + spring.#motion.position;
|
|
600
|
+
}
|
|
601
|
+
#setTarget(value) {
|
|
602
|
+
if (value !== this.#target) {
|
|
603
|
+
this.#motions.add(this.#motion);
|
|
604
|
+
const rawValue = this.#target + this.#motion.position;
|
|
605
|
+
this.#target = value;
|
|
606
|
+
this.#motion.position = rawValue - this.#target;
|
|
607
|
+
this.#motion.tick(0);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
#follow(leader, offset) {
|
|
611
|
+
if (this.#unsubLeader) this.#unsubLeader();
|
|
612
|
+
this.#leader = leader;
|
|
613
|
+
this.#offset = offset;
|
|
614
|
+
if (!this.#hasConfigOverride) {
|
|
615
|
+
this.#config = leader.#config;
|
|
616
|
+
this.#motion.configure(this.#config);
|
|
617
|
+
}
|
|
618
|
+
this.#unsubLeader = leader.onUpdate(() => {
|
|
619
|
+
this.#setTarget(Spring.#rawValue(this.#leader) + this.#offset);
|
|
620
|
+
});
|
|
621
|
+
this.#setTarget(Spring.#rawValue(leader) + offset);
|
|
622
|
+
}
|
|
623
|
+
#unfollow() {
|
|
624
|
+
if (!this.#leader) return;
|
|
625
|
+
this.#unsubLeader();
|
|
626
|
+
this.#unsubLeader = null;
|
|
627
|
+
this.#leader = null;
|
|
628
|
+
this.#offset = 0;
|
|
629
|
+
if (!this.#hasConfigOverride) {
|
|
630
|
+
this.#hasConfigOverride = true;
|
|
631
|
+
this.#config = new SpringConfig({
|
|
632
|
+
tension: this.#config.tension,
|
|
633
|
+
damping: this.#config.damping,
|
|
634
|
+
mass: this.#config.mass,
|
|
635
|
+
precision: this.#config.precision
|
|
636
|
+
});
|
|
637
|
+
this.#motion.configure(this.#config);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
//#endregion
|
|
642
|
+
//#region src/vector2.ts
|
|
643
|
+
function isVector2(value) {
|
|
644
|
+
return typeof value === "object" && value !== null && "x" in value && typeof value.x === "number";
|
|
645
|
+
}
|
|
646
|
+
//#endregion
|
|
647
|
+
//#region src/spring2d.ts
|
|
648
|
+
function normalizeTarget2D(target) {
|
|
649
|
+
if (target instanceof Spring2D) return {
|
|
650
|
+
spring: target,
|
|
651
|
+
offset: void 0
|
|
652
|
+
};
|
|
653
|
+
if (typeof target === "object" && target !== null && "spring" in target && target.spring instanceof Spring2D) return {
|
|
654
|
+
spring: target.spring,
|
|
655
|
+
offset: target.offset
|
|
656
|
+
};
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
659
|
+
function toScalarTarget(spring, offset) {
|
|
660
|
+
return offset ? {
|
|
661
|
+
spring,
|
|
662
|
+
offset
|
|
663
|
+
} : spring;
|
|
664
|
+
}
|
|
665
|
+
function toScalarPos(target, value) {
|
|
666
|
+
if (typeof target === "number") return value !== void 0 ? {
|
|
667
|
+
target,
|
|
668
|
+
value
|
|
669
|
+
} : target;
|
|
670
|
+
return {
|
|
671
|
+
target,
|
|
672
|
+
value
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
var Spring2D = class Spring2D {
|
|
676
|
+
#x;
|
|
677
|
+
#y;
|
|
678
|
+
#value = {
|
|
679
|
+
x: 0,
|
|
680
|
+
y: 0
|
|
681
|
+
};
|
|
682
|
+
#velocity = {
|
|
683
|
+
x: 0,
|
|
684
|
+
y: 0
|
|
685
|
+
};
|
|
686
|
+
constructor(motions, position, config) {
|
|
687
|
+
let xPos;
|
|
688
|
+
let yPos;
|
|
689
|
+
if (isVector2(position)) {
|
|
690
|
+
xPos = position.x;
|
|
691
|
+
yPos = position.y;
|
|
692
|
+
} else {
|
|
693
|
+
const normalized = normalizeTarget2D(position.target);
|
|
694
|
+
if (normalized) {
|
|
695
|
+
const lx = normalized.spring.#x;
|
|
696
|
+
const ly = normalized.spring.#y;
|
|
697
|
+
const xTarget = toScalarTarget(lx, normalized.offset?.x);
|
|
698
|
+
const yTarget = toScalarTarget(ly, normalized.offset?.y);
|
|
699
|
+
xPos = toScalarPos(xTarget, position.value?.x);
|
|
700
|
+
yPos = toScalarPos(yTarget, position.value?.y);
|
|
701
|
+
} else if (isVector2(position.target)) {
|
|
702
|
+
const t = position.target;
|
|
703
|
+
xPos = {
|
|
704
|
+
target: t.x,
|
|
705
|
+
value: position.value?.x
|
|
706
|
+
};
|
|
707
|
+
yPos = {
|
|
708
|
+
target: t.y,
|
|
709
|
+
value: position.value?.y
|
|
710
|
+
};
|
|
711
|
+
} else {
|
|
712
|
+
xPos = {
|
|
713
|
+
target: position.target,
|
|
714
|
+
value: position.value?.x
|
|
715
|
+
};
|
|
716
|
+
yPos = {
|
|
717
|
+
target: void 0,
|
|
718
|
+
value: position.value?.y
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
this.#x = new Spring(motions, xPos, config);
|
|
723
|
+
this.#y = new Spring(motions, yPos, config);
|
|
724
|
+
}
|
|
725
|
+
get target() {
|
|
726
|
+
return {
|
|
727
|
+
x: this.#x.target,
|
|
728
|
+
y: this.#y.target
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
set target(value) {
|
|
732
|
+
if (value instanceof Spring2D) {
|
|
733
|
+
this.#x.target = value.#x;
|
|
734
|
+
this.#y.target = value.#y;
|
|
735
|
+
} else if ("spring" in value && value.spring instanceof Spring2D) {
|
|
736
|
+
const { spring, offset } = value;
|
|
737
|
+
this.#x.target = toScalarTarget(spring.#x, offset?.x);
|
|
738
|
+
this.#y.target = toScalarTarget(spring.#y, offset?.y);
|
|
739
|
+
} else {
|
|
740
|
+
const v = value;
|
|
741
|
+
this.#x.target = v.x;
|
|
742
|
+
this.#y.target = v.y;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
get value() {
|
|
746
|
+
this.#value.x = this.#x.value;
|
|
747
|
+
this.#value.y = this.#y.value;
|
|
748
|
+
return this.#value;
|
|
749
|
+
}
|
|
750
|
+
set value(value) {
|
|
751
|
+
this.#x.value = value.x;
|
|
752
|
+
this.#y.value = value.y;
|
|
753
|
+
}
|
|
754
|
+
get velocity() {
|
|
755
|
+
this.#velocity.x = this.#x.velocity;
|
|
756
|
+
this.#velocity.y = this.#y.velocity;
|
|
757
|
+
return this.#velocity;
|
|
758
|
+
}
|
|
759
|
+
set velocity(value) {
|
|
760
|
+
this.#x.velocity = value.x;
|
|
761
|
+
this.#y.velocity = value.y;
|
|
762
|
+
}
|
|
763
|
+
get config() {
|
|
764
|
+
return this.#x.config;
|
|
765
|
+
}
|
|
766
|
+
get mass() {
|
|
767
|
+
return this.#x.mass;
|
|
768
|
+
}
|
|
769
|
+
get tension() {
|
|
770
|
+
return this.#x.tension;
|
|
771
|
+
}
|
|
772
|
+
get damping() {
|
|
773
|
+
return this.#x.damping;
|
|
774
|
+
}
|
|
775
|
+
get dampingRatio() {
|
|
776
|
+
return this.#x.dampingRatio;
|
|
777
|
+
}
|
|
778
|
+
get precision() {
|
|
779
|
+
return this.#x.precision;
|
|
780
|
+
}
|
|
781
|
+
configure(config) {
|
|
782
|
+
this.#x.configure(config);
|
|
783
|
+
this.#y.configure(config);
|
|
784
|
+
}
|
|
785
|
+
clearConfigOverride() {
|
|
786
|
+
this.#x.clearConfigOverride();
|
|
787
|
+
this.#y.clearConfigOverride();
|
|
788
|
+
}
|
|
789
|
+
get timeRemaining() {
|
|
790
|
+
return Math.max(this.#x.timeRemaining, this.#y.timeRemaining);
|
|
791
|
+
}
|
|
792
|
+
get isResting() {
|
|
793
|
+
return this.#x.isResting && this.#y.isResting;
|
|
794
|
+
}
|
|
795
|
+
jumpTo(value) {
|
|
796
|
+
this.#x.jumpTo(value.x);
|
|
797
|
+
this.#y.jumpTo(value.y);
|
|
798
|
+
}
|
|
799
|
+
dispose() {
|
|
800
|
+
this.#x.dispose();
|
|
801
|
+
this.#y.dispose();
|
|
802
|
+
}
|
|
803
|
+
onUpdate(callback) {
|
|
804
|
+
const a = this.#x.onUpdate(callback);
|
|
805
|
+
const b = this.#y.onUpdate(callback);
|
|
806
|
+
return () => {
|
|
807
|
+
a();
|
|
808
|
+
b();
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
onStart(callback) {
|
|
812
|
+
const a = this.#x.onStart(callback);
|
|
813
|
+
const b = this.#y.onStart(callback);
|
|
814
|
+
return () => {
|
|
815
|
+
a();
|
|
816
|
+
b();
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
onStop(callback) {
|
|
820
|
+
const check = () => {
|
|
821
|
+
if (this.isResting) callback();
|
|
822
|
+
};
|
|
823
|
+
const a = this.#x.onStop(check);
|
|
824
|
+
const b = this.#y.onStop(check);
|
|
825
|
+
return () => {
|
|
826
|
+
a();
|
|
827
|
+
b();
|
|
828
|
+
};
|
|
829
|
+
}
|
|
454
830
|
};
|
|
455
831
|
//#endregion
|
|
456
832
|
//#region src/ticker.ts
|
|
@@ -570,12 +946,15 @@ var SpringSystemImpl = class {
|
|
|
570
946
|
#motion;
|
|
571
947
|
#ticker;
|
|
572
948
|
constructor(options) {
|
|
573
|
-
this.#motion = new MotionSet();
|
|
949
|
+
this.#motion = new MotionSet(options?.debug);
|
|
574
950
|
this.#ticker = new Ticker(this.#motion, options);
|
|
575
951
|
}
|
|
576
952
|
createSpring(position, config) {
|
|
577
953
|
return new Spring(this.#motion, position, config);
|
|
578
954
|
}
|
|
955
|
+
createSpring2D(position, config) {
|
|
956
|
+
return new Spring2D(this.#motion, position, config);
|
|
957
|
+
}
|
|
579
958
|
advance(dt) {
|
|
580
959
|
this.#motion.tick(dt / 1e3);
|
|
581
960
|
}
|