one rAF to rule them all
npm install tempus
tempus means time in Latin, this package is a lightweight, high-performance animation frame manager for JavaScript applications.
- ð Merge multiple requestAnimationFrame loops for better performance
- ðŊ Control execution priority of different animations
- ⥠Support for custom frame rates (FPS)
- ð Compatible with popular animation libraries
- ðŠķ Zero dependencies
- ðĶ ~1KB gzipped
using package manager
``bash`
npm install tempus
`js`
import Tempus from 'tempus'
using script tag
`html`
`javascript
import Tempus from "tempus"
// Simple animation at maximum FPS
function animate(time, deltaTime) {
console.log('frame', time, deltaTime)
}
Tempus.add(animate)
`
javascript
const unsubscribe = Tempus.add(animate)unsubscribe()
`$3
`javascript
Tempus.pause() // no rafs will be called
Tempus.play() // resume
Tempus.restart() // set clock elapsed time to 0
`$3
See tempus/react
Advanced Usage
$3
`javascript
Tempus.add(animate, {
fps: 30 // Will run at 30 FPS
})Tempus.add(animate, {
fps: '50%' // Will run at 50% of the system's FPS
})
`$3
ââ[-Infinity]ââ[0]ââ[Infinity]ââ> execution order
#### Input
`javascript
// Default priority: 0 (runs second)
Tempus.add(() => console.log('animate'))// Priority: 1 (runs third)
Tempus.add(() => console.log('render'), { priority: 1 })
// Priority: -1 (runs first)
Tempus.add(() => console.log('scroll'), { priority: -1 })
`
#### Output`
scroll
animate
render
`$3
idle callback will only run when the usage is less than the idle percentage in order to not block the main thread. It's useful for optional background tasks.`javascript
Tempus.add(() => console.log('idle'), { idle: 0.8 }) // will only run when the raf usage is less than 80%
`$3
ping and pong will alternate between each frame, but never during the same frame`javascript
let framesCount = 0Tempus.add(() => {
if (framesCount === 0) {
console.log('ping')
} else {
console.log('pong')
}
framesCount++
framesCount %= 2
})
`$3
`javascript
// Patch native requestAnimationFrame across all your app
Tempus.patch()
// Now any requestAnimationFrame recursive calls will use Tempus
`Integration Examples
$3
`javascript
Tempus.add(lenis.raf)
`$3
`javascript
// Remove GSAP's internal RAF
gsap.ticker.remove(gsap.updateRoot)// Add to Tempus
Tempus.add((time) => {
gsap.updateRoot(time / 1000)
})
`$3
`javascript
Tempus.add(() => {
renderer.render(scene, camera)
}, { priority: 1 })
// the render will happen after other rafs
// so it can be synched with lenis for instance
`API Reference
$3
Adds an animation callback to the loop.
- callback:
(time: number, deltaTime: number, frameCount: number) => void
- options:
- priority: number (default: 0) - Lower numbers run first
- fps: number (default: Infinity) - Target frame rate
- Returns: () => void - Unsubscribe function$3
Patches the native
requestAnimationFrame to use Tempus.$3
Unpatches the native
requestAnimationFrame` to use the original one.- Use priorities wisely: critical animations (like scroll) should have higher priority
- Clean up animations when they're no longer needed
- Consider using specific FPS for non-critical animations to improve performance (e.g: collisions)
- Use Ping Pong technique for heavy computations running concurrently
MIT ÂĐ darkroom.engineering
Thank you to Keith Cirkel for having transfered us the npm package name ð.