FrameRateHelper is a lightweight, zero-dependency JavaScript utility that calculates the user's display refresh rate and provides a stable, clamped frame duration. It is ideal for synchronizing animations with screen refresh rates to produce smooth, consistent visual experiences.
- ๐ Automatically detects true screen refresh rate using
requestAnimationFrame
- ๐ง Falls back to
requestIdleCallback
orsetTimeout
when needed - ๐งฑ Built-in clamping prevents duration spikes on slow devices or inactive tabs
- ๐ฆ Offers methods for calculating precise animation timing
- ๐ Frame-based timing with optional min/max/rounding controls
- ๐ชถ Lightweight and dependency-free โ pure vanilla JavaScript
jsDelivr:
<!-- Development version (readable, unminified, includes source map) -->
<script src="https://cdn.jsdelivr.net/gh/InfinitumForm/[email protected]/dist/FrameRateHelper.js"></script>
<!-- Production version (minified, optimized for speed) -->
<script src="https://cdn.jsdelivr.net/gh/InfinitumForm/[email protected]/dist/FrameRateHelper.min.js"></script>
unpkg:
<!-- Development version (readable, unminified, includes source map) -->
<script src="https://unpkg.com/[email protected]/dist/FrameRateHelper.js"></script>
<!-- Production version (minified, optimized for speed) -->
<script src="https://unpkg.com/[email protected]/dist/FrameRateHelper.min.js"></script>
This exposes window.FrameRateHelper
globally.
npm install framerate-helper
Then in your module:
import FrameRateHelper from 'framerate-helper';
const fps = new FrameRateHelper();
fps.onReady((hz) => {
console.log('Detected refresh rate:', hz.toFixed(2), 'Hz');
console.log('Estimated frame duration:', fps.getDuration(), 'ms');
});
const duration = fps.getDuration(300); // base + 300ms offset
const duration = fps.getDurationForFrames(90); // Duration for 90 frames
const duration = fps.getDurationForFrames(90, {
min: 1000, // minimum 1 second
max: 2000, // maximum 2 seconds
rounded: true // round to nearest integer
});
const desiredFrames = 120;
let duration = fps.getDurationForFrames(desiredFrames, {
max: 2500, // prevent overly long animations
min: 800, // ensure minimum visibility
rounded: true
});
myElement.style.transitionDuration = `${duration}ms`;
Creates a new instance and begins refresh rate measurement immediately.
Waits for refresh rate calculation to complete and then executes the callback.
callback (function)
: Receives detected refresh rate (Hz)
Returns an adjusted frame duration based on screen refresh rate.
offset (number)
: Optional duration to add (in ms)- Returns: total duration in ms
Calculates duration based on number of frames.
frames (number)
: Desired number of animation framesoptions (object)
(optional):min (number)
: Minimum allowed duration in msmax (number)
: Maximum allowed duration in msrounded (boolean)
: Iftrue
, rounds result
- Returns: clamped, optionally rounded duration in ms
You can seamlessly use FrameRateHelper
(for example) with jQuery animation methods to ensure frame-synced transitions:
const fps = new FrameRateHelper();
fps.onReady(() => {
const duration = fps.getDuration(400); // add a 400ms offset if desired
// Smoothly toggle element visibility with frame-accurate duration
$('.my-element').slideToggle(duration);
// Show/hide with consistent frame-based speed
$('.other-element').show(duration);
$('.another-one').hide(duration);
});
This is especially useful when animations feel "choppy" on devices with non-standard refresh rates (e.g. 120Hz, 144Hz), ensuring consistent experience across screens.
- Precision animations in sliders, carousels, or onboarding steps
- Smooth frame-based motion control in games or interactive UIs
- Avoiding stutters in custom scroll or fade effects
- Performance-friendly frame sync for canvas/webgl renderers
MIT License โ free for personal and commercial use.
Developed by INFINITUM FORMยฎ
Author: Ivijan-Stefan Stipiฤ
ยฉ 2025 Ivijan-Stefan Stipiฤ. All rights reserved.
For issues, contributions, or improvements, please visit the GitHub repository.
Happy animating! ๐จ