Js requestanimationframe
Author: f | 2025-04-24
JS requestAnimationFrame frame-rate. 2. requestAnimationFrame fires far more often than 60 fps. 0. requestAnimationFrame() performance issue. 0. Javascript - JS requestAnimationFrame frame-rate. 0. request animation frame loop. 0. Javascript - requestAnimationFrame Frame Rate. 7. requestAnimationFrame JavaScript: Constant Frame
How to use requestAnimationFrame() with vanilla JS
Changes can happen purely on the GPU which will stay extremely fast and still get us quick frame rates.Watch the video above towards the end to see more on how to diagnose paint costs, see what areas are being repainted, and evaluate what elements are on the GPU.DemoClick through below, try adding more and see how the the framerate reacts. Feel free to open up DevTools, too and explore Timeline:Guidelines for animationUse CSS keyframe animation or CSS transitions, if at all possible. The browser can optimize painting and compositing bigtime here.If needs to be it’s JS-based animation, use requestAnimationFrame. Avoid setTimeout, setInterval.Avoid changing inline styles on every frame (jQuery animate()-style) if you can, declarative animations in CSS can be optimized by the browser way more.Using 2D transforms instead of absolute positioning will typically provide better FPS by way of smaller paint times and smoother animation.Use Timeline Frame’s mode to investigate what is slowing down your behavior“Show Paint Rects” and “Render Composited Layer Borders” are good pro-moves to verify where your element is being rendered.
JS: requestAnimationFrame Loop Pattern GitHub
To help developers monitor performance during development.The Ideal Frame Rate for Game LoopsThe Limitations of Hardware and Display Refresh RatesYour game loop architecture must account for hardware constraints. Not all devices can handle high frame rates due to:CPU processing powerBrowser JavaScript engine efficiency (V8 Engine or others)Display refresh rate limitsMobile battery considerationsWebGL integration can offload rendering to the GPU, but computational graphics still face bottlenecks based on the user’s hardware.Games built with PixiJS or Babylon.js automatically adjust their loop execution speed based on device capabilities.Balancing High FPS with System Resource UsagePerformance tuning requires finding the sweet spot between visual quality and resource consumption.Web Workers can handle background tasks without affecting your main game loop performance.Consider these strategies:Implement frame skipping when necessaryUse time-based movement instead of frame-basedOptimize sprite animation and asset loadingMonitor JavaScript performance metrics during developmentCommon Approaches to Implementing Game LoopsUsing Basic Loops (Inefficient Methods)The naïve while (true) loop approach and why it failsThe simplest approach – a continuous while(true) loop – causes major issues:function startGame() { while(true) { updateGame(); renderGame(); }}This blocks the JavaScript event model completely. The browser becomes unresponsive because:The event loop gets stuckDOM manipulation can’t occurUser inputs are never processedThe browser may crash entirelyNo professional JavaScript game design pattern uses this approach.Using setInterval() for a timed loopMany beginners try setInterval() for their game loop:setInterval(function() { updateGameLogic(); renderFrame();}, 16); // ~60fpsWhile better than the while loop, this method has serious flaws:Doesn’t sync with browser rendering cyclesContinues running when the tab isn’t activeProduces inconsistent timingLeads to lag compensation issuesGame engines like Construct 3 abandoned this approach years ago.Introduction to requestAnimationFrame()How requestAnimationFrame() synchronizes with the browser’s renderingThe Web Animation API introduced requestAnimationFrame() as the solution to frame management:function gameLoop() { updateGameState(); renderGame(); requestAnimationFrame(gameLoop);}requestAnimationFrame(gameLoop);This method aligns your game loop with the browser’s natural rendering cycle.Mozilla Developer Network documentation highlights these benefits:Browser optimizes animations behind the scenesPauses when users switch tabs (saving resources)Adapts to screen refresh rate automaticallyProvides smooth frame transitionsAdvantages over setInterval() and traditional loopsUsing requestAnimationFrame() offers significant performance advantages:Natural synchronization with display refresh ratesReduced CPU usage when the game isn’t visibleBetter battery life on mobile devicesConsistent timing between frame updatesImproved compatibility across modern browsersThis is why all serious JavaScript game libraries like React Game Kit, GreenSock Animation Platform, and Kontra.js use this approach.Example of a basic game loop using requestAnimationFrame()Here’s a practical implementation with delta time calculation:let lastTimestamp = 0;function gameLoop(timestamp) { // Calculate time since last frame constUse JS countdown timer in Canvas with requestAnimationFrame
Skip to main content This browser is no longer supported. Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support. Troubleshooting common performance issues Article12/11/2024 In this article -->Users expect interactive and smooth pages. Each stage in the pixel pipeline represents an opportunity to introduce jank (interruptions of rendering). Learn about tools and strategies to identify and fix common problems that slow down runtime performance.SummaryDon't write JavaScript that forces the browser to recalculate layout. Separate read and write functions, and perform reads first.Don't over-complicate your CSS. Use less CSS and keep your CSS selectors simple.Avoid layout as much as possible. Choose CSS that doesn't trigger layout at all.Painting may take up more time than any other rendering activity. Watch out for paint bottlenecks.JavaScriptJavaScript calculations, especially ones that trigger extensive visual changes, may stall application performance. Don't let badly timed or long-running JavaScript interfere with user interactions.JavaScript: ToolsTake a recording in the Performance tool and look for suspiciously long Evaluate Script events. If you notice quite a bit of jank (interruptions of rendering) in your JavaScript, you may need to take your analysis to the next level and collect a JavaScript CPU profile. CPU profiles show where runtime is spent within the functions of your page. Learn how to create CPU profiles in Speed up JavaScript runtime ("Allocation sampling" profiling type).JavaScript: ProblemsThe following are common JavaScript problems and potential solutions.ProblemExampleSolutionExpensive input handlers affecting response or animation.Touch, parallax scrolling.Let the browser handle touch and scrolls, or bind the listener as late as possible. See Expensive Input Handlers in The Runtime Performance Checklist by Paul Lewis.Badly timed JavaScript affecting response, animation, load.User scrolls right after page load, setTimeout / setInterval.Optimize JavaScript runtime: use requestAnimationFrame, spread DOM manipulation over frames, use Web Workers; see Using Web Workers.Long-running JavaScript affecting response.The DOMContentLoaded event stalls, because it's swamped with JavaScript work.Move pure computational work to Web Workers; see Using Web Workers. If you need DOM access, use requestAnimationFrame. Garbage-y scripts affecting response or animation.Garbage collection may happen anywhere.Write less garbage-y scripts. See Garbage Collection in Animations in The Runtime Performance. JS requestAnimationFrame frame-rate. 2. requestAnimationFrame fires far more often than 60 fps. 0. requestAnimationFrame() performance issue. 0. Javascript -JS - A simple requestAnimationFrame example visually explained
On deviceif (shouldReduceQuality()) { enableLowPowerMode();}Progressive Web Apps that include games often implement these battery-saving features.Handling touch input differencesTouch needs different handling than mouse:// Handle both mouse and touchlet inputX = 0;let inputY = 0;let isPointerDown = false;// Mouse eventscanvas.addEventListener('mousedown', e => { isPointerDown = true; updatePointerPosition(e.clientX, e.clientY);});canvas.addEventListener('mousemove', e => { if (isPointerDown) { updatePointerPosition(e.clientX, e.clientY); }});canvas.addEventListener('mouseup', () => { isPointerDown = false;});// Touch eventscanvas.addEventListener('touchstart', e => { isPointerDown = true; updatePointerPosition(e.touches[0].clientX, e.touches[0].clientY); e.preventDefault(); // Prevent scrolling});canvas.addEventListener('touchmove', e => { updatePointerPosition(e.touches[0].clientX, e.touches[0].clientY); e.preventDefault();});canvas.addEventListener('touchend', () => { isPointerDown = false;});function updatePointerPosition(clientX, clientY) { const rect = canvas.getBoundingClientRect(); inputX = clientX - rect.left; inputY = clientY - rect.top;}Libraries like Kontra.js handle input normalization automatically.Is requestAnimationFrame supported in all browsers?Browser compatibilitySupport for requestAnimationFrame is now universal in modern browsers, but older browsers might need a polyfill:// requestAnimationFrame polyfillif (!window.requestAnimationFrame) { window.requestAnimationFrame = (function() { return window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60); }; })();}The Mozilla Developer Network documentation confirms excellent support across all modern browsers.Alternative approaches for legacy supportFor very old browsers:// Fallback timing systemclass GameTimer { constructor(targetFPS = 60) { this.targetFPS = targetFPS; this.lastTime = 0; this.isRunning = false; this.useRAF = !!window.requestAnimationFrame; } start(loopFn) { this.isRunning = true; this.lastTime = performance.now(); if (this.useRAF) { const rafLoop = (timestamp) => { if (!this.isRunning) return; const deltaTime = timestamp - this.lastTime; this.lastTime = timestamp; loopFn(deltaTime / 1000); requestAnimationFrame(rafLoop); }; requestAnimationFrame(rafLoop); } else { // Fallback to setInterval const intervalMs = 1000 / this.targetFPS; this.intervalId = setInterval(() => { const now = performance.now(); const deltaTime = now - this.lastTime; this.lastTime = now; loopFn(deltaTime / 1000); }, intervalMs); } } stop() { this.isRunning = false; if (!this.useRAF && this.intervalId) { clearInterval(this.intervalId); } }}However, most indie game development now focuses on modern browsers where requestAnimationFrame is well-supported.How do I handle resizing and fullscreen in my game loop?Responsive canvas sizingKeep your canvas properly sized:const canvas = document.getElementById('gameCanvas');const ctx = canvas.getContext('2d');function resizeCanvas() { // Get the display size const displayWidth = window.innerWidth; const displayHeight = window.innerHeight; // Check if canvas size needs to change if (canvas.width !== displayWidth || canvas.height !== displayHeight) { // Set canvas size to match display canvas.width = displayWidth; canvas.height = displayHeight; // Update game scale/viewport updateGameViewport(displayWidth, displayHeight); }}function updateGameViewport(width, height) { // Calculate game scale to maintain aspect ratio const gameAspect = GAME_WIDTH / GAME_HEIGHT; const screenAspect = width / height; if (screenAspect > gameAspect) { // ScreenJS requestAnimationFrame frame-rate - Stack Overflow
Improves performance.Starting, Stopping, and Managing the Game LoopControlling the Execution of the LoopImplementing start and stop functionsClean control over your game loop makes development easier:let isRunning = false;let lastTimestamp = 0;let animFrameId = null;function startGameLoop() { if (!isRunning) { isRunning = true; lastTimestamp = performance.now(); animFrameId = requestAnimationFrame(gameLoop); console.log("Game loop started"); }}function stopGameLoop() { if (isRunning) { cancelAnimationFrame(animFrameId); isRunning = false; animFrameId = null; console.log("Game loop stopped"); }}This pattern keeps track of the animation frame ID, which helps prevent memory leaks.Frameworks like Babylon.js and PixiJS already implement this functionality in their core engines.Handling pausing and resuming efficientlyPausing needs special treatment to avoid time jumps:let isPaused = false;function togglePause() { isPaused = !isPaused; if (isPaused) { // Maybe show pause menu showPauseMenu(); } else { // When resuming, reset timestamp to avoid time jumps lastTimestamp = performance.now(); requestAnimationFrame(gameLoop); hidePauseMenu(); }}function gameLoop(timestamp) { if (isPaused) return; const deltaTime = (timestamp - lastTimestamp) / 1000; lastTimestamp = timestamp; updateGame(deltaTime); renderGame(); requestAnimationFrame(gameLoop);}Browser rendering engines pause requestAnimationFrame when tabs are inactive, so you don’t need to handle tab switching manually.Preventing the “Spiral of Death” IssueUnderstanding what causes update spiralsThe “death spiral” happens when:Your game can’t keep up with the fixed timestepThe time accumulator grows larger each frameThe loop tries to run more and more updates to catch upEverything freezes as the browser gets stuckGames with heavy physics particularly suffer from this issue on low-end devices.Implementing sanity checks to prevent performance crashesAlways include safety checks in your loop:const FIXED_DT = 1/60; // 60 updates per secondconst MAX_STEPS = 5; // Never run more than 5 physics updates per framelet accumulator = 0;function gameLoop(timestamp) { // Calculate real delta time let deltaTime = (timestamp - lastTimestamp) / 1000; lastTimestamp = timestamp; // Cap delta time if the game was inactive if (deltaTime > 0.25) deltaTime = 0.25; accumulator += deltaTime; let updateCount = 0; // Run fixed updates with a safety limit while (accumulator >= FIXED_DT && updateCount // If we hit the limit, discard remaining time if (updateCount >= MAX_STEPS) { console.warn("Update spiral detected, dropping accumulated time"); accumulator = 0; } // Render with interpolation for smoothness const alpha = accumulator / FIXED_DT; render(alpha); requestAnimationFrame(gameLoop);}This approach prevents browser crashes even under heavy load. Popular libraries like React Game Kit implement similar safeguards.Managing State and TransitionsInitializing the game loop properlySet up everything before starting the loop:function initGame() { // Load assets const assetsPromise = loadAssets([ 'player.png', 'enemies.png',p5.js - P5js [Violation] 'requestAnimationFrame' handler took
An element. The situation changes when it comes to animations, though. Unlike box-shadow, almost all modern browsers hardware accelerate the drop-shadow filter. This means you get faster screen updates as the drop shadow is doing its thing when animating from one state to another. This reason alone is huge, and this makes the drop-shadow filter the perfect (and only!) choice when using drop shadows that we also want to animate. Animation Time To animate our drop shadow, we have a great deal of flexibility. We can use CSS Animations, CSS Transitions, JS-based requestAnimationFrame Animations, or the Animate method. Because the drop-shadow filter is hardware accelerated by default, there isn't a lot of extra performance-related hoops we need to jump through. The only step we should follow as a good practice is to give our browser a heads-up that we will be animating the filter property. That we can do by using will-changewith a value of filter: .thingToAnimate { will-change: filter;} To put all of this together, below is an example where we have a drop shadow animate in (via a transition) on hover: .box { width: 200px; height: 200px; border-radius: 10px; background-color: #f75590; will-change: filter; transition: filter .2s ease-out;}.box:hover { filter: drop-shadow(0px 0px 50px #333);} To see this example live, click here for the CodePen version. Conclusion Creating nice drop shadow animations was historically a challenge due to performance issues. The internet is filled with tricks to work around those, such as the really awesome pseudoelement opacity trick by Tobias Ahlin. Luckily, with hardware acceleration now available by default via the filter property, we can all spend more time creating really nice user experiences and less time fiddling with the technical fallout from poorly performing properties. Just a final word before we wrap up. What you've seen here is freshly baked content without added preservatives, artificial intelligence, ads, and algorithm-driven doodads. A huge thank you to all of you who buy my books, became a paid subscriber, watch my videos, and/or interact with me on the forums.Your support keeps this site going! 😇 COMMENTS #oldComments iframe { border-radius: 5px; } DiscourseEmbed = { discourseUrl: ' discourseEmbedUrl: " + window.location.pathname.split("?")[0].split("#")[0] }; (function() { var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true; d.src = DiscourseEmbed.discourseUrl + 'javascripts/embed.js'; (document.getElementsByTagName('title')[0] || document.getElementsByTagName('title')[0]).appendChild(d); })(); Got a question? Post on our forums! Learn, share, and have fun with some of the most knowledgeable and. JS requestAnimationFrame frame-rate. 2. requestAnimationFrame fires far more often than 60 fps. 0. requestAnimationFrame() performance issue. 0. Javascript -Comments
Changes can happen purely on the GPU which will stay extremely fast and still get us quick frame rates.Watch the video above towards the end to see more on how to diagnose paint costs, see what areas are being repainted, and evaluate what elements are on the GPU.DemoClick through below, try adding more and see how the the framerate reacts. Feel free to open up DevTools, too and explore Timeline:Guidelines for animationUse CSS keyframe animation or CSS transitions, if at all possible. The browser can optimize painting and compositing bigtime here.If needs to be it’s JS-based animation, use requestAnimationFrame. Avoid setTimeout, setInterval.Avoid changing inline styles on every frame (jQuery animate()-style) if you can, declarative animations in CSS can be optimized by the browser way more.Using 2D transforms instead of absolute positioning will typically provide better FPS by way of smaller paint times and smoother animation.Use Timeline Frame’s mode to investigate what is slowing down your behavior“Show Paint Rects” and “Render Composited Layer Borders” are good pro-moves to verify where your element is being rendered.
2025-04-10To help developers monitor performance during development.The Ideal Frame Rate for Game LoopsThe Limitations of Hardware and Display Refresh RatesYour game loop architecture must account for hardware constraints. Not all devices can handle high frame rates due to:CPU processing powerBrowser JavaScript engine efficiency (V8 Engine or others)Display refresh rate limitsMobile battery considerationsWebGL integration can offload rendering to the GPU, but computational graphics still face bottlenecks based on the user’s hardware.Games built with PixiJS or Babylon.js automatically adjust their loop execution speed based on device capabilities.Balancing High FPS with System Resource UsagePerformance tuning requires finding the sweet spot between visual quality and resource consumption.Web Workers can handle background tasks without affecting your main game loop performance.Consider these strategies:Implement frame skipping when necessaryUse time-based movement instead of frame-basedOptimize sprite animation and asset loadingMonitor JavaScript performance metrics during developmentCommon Approaches to Implementing Game LoopsUsing Basic Loops (Inefficient Methods)The naïve while (true) loop approach and why it failsThe simplest approach – a continuous while(true) loop – causes major issues:function startGame() { while(true) { updateGame(); renderGame(); }}This blocks the JavaScript event model completely. The browser becomes unresponsive because:The event loop gets stuckDOM manipulation can’t occurUser inputs are never processedThe browser may crash entirelyNo professional JavaScript game design pattern uses this approach.Using setInterval() for a timed loopMany beginners try setInterval() for their game loop:setInterval(function() { updateGameLogic(); renderFrame();}, 16); // ~60fpsWhile better than the while loop, this method has serious flaws:Doesn’t sync with browser rendering cyclesContinues running when the tab isn’t activeProduces inconsistent timingLeads to lag compensation issuesGame engines like Construct 3 abandoned this approach years ago.Introduction to requestAnimationFrame()How requestAnimationFrame() synchronizes with the browser’s renderingThe Web Animation API introduced requestAnimationFrame() as the solution to frame management:function gameLoop() { updateGameState(); renderGame(); requestAnimationFrame(gameLoop);}requestAnimationFrame(gameLoop);This method aligns your game loop with the browser’s natural rendering cycle.Mozilla Developer Network documentation highlights these benefits:Browser optimizes animations behind the scenesPauses when users switch tabs (saving resources)Adapts to screen refresh rate automaticallyProvides smooth frame transitionsAdvantages over setInterval() and traditional loopsUsing requestAnimationFrame() offers significant performance advantages:Natural synchronization with display refresh ratesReduced CPU usage when the game isn’t visibleBetter battery life on mobile devicesConsistent timing between frame updatesImproved compatibility across modern browsersThis is why all serious JavaScript game libraries like React Game Kit, GreenSock Animation Platform, and Kontra.js use this approach.Example of a basic game loop using requestAnimationFrame()Here’s a practical implementation with delta time calculation:let lastTimestamp = 0;function gameLoop(timestamp) { // Calculate time since last frame const
2025-04-03On deviceif (shouldReduceQuality()) { enableLowPowerMode();}Progressive Web Apps that include games often implement these battery-saving features.Handling touch input differencesTouch needs different handling than mouse:// Handle both mouse and touchlet inputX = 0;let inputY = 0;let isPointerDown = false;// Mouse eventscanvas.addEventListener('mousedown', e => { isPointerDown = true; updatePointerPosition(e.clientX, e.clientY);});canvas.addEventListener('mousemove', e => { if (isPointerDown) { updatePointerPosition(e.clientX, e.clientY); }});canvas.addEventListener('mouseup', () => { isPointerDown = false;});// Touch eventscanvas.addEventListener('touchstart', e => { isPointerDown = true; updatePointerPosition(e.touches[0].clientX, e.touches[0].clientY); e.preventDefault(); // Prevent scrolling});canvas.addEventListener('touchmove', e => { updatePointerPosition(e.touches[0].clientX, e.touches[0].clientY); e.preventDefault();});canvas.addEventListener('touchend', () => { isPointerDown = false;});function updatePointerPosition(clientX, clientY) { const rect = canvas.getBoundingClientRect(); inputX = clientX - rect.left; inputY = clientY - rect.top;}Libraries like Kontra.js handle input normalization automatically.Is requestAnimationFrame supported in all browsers?Browser compatibilitySupport for requestAnimationFrame is now universal in modern browsers, but older browsers might need a polyfill:// requestAnimationFrame polyfillif (!window.requestAnimationFrame) { window.requestAnimationFrame = (function() { return window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60); }; })();}The Mozilla Developer Network documentation confirms excellent support across all modern browsers.Alternative approaches for legacy supportFor very old browsers:// Fallback timing systemclass GameTimer { constructor(targetFPS = 60) { this.targetFPS = targetFPS; this.lastTime = 0; this.isRunning = false; this.useRAF = !!window.requestAnimationFrame; } start(loopFn) { this.isRunning = true; this.lastTime = performance.now(); if (this.useRAF) { const rafLoop = (timestamp) => { if (!this.isRunning) return; const deltaTime = timestamp - this.lastTime; this.lastTime = timestamp; loopFn(deltaTime / 1000); requestAnimationFrame(rafLoop); }; requestAnimationFrame(rafLoop); } else { // Fallback to setInterval const intervalMs = 1000 / this.targetFPS; this.intervalId = setInterval(() => { const now = performance.now(); const deltaTime = now - this.lastTime; this.lastTime = now; loopFn(deltaTime / 1000); }, intervalMs); } } stop() { this.isRunning = false; if (!this.useRAF && this.intervalId) { clearInterval(this.intervalId); } }}However, most indie game development now focuses on modern browsers where requestAnimationFrame is well-supported.How do I handle resizing and fullscreen in my game loop?Responsive canvas sizingKeep your canvas properly sized:const canvas = document.getElementById('gameCanvas');const ctx = canvas.getContext('2d');function resizeCanvas() { // Get the display size const displayWidth = window.innerWidth; const displayHeight = window.innerHeight; // Check if canvas size needs to change if (canvas.width !== displayWidth || canvas.height !== displayHeight) { // Set canvas size to match display canvas.width = displayWidth; canvas.height = displayHeight; // Update game scale/viewport updateGameViewport(displayWidth, displayHeight); }}function updateGameViewport(width, height) { // Calculate game scale to maintain aspect ratio const gameAspect = GAME_WIDTH / GAME_HEIGHT; const screenAspect = width / height; if (screenAspect > gameAspect) { // Screen
2025-04-16Improves performance.Starting, Stopping, and Managing the Game LoopControlling the Execution of the LoopImplementing start and stop functionsClean control over your game loop makes development easier:let isRunning = false;let lastTimestamp = 0;let animFrameId = null;function startGameLoop() { if (!isRunning) { isRunning = true; lastTimestamp = performance.now(); animFrameId = requestAnimationFrame(gameLoop); console.log("Game loop started"); }}function stopGameLoop() { if (isRunning) { cancelAnimationFrame(animFrameId); isRunning = false; animFrameId = null; console.log("Game loop stopped"); }}This pattern keeps track of the animation frame ID, which helps prevent memory leaks.Frameworks like Babylon.js and PixiJS already implement this functionality in their core engines.Handling pausing and resuming efficientlyPausing needs special treatment to avoid time jumps:let isPaused = false;function togglePause() { isPaused = !isPaused; if (isPaused) { // Maybe show pause menu showPauseMenu(); } else { // When resuming, reset timestamp to avoid time jumps lastTimestamp = performance.now(); requestAnimationFrame(gameLoop); hidePauseMenu(); }}function gameLoop(timestamp) { if (isPaused) return; const deltaTime = (timestamp - lastTimestamp) / 1000; lastTimestamp = timestamp; updateGame(deltaTime); renderGame(); requestAnimationFrame(gameLoop);}Browser rendering engines pause requestAnimationFrame when tabs are inactive, so you don’t need to handle tab switching manually.Preventing the “Spiral of Death” IssueUnderstanding what causes update spiralsThe “death spiral” happens when:Your game can’t keep up with the fixed timestepThe time accumulator grows larger each frameThe loop tries to run more and more updates to catch upEverything freezes as the browser gets stuckGames with heavy physics particularly suffer from this issue on low-end devices.Implementing sanity checks to prevent performance crashesAlways include safety checks in your loop:const FIXED_DT = 1/60; // 60 updates per secondconst MAX_STEPS = 5; // Never run more than 5 physics updates per framelet accumulator = 0;function gameLoop(timestamp) { // Calculate real delta time let deltaTime = (timestamp - lastTimestamp) / 1000; lastTimestamp = timestamp; // Cap delta time if the game was inactive if (deltaTime > 0.25) deltaTime = 0.25; accumulator += deltaTime; let updateCount = 0; // Run fixed updates with a safety limit while (accumulator >= FIXED_DT && updateCount // If we hit the limit, discard remaining time if (updateCount >= MAX_STEPS) { console.warn("Update spiral detected, dropping accumulated time"); accumulator = 0; } // Render with interpolation for smoothness const alpha = accumulator / FIXED_DT; render(alpha); requestAnimationFrame(gameLoop);}This approach prevents browser crashes even under heavy load. Popular libraries like React Game Kit implement similar safeguards.Managing State and TransitionsInitializing the game loop properlySet up everything before starting the loop:function initGame() { // Load assets const assetsPromise = loadAssets([ 'player.png', 'enemies.png',
2025-04-15