Skip to content

Commit

Permalink
feat: change elapsedRunning to timeRunning, remove deltaWithThrottle,…
Browse files Browse the repository at this point in the history
… more accurate timing
  • Loading branch information
verekia committed Oct 15, 2024
1 parent 9514725 commit f600a44
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 32 deletions.
8 changes: 4 additions & 4 deletions examples/react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,13 @@ const UI = ({
return () => clearInterval(interval)
}, [])

useMainLoop(({ time, deltaWithThrottle, elapsedRunning, callbackCount, delta }) => {
mainLoopRef.current!.innerHTML = `Delta (s): ${String(delta)}<br />Delta with throttle (s): ${String(deltaWithThrottle)}<br />Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}<br />Time (ms): ${String(time)}<br />Reactive counter: ${count}<br />CBs: ${callbackCount}`
useMainLoop(({ time, timeRunning, callbackCount, delta }) => {
mainLoopRef.current!.innerHTML = `Delta (s): ${String(delta)}<br />Time (ms): ${String(time)}<br />Time running (ms): ${String(timeRunning)}<br />Reactive counter: ${count}<br />CBs: ${callbackCount}`
})

useMainLoop(
({ time, elapsedRunning, callbackCount, delta, deltaWithThrottle }) => {
mainLoopThrottledRef.current!.innerHTML = `Delta (s): ${String(delta)}<br />Delta with throttle (s): ${String(deltaWithThrottle)}<br />Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}<br />Time (ms): ${String(time)}<br />Reactive counter: ${count}<br />CBs: ${callbackCount}`
({ time, timeRunning, callbackCount, delta }) => {
mainLoopThrottledRef.current!.innerHTML = `Delta (s): ${String(delta)}<br />Time (ms): ${String(time)}<br />Time running (ms): ${String(timeRunning)}<br />Reactive counter: ${count}<br />CBs: ${callbackCount}`
},
{ throttle: 100 },
)
Expand Down
8 changes: 4 additions & 4 deletions examples/svelte/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@
return () => clearInterval(interval)
})
useMainLoop(({ callbackCount, delta, deltaWithThrottle, elapsedRunning, time }) => {
mainLoopEl.innerHTML = `Delta (s): ${String(delta)}<br />Delta with throttle (s): ${String(deltaWithThrottle)}<br />Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}<br />Time (ms): ${String(time)}<br />Counter: ${counter}<br />CBs: ${callbackCount}`
useMainLoop(({ callbackCount, delta, time, timeRunning }) => {
mainLoopEl.innerHTML = `Delta (s): ${String(delta)}<br />Time (ms): ${String(time)}<br />Time running (ms): ${String(timeRunning)}<br />Counter: ${counter}<br />CBs: ${callbackCount}`
})
useMainLoop(
({ callbackCount, delta, deltaWithThrottle, elapsedRunning, time }) => {
mainLoopThrottledEl.innerHTML = `Delta (s): ${String(delta)}<br />Delta with throttle (s): ${String(deltaWithThrottle)}<br />Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}<br />Time (ms): ${String(time)}<br />Counter: ${counter}<br />CBs: ${callbackCount}`
({ callbackCount, delta, time, timeRunning }) => {
mainLoopThrottledEl.innerHTML = `Delta (s): ${String(delta)}<br />Time (ms): ${String(time)}<br />Time running (ms): ${String(timeRunning)}<br />Counter: ${counter}<br />CBs: ${callbackCount}`
},
{ throttle: 100 },
)
Expand Down
8 changes: 4 additions & 4 deletions examples/vanilla/src/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)}<br />Delta with throttle (s): ${String(deltaWithThrottle)}<br />Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}<br />Time (ms): ${String(time)}<br />CBs: ${callbackCount}`
el.innerHTML = `Delta (s): ${String(delta)}<br />Time (ms): ${String(time)}<br />Time running (ms): ${String(timeRunning)}<br />CBs: ${callbackCount}`
})

addMainLoopEffect(
({ elapsedRunning, callbackCount, delta, deltaWithThrottle, time }) => {
({ timeRunning, callbackCount, delta, time }) => {
const el = document.getElementById('mainLoopThrottledEl')!
el.innerHTML = `Delta (s): ${String(delta)}<br />Delta with throttle (s): ${String(deltaWithThrottle)}<br />Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}<br />Time (ms): ${String(time)}<br />CBs: ${callbackCount}`
el.innerHTML = `Delta (s): ${String(delta)}<br />Time (ms): ${String(time)}<br />Time running (ms): ${String(timeRunning)}<br />CBs: ${callbackCount}`
},
{ throttle: 100 },
)
Expand Down
21 changes: 10 additions & 11 deletions examples/vue/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLSpanElement>()
const mainLoopThrottledEl = ref<HTMLSpanElement>()
const mainLoopEl = ref<HTMLDivElement>()
const mainLoopThrottledEl = ref<HTMLDivElement>()
const windowSizeEl = ref<HTMLSpanElement>()
const mousePosEl = ref<HTMLSpanElement>()
const mouseMoveEl = ref<HTMLSpanElement>()
Expand All @@ -49,13 +49,13 @@ onMounted(() => {
onUnmounted(() => clearInterval(intervalId))
})
useMainLoop(({ elapsedRunning, delta, deltaWithThrottle, time, callbackCount }) => {
mainLoopEl.value!.innerHTML = `Delta (s): ${String(delta)}<br />Delta with throttle (s): ${String(deltaWithThrottle)}<br />Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}<br />Time (ms): ${String(time)}<br />Reactive counter: ${counter.value}<br />CBs: ${callbackCount}`
useMainLoop(({ timeRunning, delta, time, callbackCount }) => {
mainLoopEl.value!.innerHTML = `Delta (s): ${String(delta)}<br />Time (ms): ${String(time)}<br />Time running (ms): ${String(timeRunning)}<br />Reactive counter: ${counter.value}<br />CBs: ${callbackCount}`
})
useMainLoop(
({ elapsedRunning, delta, deltaWithThrottle, time, callbackCount }) => {
mainLoopThrottledEl.value!.innerHTML = `Delta (s): ${String(delta)}<br />Delta with throttle (s): ${String(deltaWithThrottle)}<br />Elapsed running (s): ${String(Math.round(elapsedRunning * 1000) / 1000)}<br />Time (ms): ${String(time)}<br />Reactive counter: ${counter.value}<br />CBs: ${callbackCount}`
({ timeRunning, delta, time, callbackCount }) => {
mainLoopThrottledEl.value!.innerHTML = `Delta (s): ${String(delta)}<br />Time (ms): ${String(time)}<br />Time running (ms): ${String(timeRunning)}<br />Reactive counter: ${counter.value}<br />CBs: ${callbackCount}`
},
{ throttle: 100 },
)
Expand Down Expand Up @@ -250,11 +250,10 @@ const joystickMode = ref<'follow' | 'origin'>('follow')
</section>
<section>
<h2 class="section-heading">🔄 Main loop</h2>
<div>useMainLoop: <span ref="mainLoopEl" class="tabular-nums" /></div>
<div>
useMainLoop (throttled):
<span ref="mainLoopThrottledEl" class="tabular-nums" />
</div>
<div><b>useMainLoop</b></div>
<div ref="mainLoopEl" class="tabular-nums" />
<div><b>useMainLoop (throttled)</b></div>
<div ref="mainLoopThrottledEl" class="tabular-nums" />
</section>
<section>
<h2 class="section-heading">🍃 Tailwind</h2>
Expand Down
27 changes: 18 additions & 9 deletions packages/core/src/main-loop.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
export type MainLoopState = {
time: number
delta: number
deltaWithThrottle: number
elapsedRunning: number
timeRunning: number
callbackCount: number
}

Expand All @@ -20,9 +19,8 @@ const callbackLastExecutions = new Map<MainLoopEffectCallback, number>()
const state: MainLoopState = {
time: 0,
delta: 0,
elapsedRunning: 0,
timeRunning: 0,
callbackCount: 0,
deltaWithThrottle: 0,
}
let running = false
let previousTime = 0
Expand All @@ -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()) {
Expand Down Expand Up @@ -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)
}
}
}

Expand All @@ -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)
})
Expand Down

0 comments on commit f600a44

Please sign in to comment.