coily 0.11.0 → 0.12.1
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-BD52hyd8.js} +404 -40
- package/dist/{system-B_kZMcpg.d.ts → system-CMaMt_7p.d.ts} +105 -28
- package/dist/vue.d.ts +30 -16
- package/dist/vue.js +305 -57
- 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-CMaMt_7p.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-BD52hyd8.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,13 @@ function invariant(condition, message) {
|
|
|
25
34
|
/**
|
|
26
35
|
* Immutable spring configuration.
|
|
27
36
|
*/
|
|
28
|
-
var SpringConfig = class {
|
|
37
|
+
var SpringConfig = class SpringConfig {
|
|
38
|
+
static default = new SpringConfig({
|
|
39
|
+
dampingRatio: 1,
|
|
40
|
+
duration: 500
|
|
41
|
+
});
|
|
42
|
+
/** @internal Incremented by `SpringConfig.assign` to signal mutations. */
|
|
43
|
+
#version = 0;
|
|
29
44
|
mass;
|
|
30
45
|
tension;
|
|
31
46
|
damping;
|
|
@@ -52,10 +67,10 @@ var SpringConfig = class {
|
|
|
52
67
|
if (dampingRatio !== void 0) invariant(dampingRatio >= 0, "Damping ratio must be greater than or equal to 0");
|
|
53
68
|
if (duration !== void 0) invariant(duration > 0, "Duration must be greater than 0");
|
|
54
69
|
invariant(displacement !== 0, "Displacement must not be 0");
|
|
55
|
-
invariant(precision
|
|
70
|
+
invariant(precision >= 0, "Precision must be greater than or equal to 0");
|
|
56
71
|
this.precision = precision;
|
|
57
72
|
this.precisionMultiplier = 10 ** precision;
|
|
58
|
-
this.restingMagnitude =
|
|
73
|
+
this.restingMagnitude = .5 / this.precisionMultiplier;
|
|
59
74
|
const hasM = mass !== void 0;
|
|
60
75
|
const hasK = tension !== void 0;
|
|
61
76
|
const hasC = damping !== void 0;
|
|
@@ -80,7 +95,7 @@ var SpringConfig = class {
|
|
|
80
95
|
this.tension = tension;
|
|
81
96
|
this.damping = damping;
|
|
82
97
|
} else if (hasZ && hasT) {
|
|
83
|
-
const threshold =
|
|
98
|
+
const threshold = .005;
|
|
84
99
|
const x0 = Math.abs(displacement);
|
|
85
100
|
invariant(x0 > threshold, "displacement must be greater than the precision threshold");
|
|
86
101
|
let sigmaCoeff;
|
|
@@ -107,6 +122,52 @@ var SpringConfig = class {
|
|
|
107
122
|
this.criticalDamping = 2 * this.mass * this.naturalFrequency;
|
|
108
123
|
this.dampingRatio = this.damping / this.criticalDamping;
|
|
109
124
|
}
|
|
125
|
+
static version(config) {
|
|
126
|
+
return config.#version;
|
|
127
|
+
}
|
|
128
|
+
static assign(target, source) {
|
|
129
|
+
target.#version++;
|
|
130
|
+
const t = target;
|
|
131
|
+
t.mass = source.mass;
|
|
132
|
+
t.tension = source.tension;
|
|
133
|
+
t.damping = source.damping;
|
|
134
|
+
t.precision = source.precision;
|
|
135
|
+
t.naturalFrequency = source.naturalFrequency;
|
|
136
|
+
t.criticalDamping = source.criticalDamping;
|
|
137
|
+
t.dampingRatio = source.dampingRatio;
|
|
138
|
+
t.precisionMultiplier = source.precisionMultiplier;
|
|
139
|
+
t.restingMagnitude = source.restingMagnitude;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Analytically estimates the time remaining for a spring to come to rest,
|
|
143
|
+
* given the current displacement and velocity.
|
|
144
|
+
*
|
|
145
|
+
* Uses the exponential decay envelope common to all three damping regimes.
|
|
146
|
+
* The decay rate depends on the regime:
|
|
147
|
+
* - Underdamped (ζ < 1): σ = ζωₙ
|
|
148
|
+
* - Critically damped (ζ = 1): σ = ωₙ
|
|
149
|
+
* - Overdamped (ζ > 1): σ = (ζ - √(ζ²-1))ωₙ (the slower eigenvalue)
|
|
150
|
+
*
|
|
151
|
+
* The effective initial amplitude accounts for both displacement and velocity,
|
|
152
|
+
* since kinetic energy can convert to additional displacement:
|
|
153
|
+
* A₀ = |x₀| + |v₀| / ωₙ
|
|
154
|
+
*
|
|
155
|
+
* Settling time: t = ln(A₀ / threshold) / σ, with a 2× safety factor
|
|
156
|
+
* to account for polynomial terms in the critically damped solution.
|
|
157
|
+
*
|
|
158
|
+
* Returns the estimated time in milliseconds.
|
|
159
|
+
*/
|
|
160
|
+
computeTimeRemaining(state) {
|
|
161
|
+
const { position, velocity } = state;
|
|
162
|
+
const a0 = Math.abs(position) + Math.abs(velocity) / this.naturalFrequency;
|
|
163
|
+
if (a0 <= this.restingMagnitude) return 0;
|
|
164
|
+
let sigma;
|
|
165
|
+
if (this.dampingRatio < 1) sigma = this.dampingRatio * this.naturalFrequency;
|
|
166
|
+
else if (this.dampingRatio === 1) sigma = this.naturalFrequency;
|
|
167
|
+
else sigma = (this.dampingRatio - Math.sqrt(this.dampingRatio * this.dampingRatio - 1)) * this.naturalFrequency;
|
|
168
|
+
if (sigma <= 0) return Infinity;
|
|
169
|
+
return 2 * Math.log(a0 / this.restingMagnitude) / sigma * 1e3;
|
|
170
|
+
}
|
|
110
171
|
};
|
|
111
172
|
function defineSpring(input) {
|
|
112
173
|
return new SpringConfig(input);
|
|
@@ -174,9 +235,9 @@ var State = class {
|
|
|
174
235
|
set velocity(value) {
|
|
175
236
|
this.#velocity = value;
|
|
176
237
|
}
|
|
177
|
-
/**
|
|
178
|
-
get
|
|
179
|
-
return
|
|
238
|
+
/** A spring is resting when its rounded position and velocity are both zero. */
|
|
239
|
+
get isResting() {
|
|
240
|
+
return this.position === 0 && this.velocity === 0;
|
|
180
241
|
}
|
|
181
242
|
};
|
|
182
243
|
//#endregion
|
|
@@ -280,12 +341,15 @@ var Motion = class {
|
|
|
280
341
|
#currentSolver = null;
|
|
281
342
|
#needsUpdate = false;
|
|
282
343
|
#needsReset = false;
|
|
344
|
+
#configVersion = 0;
|
|
345
|
+
#timeRemaining = 0;
|
|
283
346
|
#emitter;
|
|
284
347
|
constructor(config, position, velocity) {
|
|
285
348
|
this.#config = config;
|
|
286
349
|
this.#state = new State(config, position, velocity);
|
|
287
350
|
this.#emitter = new Emitter();
|
|
288
351
|
this.#updateSolver();
|
|
352
|
+
this.#timeRemaining = this.#config.computeTimeRemaining(this.#state);
|
|
289
353
|
}
|
|
290
354
|
get position() {
|
|
291
355
|
return this.#state.position;
|
|
@@ -293,7 +357,7 @@ var Motion = class {
|
|
|
293
357
|
set position(value) {
|
|
294
358
|
this.#state.position = value;
|
|
295
359
|
this.#needsReset = true;
|
|
296
|
-
if (!this.#state.
|
|
360
|
+
if (!this.#state.isResting) this.#emitter.emit("start");
|
|
297
361
|
}
|
|
298
362
|
get velocity() {
|
|
299
363
|
return this.#state.velocity;
|
|
@@ -302,16 +366,26 @@ var Motion = class {
|
|
|
302
366
|
this.#state.velocity = value;
|
|
303
367
|
this.#needsReset = true;
|
|
304
368
|
}
|
|
305
|
-
get
|
|
306
|
-
return this.#
|
|
369
|
+
get timeRemaining() {
|
|
370
|
+
return this.#timeRemaining;
|
|
371
|
+
}
|
|
372
|
+
get isResting() {
|
|
373
|
+
return this.#state.isResting;
|
|
307
374
|
}
|
|
308
375
|
configure(config) {
|
|
309
376
|
this.#config = config;
|
|
310
377
|
this.#state.configure(config);
|
|
378
|
+
this.#configVersion = SpringConfig.version(config);
|
|
311
379
|
this.#needsUpdate = true;
|
|
312
380
|
}
|
|
313
381
|
tick(dt, emit = true) {
|
|
314
382
|
invariant(this.#currentSolver, "Cannot tick a disposed motion");
|
|
383
|
+
if (SpringConfig.version(this.#config) !== this.#configVersion) {
|
|
384
|
+
this.#state.configure(this.#config);
|
|
385
|
+
this.#configVersion = SpringConfig.version(this.#config);
|
|
386
|
+
this.#needsUpdate = true;
|
|
387
|
+
}
|
|
388
|
+
const needsTimeRemaining = this.#needsUpdate || this.#needsReset;
|
|
315
389
|
if (this.#needsUpdate) {
|
|
316
390
|
this.#updateSolver();
|
|
317
391
|
this.#needsUpdate = false;
|
|
@@ -320,10 +394,15 @@ var Motion = class {
|
|
|
320
394
|
this.#currentSolver.configure();
|
|
321
395
|
this.#needsReset = false;
|
|
322
396
|
}
|
|
397
|
+
if (needsTimeRemaining) this.#timeRemaining = this.#config.computeTimeRemaining(this.#state);
|
|
323
398
|
this.#currentSolver.tick(dt);
|
|
399
|
+
this.#timeRemaining = Math.max(0, this.#timeRemaining - dt * 1e3);
|
|
324
400
|
if (emit) {
|
|
325
401
|
this.#emitter.emit("update");
|
|
326
|
-
if (this.#state.
|
|
402
|
+
if (this.#state.isResting) {
|
|
403
|
+
this.#timeRemaining = 0;
|
|
404
|
+
this.#emitter.emit("stop");
|
|
405
|
+
}
|
|
327
406
|
}
|
|
328
407
|
}
|
|
329
408
|
onUpdate(callback) {
|
|
@@ -358,37 +437,69 @@ var Motion = class {
|
|
|
358
437
|
};
|
|
359
438
|
//#endregion
|
|
360
439
|
//#region src/spring.ts
|
|
440
|
+
function normalizeTarget(target) {
|
|
441
|
+
if (target instanceof Spring) return {
|
|
442
|
+
spring: target,
|
|
443
|
+
offset: 0
|
|
444
|
+
};
|
|
445
|
+
if (typeof target === "object" && target !== null && "spring" in target && target.spring instanceof Spring) return {
|
|
446
|
+
spring: target.spring,
|
|
447
|
+
offset: target.offset ?? 0
|
|
448
|
+
};
|
|
449
|
+
return null;
|
|
450
|
+
}
|
|
361
451
|
var Spring = class {
|
|
362
452
|
#target;
|
|
363
453
|
#config;
|
|
364
454
|
#motion;
|
|
365
455
|
#motions;
|
|
456
|
+
#leader = null;
|
|
457
|
+
#offset = 0;
|
|
458
|
+
#ownsConfig;
|
|
459
|
+
#unsubLeader = null;
|
|
366
460
|
constructor(motions, position, config) {
|
|
367
|
-
|
|
461
|
+
this.#motions = motions;
|
|
462
|
+
let numericTarget;
|
|
368
463
|
let value;
|
|
464
|
+
let normalized = null;
|
|
369
465
|
if (typeof position === "number") {
|
|
370
|
-
|
|
466
|
+
numericTarget = position;
|
|
371
467
|
value = position;
|
|
372
468
|
} else {
|
|
373
|
-
|
|
374
|
-
|
|
469
|
+
normalized = normalizeTarget(position.target);
|
|
470
|
+
if (normalized) {
|
|
471
|
+
numericTarget = normalized.spring.#target + normalized.spring.#motion.position + normalized.offset;
|
|
472
|
+
value = position.value ?? numericTarget;
|
|
473
|
+
} else {
|
|
474
|
+
numericTarget = position.target ?? position.value ?? 0;
|
|
475
|
+
value = position.value ?? numericTarget;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
const hasOverride = config !== void 0;
|
|
479
|
+
this.#ownsConfig = hasOverride || !normalized;
|
|
480
|
+
if (normalized && !hasOverride) this.#config = normalized.spring.#config;
|
|
481
|
+
else this.#config = config ?? SpringConfig.default;
|
|
482
|
+
this.#target = numericTarget;
|
|
483
|
+
this.#motion = new Motion(this.#config, value - numericTarget, 0);
|
|
484
|
+
if (!this.#motion.isResting) this.#motions.add(this.#motion);
|
|
485
|
+
if (normalized) {
|
|
486
|
+
this.#leader = normalized.spring;
|
|
487
|
+
this.#offset = normalized.offset;
|
|
488
|
+
this.#unsubLeader = normalized.spring.onUpdate(() => {
|
|
489
|
+
this.#setTarget(this.#leader.#target + this.#leader.#motion.position + this.#offset);
|
|
490
|
+
});
|
|
375
491
|
}
|
|
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
492
|
}
|
|
382
493
|
get target() {
|
|
383
494
|
return this.#target;
|
|
384
495
|
}
|
|
385
496
|
set target(value) {
|
|
386
|
-
if (value
|
|
387
|
-
this.#
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
this.#
|
|
497
|
+
if (typeof value === "number") {
|
|
498
|
+
this.#unfollow();
|
|
499
|
+
this.#setTarget(value);
|
|
500
|
+
} else {
|
|
501
|
+
const normalized = normalizeTarget(value);
|
|
502
|
+
this.#follow(normalized.spring, normalized.offset);
|
|
392
503
|
}
|
|
393
504
|
}
|
|
394
505
|
get value() {
|
|
@@ -409,6 +520,9 @@ var Spring = class {
|
|
|
409
520
|
this.#motions.add(this.#motion);
|
|
410
521
|
this.#motion.velocity = value;
|
|
411
522
|
}
|
|
523
|
+
get config() {
|
|
524
|
+
return this.#config;
|
|
525
|
+
}
|
|
412
526
|
get mass() {
|
|
413
527
|
return this.#config.mass;
|
|
414
528
|
}
|
|
@@ -424,13 +538,45 @@ var Spring = class {
|
|
|
424
538
|
get precision() {
|
|
425
539
|
return this.#config.precision;
|
|
426
540
|
}
|
|
427
|
-
|
|
428
|
-
|
|
541
|
+
set config(value) {
|
|
542
|
+
if (value) {
|
|
543
|
+
if (this.#leader && !this.#ownsConfig) {
|
|
544
|
+
this.#ownsConfig = true;
|
|
545
|
+
this.#config = new SpringConfig({
|
|
546
|
+
tension: value.tension,
|
|
547
|
+
damping: value.damping,
|
|
548
|
+
mass: value.mass,
|
|
549
|
+
precision: value.precision
|
|
550
|
+
});
|
|
551
|
+
this.#motion.configure(this.#config);
|
|
552
|
+
} else SpringConfig.assign(this.#config, value);
|
|
553
|
+
this.#motions.add(this.#motion);
|
|
554
|
+
} else if (this.#ownsConfig) {
|
|
555
|
+
this.#ownsConfig = false;
|
|
556
|
+
this.#config = this.#leader ? this.#leader.#config : SpringConfig.default;
|
|
557
|
+
this.#motion.configure(this.#config);
|
|
558
|
+
this.#motions.add(this.#motion);
|
|
559
|
+
}
|
|
429
560
|
}
|
|
430
|
-
|
|
431
|
-
this.#
|
|
432
|
-
|
|
433
|
-
|
|
561
|
+
get timeRemaining() {
|
|
562
|
+
return this.#motion.timeRemaining;
|
|
563
|
+
}
|
|
564
|
+
get isResting() {
|
|
565
|
+
return this.#motion.isResting;
|
|
566
|
+
}
|
|
567
|
+
jumpTo(value) {
|
|
568
|
+
this.#target = value;
|
|
569
|
+
this.#motion.position = 0;
|
|
570
|
+
this.#motion.velocity = 0;
|
|
571
|
+
this.#motion.tick(0);
|
|
572
|
+
}
|
|
573
|
+
dispose() {
|
|
574
|
+
if (this.#unsubLeader) {
|
|
575
|
+
this.#unsubLeader();
|
|
576
|
+
this.#unsubLeader = null;
|
|
577
|
+
}
|
|
578
|
+
this.#motions.remove(this.#motion);
|
|
579
|
+
this.#motion.dispose();
|
|
434
580
|
}
|
|
435
581
|
onUpdate(callback) {
|
|
436
582
|
return this.#motion.onUpdate(callback);
|
|
@@ -441,15 +587,230 @@ var Spring = class {
|
|
|
441
587
|
onStop(callback) {
|
|
442
588
|
return this.#motion.onStop(callback);
|
|
443
589
|
}
|
|
590
|
+
#setTarget(value) {
|
|
591
|
+
if (value !== this.#target) {
|
|
592
|
+
this.#motions.add(this.#motion);
|
|
593
|
+
const rawValue = this.#target + this.#motion.position;
|
|
594
|
+
this.#target = value;
|
|
595
|
+
this.#motion.position = rawValue - this.#target;
|
|
596
|
+
this.#motion.tick(0);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
#follow(leader, offset) {
|
|
600
|
+
if (this.#unsubLeader) this.#unsubLeader();
|
|
601
|
+
this.#leader = leader;
|
|
602
|
+
this.#offset = offset;
|
|
603
|
+
if (!this.#ownsConfig) {
|
|
604
|
+
this.#config = leader.#config;
|
|
605
|
+
this.#motion.configure(this.#config);
|
|
606
|
+
}
|
|
607
|
+
this.#unsubLeader = leader.onUpdate(() => {
|
|
608
|
+
this.#setTarget(this.#leader.#target + this.#leader.#motion.position + this.#offset);
|
|
609
|
+
});
|
|
610
|
+
this.#setTarget(leader.#target + leader.#motion.position + offset);
|
|
611
|
+
}
|
|
612
|
+
#unfollow() {
|
|
613
|
+
if (!this.#leader) return;
|
|
614
|
+
this.#unsubLeader();
|
|
615
|
+
this.#unsubLeader = null;
|
|
616
|
+
this.#leader = null;
|
|
617
|
+
this.#offset = 0;
|
|
618
|
+
if (!this.#ownsConfig) {
|
|
619
|
+
this.#ownsConfig = true;
|
|
620
|
+
this.#config = new SpringConfig({
|
|
621
|
+
tension: this.#config.tension,
|
|
622
|
+
damping: this.#config.damping,
|
|
623
|
+
mass: this.#config.mass,
|
|
624
|
+
precision: this.#config.precision
|
|
625
|
+
});
|
|
626
|
+
this.#motion.configure(this.#config);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
//#endregion
|
|
631
|
+
//#region src/vector2.ts
|
|
632
|
+
function isVector2(value) {
|
|
633
|
+
return typeof value === "object" && value !== null && "x" in value && typeof value.x === "number";
|
|
634
|
+
}
|
|
635
|
+
//#endregion
|
|
636
|
+
//#region src/spring2d.ts
|
|
637
|
+
function normalizeTarget2D(target) {
|
|
638
|
+
if (target instanceof Spring2D) return {
|
|
639
|
+
spring: target,
|
|
640
|
+
offset: void 0
|
|
641
|
+
};
|
|
642
|
+
if (typeof target === "object" && target !== null && "spring" in target && target.spring instanceof Spring2D) return {
|
|
643
|
+
spring: target.spring,
|
|
644
|
+
offset: target.offset
|
|
645
|
+
};
|
|
646
|
+
return null;
|
|
647
|
+
}
|
|
648
|
+
function toScalarTarget(spring, offset) {
|
|
649
|
+
return offset ? {
|
|
650
|
+
spring,
|
|
651
|
+
offset
|
|
652
|
+
} : spring;
|
|
653
|
+
}
|
|
654
|
+
function toScalarPos(target, value) {
|
|
655
|
+
if (typeof target === "number") return value !== void 0 ? {
|
|
656
|
+
target,
|
|
657
|
+
value
|
|
658
|
+
} : target;
|
|
659
|
+
return {
|
|
660
|
+
target,
|
|
661
|
+
value
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
var Spring2D = class Spring2D {
|
|
665
|
+
#x;
|
|
666
|
+
#y;
|
|
667
|
+
#value = {
|
|
668
|
+
x: 0,
|
|
669
|
+
y: 0
|
|
670
|
+
};
|
|
671
|
+
#velocity = {
|
|
672
|
+
x: 0,
|
|
673
|
+
y: 0
|
|
674
|
+
};
|
|
675
|
+
constructor(motions, position, config) {
|
|
676
|
+
let xPos;
|
|
677
|
+
let yPos;
|
|
678
|
+
if (isVector2(position)) {
|
|
679
|
+
xPos = position.x;
|
|
680
|
+
yPos = position.y;
|
|
681
|
+
} else {
|
|
682
|
+
const normalized = normalizeTarget2D(position.target);
|
|
683
|
+
if (normalized) {
|
|
684
|
+
const lx = normalized.spring.#x;
|
|
685
|
+
const ly = normalized.spring.#y;
|
|
686
|
+
const xTarget = toScalarTarget(lx, normalized.offset?.x);
|
|
687
|
+
const yTarget = toScalarTarget(ly, normalized.offset?.y);
|
|
688
|
+
xPos = toScalarPos(xTarget, position.value?.x);
|
|
689
|
+
yPos = toScalarPos(yTarget, position.value?.y);
|
|
690
|
+
} else if (isVector2(position.target)) {
|
|
691
|
+
const t = position.target;
|
|
692
|
+
xPos = {
|
|
693
|
+
target: t.x,
|
|
694
|
+
value: position.value?.x
|
|
695
|
+
};
|
|
696
|
+
yPos = {
|
|
697
|
+
target: t.y,
|
|
698
|
+
value: position.value?.y
|
|
699
|
+
};
|
|
700
|
+
} else {
|
|
701
|
+
xPos = {
|
|
702
|
+
target: position.target,
|
|
703
|
+
value: position.value?.x
|
|
704
|
+
};
|
|
705
|
+
yPos = {
|
|
706
|
+
target: void 0,
|
|
707
|
+
value: position.value?.y
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
this.#x = new Spring(motions, xPos, config);
|
|
712
|
+
this.#y = new Spring(motions, yPos, config);
|
|
713
|
+
}
|
|
714
|
+
get target() {
|
|
715
|
+
return {
|
|
716
|
+
x: this.#x.target,
|
|
717
|
+
y: this.#y.target
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
set target(value) {
|
|
721
|
+
if (value instanceof Spring2D) {
|
|
722
|
+
this.#x.target = value.#x;
|
|
723
|
+
this.#y.target = value.#y;
|
|
724
|
+
} else if ("spring" in value && value.spring instanceof Spring2D) {
|
|
725
|
+
const { spring, offset } = value;
|
|
726
|
+
this.#x.target = toScalarTarget(spring.#x, offset?.x);
|
|
727
|
+
this.#y.target = toScalarTarget(spring.#y, offset?.y);
|
|
728
|
+
} else {
|
|
729
|
+
const v = value;
|
|
730
|
+
this.#x.target = v.x;
|
|
731
|
+
this.#y.target = v.y;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
get value() {
|
|
735
|
+
this.#value.x = this.#x.value;
|
|
736
|
+
this.#value.y = this.#y.value;
|
|
737
|
+
return this.#value;
|
|
738
|
+
}
|
|
739
|
+
set value(value) {
|
|
740
|
+
this.#x.value = value.x;
|
|
741
|
+
this.#y.value = value.y;
|
|
742
|
+
}
|
|
743
|
+
get velocity() {
|
|
744
|
+
this.#velocity.x = this.#x.velocity;
|
|
745
|
+
this.#velocity.y = this.#y.velocity;
|
|
746
|
+
return this.#velocity;
|
|
747
|
+
}
|
|
748
|
+
set velocity(value) {
|
|
749
|
+
this.#x.velocity = value.x;
|
|
750
|
+
this.#y.velocity = value.y;
|
|
751
|
+
}
|
|
752
|
+
get config() {
|
|
753
|
+
return this.#x.config;
|
|
754
|
+
}
|
|
755
|
+
get mass() {
|
|
756
|
+
return this.#x.mass;
|
|
757
|
+
}
|
|
758
|
+
get tension() {
|
|
759
|
+
return this.#x.tension;
|
|
760
|
+
}
|
|
761
|
+
get damping() {
|
|
762
|
+
return this.#x.damping;
|
|
763
|
+
}
|
|
764
|
+
get dampingRatio() {
|
|
765
|
+
return this.#x.dampingRatio;
|
|
766
|
+
}
|
|
767
|
+
get precision() {
|
|
768
|
+
return this.#x.precision;
|
|
769
|
+
}
|
|
770
|
+
set config(value) {
|
|
771
|
+
this.#x.config = value;
|
|
772
|
+
this.#y.config = value;
|
|
773
|
+
}
|
|
774
|
+
get timeRemaining() {
|
|
775
|
+
return Math.max(this.#x.timeRemaining, this.#y.timeRemaining);
|
|
776
|
+
}
|
|
777
|
+
get isResting() {
|
|
778
|
+
return this.#x.isResting && this.#y.isResting;
|
|
779
|
+
}
|
|
444
780
|
jumpTo(value) {
|
|
445
|
-
this.#
|
|
446
|
-
this.#
|
|
447
|
-
this.#motion.velocity = 0;
|
|
448
|
-
this.#motion.tick(0);
|
|
781
|
+
this.#x.jumpTo(value.x);
|
|
782
|
+
this.#y.jumpTo(value.y);
|
|
449
783
|
}
|
|
450
784
|
dispose() {
|
|
451
|
-
this.#
|
|
452
|
-
this.#
|
|
785
|
+
this.#x.dispose();
|
|
786
|
+
this.#y.dispose();
|
|
787
|
+
}
|
|
788
|
+
onUpdate(callback) {
|
|
789
|
+
const a = this.#x.onUpdate(callback);
|
|
790
|
+
const b = this.#y.onUpdate(callback);
|
|
791
|
+
return () => {
|
|
792
|
+
a();
|
|
793
|
+
b();
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
onStart(callback) {
|
|
797
|
+
const a = this.#x.onStart(callback);
|
|
798
|
+
const b = this.#y.onStart(callback);
|
|
799
|
+
return () => {
|
|
800
|
+
a();
|
|
801
|
+
b();
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
onStop(callback) {
|
|
805
|
+
const check = () => {
|
|
806
|
+
if (this.isResting) callback();
|
|
807
|
+
};
|
|
808
|
+
const a = this.#x.onStop(check);
|
|
809
|
+
const b = this.#y.onStop(check);
|
|
810
|
+
return () => {
|
|
811
|
+
a();
|
|
812
|
+
b();
|
|
813
|
+
};
|
|
453
814
|
}
|
|
454
815
|
};
|
|
455
816
|
//#endregion
|
|
@@ -570,12 +931,15 @@ var SpringSystemImpl = class {
|
|
|
570
931
|
#motion;
|
|
571
932
|
#ticker;
|
|
572
933
|
constructor(options) {
|
|
573
|
-
this.#motion = new MotionSet();
|
|
934
|
+
this.#motion = new MotionSet(options?.debug);
|
|
574
935
|
this.#ticker = new Ticker(this.#motion, options);
|
|
575
936
|
}
|
|
576
937
|
createSpring(position, config) {
|
|
577
938
|
return new Spring(this.#motion, position, config);
|
|
578
939
|
}
|
|
940
|
+
createSpring2D(position, config) {
|
|
941
|
+
return new Spring2D(this.#motion, position, config);
|
|
942
|
+
}
|
|
579
943
|
advance(dt) {
|
|
580
944
|
this.#motion.tick(dt / 1e3);
|
|
581
945
|
}
|