Skip to content

Lighten the 3D office's frame on Firefox (Retina Macs especially) - #375

Open
fun-ed wants to merge 1 commit into
AgentSystemLabs:mainfrom
fun-ed:perf/firefox-mac-retina
Open

fun-ed wants to merge 1 commit into
AgentSystemLabs:mainfrom
fun-ed:perf/firefox-mac-retina

Conversation

@fun-ed

@fun-ed fun-ed commented Oct 18, 2026

Copy link
Copy Markdown

Summary

  • On Firefox, the sun's shadow map is redrawn every other frame instead of every frame. A frame of the office was ~1,890 draw calls, ~840 of them the shadow pass; per-frame draw calls now alternate 1,043 / 1,885 (about 22% fewer on average). Moving characters' shadows lag by one frame.
  • On Firefox, a Retina screen is drawn at a pixel ratio of 1.5 instead of 2: about 44% fewer pixels to fill, and less memory for the 4× multisampled framebuffer (estimated ~70 MB on a full-screen 13" MacBook Air). Slightly softer image.
  • In every browser, the first-person crosshair ray (the per-frame aim tick) stops at the longest interaction reach + 1 m instead of testing the whole building's meshes. First-person targeting only uses hits within reach, so behavior is unchanged; third-person clicks keep the unlimited ray, so "Walk closer to that first" still shows.

Why Firefox

Profiled in Firefox 159 on a MacBook Air M4 (16 GB): the tab's main thread was 94–99% busy in the frame callback. That cost is per-call JS/IPC overhead (Firefox remotes WebGL commands to another process), not GPU fill: OutlineEffect's two passes plus the shadow pass, plus the crosshair raycast.

Profile samples (same ~5 s window, before → after):

  • Rendering (OutlineEffect.render): 4,584 → 3,556
  • Shadow pass (WebGLShadowMap.render): 642 → 269
  • Crosshair raycast: 1,249 → 832

Validation

  • Pass: npm run typecheck
  • Pass: npm run build
  • Pass: npm test. 569 tests ran together; tests/workers.test.ts (32 tests) passed when run on its own. It stalled during the full run on a heavily loaded machine (load average 12–24), and it is server-side, untouched by this change.
  • Checked in Firefox that the shadow map still exists and updates on alternating frames.

Not verified

  • No fps before/after figures: the machine was too heavily loaded for stable fps numbers.
  • The 1.5× cap was not checked on a real Retina display. The test Firefox ran at devicePixelRatio 1, so there is no before/after screenshot.

Firefox's WebGL spends a lot of main-thread time per draw call, and a frame
of the office was about 1,890 of them, ~840 just redrawing the sun's shadow.

- On Firefox the sun's shadow is redrawn every other frame (about 22% fewer
  draw calls on average), and a Retina screen is drawn at 1.5x instead of 2x
  (about 44% fewer pixels to fill and multisample-buffer memory to hold).
- In every browser, the first-person crosshair ray stops at the longest reach
  instead of testing the whole building's meshes every frame.
muguetdev pushed a commit to muguetdev/agent-office that referenced this pull request Oct 27, 2026
…om Agent Office AgentSystemLabs#375)

Firefox's WebGL spends a lot of main-thread time per draw call, and a frame
of the office was about 1,890 of them, ~840 just redrawing the sun's shadow.

- On Firefox the sun's shadow is redrawn every other frame (about 22% fewer
  draw calls on average), and a Retina screen is drawn at 1.5x instead of 2x
  (about 44% fewer pixels to fill and multisample-buffer memory to hold).
- In every browser, the first-person crosshair ray stops at the longest reach
  instead of testing the whole building's meshes every frame.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant