@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/LICENSE +21 -0
- package/README.md +259 -0
- package/dist/index.cjs +621 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +184 -0
- package/dist/index.d.mts +184 -0
- package/dist/index.mjs +610 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react.cjs +61 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +9 -0
- package/dist/react.d.mts +9 -0
- package/dist/react.mjs +55 -0
- package/dist/react.mjs.map +1 -0
- package/dist/solid.cjs +81 -0
- package/dist/solid.cjs.map +1 -0
- package/dist/solid.d.cts +9 -0
- package/dist/solid.d.mts +9 -0
- package/dist/solid.mjs +75 -0
- package/dist/solid.mjs.map +1 -0
- package/dist/tween.iife.js +2 -0
- package/dist/tween.iife.js.map +1 -0
- package/package.json +96 -0
- package/wiki/Easing.md +58 -0
- package/wiki/React.md +255 -0
- package/wiki/Solid.md +149 -0
- package/wiki/Timeline.md +207 -0
- package/wiki/Tween.md +230 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 thednp
|
|
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
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
## @thednp/tween
|
|
2
|
+
[](https://coveralls.io/github/thednp/tween)
|
|
3
|
+
[](https://github.com/thednp/tween/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.typescriptlang.org/)
|
|
5
|
+
[](https://vitest.dev/)
|
|
6
|
+
[](https://github.com/vitejs)
|
|
7
|
+
|
|
8
|
+
A Typescript sourced `Tween` engine forked from the excellent [@tweenjs/tweenjs](https://github.com/tweenjs/tween.js).
|
|
9
|
+
|
|
10
|
+
* The package includes `Tween` class for creating most simple tween objects, with most essential controls over the update loop and simple methods for sequencing.
|
|
11
|
+
* Another major addition to this package is a simple to use `Timeline` class which enables an advanced control over the update loop, most importantly a **per-property** control for duration and easing.
|
|
12
|
+
* There are also a series of custom hooks/promitives for popular frameworks like React/SolidJS (more to come), with proper documentation and detailed user guides.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
- Built in custom hooks/primitives for popular frameworks like React/SolidJS
|
|
17
|
+
- Simple and powerful `Timeline` class for advanced sequencing/overlaps
|
|
18
|
+
- Lightweight fork of tween.js (~half the size)
|
|
19
|
+
- Chainable API for proper DX
|
|
20
|
+
- Easy to extend via custom interpolators
|
|
21
|
+
- Duration/delay in seconds
|
|
22
|
+
- Automatic rAF loop (starts and stops automatically)
|
|
23
|
+
- TypeScript-native, zero dependencies
|
|
24
|
+
- Tested with Vitest 100% code coverage
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Install
|
|
28
|
+
```
|
|
29
|
+
npm install @thednp/tween
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
pnpm add @thednp/tween
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
deno add @thednp/tween
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
bun add @thednp/tween
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
### Usage
|
|
46
|
+
|
|
47
|
+
#### Using Tween
|
|
48
|
+
```ts
|
|
49
|
+
import { Tween, Easing } from '@thednp/tween';
|
|
50
|
+
|
|
51
|
+
// find some target
|
|
52
|
+
const target = document.getElementById('my-target');
|
|
53
|
+
|
|
54
|
+
// define a tween
|
|
55
|
+
const tween = new Tween({ x: 0 })
|
|
56
|
+
.duration(1.5) // duration/delay accept seconds (e.g., 1.5 = 1.5s)
|
|
57
|
+
.onUpdate((obj, elapsed, eased) => {
|
|
58
|
+
// update App state
|
|
59
|
+
// OR manipulate the DOM directly
|
|
60
|
+
Object.assign(target.style, { translate: obj.x + "px"});
|
|
61
|
+
// monitor progress of the tween
|
|
62
|
+
console.log(`Tween progress: ${Math.floor(elapsed * 100)}%`)
|
|
63
|
+
// do other stuff with the `eased` value
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// override any value on the fly
|
|
67
|
+
const moveRight = () => tween
|
|
68
|
+
.from({ x: 0 }) // override/reset start values
|
|
69
|
+
.to({ x: 150 }) // override end values
|
|
70
|
+
.easing(Easing.Quadratic.Out) // set a special easing function for every case
|
|
71
|
+
.duration(1.5) // set duration as well in seconds
|
|
72
|
+
.start(); // start the tween
|
|
73
|
+
|
|
74
|
+
const moveLeft = () => tween
|
|
75
|
+
.to({ x: -150 }) // set a different to
|
|
76
|
+
.easing(Easing.Elastic.Out) // override easing
|
|
77
|
+
.duration(1.5) // override duration in seconds
|
|
78
|
+
.start(); // start the tween
|
|
79
|
+
|
|
80
|
+
// trigger any time
|
|
81
|
+
const button1 = document.getElementById('my-button-1');
|
|
82
|
+
const button2 = document.getElementById('my-button-2');
|
|
83
|
+
|
|
84
|
+
button1.onclick = moveRight;
|
|
85
|
+
button2.onclick = moveLeft;
|
|
86
|
+
|
|
87
|
+
// The engine does requestAnimationFrame/cancelAnimationFrame for you
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### Using Timeline
|
|
91
|
+
```ts
|
|
92
|
+
import { Timeline, Easing } from '@thednp/tween';
|
|
93
|
+
|
|
94
|
+
// find some target
|
|
95
|
+
const target = document.getElementById('my-target');
|
|
96
|
+
|
|
97
|
+
// define a timeline
|
|
98
|
+
const myTimeline = new Timeline({ x: 0, y: 0 })
|
|
99
|
+
.to({ x: 150, duration: 2.5, easing: Easing.Elastic.Out })
|
|
100
|
+
.to({ y: 150, duration: 1.5, easing: Easing.Elastic.Out }, "-=1")
|
|
101
|
+
.onUpdate((obj, elapsed) => {
|
|
102
|
+
// update App state
|
|
103
|
+
// OR manipulate the DOM directly
|
|
104
|
+
Object.assign(target.style, {
|
|
105
|
+
translate: obj.x + "px " + obj.y + "px",
|
|
106
|
+
});
|
|
107
|
+
// monitor progress of the tween
|
|
108
|
+
console.log(`Timeline progress: ${Math.floor(elapsed * 100)}%`)
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// trigger any time
|
|
112
|
+
const button = document.getElementById('my-button-1');
|
|
113
|
+
|
|
114
|
+
button.onclick = myTimeline.play();
|
|
115
|
+
|
|
116
|
+
// The engine does requestAnimationFrame/cancelAnimationFrame for you
|
|
117
|
+
```
|
|
118
|
+
To use `Tween` or `Timeline` with frameworks please check [React](wiki/React.md), [SolidJS](wiki/Solid.md) (more to come).
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
### What is different from original?
|
|
122
|
+
|
|
123
|
+
#### Back to Base
|
|
124
|
+
This `Tween` version is very small, maybe half the size of the current original version. It was developed to create easy to use hooks for UI frameworks like Solid/React and enable customizable animations.
|
|
125
|
+
In fact this is closer to the earlier versions of the original TWEEN.Tween.js.
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
#### New Features
|
|
129
|
+
This package comes with `Timeline`, which works like a regular `Tween` under the hood, but it provides additional control methods like `pause()`, `resume()` `seek()`.
|
|
130
|
+
|
|
131
|
+
Both `Tween` and `Timeline` have a static method to add custom interpolators, which is a unique way to extend beyond the original design and very different from the original library.
|
|
132
|
+
|
|
133
|
+
#### Other Notable Changes
|
|
134
|
+
* Some features like `yoyo`, `repeat`, `repeatDelay`, `chain` and
|
|
135
|
+
* callback options like `onRepeat` or `onEveryStart`, `onFirstStart` are **not** implemented;
|
|
136
|
+
* `duration()` and `delay()` methods accept values in seconds and convert them to milliseconds;
|
|
137
|
+
* The `pause()` and `resume()` methods have **not** been implemented in `Tween`, but they are implemented in `Timeline`;
|
|
138
|
+
* The update loop which consists of `requestAnimationFrame` / `cancelAnimationFrame` calls is automatic and is integrated in the `Tween` methods;
|
|
139
|
+
* The `onUpdate` callback also uses the value calculated by the easing function as the third parameter of your callback;
|
|
140
|
+
* The original Tween.js array interpolation is **not** supported, however we have a static method to add custom interpolators.
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
### Guides and Resources
|
|
144
|
+
* The original Tween.js [User Guide](https://github.com/tweenjs/tween.js/blob/main/docs/user_guide.md)
|
|
145
|
+
* [Tween.md](wiki/Tween.md) - our official `Tween` guide
|
|
146
|
+
* [Timeline.md](wiki/Timeline.md) - our official `Timeline` guide
|
|
147
|
+
* [Easing.md](wiki/Easing.md) - an extensive guide on easing functions.
|
|
148
|
+
* [React.md](wiki/React.md) - use `Tween` / `Timeline` with React with custom hooks.
|
|
149
|
+
* [Solid.md](wiki/Solid.md) - use `Tween` / `Timeline` with SolidJS with primitives.
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
### Technical Notes & Design Choices
|
|
153
|
+
|
|
154
|
+
**@thednp/tween** is intentionally designed as a **lightweight, state-first** tweening engine. Here's why certain choices were made and how the system works under the hood.
|
|
155
|
+
|
|
156
|
+
#### Why declarative state-based animation?
|
|
157
|
+
|
|
158
|
+
Most classic animation libraries (GSAP, KUTE.js, Velocity.js) are **imperative**: they read current DOM styles/attributes at runtime, parse them, compute differences, and write back updates.
|
|
159
|
+
|
|
160
|
+
**@thednp/tween** keeps with the original Tween.js, which is the opposite approach — it's **purely state-driven**:
|
|
161
|
+
|
|
162
|
+
- You provide **target state values** (numbers, arrays, objects)
|
|
163
|
+
- The engine interpolates **from current state** (captured at `.start()` / `.play()`)
|
|
164
|
+
- No DOM reading/parsing ever happens
|
|
165
|
+
- No per browser handling/processing
|
|
166
|
+
|
|
167
|
+
**Advantages**:
|
|
168
|
+
- Zero runtime style/attribute parsing → much faster startup & safer in concurrent React/Solid renders
|
|
169
|
+
- Perfect for **state-based UI** (React, SolidJS, Vue, Svelte, etc.) — animate your app state, not the DOM directly
|
|
170
|
+
- No surprises from inherited styles, CSS transitions, or computed values
|
|
171
|
+
- Works equally well with **Canvas**, **SVG**, **Three.js**, **WebGL**, or **pure data** — no DOM dependency at all
|
|
172
|
+
- Considerably smaller bundle size (no style parsing code)
|
|
173
|
+
- More power to you due to the simplicity or the prototype
|
|
174
|
+
|
|
175
|
+
**Trade-offs**:
|
|
176
|
+
- You must manage state yourself (which is the norm in modern frameworks anyway)
|
|
177
|
+
- You must process complex values yourself (values for SVG path morph)
|
|
178
|
+
|
|
179
|
+
This makes `@thednp/tween` feel more like **a reactive state interpolator** than a traditional DOM tweener.
|
|
180
|
+
|
|
181
|
+
#### How the global update loop works
|
|
182
|
+
|
|
183
|
+
All animations share **one single `requestAnimationFrame` loop** managed by `Runtime.ts`.
|
|
184
|
+
|
|
185
|
+
- When you call `.start()` / `.play()`, the instance is added to a global `Queue`
|
|
186
|
+
- `Runtime()` runs every frame → calls `.update(time)` on every queued item
|
|
187
|
+
- If `.update()` returns `false` (finished/stopped), the item is removed from the Queue
|
|
188
|
+
- When `Queue` becomes empty → `cancelAnimationFrame` is called automatically → loop stops completely
|
|
189
|
+
|
|
190
|
+
**Benefits**:
|
|
191
|
+
- Only **one** rAF subscription for the entire app — extremely efficient
|
|
192
|
+
- No manual start/stop of animation loop per tween/timeline
|
|
193
|
+
- Zero overhead when nothing is animating
|
|
194
|
+
|
|
195
|
+
This shared loop is why you never need to worry about starting/stopping individual `requestAnimationFrame` calls.
|
|
196
|
+
|
|
197
|
+
#### Async nature of requestAnimationFrame
|
|
198
|
+
|
|
199
|
+
All updates are **async** by nature:
|
|
200
|
+
|
|
201
|
+
1. You call `.start()` / `.play()` → instance queued
|
|
202
|
+
2. Next `rAF` tick → `Runtime()` calls `.update(time)` → interpolates → calls `onUpdate`
|
|
203
|
+
3. DOM/state updates happen **on the next frame(s)** — never synchronous
|
|
204
|
+
|
|
205
|
+
This means:
|
|
206
|
+
- Visual changes are always **smooth** and **tied to the display refresh rate**
|
|
207
|
+
- You can safely call `.to()`, `.duration()`, etc. **during** an animation — changes apply on the next frame
|
|
208
|
+
- No risk of partial/inconsistent frames (all calculations happen before paint)
|
|
209
|
+
|
|
210
|
+
#### Server-Side Rendering (SSR) compatibility
|
|
211
|
+
|
|
212
|
+
`@thednp/tween` is **SSR-safe** out of the box:
|
|
213
|
+
|
|
214
|
+
- No DOM access anywhere in the core
|
|
215
|
+
- `requestAnimationFrame` / `cancelAnimationFrame` are only called in browser (via `Runtime()`)
|
|
216
|
+
- `now()` defaults to `performance.now()` or `Date.now()` — safe fallbacks in Node
|
|
217
|
+
- Hooks/primitives only start animation on client (via mount effects)
|
|
218
|
+
|
|
219
|
+
Just make sure to **not call `tween.start()` / `timeline.play()`** during SSR (e.g. wrap in `if (typeof window !== 'undefined')` or use `useEffect`).
|
|
220
|
+
|
|
221
|
+
#### Other important differences from classic tween libraries
|
|
222
|
+
|
|
223
|
+
| Feature/Aspect | Classic (GSAP/KUTE/Velocity) | @thednp/tween |
|
|
224
|
+
|------------------------------------|-------------------------------------------|--------------------------------------------|
|
|
225
|
+
| Animation target | DOM elements & CSS | Any JS object (state, data, Canvas, etc.) |
|
|
226
|
+
| Value reading | Parses current style/attr at runtime | Captures current JS values at start |
|
|
227
|
+
| Performance on startup | Slower (parsing + computation) | Fastest (no parsing) |
|
|
228
|
+
| State-based UI compatibility | Requires extra glue code | Native — ideal for React/Solid/Vue/Svelte |
|
|
229
|
+
| Global vs per-instance config | Plugins/global easing | Per-instance `.use()` (recommended) |
|
|
230
|
+
| Bundle size | Larger (DOM utils, parsing, plugins) | Very small (~2–4 KB minzipped) |
|
|
231
|
+
| Runtime loop | Per-tween or managed | Single shared global loop (most efficient) |
|
|
232
|
+
|
|
233
|
+
#### Additional notes
|
|
234
|
+
|
|
235
|
+
- **No pause/resume on single Tween** — use `.stop()` + `.startFromLast()` for pause-like behavior (keeps it simple)
|
|
236
|
+
- **Repeat & yoyo** — not built-in on `Tween` (use `Timeline` for sequencing/repeats)
|
|
237
|
+
- **Custom interpolators** — register per instance with `.use('prop', fn)` (prevents conflicts in large apps)
|
|
238
|
+
- **Testing** — `setNow()` allows perfect time control in tests (override `now()` to fake progression)
|
|
239
|
+
|
|
240
|
+
We believe this combination of **small size**, **state-first design**, **shared loop**, and **per-instance flexibility** makes **@thednp/tween** uniquely suitable for modern component-based UIs in 2026.
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
### Contributing
|
|
244
|
+
This is a work in progress. For any issue or unclear guides, please [file an issue](https://github.com/thednp/tween/issues/new) and help make this guide better. Or feel free to submit a PR! Thank you!
|
|
245
|
+
|
|
246
|
+
**How to contribute**:
|
|
247
|
+
* fork the project
|
|
248
|
+
* change code/docs & update tests
|
|
249
|
+
* submit PR.
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
### Credits
|
|
253
|
+
* @sole for the creation and maintaining of the original [tween.js](https://github.com/tweenjs/tween.js)
|
|
254
|
+
* @dalisoft for his excellent [es6-tween](https://github.com/tweenjs/es6-tween)
|
|
255
|
+
* CreateJS for their excellent [TweenJS](https://github.com/CreateJS/TweenJS)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
### License
|
|
259
|
+
**@thednp/tween** is released under [MIT License](LICENCE).
|