@thednp/tween 0.0.1

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/wiki/Tween.md ADDED
@@ -0,0 +1,230 @@
1
+ ## Tween
2
+
3
+ A tiny, ultra-fast single-object tween engine. Simple, pure and flexible from/to animation with proper DX, chaining methods and support for nested objects. It's the core building block for more complex animations and a lightweight alternative to heavier tween libraries.
4
+ Perfect for reactive stores (SolidJS, Svelte, React, etc), SVG/Canvas animations, or anything needing a single precise tween without overhead.
5
+
6
+ ### Features
7
+ * Chainable methods for best DX
8
+ * Proper relative-to-current start values (captured at `.start()` unless `.from()` used)
9
+ * Nested objects supported out-of-box
10
+ * Custom interpolators via `Tween.use()`
11
+ * Arrays, tuples, colors, paths via included interpolators
12
+ * Callbacks: `onUpdate` (with `elapsed` and eased `progress`), `onComplete`, `onStop`
13
+ * Manual `.update()` for custom timing loops
14
+ * ~150 lines, blazing fast
15
+ * `requestAnimationFrame` loop handled automatically when `.start()` called.
16
+
17
+
18
+ ### Usage
19
+
20
+ ```ts
21
+ import { Tween, Easing, interpolateArray } from '@thednp/tween';
22
+
23
+ // initial state
24
+ const obj = { x: 0, y: 0, rotate: 0, rgb: [255,0,0], opacity: 1 };
25
+
26
+ // Create tween
27
+ const tween1 = new Tween(obj)
28
+ // Optional: register interpolators (arrays work great for colors, vectors)
29
+ .use('rgb', interpolateArray)
30
+ .to({ x: 100, y: 200, rotate: 360, rgb: [0,255,0], opacity: 0.5 })
31
+ .duration(2) // 2 seconds
32
+ .delay(0.5) // 0.5s delay
33
+ .easing(Easing.Elastic.Out)
34
+ .onUpdate((state, elapsed, eased) => {
35
+ // elapsed: raw [0-1] progress
36
+ // eased: progress after easing function
37
+ // update DOM / store / canvas directly
38
+ console.log('Progress:', eased, state);
39
+ })
40
+ .onComplete((state) => {
41
+ console.log('Done!', state);
42
+ })
43
+ .start(); // begins animation right away
44
+
45
+ // Or chain from current values later
46
+ const tween2 = new Tween(obj)
47
+ .duration(1)
48
+ .easing(Easing.Back.InOut);
49
+
50
+ tween2.to({ x: 300 }).start();
51
+ // later:
52
+ tween2.to({ y: 400 }).startFromLast(); // continues from current values
53
+ ```
54
+
55
+ ### API
56
+
57
+ #### `new Tween(initialValues)`
58
+ Creates a new **Tween** instance targeting the provided object, which means this object is updated during the update runtime.
59
+
60
+ #### `.to(endValues)`
61
+ Sets the target **end** values. Can be called multiple times; latest wins.
62
+
63
+ #### `.from(startValues)`
64
+ Explicitly sets **start** values (overrides auto-capture at start).
65
+
66
+ #### `.duration(seconds = 1)`
67
+ Sets animation duration in seconds (converted internally to ms).
68
+
69
+ #### `.delay(seconds = 0)`
70
+ Sets start delay in seconds. More complex arrangements might require delaying a tween before it actually starts running.
71
+
72
+ You can do that using the `delay` method:
73
+
74
+ ```ts
75
+ tween.delay(1.5)
76
+ ```
77
+
78
+ This tween will start updating 1.5 seconds after the `start()` method has been called.
79
+
80
+
81
+ #### `.easing(function = linear)`
82
+ Sets the easing function (from Easing object, custom or external). `Tween` will perform the interpolation between values (i.e. the easing) in a linear manner by default, so the change will be directly proportional to the elapsed time. This is predictable but also quite uninteresting visually wise.
83
+
84
+ This behaviour can be easily changed using the `easing()` method. For example:
85
+
86
+ ```ts
87
+ import { Tween, Easing } from '@thednp/tween'
88
+ // ...
89
+ tween.easing(Easing.Quadratic.In)
90
+ ```
91
+
92
+ This will result in the tween slowly starting to change towards the final value, accelerating towards the middle, and then quickly reaching its final value. In contrast, `Easing.Quadratic.Out` would start changing quickly towards the value, but then slow down as it approaches the final value.
93
+
94
+ #### `.start(time?, overrideStart?)`
95
+ Starts the update loop and fires the `onStart` callback.
96
+
97
+ **Parameters**:
98
+ * Optional `time` - If you use it, the tween won't start until that particular moment in time; otherwise it will start as soon as possible (i.e. on the next call to `tween.update()`).
99
+
100
+ * Optional `overrideStart` forces re-capture of current values, which means that when `true`, a tween that we previously used will start from the values in the target object, instead of starting from the beginning. Useful for stopping a tween, then starting another one that will continue from the current location.
101
+
102
+ #### `.startFromLast(time?)`
103
+ Convenience: starts and forces re-capture of current values (for sequential tweens).
104
+
105
+ #### `.stop()`
106
+ Stops animation and fires `onStop` callback. Stopping a tween that was never started or that has already been stopped has no effect. No errors are thrown either.
107
+
108
+ #### `.update(time?, autoStart?)`
109
+ Updates the state and fires the `onUpdate` callback. Returns true if still active.
110
+
111
+ Individual tweens have an `update()` method to so that they can be updated over time in an animation loop, and on each update they will apply updated values to their target object.
112
+
113
+ The global update loop is handled automatically once you call `start()`:
114
+
115
+ ```ts
116
+ // your defined tween
117
+ const tween = new Tween(someObject).to(/*...*/)
118
+
119
+ // later or anytime
120
+ tween.start()
121
+ ```
122
+ When no active `Tween` objects remain, the global update loop stops automatically.
123
+
124
+ ### Callbacks
125
+
126
+ Another powerful feature is to be able to run your own functions at specific times in each tween's life cycle. This is usually required when changing properties is not enough.
127
+
128
+ For example, suppose you're trying to animate some object whose properties can't be accessed directly but require you to call a setter instead. You can use an `update` callback to read the new updated values and then manually call the setters. All callbacks are passed the tweened `object` as the first parameter, and the second parameter as the [0-1] elapsed (or progress).
129
+
130
+ #### `.onStart(callback)`
131
+ Callback receives (`object`) parameter and is fired right before the tween starts animating, after any delay time specified by the `delay()` method.
132
+
133
+ It's great for synchronising to other events or triggering actions you want to happen when a tween starts.
134
+
135
+
136
+ #### `.onUpdate(callback)`
137
+ Add a callback which receives (`object`, `elapsed`[0-1 raw], `value`[0-1 after easing]) parameters.
138
+
139
+ Executed each time the tween is updated, after the values have been actually updated.
140
+
141
+ #### `.onComplete(callback)`
142
+ A callback which receives (`object`) parameter when finished. Executed when a tween is finished normally (i.e. not stopped).
143
+
144
+ #### `.onStop(callback)`
145
+ A callback which receives (`object`) parameter and is fired when calling `stop()`, but not when it is completed normally.
146
+
147
+ #### Custom Interpolators
148
+ The `.use(propName: string, interpolationFunction: InterpolatorFunction)` allows you to add custom interpolator functions for your instance.
149
+
150
+
151
+ ### Tween State
152
+ #### `.isPlaying`
153
+ Getter: `boolean` whether currently running.
154
+
155
+
156
+ ### Custom Interpolators
157
+
158
+ Same as [Timeline](Timeline.md) - use the provided `interpolateArray` and `interpolatePath`.
159
+
160
+ **Example for colors**:
161
+
162
+ ```ts
163
+ import { Tween, interpolateArray } from "@thednp/tween";
164
+
165
+ new Tween({ rgb: [255,0,0] })
166
+ .use('rgb', interpolateArray)
167
+ .to({ rgb: [0,255,0] })
168
+ .onUpdate((state) => {
169
+ // update App state
170
+ // OR update DOM elements directly
171
+ Object.assign(
172
+ target.style,
173
+ { "background-color": "rgb(" + state.rgb.join(",") + ")" }),
174
+ });
175
+ .duration(1.5)
176
+ .start();
177
+ ```
178
+
179
+ **Example for SVG path**
180
+
181
+ The `interpolatePath` interpolator adds SVG morph capability and assumes compatible paths (same segment count/types and coordinate counts — use [svg-path-commander](https://github.com/thednp/svg-path-commander) to process if needed).
182
+
183
+ ```ts
184
+ import { Tween, interpolatePath } from "@thednp/tween";
185
+
186
+ // Use a fast `PathArray` to string
187
+ // For faster performance use `pathToString` from svg-path-commander
188
+ function pathToString(path: ["M" | "C" | "L", ...number[]][]) {
189
+ return p.map(([c, ...args]) => c + args.join(",")).join(" ");
190
+ }
191
+
192
+ const path = document.getElementById("my-path");
193
+ // "M0,0 L600,0 L600,300 L600,600 L0,600 Z"
194
+ const square = [
195
+ ["M", 0, 0],
196
+ ["L", 600, 0],
197
+ ["L", 600, 300], // mid
198
+ ["L", 600, 600],
199
+ ["L", 0, 600],
200
+ ["Z"],
201
+ ];
202
+
203
+ // "M0,0 L300,150 L600,300 L300,450 L0,600 Z"
204
+ const triangle = [
205
+ ["M", 150, 0],
206
+ ["L", 300, 150], // mid
207
+ ["L", 450, 300],
208
+ ["L", 300, 450], // mid
209
+ ["L", 150, 600],
210
+ ["Z"],
211
+ ];
212
+
213
+ const tween = new Tween({ path: square })
214
+ // you can use any property name you want
215
+ .use('path', interpolatePath)
216
+ // `d` might be a good choice as well
217
+ .to({ path: triangle })
218
+ .onUpdate(state => {
219
+ // update App state
220
+ // OR update DOM elements directly
221
+ path.setAttribute('d', pathToString(state.path));
222
+ })
223
+ .duration(2)
224
+ .start();
225
+ ```
226
+
227
+ **Notes**
228
+ * The example provides ready-made `PathArray` objects, they usually require prior preparation manually or using some script to [equalize segments](https://minus-ze.ro/posts/morphing-arbitrary-paths-in-svg/);
229
+ * Continuous `path` updates between multiple shapes requires that **all** path values are compatible, which means they all have same amount of segments and all segments are of the same type (ideal are `[[M, x, y], ...[L, x, y]], ` OR `[[M, x, y], ...[C, cx1, cy1, cx2, cy2, x, y]], `);
230
+ * Our [svg-path-commander](https://github.com/thednp/svg-path-commander/) provides all the tools necessary to process path strings, optimize and even equalize segments (work in progress).