@thednp/tween
v0.0.5
Published
🌸 A Typescript sourced tweening engine with Tween and Timeline
Maintainers
Readme
@thednp/tween
A TypeScript-first tweening engine forked from the excellent @tweenjs/tweenjs.
Popular UI frameworks supported:
Your favorite framework isn't listed? Let us know!
Why @thednp/tween?
State-first architecture with validation before runtime, not during. Explicit configuration, zero guesswork, minimal overhead.
Key Benefits
- SSR-compatible hooks for React, SolidJS, Svelte, Preact, and Vue — provide initial values for server rendering, skip initialization entirely on the server
- Predictable outcomes through upfront value validation — invalid values prevent animation start with clear feedback
- Production-ready validation system catches configuration errors before they break your app
- Natural reverse playback via inverted easing (no
reverseEasingoption orvaluesStartreassignment) - Extensible interpolation with built-in extensions for custom per-property validators and interpolators
Performance Optimizations
- Single shared
requestAnimationFrameloop for all tweens/timelines with automatic start/stop - Zero GC pressure via specialized
miniStorefor framework integrations - Tuple-based hot update runtime eliminates object lookup
- No validation during updates—all checks happen at initialization
whileloops throughout for maximum speed
Documentation
Core Features
- Tween Guide - the official
Tweendocumentation - Timeline Guide - the official
Timelinedocumentation - Easing Guide - the easing functions documentation
- Extend Guide - the extensions documentation
- Troubleshooting - a quick check on issues and how to solve them.
- Ministore - an inside look at
miniStore.
UI Frameworks
Other Sources
- The original Tween.js User Guide can also provide valuable tips.
Installation
npm install @thednp/tweenpnpm add @thednp/tweendeno add @thednp/tweenbun add @thednp/tweenLoad From CDN
<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>Usage
To use Tween and Timeline with UI frameworks please check the dedicated sections: React, SolidJS, Svelte, Preact and Vue.
Using Tween
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 youFor an extended guide, check the Tween Wiki.
Using Timeline
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 youFor an extended guide, check the Timeline Wiki.
Core Features
Tween
Simple tween objects with essential controls, callbacks, and sequencing methods.
Timeline
Complex scheduling with per-property duration, delay, and easing. Includes seek() and label() for precise control.
Extensions
Built-in and custom per-property validators and interpolators. Single-level plain objects only.
Validation System
All values validated on initialization from initialValues (source of truth). Invalid configurations prevent execution with actionable feedback.
Automatic RAF Loop
Shared requestAnimationFrame loop starts on first start() / play(), stops when queue empties.
Key Differences from Original
Not Implemented
chain()featureonEveryStart,onFirstStartcallbacks- The original Tween.js array interpolation
- Deeply nested objects
- The original Tween.js dynamic end values
Changes
duration(),delay(),repeatDelay(),seek()accept values in seconds (converted to milliseconds internally)- Automatic RAF queue system (you don't need to define a global
requestAnimationFrameupdate loop yourself) - Reverse playback via inverted easing (no
reverseEasingoption required) - Per-property extensions via
.use('propName', extensionConfig)
Architecture Notes
Global Update Loop
Single requestAnimationFrame loop managed by Runtime.ts:
tween.start()/timeline.play()adds instance to global queueRuntime()calls.update(time)on all queued items each frame- Instances returning false (finished/stopped) are removed
- Empty queue triggers automatic
cancelAnimationFrame
Async Nature
Updates are async by design:
start()/play()queues instance- Next RAF tick →
Runtime()→update(time)→ interpolation - DOM/state updates on subsequent frames
- Visual changes sync with display refresh rate for smooth animations.
SSR Compatibility
- No DOM access in core
- RAF calls browser-only (via
Runtime()) now()defaults toperformance.now()(can fallback to Date.now() for Node)- Framework hooks include SSR guards and provide values for server-rendered HTML
- Important: Don't call
start()/play()during SSR.
Workarounds
- Chaining — use
onCompletecallback to trigger next tween/timeline - Custom interpolation — register per-property extensions with
.use()
Contributing
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:
- fork the project
- change code/docs & update tests
- submit PR
Credits
- @sole for the creation and maintaining of the original tween.js
- @dalisoft for his excellent es6-tween
- CreateJS for their excellent TweenJS
