@vysmo/easings 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 (198) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +368 -0
  3. package/dist/builders/anticipate.d.ts +20 -0
  4. package/dist/builders/anticipate.d.ts.map +1 -0
  5. package/dist/builders/anticipate.js +52 -0
  6. package/dist/builders/anticipate.js.map +1 -0
  7. package/dist/builders/bezier.d.ts +7 -0
  8. package/dist/builders/bezier.d.ts.map +1 -0
  9. package/dist/builders/bezier.js +69 -0
  10. package/dist/builders/bezier.js.map +1 -0
  11. package/dist/builders/breathe.d.ts +11 -0
  12. package/dist/builders/breathe.d.ts.map +1 -0
  13. package/dist/builders/breathe.js +14 -0
  14. package/dist/builders/breathe.js.map +1 -0
  15. package/dist/builders/custom.d.ts +13 -0
  16. package/dist/builders/custom.d.ts.map +1 -0
  17. package/dist/builders/custom.js +40 -0
  18. package/dist/builders/custom.js.map +1 -0
  19. package/dist/builders/expoScale.d.ts +13 -0
  20. package/dist/builders/expoScale.d.ts.map +1 -0
  21. package/dist/builders/expoScale.js +27 -0
  22. package/dist/builders/expoScale.js.map +1 -0
  23. package/dist/builders/gravity.d.ts +12 -0
  24. package/dist/builders/gravity.d.ts.map +1 -0
  25. package/dist/builders/gravity.js +11 -0
  26. package/dist/builders/gravity.js.map +1 -0
  27. package/dist/builders/index.d.ts +12 -0
  28. package/dist/builders/index.d.ts.map +1 -0
  29. package/dist/builders/index.js +12 -0
  30. package/dist/builders/index.js.map +1 -0
  31. package/dist/builders/rough.d.ts +17 -0
  32. package/dist/builders/rough.d.ts.map +1 -0
  33. package/dist/builders/rough.js +62 -0
  34. package/dist/builders/rough.js.map +1 -0
  35. package/dist/builders/slow.d.ts +16 -0
  36. package/dist/builders/slow.d.ts.map +1 -0
  37. package/dist/builders/slow.js +59 -0
  38. package/dist/builders/slow.js.map +1 -0
  39. package/dist/builders/spring-presets.d.ts +48 -0
  40. package/dist/builders/spring-presets.d.ts.map +1 -0
  41. package/dist/builders/spring-presets.js +19 -0
  42. package/dist/builders/spring-presets.js.map +1 -0
  43. package/dist/builders/spring.d.ts +12 -0
  44. package/dist/builders/spring.d.ts.map +1 -0
  45. package/dist/builders/spring.js +46 -0
  46. package/dist/builders/spring.js.map +1 -0
  47. package/dist/builders/wiggle.d.ts +9 -0
  48. package/dist/builders/wiggle.d.ts.map +1 -0
  49. package/dist/builders/wiggle.js +23 -0
  50. package/dist/builders/wiggle.js.map +1 -0
  51. package/dist/css.d.ts +40 -0
  52. package/dist/css.d.ts.map +1 -0
  53. package/dist/css.js +71 -0
  54. package/dist/css.js.map +1 -0
  55. package/dist/define.d.ts +12 -0
  56. package/dist/define.d.ts.map +1 -0
  57. package/dist/define.js +31 -0
  58. package/dist/define.js.map +1 -0
  59. package/dist/easings/back.d.ts +8 -0
  60. package/dist/easings/back.d.ts.map +1 -0
  61. package/dist/easings/back.js +20 -0
  62. package/dist/easings/back.js.map +1 -0
  63. package/dist/easings/bounce.d.ts +4 -0
  64. package/dist/easings/bounce.d.ts.map +1 -0
  65. package/dist/easings/bounce.js +21 -0
  66. package/dist/easings/bounce.js.map +1 -0
  67. package/dist/easings/circ.d.ts +4 -0
  68. package/dist/easings/circ.d.ts.map +1 -0
  69. package/dist/easings/circ.js +7 -0
  70. package/dist/easings/circ.js.map +1 -0
  71. package/dist/easings/elastic.d.ts +9 -0
  72. package/dist/easings/elastic.d.ts.map +1 -0
  73. package/dist/easings/elastic.js +33 -0
  74. package/dist/easings/elastic.js.map +1 -0
  75. package/dist/easings/expo.d.ts +4 -0
  76. package/dist/easings/expo.d.ts.map +1 -0
  77. package/dist/easings/expo.js +11 -0
  78. package/dist/easings/expo.js.map +1 -0
  79. package/dist/easings/index.d.ts +11 -0
  80. package/dist/easings/index.d.ts.map +1 -0
  81. package/dist/easings/index.js +11 -0
  82. package/dist/easings/index.js.map +1 -0
  83. package/dist/easings/linear.d.ts +3 -0
  84. package/dist/easings/linear.d.ts.map +1 -0
  85. package/dist/easings/linear.js +4 -0
  86. package/dist/easings/linear.js.map +1 -0
  87. package/dist/easings/power.d.ts +25 -0
  88. package/dist/easings/power.d.ts.map +1 -0
  89. package/dist/easings/power.js +29 -0
  90. package/dist/easings/power.js.map +1 -0
  91. package/dist/easings/sine.d.ts +4 -0
  92. package/dist/easings/sine.d.ts.map +1 -0
  93. package/dist/easings/sine.js +6 -0
  94. package/dist/easings/sine.js.map +1 -0
  95. package/dist/easings/smooth.d.ts +4 -0
  96. package/dist/easings/smooth.d.ts.map +1 -0
  97. package/dist/easings/smooth.js +21 -0
  98. package/dist/easings/smooth.js.map +1 -0
  99. package/dist/easings/steps.d.ts +8 -0
  100. package/dist/easings/steps.d.ts.map +1 -0
  101. package/dist/easings/steps.js +16 -0
  102. package/dist/easings/steps.js.map +1 -0
  103. package/dist/index.d.ts +10 -0
  104. package/dist/index.d.ts.map +1 -0
  105. package/dist/index.js +8 -0
  106. package/dist/index.js.map +1 -0
  107. package/dist/modifiers/blend.d.ts +13 -0
  108. package/dist/modifiers/blend.d.ts.map +1 -0
  109. package/dist/modifiers/blend.js +21 -0
  110. package/dist/modifiers/blend.js.map +1 -0
  111. package/dist/modifiers/chain.d.ts +18 -0
  112. package/dist/modifiers/chain.d.ts.map +1 -0
  113. package/dist/modifiers/chain.js +40 -0
  114. package/dist/modifiers/chain.js.map +1 -0
  115. package/dist/modifiers/index.d.ts +7 -0
  116. package/dist/modifiers/index.d.ts.map +1 -0
  117. package/dist/modifiers/index.js +7 -0
  118. package/dist/modifiers/index.js.map +1 -0
  119. package/dist/modifiers/mirror.d.ts +8 -0
  120. package/dist/modifiers/mirror.d.ts.map +1 -0
  121. package/dist/modifiers/mirror.js +14 -0
  122. package/dist/modifiers/mirror.js.map +1 -0
  123. package/dist/modifiers/reverse.d.ts +4 -0
  124. package/dist/modifiers/reverse.d.ts.map +1 -0
  125. package/dist/modifiers/reverse.js +6 -0
  126. package/dist/modifiers/reverse.js.map +1 -0
  127. package/dist/modifiers/slice.d.ts +11 -0
  128. package/dist/modifiers/slice.d.ts.map +1 -0
  129. package/dist/modifiers/slice.js +28 -0
  130. package/dist/modifiers/slice.js.map +1 -0
  131. package/dist/modifiers/yoyo.d.ts +8 -0
  132. package/dist/modifiers/yoyo.d.ts.map +1 -0
  133. package/dist/modifiers/yoyo.js +10 -0
  134. package/dist/modifiers/yoyo.js.map +1 -0
  135. package/dist/parse.d.ts +14 -0
  136. package/dist/parse.d.ts.map +1 -0
  137. package/dist/parse.js +108 -0
  138. package/dist/parse.js.map +1 -0
  139. package/dist/reduced-motion.d.ts +17 -0
  140. package/dist/reduced-motion.d.ts.map +1 -0
  141. package/dist/reduced-motion.js +24 -0
  142. package/dist/reduced-motion.js.map +1 -0
  143. package/dist/types.d.ts +8 -0
  144. package/dist/types.d.ts.map +1 -0
  145. package/dist/types.js +2 -0
  146. package/dist/types.js.map +1 -0
  147. package/package.json +63 -0
  148. package/src/__tests__/anticipate-variants.test.ts +58 -0
  149. package/src/__tests__/builders.test.ts +349 -0
  150. package/src/__tests__/contract.test.ts +47 -0
  151. package/src/__tests__/css.test.ts +93 -0
  152. package/src/__tests__/easings.bench.ts +66 -0
  153. package/src/__tests__/endpoint-correctness.test.ts +170 -0
  154. package/src/__tests__/modifiers.test.ts +134 -0
  155. package/src/__tests__/parametric.test.ts +148 -0
  156. package/src/__tests__/parse.test.ts +71 -0
  157. package/src/__tests__/property.test.ts +110 -0
  158. package/src/__tests__/reduced-motion.test.ts +66 -0
  159. package/src/__tests__/slice.test.ts +38 -0
  160. package/src/__tests__/spring-presets.test.ts +48 -0
  161. package/src/__tests__/ssr.test.ts +62 -0
  162. package/src/__tests__/types-check.ts +104 -0
  163. package/src/builders/anticipate.ts +66 -0
  164. package/src/builders/bezier.ts +71 -0
  165. package/src/builders/breathe.ts +31 -0
  166. package/src/builders/custom.ts +43 -0
  167. package/src/builders/expoScale.ts +30 -0
  168. package/src/builders/gravity.ts +27 -0
  169. package/src/builders/index.ts +24 -0
  170. package/src/builders/rough.ts +83 -0
  171. package/src/builders/slow.ts +72 -0
  172. package/src/builders/spring-presets.ts +20 -0
  173. package/src/builders/spring.ts +61 -0
  174. package/src/builders/wiggle.ts +40 -0
  175. package/src/css.ts +79 -0
  176. package/src/define.ts +49 -0
  177. package/src/easings/back.ts +24 -0
  178. package/src/easings/bounce.ts +23 -0
  179. package/src/easings/circ.ts +9 -0
  180. package/src/easings/elastic.ts +52 -0
  181. package/src/easings/expo.ts +9 -0
  182. package/src/easings/index.ts +35 -0
  183. package/src/easings/linear.ts +4 -0
  184. package/src/easings/power.ts +38 -0
  185. package/src/easings/sine.ts +7 -0
  186. package/src/easings/smooth.ts +25 -0
  187. package/src/easings/steps.ts +25 -0
  188. package/src/index.ts +9 -0
  189. package/src/modifiers/blend.ts +24 -0
  190. package/src/modifiers/chain.ts +63 -0
  191. package/src/modifiers/index.ts +6 -0
  192. package/src/modifiers/mirror.ts +14 -0
  193. package/src/modifiers/reverse.ts +7 -0
  194. package/src/modifiers/slice.ts +29 -0
  195. package/src/modifiers/yoyo.ts +15 -0
  196. package/src/parse.ts +167 -0
  197. package/src/reduced-motion.ts +26 -0
  198. package/src/types.ts +8 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/modifiers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { reverse } from "./reverse.js";
2
+ export { mirror } from "./mirror.js";
3
+ export { yoyo } from "./yoyo.js";
4
+ export { chain } from "./chain.js";
5
+ export { blend, compose } from "./blend.js";
6
+ export { slice } from "./slice.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/modifiers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAqB,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { EasingFn } from "../types.js";
2
+ /**
3
+ * Mirror an ease across the midpoint. The first half plays the ease forward,
4
+ * scaled into [0, 0.5]; the second half plays it reversed, scaled into
5
+ * [0.5, 1]. Turns any ease into its inOut variant.
6
+ */
7
+ export declare function mirror(ease: EasingFn): EasingFn;
8
+ //# sourceMappingURL=mirror.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mirror.d.ts","sourceRoot":"","sources":["../../src/modifiers/mirror.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAK/C"}
@@ -0,0 +1,14 @@
1
+ import { defineEasing } from "../define.js";
2
+ /**
3
+ * Mirror an ease across the midpoint. The first half plays the ease forward,
4
+ * scaled into [0, 0.5]; the second half plays it reversed, scaled into
5
+ * [0.5, 1]. Turns any ease into its inOut variant.
6
+ */
7
+ export function mirror(ease) {
8
+ return defineEasing(`mirror(${ease.easingName})`, (t) => {
9
+ if (t < 0.5)
10
+ return ease(t * 2) / 2;
11
+ return 1 - ease((1 - t) * 2) / 2;
12
+ });
13
+ }
14
+ //# sourceMappingURL=mirror.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mirror.js","sourceRoot":"","sources":["../../src/modifiers/mirror.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C;;;;GAIG;AACH,MAAM,UAAU,MAAM,CAAC,IAAc;IACnC,OAAO,YAAY,CAAC,UAAU,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE;QACtD,IAAI,CAAC,GAAG,GAAG;YAAE,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { EasingFn } from "../types.js";
2
+ /** Play the ease backward: f(t) → 1 - f(1 - t). Useful to turn any "in" into an "out". */
3
+ export declare function reverse(ease: EasingFn): EasingFn;
4
+ //# sourceMappingURL=reverse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reverse.d.ts","sourceRoot":"","sources":["../../src/modifiers/reverse.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,0FAA0F;AAC1F,wBAAgB,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAEhD"}
@@ -0,0 +1,6 @@
1
+ import { defineEasing } from "../define.js";
2
+ /** Play the ease backward: f(t) → 1 - f(1 - t). Useful to turn any "in" into an "out". */
3
+ export function reverse(ease) {
4
+ return defineEasing(`reverse(${ease.easingName})`, (t) => 1 - ease(1 - t));
5
+ }
6
+ //# sourceMappingURL=reverse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reverse.js","sourceRoot":"","sources":["../../src/modifiers/reverse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C,0FAA0F;AAC1F,MAAM,UAAU,OAAO,CAAC,IAAc;IACpC,OAAO,YAAY,CAAC,WAAW,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC7E,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { EasingFn } from "../types.js";
2
+ /**
3
+ * Extract a sub-section of an easing curve, stretched to fill [0, 1].
4
+ * Use when you want to play only part of a curve (e.g., just the overshoot
5
+ * portion of `back.out`, or the settle portion of `elastic.out`).
6
+ *
7
+ * The sliced portion is normalised: y(0) = ease(start), y(1) = ease(end),
8
+ * then remapped so the output hits 0 and 1 at the new endpoints.
9
+ */
10
+ export declare function slice(ease: EasingFn, start: number, end: number): EasingFn;
11
+ //# sourceMappingURL=slice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slice.d.ts","sourceRoot":"","sources":["../../src/modifiers/slice.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ,CAiB1E"}
@@ -0,0 +1,28 @@
1
+ import { defineEasing } from "../define.js";
2
+ /**
3
+ * Extract a sub-section of an easing curve, stretched to fill [0, 1].
4
+ * Use when you want to play only part of a curve (e.g., just the overshoot
5
+ * portion of `back.out`, or the settle portion of `elastic.out`).
6
+ *
7
+ * The sliced portion is normalised: y(0) = ease(start), y(1) = ease(end),
8
+ * then remapped so the output hits 0 and 1 at the new endpoints.
9
+ */
10
+ export function slice(ease, start, end) {
11
+ if (!(start >= 0 && start < end && end <= 1)) {
12
+ throw new RangeError(`slice: require 0 <= start < end <= 1; got start=${start}, end=${end}`);
13
+ }
14
+ if (start === 0 && end === 1)
15
+ return ease;
16
+ const span = end - start;
17
+ const baseStart = ease(start);
18
+ const baseEnd = ease(end);
19
+ const ySpan = baseEnd - baseStart;
20
+ return defineEasing(`slice(${ease.easingName}, ${start}, ${end})`, (t) => {
21
+ const u = start + span * t;
22
+ const v = ease(u);
23
+ if (ySpan === 0)
24
+ return 0;
25
+ return (v - baseStart) / ySpan;
26
+ });
27
+ }
28
+ //# sourceMappingURL=slice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slice.js","sourceRoot":"","sources":["../../src/modifiers/slice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C;;;;;;;GAOG;AACH,MAAM,UAAU,KAAK,CAAC,IAAc,EAAE,KAAa,EAAE,GAAW;IAC9D,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,KAAK,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,UAAU,CAClB,mDAAmD,KAAK,SAAS,GAAG,EAAE,CACvE,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,MAAM,IAAI,GAAG,GAAG,GAAG,KAAK,CAAC;IACzB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1B,MAAM,KAAK,GAAG,OAAO,GAAG,SAAS,CAAC;IAClC,OAAO,YAAY,CAAC,SAAS,IAAI,CAAC,UAAU,KAAK,KAAK,KAAK,GAAG,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE;QACvE,MAAM,CAAC,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC;QAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QAC1B,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { EasingFn } from "../types.js";
2
+ /**
3
+ * Round-trip an ease: 0 → 1 → 0 over t in [0, 1]. First half runs the ease
4
+ * forward, second half runs it reversed. Unlike `mirror` which produces an
5
+ * inOut, `yoyo` returns to the start.
6
+ */
7
+ export declare function yoyo(ease: EasingFn): EasingFn;
8
+ //# sourceMappingURL=yoyo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yoyo.d.ts","sourceRoot":"","sources":["../../src/modifiers/yoyo.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAM7C"}
@@ -0,0 +1,10 @@
1
+ import { defineEasing } from "../define.js";
2
+ /**
3
+ * Round-trip an ease: 0 → 1 → 0 over t in [0, 1]. First half runs the ease
4
+ * forward, second half runs it reversed. Unlike `mirror` which produces an
5
+ * inOut, `yoyo` returns to the start.
6
+ */
7
+ export function yoyo(ease) {
8
+ return defineEasing(`yoyo(${ease.easingName})`, (t) => (t < 0.5 ? ease(t * 2) : ease((1 - t) * 2)), { exactEndpoints: false });
9
+ }
10
+ //# sourceMappingURL=yoyo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yoyo.js","sourceRoot":"","sources":["../../src/modifiers/yoyo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAC,IAAc;IACjC,OAAO,YAAY,CACjB,QAAQ,IAAI,CAAC,UAAU,GAAG,EAC1B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAClD,EAAE,cAAc,EAAE,KAAK,EAAE,CAC1B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { EasingFn } from "./types.js";
2
+ /**
3
+ * Parse a GSAP-style string reference into an EasingFn. Examples:
4
+ *
5
+ * - `"linear"`, `"power2.out"`, `"sine.inOut"` — core + variant
6
+ * - `"back.out(2)"` — parametric with positional arg
7
+ * - `"elastic.out(1.2, 0.4)"` — multiple positional args (amplitude, period)
8
+ * - `"steps(5, start)"` — mix of numeric and string args
9
+ * - `"cubic-bezier(0.42, 0, 0.58, 1)"` — CSS-style, exact bezier
10
+ *
11
+ * Throws a RangeError for unknown names or malformed input.
12
+ */
13
+ export declare function parseEasing(spec: string): EasingFn;
14
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAwDA,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAC;AA2E7D;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAwBlD"}
package/dist/parse.js ADDED
@@ -0,0 +1,108 @@
1
+ import { backIn, backInOut, backOut, bounceIn, bounceInOut, bounceOut, circIn, circInOut, circOut, cubicIn, cubicInOut, cubicOut, elasticIn, elasticInOut, elasticOut, expoIn, expoInOut, expoOut, linear, none, power1In, power1InOut, power1Out, power2In, power2InOut, power2Out, power3In, power3InOut, power3Out, power4In, power4InOut, power4Out, quadIn, quadInOut, quadOut, quartIn, quartInOut, quartOut, quintIn, quintInOut, quintOut, sineIn, sineInOut, sineOut, steps, } from "./easings/index.js";
2
+ import { anticipate, anticipateIn, anticipateInOut, anticipateOut, bezier, spring, wiggle, } from "./builders/index.js";
3
+ const REGISTRY = {
4
+ linear,
5
+ none,
6
+ "power1.in": power1In,
7
+ "power1.out": power1Out,
8
+ "power1.inOut": power1InOut,
9
+ "power2.in": power2In,
10
+ "power2.out": power2Out,
11
+ "power2.inOut": power2InOut,
12
+ "power3.in": power3In,
13
+ "power3.out": power3Out,
14
+ "power3.inOut": power3InOut,
15
+ "power4.in": power4In,
16
+ "power4.out": power4Out,
17
+ "power4.inOut": power4InOut,
18
+ "quad.in": quadIn,
19
+ "quad.out": quadOut,
20
+ "quad.inOut": quadInOut,
21
+ "cubic.in": cubicIn,
22
+ "cubic.out": cubicOut,
23
+ "cubic.inOut": cubicInOut,
24
+ "quart.in": quartIn,
25
+ "quart.out": quartOut,
26
+ "quart.inOut": quartInOut,
27
+ "quint.in": quintIn,
28
+ "quint.out": quintOut,
29
+ "quint.inOut": quintInOut,
30
+ "sine.in": sineIn,
31
+ "sine.out": sineOut,
32
+ "sine.inOut": sineInOut,
33
+ "circ.in": circIn,
34
+ "circ.out": circOut,
35
+ "circ.inOut": circInOut,
36
+ "expo.in": expoIn,
37
+ "expo.out": expoOut,
38
+ "expo.inOut": expoInOut,
39
+ "back.in": backIn,
40
+ "back.out": backOut,
41
+ "back.inOut": backInOut,
42
+ "elastic.in": elasticIn,
43
+ "elastic.out": elasticOut,
44
+ "elastic.inOut": elasticInOut,
45
+ "bounce.in": bounceIn,
46
+ "bounce.out": bounceOut,
47
+ "bounce.inOut": bounceInOut,
48
+ steps: steps,
49
+ spring: spring,
50
+ wiggle: wiggle,
51
+ anticipate: anticipate,
52
+ "anticipate.in": anticipateIn,
53
+ "anticipate.out": anticipateOut,
54
+ "anticipate.inOut": anticipateInOut,
55
+ };
56
+ const PARSE_RE = /^([a-zA-Z][\w]*(?:\.[a-zA-Z][\w]*)?)(?:\((.*)\))?$/;
57
+ const CUBIC_BEZIER_RE = /^cubic-bezier\(\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^)]+)\s*\)$/;
58
+ function isParametric(x) {
59
+ return (typeof x === "function" &&
60
+ "defaults" in x &&
61
+ "with" in x);
62
+ }
63
+ function coerceArg(raw) {
64
+ const trimmed = raw.trim().replace(/^["']|["']$/g, "");
65
+ const n = Number(trimmed);
66
+ return Number.isFinite(n) ? n : trimmed;
67
+ }
68
+ /**
69
+ * Parse a GSAP-style string reference into an EasingFn. Examples:
70
+ *
71
+ * - `"linear"`, `"power2.out"`, `"sine.inOut"` — core + variant
72
+ * - `"back.out(2)"` — parametric with positional arg
73
+ * - `"elastic.out(1.2, 0.4)"` — multiple positional args (amplitude, period)
74
+ * - `"steps(5, start)"` — mix of numeric and string args
75
+ * - `"cubic-bezier(0.42, 0, 0.58, 1)"` — CSS-style, exact bezier
76
+ *
77
+ * Throws a RangeError for unknown names or malformed input.
78
+ */
79
+ export function parseEasing(spec) {
80
+ const input = spec.trim();
81
+ const cb = CUBIC_BEZIER_RE.exec(input);
82
+ if (cb) {
83
+ const [, a, b, c, d] = cb;
84
+ return bezier(Number(a), Number(b), Number(c), Number(d));
85
+ }
86
+ const match = PARSE_RE.exec(input);
87
+ if (!match)
88
+ throw new RangeError(`parseEasing: cannot parse '${spec}'`);
89
+ const [, name, argsStr] = match;
90
+ const entry = REGISTRY[name];
91
+ if (!entry)
92
+ throw new RangeError(`parseEasing: unknown easing '${name}'`);
93
+ const args = argsStr !== undefined && argsStr.length > 0 ? argsStr.split(",").map(coerceArg) : [];
94
+ if (args.length === 0)
95
+ return entry;
96
+ if (!isParametric(entry)) {
97
+ throw new RangeError(`parseEasing: '${name}' is not parametric but received arguments`);
98
+ }
99
+ const keys = Object.keys(entry.defaults);
100
+ const params = {};
101
+ args.forEach((value, i) => {
102
+ const key = keys[i];
103
+ if (key !== undefined)
104
+ params[key] = value;
105
+ });
106
+ return entry.with(params);
107
+ }
108
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { EasingFn } from "./types.js";
2
+ /**
3
+ * Check if the user has requested reduced motion via OS-level setting.
4
+ * Returns false when no DOM is available (SSR / Node).
5
+ */
6
+ export declare function prefersReducedMotion(): boolean;
7
+ /**
8
+ * Wrap an easing to respect the user's `prefers-reduced-motion` setting.
9
+ * When reduced motion is requested, returns `fallback` (default: linear);
10
+ * otherwise returns the original ease.
11
+ *
12
+ * Evaluated at call time — not reactive to preference changes during the
13
+ * lifetime of a single animation. For long-running apps, re-evaluate when
14
+ * starting new animations.
15
+ */
16
+ export declare function respectReducedMotion(ease: EasingFn, fallback?: EasingFn): EasingFn;
17
+ //# sourceMappingURL=reduced-motion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reduced-motion.d.ts","sourceRoot":"","sources":["../src/reduced-motion.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAK9C;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,GAAE,QAAiB,GAAG,QAAQ,CAE1F"}
@@ -0,0 +1,24 @@
1
+ import { linear } from "./easings/linear.js";
2
+ /**
3
+ * Check if the user has requested reduced motion via OS-level setting.
4
+ * Returns false when no DOM is available (SSR / Node).
5
+ */
6
+ export function prefersReducedMotion() {
7
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
8
+ return false;
9
+ }
10
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
11
+ }
12
+ /**
13
+ * Wrap an easing to respect the user's `prefers-reduced-motion` setting.
14
+ * When reduced motion is requested, returns `fallback` (default: linear);
15
+ * otherwise returns the original ease.
16
+ *
17
+ * Evaluated at call time — not reactive to preference changes during the
18
+ * lifetime of a single animation. For long-running apps, re-evaluate when
19
+ * starting new animations.
20
+ */
21
+ export function respectReducedMotion(ease, fallback = linear) {
22
+ return prefersReducedMotion() ? fallback : ease;
23
+ }
24
+ //# sourceMappingURL=reduced-motion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reduced-motion.js","sourceRoot":"","sources":["../src/reduced-motion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAG7C;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;QAC7E,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,MAAM,CAAC,UAAU,CAAC,kCAAkC,CAAC,CAAC,OAAO,CAAC;AACvE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAc,EAAE,WAAqB,MAAM;IAC9E,OAAO,oBAAoB,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC"}
@@ -0,0 +1,8 @@
1
+ export type EasingFn = ((t: number) => number) & {
2
+ readonly easingName: string;
3
+ };
4
+ export type ParametricEasing<P extends object> = EasingFn & {
5
+ readonly defaults: Readonly<P>;
6
+ with(params: Partial<P>): EasingFn;
7
+ };
8
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG;IAC/C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,IAAI,QAAQ,GAAG;IAC1D,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;CACpC,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@vysmo/easings",
3
+ "version": "0.1.0",
4
+ "description": "Curated easing catalog (40+ named curves) + parametric builders (spring, bezier, wiggle, rough, anticipate) + composition modifiers (chain, reverse, mirror, yoyo, blend, slice). Pure math, zero deps. CSS export via toCSSLinear / toCSSBezier; reduced-motion helpers; GSAP-style string parser.",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "easing",
8
+ "easings",
9
+ "tween",
10
+ "spring",
11
+ "bezier",
12
+ "wiggle",
13
+ "animation",
14
+ "interpolation",
15
+ "reduced-motion",
16
+ "tree-shakable",
17
+ "headless"
18
+ ],
19
+ "type": "module",
20
+ "sideEffects": false,
21
+ "main": "./dist/index.js",
22
+ "module": "./src/index.ts",
23
+ "types": "./dist/index.d.ts",
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "import": "./dist/index.js"
28
+ },
29
+ "./css": {
30
+ "types": "./dist/css.d.ts",
31
+ "import": "./dist/css.js"
32
+ },
33
+ "./parse": {
34
+ "types": "./dist/parse.d.ts",
35
+ "import": "./dist/parse.js"
36
+ },
37
+ "./reduced-motion": {
38
+ "types": "./dist/reduced-motion.d.ts",
39
+ "import": "./dist/reduced-motion.js"
40
+ }
41
+ },
42
+ "files": [
43
+ "dist",
44
+ "src",
45
+ "README.md",
46
+ "LICENSE"
47
+ ],
48
+ "devDependencies": {
49
+ "esbuild": "^0.28.0",
50
+ "fast-check": "^4.7.0",
51
+ "tinybench": "^6.0.0",
52
+ "typescript": "^5.6.3",
53
+ "vitest": "^3.2.4"
54
+ },
55
+ "scripts": {
56
+ "build": "tsc -p tsconfig.json",
57
+ "typecheck": "tsc -p tsconfig.typecheck.json",
58
+ "test": "vitest run",
59
+ "test:watch": "vitest",
60
+ "bench": "vitest bench",
61
+ "size": "node scripts/check-bundle-size.mjs"
62
+ }
63
+ }
@@ -0,0 +1,58 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ anticipate,
4
+ anticipateIn,
5
+ anticipateInOut,
6
+ anticipateOut,
7
+ } from "../index.js";
8
+
9
+ describe("anticipate variants", () => {
10
+ it("anticipate alias equals anticipateIn", () => {
11
+ expect(anticipate).toBe(anticipateIn);
12
+ });
13
+
14
+ it("all variants hit endpoints exactly", () => {
15
+ for (const fn of [anticipateIn, anticipateOut, anticipateInOut]) {
16
+ expect(fn(0)).toBe(0);
17
+ expect(fn(1)).toBe(1);
18
+ }
19
+ });
20
+
21
+ it("anticipateIn dips below zero early", () => {
22
+ let min = 0;
23
+ for (let i = 0; i <= 100; i++) min = Math.min(min, anticipateIn(i / 100));
24
+ expect(min).toBeLessThan(-0.01);
25
+ });
26
+
27
+ it("anticipateOut overshoots above one late", () => {
28
+ let max = 0;
29
+ for (let i = 0; i <= 100; i++) max = Math.max(max, anticipateOut(i / 100));
30
+ expect(max).toBeGreaterThan(1.01);
31
+ });
32
+
33
+ it("anticipateInOut both dips and overshoots", () => {
34
+ let min = 0;
35
+ let max = 0;
36
+ for (let i = 0; i <= 100; i++) {
37
+ const v = anticipateInOut(i / 100);
38
+ if (v < min) min = v;
39
+ if (v > max) max = v;
40
+ }
41
+ expect(min).toBeLessThan(-0.01);
42
+ expect(max).toBeGreaterThan(1.01);
43
+ });
44
+
45
+ it("anticipateOut is approximately reverse of anticipateIn", () => {
46
+ for (let i = 0; i <= 20; i++) {
47
+ const t = i / 20;
48
+ expect(anticipateOut(t)).toBeCloseTo(1 - anticipateIn(1 - t), 6);
49
+ }
50
+ });
51
+
52
+ it("anticipateInOut is symmetric around t=0.5", () => {
53
+ for (let i = 0; i <= 20; i++) {
54
+ const t = i / 20;
55
+ expect(anticipateInOut(t) + anticipateInOut(1 - t)).toBeCloseTo(1, 6);
56
+ }
57
+ });
58
+ });