Skip to content

Commit 48f5fb5

Browse files
committed
update loop from feedback
1 parent 67e8ff7 commit 48f5fb5

1 file changed

Lines changed: 31 additions & 12 deletions

File tree

src/core/platforms/web/WebPlatform.ts

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export class WebPlatform extends Platform {
2929
override startLoop(stage: Stage): void {
3030
let isIdle = false;
3131
let lastFrameTime = 0;
32+
const buffer = 4;
3233

3334
const runLoop = (currentTime: number = 0) => {
3435
const targetFrameTime = stage.targetFrameTime;
@@ -39,7 +40,13 @@ export class WebPlatform extends Platform {
3940

4041
// If not enough time has passed, skip this frame
4142
if (elapsed < targetFrameTime) {
42-
requestAnimationFrame(runLoop);
43+
const wait = targetFrameTime - elapsed;
44+
45+
if (wait > buffer) {
46+
setTimeout(() => requestAnimationFrame(runLoop), wait - buffer);
47+
} else {
48+
requestAnimationFrame(runLoop);
49+
}
4350
return;
4451
}
4552

@@ -56,16 +63,13 @@ export class WebPlatform extends Platform {
5663
// We still need to calculate the fps else it looks like the app is frozen
5764
stage.calculateFps();
5865

59-
if (targetFrameTime > 0) {
60-
// Use setTimeout for throttled idle frames
61-
setTimeout(
62-
() => requestAnimationFrame(runLoop),
63-
Math.max(targetFrameTime, 16.666666666666668),
64-
);
65-
} else {
66-
// Use standard idle timeout when not throttling
67-
setTimeout(() => requestAnimationFrame(runLoop), 16.666666666666668);
68-
}
66+
// We use 15ms instead of 16.6ms to provide a safety buffer.
67+
// This ensures we wake up slightly before the next frame to check for updates,
68+
// preventing us from missing a frame due to timer variances.
69+
setTimeout(
70+
() => requestAnimationFrame(runLoop),
71+
Math.max(targetFrameTime, 15),
72+
);
6973

7074
if (isIdle === false) {
7175
stage.shManager.cleanup();
@@ -86,7 +90,22 @@ export class WebPlatform extends Platform {
8690
stage.flushFrameEvents();
8791

8892
// Schedule next frame
89-
requestAnimationFrame(runLoop);
93+
if (targetFrameTime > 0) {
94+
const nextTarget = lastFrameTime + targetFrameTime;
95+
const now = performance.now();
96+
const wait = nextTarget - now;
97+
98+
// If we have a significant wait time, use setTimeout to yield to the browser.
99+
// We subtract a small buffer (4ms) to ensure we wake up BEFORE the next frame.
100+
if (wait > buffer) {
101+
setTimeout(() => requestAnimationFrame(runLoop), wait - buffer);
102+
} else {
103+
requestAnimationFrame(runLoop);
104+
}
105+
} else {
106+
// Use standard rAF when not throttling
107+
requestAnimationFrame(runLoop);
108+
}
90109
};
91110
requestAnimationFrame(runLoop);
92111
}

0 commit comments

Comments
 (0)