@flighthq/easing 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.
- package/dist/createEasingSamples.d.ts +3 -0
- package/dist/createEasingSamples.d.ts.map +1 -0
- package/dist/createEasingSamples.js +36 -0
- package/dist/createEasingSamples.js.map +1 -0
- package/dist/easeBack.d.ts +5 -0
- package/dist/easeBack.d.ts.map +1 -0
- package/dist/easeBack.js +6 -0
- package/dist/easeBack.js.map +1 -0
- package/dist/easeBounce.d.ts +5 -0
- package/dist/easeBounce.d.ts.map +1 -0
- package/dist/easeBounce.js +13 -0
- package/dist/easeBounce.js.map +1 -0
- package/dist/easeCircular.d.ts +5 -0
- package/dist/easeCircular.d.ts.map +1 -0
- package/dist/easeCircular.js +4 -0
- package/dist/easeCircular.js.map +1 -0
- package/dist/easeCombinators.d.ts +8 -0
- package/dist/easeCombinators.d.ts.map +1 -0
- package/dist/easeCombinators.js +53 -0
- package/dist/easeCombinators.js.map +1 -0
- package/dist/easeCubic.d.ts +5 -0
- package/dist/easeCubic.d.ts.map +1 -0
- package/dist/easeCubic.js +4 -0
- package/dist/easeCubic.js.map +1 -0
- package/dist/easeCubicBezier.d.ts +3 -0
- package/dist/easeCubicBezier.d.ts.map +1 -0
- package/dist/easeCubicBezier.js +68 -0
- package/dist/easeCubicBezier.js.map +1 -0
- package/dist/easeElastic.d.ts +5 -0
- package/dist/easeElastic.d.ts.map +1 -0
- package/dist/easeElastic.js +22 -0
- package/dist/easeElastic.js.map +1 -0
- package/dist/easeExponential.d.ts +5 -0
- package/dist/easeExponential.d.ts.map +1 -0
- package/dist/easeExponential.js +8 -0
- package/dist/easeExponential.js.map +1 -0
- package/dist/easeLinear.d.ts +3 -0
- package/dist/easeLinear.d.ts.map +1 -0
- package/dist/easeLinear.js +2 -0
- package/dist/easeLinear.js.map +1 -0
- package/dist/easePiecewise.d.ts +3 -0
- package/dist/easePiecewise.d.ts.map +1 -0
- package/dist/easePiecewise.js +45 -0
- package/dist/easePiecewise.js.map +1 -0
- package/dist/easePower.d.ts +5 -0
- package/dist/easePower.d.ts.map +1 -0
- package/dist/easePower.js +24 -0
- package/dist/easePower.js.map +1 -0
- package/dist/easeQuadratic.d.ts +5 -0
- package/dist/easeQuadratic.d.ts.map +1 -0
- package/dist/easeQuadratic.js +4 -0
- package/dist/easeQuadratic.js.map +1 -0
- package/dist/easeQuartic.d.ts +5 -0
- package/dist/easeQuartic.d.ts.map +1 -0
- package/dist/easeQuartic.js +4 -0
- package/dist/easeQuartic.js.map +1 -0
- package/dist/easeQuintic.d.ts +5 -0
- package/dist/easeQuintic.d.ts.map +1 -0
- package/dist/easeQuintic.js +4 -0
- package/dist/easeQuintic.js.map +1 -0
- package/dist/easeSine.d.ts +5 -0
- package/dist/easeSine.d.ts.map +1 -0
- package/dist/easeSine.js +4 -0
- package/dist/easeSine.js.map +1 -0
- package/dist/easeSmoothstep.d.ts +5 -0
- package/dist/easeSmoothstep.d.ts.map +1 -0
- package/dist/easeSmoothstep.js +17 -0
- package/dist/easeSmoothstep.js.map +1 -0
- package/dist/easeSteps.d.ts +3 -0
- package/dist/easeSteps.d.ts.map +1 -0
- package/dist/easeSteps.js +27 -0
- package/dist/easeSteps.js.map +1 -0
- package/dist/getEasingDerivative.d.ts +3 -0
- package/dist/getEasingDerivative.d.ts.map +1 -0
- package/dist/getEasingDerivative.js +28 -0
- package/dist/getEasingDerivative.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/package.json +37 -0
- package/src/createEasingSamples.test.ts +51 -0
- package/src/easeBack.test.ts +30 -0
- package/src/easeBounce.test.ts +30 -0
- package/src/easeCircular.test.ts +44 -0
- package/src/easeCombinators.test.ts +119 -0
- package/src/easeCubic.test.ts +34 -0
- package/src/easeCubicBezier.test.ts +47 -0
- package/src/easeElastic.test.ts +30 -0
- package/src/easeExponential.test.ts +34 -0
- package/src/easeLinear.test.ts +17 -0
- package/src/easePiecewise.test.ts +58 -0
- package/src/easePower.test.ts +82 -0
- package/src/easeQuadratic.test.ts +34 -0
- package/src/easeQuartic.test.ts +34 -0
- package/src/easeQuintic.test.ts +34 -0
- package/src/easeSine.test.ts +34 -0
- package/src/easeSmoothstep.test.ts +76 -0
- package/src/easeSteps.test.ts +65 -0
- package/src/getEasingDerivative.test.ts +37 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Perlin's smootherstep: a higher-order variant with zero first- and
|
|
2
|
+
// second-derivatives at both endpoints, for a gentler approach to 0 and 1.
|
|
3
|
+
// Like the other families here, input is assumed pre-clamped to [0,1].
|
|
4
|
+
export const easeSmootherstep = (t) => t * t * t * (t * (t * 6 - 15) + 10);
|
|
5
|
+
// Hermite smoothstep: a sigmoid-like ease with zero first-derivative at both endpoints.
|
|
6
|
+
export const easeSmoothstep = (t) => t * t * (3 - 2 * t);
|
|
7
|
+
// Returns a smoothstep remap over an arbitrary domain [edge0, edge1].
|
|
8
|
+
// The returned function clamps its input to [edge0, edge1], maps to [0, 1],
|
|
9
|
+
// and applies the Hermite smoothstep. Unlike EasingFunction (domain [0,1]),
|
|
10
|
+
// the result is a ScalarRemap whose domain is [edge0, edge1].
|
|
11
|
+
export function easeSmoothstepRange(edge0, edge1) {
|
|
12
|
+
return (x) => {
|
|
13
|
+
const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));
|
|
14
|
+
return t * t * (3 - 2 * t);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=easeSmoothstep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"easeSmoothstep.js","sourceRoot":"","sources":["../src/easeSmoothstep.ts"],"names":[],"mappings":"AAEA,qEAAqE;AACrE,2EAA2E;AAC3E,uEAAuE;AACvE,MAAM,CAAC,MAAM,gBAAgB,GAAmB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;AAE3F,wFAAwF;AACxF,MAAM,CAAC,MAAM,cAAc,GAAmB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAEzE,sEAAsE;AACtE,4EAA4E;AAC5E,4EAA4E;AAC5E,8DAA8D;AAC9D,MAAM,UAAU,mBAAmB,CAAC,KAAa,EAAE,KAAa;IAC9D,OAAO,CAAC,CAAC,EAAE,EAAE;QACX,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7B,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"easeSteps.d.ts","sourceRoot":"","sources":["../src/easeSteps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAcpE,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,GAAE,YAAwB,GAAG,cAAc,CAc3F"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Returns a stepped easing function that quantizes [0,1] into `count` equal
|
|
2
|
+
// intervals, jumping at the position(s) selected by `position`:
|
|
3
|
+
// jumpStart - jump at t=0; the first interval already outputs 1/count.
|
|
4
|
+
// jumpEnd - jump at t=1 (default); output stays 0 over the first interval.
|
|
5
|
+
// jumpNone - no jump at either edge; output spans 0..1 with count-1 interior jumps.
|
|
6
|
+
// jumpBoth - jump at both edges; count+1 levels from 0 to 1 inclusive.
|
|
7
|
+
// Follows the CSS Easing Level 1 step algorithm.
|
|
8
|
+
//
|
|
9
|
+
// Sharp edge: easeSteps(1, 'jumpNone') has jumps = count - 1 = 0, so the returned
|
|
10
|
+
// function divides by zero and yields NaN. This mirrors the CSS spec, which forbids
|
|
11
|
+
// steps(1, jump-none) for the same reason. Callers must pass count >= 2 with
|
|
12
|
+
// 'jumpNone'; every other position is well-defined for count >= 1.
|
|
13
|
+
export function easeSteps(count, position = 'jumpEnd') {
|
|
14
|
+
const jumps = position === 'jumpNone' ? count - 1 : position === 'jumpBoth' ? count + 1 : count;
|
|
15
|
+
const startOffset = position === 'jumpStart' || position === 'jumpBoth' ? 1 : 0;
|
|
16
|
+
return (t) => {
|
|
17
|
+
let step = Math.floor(t * count) + startOffset;
|
|
18
|
+
if (t >= 0 && step < 0) {
|
|
19
|
+
step = 0;
|
|
20
|
+
}
|
|
21
|
+
if (t <= 1 && step > jumps) {
|
|
22
|
+
step = jumps;
|
|
23
|
+
}
|
|
24
|
+
return step / jumps;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=easeSteps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"easeSteps.js","sourceRoot":"","sources":["../src/easeSteps.ts"],"names":[],"mappings":"AAEA,4EAA4E;AAC5E,gEAAgE;AAChE,yEAAyE;AACzE,+EAA+E;AAC/E,uFAAuF;AACvF,0EAA0E;AAC1E,iDAAiD;AACjD,EAAE;AACF,kFAAkF;AAClF,oFAAoF;AACpF,6EAA6E;AAC7E,mEAAmE;AACnE,MAAM,UAAU,SAAS,CAAC,KAAa,EAAE,WAAyB,SAAS;IACzE,MAAM,KAAK,GAAG,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAChG,MAAM,WAAW,GAAG,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEhF,OAAO,CAAC,CAAC,EAAE,EAAE;QACX,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,WAAW,CAAC;QAC/C,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,CAAC;QACX,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;YAC3B,IAAI,GAAG,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,GAAG,KAAK,CAAC;IACtB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getEasingDerivative.d.ts","sourceRoot":"","sources":["../src/getEasingDerivative.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AActD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,cAAc,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,MAAuB,GAAG,MAAM,CAW7G"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Returns the numerical derivative (instantaneous velocity) of `ease` at the
|
|
2
|
+
// given `t` using a centered finite-difference approximation:
|
|
3
|
+
// (ease(t + epsilon) - ease(t - epsilon)) / (2 * epsilon)
|
|
4
|
+
//
|
|
5
|
+
// This is the slope of the easing curve at `t`, useful for handing off
|
|
6
|
+
// velocity when transitioning between animations (e.g. from a finishing tween
|
|
7
|
+
// to a starting spring). The endpoint boundary is handled by clamping: at
|
|
8
|
+
// `t ≤ epsilon` a forward difference is used; at `t ≥ 1 - epsilon` a backward
|
|
9
|
+
// difference is used.
|
|
10
|
+
//
|
|
11
|
+
// `epsilon` defaults to 1e-6. Pass a smaller value for smoother curves or a
|
|
12
|
+
// larger one for noisy/discretized curves. The function never throws.
|
|
13
|
+
export function getEasingDerivative(ease, t, epsilon = defaultEpsilon) {
|
|
14
|
+
if (t <= epsilon) {
|
|
15
|
+
// Forward difference at the left boundary.
|
|
16
|
+
return (ease(epsilon * 2) - ease(0)) / (epsilon * 2);
|
|
17
|
+
}
|
|
18
|
+
if (t >= 1 - epsilon) {
|
|
19
|
+
// Backward difference at the right boundary.
|
|
20
|
+
return (ease(1) - ease(1 - epsilon * 2)) / (epsilon * 2);
|
|
21
|
+
}
|
|
22
|
+
// Central difference in the interior.
|
|
23
|
+
return (ease(t + epsilon) - ease(t - epsilon)) / (2 * epsilon);
|
|
24
|
+
}
|
|
25
|
+
// Default step size for numerical differentiation. Small enough for smooth
|
|
26
|
+
// curves but large enough to avoid cancellation errors in Float64.
|
|
27
|
+
const defaultEpsilon = 1e-6;
|
|
28
|
+
//# sourceMappingURL=getEasingDerivative.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getEasingDerivative.js","sourceRoot":"","sources":["../src/getEasingDerivative.ts"],"names":[],"mappings":"AAEA,6EAA6E;AAC7E,8DAA8D;AAC9D,4DAA4D;AAC5D,EAAE;AACF,uEAAuE;AACvE,8EAA8E;AAC9E,0EAA0E;AAC1E,8EAA8E;AAC9E,sBAAsB;AACtB,EAAE;AACF,4EAA4E;AAC5E,sEAAsE;AACtE,MAAM,UAAU,mBAAmB,CAAC,IAAoB,EAAE,CAAS,EAAE,UAAkB,cAAc;IACnG,IAAI,CAAC,IAAI,OAAO,EAAE,CAAC;QACjB,2CAA2C;QAC3C,OAAO,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,EAAE,CAAC;QACrB,6CAA6C;QAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,sCAAsC;IACtC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC;AACjE,CAAC;AAED,2EAA2E;AAC3E,mEAAmE;AACnE,MAAM,cAAc,GAAG,IAAI,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export * from './createEasingSamples';
|
|
2
|
+
export * from './easeBack';
|
|
3
|
+
export * from './easeBounce';
|
|
4
|
+
export * from './easeCircular';
|
|
5
|
+
export * from './easeCombinators';
|
|
6
|
+
export * from './easeCubic';
|
|
7
|
+
export * from './easeCubicBezier';
|
|
8
|
+
export * from './easeElastic';
|
|
9
|
+
export * from './easeExponential';
|
|
10
|
+
export * from './easeLinear';
|
|
11
|
+
export * from './easePiecewise';
|
|
12
|
+
export * from './easePower';
|
|
13
|
+
export * from './easeQuadratic';
|
|
14
|
+
export * from './easeQuartic';
|
|
15
|
+
export * from './easeQuintic';
|
|
16
|
+
export * from './easeSine';
|
|
17
|
+
export * from './easeSmoothstep';
|
|
18
|
+
export * from './easeSteps';
|
|
19
|
+
export * from './getEasingDerivative';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export * from './createEasingSamples';
|
|
2
|
+
export * from './easeBack';
|
|
3
|
+
export * from './easeBounce';
|
|
4
|
+
export * from './easeCircular';
|
|
5
|
+
export * from './easeCombinators';
|
|
6
|
+
export * from './easeCubic';
|
|
7
|
+
export * from './easeCubicBezier';
|
|
8
|
+
export * from './easeElastic';
|
|
9
|
+
export * from './easeExponential';
|
|
10
|
+
export * from './easeLinear';
|
|
11
|
+
export * from './easePiecewise';
|
|
12
|
+
export * from './easePower';
|
|
13
|
+
export * from './easeQuadratic';
|
|
14
|
+
export * from './easeQuartic';
|
|
15
|
+
export * from './easeQuintic';
|
|
16
|
+
export * from './easeSine';
|
|
17
|
+
export * from './easeSmoothstep';
|
|
18
|
+
export * from './easeSteps';
|
|
19
|
+
export * from './getEasingDerivative';
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flighthq/easing",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"src/**/*.test.ts",
|
|
16
|
+
"!dist/**/*.test.js",
|
|
17
|
+
"!dist/**/*.test.d.ts",
|
|
18
|
+
"!dist/**/*.test.js.map",
|
|
19
|
+
"!dist/**/*.test.d.ts.map"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -b",
|
|
23
|
+
"clean": "tsc -b --clean",
|
|
24
|
+
"test": "vitest run --config vitest.config.ts",
|
|
25
|
+
"test:watch": "vitest --watch --config vitest.config.ts",
|
|
26
|
+
"prepack": "npm run clean && npm run clean:dist && npm run build",
|
|
27
|
+
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@flighthq/types": "0.1.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"typescript": "^5.3.0"
|
|
34
|
+
},
|
|
35
|
+
"description": "Easing functions for animation",
|
|
36
|
+
"sideEffects": false
|
|
37
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createEasingSamples } from './createEasingSamples';
|
|
2
|
+
import { easeInCubic } from './easeCubic';
|
|
3
|
+
import { easeLinear } from './easeLinear';
|
|
4
|
+
|
|
5
|
+
describe('createEasingSamples', () => {
|
|
6
|
+
it('throws for count < 1', () => {
|
|
7
|
+
expect(() => createEasingSamples(easeLinear, 0)).toThrow();
|
|
8
|
+
expect(() => createEasingSamples(easeLinear, -1)).toThrow();
|
|
9
|
+
});
|
|
10
|
+
it('throws for non-finite count', () => {
|
|
11
|
+
expect(() => createEasingSamples(easeLinear, Infinity)).toThrow();
|
|
12
|
+
expect(() => createEasingSamples(easeLinear, NaN)).toThrow();
|
|
13
|
+
});
|
|
14
|
+
it('allocates a Float32Array when out is omitted', () => {
|
|
15
|
+
const result = createEasingSamples(easeLinear, 5);
|
|
16
|
+
expect(result).toBeInstanceOf(Float32Array);
|
|
17
|
+
expect(result.length).toBe(5);
|
|
18
|
+
});
|
|
19
|
+
it('writes into the provided out array and returns it', () => {
|
|
20
|
+
const out = new Float32Array(5);
|
|
21
|
+
const result = createEasingSamples(easeLinear, 5, out);
|
|
22
|
+
expect(result).toBe(out);
|
|
23
|
+
});
|
|
24
|
+
it('first sample is ease(0) and last is ease(1)', () => {
|
|
25
|
+
const result = createEasingSamples(easeInCubic, 11);
|
|
26
|
+
expect(result[0]).toBeCloseTo(easeInCubic(0));
|
|
27
|
+
expect(result[10]).toBeCloseTo(easeInCubic(1));
|
|
28
|
+
});
|
|
29
|
+
it('samples easeLinear uniformly: result[i] ≈ i/(count-1)', () => {
|
|
30
|
+
const count = 6;
|
|
31
|
+
const result = createEasingSamples(easeLinear, count);
|
|
32
|
+
for (let i = 0; i < count; i++) {
|
|
33
|
+
expect(result[i]).toBeCloseTo(i / (count - 1), 5);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
it('count=1 samples at the midpoint (t=0.5)', () => {
|
|
37
|
+
const result = createEasingSamples(easeInCubic, 1);
|
|
38
|
+
expect(result[0]).toBeCloseTo(easeInCubic(0.5));
|
|
39
|
+
});
|
|
40
|
+
it('is alias-safe: out can be any Float32Array length >= count', () => {
|
|
41
|
+
const out = new Float32Array(10);
|
|
42
|
+
const result = createEasingSamples(easeLinear, 5, out);
|
|
43
|
+
// Only the first 5 entries are written; the rest are still 0.
|
|
44
|
+
expect(result[4]).toBeCloseTo(1);
|
|
45
|
+
expect(result[5]).toBe(0);
|
|
46
|
+
});
|
|
47
|
+
it('floor(count) is used for fractional counts', () => {
|
|
48
|
+
const result = createEasingSamples(easeLinear, 5.9);
|
|
49
|
+
expect(result.length).toBe(5);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { easeInBack, easeInOutBack, easeOutBack } from './easeBack';
|
|
2
|
+
|
|
3
|
+
describe('easeInBack', () => {
|
|
4
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
5
|
+
expect(easeInBack(0)).toBeCloseTo(0);
|
|
6
|
+
expect(easeInBack(1)).toBeCloseTo(1);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('undershoots below 0 before settling', () => {
|
|
10
|
+
expect(easeInBack(0.3)).toBeLessThan(0);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('easeInOutBack', () => {
|
|
15
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
16
|
+
expect(easeInOutBack(0)).toBeCloseTo(0);
|
|
17
|
+
expect(easeInOutBack(1)).toBeCloseTo(1);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('easeOutBack', () => {
|
|
22
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
23
|
+
expect(easeOutBack(0)).toBeCloseTo(0);
|
|
24
|
+
expect(easeOutBack(1)).toBeCloseTo(1);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('overshoots past 1 before settling', () => {
|
|
28
|
+
expect(easeOutBack(0.7)).toBeGreaterThan(1);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { easeInBounce, easeInOutBounce, easeOutBounce } from './easeBounce';
|
|
2
|
+
|
|
3
|
+
describe('easeInBounce', () => {
|
|
4
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
5
|
+
expect(easeInBounce(0)).toBeCloseTo(0);
|
|
6
|
+
expect(easeInBounce(1)).toBeCloseTo(1);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('is slow at start (value below 0.5 at midpoint)', () => {
|
|
10
|
+
expect(easeInBounce(0.5)).toBeLessThan(0.5);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('easeInOutBounce', () => {
|
|
15
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
16
|
+
expect(easeInOutBounce(0)).toBeCloseTo(0);
|
|
17
|
+
expect(easeInOutBounce(1)).toBeCloseTo(1);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('easeOutBounce', () => {
|
|
22
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
23
|
+
expect(easeOutBounce(0)).toBeCloseTo(0);
|
|
24
|
+
expect(easeOutBounce(1)).toBeCloseTo(1);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('is fast at start (value above 0.5 at midpoint)', () => {
|
|
28
|
+
expect(easeOutBounce(0.5)).toBeGreaterThan(0.5);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { easeInCircular, easeInOutCircular, easeOutCircular } from './easeCircular';
|
|
2
|
+
|
|
3
|
+
describe('easeInCircular', () => {
|
|
4
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
5
|
+
expect(easeInCircular(0)).toBeCloseTo(0);
|
|
6
|
+
expect(easeInCircular(1)).toBeCloseTo(1);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('is slow at start (value below 0.5 at midpoint)', () => {
|
|
10
|
+
expect(easeInCircular(0.5)).toBeLessThan(0.5);
|
|
11
|
+
expect(easeInCircular(0.5)).toBeCloseTo(1 - Math.sqrt(0.75));
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('is monotonically increasing', () => {
|
|
15
|
+
let prev = easeInCircular(0);
|
|
16
|
+
for (let i = 1; i <= 20; i++) {
|
|
17
|
+
const value = easeInCircular(i / 20);
|
|
18
|
+
expect(value).toBeGreaterThanOrEqual(prev);
|
|
19
|
+
prev = value;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('easeInOutCircular', () => {
|
|
25
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
26
|
+
expect(easeInOutCircular(0)).toBeCloseTo(0);
|
|
27
|
+
expect(easeInOutCircular(1)).toBeCloseTo(1);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('is symmetric at midpoint', () => {
|
|
31
|
+
expect(easeInOutCircular(0.5)).toBeCloseTo(0.5);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('easeOutCircular', () => {
|
|
36
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
37
|
+
expect(easeOutCircular(0)).toBeCloseTo(0);
|
|
38
|
+
expect(easeOutCircular(1)).toBeCloseTo(1);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('is fast at start (value above 0.5 at midpoint)', () => {
|
|
42
|
+
expect(easeOutCircular(0.5)).toBeGreaterThan(0.5);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { easeClamp, easeClampOutput, easeInvert, easeMirror, easeReverse, easeScaleOutput } from './easeCombinators';
|
|
2
|
+
import { easeInCubic, easeOutCubic } from './easeCubic';
|
|
3
|
+
|
|
4
|
+
describe('easeClamp', () => {
|
|
5
|
+
it('passes through values already in [0,1]', () => {
|
|
6
|
+
const clamped = easeClamp(easeInCubic);
|
|
7
|
+
expect(clamped(0)).toBeCloseTo(easeInCubic(0));
|
|
8
|
+
expect(clamped(0.5)).toBeCloseTo(easeInCubic(0.5));
|
|
9
|
+
expect(clamped(1)).toBeCloseTo(easeInCubic(1));
|
|
10
|
+
});
|
|
11
|
+
it('clamps negative t to 0', () => {
|
|
12
|
+
const clamped = easeClamp(easeInCubic);
|
|
13
|
+
expect(clamped(-0.5)).toBeCloseTo(easeInCubic(0));
|
|
14
|
+
});
|
|
15
|
+
it('clamps t above 1 to 1', () => {
|
|
16
|
+
const clamped = easeClamp(easeInCubic);
|
|
17
|
+
expect(clamped(1.5)).toBeCloseTo(easeInCubic(1));
|
|
18
|
+
});
|
|
19
|
+
it('is safe when composed: easeClamp(easeClamp(fn))', () => {
|
|
20
|
+
const double = easeClamp(easeClamp(easeInCubic));
|
|
21
|
+
expect(double(-1)).toBeCloseTo(easeInCubic(0));
|
|
22
|
+
expect(double(2)).toBeCloseTo(easeInCubic(1));
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('easeClampOutput', () => {
|
|
27
|
+
it('does not clamp when output is within range', () => {
|
|
28
|
+
const fn = easeClampOutput(easeInCubic, 0, 1);
|
|
29
|
+
expect(fn(0.5)).toBeCloseTo(easeInCubic(0.5));
|
|
30
|
+
});
|
|
31
|
+
it('clamps output below min', () => {
|
|
32
|
+
// a constant function returning -0.5 for the test
|
|
33
|
+
const below = easeClampOutput(() => -0.5, 0, 1);
|
|
34
|
+
expect(below(0.5)).toBe(0);
|
|
35
|
+
});
|
|
36
|
+
it('clamps output above max', () => {
|
|
37
|
+
const above = easeClampOutput(() => 1.5, 0, 1);
|
|
38
|
+
expect(above(0.5)).toBe(1);
|
|
39
|
+
});
|
|
40
|
+
it('respects custom range', () => {
|
|
41
|
+
const fn = easeClampOutput(easeInCubic, 0.2, 0.8);
|
|
42
|
+
expect(fn(0)).toBe(0.2);
|
|
43
|
+
expect(fn(1)).toBe(0.8);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('easeInvert', () => {
|
|
48
|
+
it('maps 0 to 1 and 1 to 0', () => {
|
|
49
|
+
const inv = easeInvert(easeInCubic);
|
|
50
|
+
expect(inv(0)).toBeCloseTo(1);
|
|
51
|
+
expect(inv(1)).toBeCloseTo(0);
|
|
52
|
+
});
|
|
53
|
+
it('is the vertical mirror: easeInvert(f)(t) = 1 - f(t)', () => {
|
|
54
|
+
const inv = easeInvert(easeInCubic);
|
|
55
|
+
expect(inv(0.5)).toBeCloseTo(1 - easeInCubic(0.5));
|
|
56
|
+
expect(inv(0.3)).toBeCloseTo(1 - easeInCubic(0.3));
|
|
57
|
+
});
|
|
58
|
+
it('double inversion is the identity', () => {
|
|
59
|
+
const id = easeInvert(easeInvert(easeInCubic));
|
|
60
|
+
expect(id(0.4)).toBeCloseTo(easeInCubic(0.4));
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('easeMirror', () => {
|
|
65
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
66
|
+
const fn = easeMirror(easeInCubic);
|
|
67
|
+
expect(fn(0)).toBeCloseTo(0);
|
|
68
|
+
expect(fn(1)).toBeCloseTo(1);
|
|
69
|
+
});
|
|
70
|
+
it('passes through 0.5 at t=0.5', () => {
|
|
71
|
+
const fn = easeMirror(easeInCubic);
|
|
72
|
+
expect(fn(0.5)).toBeCloseTo(0.5);
|
|
73
|
+
});
|
|
74
|
+
it('is symmetric: f(t) + f(1-t) = 1', () => {
|
|
75
|
+
const fn = easeMirror(easeInCubic);
|
|
76
|
+
expect(fn(0.3) + fn(0.7)).toBeCloseTo(1);
|
|
77
|
+
expect(fn(0.1) + fn(0.9)).toBeCloseTo(1);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('easeReverse', () => {
|
|
82
|
+
it('converts an In curve to an Out curve: f(t) = 1 - easeIn(1 - t)', () => {
|
|
83
|
+
const reversed = easeReverse(easeInCubic);
|
|
84
|
+
expect(reversed(0.3)).toBeCloseTo(1 - easeInCubic(0.7));
|
|
85
|
+
expect(reversed(0.7)).toBeCloseTo(1 - easeInCubic(0.3));
|
|
86
|
+
});
|
|
87
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
88
|
+
const reversed = easeReverse(easeInCubic);
|
|
89
|
+
expect(reversed(0)).toBeCloseTo(0);
|
|
90
|
+
expect(reversed(1)).toBeCloseTo(1);
|
|
91
|
+
});
|
|
92
|
+
it('easeReverse(easeInCubic) approximates easeOutCubic', () => {
|
|
93
|
+
const reversed = easeReverse(easeInCubic);
|
|
94
|
+
expect(reversed(0.5)).toBeCloseTo(easeOutCubic(0.5), 10);
|
|
95
|
+
expect(reversed(0.3)).toBeCloseTo(easeOutCubic(0.3), 10);
|
|
96
|
+
});
|
|
97
|
+
it('double reverse is the identity', () => {
|
|
98
|
+
const id = easeReverse(easeReverse(easeInCubic));
|
|
99
|
+
expect(id(0.4)).toBeCloseTo(easeInCubic(0.4));
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('easeScaleOutput', () => {
|
|
104
|
+
it('maps [0,1] output to [fromValue, toValue]', () => {
|
|
105
|
+
const fn = easeScaleOutput(easeInCubic, 100, 300);
|
|
106
|
+
expect(fn(0)).toBeCloseTo(100);
|
|
107
|
+
expect(fn(1)).toBeCloseTo(300);
|
|
108
|
+
expect(fn(0.5)).toBeCloseTo(100 + easeInCubic(0.5) * 200);
|
|
109
|
+
});
|
|
110
|
+
it('handles inverted ranges (toValue < fromValue)', () => {
|
|
111
|
+
const fn = easeScaleOutput(easeInCubic, 300, 100);
|
|
112
|
+
expect(fn(0)).toBeCloseTo(300);
|
|
113
|
+
expect(fn(1)).toBeCloseTo(100);
|
|
114
|
+
});
|
|
115
|
+
it('is alias-safe: same result when composed', () => {
|
|
116
|
+
const fn = easeScaleOutput(easeInCubic, 0, 1);
|
|
117
|
+
expect(fn(0.5)).toBeCloseTo(easeInCubic(0.5));
|
|
118
|
+
});
|
|
119
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { easeInCubic, easeInOutCubic, easeOutCubic } from './easeCubic';
|
|
2
|
+
|
|
3
|
+
describe('easeInCubic', () => {
|
|
4
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
5
|
+
expect(easeInCubic(0)).toBe(0);
|
|
6
|
+
expect(easeInCubic(1)).toBe(1);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('is slow at start (value below 0.5 at midpoint)', () => {
|
|
10
|
+
expect(easeInCubic(0.5)).toBeLessThan(0.5);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('easeInOutCubic', () => {
|
|
15
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
16
|
+
expect(easeInOutCubic(0)).toBe(0);
|
|
17
|
+
expect(easeInOutCubic(1)).toBe(1);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('is symmetric at midpoint', () => {
|
|
21
|
+
expect(easeInOutCubic(0.5)).toBeCloseTo(0.5);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('easeOutCubic', () => {
|
|
26
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
27
|
+
expect(easeOutCubic(0)).toBe(0);
|
|
28
|
+
expect(easeOutCubic(1)).toBe(1);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('is fast at start (value above 0.5 at midpoint)', () => {
|
|
32
|
+
expect(easeOutCubic(0.5)).toBeGreaterThan(0.5);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { easeCubicBezier } from './easeCubicBezier';
|
|
2
|
+
|
|
3
|
+
describe('easeCubicBezier', () => {
|
|
4
|
+
it('returns exact endpoints regardless of control points', () => {
|
|
5
|
+
const ease = easeCubicBezier(0.25, 0.1, 0.25, 1.0);
|
|
6
|
+
expect(ease(0)).toBe(0);
|
|
7
|
+
expect(ease(1)).toBe(1);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('clamps out-of-range input to the endpoints', () => {
|
|
11
|
+
const ease = easeCubicBezier(0.42, 0, 0.58, 1);
|
|
12
|
+
expect(ease(-0.5)).toBe(0);
|
|
13
|
+
expect(ease(1.5)).toBe(1);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('approximates the identity for the diagonal control points', () => {
|
|
17
|
+
const linear = easeCubicBezier(0, 0, 1, 1);
|
|
18
|
+
for (let i = 0; i <= 10; i++) {
|
|
19
|
+
const t = i / 10;
|
|
20
|
+
expect(linear(t)).toBeCloseTo(t, 3);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('matches the CSS "ease" curve at a sampled point', () => {
|
|
25
|
+
const ease = easeCubicBezier(0.25, 0.1, 0.25, 1.0);
|
|
26
|
+
// The CSS default "ease" front-loads progress; at the midpoint it is well
|
|
27
|
+
// ahead of linear. Reference value from a WebKit UnitBezier evaluation.
|
|
28
|
+
expect(ease(0.5)).toBeCloseTo(0.8024, 2);
|
|
29
|
+
expect(ease(0.5)).toBeGreaterThan(0.5);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('is monotonically non-decreasing across the interval', () => {
|
|
33
|
+
const ease = easeCubicBezier(0.25, 0.1, 0.25, 1.0);
|
|
34
|
+
let prev = ease(0);
|
|
35
|
+
for (let i = 1; i <= 50; i++) {
|
|
36
|
+
const value = ease(i / 50);
|
|
37
|
+
expect(value).toBeGreaterThanOrEqual(prev - 1e-6);
|
|
38
|
+
prev = value;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('inverts x correctly for an asymmetric curve', () => {
|
|
43
|
+
const ease = easeCubicBezier(0.42, 0, 0.58, 1);
|
|
44
|
+
// ease-in-out is symmetric about the midpoint.
|
|
45
|
+
expect(ease(0.5)).toBeCloseTo(0.5, 2);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { easeInElastic, easeInOutElastic, easeOutElastic } from './easeElastic';
|
|
2
|
+
|
|
3
|
+
describe('easeInElastic', () => {
|
|
4
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
5
|
+
expect(easeInElastic(0)).toBe(0);
|
|
6
|
+
expect(easeInElastic(1)).toBe(1);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('oscillates below 0 before reaching target', () => {
|
|
10
|
+
expect(easeInElastic(0.8)).toBeLessThan(0);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('easeInOutElastic', () => {
|
|
15
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
16
|
+
expect(easeInOutElastic(0)).toBe(0);
|
|
17
|
+
expect(easeInOutElastic(1)).toBe(1);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('easeOutElastic', () => {
|
|
22
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
23
|
+
expect(easeOutElastic(0)).toBe(0);
|
|
24
|
+
expect(easeOutElastic(1)).toBe(1);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('oscillates past 1 near the end', () => {
|
|
28
|
+
expect(easeOutElastic(0.6)).toBeGreaterThan(1);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { easeInExponential, easeInOutExponential, easeOutExponential } from './easeExponential';
|
|
2
|
+
|
|
3
|
+
describe('easeInExponential', () => {
|
|
4
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
5
|
+
expect(easeInExponential(0)).toBe(0);
|
|
6
|
+
expect(easeInExponential(1)).toBeCloseTo(1);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('is slow at start (value below 0.5 at midpoint)', () => {
|
|
10
|
+
expect(easeInExponential(0.5)).toBeLessThan(0.5);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('easeInOutExponential', () => {
|
|
15
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
16
|
+
expect(easeInOutExponential(0)).toBe(0);
|
|
17
|
+
expect(easeInOutExponential(1)).toBe(1);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('is symmetric at midpoint', () => {
|
|
21
|
+
expect(easeInOutExponential(0.5)).toBeCloseTo(0.5);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('easeOutExponential', () => {
|
|
26
|
+
it('returns 0 at t=0 and 1 at t=1', () => {
|
|
27
|
+
expect(easeOutExponential(0)).toBeCloseTo(0);
|
|
28
|
+
expect(easeOutExponential(1)).toBe(1);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('is fast at start (value above 0.5 at midpoint)', () => {
|
|
32
|
+
expect(easeOutExponential(0.5)).toBeGreaterThan(0.5);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { easeLinear } from './easeLinear';
|
|
2
|
+
|
|
3
|
+
describe('easeLinear', () => {
|
|
4
|
+
it('returns 0 at t=0', () => {
|
|
5
|
+
expect(easeLinear(0)).toBe(0);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('returns 1 at t=1', () => {
|
|
9
|
+
expect(easeLinear(1)).toBe(1);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('returns t unchanged', () => {
|
|
13
|
+
expect(easeLinear(0.5)).toBe(0.5);
|
|
14
|
+
expect(easeLinear(0.25)).toBe(0.25);
|
|
15
|
+
expect(easeLinear(0.75)).toBe(0.75);
|
|
16
|
+
});
|
|
17
|
+
});
|