@effing/tween 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/LICENSE ADDED
@@ -0,0 +1,11 @@
1
+ O'Saasy License
2
+
3
+ Copyright © 2026, Trackuity BV.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ 1. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ 2. No licensee or downstream recipient may use the Software (including any modified or derivative versions) to directly compete with the original Licensor by offering it to third parties as a hosted, managed, or Software-as-a-Service (SaaS) product or cloud service where the primary value of the service is the functionality of the Software itself.
10
+
11
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # @effing/tween
2
+
3
+ **Easing functions and step iteration for frame-based animations.**
4
+
5
+ > Part of the [**Effing**](../../README.md) family — programmatic video creation with TypeScript.
6
+
7
+ Generate animation frames with precise timing control. Iterate over steps with progress values, apply easing functions for smooth motion.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @effing/tween
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { tween, easeOutQuad } from "@effing/tween";
19
+ import { pngFromSatori } from "@effing/satori";
20
+
21
+ async function* generateFrames() {
22
+ yield* tween(90, async ({ lower: progress }) => {
23
+ // Apply easing to progress
24
+ const easedProgress = easeOutQuad(progress);
25
+
26
+ // Use eased progress for animation
27
+ const scale = 1 + 0.5 * easedProgress;
28
+ const opacity = easedProgress;
29
+
30
+ return pngFromSatori(
31
+ <div style={{ transform: `scale(${scale})`, opacity }}>
32
+ Animated!
33
+ </div>,
34
+ { width: 1080, height: 1920, fonts }
35
+ );
36
+ });
37
+ }
38
+ ```
39
+
40
+ ## Concepts
41
+
42
+ ### Tweening
43
+
44
+ The `tween()` async generator iterates over animation frames with concurrency control. Each frame receives a `TweenInterval` with `lower` and `upper` bounds representing its position in the animation (0→1):
45
+
46
+ ```typescript
47
+ import { tween } from "@effing/tween";
48
+
49
+ // Generate 60 frames with concurrent processing
50
+ yield *
51
+ tween(60, async ({ lower, upper }, index) => {
52
+ // lower: 0/60, 1/60, 2/60, ... 59/60
53
+ // upper: 1/60, 2/60, 3/60, ... 60/60
54
+ // index: 0, 1, 2, ... 59
55
+ return renderFrame(lower);
56
+ });
57
+ ```
58
+
59
+ Frames are processed concurrently (defaulting to CPU count) but yielded in order—ideal for CPU-bound rendering work.
60
+
61
+ ### Easing Functions
62
+
63
+ Transform linear progress into curved motion. All easing functions take a value in `[0, 1]` and return a value in `[0, 1]`:
64
+
65
+ ```typescript
66
+ import { easeOutQuad, easeInOutCubic } from "@effing/tween";
67
+
68
+ const progress = 0.5;
69
+ easeOutQuad(progress); // 0.75 — starts fast, ends slow
70
+ easeInOutCubic(progress); // 0.5 — slow start and end
71
+ ```
72
+
73
+ ## API Overview
74
+
75
+ ### Step Iteration
76
+
77
+ #### `steps(count)`
78
+
79
+ Returns an array of progress values from 0 to (count-1)/count:
80
+
81
+ ```typescript
82
+ function steps(count: number): number[];
83
+
84
+ steps(4); // [0, 0.25, 0.5, 0.75]
85
+ ```
86
+
87
+ #### `tween(count, fn, options?)`
88
+
89
+ Tween frames, with concurrency control. Yields resulting frames in order.
90
+
91
+ ```typescript
92
+ async function* tween<T>(
93
+ count: number,
94
+ fn: (interval: TweenInterval, index: number) => Promise<T>,
95
+ options?: { concurrency?: number }
96
+ ): AsyncGenerator<T>
97
+ ```
98
+
99
+ #### `tweenToArray(count, fn, options?)`
100
+
101
+ Tween frames, with concurrency control, returning an array.
102
+
103
+ ```typescript
104
+ async function tweenToArray<T>(
105
+ count: number,
106
+ fn: (interval: TweenInterval, index: number) => Promise<T>,
107
+ options?: { concurrency?: number },
108
+ ): Promise<T[]>;
109
+ ```
110
+
111
+ ### Easing Functions
112
+
113
+ All easing functions have the signature `(t: number) => number`.
114
+
115
+ | Category | Functions |
116
+ | -------- | ----------------------------------------------------- |
117
+ | Linear | `linear` |
118
+ | Sine | `easeInSine`, `easeOutSine`, `easeInOutSine` |
119
+ | Quad | `easeInQuad`, `easeOutQuad`, `easeInOutQuad` |
120
+ | Cubic | `easeInCubic`, `easeOutCubic`, `easeInOutCubic` |
121
+ | Quart | `easeInQuart`, `easeOutQuart`, `easeInOutQuart` |
122
+ | Quint | `easeInQuint`, `easeOutQuint`, `easeInOutQuint` |
123
+ | Expo | `easeInExpo`, `easeOutExpo`, `easeInOutExpo` |
124
+ | Circ | `easeInCirc`, `easeOutCirc`, `easeInOutCirc` |
125
+ | Back | `easeInBack`, `easeOutBack`, `easeInOutBack` |
126
+ | Elastic | `easeInElastic`, `easeOutElastic`, `easeInOutElastic` |
127
+ | Bounce | `easeInBounce`, `easeOutBounce`, `easeInOutBounce` |
128
+
129
+ **Naming convention:**
130
+
131
+ - `easeIn*` — Starts slow, ends fast
132
+ - `easeOut*` — Starts fast, ends slow
133
+ - `easeInOut*` — Slow at both ends
134
+
135
+ ## Examples
136
+
137
+ ### Zoom Animation
138
+
139
+ ```typescript
140
+ import { tween, easeOutQuad } from "@effing/tween";
141
+
142
+ yield *
143
+ tween(90, async ({ lower: p }) => {
144
+ const zoom = 1 + 0.3 * easeOutQuad(p);
145
+ return renderFrame({ zoom });
146
+ });
147
+ ```
148
+
149
+ ### Fade In/Out
150
+
151
+ ```typescript
152
+ import { tween, easeInOutSine } from "@effing/tween";
153
+
154
+ yield *
155
+ tween(60, async ({ lower: p }) => {
156
+ // Fade in for first half, fade out for second half
157
+ const opacity = p < 0.5 ? easeInOutSine(p * 2) : easeInOutSine((1 - p) * 2);
158
+ return renderFrame({ opacity });
159
+ });
160
+ ```
161
+
162
+ ### Bounce Effect
163
+
164
+ ```typescript
165
+ import { tween, easeOutBounce } from "@effing/tween";
166
+
167
+ yield *
168
+ tween(45, async ({ lower: p }) => {
169
+ const y = 100 * (1 - easeOutBounce(p)); // Fall and bounce
170
+ return renderFrame({ translateY: y });
171
+ });
172
+ ```
173
+
174
+ ## Related Packages
175
+
176
+ - [`@effing/annie`](../annie) — Package frames into TAR archives
177
+ - [`@effing/satori`](../satori) — Render JSX to PNG for each frame
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Generate an array of step values for an animation
3
+ * @param count Number of steps
4
+ * @returns Array of step values from 0 to (count-1)/count
5
+ */
6
+ declare function steps(count: number): number[];
7
+
8
+ /**
9
+ * Tween interval representing a frame's position in the animation
10
+ */
11
+ type TweenInterval = {
12
+ /** Lower bound (inclusive), in range [0, 1) */
13
+ lower: number;
14
+ /** Upper bound (exclusive for all but last frame), in range (0, 1] */
15
+ upper: number;
16
+ };
17
+ /**
18
+ * Tween frames with concurrency control
19
+ * @param count Number of frames to generate
20
+ * @param fn Function that takes a tween interval and index, returns a promise
21
+ * @param options Configuration options
22
+ * @yields Resulting frames in order
23
+ */
24
+ declare function tween<T>(count: number, fn: (interval: TweenInterval, index: number) => Promise<T>, options?: {
25
+ concurrency?: number;
26
+ }): AsyncGenerator<T>;
27
+ /**
28
+ * Tween frames with concurrency control, returning an array
29
+ * @param count Number of frames to generate
30
+ * @param fn Function that takes a tween interval and index, returns a promise
31
+ * @param options Configuration options
32
+ * @returns Promise resolving to array of resulting frames
33
+ */
34
+ declare function tweenToArray<T>(count: number, fn: (interval: TweenInterval, index: number) => Promise<T>, options?: {
35
+ concurrency?: number;
36
+ }): Promise<T[]>;
37
+
38
+ /** Linear interpolation (no easing) */
39
+ declare function linear(x: number): number;
40
+ /** Ease in using sine curve */
41
+ declare function easeInSine(x: number): number;
42
+ /** Ease out using sine curve */
43
+ declare function easeOutSine(x: number): number;
44
+ /** Ease in-out using sine curve */
45
+ declare function easeInOutSine(x: number): number;
46
+ /** Ease in using quadratic curve */
47
+ declare function easeInQuad(x: number): number;
48
+ /** Ease out using quadratic curve */
49
+ declare function easeOutQuad(x: number): number;
50
+ /** Ease in-out using quadratic curve */
51
+ declare function easeInOutQuad(x: number): number;
52
+ /** Ease in using cubic curve */
53
+ declare function easeInCubic(x: number): number;
54
+ /** Ease out using cubic curve */
55
+ declare function easeOutCubic(x: number): number;
56
+ /** Ease in-out using cubic curve */
57
+ declare function easeInOutCubic(x: number): number;
58
+ /** Ease in using quartic curve */
59
+ declare function easeInQuart(x: number): number;
60
+ /** Ease out using quartic curve */
61
+ declare function easeOutQuart(x: number): number;
62
+ /** Ease in-out using quartic curve */
63
+ declare function easeInOutQuart(x: number): number;
64
+ /** Ease in using quintic curve */
65
+ declare function easeInQuint(x: number): number;
66
+ /** Ease out using quintic curve */
67
+ declare function easeOutQuint(x: number): number;
68
+ /** Ease in-out using quintic curve */
69
+ declare function easeInOutQuint(x: number): number;
70
+ /** Ease in using exponential curve */
71
+ declare function easeInExpo(x: number): number;
72
+ /** Ease out using exponential curve */
73
+ declare function easeOutExpo(x: number): number;
74
+ /** Ease in-out using exponential curve */
75
+ declare function easeInOutExpo(x: number): number;
76
+ /** Ease in using circular curve */
77
+ declare function easeInCirc(x: number): number;
78
+ /** Ease out using circular curve */
79
+ declare function easeOutCirc(x: number): number;
80
+ /** Ease in-out using circular curve */
81
+ declare function easeInOutCirc(x: number): number;
82
+ /** Ease in with overshoot (back) */
83
+ declare function easeInBack(x: number): number;
84
+ /** Ease out with overshoot (back) */
85
+ declare function easeOutBack(x: number): number;
86
+ /** Ease in-out with overshoot (back) */
87
+ declare function easeInOutBack(x: number): number;
88
+ /** Ease in with elastic bounce */
89
+ declare function easeInElastic(x: number): number;
90
+ /** Ease out with elastic bounce */
91
+ declare function easeOutElastic(x: number): number;
92
+ /** Ease in-out with elastic bounce */
93
+ declare function easeInOutElastic(x: number): number;
94
+ /** Ease out with bounce */
95
+ declare function easeOutBounce(x: number): number;
96
+ /** Ease in with bounce */
97
+ declare function easeInBounce(x: number): number;
98
+ /** Ease in-out with bounce */
99
+ declare function easeInOutBounce(x: number): number;
100
+
101
+ export { type TweenInterval, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, linear, steps, tween, tweenToArray };
package/dist/index.js ADDED
@@ -0,0 +1,196 @@
1
+ // src/steps.ts
2
+ function steps(count) {
3
+ return Array.from({ length: count }, (_, i) => i / count);
4
+ }
5
+
6
+ // src/tween.ts
7
+ import os from "os";
8
+ async function* tween(count, fn, options = { concurrency: os.cpus().length }) {
9
+ if (count === 0) {
10
+ return;
11
+ }
12
+ const range = steps(count);
13
+ const maxConcurrency = Math.max(1, options.concurrency ?? os.cpus().length);
14
+ const activeTasks = /* @__PURE__ */ new Map();
15
+ let nextIndexToStart = 0;
16
+ let nextIndexToYield = 0;
17
+ const startTask = (index) => {
18
+ const lower = range[index];
19
+ const upper = range[index + 1] ?? 1;
20
+ const promise = fn({ lower, upper }, index);
21
+ activeTasks.set(index, promise);
22
+ };
23
+ const fillConcurrencySlots = () => {
24
+ while (nextIndexToStart < count && activeTasks.size < maxConcurrency) {
25
+ startTask(nextIndexToStart++);
26
+ }
27
+ };
28
+ fillConcurrencySlots();
29
+ while (nextIndexToYield < count) {
30
+ const taskPromise = activeTasks.get(nextIndexToYield);
31
+ if (!taskPromise) {
32
+ throw new Error(
33
+ `Internal error: task at index ${nextIndexToYield} not found in active tasks`
34
+ );
35
+ }
36
+ const result = await taskPromise;
37
+ activeTasks.delete(nextIndexToYield);
38
+ yield result;
39
+ fillConcurrencySlots();
40
+ nextIndexToYield++;
41
+ }
42
+ }
43
+ async function tweenToArray(count, fn, options = { concurrency: os.cpus().length }) {
44
+ return Array.fromAsync(tween(count, fn, options));
45
+ }
46
+
47
+ // src/easing.ts
48
+ function linear(x) {
49
+ return x;
50
+ }
51
+ function easeInSine(x) {
52
+ return 1 - Math.cos(x * Math.PI / 2);
53
+ }
54
+ function easeOutSine(x) {
55
+ return Math.sin(x * Math.PI / 2);
56
+ }
57
+ function easeInOutSine(x) {
58
+ return -(Math.cos(Math.PI * x) - 1) / 2;
59
+ }
60
+ function easeInQuad(x) {
61
+ return x * x;
62
+ }
63
+ function easeOutQuad(x) {
64
+ return 1 - Math.pow(1 - x, 2);
65
+ }
66
+ function easeInOutQuad(x) {
67
+ return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;
68
+ }
69
+ function easeInCubic(x) {
70
+ return x * x * x;
71
+ }
72
+ function easeOutCubic(x) {
73
+ return 1 - Math.pow(1 - x, 3);
74
+ }
75
+ function easeInOutCubic(x) {
76
+ return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
77
+ }
78
+ function easeInQuart(x) {
79
+ return x * x * x * x;
80
+ }
81
+ function easeOutQuart(x) {
82
+ return 1 - Math.pow(1 - x, 4);
83
+ }
84
+ function easeInOutQuart(x) {
85
+ return x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2, 4) / 2;
86
+ }
87
+ function easeInQuint(x) {
88
+ return x * x * x * x * x;
89
+ }
90
+ function easeOutQuint(x) {
91
+ return 1 - Math.pow(1 - x, 5);
92
+ }
93
+ function easeInOutQuint(x) {
94
+ return x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2;
95
+ }
96
+ function easeInExpo(x) {
97
+ return x === 0 ? 0 : Math.pow(2, 10 * x - 10);
98
+ }
99
+ function easeOutExpo(x) {
100
+ return x === 1 ? 1 : 1 - Math.pow(2, -10 * x);
101
+ }
102
+ function easeInOutExpo(x) {
103
+ return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? Math.pow(2, 20 * x - 10) / 2 : (2 - Math.pow(2, -20 * x + 10)) / 2;
104
+ }
105
+ function easeInCirc(x) {
106
+ return 1 - Math.sqrt(1 - Math.pow(x, 2));
107
+ }
108
+ function easeOutCirc(x) {
109
+ return Math.sqrt(1 - Math.pow(x - 1, 2));
110
+ }
111
+ function easeInOutCirc(x) {
112
+ return x < 0.5 ? (1 - Math.sqrt(1 - Math.pow(2 * x, 2))) / 2 : (Math.sqrt(1 - Math.pow(-2 * x + 2, 2)) + 1) / 2;
113
+ }
114
+ function easeInBack(x) {
115
+ const c1 = 1.70158;
116
+ const c3 = c1 + 1;
117
+ return c3 * x * x * x - c1 * x * x;
118
+ }
119
+ function easeOutBack(x) {
120
+ const c1 = 1.70158;
121
+ const c3 = c1 + 1;
122
+ return 1 + c3 * Math.pow(x - 1, 3) + c1 * Math.pow(x - 1, 2);
123
+ }
124
+ function easeInOutBack(x) {
125
+ const c1 = 1.70158;
126
+ const c2 = c1 * 1.525;
127
+ return x < 0.5 ? Math.pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2) / 2 : (Math.pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;
128
+ }
129
+ function easeInElastic(x) {
130
+ const c4 = 2 * Math.PI / 3;
131
+ return x === 0 ? 0 : x === 1 ? 1 : -Math.pow(2, 10 * x - 10) * Math.sin((x * 10 - 10.75) * c4);
132
+ }
133
+ function easeOutElastic(x) {
134
+ const c4 = 2 * Math.PI / 3;
135
+ return x === 0 ? 0 : x === 1 ? 1 : Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1;
136
+ }
137
+ function easeInOutElastic(x) {
138
+ const c5 = 2 * Math.PI / 4.5;
139
+ return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? -(Math.pow(2, 20 * x - 10) * Math.sin((20 * x - 11.125) * c5)) / 2 : Math.pow(2, -20 * x + 10) * Math.sin((20 * x - 11.125) * c5) / 2 + 1;
140
+ }
141
+ function easeOutBounce(x) {
142
+ const n1 = 7.5625;
143
+ const d1 = 2.75;
144
+ if (x < 1 / d1) {
145
+ return n1 * x * x;
146
+ } else if (x < 2 / d1) {
147
+ return n1 * (x -= 1.5 / d1) * x + 0.75;
148
+ } else if (x < 2.5 / d1) {
149
+ return n1 * (x -= 2.25 / d1) * x + 0.9375;
150
+ } else {
151
+ return n1 * (x -= 2.625 / d1) * x + 0.984375;
152
+ }
153
+ }
154
+ function easeInBounce(x) {
155
+ return 1 - easeOutBounce(1 - x);
156
+ }
157
+ function easeInOutBounce(x) {
158
+ return x < 0.5 ? (1 - easeOutBounce(1 - 2 * x)) / 2 : (1 + easeOutBounce(2 * x - 1)) / 2;
159
+ }
160
+ export {
161
+ easeInBack,
162
+ easeInBounce,
163
+ easeInCirc,
164
+ easeInCubic,
165
+ easeInElastic,
166
+ easeInExpo,
167
+ easeInOutBack,
168
+ easeInOutBounce,
169
+ easeInOutCirc,
170
+ easeInOutCubic,
171
+ easeInOutElastic,
172
+ easeInOutExpo,
173
+ easeInOutQuad,
174
+ easeInOutQuart,
175
+ easeInOutQuint,
176
+ easeInOutSine,
177
+ easeInQuad,
178
+ easeInQuart,
179
+ easeInQuint,
180
+ easeInSine,
181
+ easeOutBack,
182
+ easeOutBounce,
183
+ easeOutCirc,
184
+ easeOutCubic,
185
+ easeOutElastic,
186
+ easeOutExpo,
187
+ easeOutQuad,
188
+ easeOutQuart,
189
+ easeOutQuint,
190
+ easeOutSine,
191
+ linear,
192
+ steps,
193
+ tween,
194
+ tweenToArray
195
+ };
196
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/steps.ts","../src/tween.ts","../src/easing.ts"],"sourcesContent":["/**\n * Generate an array of step values for an animation\n * @param count Number of steps\n * @returns Array of step values from 0 to (count-1)/count\n */\nexport function steps(count: number): number[] {\n return Array.from({ length: count }, (_, i) => i / count);\n}\n","import os from \"os\";\nimport { steps } from \"./steps\";\n\n/**\n * Tween interval representing a frame's position in the animation\n */\nexport type TweenInterval = {\n /** Lower bound (inclusive), in range [0, 1) */\n lower: number;\n /** Upper bound (exclusive for all but last frame), in range (0, 1] */\n upper: number;\n};\n\n/**\n * Tween frames with concurrency control\n * @param count Number of frames to generate\n * @param fn Function that takes a tween interval and index, returns a promise\n * @param options Configuration options\n * @yields Resulting frames in order\n */\nexport async function* tween<T>(\n count: number,\n fn: (interval: TweenInterval, index: number) => Promise<T>,\n options: { concurrency?: number } = { concurrency: os.cpus().length },\n): AsyncGenerator<T> {\n if (count === 0) {\n return;\n }\n\n const range = steps(count);\n const maxConcurrency = Math.max(1, options.concurrency ?? os.cpus().length);\n const activeTasks = new Map<number, Promise<T>>();\n\n let nextIndexToStart = 0;\n let nextIndexToYield = 0;\n\n const startTask = (index: number): void => {\n const lower = range[index];\n const upper = range[index + 1] ?? 1;\n const promise = fn({ lower, upper }, index);\n activeTasks.set(index, promise);\n };\n\n const fillConcurrencySlots = (): void => {\n while (nextIndexToStart < count && activeTasks.size < maxConcurrency) {\n startTask(nextIndexToStart++);\n }\n };\n\n fillConcurrencySlots();\n\n while (nextIndexToYield < count) {\n const taskPromise = activeTasks.get(nextIndexToYield);\n\n if (!taskPromise) {\n throw new Error(\n `Internal error: task at index ${nextIndexToYield} not found in active tasks`,\n );\n }\n\n const result = await taskPromise;\n activeTasks.delete(nextIndexToYield);\n yield result;\n\n fillConcurrencySlots();\n nextIndexToYield++;\n }\n}\n\n/**\n * Tween frames with concurrency control, returning an array\n * @param count Number of frames to generate\n * @param fn Function that takes a tween interval and index, returns a promise\n * @param options Configuration options\n * @returns Promise resolving to array of resulting frames\n */\nexport async function tweenToArray<T>(\n count: number,\n fn: (interval: TweenInterval, index: number) => Promise<T>,\n options: { concurrency?: number } = { concurrency: os.cpus().length },\n): Promise<T[]> {\n return Array.fromAsync(tween(count, fn, options));\n}\n","// ============================================\n// Easing functions\n// See: https://easings.net/\n// ============================================\n\n/** Linear interpolation (no easing) */\nexport function linear(x: number): number {\n return x;\n}\n\n// Sine\n\n/** Ease in using sine curve */\nexport function easeInSine(x: number): number {\n return 1 - Math.cos((x * Math.PI) / 2);\n}\n\n/** Ease out using sine curve */\nexport function easeOutSine(x: number): number {\n return Math.sin((x * Math.PI) / 2);\n}\n\n/** Ease in-out using sine curve */\nexport function easeInOutSine(x: number): number {\n return -(Math.cos(Math.PI * x) - 1) / 2;\n}\n\n// Quad\n\n/** Ease in using quadratic curve */\nexport function easeInQuad(x: number): number {\n return x * x;\n}\n\n/** Ease out using quadratic curve */\nexport function easeOutQuad(x: number): number {\n return 1 - Math.pow(1 - x, 2);\n}\n\n/** Ease in-out using quadratic curve */\nexport function easeInOutQuad(x: number): number {\n return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;\n}\n\n// Cubic\n\n/** Ease in using cubic curve */\nexport function easeInCubic(x: number): number {\n return x * x * x;\n}\n\n/** Ease out using cubic curve */\nexport function easeOutCubic(x: number): number {\n return 1 - Math.pow(1 - x, 3);\n}\n\n/** Ease in-out using cubic curve */\nexport function easeInOutCubic(x: number): number {\n return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;\n}\n\n// Quart\n\n/** Ease in using quartic curve */\nexport function easeInQuart(x: number): number {\n return x * x * x * x;\n}\n\n/** Ease out using quartic curve */\nexport function easeOutQuart(x: number): number {\n return 1 - Math.pow(1 - x, 4);\n}\n\n/** Ease in-out using quartic curve */\nexport function easeInOutQuart(x: number): number {\n return x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2, 4) / 2;\n}\n\n// Quint\n\n/** Ease in using quintic curve */\nexport function easeInQuint(x: number): number {\n return x * x * x * x * x;\n}\n\n/** Ease out using quintic curve */\nexport function easeOutQuint(x: number): number {\n return 1 - Math.pow(1 - x, 5);\n}\n\n/** Ease in-out using quintic curve */\nexport function easeInOutQuint(x: number): number {\n return x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2;\n}\n\n// Expo\n\n/** Ease in using exponential curve */\nexport function easeInExpo(x: number): number {\n return x === 0 ? 0 : Math.pow(2, 10 * x - 10);\n}\n\n/** Ease out using exponential curve */\nexport function easeOutExpo(x: number): number {\n return x === 1 ? 1 : 1 - Math.pow(2, -10 * x);\n}\n\n/** Ease in-out using exponential curve */\nexport function easeInOutExpo(x: number): number {\n return x === 0\n ? 0\n : x === 1\n ? 1\n : x < 0.5\n ? Math.pow(2, 20 * x - 10) / 2\n : (2 - Math.pow(2, -20 * x + 10)) / 2;\n}\n\n// Circ\n\n/** Ease in using circular curve */\nexport function easeInCirc(x: number): number {\n return 1 - Math.sqrt(1 - Math.pow(x, 2));\n}\n\n/** Ease out using circular curve */\nexport function easeOutCirc(x: number): number {\n return Math.sqrt(1 - Math.pow(x - 1, 2));\n}\n\n/** Ease in-out using circular curve */\nexport function easeInOutCirc(x: number): number {\n return x < 0.5\n ? (1 - Math.sqrt(1 - Math.pow(2 * x, 2))) / 2\n : (Math.sqrt(1 - Math.pow(-2 * x + 2, 2)) + 1) / 2;\n}\n\n// Back\n\n/** Ease in with overshoot (back) */\nexport function easeInBack(x: number): number {\n const c1 = 1.70158;\n const c3 = c1 + 1;\n return c3 * x * x * x - c1 * x * x;\n}\n\n/** Ease out with overshoot (back) */\nexport function easeOutBack(x: number): number {\n const c1 = 1.70158;\n const c3 = c1 + 1;\n return 1 + c3 * Math.pow(x - 1, 3) + c1 * Math.pow(x - 1, 2);\n}\n\n/** Ease in-out with overshoot (back) */\nexport function easeInOutBack(x: number): number {\n const c1 = 1.70158;\n const c2 = c1 * 1.525;\n\n return x < 0.5\n ? (Math.pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2\n : (Math.pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;\n}\n\n// Elastic\n\n/** Ease in with elastic bounce */\nexport function easeInElastic(x: number): number {\n const c4 = (2 * Math.PI) / 3;\n return x === 0\n ? 0\n : x === 1\n ? 1\n : -Math.pow(2, 10 * x - 10) * Math.sin((x * 10 - 10.75) * c4);\n}\n\n/** Ease out with elastic bounce */\nexport function easeOutElastic(x: number): number {\n const c4 = (2 * Math.PI) / 3;\n return x === 0\n ? 0\n : x === 1\n ? 1\n : Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1;\n}\n\n/** Ease in-out with elastic bounce */\nexport function easeInOutElastic(x: number): number {\n const c5 = (2 * Math.PI) / 4.5;\n return x === 0\n ? 0\n : x === 1\n ? 1\n : x < 0.5\n ? -(Math.pow(2, 20 * x - 10) * Math.sin((20 * x - 11.125) * c5)) / 2\n : (Math.pow(2, -20 * x + 10) * Math.sin((20 * x - 11.125) * c5)) / 2 +\n 1;\n}\n\n// Bounce\n\n/** Ease out with bounce */\nexport function easeOutBounce(x: number): number {\n const n1 = 7.5625;\n const d1 = 2.75;\n\n if (x < 1 / d1) {\n return n1 * x * x;\n } else if (x < 2 / d1) {\n return n1 * (x -= 1.5 / d1) * x + 0.75;\n } else if (x < 2.5 / d1) {\n return n1 * (x -= 2.25 / d1) * x + 0.9375;\n } else {\n return n1 * (x -= 2.625 / d1) * x + 0.984375;\n }\n}\n\n/** Ease in with bounce */\nexport function easeInBounce(x: number): number {\n return 1 - easeOutBounce(1 - x);\n}\n\n/** Ease in-out with bounce */\nexport function easeInOutBounce(x: number): number {\n return x < 0.5\n ? (1 - easeOutBounce(1 - 2 * x)) / 2\n : (1 + easeOutBounce(2 * x - 1)) / 2;\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@effing/tween",
3
+ "version": "0.1.0",
4
+ "description": "Tweening and easing functions for animations",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js"
10
+ }
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "devDependencies": {
16
+ "tsup": "^8.0.0",
17
+ "typescript": "^5.9.3",
18
+ "vitest": "^3.2.4"
19
+ },
20
+ "keywords": [
21
+ "animation",
22
+ "easing",
23
+ "tween",
24
+ "interpolation"
25
+ ],
26
+ "license": "O'Saasy",
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "scripts": {
31
+ "build": "tsup",
32
+ "typecheck": "tsc --noEmit",
33
+ "test": "vitest run"
34
+ }
35
+ }