physics-animator 0.1.0 → 0.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.
Files changed (43) hide show
  1. package/dist/cjs/AnimationSequencer.js +156 -0
  2. package/dist/cjs/Animator.js +310 -0
  3. package/{src/Spring.ts → dist/cjs/Spring.js} +38 -80
  4. package/dist/cjs/index.js +19 -0
  5. package/dist/cjs/package.json +1 -0
  6. package/dist/cjs/react/index.js +19 -0
  7. package/dist/cjs/react/useAnimator.js +29 -0
  8. package/dist/cjs/react/useSpringState.js +16 -0
  9. package/dist/cjs/react/useSpringValue.js +59 -0
  10. package/dist/cjs/three/ThreeAnimator.js +453 -0
  11. package/dist/cjs/three/index.js +17 -0
  12. package/dist/esm/package.json +1 -0
  13. package/package.json +17 -10
  14. package/src/AnimationSequencer.ts +0 -193
  15. package/src/Animator.ts +0 -377
  16. package/src/index.ts +0 -3
  17. package/src/react/index.ts +0 -3
  18. package/src/react/useAnimator.ts +0 -45
  19. package/src/react/useSpringState.ts +0 -22
  20. package/src/react/useSpringValue.ts +0 -81
  21. package/src/three/ThreeAnimator.ts +0 -605
  22. package/src/three/index.ts +0 -1
  23. package/tsconfig.json +0 -14
  24. /package/dist/{AnimationSequencer.js → esm/AnimationSequencer.js} +0 -0
  25. /package/dist/{Animator.js → esm/Animator.js} +0 -0
  26. /package/dist/{Spring.js → esm/Spring.js} +0 -0
  27. /package/dist/{index.js → esm/index.js} +0 -0
  28. /package/dist/{react → esm/react}/index.js +0 -0
  29. /package/dist/{react → esm/react}/useAnimator.js +0 -0
  30. /package/dist/{react → esm/react}/useSpringState.js +0 -0
  31. /package/dist/{react → esm/react}/useSpringValue.js +0 -0
  32. /package/dist/{three → esm/three}/ThreeAnimator.js +0 -0
  33. /package/dist/{three → esm/three}/index.js +0 -0
  34. /package/dist/{AnimationSequencer.d.ts → types/AnimationSequencer.d.ts} +0 -0
  35. /package/dist/{Animator.d.ts → types/Animator.d.ts} +0 -0
  36. /package/dist/{Spring.d.ts → types/Spring.d.ts} +0 -0
  37. /package/dist/{index.d.ts → types/index.d.ts} +0 -0
  38. /package/dist/{react → types/react}/index.d.ts +0 -0
  39. /package/dist/{react → types/react}/useAnimator.d.ts +0 -0
  40. /package/dist/{react → types/react}/useSpringState.d.ts +0 -0
  41. /package/dist/{react → types/react}/useSpringValue.d.ts +0 -0
  42. /package/dist/{three → types/three}/ThreeAnimator.d.ts +0 -0
  43. /package/dist/{three → types/three}/index.d.ts +0 -0
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AnimationSequencer = void 0;
4
+ const event_signal_1 = require("@haxiomic/event-signal");
5
+ class AnimationSequencer {
6
+ constructor() {
7
+ this.timeoutHandles = [];
8
+ this.intervalHandles = [];
9
+ this.sequences = [];
10
+ /**
11
+ * Execute a serial sequence of steps, firing a callback at each step. We either wait for the onCompleteEvent to be fired, or we wait for maxWait milliseconds before moving on to the next step.
12
+ *
13
+ * @returns Sequence - a function that can be called to stop the sequence
14
+ */
15
+ this.runSequence = (steps) => {
16
+ let sequenceEvents = {
17
+ onStep: new event_signal_1.EventSignal(),
18
+ onComplete: new event_signal_1.EventSignal(),
19
+ onFinally: new event_signal_1.EventSignal(),
20
+ onError: new event_signal_1.EventSignal(),
21
+ };
22
+ let openListeners = new Set();
23
+ let timeoutHandles = new Array();
24
+ let stepIndex = 0;
25
+ const executeStep = (index) => {
26
+ try {
27
+ // check if we've reached the end of the sequence
28
+ if (index >= steps.length) {
29
+ sequenceEvents.onComplete.dispatch();
30
+ sequenceEvents.onFinally.dispatch({
31
+ complete: true,
32
+ stepIndex: steps.length - 1,
33
+ });
34
+ return;
35
+ }
36
+ let step = steps[index];
37
+ if (!step) {
38
+ throw new Error(`Step at index ${index} is undefined`);
39
+ }
40
+ sequenceEvents.onStep.dispatch(index);
41
+ let timeoutHandle = null;
42
+ let completeListener = null;
43
+ if (step.onCompleteEvent) {
44
+ let listener = step.onCompleteEvent.once(() => {
45
+ openListeners.delete(listener);
46
+ });
47
+ }
48
+ if (step.maxWait_ms) {
49
+ timeoutHandle = this.setTimeout(() => next(), step.maxWait_ms);
50
+ timeoutHandles.push(timeoutHandle);
51
+ }
52
+ if (!step.onCompleteEvent && !step.maxWait_ms) {
53
+ next();
54
+ }
55
+ let hasFinished = false;
56
+ function next() {
57
+ if (hasFinished)
58
+ return;
59
+ clearTimeout(timeoutHandle);
60
+ completeListener?.remove();
61
+ stepIndex++;
62
+ hasFinished = true;
63
+ executeStep(stepIndex);
64
+ }
65
+ let result = step.callback();
66
+ if (result['then']) {
67
+ result.then(() => {
68
+ // if no onCompleteEvent, then we can move on to the next step
69
+ if (!step.onCompleteEvent) {
70
+ next();
71
+ }
72
+ }).catch((error) => {
73
+ sequenceEvents.onError.dispatch(error);
74
+ stop();
75
+ });
76
+ }
77
+ }
78
+ catch (error) {
79
+ sequenceEvents.onError.dispatch(error);
80
+ stop();
81
+ }
82
+ };
83
+ let stopped = false;
84
+ function stop() {
85
+ if (stopped)
86
+ return;
87
+ for (let listener of openListeners) {
88
+ listener.remove();
89
+ }
90
+ for (let handle of timeoutHandles) {
91
+ clearTimeout(handle);
92
+ }
93
+ sequenceEvents.onFinally.dispatch({
94
+ complete: false,
95
+ stepIndex,
96
+ });
97
+ stopped = true;
98
+ }
99
+ // promise interface
100
+ let promise = new Promise((resolve, reject) => {
101
+ sequenceEvents.onComplete.once(() => resolve());
102
+ sequenceEvents.onFinally.once(() => resolve());
103
+ sequenceEvents.onError.once((error) => reject(error));
104
+ });
105
+ let sequence = {
106
+ stop,
107
+ events: sequenceEvents,
108
+ promise,
109
+ };
110
+ // track sequence
111
+ this.sequences.push(sequence);
112
+ sequenceEvents.onFinally.once(() => {
113
+ let index = this.sequences.indexOf(sequence);
114
+ this.sequences.splice(index, 1);
115
+ });
116
+ // start
117
+ executeStep(stepIndex);
118
+ return sequence;
119
+ };
120
+ this.registerSequence = (sequence) => {
121
+ this.sequences.push(sequence);
122
+ sequence.events.onFinally.once(() => {
123
+ let index = this.sequences.indexOf(sequence);
124
+ this.sequences.splice(index, 1);
125
+ });
126
+ };
127
+ this.setTimeout = (callback, delay) => {
128
+ let handle = window.setTimeout(callback, delay);
129
+ this.timeoutHandles.push(handle);
130
+ return handle;
131
+ };
132
+ this.setInterval = (callback, delay) => {
133
+ let handle = window.setInterval(callback, delay);
134
+ this.intervalHandles.push(handle);
135
+ return handle;
136
+ };
137
+ this.stopAllTimeouts = () => {
138
+ this.timeoutHandles.forEach(handle => clearTimeout(handle));
139
+ this.timeoutHandles = [];
140
+ };
141
+ this.stopAllIntervals = () => {
142
+ this.intervalHandles.forEach(handle => clearInterval(handle));
143
+ this.intervalHandles = [];
144
+ };
145
+ this.stopAllSequences = () => {
146
+ this.sequences.forEach(sequence => sequence.stop());
147
+ this.sequences = [];
148
+ };
149
+ this.stopAll = () => {
150
+ this.stopAllTimeouts();
151
+ this.stopAllIntervals();
152
+ this.stopAllSequences();
153
+ };
154
+ }
155
+ }
156
+ exports.AnimationSequencer = AnimationSequencer;
@@ -0,0 +1,310 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Tween = exports.Animator = void 0;
4
+ const event_signal_1 = require("@haxiomic/event-signal");
5
+ const Spring_js_1 = require("./Spring.js");
6
+ var AnimationType;
7
+ (function (AnimationType) {
8
+ AnimationType[AnimationType["Spring"] = 0] = "Spring";
9
+ AnimationType[AnimationType["Tween"] = 1] = "Tween";
10
+ })(AnimationType || (AnimationType = {}));
11
+ /**
12
+ * Physically based animation of numeric properties of objects
13
+ *
14
+ * Designed to avoid discontinuities for smooth animation in all conditions
15
+ */
16
+ class Animator {
17
+ constructor(onBeforeStep, onAfterStep) {
18
+ this.onBeforeStep = new event_signal_1.EventSignal();
19
+ this.onAfterStep = new event_signal_1.EventSignal();
20
+ this._onAnimationComplete = new event_signal_1.EventSignal();
21
+ this._onObjectAnimationsComplete = new event_signal_1.EventSignal();
22
+ this.animations = new Map();
23
+ this._springState = { x: 0, targetX: 0, v: 0 };
24
+ this.t_last = -1;
25
+ this._currentLoopControl = null;
26
+ if (onBeforeStep) {
27
+ this.onBeforeStep.addListener(e => onBeforeStep(e.dt_s));
28
+ }
29
+ if (onAfterStep) {
30
+ this.onAfterStep.addListener(e => onAfterStep(e.dt_s));
31
+ }
32
+ }
33
+ springTo(object, field, target, params = { duration_s: 0.5 }) {
34
+ if (params != null) {
35
+ let spring = this.getAnimationOrCreate(object, field, AnimationType.Spring);
36
+ // update the target and parameters
37
+ spring.type = AnimationType.Spring;
38
+ spring.target = target;
39
+ spring.springParams = Spring_js_1.Spring.getPhysicsParameters(params);
40
+ spring.step = null;
41
+ }
42
+ else {
43
+ this.setTo(object, field, target);
44
+ }
45
+ }
46
+ customTweenTo(object, field, target, duration_s, step) {
47
+ let animation = this.getAnimationOrCreate(object, field, AnimationType.Tween);
48
+ animation.type = AnimationType.Tween;
49
+ animation.target = target;
50
+ animation.tweenParams = {
51
+ x0: object[field],
52
+ t0_ms: performance.now(),
53
+ duration_s: duration_s,
54
+ };
55
+ animation.step = step;
56
+ }
57
+ linearTo(object, field, target, duration_s) {
58
+ this.customTweenTo(object, field, target, duration_s, Tween.linearStep);
59
+ }
60
+ easeInOutTo(object, field, target, duration_s) {
61
+ this.customTweenTo(object, field, target, duration_s, Tween.easeInOutStep);
62
+ }
63
+ easeInTo(object, field, target, duration_s) {
64
+ this.customTweenTo(object, field, target, duration_s, Tween.easeInStep);
65
+ }
66
+ easeOutTo(object, field, target, duration_s) {
67
+ this.customTweenTo(object, field, target, duration_s, Tween.easeOutStep);
68
+ }
69
+ /**
70
+ * Remove animation from the object and set the field to the target value
71
+ */
72
+ setTo(object, field, target) {
73
+ this.remove(object, field);
74
+ object[field] = target;
75
+ }
76
+ onComplete(object, field, callback) {
77
+ return this._onAnimationComplete.addListener(e => {
78
+ if (e.object === object && e.field === field) {
79
+ callback(object, field);
80
+ }
81
+ });
82
+ }
83
+ onAllComplete(object, callback, once) {
84
+ let listener = this._onObjectAnimationsComplete.addListener(e => {
85
+ if (e.object === object) {
86
+ callback(object);
87
+ if (once) {
88
+ listener.remove();
89
+ }
90
+ }
91
+ });
92
+ return listener;
93
+ }
94
+ step(dt_s) {
95
+ if (this.onBeforeStep.hasListeners()) {
96
+ this.onBeforeStep.dispatch({ dt_s });
97
+ }
98
+ let springState = this._springState;
99
+ // step all animations
100
+ this.animations.forEach((objectAnims, object) => {
101
+ objectAnims.forEach((animation, field) => {
102
+ switch (animation.type) {
103
+ case AnimationType.Spring:
104
+ {
105
+ // step the spring
106
+ springState.x = object[field];
107
+ springState.targetX = animation.target;
108
+ springState.v = animation.velocity;
109
+ if (animation.springParams != null) {
110
+ Spring_js_1.Spring.stepSpring(dt_s, springState, animation.springParams);
111
+ }
112
+ else {
113
+ // instant transition: set to the target
114
+ springState.x = springState.targetX;
115
+ springState.v = 0;
116
+ }
117
+ // update the object
118
+ object[field] = springState.x;
119
+ animation.velocity = springState.v;
120
+ // remove the spring if it's close enough to the target and velocity is close to 0
121
+ if (Math.abs(springState.x - springState.targetX) < 0.0001 && Math.abs(springState.v) < 0.0001) {
122
+ object[field] = animation.target;
123
+ objectAnims.delete(field);
124
+ this._onAnimationComplete.dispatch({ object, field });
125
+ }
126
+ }
127
+ break;
128
+ case AnimationType.Tween: {
129
+ // step the tween
130
+ let x = object[field];
131
+ animation.step(object, field, animation.target, animation.tweenParams, dt_s);
132
+ let x_new = object[field];
133
+ animation.velocity = (x_new - x) / dt_s;
134
+ // remove the tween if it's complete
135
+ let deltaTime_s = (performance.now() - animation.tweenParams.t0_ms) / 1000;
136
+ if (deltaTime_s >= animation.tweenParams.duration_s) {
137
+ object[field] = animation.target;
138
+ objectAnims.delete(field);
139
+ this._onAnimationComplete.dispatch({ object, field });
140
+ }
141
+ break;
142
+ }
143
+ }
144
+ });
145
+ // remove the object if it has no more springs
146
+ if (objectAnims.size == 0) {
147
+ this.animations.delete(object);
148
+ this._onObjectAnimationsComplete.dispatch({ object });
149
+ }
150
+ });
151
+ this.onAfterStep.dispatch({ dt_s });
152
+ }
153
+ tick() {
154
+ let t_s = performance.now() / 1000;
155
+ let dt_s = this.t_last >= 0 ? t_s - this.t_last : 1 / 60;
156
+ this.t_last = t_s;
157
+ this.step(dt_s);
158
+ return dt_s;
159
+ }
160
+ /**
161
+ * Start the animation loop using requestAnimationFrame
162
+ *
163
+ * This will stop any existing animation loop
164
+ */
165
+ startAnimationFrameLoop() {
166
+ this.stop();
167
+ let frameLoopHandle = -1;
168
+ let frameLoop = () => {
169
+ this.tick();
170
+ frameLoopHandle = window.requestAnimationFrame(frameLoop);
171
+ };
172
+ frameLoop();
173
+ this._currentLoopControl = {
174
+ stop: () => {
175
+ window.cancelAnimationFrame(frameLoopHandle);
176
+ },
177
+ start: () => {
178
+ frameLoop();
179
+ }
180
+ };
181
+ }
182
+ /**
183
+ * Start the animation loop using setTimeout
184
+ *
185
+ * This will stop any existing animation loop
186
+ */
187
+ startIntervalLoop(interval_ms = 1000 / 240) {
188
+ this.stop();
189
+ let intervalHandle = -1;
190
+ let intervalLoop = () => {
191
+ this.tick();
192
+ intervalHandle = window.setTimeout(intervalLoop, interval_ms);
193
+ };
194
+ intervalLoop();
195
+ this._currentLoopControl = {
196
+ stop: () => {
197
+ window.clearTimeout(intervalHandle);
198
+ },
199
+ start: () => {
200
+ intervalLoop();
201
+ }
202
+ };
203
+ }
204
+ stop() {
205
+ if (this._currentLoopControl != null) {
206
+ this._currentLoopControl.stop();
207
+ this._currentLoopControl = null;
208
+ }
209
+ }
210
+ /**
211
+ * Remove animation for this object and field if it exists
212
+ * Does not change the value of the field
213
+ */
214
+ remove(object, field) {
215
+ let objectSprings = this.animations.get(object);
216
+ if (objectSprings != null) {
217
+ objectSprings.delete(field);
218
+ }
219
+ // if there are no more springs for this object, remove it from the map
220
+ if (objectSprings != null && objectSprings.size == 0) {
221
+ this.animations.delete(object);
222
+ }
223
+ }
224
+ /**
225
+ * Remove all animations for this object
226
+ */
227
+ removeObject(object) {
228
+ this.animations.delete(object);
229
+ }
230
+ /**
231
+ * Remove all animations
232
+ */
233
+ removeAll() {
234
+ this.animations.clear();
235
+ }
236
+ getVelocity(object, field) {
237
+ let spring = this.getObjectAnimations(object).get(field);
238
+ return spring?.velocity ?? 0;
239
+ }
240
+ /**
241
+ * Creates a new map if one doesn't already exist for the given object
242
+ */
243
+ getObjectAnimations(object) {
244
+ let objectAnimations = this.animations.get(object);
245
+ if (objectAnimations == null) {
246
+ // create
247
+ objectAnimations = new Map();
248
+ this.animations.set(object, objectAnimations);
249
+ }
250
+ return objectAnimations;
251
+ }
252
+ /**
253
+ * Creates a new spring if one doesn't already exist for the given object and field
254
+ */
255
+ getAnimationOrCreate(object, field, type) {
256
+ let objectAnimations = this.getObjectAnimations(object);
257
+ let animation = objectAnimations.get(field);
258
+ if (animation == null) {
259
+ // create
260
+ animation = {
261
+ target: 0,
262
+ type: type,
263
+ springParams: null,
264
+ tweenParams: null,
265
+ velocity: 0,
266
+ step: null
267
+ };
268
+ objectAnimations.set(field, animation);
269
+ }
270
+ animation.type = type;
271
+ return animation;
272
+ }
273
+ }
274
+ exports.Animator = Animator;
275
+ var Tween;
276
+ (function (Tween) {
277
+ function linearStep(object, field, target, params, dt_s) {
278
+ let dx = target - params.x0;
279
+ let t = (performance.now() - params.t0_ms) / 1000;
280
+ let u = t / params.duration_s;
281
+ let x_new = params.x0 + dx * u;
282
+ object[field] = x_new;
283
+ }
284
+ Tween.linearStep = linearStep;
285
+ // cubic ease in out
286
+ function easeInOutStep(object, field, target, params, dt_s) {
287
+ let dx = target - params.x0;
288
+ let t = (performance.now() - params.t0_ms) / 1000;
289
+ let u = t / params.duration_s;
290
+ let x_new = params.x0 + dx * u * u * (3 - 2 * u);
291
+ object[field] = x_new;
292
+ }
293
+ Tween.easeInOutStep = easeInOutStep;
294
+ function easeInStep(object, field, target, params, dt_s) {
295
+ let dx = target - params.x0;
296
+ let t = (performance.now() - params.t0_ms) / 1000;
297
+ let u = t / params.duration_s;
298
+ let x_new = params.x0 + dx * u * u * u;
299
+ object[field] = x_new;
300
+ }
301
+ Tween.easeInStep = easeInStep;
302
+ function easeOutStep(object, field, target, params, dt_s) {
303
+ let dx = target - params.x0;
304
+ let t = (performance.now() - params.t0_ms) / 1000;
305
+ let u = t / params.duration_s;
306
+ let x_new = params.x0 + dx * (1 - Math.pow(1 - u, 3));
307
+ object[field] = x_new;
308
+ }
309
+ Tween.easeOutStep = easeOutStep;
310
+ })(Tween || (exports.Tween = Tween = {}));
@@ -1,51 +1,30 @@
1
+ "use strict";
1
2
  /**
2
3
  * Spring
3
- *
4
+ *
4
5
  * @author George Corney (haxiomic)
5
6
  */
6
-
7
- type ExponentialParameters = {
8
- /** Defined as the point in time we'll reach within 0.01% of target from 0 velocity start */
9
- duration_s: number,
10
- }
11
-
12
- type UnderdampedParameters = {
13
- /** Defined as the point in time we'll reach within 0.01% of target from 0 velocity start */
14
- duration_s: number,
15
- /**
16
- * How soft / bouncy the spring, at 0 there is no bounce and decay is exponential, from 0 to infinity the spring will overshoot its target while decaying
17
- * It can be loosely through of roughly the number of oscillations it will take to reach the target
18
- */
19
- bounce: number,
20
- };
21
-
22
- export type SpringParameters = ExponentialParameters | UnderdampedParameters | Spring.PhysicsParameters;
23
-
24
- export namespace Spring {
25
-
26
- export type PhysicsParameters = {
27
- strength: number,
28
- damping: number,
29
- }
30
-
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.Spring = void 0;
9
+ var Spring;
10
+ (function (Spring) {
31
11
  /**
32
12
  * Starting with 0 velocity, this parameter describes how long it would take to reach half-way to the target
33
- *
13
+ *
34
14
  * `damping = 3.356694 / approxHalfLife_s`
35
- *
15
+ *
36
16
  * `strength = damping * damping / 4`
37
17
  */
38
- export function Exponential(options: ExponentialParameters): PhysicsParameters {
18
+ function Exponential(options) {
39
19
  // solved numerically
40
20
  const halfLifeConstant = 3.356694; // from solve (1+u)*exp(-u)=0.5 for u, and constant = 2u
41
21
  const pointOnePercentConstant = 18.46682; // from solve (1+u)*exp(-u)=0.001 for u, and constant = 2u
42
22
  const damping = pointOnePercentConstant / options.duration_s;
43
-
44
23
  let strength = damping * damping / 4;
45
24
  return { damping, strength };
46
25
  }
47
-
48
- export function Underdamped(options: UnderdampedParameters): PhysicsParameters {
26
+ Spring.Exponential = Exponential;
27
+ function Underdamped(options) {
49
28
  const { duration_s, bounce } = options;
50
29
  // -2ln(0.001) = b t
51
30
  const durationTarget = 0.001; // 0.1% of target
@@ -53,110 +32,89 @@ export namespace Spring {
53
32
  // 4k - b^2 > 0
54
33
  let bSq = damping * damping;
55
34
  const criticalStrength = bSq / 4;
56
- let strength = criticalStrength + (bounce * bounce + 1);
35
+ let strength = criticalStrength + (bounce * bounce + 1);
57
36
  return { damping, strength };
58
37
  }
59
-
60
- export function getPhysicsParameters(
61
- parameters: SpringParameters
62
- ): PhysicsParameters {
38
+ Spring.Underdamped = Underdamped;
39
+ function getPhysicsParameters(parameters) {
63
40
  if ('duration_s' in parameters) {
64
41
  if ('bounce' in parameters) {
65
42
  return Underdamped(parameters);
66
- } else {
43
+ }
44
+ else {
67
45
  return Exponential(parameters);
68
46
  }
69
- } else {
47
+ }
48
+ else {
70
49
  // assume physics parameters
71
- return parameters as PhysicsParameters;
50
+ return parameters;
72
51
  }
73
52
  }
74
-
53
+ Spring.getPhysicsParameters = getPhysicsParameters;
75
54
  /**
76
55
  * Analytic spring integration
77
- * @param dt_s
78
- * @param state
79
- * @param parameters
56
+ * @param dt_s
57
+ * @param state
58
+ * @param parameters
80
59
  */
81
- export function stepSpring(
82
- dt_s: number,
83
- state: {
84
- x: number,
85
- targetX: number,
86
- v: number,
87
- },
88
- parameters: PhysicsParameters
89
- ) {
60
+ function stepSpring(dt_s, state, parameters) {
90
61
  // analytic integration (unconditionally stable)
91
62
  // visualization: https://www.desmos.com/calculator/c2iug0kerh
92
63
  // references:
93
64
  // https://mathworld.wolfram.com/OverdampedSimpleHarmonicMotion.html
94
65
  // https://mathworld.wolfram.com/CriticallyDampedSimpleHarmonicMotion.html
95
66
  // https://mathworld.wolfram.com/UnderdampedSimpleHarmonicMotion.html
96
-
97
67
  let k = parameters.strength;
98
68
  let b = parameters.damping;
99
69
  let t = dt_s;
100
70
  let v0 = state.v;
101
71
  let dx0 = state.x - state.targetX;
102
-
103
72
  // nothing will change; exit early
104
- if (dx0 === 0 && v0 === 0) return;
105
- if (dt_s === 0) return;
106
-
73
+ if (dx0 === 0 && v0 === 0)
74
+ return;
75
+ if (dt_s === 0)
76
+ return;
107
77
  let critical = k * 4 - b * b;
108
-
109
78
  if (critical > 0) {
110
79
  // under damped
111
80
  let q = 0.5 * Math.sqrt(critical); // γ
112
-
113
81
  let A = dx0;
114
82
  let B = ((b * dx0) * 0.5 + v0) / q;
115
-
116
83
  let m = Math.exp(-b * 0.5 * t);
117
84
  let c = Math.cos(q * t);
118
85
  let s = Math.sin(q * t);
119
-
120
- let dx1 = m * (A*c + B*s);
121
- let v1 = m * (
122
- ( B*q - 0.5*A*b) * c +
123
- (-A*q - 0.5*b*B) * s
124
- );
125
-
86
+ let dx1 = m * (A * c + B * s);
87
+ let v1 = m * ((B * q - 0.5 * A * b) * c +
88
+ (-A * q - 0.5 * b * B) * s);
126
89
  state.v = v1;
127
90
  state.x = dx1 + state.targetX;
128
- } else if (critical < 0) {
91
+ }
92
+ else if (critical < 0) {
129
93
  // over damped
130
94
  let u = 0.5 * Math.sqrt(-critical);
131
95
  let p = -0.5 * b + u;
132
96
  let n = -0.5 * b - u;
133
- let B = -(n*dx0 - v0)/(2*u);
97
+ let B = -(n * dx0 - v0) / (2 * u);
134
98
  let A = dx0 - B;
135
-
136
99
  let ep = Math.exp(p * t);
137
100
  let en = Math.exp(n * t);
138
-
139
101
  let dx1 = A * en + B * ep;
140
102
  let v1 = A * n * en + B * p * ep;
141
-
142
103
  state.v = v1;
143
104
  state.x = dx1 + state.targetX;
144
- } else {
105
+ }
106
+ else {
145
107
  // critically damped
146
108
  let w = Math.sqrt(k); // ω
147
-
148
109
  let A = dx0;
149
110
  let B = v0 + w * dx0;
150
111
  let e = Math.exp(-w * t);
151
-
152
112
  let dx1 = (A + B * t) * e;
153
113
  let v1 = (B - w * (A + B * t)) * e;
154
-
155
114
  state.v = v1;
156
115
  state.x = dx1 + state.targetX;
157
116
  }
158
-
159
117
  return 0.5 * k * state.x * state.x;
160
118
  }
161
-
162
- }
119
+ Spring.stepSpring = stepSpring;
120
+ })(Spring || (exports.Spring = Spring = {}));
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./AnimationSequencer.js"), exports);
18
+ __exportStar(require("./Animator.js"), exports);
19
+ __exportStar(require("./Spring.js"), exports);
@@ -0,0 +1 @@
1
+ {"type": "commonjs"}