HeadlinesBriefing favicon HeadlinesBriefing.com

Optimizing Angular and Three.js Performance

DEV Community •
×

A production Angular app faced performance issues with a Three.js globe, running at only 30fps due to Zone.js triggering change detection on every requestAnimationFrame tick. This caused 60 unnecessary change detection cycles per second, leading to high GPU usage and battery drain. The solution combined OnPush change detection with Angular Signals and a render-on-demand pattern, ensuring that frames are only drawn when the scene actually changes.

The GlobeSceneService now owns the render lifecycle, starting and stopping the animation loop on init and destroy. This approach exposes requestRender() and requestFrameIfNeeded() APIs, making rendering behavior predictable and debuggable. As a result, the app achieves consistent 60fps, reduces GPU usage by 90% when idle, and eliminates Zone.js interference with the render loop.

Instead of using the experimental zoneless API, this hybrid approach keeps Zone.js for UI interactions while preventing it from affecting Three.js. The key is the render-on-demand pattern, where the animation loop runs continuously, but rendering is conditional. This optimization is particularly beneficial for 3D visualizations and data dashboards where renders are event-driven.

To implement this, every component uses OnPush change detection, and Angular Signals are used for reactive state instead of RxJS. The render loop remains imperative to avoid the overhead of Observable allocation and scheduling. This method ensures that the 3D Global Dashboard runs smoothly, with users reporting better battery life and a responsive UI during complex animations.