diff --git a/examples/react/src/App.tsx b/examples/react/src/App.tsx index 206f759..5e88829 100644 --- a/examples/react/src/App.tsx +++ b/examples/react/src/App.tsx @@ -119,13 +119,13 @@ const UI = ({ return () => clearInterval(interval) }, []) - useMainLoop(({ time, deltaWithThrottle, elapsedRunning, callbackCount, delta }) => { - mainLoopRef.current!.innerHTML = `Delta (s): ${String(delta)}
Delta with throttle (s): ${String(deltaWithThrottle)}
Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}
Time (ms): ${String(time)}
Reactive counter: ${count}
CBs: ${callbackCount}` + useMainLoop(({ time, timeRunning, callbackCount, delta }) => { + mainLoopRef.current!.innerHTML = `Delta (s): ${String(delta)}
Time (ms): ${String(time)}
Time running (ms): ${String(timeRunning)}
Reactive counter: ${count}
CBs: ${callbackCount}` }) useMainLoop( - ({ time, elapsedRunning, callbackCount, delta, deltaWithThrottle }) => { - mainLoopThrottledRef.current!.innerHTML = `Delta (s): ${String(delta)}
Delta with throttle (s): ${String(deltaWithThrottle)}
Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}
Time (ms): ${String(time)}
Reactive counter: ${count}
CBs: ${callbackCount}` + ({ time, timeRunning, callbackCount, delta }) => { + mainLoopThrottledRef.current!.innerHTML = `Delta (s): ${String(delta)}
Time (ms): ${String(time)}
Time running (ms): ${String(timeRunning)}
Reactive counter: ${count}
CBs: ${callbackCount}` }, { throttle: 100 }, ) diff --git a/examples/svelte/src/App.svelte b/examples/svelte/src/App.svelte index 2d73f5d..f61d172 100644 --- a/examples/svelte/src/App.svelte +++ b/examples/svelte/src/App.svelte @@ -57,13 +57,13 @@ return () => clearInterval(interval) }) - useMainLoop(({ callbackCount, delta, deltaWithThrottle, elapsedRunning, time }) => { - mainLoopEl.innerHTML = `Delta (s): ${String(delta)}
Delta with throttle (s): ${String(deltaWithThrottle)}
Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}
Time (ms): ${String(time)}
Counter: ${counter}
CBs: ${callbackCount}` + useMainLoop(({ callbackCount, delta, time, timeRunning }) => { + mainLoopEl.innerHTML = `Delta (s): ${String(delta)}
Time (ms): ${String(time)}
Time running (ms): ${String(timeRunning)}
Counter: ${counter}
CBs: ${callbackCount}` }) useMainLoop( - ({ callbackCount, delta, deltaWithThrottle, elapsedRunning, time }) => { - mainLoopThrottledEl.innerHTML = `Delta (s): ${String(delta)}
Delta with throttle (s): ${String(deltaWithThrottle)}
Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}
Time (ms): ${String(time)}
Counter: ${counter}
CBs: ${callbackCount}` + ({ callbackCount, delta, time, timeRunning }) => { + mainLoopThrottledEl.innerHTML = `Delta (s): ${String(delta)}
Time (ms): ${String(time)}
Time running (ms): ${String(timeRunning)}
Counter: ${counter}
CBs: ${callbackCount}` }, { throttle: 100 }, ) diff --git a/examples/vanilla/src/App.ts b/examples/vanilla/src/App.ts index 7d63391..37460da 100644 --- a/examples/vanilla/src/App.ts +++ b/examples/vanilla/src/App.ts @@ -240,15 +240,15 @@ document.addEventListener('DOMContentLoaded', () => { updateJoystickButton() - addMainLoopEffect(({ elapsedRunning, callbackCount, delta, deltaWithThrottle, time }) => { + addMainLoopEffect(({ timeRunning, callbackCount, delta, time }) => { const el = document.getElementById('mainLoopEl')! - el.innerHTML = `Delta (s): ${String(delta)}
Delta with throttle (s): ${String(deltaWithThrottle)}
Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}
Time (ms): ${String(time)}
CBs: ${callbackCount}` + el.innerHTML = `Delta (s): ${String(delta)}
Time (ms): ${String(time)}
Time running (ms): ${String(timeRunning)}
CBs: ${callbackCount}` }) addMainLoopEffect( - ({ elapsedRunning, callbackCount, delta, deltaWithThrottle, time }) => { + ({ timeRunning, callbackCount, delta, time }) => { const el = document.getElementById('mainLoopThrottledEl')! - el.innerHTML = `Delta (s): ${String(delta)}
Delta with throttle (s): ${String(deltaWithThrottle)}
Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}
Time (ms): ${String(time)}
CBs: ${callbackCount}` + el.innerHTML = `Delta (s): ${String(delta)}
Time (ms): ${String(time)}
Time running (ms): ${String(timeRunning)}
CBs: ${callbackCount}` }, { throttle: 100 }, ) diff --git a/examples/vue/src/App.vue b/examples/vue/src/App.vue index 01a88fd..a601fd0 100644 --- a/examples/vue/src/App.vue +++ b/examples/vue/src/App.vue @@ -32,8 +32,8 @@ import RightMouseButtonLabel from './components/labels/RightMouseButtonLabel.vue import MobileJoystick from './components/MobileJoystick.vue' import TwitterIcon from './components/TwitterIcon.vue' -const mainLoopEl = ref() -const mainLoopThrottledEl = ref() +const mainLoopEl = ref() +const mainLoopThrottledEl = ref() const windowSizeEl = ref() const mousePosEl = ref() const mouseMoveEl = ref() @@ -49,13 +49,13 @@ onMounted(() => { onUnmounted(() => clearInterval(intervalId)) }) -useMainLoop(({ elapsedRunning, delta, deltaWithThrottle, time, callbackCount }) => { - mainLoopEl.value!.innerHTML = `Delta (s): ${String(delta)}
Delta with throttle (s): ${String(deltaWithThrottle)}
Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}
Time (ms): ${String(time)}
Reactive counter: ${counter.value}
CBs: ${callbackCount}` +useMainLoop(({ timeRunning, delta, time, callbackCount }) => { + mainLoopEl.value!.innerHTML = `Delta (s): ${String(delta)}
Time (ms): ${String(time)}
Time running (ms): ${String(timeRunning)}
Reactive counter: ${counter.value}
CBs: ${callbackCount}` }) useMainLoop( - ({ elapsedRunning, delta, deltaWithThrottle, time, callbackCount }) => { - mainLoopThrottledEl.value!.innerHTML = `Delta (s): ${String(delta)}
Delta with throttle (s): ${String(deltaWithThrottle)}
Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}
Time (ms): ${String(time)}
Reactive counter: ${counter.value}
CBs: ${callbackCount}` + ({ timeRunning, delta, time, callbackCount }) => { + mainLoopThrottledEl.value!.innerHTML = `Delta (s): ${String(delta)}
Time (ms): ${String(time)}
Time running (ms): ${String(timeRunning)}
Reactive counter: ${counter.value}
CBs: ${callbackCount}` }, { throttle: 100 }, ) @@ -250,11 +250,10 @@ const joystickMode = ref<'follow' | 'origin'>('follow')

🔄 Main loop

-
useMainLoop:
-
- useMainLoop (throttled): - -
+
useMainLoop
+
+
useMainLoop (throttled)
+

🍃 Tailwind

diff --git a/packages/core/src/main-loop.ts b/packages/core/src/main-loop.ts index 91fc1ae..f5de3f7 100644 --- a/packages/core/src/main-loop.ts +++ b/packages/core/src/main-loop.ts @@ -1,8 +1,7 @@ export type MainLoopState = { time: number delta: number - deltaWithThrottle: number - elapsedRunning: number + timeRunning: number callbackCount: number } @@ -20,9 +19,8 @@ const callbackLastExecutions = new Map() const state: MainLoopState = { time: 0, delta: 0, - elapsedRunning: 0, + timeRunning: 0, callbackCount: 0, - deltaWithThrottle: 0, } let running = false let previousTime = 0 @@ -32,8 +30,8 @@ const mainLoop = (time: number) => { if (!running) return state.time = time + state.timeRunning += state.time - previousTime state.delta = (state.time - previousTime) / 1000 - state.elapsedRunning += state.delta let callbackCount = 0 for (const callbacksSet of callbacks.values()) { @@ -66,11 +64,22 @@ export const addMainLoopEffect = ( const lastExecution = callbackLastExecutions.get(callback) || 0 const throttleInterval = options?.throttle || 0 - if (state.time - lastExecution >= throttleInterval) { - state.deltaWithThrottle = (state.time - lastExecution) / 1000 - + if (throttleInterval === 0) { + // No throttling, execute every frame callbackLastExecutions.set(callback, state.time) callback(state) + } else { + // Calculate the number of intervals passed + const intervalsPassed = Math.floor((state.time - lastExecution) / throttleInterval) + + if (intervalsPassed >= 1) { + // Update last execution time to the most recent interval + const newLastExecution = lastExecution + intervalsPassed * throttleInterval + callbackLastExecutions.set(callback, newLastExecution) + + state.delta = (newLastExecution - lastExecution) / 1000 + callback(state) + } } } @@ -84,7 +93,7 @@ export const addMainLoopEffect = ( running = true // Reset time to avoid large delta after pause animationFrameId = requestAnimationFrame(time => { - previousTime = time + previousTime = Math.round(time) // To avoid microseconds that we might get at the initial call callbackLastExecutions.forEach((_, callback) => callbackLastExecutions.set(callback, time)) mainLoop(time) })