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
requestIdleCallbackorsetTimeoutwhen 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-helperThen 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 offsetconst duration = fps.getDurationForFrames(90); // Duration for 90 framesconst 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! ๐จ