Building Your Learning Module...
Getting things ready for you!
Find videos you like?
Save to resource drawer for future reference!
requestAnimationFrame tells the browser you want to animate something. The browser runs your animation callback before the next repaint, giving you smooth 60fps animations!
Synced with browser refresh rate
Pauses when tab is hidden
Smooth, optimized rendering
setTimeout isn't synced with screen refresh!requestAnimationFrame runs at the perfect time (60fps), pauses when hidden, and is way more efficient!Watch requestAnimationFrame create butter-smooth animations!
<div style="max-width: 700px; margin: 0 auto; font-family: 'Segoe UI', sans-serif;">
<div style="background: linear-gradient(135deg, #a855f7 0%, #d946ef 50%, #ec4899 100%); padding: 40px; border-radius: 16px; box-shadow: 0 10px 30px rgba(168, 85, 247, 0.3);">
<h2 style="color: white; margin: 0 0 12px 0; font-size: 28px; font-weight: 700; text-align: center;">š¬ Animation Demo</h2>
<p style="color: rgba(255, 255, 255, 0.9); margin: 0 0 30px 0; font-size: 15px; text-align: center;">Smooth 60fps animations with requestAnimationFrame</p>
<div style="background: rgba(255, 255, 255, 0.95); padding: 24px; border-radius: 12px; backdrop-filter: blur(10px);">
<!-- Animation Canvas -->
<div id="canvas" style="position: relative; height: 150px; background: linear-gradient(135deg, #f0f9ff 0%, #e0e7ff 100%); border-radius: 12px; overflow: hidden; margin-bottom: 20px; border: 3px solid #a855f7;">
<div id="ball" style="position: absolute; top: 50%; width: 40px; height: 40px; background: linear-gradient(135deg, #a855f7 0%, #ec4899 100%); border-radius: 50%; box-shadow: 0 4px 12px rgba(168, 85, 247, 0.4); transform: translateY(-50%);"></div>
</div>
<!-- Controls -->
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 16px;">
<button id="startBtn" style="padding: 14px; background: linear-gradient(135deg, #10b981 0%, #059669 100%); color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600; font-size: 15px;">
ā¶ļø Start
</button>
<button id="stopBtn" disabled style="padding: 14px; background: #6b7280; color: white; border: none; border-radius: 8px; cursor: not-allowed; font-weight: 600; font-size: 15px; opacity: 0.5;">
āøļø Stop
</button>
</div>
<!-- Stats -->
<div id="stats" style="padding: 16px; background: linear-gradient(135deg, #fef3c7 0%, #fed7aa 100%); border-radius: 8px; border-left: 4px solid #f59e0b; font-size: 14px;"></div>
</div>
</div>
</div>Loading preview...
// Animation loop function
function animate(timestamp) {
// 1. Update your animation state
position += velocity;
rotation += rotationSpeed;
// 2. Update DOM elements
element.style.transform = `translateX(${position}px) rotate(${rotation}deg)`;
// 3. Request next frame (creates loop)
requestAnimationFrame(animate);
}
// Start the animation
requestAnimationFrame(animate);
// šÆ The callback receives a DOMHighResTimeStamp
// - Precise timestamp of when the frame is called
// - Use it to calculate smooth, time-based animations
// To stop the animation:
let animationId = requestAnimationFrame(animate);
cancelAnimationFrame(animationId);let lastTime = 0;
let position = 0;
const speed = 100; // pixels per second
function animate(timestamp) {
// Calculate delta time (time since last frame)
const deltaTime = (timestamp - lastTime) / 1000; // Convert to seconds
lastTime = timestamp;
// Move based on time, not frames
position += speed * deltaTime;
// Update element
element.style.left = position + 'px';
// Continue
requestAnimationFrame(animate);
}
// Start
requestAnimationFrame(animate);
// šÆ Benefits:
// - Animation speed is consistent
// - Works on 30fps, 60fps, 144fps screens
// - Dropped frames don't slow animation
// - Professional game-dev techniqueconst box = document.getElementById('box');
let position = 0;
let lastTime = null;
function moveBox(timestamp) {
if (!lastTime) lastTime = timestamp;
const delta = (timestamp - lastTime) / 1000;
lastTime = timestamp;
// Move 200 pixels per second
position += 200 * delta;
// Wrap around at 500px
if (position > 500) position = 0;
box.style.transform = `translateX(${position}px)`;
requestAnimationFrame(moveBox);
}
requestAnimationFrame(moveBox);
// Result: Smooth movement at exactly 200px/second
// on any device, any refresh rate!const background = document.getElementById('bg');
const foreground = document.getElementById('fg');
function updateParallax() {
const scrollY = window.scrollY;
// Move background slower than foreground
background.style.transform = `translateY(${scrollY * 0.5}px)`;
foreground.style.transform = `translateY(${scrollY * 0.8}px)`;
requestAnimationFrame(updateParallax);
}
requestAnimationFrame(updateParallax);
// Creates smooth parallax effect on scroll!function smoothScrollTo(element, targetY, duration = 1000) {
const startY = window.scrollY;
const distance = targetY - startY;
const startTime = performance.now();
function scroll(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// Easing function (ease-in-out)
const eased = progress < 0.5
? 2 * progress * progress
: 1 - Math.pow(-2 * progress + 2, 2) / 2;
window.scrollTo(0, startY + distance * eased);
if (progress < 1) {
requestAnimationFrame(scroll);
}
}
requestAnimationFrame(scroll);
}
// Usage
smoothScrollTo(element, 1000, 800); // Scroll to 1000px in 800msfunction animateProgress(element, targetPercent, duration = 1000) {
const startTime = performance.now();
const startPercent = parseFloat(element.style.width) || 0;
function update(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
const currentPercent = startPercent + (targetPercent - startPercent) * progress;
element.style.width = currentPercent + '%';
if (progress < 1) {
requestAnimationFrame(update);
}
}
requestAnimationFrame(update);
}
// Usage
const progressBar = document.getElementById('progress');
animateProgress(progressBar, 75); // Animate to 75%class Game {
constructor() {
this.player = { x: 0, y: 0, vx: 0, vy: 0 };
this.lastTime = 0;
this.running = false;
}
update(deltaTime) {
// Update game physics
this.player.x += this.player.vx * deltaTime;
this.player.y += this.player.vy * deltaTime;
// Apply gravity
this.player.vy += 980 * deltaTime; // 980px/s²
// Collision detection, etc.
}
render() {
// Draw game
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(this.player.x, this.player.y, 32, 32);
}
loop(timestamp) {
if (!this.running) return;
const deltaTime = (timestamp - this.lastTime) / 1000;
this.lastTime = timestamp;
this.update(deltaTime);
this.render();
requestAnimationFrame((t) => this.loop(t));
}
start() {
this.running = true;
this.lastTime = performance.now();
requestAnimationFrame((t) => this.loop(t));
}
stop() {
this.running = false;
}
}
const game = new Game();
game.start();setInterval(fn, 16) isn't perfectly synced with 60Hz refresh rate, causes visual tearing
Continues running when tab is hidden, wasting battery. requestAnimationFrame pauses automatically!
Browser can't optimize multiple DOM updates. requestAnimationFrame batches all changes before paint!
Perfect sync, battery-friendly, optimized by browser, smooth 60fps animations
JavaScript-driven animations (move, rotate, scale)
Update game state and render at 60fps
Animate charts, graphs, transitions
Parallax, smooth scrolling, reveal animations
Synced with browser refresh rate
Use timestamp for smooth animation
Pauses when tab is hidden
cancelAnimationFrame(id)