You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I went to the GraphQL events page, and although it doesn't seem to be doing anything (no visible changes), the fans on my PC span up and it seems to have pegged 16 of my cores to 60+% CPU each. The same does not happen on the graphql.org home page, it seems specific to the events page.
The VM likely does not have graphics acceleration, so maybe it's a WebGL thing? Even so, nothing seems to be changing on the page, so I'm not sure why this would happen.
It does a full WebGL re-render every frame and immediately schedules the next one — even when the map is completely idle (no pan, no inertia, no marker animation). With hardware acceleration the GPU absorbs this; in a VM without GPU acceleration (software/llvmpipe), every frame's render runs on the CPU, which pegs many cores while nothing visibly changes. That matches the report exactly.
Quantifying it
While the page sits idle with no interaction, the map keeps calling requestAnimationFrame continuously — measured at ~124 calls/second (247 in a 2s window). A correct on-demand map would be ~0.
How to test it programmatically
Rather than measuring CPU directly (hardware/CI-dependent and flaky), assert the invariant that's actually broken: the render loop must go idle when nothing is animating. Counting engine requestAnimationFrame calls over an idle window is deterministic and GPU-independent, and drops into the existing test/e2e/community-events.spec.ts:
test("map render loop goes idle when nothing is animating",async({ page })=>{constmapContainer=page.locator("#meetups-map").first()awaitmapContainer.scrollIntoViewIfNeeded()awaitexpect(mapContainer.locator("canvas").first()).toBeVisible({timeout: 15_000})// Let the intro/zoom animation and any inertia settle.awaitpage.waitForTimeout(4000)// Count rAF calls over a fixed idle window, timed by setTimeout so the// measurement itself never drives the loop. No pointer interaction here.constframesWhileIdle=awaitpage.evaluate(async()=>{constorig=window.requestAnimationFrame.bind(window)letcount=0window.requestAnimationFrame=cb=>{count++;returnorig(cb)}awaitnewPromise(r=>setTimeout(r,2000))window.requestAnimationFrame=origreturncount})// Idle should be ~0; allow a few trailing frames.// Today this is ~240 → fails, documenting the bug. Passes once the loop is on-demand.expect(framesWhileIdle).toBeLessThan(10)})
Suggested fix
Make loop() schedule a new frame only while something is actually changing (active inertia, marker animations, cooling pointer trail, active drag, resize) and park the loop when idle, re-arming on the next interaction. The test above then goes green.
Activity
jeanlucaslima commentedon Jun 29, 2026
Root cause
The events page renders a custom WebGL map (
src/app/(main)/community/events/map/engine.ts) that drives an unconditional render loop:It does a full WebGL re-render every frame and immediately schedules the next one — even when the map is completely idle (no pan, no inertia, no marker animation). With hardware acceleration the GPU absorbs this; in a VM without GPU acceleration (software/llvmpipe), every frame's render runs on the CPU, which pegs many cores while nothing visibly changes. That matches the report exactly.
Quantifying it
While the page sits idle with no interaction, the map keeps calling
requestAnimationFramecontinuously — measured at ~124 calls/second (247 in a 2s window). A correct on-demand map would be ~0.How to test it programmatically
Rather than measuring CPU directly (hardware/CI-dependent and flaky), assert the invariant that's actually broken: the render loop must go idle when nothing is animating. Counting engine
requestAnimationFramecalls over an idle window is deterministic and GPU-independent, and drops into the existingtest/e2e/community-events.spec.ts:Suggested fix
Make
loop()schedule a new frame only while something is actually changing (active inertia, marker animations, cooling pointer trail, active drag, resize) and park the loop when idle, re-arming on the next interaction. The test above then goes green.jeanlucaslima commentedon Jun 29, 2026
Sorry, this was an automated comment, but maybe another approach is having something simpler in place as well. But the issue is real