@starweb-libs/tween 0.0.1 → 0.0.2

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 CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Starweb Libraries, Mason L'Etoile
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Starweb Libraries, Mason L'Etoile
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,23 +1,23 @@
1
- # Starweb Tween
2
-
3
- Frame-driven tween manager with easing for the browser, built with TypeScript.
4
-
5
- ## Tech Stack
6
- <p align="left">
7
- <img height="35" src="https://img.shields.io/badge/TypeScript-%23007ACC?logo=typescript&logoColor=white&style=for-the-badge"/>
8
- </p>
9
-
10
- ## Modules
11
- | Module | Description |
12
- | ------ | ----------- |
13
- | `easing` | Easing functions and lookup table |
14
- | `manager` | Frame-driven tween manager |
15
- | `types` | Tween config, handle, and target types |
16
-
17
- ## Installation
18
- ```bash
19
- npm install github:starweb-libs/tween
20
- ```
21
-
22
- ## License
23
- MIT — see [LICENSE](./LICENSE) for details.
1
+ # Starweb Tween
2
+
3
+ Frame-driven tween manager with easing for the browser, built with TypeScript.
4
+
5
+ ## Tech Stack
6
+ <p align="left">
7
+ <img height="35" src="https://img.shields.io/badge/TypeScript-%23007ACC?logo=typescript&logoColor=white&style=for-the-badge"/>
8
+ </p>
9
+
10
+ ## Modules
11
+ | Module | Description |
12
+ | ------ | ----------- |
13
+ | `easing` | Easing functions and lookup table |
14
+ | `manager` | Frame-driven tween manager |
15
+ | `types` | Tween config, handle, and target types |
16
+
17
+ ## Installation
18
+ ```bash
19
+ npm install github:starweb-libs/tween
20
+ ```
21
+
22
+ ## License
23
+ MIT — see [LICENSE](./LICENSE) for details.
@@ -0,0 +1,20 @@
1
+ //#region src/easing.d.ts
2
+ /** Easing function name. */
3
+ type EasingName = 'linear' | 'sine.in' | 'sine.out' | 'sine.inOut' | 'quad.in' | 'quad.out' | 'quad.inOut' | 'cubic.in' | 'cubic.out' | 'cubic.inOut' | 'expo.in' | 'expo.out' | 'expo.inOut';
4
+ /** A function that maps a linear progress value (0-1) to an eased value (0-1).*/
5
+ type EasingFunction = (t: number) => number;
6
+ /** Flips an ease-in function into its ease-out equivalent. */
7
+ declare const easeOut: (f: EasingFunction) => EasingFunction;
8
+ /** Combines an ease-in function with its inverse for a symmetric ease-in-out curve. */
9
+ declare const easeInOut: (f: EasingFunction) => EasingFunction;
10
+ /** Generates in/out/inOut easing functions for a given exponent. */
11
+ declare const makePowerEase: (exponent: number) => {
12
+ in: EasingFunction;
13
+ out: EasingFunction;
14
+ inOut: EasingFunction;
15
+ };
16
+ /** Lookup table of easing functions keyed by name. */
17
+ declare const TWEEN_EASING: Readonly<Record<EasingName, EasingFunction>>;
18
+ //#endregion
19
+ export { EasingFunction, EasingName, TWEEN_EASING, easeInOut, easeOut, makePowerEase };
20
+ //# sourceMappingURL=easing.d.mts.map
@@ -0,0 +1,50 @@
1
+ //#region src/easing.ts
2
+ /** Flips an ease-in function into its ease-out equivalent. */
3
+ const easeOut = (f) => (t) => 1 - f(1 - t);
4
+ /** Combines an ease-in function with its inverse for a symmetric ease-in-out curve. */
5
+ const easeInOut = (f) => (t) => t < .5 ? f(2 * t) / 2 : 1 - f(-2 * t + 2) / 2;
6
+ /** Generates in/out/inOut easing functions for a given exponent. */
7
+ const makePowerEase = (exponent) => {
8
+ const i = (t) => t ** exponent;
9
+ return {
10
+ in: i,
11
+ out: easeOut(i),
12
+ inOut: easeInOut(i)
13
+ };
14
+ };
15
+ /** Sine ease-in base curve. */
16
+ const sineIn = (t) => 1 - Math.cos(t * Math.PI / 2);
17
+ /** Sine ease-out. */
18
+ const sineOut = easeOut(sineIn);
19
+ /** Sine ease-in-out. */
20
+ const sineInOut = easeInOut(sineIn);
21
+ /** Quadratic easing curves. */
22
+ const quad = makePowerEase(2);
23
+ /** Cubic easing curves.*/
24
+ const cubic = makePowerEase(3);
25
+ /** Exponential ease-in with edge case guards. */
26
+ const expoIn = (t) => t === 0 ? 0 : t === 1 ? 1 : 2 ** (10 * t - 10);
27
+ /** Exponential ease-out. */
28
+ const expoOut = easeOut(expoIn);
29
+ /** Exponential ease-in-out. */
30
+ const expoInOut = easeInOut(expoIn);
31
+ /** Lookup table of easing functions keyed by name. */
32
+ const TWEEN_EASING = {
33
+ "linear": (t) => t,
34
+ "sine.in": sineIn,
35
+ "sine.out": sineOut,
36
+ "sine.inOut": sineInOut,
37
+ "quad.in": quad.in,
38
+ "quad.out": quad.out,
39
+ "quad.inOut": quad.inOut,
40
+ "cubic.in": cubic.in,
41
+ "cubic.out": cubic.out,
42
+ "cubic.inOut": cubic.inOut,
43
+ "expo.in": expoIn,
44
+ "expo.out": expoOut,
45
+ "expo.inOut": expoInOut
46
+ };
47
+ //#endregion
48
+ export { TWEEN_EASING, easeInOut, easeOut, makePowerEase };
49
+
50
+ //# sourceMappingURL=easing.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"easing.mjs","names":[],"sources":["../src/easing.ts"],"sourcesContent":["/** Easing function name. */\nexport type EasingName = 'linear'\n | 'sine.in' | 'sine.out' | 'sine.inOut'\n | 'quad.in' | 'quad.out' | 'quad.inOut'\n | 'cubic.in' | 'cubic.out' | 'cubic.inOut'\n | 'expo.in' | 'expo.out' | 'expo.inOut';\n\n/** A function that maps a linear progress value (0-1) to an eased value (0-1).*/\nexport type EasingFunction = (t: number) => number;\n\n/** Flips an ease-in function into its ease-out equivalent. */\nexport const easeOut = (f: EasingFunction): EasingFunction =>\n t => 1 - f(1 - t);\n\n/** Combines an ease-in function with its inverse for a symmetric ease-in-out curve. */\nexport const easeInOut = (f: EasingFunction): EasingFunction =>\n t => t < 0.5 ? f(2*t) / 2 : 1 - f(-2 * t + 2) / 2;\n\n/** Generates in/out/inOut easing functions for a given exponent. */\nexport const makePowerEase = (exponent: number) => {\n const i: EasingFunction = t => t ** exponent;\n return { in: i, out: easeOut(i), inOut: easeInOut(i) };\n};\n\n/** Sine ease-in base curve. */\nconst sineIn: EasingFunction = t => 1 - Math.cos(t * Math.PI / 2);\n/** Sine ease-out. */\nconst sineOut: EasingFunction = easeOut(sineIn);\n/** Sine ease-in-out. */\nconst sineInOut: EasingFunction = easeInOut(sineIn);\n\n/** Quadratic easing curves. */\nconst quad = makePowerEase(2);\n/** Cubic easing curves.*/\nconst cubic = makePowerEase(3);\n\n/** Exponential ease-in with edge case guards. */\nconst expoIn: EasingFunction = t => t === 0 ? 0 : t === 1 ? 1 : 2 ** (10 * t - 10);\n/** Exponential ease-out. */\nconst expoOut: EasingFunction = easeOut(expoIn);\n/** Exponential ease-in-out. */\nconst expoInOut: EasingFunction = easeInOut(expoIn);\n\n/** Lookup table of easing functions keyed by name. */\nexport const TWEEN_EASING: Readonly<Record<EasingName, EasingFunction>> = {\n 'linear': t => t,\n\n // Sine\n 'sine.in': sineIn,\n 'sine.out': sineOut,\n 'sine.inOut': sineInOut,\n\n // Quad\n 'quad.in': quad.in,\n 'quad.out': quad.out,\n 'quad.inOut': quad.inOut,\n\n // Cubic\n 'cubic.in': cubic.in,\n 'cubic.out': cubic.out,\n 'cubic.inOut': cubic.inOut,\n\n // Exponential\n 'expo.in': expoIn,\n 'expo.out': expoOut,\n 'expo.inOut': expoInOut,\n}\n"],"mappings":";;AAWA,MAAa,WAAW,OACtB,MAAK,IAAI,EAAE,IAAI,CAAC;;AAGlB,MAAa,aAAa,OACxB,MAAK,IAAI,KAAM,EAAE,IAAE,CAAC,IAAI,IAAI,IAAI,EAAE,KAAK,IAAI,CAAC,IAAI;;AAGlD,MAAa,iBAAiB,aAAqB;CACjD,MAAM,KAAoB,MAAK,KAAK;CACpC,OAAO;EAAE,IAAI;EAAG,KAAK,QAAQ,CAAC;EAAG,OAAO,UAAU,CAAC;CAAE;AACvD;;AAGA,MAAM,UAA4B,MAAK,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,CAAC;;AAEnE,MAAM,UAA4B,QAAQ,MAAM;;AAEhD,MAAM,YAA4B,UAAU,MAAM;;AAGlD,MAAM,OAAO,cAAc,CAAC;;AAE5B,MAAM,QAAQ,cAAc,CAAC;;AAG7B,MAAM,UAAyB,MAAK,MAAM,IAAI,IAAI,MAAM,IAAI,IAAI,MAAM,KAAK,IAAI;;AAE/E,MAAM,UAA4B,QAAQ,MAAM;;AAEhD,MAAM,YAA4B,UAAU,MAAM;;AAGlD,MAAa,eAA6D;CACxE,WAAe,MAAK;CAGpB,WAAe;CACf,YAAe;CACf,cAAe;CAGf,WAAe,KAAK;CACpB,YAAe,KAAK;CACpB,cAAe,KAAK;CAGpB,YAAe,MAAM;CACrB,aAAe,MAAM;CACrB,eAAe,MAAM;CAGrB,WAAe;CACf,YAAe;CACf,cAAe;AACjB"}
@@ -1,9 +1,13 @@
1
- import type { TweenManager } from "./types.js";
1
+ import { TweenManager } from "./types.mjs";
2
+
3
+ //#region src/manager.d.ts
2
4
  /** Creates a tween manager that drives property animations each frame.
3
5
  *
4
6
  * Call `update` once per frame with the frame delta in **ms**.
5
7
  *
6
8
  * @returns A {@link TweenManager} with `add`, `update`, and `stopAll`.
7
9
  */
8
- export declare function createTweenManager(): TweenManager;
9
- //# sourceMappingURL=manager.d.ts.map
10
+ declare function createTweenManager(): TweenManager;
11
+ //#endregion
12
+ export { createTweenManager };
13
+ //# sourceMappingURL=manager.d.mts.map
@@ -0,0 +1,153 @@
1
+ import { TWEEN_EASING } from "./easing.mjs";
2
+ //#region src/manager.ts
3
+ /** Creates a tween manager that drives property animations each frame.
4
+ *
5
+ * Call `update` once per frame with the frame delta in **ms**.
6
+ *
7
+ * @returns A {@link TweenManager} with `add`, `update`, and `stopAll`.
8
+ */
9
+ function createTweenManager() {
10
+ const tweens = /* @__PURE__ */ new Set();
11
+ /** Adds and starts a tween from the given config.
12
+ * @returns A {@link TweenHandle} to control the tween.
13
+ */
14
+ function add(config) {
15
+ const targetArray = Array.isArray(config.targets) ? [...config.targets] : [config.targets];
16
+ const easeFn = TWEEN_EASING[config.ease ?? "linear"];
17
+ const tween = {
18
+ targets: targetArray.map((obj) => {
19
+ const props = {};
20
+ const keys = [];
21
+ for (const [key, val] of Object.entries(config.props)) {
22
+ if (val === void 0) continue;
23
+ props[key] = typeof val === "number" ? {
24
+ from: obj[key] ?? 0,
25
+ to: val
26
+ } : val;
27
+ keys.push(key);
28
+ }
29
+ return {
30
+ obj,
31
+ props,
32
+ keys
33
+ };
34
+ }),
35
+ duration: config.duration,
36
+ ease: easeFn,
37
+ yoyo: config.yoyo ?? false,
38
+ repeat: config.repeat ?? 0,
39
+ delay: config.delay ?? 0,
40
+ elapsed: 0,
41
+ delayElapsed: 0,
42
+ direction: 1,
43
+ repeatsDone: 0,
44
+ started: false,
45
+ paused: false,
46
+ stopped: false,
47
+ onStart: config.onStart,
48
+ onUpdate: config.onUpdate,
49
+ onComplete: config.onComplete,
50
+ onYoyo: config.onYoyo,
51
+ onRepeat: config.onRepeat
52
+ };
53
+ tweens.add(tween);
54
+ return {
55
+ stop: () => {
56
+ if (!tween.stopped) {
57
+ tween.stopped = true;
58
+ tweens.delete(tween);
59
+ }
60
+ },
61
+ pause: () => {
62
+ if (!tween.stopped) tween.paused = true;
63
+ },
64
+ resume: () => {
65
+ if (!tween.stopped) tween.paused = false;
66
+ },
67
+ get isPlaying() {
68
+ return !tween.paused && !tween.stopped;
69
+ }
70
+ };
71
+ }
72
+ /** Advances all active tweens by `deltaMs` **milliseconds**. Call once per frame. */
73
+ function update(deltaMs) {
74
+ for (const tween of [...tweens]) {
75
+ if (tween.paused || tween.stopped) continue;
76
+ let step = deltaMs;
77
+ if (tween.delayElapsed < tween.delay) {
78
+ const remaining = tween.delay - tween.delayElapsed;
79
+ if (step <= remaining) {
80
+ tween.delayElapsed += step;
81
+ continue;
82
+ }
83
+ tween.delayElapsed = tween.delay;
84
+ step -= remaining;
85
+ }
86
+ if (!tween.started) {
87
+ tween.started = true;
88
+ tween.onStart?.();
89
+ }
90
+ if (tween.duration <= 0) {
91
+ for (const { obj, props, keys } of tween.targets) for (const key of keys) {
92
+ const resolved = props[key];
93
+ if (resolved) obj[key] = resolved.to;
94
+ }
95
+ tween.onUpdate?.(1);
96
+ tween.onComplete?.();
97
+ tweens.delete(tween);
98
+ continue;
99
+ }
100
+ while (step > 0 && !tween.stopped) {
101
+ const next = tween.elapsed + step;
102
+ const overflow = Math.max(0, next - tween.duration);
103
+ tween.elapsed = Math.min(next, tween.duration);
104
+ const raw = tween.elapsed / tween.duration;
105
+ const t = tween.direction === 1 ? tween.ease(raw) : tween.ease(1 - raw);
106
+ for (const { obj, props, keys } of tween.targets) for (const key of keys) {
107
+ const resolved = props[key];
108
+ if (resolved) obj[key] = resolved.from + (resolved.to - resolved.from) * t;
109
+ }
110
+ tween.onUpdate?.(t);
111
+ if (tween.elapsed >= tween.duration) {
112
+ if (tween.yoyo) if (tween.direction === 1) {
113
+ tween.direction = -1;
114
+ tween.onYoyo?.();
115
+ } else {
116
+ tween.direction = 1;
117
+ if (tween.repeat === -1 || tween.repeatsDone < tween.repeat) {
118
+ tween.repeatsDone++;
119
+ tween.onRepeat?.();
120
+ } else {
121
+ tween.onComplete?.();
122
+ tweens.delete(tween);
123
+ break;
124
+ }
125
+ }
126
+ else if (tween.repeat === -1 || tween.repeatsDone < tween.repeat) {
127
+ tween.repeatsDone++;
128
+ tween.onRepeat?.();
129
+ } else {
130
+ tween.onComplete?.();
131
+ tweens.delete(tween);
132
+ break;
133
+ }
134
+ tween.elapsed = overflow;
135
+ step = overflow;
136
+ } else step = 0;
137
+ }
138
+ }
139
+ }
140
+ /** Immediately stops and removes all active tweens. */
141
+ function stopAll() {
142
+ tweens.clear();
143
+ }
144
+ return {
145
+ add,
146
+ update,
147
+ stopAll
148
+ };
149
+ }
150
+ //#endregion
151
+ export { createTweenManager };
152
+
153
+ //# sourceMappingURL=manager.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.mjs","names":[],"sources":["../src/manager.ts"],"sourcesContent":["import { type EasingFunction, TWEEN_EASING } from \"./easing.js\";\nimport type { TweenConfig, TweenHandle, TweenTarget, TweenManager } from \"./types.js\";\n\ntype ResolvedProp = {\n readonly from: number;\n readonly to: number\n};\ntype ResolvedTarget = {\n readonly obj: TweenTarget;\n readonly props: Partial<Record<keyof TweenTarget, ResolvedProp>>\n readonly keys: readonly (keyof TweenTarget)[];\n};\n\ninterface ActiveTween {\n readonly targets: readonly ResolvedTarget[];\n readonly duration: number;\n readonly delay: number;\n readonly ease: EasingFunction;\n readonly yoyo: boolean;\n readonly repeat: number;\n\n elapsed: number;\n delayElapsed: number;\n direction: 1 | -1;\n repeatsDone: number;\n started: boolean;\n paused: boolean;\n stopped: boolean;\n\n readonly onStart: (() => void) | undefined;\n readonly onUpdate: ((progress: number) => void )| undefined;\n readonly onComplete: (() => void) | undefined;\n readonly onYoyo: (() => void) | undefined;\n readonly onRepeat: (() => void) | undefined;\n}\n\n/** Creates a tween manager that drives property animations each frame.\n *\n * Call `update` once per frame with the frame delta in **ms**.\n *\n * @returns A {@link TweenManager} with `add`, `update`, and `stopAll`.\n */\nexport function createTweenManager(): TweenManager {\n const tweens = new Set<ActiveTween>();\n\n /** Adds and starts a tween from the given config.\n * @returns A {@link TweenHandle} to control the tween.\n */\n function add(config: TweenConfig): TweenHandle {\n const targetArray = Array.isArray(config.targets) ? [...config.targets] : [config.targets];\n const easeFn = TWEEN_EASING[config.ease ?? 'linear'];\n\n const resolvedTargets: ResolvedTarget[] = targetArray.map(obj => {\n const props: Partial<Record<keyof TweenTarget, ResolvedProp>> = {};\n const keys: (keyof TweenTarget)[] = [];\n for (const [key, val] of Object.entries(config.props) as\n [keyof TweenTarget, typeof config.props[keyof TweenTarget]][]\n ) {\n if (val === undefined) continue;\n props[key] = typeof val === 'number' ? { from: obj[key] ?? 0, to: val } : val;\n keys.push(key);\n }\n return { obj, props, keys };\n });\n\n const tween: ActiveTween = {\n targets: resolvedTargets,\n duration: config.duration,\n ease: easeFn,\n yoyo: config.yoyo ?? false,\n repeat: config.repeat ?? 0,\n delay: config.delay ?? 0,\n elapsed: 0,\n delayElapsed: 0,\n direction: 1,\n repeatsDone: 0,\n started: false,\n paused: false,\n stopped: false,\n onStart: config.onStart,\n onUpdate: config.onUpdate,\n onComplete: config.onComplete,\n onYoyo: config.onYoyo,\n onRepeat: config.onRepeat,\n };\n\n tweens.add(tween);\n\n return {\n stop: () => { if (!tween.stopped) { tween.stopped = true; tweens.delete(tween); } },\n pause: () => { if (!tween.stopped) tween.paused = true; },\n resume: () => { if (!tween.stopped) tween.paused = false; },\n get isPlaying() { return !tween.paused && !tween.stopped; },\n };\n }\n\n /** Advances all active tweens by `deltaMs` **milliseconds**. Call once per frame. */\n function update(deltaMs: number): void {\n for (const tween of [...tweens]) {\n if (tween.paused || tween.stopped) continue;\n\n let step = deltaMs;\n if (tween.delayElapsed < tween.delay) {\n const remaining = tween.delay - tween.delayElapsed;\n if (step <= remaining) {\n tween.delayElapsed += step;\n continue;\n }\n tween.delayElapsed = tween.delay;\n step -= remaining;\n }\n\n if (!tween.started) {\n tween.started = true;\n tween.onStart?.();\n }\n\n if (tween.duration <= 0) {\n for (const { obj, props, keys } of tween.targets) {\n for (const key of keys) {\n const resolved = props[key];\n if (resolved) obj[key] = resolved.to;\n }\n }\n\n tween.onUpdate?.(1);\n tween.onComplete?.();\n tweens.delete(tween);\n continue;\n }\n\n while (step > 0 && !tween.stopped) {\n const next = tween.elapsed + step;\n const overflow = Math.max(0, next - tween.duration);\n tween.elapsed = Math.min(next, tween.duration);\n\n const raw = tween.elapsed / tween.duration;\n const t = tween.direction === 1 ? tween.ease(raw) : tween.ease(1 - raw);\n\n for (const { obj, props, keys } of tween.targets) {\n for (const key of keys) {\n const resolved = props[key];\n if (resolved) obj[key] = resolved.from + (resolved.to - resolved.from) * t;\n }\n }\n\n tween.onUpdate?.(t);\n\n if (tween.elapsed >= tween.duration) {\n if (tween.yoyo) {\n if (tween.direction === 1) {\n tween.direction = -1;\n tween.onYoyo?.();\n } else {\n tween.direction = 1;\n if (tween.repeat === -1 || tween.repeatsDone < tween.repeat) {\n tween.repeatsDone++;\n tween.onRepeat?.();\n } else {\n tween.onComplete?.();\n tweens.delete(tween);\n break;\n }\n }\n } else {\n if (tween.repeat === -1 || tween.repeatsDone < tween.repeat) {\n tween.repeatsDone++;\n tween.onRepeat?.();\n } else {\n tween.onComplete?.();\n tweens.delete(tween);\n break;\n }\n }\n tween.elapsed = overflow;\n step = overflow;\n } else {\n step = 0;\n }\n }\n }\n }\n\n /** Immediately stops and removes all active tweens. */\n function stopAll(): void {\n tweens.clear();\n }\n\n return { add, update, stopAll };\n}\n"],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ import { EasingName } from "./easing.mjs";
2
+
3
+ //#region src/types.d.ts
4
+ /** An object whose properties can be animated by the tween system. */
5
+ type TweenTarget = {
6
+ alpha?: number;
7
+ y?: number;
8
+ };
9
+ /** A single target, or an array of targets to animate in parallel. */
10
+ type TweenTargets = TweenTarget | readonly TweenTarget[];
11
+ /** A target value: number (tweens from current) or explicit from/to. */
12
+ type TweenPropValue = number | {
13
+ from: number;
14
+ to: number;
15
+ };
16
+ /** Map of supported property names to target values. */
17
+ type TweenProps = Partial<Record<keyof TweenTarget, TweenPropValue>>;
18
+ /** Configuration for a tween animation. */
19
+ interface TweenConfig {
20
+ /** Target or array of targets whose properties will be animated. */
21
+ targets: TweenTargets;
22
+ /** Map of supported property names to target values. */
23
+ props: TweenProps;
24
+ /** Duration of one pass in milliseconds. */
25
+ duration: number;
26
+ /** Delay before starting in milliseconds. Default: 0. */
27
+ delay?: number;
28
+ /** Easing function. Default: 'linear'. */
29
+ ease?: EasingName;
30
+ /** Reverse the animation at the end of each pass. Default: false. */
31
+ yoyo?: boolean;
32
+ /**
33
+ * Additional repeat count after the first play. 0 = play once, -1 = infinite.
34
+ * With yoyo, each forward+backward pair counts as one repeat.
35
+ * Default: 0.
36
+ */
37
+ repeat?: number;
38
+ /** Called once when the tween starts (after any delay). */
39
+ onStart?: () => void;
40
+ /** Called every frame with the eased progress value (0–1). */
41
+ onUpdate?: (progress: number) => void;
42
+ /** Called each time a yoyo reverses direction (forward → backward). */
43
+ onYoyo?: () => void;
44
+ /** Called at the start of each new repeat cycle (backward → forward). */
45
+ onRepeat?: () => void;
46
+ /** Called when the tween fully completes. Not called for infinite repeats. */
47
+ onComplete?: () => void;
48
+ }
49
+ /** A handle to control a running tween returned by {@link TweenManager.add}.*/
50
+ interface TweenHandle {
51
+ /** Immediately stop and remove the tween. */
52
+ stop(): void;
53
+ /** Pause without removing. */
54
+ pause(): void;
55
+ /** Resume a paused tween. */
56
+ resume(): void;
57
+ /** `true` if the tween is active and not paused. */
58
+ readonly isPlaying: boolean;
59
+ }
60
+ /** Manages a collection of active tweens, advancing them each frame. */
61
+ interface TweenManager {
62
+ /** Adds and starts a tween from the given config.
63
+ * @returns A {@link TweenHandle} to control the tween.
64
+ */
65
+ add(config: TweenConfig): TweenHandle;
66
+ /** Advances all active tweens by `deltaMs` **ms**. Call once per frame. */
67
+ update(deltaMs: number): void;
68
+ /** Immediately stops and removes all active tweens. */
69
+ stopAll(): void;
70
+ }
71
+ //#endregion
72
+ export { TweenConfig, TweenHandle, TweenManager, TweenPropValue, TweenProps, TweenTarget, TweenTargets };
73
+ //# sourceMappingURL=types.d.mts.map
package/dist/types.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import "./easing.mjs";
2
+ export {};
package/package.json CHANGED
@@ -1,37 +1,43 @@
1
- {
2
- "name": "@starweb-libs/tween",
3
- "description": "Frame-driven tween manager with easing for the browser",
4
- "author": "Mason L'Etoile",
5
- "version": "0.0.1",
6
- "license": "MIT",
7
- "repository": {
8
- "type": "git",
9
- "url": "git+https://github.com/starweb-libs/tween.git"
10
- },
11
- "homepage": "https://github.com/starweb-libs/tween#readme",
12
- "bugs": {
13
- "url": "https://github.com/starweb-libs/tween/issues"
14
- },
15
- "keywords": ["tween", "animation", "easing", "typescript", "browser", "starweb"],
16
- "type": "module",
17
- "devDependencies": { "typescript": "~6.0.2" },
18
- "scripts": {
19
- "build": "tsc -p tsconfig.build.json",
20
- "prepare": "npm run build"
21
- },
22
- "files": ["dist"],
23
- "exports": {
24
- "./easing.js": {
25
- "types": "./dist/easing.d.ts",
26
- "import": "./dist/easing.js"
27
- },
28
- "./manager.js": {
29
- "types": "./dist/manager.d.ts",
30
- "import": "./dist/manager.js"
31
- },
32
- "./types.js": {
33
- "types": "./dist/types.d.ts",
34
- "import": "./dist/types.js"
35
- }
36
- }
37
- }
1
+ {
2
+ "name": "@starweb-libs/tween",
3
+ "description": "Frame-driven tween manager with easing for the browser",
4
+ "author": "Mason L'Etoile",
5
+ "version": "0.0.2",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/starweb-libs/tween.git"
10
+ },
11
+ "homepage": "https://github.com/starweb-libs/tween#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/starweb-libs/tween/issues"
14
+ },
15
+ "keywords": ["tween", "animation", "easing", "typescript", "browser", "starweb"],
16
+ "type": "module",
17
+ "devDependencies": {
18
+ "typescript": "~6.0.2",
19
+ "tsdown": "^0.22.0"
20
+ },
21
+ "scripts": {
22
+ "build": "tsdown",
23
+ "prepare": "npm run build"
24
+ },
25
+ "files": ["dist"],
26
+ "exports": {
27
+ "./easing.js": {
28
+ "types": "./dist/easing.d.mts",
29
+ "@starweb-libs/source": "./src/easing.ts",
30
+ "import": "./dist/easing.mjs"
31
+ },
32
+ "./manager.js": {
33
+ "types": "./dist/manager.d.mts",
34
+ "@starweb-libs/source": "./src/manager.ts",
35
+ "import": "./dist/manager.mjs"
36
+ },
37
+ "./types.js": {
38
+ "types": "./dist/types.d.mts",
39
+ "@starweb-libs/source": "./src/types.ts",
40
+ "import": "./dist/types.mjs"
41
+ }
42
+ }
43
+ }
package/dist/easing.d.ts DELETED
@@ -1,17 +0,0 @@
1
- /** Easing function name. */
2
- export type EasingName = 'linear' | 'sine.in' | 'sine.out' | 'sine.inOut' | 'quad.in' | 'quad.out' | 'quad.inOut' | 'cubic.in' | 'cubic.out' | 'cubic.inOut' | 'expo.in' | 'expo.out' | 'expo.inOut';
3
- /** A function that maps a linear progress value (0-1) to an eased value (0-1).*/
4
- export type EasingFunction = (t: number) => number;
5
- /** Flips an ease-in function into its ease-out equivalent. */
6
- export declare const easeOut: (f: EasingFunction) => EasingFunction;
7
- /** Combines an ease-in function with its inverse for a symmetric ease-in-out curve. */
8
- export declare const easeInOut: (f: EasingFunction) => EasingFunction;
9
- /** Generates in/out/inOut easing functions for a given exponent. */
10
- export declare const makePowerEase: (exponent: number) => {
11
- in: EasingFunction;
12
- out: EasingFunction;
13
- inOut: EasingFunction;
14
- };
15
- /** Lookup table of easing functions keyed by name. */
16
- export declare const TWEEN_EASING: Readonly<Record<EasingName, EasingFunction>>;
17
- //# sourceMappingURL=easing.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"easing.d.ts","sourceRoot":"","sources":["../src/easing.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAC5B,MAAM,MAAM,UAAU,GAAG,QAAQ,GACL,SAAS,GAAK,UAAU,GAAK,YAAY,GACzC,SAAS,GAAK,UAAU,GAAK,YAAY,GACzC,UAAU,GAAI,WAAW,GAAI,aAAa,GAC1C,SAAS,GAAK,UAAU,GAAK,YAAY,CAAC;AAEtE,iFAAiF;AACjF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AAEnD,8DAA8D;AAC9D,eAAO,MAAM,OAAO,GAAI,GAAG,cAAc,KAAG,cACzB,CAAC;AAEpB,uFAAuF;AACvF,eAAO,MAAM,SAAS,GAAI,GAAG,cAAc,KAAG,cACK,CAAC;AAEpD,oEAAoE;AACpE,eAAO,MAAM,aAAa,GAAI,UAAU,MAAM;;;;CAG7C,CAAC;AAqBF,sDAAsD;AACtD,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,cAAc,CAAC,CAsBrE,CAAA"}
package/dist/easing.js DELETED
@@ -1,46 +0,0 @@
1
- /** Flips an ease-in function into its ease-out equivalent. */
2
- export const easeOut = (f) => t => 1 - f(1 - t);
3
- /** Combines an ease-in function with its inverse for a symmetric ease-in-out curve. */
4
- export const easeInOut = (f) => t => t < 0.5 ? f(2 * t) / 2 : 1 - f(-2 * t + 2) / 2;
5
- /** Generates in/out/inOut easing functions for a given exponent. */
6
- export const makePowerEase = (exponent) => {
7
- const i = t => t ** exponent;
8
- return { in: i, out: easeOut(i), inOut: easeInOut(i) };
9
- };
10
- /** Sine ease-in base curve. */
11
- const sineIn = t => 1 - Math.cos(t * Math.PI / 2);
12
- /** Sine ease-out. */
13
- const sineOut = easeOut(sineIn);
14
- /** Sine ease-in-out. */
15
- const sineInOut = easeInOut(sineIn);
16
- /** Quadratic easing curves. */
17
- const quad = makePowerEase(2);
18
- /** Cubic easing curves.*/
19
- const cubic = makePowerEase(3);
20
- /** Exponential ease-in with edge case guards. */
21
- const expoIn = t => t === 0 ? 0 : t === 1 ? 1 : 2 ** (10 * t - 10);
22
- /** Exponential ease-out. */
23
- const expoOut = easeOut(expoIn);
24
- /** Exponential ease-in-out. */
25
- const expoInOut = easeInOut(expoIn);
26
- /** Lookup table of easing functions keyed by name. */
27
- export const TWEEN_EASING = {
28
- 'linear': t => t,
29
- // Sine
30
- 'sine.in': sineIn,
31
- 'sine.out': sineOut,
32
- 'sine.inOut': sineInOut,
33
- // Quad
34
- 'quad.in': quad.in,
35
- 'quad.out': quad.out,
36
- 'quad.inOut': quad.inOut,
37
- // Cubic
38
- 'cubic.in': cubic.in,
39
- 'cubic.out': cubic.out,
40
- 'cubic.inOut': cubic.inOut,
41
- // Exponential
42
- 'expo.in': expoIn,
43
- 'expo.out': expoOut,
44
- 'expo.inOut': expoInOut,
45
- };
46
- //# sourceMappingURL=easing.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"easing.js","sourceRoot":"","sources":["../src/easing.ts"],"names":[],"mappings":"AAUA,8DAA8D;AAC9D,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAiB,EAAkB,EAAE,CAC3D,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAEpB,uFAAuF;AACvF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAiB,EAAkB,EAAE,CAC7D,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AAEpD,oEAAoE;AACpE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAgB,EAAE,EAAE;IAChD,MAAM,CAAC,GAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,QAAQ,CAAC;IAC7C,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;AACzD,CAAC,CAAC;AAEF,+BAA+B;AAC/B,MAAM,MAAM,GAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;AACrE,qBAAqB;AACrB,MAAM,OAAO,GAAqB,OAAO,CAAC,MAAM,CAAC,CAAC;AAClD,wBAAwB;AACxB,MAAM,SAAS,GAAmB,SAAS,CAAC,MAAM,CAAC,CAAC;AAEpD,+BAA+B;AAC/B,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;AAC9B,0BAA0B;AAC1B,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;AAE/B,iDAAiD;AACjD,MAAM,MAAM,GAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;AACnF,4BAA4B;AAC5B,MAAM,OAAO,GAAqB,OAAO,CAAC,MAAM,CAAC,CAAC;AAClD,+BAA+B;AAC/B,MAAM,SAAS,GAAmB,SAAS,CAAC,MAAM,CAAC,CAAC;AAEpD,sDAAsD;AACtD,MAAM,CAAC,MAAM,YAAY,GAAiD;IACxE,QAAQ,EAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAErB,OAAO;IACP,SAAS,EAAM,MAAM;IACrB,UAAU,EAAK,OAAO;IACtB,YAAY,EAAG,SAAS;IAExB,OAAO;IACP,SAAS,EAAM,IAAI,CAAC,EAAE;IACtB,UAAU,EAAK,IAAI,CAAC,GAAG;IACvB,YAAY,EAAG,IAAI,CAAC,KAAK;IAEzB,QAAQ;IACR,UAAU,EAAK,KAAK,CAAC,EAAE;IACvB,WAAW,EAAI,KAAK,CAAC,GAAG;IACxB,aAAa,EAAE,KAAK,CAAC,KAAK;IAE1B,cAAc;IACd,SAAS,EAAM,MAAM;IACrB,UAAU,EAAK,OAAO;IACtB,YAAY,EAAG,SAAS;CACzB,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAyC,YAAY,EAAE,MAAM,YAAY,CAAC;AAmCtF;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAmJjD"}
package/dist/manager.js DELETED
@@ -1,151 +0,0 @@
1
- import { TWEEN_EASING } from "./easing.js";
2
- /** Creates a tween manager that drives property animations each frame.
3
- *
4
- * Call `update` once per frame with the frame delta in **ms**.
5
- *
6
- * @returns A {@link TweenManager} with `add`, `update`, and `stopAll`.
7
- */
8
- export function createTweenManager() {
9
- const tweens = new Set();
10
- /** Adds and starts a tween from the given config.
11
- * @returns A {@link TweenHandle} to control the tween.
12
- */
13
- function add(config) {
14
- const targetArray = Array.isArray(config.targets) ? [...config.targets] : [config.targets];
15
- const easeFn = TWEEN_EASING[config.ease ?? 'linear'];
16
- const resolvedTargets = targetArray.map(obj => {
17
- const props = {};
18
- const keys = [];
19
- for (const [key, val] of Object.entries(config.props)) {
20
- if (val === undefined)
21
- continue;
22
- props[key] = typeof val === 'number' ? { from: obj[key] ?? 0, to: val } : val;
23
- keys.push(key);
24
- }
25
- return { obj, props, keys };
26
- });
27
- const tween = {
28
- targets: resolvedTargets,
29
- duration: config.duration,
30
- ease: easeFn,
31
- yoyo: config.yoyo ?? false,
32
- repeat: config.repeat ?? 0,
33
- delay: config.delay ?? 0,
34
- elapsed: 0,
35
- delayElapsed: 0,
36
- direction: 1,
37
- repeatsDone: 0,
38
- started: false,
39
- paused: false,
40
- stopped: false,
41
- onStart: config.onStart,
42
- onUpdate: config.onUpdate,
43
- onComplete: config.onComplete,
44
- onYoyo: config.onYoyo,
45
- onRepeat: config.onRepeat,
46
- };
47
- tweens.add(tween);
48
- return {
49
- stop: () => { if (!tween.stopped) {
50
- tween.stopped = true;
51
- tweens.delete(tween);
52
- } },
53
- pause: () => { if (!tween.stopped)
54
- tween.paused = true; },
55
- resume: () => { if (!tween.stopped)
56
- tween.paused = false; },
57
- get isPlaying() { return !tween.paused && !tween.stopped; },
58
- };
59
- }
60
- /** Advances all active tweens by `deltaMs` **milliseconds**. Call once per frame. */
61
- function update(deltaMs) {
62
- for (const tween of [...tweens]) {
63
- if (tween.paused || tween.stopped)
64
- continue;
65
- let step = deltaMs;
66
- if (tween.delayElapsed < tween.delay) {
67
- const remaining = tween.delay - tween.delayElapsed;
68
- if (step <= remaining) {
69
- tween.delayElapsed += step;
70
- continue;
71
- }
72
- tween.delayElapsed = tween.delay;
73
- step -= remaining;
74
- }
75
- if (!tween.started) {
76
- tween.started = true;
77
- tween.onStart?.();
78
- }
79
- if (tween.duration <= 0) {
80
- for (const { obj, props, keys } of tween.targets) {
81
- for (const key of keys) {
82
- const resolved = props[key];
83
- if (resolved)
84
- obj[key] = resolved.to;
85
- }
86
- }
87
- tween.onUpdate?.(1);
88
- tween.onComplete?.();
89
- tweens.delete(tween);
90
- continue;
91
- }
92
- while (step > 0 && !tween.stopped) {
93
- const next = tween.elapsed + step;
94
- const overflow = Math.max(0, next - tween.duration);
95
- tween.elapsed = Math.min(next, tween.duration);
96
- const raw = tween.elapsed / tween.duration;
97
- const t = tween.direction === 1 ? tween.ease(raw) : tween.ease(1 - raw);
98
- for (const { obj, props, keys } of tween.targets) {
99
- for (const key of keys) {
100
- const resolved = props[key];
101
- if (resolved)
102
- obj[key] = resolved.from + (resolved.to - resolved.from) * t;
103
- }
104
- }
105
- tween.onUpdate?.(t);
106
- if (tween.elapsed >= tween.duration) {
107
- if (tween.yoyo) {
108
- if (tween.direction === 1) {
109
- tween.direction = -1;
110
- tween.onYoyo?.();
111
- }
112
- else {
113
- tween.direction = 1;
114
- if (tween.repeat === -1 || tween.repeatsDone < tween.repeat) {
115
- tween.repeatsDone++;
116
- tween.onRepeat?.();
117
- }
118
- else {
119
- tween.onComplete?.();
120
- tweens.delete(tween);
121
- break;
122
- }
123
- }
124
- }
125
- else {
126
- if (tween.repeat === -1 || tween.repeatsDone < tween.repeat) {
127
- tween.repeatsDone++;
128
- tween.onRepeat?.();
129
- }
130
- else {
131
- tween.onComplete?.();
132
- tweens.delete(tween);
133
- break;
134
- }
135
- }
136
- tween.elapsed = overflow;
137
- step = overflow;
138
- }
139
- else {
140
- step = 0;
141
- }
142
- }
143
- }
144
- }
145
- /** Immediately stops and removes all active tweens. */
146
- function stopAll() {
147
- tweens.clear();
148
- }
149
- return { add, update, stopAll };
150
- }
151
- //# sourceMappingURL=manager.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"manager.js","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts DELETED
@@ -1,69 +0,0 @@
1
- import { type EasingName } from "./easing.js";
2
- /** An object whose properties can be animated by the tween system. */
3
- export type TweenTarget = {
4
- alpha?: number;
5
- y?: number;
6
- };
7
- /** A single target, or an array of targets to animate in parallel. */
8
- export type TweenTargets = TweenTarget | readonly TweenTarget[];
9
- /** A target value: number (tweens from current) or explicit from/to. */
10
- export type TweenPropValue = number | {
11
- from: number;
12
- to: number;
13
- };
14
- /** Map of supported property names to target values. */
15
- export type TweenProps = Partial<Record<keyof TweenTarget, TweenPropValue>>;
16
- /** Configuration for a tween animation. */
17
- export interface TweenConfig {
18
- /** Target or array of targets whose properties will be animated. */
19
- targets: TweenTargets;
20
- /** Map of supported property names to target values. */
21
- props: TweenProps;
22
- /** Duration of one pass in milliseconds. */
23
- duration: number;
24
- /** Delay before starting in milliseconds. Default: 0. */
25
- delay?: number;
26
- /** Easing function. Default: 'linear'. */
27
- ease?: EasingName;
28
- /** Reverse the animation at the end of each pass. Default: false. */
29
- yoyo?: boolean;
30
- /**
31
- * Additional repeat count after the first play. 0 = play once, -1 = infinite.
32
- * With yoyo, each forward+backward pair counts as one repeat.
33
- * Default: 0.
34
- */
35
- repeat?: number;
36
- /** Called once when the tween starts (after any delay). */
37
- onStart?: () => void;
38
- /** Called every frame with the eased progress value (0–1). */
39
- onUpdate?: (progress: number) => void;
40
- /** Called each time a yoyo reverses direction (forward → backward). */
41
- onYoyo?: () => void;
42
- /** Called at the start of each new repeat cycle (backward → forward). */
43
- onRepeat?: () => void;
44
- /** Called when the tween fully completes. Not called for infinite repeats. */
45
- onComplete?: () => void;
46
- }
47
- /** A handle to control a running tween returned by {@link TweenManager.add}.*/
48
- export interface TweenHandle {
49
- /** Immediately stop and remove the tween. */
50
- stop(): void;
51
- /** Pause without removing. */
52
- pause(): void;
53
- /** Resume a paused tween. */
54
- resume(): void;
55
- /** `true` if the tween is active and not paused. */
56
- readonly isPlaying: boolean;
57
- }
58
- /** Manages a collection of active tweens, advancing them each frame. */
59
- export interface TweenManager {
60
- /** Adds and starts a tween from the given config.
61
- * @returns A {@link TweenHandle} to control the tween.
62
- */
63
- add(config: TweenConfig): TweenHandle;
64
- /** Advances all active tweens by `deltaMs` **ms**. Call once per frame. */
65
- update(deltaMs: number): void;
66
- /** Immediately stops and removes all active tweens. */
67
- stopAll(): void;
68
- }
69
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,sEAAsE;AACtE,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ,CAAC;AACF,sEAAsE;AACtE,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,SAAS,WAAW,EAAE,CAAC;AAEhE,wEAAwE;AACxE,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AACnE,wDAAwD;AACxD,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;AAE5E,2CAA2C;AAC3C,MAAM,WAAW,WAAW;IAC1B,oEAAoE;IACpE,OAAO,EAAE,YAAY,CAAC;IACtB,wDAAwD;IACxD,KAAK,EAAE,UAAU,CAAC;IAElB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,0CAA0C;IAC1C,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,qEAAqE;IACrE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,+EAA+E;AAC/E,MAAM,WAAW,WAAW;IAC1B,6CAA6C;IAC7C,IAAI,IAAI,IAAI,CAAC;IACb,8BAA8B;IAC9B,KAAK,IAAI,IAAI,CAAC;IACd,6BAA6B;IAC7B,MAAM,IAAI,IAAI,CAAC;IACf,oDAAoD;IACpD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAAC;IAEtC,2EAA2E;IAC3E,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAE9B,uDAAuD;IACvD,OAAO,IAAI,IAAI,CAAC;CACjB"}
package/dist/types.js DELETED
@@ -1,2 +0,0 @@
1
- import {} from "./easing.js";
2
- //# sourceMappingURL=types.js.map
package/dist/types.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,MAAM,aAAa,CAAC"}