animejs 4.2.0-beta.0 → 4.2.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 +6 -1
- package/dist/bundles/anime.esm.js +448 -260
- package/dist/bundles/anime.esm.min.js +1 -1
- package/dist/bundles/anime.umd.js +449 -261
- package/dist/bundles/anime.umd.min.js +1 -1
- package/dist/modules/animatable/animatable.cjs +2 -2
- package/dist/modules/animatable/animatable.js +1 -1
- package/dist/modules/animation/animation.cjs +21 -14
- package/dist/modules/animation/animation.d.ts +0 -2
- package/dist/modules/animation/animation.js +20 -13
- package/dist/modules/core/consts.cjs +6 -1
- package/dist/modules/core/consts.d.ts +2 -0
- package/dist/modules/core/consts.js +5 -2
- package/dist/modules/core/globals.cjs +1 -0
- package/dist/modules/core/globals.js +1 -0
- package/dist/modules/core/render.cjs +3 -1
- package/dist/modules/core/render.js +3 -1
- package/dist/modules/core/styles.cjs +7 -7
- package/dist/modules/core/styles.js +9 -9
- package/dist/modules/core/values.cjs +16 -5
- package/dist/modules/core/values.js +18 -7
- package/dist/modules/draggable/draggable.cjs +16 -16
- package/dist/modules/draggable/draggable.d.ts +1 -1
- package/dist/modules/draggable/draggable.js +11 -11
- package/dist/modules/easings/{cubic-bezier.cjs → cubic-bezier/index.cjs} +3 -3
- package/dist/modules/easings/{cubic-bezier.d.ts → cubic-bezier/index.d.ts} +1 -1
- package/dist/modules/easings/{cubic-bezier.js → cubic-bezier/index.js} +3 -3
- package/dist/modules/easings/eases/index.cjs +14 -0
- package/dist/modules/easings/eases/index.d.ts +1 -0
- package/dist/modules/{spring → easings/eases}/index.js +2 -2
- package/dist/modules/easings/{eases.cjs → eases/parser.cjs} +68 -26
- package/dist/modules/easings/{eases.d.ts → eases/parser.d.ts} +31 -17
- package/dist/modules/easings/{eases.js → eases/parser.js} +59 -20
- package/dist/modules/easings/index.cjs +14 -12
- package/dist/modules/easings/index.d.ts +6 -6
- package/dist/modules/easings/index.js +6 -6
- package/dist/modules/easings/{irregular.cjs → irregular/index.cjs} +4 -4
- package/dist/modules/easings/{irregular.d.ts → irregular/index.d.ts} +1 -1
- package/dist/modules/easings/{irregular.js → irregular/index.js} +3 -3
- package/dist/modules/easings/{linear.cjs → linear/index.cjs} +3 -3
- package/dist/modules/easings/{linear.d.ts → linear/index.d.ts} +1 -1
- package/dist/modules/easings/{linear.js → linear/index.js} +3 -3
- package/dist/modules/easings/spring/index.cjs +255 -0
- package/dist/modules/{spring/spring.d.ts → easings/spring/index.d.ts} +21 -5
- package/dist/modules/easings/spring/index.js +251 -0
- package/dist/modules/easings/{steps.cjs → steps/index.cjs} +2 -2
- package/dist/modules/easings/{steps.d.ts → steps/index.d.ts} +1 -1
- package/dist/modules/easings/{steps.js → steps/index.js} +2 -2
- package/dist/modules/events/scroll.cjs +10 -6
- package/dist/modules/events/scroll.d.ts +2 -0
- package/dist/modules/events/scroll.js +9 -5
- package/dist/modules/index.cjs +14 -15
- package/dist/modules/index.d.ts +0 -1
- package/dist/modules/index.js +6 -7
- package/dist/modules/timeline/timeline.cjs +2 -2
- package/dist/modules/timeline/timeline.js +1 -1
- package/dist/modules/types/index.d.ts +30 -13
- package/dist/modules/utils/stagger.cjs +3 -3
- package/dist/modules/utils/stagger.js +2 -2
- package/dist/modules/waapi/composition.cjs +10 -4
- package/dist/modules/waapi/composition.d.ts +1 -1
- package/dist/modules/waapi/composition.js +10 -4
- package/dist/modules/waapi/waapi.cjs +50 -31
- package/dist/modules/waapi/waapi.d.ts +4 -2
- package/dist/modules/waapi/waapi.js +51 -32
- package/package.json +46 -10
- package/dist/modules/easings/parser.cjs +0 -59
- package/dist/modules/easings/parser.d.ts +0 -21
- package/dist/modules/easings/parser.js +0 -55
- package/dist/modules/spring/index.cjs +0 -15
- package/dist/modules/spring/index.d.ts +0 -1
- package/dist/modules/spring/spring.cjs +0 -133
- package/dist/modules/spring/spring.js +0 -130
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* @copyright 2025 - Julian Garnier
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
export {
|
|
9
|
-
export {
|
|
10
|
-
export {
|
|
11
|
-
export {
|
|
12
|
-
export {
|
|
13
|
-
export { eases } from './eases.js';
|
|
8
|
+
export { cubicBezier } from './cubic-bezier/index.js';
|
|
9
|
+
export { steps } from './steps/index.js';
|
|
10
|
+
export { linear } from './linear/index.js';
|
|
11
|
+
export { irregular } from './irregular/index.js';
|
|
12
|
+
export { Spring, createSpring, spring } from './spring/index.js';
|
|
13
|
+
export { eases } from './eases/parser.js';
|
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
|
-
var helpers = require('
|
|
11
|
-
var
|
|
10
|
+
var helpers = require('../../core/helpers.cjs');
|
|
11
|
+
var index = require('../linear/index.cjs');
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @import {
|
|
15
15
|
* EasingFunction,
|
|
16
|
-
* } from '
|
|
16
|
+
* } from '../../types/index.js'
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -35,7 +35,7 @@ const irregular = (length = 10, randomness = 1) => {
|
|
|
35
35
|
values.push(helpers.clamp(randomValue, previousValue, 1));
|
|
36
36
|
}
|
|
37
37
|
values.push(1);
|
|
38
|
-
return
|
|
38
|
+
return index.linear(...values);
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
exports.irregular = irregular;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export function irregular(length?: number, randomness?: number): EasingFunction;
|
|
2
|
-
import type { EasingFunction } from '
|
|
2
|
+
import type { EasingFunction } from '../../types/index.js';
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* @copyright 2025 - Julian Garnier
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { clamp } from '
|
|
9
|
-
import { linear } from '
|
|
8
|
+
import { clamp } from '../../core/helpers.js';
|
|
9
|
+
import { linear } from '../linear/index.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @import {
|
|
13
13
|
* EasingFunction,
|
|
14
|
-
* } from '
|
|
14
|
+
* } from '../../types/index.js'
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
|
-
var helpers = require('
|
|
11
|
-
var none = require('
|
|
10
|
+
var helpers = require('../../core/helpers.cjs');
|
|
11
|
+
var none = require('../none.cjs');
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @import {
|
|
15
15
|
* EasingFunction,
|
|
16
|
-
* } from '
|
|
16
|
+
* } from '../../types/index.js'
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export function linear(...args: (string | number)[]): EasingFunction;
|
|
2
|
-
import type { EasingFunction } from '
|
|
2
|
+
import type { EasingFunction } from '../../types/index.js';
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* @copyright 2025 - Julian Garnier
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { isStr, parseNumber, isUnd } from '
|
|
9
|
-
import { none } from '
|
|
8
|
+
import { isStr, parseNumber, isUnd } from '../../core/helpers.js';
|
|
9
|
+
import { none } from '../none.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @import {
|
|
13
13
|
* EasingFunction,
|
|
14
|
-
* } from '
|
|
14
|
+
* } from '../../types/index.js'
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anime.js - easings - CJS
|
|
3
|
+
* @version v4.2.0
|
|
4
|
+
* @license MIT
|
|
5
|
+
* @copyright 2025 - Julian Garnier
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
var consts = require('../../core/consts.cjs');
|
|
11
|
+
var globals = require('../../core/globals.cjs');
|
|
12
|
+
var helpers = require('../../core/helpers.cjs');
|
|
13
|
+
var values = require('../../core/values.cjs');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @import {
|
|
17
|
+
* JSAnimation,
|
|
18
|
+
* } from '../../animation/animation.js'
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @import {
|
|
23
|
+
* EasingFunction,
|
|
24
|
+
* SpringParams,
|
|
25
|
+
* Callback,
|
|
26
|
+
* } from '../../types/index.js'
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* Spring easing solver adapted from https://webkit.org/demos/spring/spring.js
|
|
31
|
+
* (c) 2016 Webkit - Apple Inc
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
const maxSpringParamValue = consts.K * 10;
|
|
35
|
+
|
|
36
|
+
class Spring {
|
|
37
|
+
/**
|
|
38
|
+
* @param {SpringParams} [parameters]
|
|
39
|
+
*/
|
|
40
|
+
constructor(parameters = {}) {
|
|
41
|
+
const hasBounceOrDuration = !helpers.isUnd(parameters.bounce) || !helpers.isUnd(parameters.duration);
|
|
42
|
+
this.timeStep = .02; // Interval fed to the solver to calculate duration
|
|
43
|
+
this.restThreshold = .0005; // Values below this threshold are considered resting position
|
|
44
|
+
this.restDuration = 200; // Duration in ms used to check if the spring is resting after reaching restThreshold
|
|
45
|
+
this.maxDuration = 60000; // The maximum allowed spring duration in ms (default 1 min)
|
|
46
|
+
this.maxRestSteps = this.restDuration / this.timeStep / consts.K; // How many steps allowed after reaching restThreshold before stopping the duration calculation
|
|
47
|
+
this.maxIterations = this.maxDuration / this.timeStep / consts.K; // Calculate the maximum iterations allowed based on maxDuration
|
|
48
|
+
this.bn = helpers.clamp(values.setValue(parameters.bounce, .5), -1, 1); // The bounce percentage between -1 and 1.
|
|
49
|
+
this.pd = helpers.clamp(values.setValue(parameters.duration, 628), 10 * globals.globals.timeScale, maxSpringParamValue * globals.globals.timeScale); // The perceived duration
|
|
50
|
+
this.m = helpers.clamp(values.setValue(parameters.mass, 1), 1, maxSpringParamValue);
|
|
51
|
+
this.s = helpers.clamp(values.setValue(parameters.stiffness, 100), consts.minValue, maxSpringParamValue);
|
|
52
|
+
this.d = helpers.clamp(values.setValue(parameters.damping, 10), consts.minValue, maxSpringParamValue);
|
|
53
|
+
this.v = helpers.clamp(values.setValue(parameters.velocity, 0), -maxSpringParamValue, maxSpringParamValue);
|
|
54
|
+
this.w0 = 0;
|
|
55
|
+
this.zeta = 0;
|
|
56
|
+
this.wd = 0;
|
|
57
|
+
this.b = 0;
|
|
58
|
+
this.completed = false;
|
|
59
|
+
this.solverDuration = 0;
|
|
60
|
+
this.settlingDuration = 0;
|
|
61
|
+
/** @type {JSAnimation} */
|
|
62
|
+
this.parent = null;
|
|
63
|
+
/** @type {Callback<JSAnimation>} */
|
|
64
|
+
this.onComplete = parameters.onComplete || consts.noop;
|
|
65
|
+
if (hasBounceOrDuration) this.calculateSDFromBD();
|
|
66
|
+
this.compute();
|
|
67
|
+
/** @type {EasingFunction} */
|
|
68
|
+
this.ease = t => {
|
|
69
|
+
const currentTime = t * this.settlingDuration;
|
|
70
|
+
const completed = this.completed;
|
|
71
|
+
const perceivedTime = this.pd;
|
|
72
|
+
if (currentTime >= perceivedTime && !completed) {
|
|
73
|
+
this.completed = true;
|
|
74
|
+
this.onComplete(this.parent);
|
|
75
|
+
}
|
|
76
|
+
if (currentTime < perceivedTime && completed) {
|
|
77
|
+
this.completed = false;
|
|
78
|
+
}
|
|
79
|
+
return t === 0 || t === 1 ? t : this.solve(t * this.solverDuration);
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** @type {EasingFunction} */
|
|
84
|
+
solve(time) {
|
|
85
|
+
const { zeta, w0, wd, b } = this;
|
|
86
|
+
let t = time;
|
|
87
|
+
if (zeta < 1) {
|
|
88
|
+
// Underdamped
|
|
89
|
+
t = helpers.exp(-t * zeta * w0) * (1 * helpers.cos(wd * t) + b * helpers.sin(wd * t));
|
|
90
|
+
} else if (zeta === 1) {
|
|
91
|
+
// Critically damped
|
|
92
|
+
t = (1 + b * t) * helpers.exp(-t * w0);
|
|
93
|
+
} else {
|
|
94
|
+
// Overdamped
|
|
95
|
+
// Using exponential instead of cosh and sinh functions to prevent Infinity
|
|
96
|
+
// Original exp(-zeta * w0 * t) * (cosh(wd * t) + b * sinh(wd * t))
|
|
97
|
+
t = ((1 + b) * helpers.exp((-zeta * w0 + wd) * t) + (1 - b) * helpers.exp((-zeta * w0 - wd) * t)) / 2;
|
|
98
|
+
}
|
|
99
|
+
return 1 - t;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
calculateSDFromBD() {
|
|
103
|
+
// Apple's SwiftUI perceived spring duration implementation https://developer.apple.com/videos/play/wwdc2023/10158/?time=1010
|
|
104
|
+
// Equations taken from Kevin Grajeda's article https://www.kvin.me/posts/effortless-ui-spring-animations
|
|
105
|
+
const pds = globals.globals.timeScale === 1 ? this.pd / consts.K : this.pd;
|
|
106
|
+
// Mass and velocity should be set to their default values
|
|
107
|
+
this.m = 1;
|
|
108
|
+
this.v = 0;
|
|
109
|
+
// Stiffness = (2π ÷ perceptualDuration)²
|
|
110
|
+
this.s = helpers.pow((2 * helpers.PI) / pds, 2);
|
|
111
|
+
if (this.bn >= 0) {
|
|
112
|
+
// For bounce ≥ 0 (critically damped to underdamped)
|
|
113
|
+
// damping = ((1 - bounce) × 4π) ÷ perceptualDuration
|
|
114
|
+
this.d = ((1 - this.bn) * 4 * helpers.PI) / pds;
|
|
115
|
+
} else {
|
|
116
|
+
// For bounce < 0 (overdamped)
|
|
117
|
+
// damping = 4π ÷ (perceptualDuration × (1 + bounce))
|
|
118
|
+
// Note: (1 + bounce) is positive since bounce is negative
|
|
119
|
+
this.d = (4 * helpers.PI) / (pds * (1 + this.bn));
|
|
120
|
+
}
|
|
121
|
+
this.s = helpers.round(helpers.clamp(this.s, consts.minValue, maxSpringParamValue), 3);
|
|
122
|
+
this.d = helpers.round(helpers.clamp(this.d, consts.minValue, 300), 3); // Clamping to 300 is needed to prevent insane values in the solver
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
calculateBDFromSD() {
|
|
126
|
+
// Calculate perceived duration and bounce from stiffness and damping
|
|
127
|
+
// Note: We assumes m = 1 and v = 0 for these calculations
|
|
128
|
+
const pds = (2 * helpers.PI) / helpers.sqrt(this.s);
|
|
129
|
+
this.pd = pds * (globals.globals.timeScale === 1 ? consts.K : 1);
|
|
130
|
+
const zeta = this.d / (2 * helpers.sqrt(this.s));
|
|
131
|
+
if (zeta <= 1) {
|
|
132
|
+
// Critically damped to underdamped
|
|
133
|
+
this.bn = 1 - (this.d * pds) / (4 * helpers.PI);
|
|
134
|
+
} else {
|
|
135
|
+
// Overdamped
|
|
136
|
+
this.bn = (4 * helpers.PI) / (this.d * pds) - 1;
|
|
137
|
+
}
|
|
138
|
+
this.bn = helpers.round(helpers.clamp(this.bn, -1, 1), 3);
|
|
139
|
+
this.pd = helpers.round(helpers.clamp(this.pd, 10 * globals.globals.timeScale, maxSpringParamValue * globals.globals.timeScale), 3);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
compute() {
|
|
143
|
+
const { maxRestSteps, maxIterations, restThreshold, timeStep, m, d, s, v } = this;
|
|
144
|
+
const w0 = this.w0 = helpers.clamp(helpers.sqrt(s / m), consts.minValue, consts.K);
|
|
145
|
+
const bouncedZeta = this.zeta = d / (2 * helpers.sqrt(s * m));
|
|
146
|
+
// Calculate wd based on damping type
|
|
147
|
+
if (bouncedZeta < 1) {
|
|
148
|
+
// Underdamped
|
|
149
|
+
this.wd = w0 * helpers.sqrt(1 - bouncedZeta * bouncedZeta);
|
|
150
|
+
this.b = (bouncedZeta * w0 + -v) / this.wd;
|
|
151
|
+
} else if (bouncedZeta === 1) {
|
|
152
|
+
// Critically damped
|
|
153
|
+
this.wd = 0;
|
|
154
|
+
this.b = -v + w0;
|
|
155
|
+
} else {
|
|
156
|
+
// Overdamped
|
|
157
|
+
this.wd = w0 * helpers.sqrt(bouncedZeta * bouncedZeta - 1);
|
|
158
|
+
this.b = (bouncedZeta * w0 + -v) / this.wd;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let solverTime = 0;
|
|
162
|
+
let restSteps = 0;
|
|
163
|
+
let iterations = 0;
|
|
164
|
+
while (restSteps <= maxRestSteps && iterations <= maxIterations) {
|
|
165
|
+
if (helpers.abs(1 - this.solve(solverTime)) < restThreshold) {
|
|
166
|
+
restSteps++;
|
|
167
|
+
} else {
|
|
168
|
+
restSteps = 0;
|
|
169
|
+
}
|
|
170
|
+
this.solverDuration = solverTime;
|
|
171
|
+
solverTime += timeStep;
|
|
172
|
+
iterations++;
|
|
173
|
+
}
|
|
174
|
+
this.settlingDuration = helpers.round(this.solverDuration * consts.K, 0) * globals.globals.timeScale;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
get bounce() {
|
|
178
|
+
return this.bn;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
set bounce(v) {
|
|
182
|
+
this.bn = helpers.clamp(values.setValue(v, 1), -1, 1);
|
|
183
|
+
this.calculateSDFromBD();
|
|
184
|
+
this.compute();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
get duration() {
|
|
188
|
+
return this.pd;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
set duration(v) {
|
|
192
|
+
this.pd = helpers.clamp(values.setValue(v, 1), 10 * globals.globals.timeScale, maxSpringParamValue * globals.globals.timeScale);
|
|
193
|
+
this.calculateSDFromBD();
|
|
194
|
+
this.compute();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
get stiffness() {
|
|
198
|
+
return this.s;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
set stiffness(v) {
|
|
202
|
+
this.s = helpers.clamp(values.setValue(v, 100), consts.minValue, maxSpringParamValue);
|
|
203
|
+
this.calculateBDFromSD();
|
|
204
|
+
this.compute();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
get damping() {
|
|
208
|
+
return this.d;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
set damping(v) {
|
|
212
|
+
this.d = helpers.clamp(values.setValue(v, 10), consts.minValue, maxSpringParamValue);
|
|
213
|
+
this.calculateBDFromSD();
|
|
214
|
+
this.compute();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
get mass() {
|
|
218
|
+
return this.m;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
set mass(v) {
|
|
222
|
+
this.m = helpers.clamp(values.setValue(v, 1), 1, maxSpringParamValue);
|
|
223
|
+
this.compute();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
get velocity() {
|
|
227
|
+
return this.v;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
set velocity(v) {
|
|
231
|
+
this.v = helpers.clamp(values.setValue(v, 0), -maxSpringParamValue, maxSpringParamValue);
|
|
232
|
+
this.compute();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @param {SpringParams} [parameters]
|
|
238
|
+
* @returns {Spring}
|
|
239
|
+
*/
|
|
240
|
+
const spring = (parameters) => new Spring(parameters);
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* @deprecated createSpring() is deprecated use spring() instead
|
|
244
|
+
*
|
|
245
|
+
* @param {SpringParams} [parameters]
|
|
246
|
+
* @returns {Spring}
|
|
247
|
+
*/
|
|
248
|
+
const createSpring = (parameters) => {
|
|
249
|
+
console.warn('createSpring() is deprecated use spring() instead');
|
|
250
|
+
return new Spring(parameters);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
exports.Spring = Spring;
|
|
254
|
+
exports.createSpring = createSpring;
|
|
255
|
+
exports.spring = spring;
|
|
@@ -9,6 +9,8 @@ export class Spring {
|
|
|
9
9
|
maxDuration: number;
|
|
10
10
|
maxRestSteps: number;
|
|
11
11
|
maxIterations: number;
|
|
12
|
+
bn: number;
|
|
13
|
+
pd: number;
|
|
12
14
|
m: number;
|
|
13
15
|
s: number;
|
|
14
16
|
d: number;
|
|
@@ -17,21 +19,35 @@ export class Spring {
|
|
|
17
19
|
zeta: number;
|
|
18
20
|
wd: number;
|
|
19
21
|
b: number;
|
|
22
|
+
completed: boolean;
|
|
20
23
|
solverDuration: number;
|
|
21
|
-
|
|
24
|
+
settlingDuration: number;
|
|
25
|
+
/** @type {JSAnimation} */
|
|
26
|
+
parent: JSAnimation;
|
|
27
|
+
/** @type {Callback<JSAnimation>} */
|
|
28
|
+
onComplete: Callback<JSAnimation>;
|
|
22
29
|
/** @type {EasingFunction} */
|
|
23
30
|
ease: EasingFunction;
|
|
24
31
|
solve(time: number): number;
|
|
32
|
+
calculateSDFromBD(): void;
|
|
33
|
+
calculateBDFromSD(): void;
|
|
25
34
|
compute(): void;
|
|
26
|
-
set
|
|
27
|
-
get
|
|
35
|
+
set bounce(v: number);
|
|
36
|
+
get bounce(): number;
|
|
37
|
+
set duration(v: number);
|
|
38
|
+
get duration(): number;
|
|
28
39
|
set stiffness(v: number);
|
|
29
40
|
get stiffness(): number;
|
|
30
41
|
set damping(v: number);
|
|
31
42
|
get damping(): number;
|
|
43
|
+
set mass(v: number);
|
|
44
|
+
get mass(): number;
|
|
32
45
|
set velocity(v: number);
|
|
33
46
|
get velocity(): number;
|
|
34
47
|
}
|
|
48
|
+
export function spring(parameters?: SpringParams): Spring;
|
|
35
49
|
export function createSpring(parameters?: SpringParams): Spring;
|
|
36
|
-
import type {
|
|
37
|
-
import type {
|
|
50
|
+
import type { JSAnimation } from '../../animation/animation.js';
|
|
51
|
+
import type { Callback } from '../../types/index.js';
|
|
52
|
+
import type { EasingFunction } from '../../types/index.js';
|
|
53
|
+
import type { SpringParams } from '../../types/index.js';
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anime.js - easings - ESM
|
|
3
|
+
* @version v4.2.0
|
|
4
|
+
* @license MIT
|
|
5
|
+
* @copyright 2025 - Julian Garnier
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { K, minValue, noop } from '../../core/consts.js';
|
|
9
|
+
import { globals } from '../../core/globals.js';
|
|
10
|
+
import { isUnd, clamp, pow, PI, round, sqrt, abs, exp, cos, sin } from '../../core/helpers.js';
|
|
11
|
+
import { setValue } from '../../core/values.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @import {
|
|
15
|
+
* JSAnimation,
|
|
16
|
+
* } from '../../animation/animation.js'
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @import {
|
|
21
|
+
* EasingFunction,
|
|
22
|
+
* SpringParams,
|
|
23
|
+
* Callback,
|
|
24
|
+
* } from '../../types/index.js'
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/*
|
|
28
|
+
* Spring easing solver adapted from https://webkit.org/demos/spring/spring.js
|
|
29
|
+
* (c) 2016 Webkit - Apple Inc
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
const maxSpringParamValue = K * 10;
|
|
33
|
+
|
|
34
|
+
class Spring {
|
|
35
|
+
/**
|
|
36
|
+
* @param {SpringParams} [parameters]
|
|
37
|
+
*/
|
|
38
|
+
constructor(parameters = {}) {
|
|
39
|
+
const hasBounceOrDuration = !isUnd(parameters.bounce) || !isUnd(parameters.duration);
|
|
40
|
+
this.timeStep = .02; // Interval fed to the solver to calculate duration
|
|
41
|
+
this.restThreshold = .0005; // Values below this threshold are considered resting position
|
|
42
|
+
this.restDuration = 200; // Duration in ms used to check if the spring is resting after reaching restThreshold
|
|
43
|
+
this.maxDuration = 60000; // The maximum allowed spring duration in ms (default 1 min)
|
|
44
|
+
this.maxRestSteps = this.restDuration / this.timeStep / K; // How many steps allowed after reaching restThreshold before stopping the duration calculation
|
|
45
|
+
this.maxIterations = this.maxDuration / this.timeStep / K; // Calculate the maximum iterations allowed based on maxDuration
|
|
46
|
+
this.bn = clamp(setValue(parameters.bounce, .5), -1, 1); // The bounce percentage between -1 and 1.
|
|
47
|
+
this.pd = clamp(setValue(parameters.duration, 628), 10 * globals.timeScale, maxSpringParamValue * globals.timeScale); // The perceived duration
|
|
48
|
+
this.m = clamp(setValue(parameters.mass, 1), 1, maxSpringParamValue);
|
|
49
|
+
this.s = clamp(setValue(parameters.stiffness, 100), minValue, maxSpringParamValue);
|
|
50
|
+
this.d = clamp(setValue(parameters.damping, 10), minValue, maxSpringParamValue);
|
|
51
|
+
this.v = clamp(setValue(parameters.velocity, 0), -maxSpringParamValue, maxSpringParamValue);
|
|
52
|
+
this.w0 = 0;
|
|
53
|
+
this.zeta = 0;
|
|
54
|
+
this.wd = 0;
|
|
55
|
+
this.b = 0;
|
|
56
|
+
this.completed = false;
|
|
57
|
+
this.solverDuration = 0;
|
|
58
|
+
this.settlingDuration = 0;
|
|
59
|
+
/** @type {JSAnimation} */
|
|
60
|
+
this.parent = null;
|
|
61
|
+
/** @type {Callback<JSAnimation>} */
|
|
62
|
+
this.onComplete = parameters.onComplete || noop;
|
|
63
|
+
if (hasBounceOrDuration) this.calculateSDFromBD();
|
|
64
|
+
this.compute();
|
|
65
|
+
/** @type {EasingFunction} */
|
|
66
|
+
this.ease = t => {
|
|
67
|
+
const currentTime = t * this.settlingDuration;
|
|
68
|
+
const completed = this.completed;
|
|
69
|
+
const perceivedTime = this.pd;
|
|
70
|
+
if (currentTime >= perceivedTime && !completed) {
|
|
71
|
+
this.completed = true;
|
|
72
|
+
this.onComplete(this.parent);
|
|
73
|
+
}
|
|
74
|
+
if (currentTime < perceivedTime && completed) {
|
|
75
|
+
this.completed = false;
|
|
76
|
+
}
|
|
77
|
+
return t === 0 || t === 1 ? t : this.solve(t * this.solverDuration);
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** @type {EasingFunction} */
|
|
82
|
+
solve(time) {
|
|
83
|
+
const { zeta, w0, wd, b } = this;
|
|
84
|
+
let t = time;
|
|
85
|
+
if (zeta < 1) {
|
|
86
|
+
// Underdamped
|
|
87
|
+
t = exp(-t * zeta * w0) * (1 * cos(wd * t) + b * sin(wd * t));
|
|
88
|
+
} else if (zeta === 1) {
|
|
89
|
+
// Critically damped
|
|
90
|
+
t = (1 + b * t) * exp(-t * w0);
|
|
91
|
+
} else {
|
|
92
|
+
// Overdamped
|
|
93
|
+
// Using exponential instead of cosh and sinh functions to prevent Infinity
|
|
94
|
+
// Original exp(-zeta * w0 * t) * (cosh(wd * t) + b * sinh(wd * t))
|
|
95
|
+
t = ((1 + b) * exp((-zeta * w0 + wd) * t) + (1 - b) * exp((-zeta * w0 - wd) * t)) / 2;
|
|
96
|
+
}
|
|
97
|
+
return 1 - t;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
calculateSDFromBD() {
|
|
101
|
+
// Apple's SwiftUI perceived spring duration implementation https://developer.apple.com/videos/play/wwdc2023/10158/?time=1010
|
|
102
|
+
// Equations taken from Kevin Grajeda's article https://www.kvin.me/posts/effortless-ui-spring-animations
|
|
103
|
+
const pds = globals.timeScale === 1 ? this.pd / K : this.pd;
|
|
104
|
+
// Mass and velocity should be set to their default values
|
|
105
|
+
this.m = 1;
|
|
106
|
+
this.v = 0;
|
|
107
|
+
// Stiffness = (2π ÷ perceptualDuration)²
|
|
108
|
+
this.s = pow((2 * PI) / pds, 2);
|
|
109
|
+
if (this.bn >= 0) {
|
|
110
|
+
// For bounce ≥ 0 (critically damped to underdamped)
|
|
111
|
+
// damping = ((1 - bounce) × 4π) ÷ perceptualDuration
|
|
112
|
+
this.d = ((1 - this.bn) * 4 * PI) / pds;
|
|
113
|
+
} else {
|
|
114
|
+
// For bounce < 0 (overdamped)
|
|
115
|
+
// damping = 4π ÷ (perceptualDuration × (1 + bounce))
|
|
116
|
+
// Note: (1 + bounce) is positive since bounce is negative
|
|
117
|
+
this.d = (4 * PI) / (pds * (1 + this.bn));
|
|
118
|
+
}
|
|
119
|
+
this.s = round(clamp(this.s, minValue, maxSpringParamValue), 3);
|
|
120
|
+
this.d = round(clamp(this.d, minValue, 300), 3); // Clamping to 300 is needed to prevent insane values in the solver
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
calculateBDFromSD() {
|
|
124
|
+
// Calculate perceived duration and bounce from stiffness and damping
|
|
125
|
+
// Note: We assumes m = 1 and v = 0 for these calculations
|
|
126
|
+
const pds = (2 * PI) / sqrt(this.s);
|
|
127
|
+
this.pd = pds * (globals.timeScale === 1 ? K : 1);
|
|
128
|
+
const zeta = this.d / (2 * sqrt(this.s));
|
|
129
|
+
if (zeta <= 1) {
|
|
130
|
+
// Critically damped to underdamped
|
|
131
|
+
this.bn = 1 - (this.d * pds) / (4 * PI);
|
|
132
|
+
} else {
|
|
133
|
+
// Overdamped
|
|
134
|
+
this.bn = (4 * PI) / (this.d * pds) - 1;
|
|
135
|
+
}
|
|
136
|
+
this.bn = round(clamp(this.bn, -1, 1), 3);
|
|
137
|
+
this.pd = round(clamp(this.pd, 10 * globals.timeScale, maxSpringParamValue * globals.timeScale), 3);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
compute() {
|
|
141
|
+
const { maxRestSteps, maxIterations, restThreshold, timeStep, m, d, s, v } = this;
|
|
142
|
+
const w0 = this.w0 = clamp(sqrt(s / m), minValue, K);
|
|
143
|
+
const bouncedZeta = this.zeta = d / (2 * sqrt(s * m));
|
|
144
|
+
// Calculate wd based on damping type
|
|
145
|
+
if (bouncedZeta < 1) {
|
|
146
|
+
// Underdamped
|
|
147
|
+
this.wd = w0 * sqrt(1 - bouncedZeta * bouncedZeta);
|
|
148
|
+
this.b = (bouncedZeta * w0 + -v) / this.wd;
|
|
149
|
+
} else if (bouncedZeta === 1) {
|
|
150
|
+
// Critically damped
|
|
151
|
+
this.wd = 0;
|
|
152
|
+
this.b = -v + w0;
|
|
153
|
+
} else {
|
|
154
|
+
// Overdamped
|
|
155
|
+
this.wd = w0 * sqrt(bouncedZeta * bouncedZeta - 1);
|
|
156
|
+
this.b = (bouncedZeta * w0 + -v) / this.wd;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let solverTime = 0;
|
|
160
|
+
let restSteps = 0;
|
|
161
|
+
let iterations = 0;
|
|
162
|
+
while (restSteps <= maxRestSteps && iterations <= maxIterations) {
|
|
163
|
+
if (abs(1 - this.solve(solverTime)) < restThreshold) {
|
|
164
|
+
restSteps++;
|
|
165
|
+
} else {
|
|
166
|
+
restSteps = 0;
|
|
167
|
+
}
|
|
168
|
+
this.solverDuration = solverTime;
|
|
169
|
+
solverTime += timeStep;
|
|
170
|
+
iterations++;
|
|
171
|
+
}
|
|
172
|
+
this.settlingDuration = round(this.solverDuration * K, 0) * globals.timeScale;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
get bounce() {
|
|
176
|
+
return this.bn;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
set bounce(v) {
|
|
180
|
+
this.bn = clamp(setValue(v, 1), -1, 1);
|
|
181
|
+
this.calculateSDFromBD();
|
|
182
|
+
this.compute();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
get duration() {
|
|
186
|
+
return this.pd;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
set duration(v) {
|
|
190
|
+
this.pd = clamp(setValue(v, 1), 10 * globals.timeScale, maxSpringParamValue * globals.timeScale);
|
|
191
|
+
this.calculateSDFromBD();
|
|
192
|
+
this.compute();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
get stiffness() {
|
|
196
|
+
return this.s;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
set stiffness(v) {
|
|
200
|
+
this.s = clamp(setValue(v, 100), minValue, maxSpringParamValue);
|
|
201
|
+
this.calculateBDFromSD();
|
|
202
|
+
this.compute();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
get damping() {
|
|
206
|
+
return this.d;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
set damping(v) {
|
|
210
|
+
this.d = clamp(setValue(v, 10), minValue, maxSpringParamValue);
|
|
211
|
+
this.calculateBDFromSD();
|
|
212
|
+
this.compute();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
get mass() {
|
|
216
|
+
return this.m;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
set mass(v) {
|
|
220
|
+
this.m = clamp(setValue(v, 1), 1, maxSpringParamValue);
|
|
221
|
+
this.compute();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
get velocity() {
|
|
225
|
+
return this.v;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
set velocity(v) {
|
|
229
|
+
this.v = clamp(setValue(v, 0), -maxSpringParamValue, maxSpringParamValue);
|
|
230
|
+
this.compute();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* @param {SpringParams} [parameters]
|
|
236
|
+
* @returns {Spring}
|
|
237
|
+
*/
|
|
238
|
+
const spring = (parameters) => new Spring(parameters);
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* @deprecated createSpring() is deprecated use spring() instead
|
|
242
|
+
*
|
|
243
|
+
* @param {SpringParams} [parameters]
|
|
244
|
+
* @returns {Spring}
|
|
245
|
+
*/
|
|
246
|
+
const createSpring = (parameters) => {
|
|
247
|
+
console.warn('createSpring() is deprecated use spring() instead');
|
|
248
|
+
return new Spring(parameters);
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
export { Spring, createSpring, spring };
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
|
-
var helpers = require('
|
|
10
|
+
var helpers = require('../../core/helpers.cjs');
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* @import {
|
|
14
14
|
* EasingFunction,
|
|
15
|
-
* } from '
|
|
15
|
+
* } from '../../types/index.js'
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export function steps(steps?: number, fromStart?: boolean): EasingFunction;
|
|
2
|
-
import type { EasingFunction } from '
|
|
2
|
+
import type { EasingFunction } from '../../types/index.js';
|