A TypeScript-first tweening engine forked from the excellent @tweenjs/tweenjs.
Popular UI frameworks supported:
Your favorite framework isn't listed? Let us know!
State-first architecture with validation before runtime, not during. Explicit configuration, zero guesswork, minimal overhead.
reverseEasing option or valuesStart reassignment)requestAnimationFrame loop for all tweens/timelines with automatic start/stopminiStore for framework integrationswhile loops throughout for maximum speedTween documentationTimeline documentationminiStore.npm install @thednp/tween
pnpm add @thednp/tween
deno add @thednp/tween
bun add @thednp/tween
<script src="https://cdn.jsdelivr.net/npm/@thednp/tween/dist/tween.min.js"></script>
<script>
const { Tween, Easing } = TWEEN;
const tween = new Tween({ x: 0 });
</script>
To use Tween and Timeline with UI frameworks please check the dedicated sections: React, SolidJS, Svelte, Preact and Vue.
import { Tween, Easing } from '@thednp/tween';
// find some target
const target = document.getElementById('my-target');
// define a tween
const tween = new Tween({ x: 0 })
.duration(1.5) // duration/delay accept seconds (e.g., 1.5 = 1.5s)
.onUpdate((obj, elapsed) => {
// manipulate the DOM directly
Object.assign(target.style, { translate: obj.x + "px" });
// monitor progress of the tween
console.log(`Tween progress: ${Math.floor(elapsed * 100)}%`)
});
// override any value on the fly
const moveRight = () => tween
.from({ x: 0 }) // override/reset start values
.to({ x: 150 }) // override end values
.easing(Easing.Quadratic.Out) // set a special easing function for every case
.duration(1.5) // set duration as well in seconds
.start(); // start the tween
const moveLeft = () => tween
.from({ x: 150 }) // set a different from
.to({ x: -150 }) // set a different to
.easing(Easing.Elastic.Out) // override easing
.duration(1.5) // override duration in seconds
.start(); // start the tween
// trigger any time
const button1 = document.getElementById('my-button-1');
const button2 = document.getElementById('my-button-2');
button1.onclick = moveRight;
button2.onclick = moveLeft;
// The engine does requestAnimationFrame/cancelAnimationFrame for you
For an extended guide, check the Tween Wiki.
import { Timeline, Easing } from '@thednp/tween';
// find some target
const target = document.getElementById('my-target');
// define a timeline
const myTimeline = new Timeline({ x: 0, y: 0 })
.to({ x: 150, duration: 2.5, easing: Easing.Elastic.Out })
.to({ y: 150, duration: 1.5, easing: Easing.Elastic.Out }, "-=1")
.onUpdate((obj, elapsed) => {
// manipulate the DOM directly
Object.assign(target.style, {
translate: obj.x + "px " + obj.y + "px",
});
// monitor progress of the timeline
console.log(`Timeline progress: ${Math.floor(elapsed * 100)}%`)
});
// trigger any time
const button = document.getElementById('my-button');
button.onclick = myTimeline.play();
// The engine does requestAnimationFrame/cancelAnimationFrame for you
For an extended guide, check the Timeline Wiki.
Simple tween objects with essential controls, callbacks, and sequencing methods.
Complex scheduling with per-property duration, delay, and easing. Includes seek() and label() for precise control.
Built-in and custom per-property validators and interpolators. Single-level plain objects only.
All values validated on initialization from initialValues (source of truth). Invalid configurations prevent execution with actionable feedback.
Shared requestAnimationFrame loop starts on first start() / play(), stops when queue empties.
Not Implemented
chain() featureonEveryStart, onFirstStart callbacksChanges
duration(), delay(), repeatDelay(), seek() accept values in seconds (converted to milliseconds internally)requestAnimationFrame update loop yourself)reverseEasing option required).use('propName', extensionConfig)Single requestAnimationFrame loop managed by Runtime.ts:
tween.start() / timeline.play() adds instance to global queueRuntime() calls .update(time) on all queued items each framecancelAnimationFrameUpdates are async by design:
start() / play() queues instanceRuntime() β update(time) β interpolationRuntime())now() defaults to performance.now() (can fallback to Date.now() for Node)start() / play() during SSR.onComplete callback to trigger next tween/timeline.use()For any issue or unclear guides, please file an issue and help make this guide better. Or feel free to submit a PR! Thank you!
How to contribute: