tensum 0.1.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 (134) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/LICENSE +21 -0
  3. package/README.md +340 -0
  4. package/dist/coupled-system.d.ts +50 -0
  5. package/dist/coupled-system.d.ts.map +1 -0
  6. package/dist/coupled-system.js +269 -0
  7. package/dist/coupled-system.js.map +1 -0
  8. package/dist/coupled.d.ts +3 -0
  9. package/dist/coupled.d.ts.map +1 -0
  10. package/dist/coupled.js +2 -0
  11. package/dist/coupled.js.map +1 -0
  12. package/dist/css-linear.d.ts +20 -0
  13. package/dist/css-linear.d.ts.map +1 -0
  14. package/dist/css-linear.js +95 -0
  15. package/dist/css-linear.js.map +1 -0
  16. package/dist/css.d.ts +3 -0
  17. package/dist/css.d.ts.map +1 -0
  18. package/dist/css.js +2 -0
  19. package/dist/css.js.map +1 -0
  20. package/dist/gsap/active-tracks.d.ts +32 -0
  21. package/dist/gsap/active-tracks.d.ts.map +1 -0
  22. package/dist/gsap/active-tracks.js +177 -0
  23. package/dist/gsap/active-tracks.js.map +1 -0
  24. package/dist/gsap/gsap-time.d.ts +10 -0
  25. package/dist/gsap/gsap-time.d.ts.map +1 -0
  26. package/dist/gsap/gsap-time.js +62 -0
  27. package/dist/gsap/gsap-time.js.map +1 -0
  28. package/dist/gsap/plugin-tween-coordinator.d.ts +30 -0
  29. package/dist/gsap/plugin-tween-coordinator.d.ts.map +1 -0
  30. package/dist/gsap/plugin-tween-coordinator.js +72 -0
  31. package/dist/gsap/plugin-tween-coordinator.js.map +1 -0
  32. package/dist/gsap/plugin.d.ts +84 -0
  33. package/dist/gsap/plugin.d.ts.map +1 -0
  34. package/dist/gsap/plugin.js +552 -0
  35. package/dist/gsap/plugin.js.map +1 -0
  36. package/dist/gsap/spring-to.d.ts +93 -0
  37. package/dist/gsap/spring-to.d.ts.map +1 -0
  38. package/dist/gsap/spring-to.js +569 -0
  39. package/dist/gsap/spring-to.js.map +1 -0
  40. package/dist/gsap/spring-track-policy.d.ts +24 -0
  41. package/dist/gsap/spring-track-policy.d.ts.map +1 -0
  42. package/dist/gsap/spring-track-policy.js +76 -0
  43. package/dist/gsap/spring-track-policy.js.map +1 -0
  44. package/dist/gsap/track-lifecycle.d.ts +16 -0
  45. package/dist/gsap/track-lifecycle.d.ts.map +1 -0
  46. package/dist/gsap/track-lifecycle.js +33 -0
  47. package/dist/gsap/track-lifecycle.js.map +1 -0
  48. package/dist/index.d.ts +28 -0
  49. package/dist/index.d.ts.map +1 -0
  50. package/dist/index.js +16 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/math.d.ts +9 -0
  53. package/dist/math.d.ts.map +1 -0
  54. package/dist/math.js +38 -0
  55. package/dist/math.js.map +1 -0
  56. package/dist/model.d.ts +14 -0
  57. package/dist/model.d.ts.map +1 -0
  58. package/dist/model.js +38 -0
  59. package/dist/model.js.map +1 -0
  60. package/dist/motion-compatibility.d.ts +18 -0
  61. package/dist/motion-compatibility.d.ts.map +1 -0
  62. package/dist/motion-compatibility.js +83 -0
  63. package/dist/motion-compatibility.js.map +1 -0
  64. package/dist/parameters.d.ts +52 -0
  65. package/dist/parameters.d.ts.map +1 -0
  66. package/dist/parameters.js +124 -0
  67. package/dist/parameters.js.map +1 -0
  68. package/dist/settling.d.ts +12 -0
  69. package/dist/settling.d.ts.map +1 -0
  70. package/dist/settling.js +107 -0
  71. package/dist/settling.js.map +1 -0
  72. package/dist/solver.d.ts +17 -0
  73. package/dist/solver.d.ts.map +1 -0
  74. package/dist/solver.js +190 -0
  75. package/dist/solver.js.map +1 -0
  76. package/dist/spring.d.ts +9 -0
  77. package/dist/spring.d.ts.map +1 -0
  78. package/dist/spring.js +91 -0
  79. package/dist/spring.js.map +1 -0
  80. package/dist/support/additive-spring-value.d.ts +39 -0
  81. package/dist/support/additive-spring-value.d.ts.map +1 -0
  82. package/dist/support/additive-spring-value.js +281 -0
  83. package/dist/support/additive-spring-value.js.map +1 -0
  84. package/dist/support/inertia.d.ts +34 -0
  85. package/dist/support/inertia.d.ts.map +1 -0
  86. package/dist/support/inertia.js +293 -0
  87. package/dist/support/inertia.js.map +1 -0
  88. package/dist/support/keyframes.d.ts +34 -0
  89. package/dist/support/keyframes.d.ts.map +1 -0
  90. package/dist/support/keyframes.js +117 -0
  91. package/dist/support/keyframes.js.map +1 -0
  92. package/dist/support/spring-value.d.ts +38 -0
  93. package/dist/support/spring-value.d.ts.map +1 -0
  94. package/dist/support/spring-value.js +289 -0
  95. package/dist/support/spring-value.js.map +1 -0
  96. package/dist/support/velocity.d.ts +14 -0
  97. package/dist/support/velocity.d.ts.map +1 -0
  98. package/dist/support/velocity.js +75 -0
  99. package/dist/support/velocity.js.map +1 -0
  100. package/dist/types.d.ts +61 -0
  101. package/dist/types.d.ts.map +1 -0
  102. package/dist/types.js +2 -0
  103. package/dist/types.js.map +1 -0
  104. package/dist/vector.d.ts +32 -0
  105. package/dist/vector.d.ts.map +1 -0
  106. package/dist/vector.js +121 -0
  107. package/dist/vector.js.map +1 -0
  108. package/package.json +68 -0
  109. package/src/coupled-system.ts +383 -0
  110. package/src/coupled.ts +10 -0
  111. package/src/css-linear.ts +148 -0
  112. package/src/css.ts +6 -0
  113. package/src/gsap/active-tracks.ts +244 -0
  114. package/src/gsap/gsap-time.ts +91 -0
  115. package/src/gsap/plugin-tween-coordinator.ts +112 -0
  116. package/src/gsap/plugin.ts +861 -0
  117. package/src/gsap/spring-to.ts +836 -0
  118. package/src/gsap/spring-track-policy.ts +133 -0
  119. package/src/gsap/track-lifecycle.ts +53 -0
  120. package/src/index.ts +130 -0
  121. package/src/math.ts +46 -0
  122. package/src/model.ts +70 -0
  123. package/src/motion-compatibility.ts +131 -0
  124. package/src/parameters.ts +226 -0
  125. package/src/settling.ts +141 -0
  126. package/src/solver.ts +262 -0
  127. package/src/spring.ts +119 -0
  128. package/src/support/additive-spring-value.ts +343 -0
  129. package/src/support/inertia.ts +367 -0
  130. package/src/support/keyframes.ts +188 -0
  131. package/src/support/spring-value.ts +399 -0
  132. package/src/support/velocity.ts +119 -0
  133. package/src/types.ts +70 -0
  134. package/src/vector.ts +191 -0
@@ -0,0 +1,124 @@
1
+ import { angularFrequency, assertFinite, classifyDamping, dampingRatio, } from './math.js';
2
+ import { validateSpringParameters } from './solver.js';
3
+ const DEFAULT_MASS = 1;
4
+ const TWO_PI = 2 * Math.PI;
5
+ function assertPositive(name, value) {
6
+ assertFinite(name, value);
7
+ if (value <= 0)
8
+ throw new RangeError(`${name} must be greater than 0`);
9
+ }
10
+ function assertNonNegative(name, value) {
11
+ assertFinite(name, value);
12
+ if (value < 0)
13
+ throw new RangeError(`${name} must be greater than or equal to 0`);
14
+ }
15
+ function resolvedMass(mass) {
16
+ const value = mass === undefined ? DEFAULT_MASS : mass;
17
+ assertPositive('mass', value);
18
+ return value;
19
+ }
20
+ function freezeParameters(parameters) {
21
+ validateSpringParameters(parameters);
22
+ const frequency = angularFrequency(parameters);
23
+ const ratio = dampingRatio(parameters);
24
+ assertPositive('angularFrequency', frequency);
25
+ assertFinite('dampingRatio', ratio);
26
+ return Object.freeze({ ...parameters });
27
+ }
28
+ function fromFrequency(frequency, ratio, mass) {
29
+ assertPositive('angularFrequency', frequency);
30
+ assertNonNegative('dampingRatio', ratio);
31
+ const stiffness = mass * frequency * frequency;
32
+ let damping = 2 * ratio * mass * frequency;
33
+ if (!Number.isFinite(damping) || damping === 0) {
34
+ const candidates = [
35
+ 2 * mass * ratio * frequency,
36
+ 2 * frequency * mass * ratio,
37
+ 2 * mass * (ratio * frequency),
38
+ ];
39
+ const representable = candidates.find((candidate) => Number.isFinite(candidate) && candidate > 0);
40
+ if (representable !== undefined)
41
+ damping = representable;
42
+ }
43
+ return freezeParameters({ mass, stiffness, damping });
44
+ }
45
+ function bounceToDampingRatio(bounce) {
46
+ assertFinite('bounce', bounce);
47
+ if (bounce <= -1) {
48
+ throw new RangeError('bounce must be greater than -1 for finite spring parameters');
49
+ }
50
+ if (bounce >= 0)
51
+ return 1 - Math.min(bounce, 1);
52
+ return 1 / (1 + bounce);
53
+ }
54
+ function dampingRatioToBounce(ratio) {
55
+ return ratio <= 1 ? 1 - ratio : 1 / ratio - 1;
56
+ }
57
+ export function springCharacteristics(parameters) {
58
+ validateSpringParameters(parameters);
59
+ const frequency = angularFrequency(parameters);
60
+ const ratio = dampingRatio(parameters);
61
+ assertPositive('angularFrequency', frequency);
62
+ assertFinite('dampingRatio', ratio);
63
+ const response = TWO_PI / frequency;
64
+ assertPositive('response', response);
65
+ return Object.freeze({
66
+ angularFrequency: frequency,
67
+ dampingRatio: ratio,
68
+ regime: classifyDamping(ratio),
69
+ response,
70
+ bounce: dampingRatioToBounce(ratio),
71
+ perceptualDuration: response,
72
+ });
73
+ }
74
+ export const springParameters = Object.freeze({
75
+ fromPhysics(parameters) {
76
+ return freezeParameters({
77
+ mass: parameters.mass,
78
+ stiffness: parameters.stiffness,
79
+ damping: parameters.damping,
80
+ });
81
+ },
82
+ fromResponse({ response, dampingRatio: ratio, mass, }) {
83
+ assertPositive('response', response);
84
+ return fromFrequency(TWO_PI / response, ratio, resolvedMass(mass));
85
+ },
86
+ fromPerceptualDuration({ duration, bounce, mass, }) {
87
+ assertPositive('duration', duration);
88
+ return fromFrequency(TWO_PI / duration, bounceToDampingRatio(bounce), resolvedMass(mass));
89
+ },
90
+ fromSettlingDuration({ duration, dampingRatio: ratio, epsilon, mass, }) {
91
+ assertPositive('duration', duration);
92
+ assertPositive('dampingRatio', ratio);
93
+ assertFinite('epsilon', epsilon);
94
+ if (epsilon <= 0 || epsilon >= 1) {
95
+ throw new RangeError('epsilon must be greater than 0 and less than 1');
96
+ }
97
+ const frequency = -Math.log(epsilon) / (ratio * duration);
98
+ return fromFrequency(frequency, ratio, resolvedMass(mass));
99
+ },
100
+ fromVisualDuration({ visualDuration, bounce, mass, }) {
101
+ return springParameters.fromPerceptualDuration({
102
+ duration: visualDuration,
103
+ bounce,
104
+ ...(mass === undefined ? {} : { mass }),
105
+ });
106
+ },
107
+ });
108
+ function createPreset(baseBounce) {
109
+ return (options = {}) => {
110
+ const extraBounce = options.extraBounce === undefined ? 0 : options.extraBounce;
111
+ assertFinite('extraBounce', extraBounce);
112
+ return springParameters.fromPerceptualDuration({
113
+ duration: options.duration === undefined ? 0.5 : options.duration,
114
+ bounce: baseBounce + extraBounce,
115
+ ...(options.mass === undefined ? {} : { mass: options.mass }),
116
+ });
117
+ };
118
+ }
119
+ export const springPresets = Object.freeze({
120
+ smooth: createPreset(0),
121
+ snappy: createPreset(0.15),
122
+ bouncy: createPreset(0.3),
123
+ });
124
+ //# sourceMappingURL=parameters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parameters.js","sourceRoot":"","sources":["../src/parameters.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { AnalyticalSolver } from './solver.js';
2
+ import type { SettlingResult, SpringSettleInput, SpringSettlingOptions } from './types.js';
3
+ export declare const DEFAULT_SETTLING_OPTIONS: Readonly<SpringSettlingOptions>;
4
+ export declare function resolveSettlingOptions(input?: SpringSettleInput): Readonly<SpringSettlingOptions>;
5
+ export declare function validateSettlingOptions(options: SpringSettlingOptions): void;
6
+ /**
7
+ * Finds the first time at which analytical tail envelopes are below both
8
+ * tolerances. The envelopes bound every future position error and velocity,
9
+ * so an underdamped zero-crossing cannot be mistaken for settlement.
10
+ */
11
+ export declare function getSettlingResult(solver: AnalyticalSolver, options: SpringSettlingOptions): SettlingResult;
12
+ //# sourceMappingURL=settling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settling.d.ts","sourceRoot":"","sources":["../src/settling.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,wBAAwB,EAAE,QAAQ,CAAC,qBAAqB,CAKpE,CAAC;AAEF,wBAAgB,sBAAsB,CACpC,KAAK,GAAE,iBAAsB,GAC5B,QAAQ,CAAC,qBAAqB,CAAC,CAwBjC;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAqB5E;AAaD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,qBAAqB,GAC7B,cAAc,CAuDhB"}
@@ -0,0 +1,107 @@
1
+ import { assertFinite } from './math.js';
2
+ export const DEFAULT_SETTLING_OPTIONS = {
3
+ positionEpsilon: 0.1,
4
+ velocityEpsilon: 0.1,
5
+ maxDuration: 60,
6
+ refinementIterations: 48,
7
+ };
8
+ export function resolveSettlingOptions(input = {}) {
9
+ if (typeof input !== 'object' || input === null || Array.isArray(input)) {
10
+ throw new TypeError('settle must be an object when provided');
11
+ }
12
+ const options = {
13
+ positionEpsilon: input.position === undefined
14
+ ? DEFAULT_SETTLING_OPTIONS.positionEpsilon
15
+ : input.position,
16
+ velocityEpsilon: input.velocity === undefined
17
+ ? DEFAULT_SETTLING_OPTIONS.velocityEpsilon
18
+ : input.velocity,
19
+ maxDuration: input.maxDuration === undefined
20
+ ? DEFAULT_SETTLING_OPTIONS.maxDuration
21
+ : input.maxDuration,
22
+ refinementIterations: input.refinementIterations === undefined
23
+ ? DEFAULT_SETTLING_OPTIONS.refinementIterations
24
+ : input.refinementIterations,
25
+ };
26
+ validateSettlingOptions(options);
27
+ return Object.freeze(options);
28
+ }
29
+ export function validateSettlingOptions(options) {
30
+ assertFinite('positionEpsilon', options.positionEpsilon);
31
+ assertFinite('velocityEpsilon', options.velocityEpsilon);
32
+ assertFinite('maxDuration', options.maxDuration);
33
+ assertFinite('refinementIterations', options.refinementIterations);
34
+ if (options.positionEpsilon <= 0) {
35
+ throw new RangeError('positionEpsilon must be greater than 0');
36
+ }
37
+ if (options.velocityEpsilon <= 0) {
38
+ throw new RangeError('velocityEpsilon must be greater than 0');
39
+ }
40
+ if (options.maxDuration <= 0) {
41
+ throw new RangeError('maxDuration must be greater than 0');
42
+ }
43
+ if (!Number.isInteger(options.refinementIterations)) {
44
+ throw new RangeError('refinementIterations must be an integer');
45
+ }
46
+ if (options.refinementIterations <= 0) {
47
+ throw new RangeError('refinementIterations must be greater than 0');
48
+ }
49
+ }
50
+ function boundsMeetThresholds(solver, time, options) {
51
+ const bounds = solver.tailBoundsAt(time);
52
+ return (bounds.position <= options.positionEpsilon && bounds.velocity <= options.velocityEpsilon);
53
+ }
54
+ /**
55
+ * Finds the first time at which analytical tail envelopes are below both
56
+ * tolerances. The envelopes bound every future position error and velocity,
57
+ * so an underdamped zero-crossing cannot be mistaken for settlement.
58
+ */
59
+ export function getSettlingResult(solver, options) {
60
+ validateSettlingOptions(options);
61
+ const { maxDuration, refinementIterations } = options;
62
+ const initialBounds = solver.tailBoundsAt(0);
63
+ if (initialBounds.position === 0 && initialBounds.velocity === 0) {
64
+ return { duration: 0, iterations: 0, settled: true };
65
+ }
66
+ if (boundsMeetThresholds(solver, 0, options) && solver.tailBoundsMonotonicAfter === 0) {
67
+ return { duration: 0, iterations: 0, settled: true };
68
+ }
69
+ // An undamped non-equilibrium oscillator has a constant analytical envelope.
70
+ if (solver.dampingRatio === 0) {
71
+ return { duration: maxDuration, iterations: 0, settled: false };
72
+ }
73
+ if (solver.tailBoundsMonotonicAfter > maxDuration) {
74
+ return { duration: maxDuration, iterations: 0, settled: false };
75
+ }
76
+ let iterations = 0;
77
+ let lower = solver.tailBoundsMonotonicAfter;
78
+ let upper = Math.max(lower, Math.min(maxDuration, Math.max(1 / solver.angularFrequency, 1 / 120)));
79
+ if (boundsMeetThresholds(solver, lower, options)) {
80
+ // Critical-damping polynomial envelopes can grow before this point. Using
81
+ // the monotonic boundary is conservative and avoids an invalid binary
82
+ // search across that non-monotonic interval.
83
+ return { duration: lower, iterations, settled: true };
84
+ }
85
+ else {
86
+ while (upper < maxDuration && !boundsMeetThresholds(solver, upper, options)) {
87
+ lower = upper;
88
+ upper = Math.min(maxDuration, upper * 2);
89
+ iterations += 1;
90
+ }
91
+ }
92
+ if (!boundsMeetThresholds(solver, upper, options)) {
93
+ return { duration: maxDuration, iterations, settled: false };
94
+ }
95
+ for (let index = 0; index < refinementIterations; index += 1) {
96
+ const midpoint = lower + (upper - lower) / 2;
97
+ if (midpoint === lower || midpoint === upper)
98
+ break;
99
+ if (boundsMeetThresholds(solver, midpoint, options))
100
+ upper = midpoint;
101
+ else
102
+ lower = midpoint;
103
+ iterations += 1;
104
+ }
105
+ return { duration: upper, iterations, settled: true };
106
+ }
107
+ //# sourceMappingURL=settling.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settling.js","sourceRoot":"","sources":["../src/settling.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { SpringInitialState, SpringParameters, SpringRegime, SpringState } from './types.js';
2
+ export interface AnalyticalSolver {
3
+ readonly angularFrequency: number;
4
+ readonly dampingRatio: number;
5
+ readonly regime: SpringRegime;
6
+ stateAt(time: number): SpringState;
7
+ tailBoundsAt(time: number): SpringState;
8
+ tailBoundsMonotonicAfter: number;
9
+ }
10
+ export declare function validateSpringParameters(parameters: SpringParameters): void;
11
+ export declare function validateInitialState(initial: SpringInitialState): void;
12
+ /**
13
+ * Solves m·x″ + c·x′ + k·(x - target) = 0 in closed form.
14
+ * Every sample is calculated from the initial conditions and absolute time.
15
+ */
16
+ export declare function createAnalyticalSolver(parameters: SpringParameters, initial: SpringInitialState): AnalyticalSolver;
17
+ //# sourceMappingURL=solver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solver.d.ts","sourceRoot":"","sources":["../src/solver.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IACnC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IACxC,wBAAwB,EAAE,MAAM,CAAC;CAClC;AAED,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAQ3E;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAItE;AAyBD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,gBAAgB,EAC5B,OAAO,EAAE,kBAAkB,GAC1B,gBAAgB,CA+LlB"}
package/dist/solver.js ADDED
@@ -0,0 +1,190 @@
1
+ import { angularFrequency, assertFinite, assertNonNegativeTime, classifyDamping, dampingDecayRate, dampingRatio, } from './math.js';
2
+ export function validateSpringParameters(parameters) {
3
+ assertFinite('mass', parameters.mass);
4
+ assertFinite('stiffness', parameters.stiffness);
5
+ assertFinite('damping', parameters.damping);
6
+ if (parameters.mass <= 0)
7
+ throw new RangeError('mass must be greater than 0');
8
+ if (parameters.stiffness <= 0)
9
+ throw new RangeError('stiffness must be greater than 0');
10
+ if (parameters.damping < 0)
11
+ throw new RangeError('damping must be greater than or equal to 0');
12
+ }
13
+ export function validateInitialState(initial) {
14
+ assertFinite('position', initial.position);
15
+ assertFinite('velocity', initial.velocity);
16
+ assertFinite('target', initial.target);
17
+ }
18
+ function finiteState(position, velocity, suffix = '') {
19
+ assertFinite(`position${suffix}`, position);
20
+ assertFinite(`velocity${suffix}`, velocity);
21
+ return { position, velocity };
22
+ }
23
+ function multiplyDivide(first, second, divisor) {
24
+ const firstQuotient = (first / divisor) * second;
25
+ const secondQuotient = first * (second / divisor);
26
+ if (Number.isFinite(firstQuotient)) {
27
+ if (firstQuotient !== 0 || secondQuotient === 0)
28
+ return firstQuotient;
29
+ }
30
+ return secondQuotient;
31
+ }
32
+ /**
33
+ * Solves m·x″ + c·x′ + k·(x - target) = 0 in closed form.
34
+ * Every sample is calculated from the initial conditions and absolute time.
35
+ */
36
+ export function createAnalyticalSolver(parameters, initial) {
37
+ validateSpringParameters(parameters);
38
+ validateInitialState(initial);
39
+ // Keep the public solver deterministic if the caller later reuses and
40
+ // mutates its input object.
41
+ const initialPosition = initial.position;
42
+ const initialVelocity = initial.velocity;
43
+ const target = initial.target;
44
+ const omega0 = angularFrequency(parameters);
45
+ const alpha = dampingDecayRate(parameters);
46
+ const zeta = dampingRatio(parameters);
47
+ assertFinite('angularFrequency', omega0);
48
+ assertFinite('dampingDecayRate', alpha);
49
+ assertFinite('dampingRatio', zeta);
50
+ if (omega0 <= 0) {
51
+ throw new RangeError('spring parameters must produce a positive angularFrequency');
52
+ }
53
+ const regime = classifyDamping(zeta);
54
+ const y0 = initialPosition - target;
55
+ const v0 = initialVelocity;
56
+ assertFinite('initial displacement', y0);
57
+ if (regime === 'underdamped') {
58
+ const omegaD = omega0 * Math.sqrt(Math.max(0, (1 - zeta) * (1 + zeta)));
59
+ const a = y0;
60
+ const b = (v0 + alpha * y0) / omegaD;
61
+ const velocityCos = -alpha * a + omegaD * b;
62
+ const velocitySin = -alpha * b - omegaD * a;
63
+ const positionAmplitude = Math.hypot(a, b);
64
+ const velocityAmplitude = Math.hypot(velocityCos, velocitySin);
65
+ for (const [name, value] of [
66
+ ['dampedAngularFrequency', omegaD],
67
+ ['positionCoefficient', b],
68
+ ['velocityCosCoefficient', velocityCos],
69
+ ['velocitySinCoefficient', velocitySin],
70
+ ['positionAmplitude', positionAmplitude],
71
+ ['velocityAmplitude', velocityAmplitude],
72
+ ]) {
73
+ assertFinite(name, value);
74
+ }
75
+ return {
76
+ angularFrequency: omega0,
77
+ dampingRatio: zeta,
78
+ regime,
79
+ stateAt(time) {
80
+ assertNonNegativeTime(time);
81
+ if (time === 0) {
82
+ return { position: initialPosition, velocity: initialVelocity };
83
+ }
84
+ const decay = Math.exp(-alpha * time);
85
+ if (decay === 0)
86
+ return { position: target, velocity: 0 };
87
+ const rawPhase = omegaD * time;
88
+ const phase = Number.isFinite(rawPhase)
89
+ ? rawPhase
90
+ : (time % ((2 * Math.PI) / omegaD)) * omegaD;
91
+ const cosine = Math.cos(phase);
92
+ const sine = Math.sin(phase);
93
+ return finiteState(target + decay * (a * cosine + b * sine), decay * (velocityCos * cosine + velocitySin * sine));
94
+ },
95
+ tailBoundsAt(time) {
96
+ assertNonNegativeTime(time);
97
+ const decay = Math.exp(-alpha * time);
98
+ return finiteState(decay * positionAmplitude, decay * velocityAmplitude, ' bound');
99
+ },
100
+ tailBoundsMonotonicAfter: 0,
101
+ };
102
+ }
103
+ if (regime === 'critical') {
104
+ const a = y0;
105
+ const b = v0 + omega0 * y0;
106
+ const velocityConstant = b - omega0 * a;
107
+ const velocityLinear = -omega0 * b;
108
+ for (const [name, value] of [
109
+ ['positionCoefficient', b],
110
+ ['velocityConstant', velocityConstant],
111
+ ['velocityLinear', velocityLinear],
112
+ ]) {
113
+ assertFinite(name, value);
114
+ }
115
+ return {
116
+ angularFrequency: omega0,
117
+ dampingRatio: zeta,
118
+ regime,
119
+ stateAt(time) {
120
+ assertNonNegativeTime(time);
121
+ if (time === 0) {
122
+ return { position: initialPosition, velocity: initialVelocity };
123
+ }
124
+ const decay = Math.exp(-omega0 * time);
125
+ if (decay === 0)
126
+ return { position: target, velocity: 0 };
127
+ const timeDecay = time * decay;
128
+ return finiteState(target + decay * a + timeDecay * b, decay * velocityConstant + timeDecay * velocityLinear);
129
+ },
130
+ tailBoundsAt(time) {
131
+ assertNonNegativeTime(time);
132
+ const decay = Math.exp(-omega0 * time);
133
+ if (decay === 0)
134
+ return { position: 0, velocity: 0 };
135
+ const timeDecay = time * decay;
136
+ return finiteState(decay * Math.abs(a) + timeDecay * Math.abs(b), decay * Math.abs(velocityConstant) +
137
+ timeDecay * Math.abs(velocityLinear), ' bound');
138
+ },
139
+ // Every t·exp(-ωt) term decreases after t = 1/ω.
140
+ tailBoundsMonotonicAfter: 1 / omega0,
141
+ };
142
+ }
143
+ const normalizedFrequency = omega0 / alpha;
144
+ const normalizedOffset = Math.sqrt(Math.max(0, (1 - normalizedFrequency) * (1 + normalizedFrequency)));
145
+ const rootFastMagnitude = alpha * (1 + normalizedOffset);
146
+ const rootFast = -rootFastMagnitude;
147
+ // Vieta's relation avoids subtracting two almost equal values in
148
+ // -alpha + sqrt(alpha² - omega0²).
149
+ const rootSlow = -omega0 * (omega0 / rootFastMagnitude);
150
+ const rootSeparation = rootSlow - rootFast;
151
+ const normalizedVelocity = v0 / rootSeparation;
152
+ const coefficientSlow = normalizedVelocity - multiplyDivide(rootFast, y0, rootSeparation);
153
+ const coefficientFast = multiplyDivide(rootSlow, y0, rootSeparation) - normalizedVelocity;
154
+ for (const [name, value] of [
155
+ ['overdampedSlowRoot', rootSlow],
156
+ ['overdampedFastRoot', rootFast],
157
+ ['overdampedRootSeparation', rootSeparation],
158
+ ['slowModeCoefficient', coefficientSlow],
159
+ ['fastModeCoefficient', coefficientFast],
160
+ ]) {
161
+ assertFinite(name, value);
162
+ }
163
+ if (rootSlow >= 0 || rootFast >= 0 || rootSeparation <= 0) {
164
+ throw new RangeError('overdamped roots must be distinct negative finite numbers');
165
+ }
166
+ return {
167
+ angularFrequency: omega0,
168
+ dampingRatio: zeta,
169
+ regime,
170
+ stateAt(time) {
171
+ assertNonNegativeTime(time);
172
+ if (time === 0) {
173
+ return { position: initialPosition, velocity: initialVelocity };
174
+ }
175
+ const slow = coefficientSlow * Math.exp(rootSlow * time);
176
+ const fast = coefficientFast * Math.exp(rootFast * time);
177
+ return finiteState(target + slow + fast, rootSlow * slow + rootFast * fast);
178
+ },
179
+ tailBoundsAt(time) {
180
+ assertNonNegativeTime(time);
181
+ const slowDecay = Math.exp(rootSlow * time);
182
+ const fastDecay = Math.exp(rootFast * time);
183
+ return finiteState(Math.abs(coefficientSlow) * slowDecay +
184
+ Math.abs(coefficientFast) * fastDecay, Math.abs(rootSlow * coefficientSlow) * slowDecay +
185
+ Math.abs(rootFast * coefficientFast) * fastDecay, ' bound');
186
+ },
187
+ tailBoundsMonotonicAfter: 0,
188
+ };
189
+ }
190
+ //# sourceMappingURL=solver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solver.js","sourceRoot":"","sources":["../src/solver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { SpringInitialState, SpringOptions, SpringParameters, SpringSettleInput, SpringSolution, SpringTimingInput } from './types.js';
2
+ export interface SpringSolutionOptions {
3
+ settle?: SpringSettleInput;
4
+ timing?: SpringTimingInput;
5
+ }
6
+ export declare function resolveSpringTimingInput(input: SpringTimingInput | undefined): Readonly<SpringTimingInput> | undefined;
7
+ export declare function createSpringSolution(parameters: SpringParameters, initialState: SpringInitialState, options?: SpringSolutionOptions): SpringSolution;
8
+ export declare function createSpring(options: SpringOptions): SpringSolution;
9
+ //# sourceMappingURL=spring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring.d.ts","sourceRoot":"","sources":["../src/spring.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EAGd,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,iBAAiB,GAAG,SAAS,GACnC,QAAQ,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAWzC;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,gBAAgB,EAC5B,YAAY,EAAE,kBAAkB,EAChC,OAAO,GAAE,qBAA0B,GAClC,cAAc,CA6DhB;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,cAAc,CAiBnE"}
package/dist/spring.js ADDED
@@ -0,0 +1,91 @@
1
+ import { assertFinite } from './math.js';
2
+ import { getSettlingResult, resolveSettlingOptions } from './settling.js';
3
+ import { createAnalyticalSolver } from './solver.js';
4
+ export function resolveSpringTimingInput(input) {
5
+ if (input === undefined)
6
+ return undefined;
7
+ if (typeof input !== 'object' || input === null || Array.isArray(input)) {
8
+ throw new TypeError('timing must be an object when provided');
9
+ }
10
+ if (input.perceptualDuration === undefined)
11
+ return Object.freeze({});
12
+ assertFinite('perceptualDuration', input.perceptualDuration);
13
+ if (input.perceptualDuration < 0) {
14
+ throw new RangeError('perceptualDuration must be greater than or equal to 0');
15
+ }
16
+ return Object.freeze({ perceptualDuration: input.perceptualDuration });
17
+ }
18
+ export function createSpringSolution(parameters, initialState, options = {}) {
19
+ const resolvedTiming = resolveSpringTimingInput(options.timing);
20
+ const settling = resolveSettlingOptions(options.settle);
21
+ const solver = createAnalyticalSolver(parameters, initialState);
22
+ const settlingResult = getSettlingResult(solver, settling);
23
+ const requestedPerceptualDuration = resolvedTiming?.perceptualDuration;
24
+ const perceptualDuration = requestedPerceptualDuration === undefined
25
+ ? (2 * Math.PI) / solver.angularFrequency
26
+ : requestedPerceptualDuration;
27
+ assertFinite('perceptualDuration', perceptualDuration);
28
+ if (perceptualDuration < 0) {
29
+ throw new RangeError('perceptualDuration must be greater than or equal to 0');
30
+ }
31
+ const timing = {
32
+ perceptualDuration,
33
+ settlingDuration: settlingResult.duration,
34
+ settled: settlingResult.settled,
35
+ };
36
+ const stateAt = (time) => solver.stateAt(time);
37
+ return Object.freeze({
38
+ dampingRatio: solver.dampingRatio,
39
+ angularFrequency: solver.angularFrequency,
40
+ regime: solver.regime,
41
+ parameters: Object.freeze({ ...parameters }),
42
+ initialState: Object.freeze({ ...initialState }),
43
+ settling,
44
+ timing: Object.freeze(timing),
45
+ positionAt(time) {
46
+ return stateAt(time).position;
47
+ },
48
+ velocityAt(time) {
49
+ return stateAt(time).velocity;
50
+ },
51
+ stateAt,
52
+ getSettlingDuration() {
53
+ return settlingResult.duration;
54
+ },
55
+ getSettlingResult() {
56
+ return { ...settlingResult };
57
+ },
58
+ retarget(target, time) {
59
+ assertFinite('target', target);
60
+ const current = stateAt(time);
61
+ return createSpringSolution(parameters, {
62
+ position: current.position,
63
+ velocity: current.velocity,
64
+ target,
65
+ }, {
66
+ settle: {
67
+ position: settling.positionEpsilon,
68
+ velocity: settling.velocityEpsilon,
69
+ maxDuration: settling.maxDuration,
70
+ refinementIterations: settling.refinementIterations,
71
+ },
72
+ timing: { perceptualDuration: timing.perceptualDuration },
73
+ });
74
+ },
75
+ });
76
+ }
77
+ export function createSpring(options) {
78
+ return createSpringSolution({
79
+ mass: options.mass,
80
+ stiffness: options.stiffness,
81
+ damping: options.damping,
82
+ }, {
83
+ position: options.from,
84
+ velocity: options.velocity === undefined ? 0 : options.velocity,
85
+ target: options.to,
86
+ }, {
87
+ ...(options.settle === undefined ? {} : { settle: options.settle }),
88
+ ...(options.timing === undefined ? {} : { timing: options.timing }),
89
+ });
90
+ }
91
+ //# sourceMappingURL=spring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring.js","sourceRoot":"","sources":["../src/spring.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { SpringParameters, SpringSettleInput, SpringTimingInput } from '../types.js';
2
+ import type { FrameDriver } from './spring-value.js';
3
+ export interface AdditiveSpringOptions {
4
+ settle?: SpringSettleInput;
5
+ timing?: SpringTimingInput;
6
+ }
7
+ export interface AdditiveSpringContributionOptions {
8
+ parameters?: SpringParameters;
9
+ settle?: SpringSettleInput;
10
+ timing?: SpringTimingInput;
11
+ velocity?: number;
12
+ }
13
+ export interface AdditiveSpringSnapshot {
14
+ value: number;
15
+ velocity: number;
16
+ target: number;
17
+ animating: boolean;
18
+ contributions: number;
19
+ }
20
+ export type AdditiveSpringEvent = 'change' | 'settle' | 'unsettled';
21
+ export type AdditiveSpringListener = (snapshot: Readonly<AdditiveSpringSnapshot>) => void;
22
+ export interface AdditiveSpringValue {
23
+ get(): number;
24
+ getVelocity(): number;
25
+ getTarget(): number;
26
+ getSnapshot(): Readonly<AdditiveSpringSnapshot>;
27
+ animateBy(delta: number, options?: AdditiveSpringContributionOptions): number;
28
+ cancel(contribution: number): void;
29
+ jump(value: number): void;
30
+ stop(): void;
31
+ on(event: AdditiveSpringEvent, listener: AdditiveSpringListener): () => void;
32
+ destroy(): void;
33
+ }
34
+ /**
35
+ * Composes overlapping spring effects as independent additive contributions.
36
+ * Use createSpringValue when each new target should replace the previous one.
37
+ */
38
+ export declare function createAdditiveSpringValue(initialValue: number, parameters: SpringParameters, driver: FrameDriver, options?: AdditiveSpringOptions): AdditiveSpringValue;
39
+ //# sourceMappingURL=additive-spring-value.d.ts.map