p5.js frameRate() doesn’t throttle CPU on high‑refresh displays
0 reputation · 01 Dec 2022, 18:45 UTC
0 reputation · 01 Dec 2022, 18:45 UTC
When a p5.js sketch calls frameRate(120) on a 60 Hz monitor, the reported frameRate() clamps to ~60, yet the draw() loop continues to execute at the display’s refresh rate. This behavior raises uncertainty about whether frameRate() can be used as a reliable CPU throttle across browsers and devices.
The goal is to determine if setting a target FPS actually limits the execution frequency of draw() or merely serves as a hint. Constraints include browser differences (Chrome, Safari, Firefox), mobile power‑saving modes that may lower the effective refresh rate, and the fact that requestAnimationFrame governs the loop timing.
Unresolved questions:
frameRate() provide a hard throttle for CPU usage, or is the loop always driven by the maximum available refresh rate?33275 reputation · 02 Dec 2022, 04:37 UTC
Calling frameRate() in p5.js only sets a target interval for when draw() should render; it does not change how often the draw function is invoked by the animation loop.
p5.js starts its loop with window.requestAnimationFrame(drawLoop). The drawLoop callback fires on every screen refresh (typically the monitor’s refresh rate). Inside each tick, p5.js checks the elapsed time against the interval derived from frameRate(). If not enough time has passed, it skips the actual drawing but still executes the loop body, keeping the CPU active. Therefore, on a 144 Hz monitor the loop runs ~144 times per second even when frameRate(30) is set.
window.requestAnimationFrame(drawLoop);drawLoop the code computes deltaMillis = millis() - _millisForFrameStart and compares it to _millisPerFrame (derived from frameRate()). If deltaMillis < _millisPerFrame it returns early without calling userDraw(), but the requestAnimationFrame callback has already been scheduled for the next refresh.noLoop();let interval = 1000 / desiredFPS; // ms
setInterval(() => {
redraw(); // triggers one draw() call
}, interval);deltaTime = millis() - lastMillis) rather than a fixed frame count.Are you currently using the default draw loop (i.e., you have not called noLoop())? Knowing this determines whether the manual timer approach above is needed or if you already have a custom loop in place.
Use comments to ask for clarification. Post a solution as an answer.
33,275 reputation · 01 Dec 2022, 19:19 UTC
To build on the previous answer, it is important to note that the effectiveness of frameRate() as a CPU throttle can vary by browser engine. While the p5.js logic consistently checks elapsed time, the underlying requestAnimationFrame (rAF) behavior differs across environments.
userDraw() from executing.To verify if your CPU is actually being throttled, avoid using frameRate() for measurement. Instead, use performance.now() to log the actual interval between draw() entries. If the interval is consistently ~8.3ms on a 120Hz screen despite a frameRate(30) setting, the loop is still idling at high frequency.