b180637ea7
The table reflection (full scene re-render) and the book shadow maps each cost ~11ms/frame and were refreshing at 30Hz even when nothing moved, so every idle/reveal frame paid for one heavy pass on top of the ~12ms scene render — ~45-52fps. These passes only need full-rate updates while the book geometry is actually moving (a page flip). At idle, or during a text reveal where only the page texture mask animates, they now refresh at 8Hz (candle flicker is the only thing changing them then, captured imperceptibly). Most non-flip frames are then just the scene render. pixelRatio is deliberately left at 2x: the book is tilted, so page glyphs are minified along the tilt and the supersampling is the scene's antialiasing (the composer MSAA is disabled in app-integration mode). Reducing it blurs text and exposes edge aliasing, so 60fps is bought from the geometry-independent passes instead. Expressed pixelRatio via devicePixelRatio so it stays native on HiDPI. Verified live at WQHD/2x (screenshot-checked crisp text + clean edges): idle ~64fps median (was 52), reveal ~66fps median (was ~33). Remaining single-digit dips are main-thread page rasterization during background prepare — addressed by the worker migration. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>