Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Your Three.js canvas can look completely still while your application continues to call renderer.render(scene, camera) on every animation frame. That repeated CPU and GPU work is a plausible reason for a warm phone and faster battery drain. The Three.js manual explicitly warns that continuously rendering a scene that does not animate wastes device power and, on portable devices, battery. This explains unnecessary rendering work; it does not prove that Three.js alone caused a particular phone’s temperature.

The practical fix is to render once after setup, then request another frame only when something that affects the image changes: a control gesture, a resize, a newly loaded texture or model, incoming data, a setting change, or camera movement. Keep a continuous loop only for genuinely animated content or while an interaction such as damped controls is still settling.

What is probably making the phone hot?

The important distinction is between a static scene and a static-looking canvas. If your code starts an endless requestAnimationFrame chain and renders from its callback, the browser keeps waking your JavaScript and graphics pipeline even when every object remains in the same place. A typical loop looks like this:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate();

Nothing in that code checks whether the scene changed. Every callback performs another render, and the browser may continue doing that at the display’s refresh cadence. The Three.js “Rendering on Demand” manual describes this exact non-animated case as a waste of device power and portable-device battery. Read the guidance at threejs.org/manual/pages/rendering-on-demand.html.

#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter | 4Pack Type C Female to A Male Cable Converter for Apple Duo 17 16 15 14 Plus,iWatch Watch 12 11 10,iPad 9 8 Air,Airpods 5 4
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.

That documentation establishes needless repeated rendering as a power cost, not a measured thermal diagnosis. The report of a “cooking” phone contains no model, browser, operating system, scene complexity, frame rate, ambient temperature, or thermometer reading. Rendering may be one contributor; other JavaScript, video, sensors, network processing, browser tabs, or a poorly behaved shader can add work. First verify that your application is still scheduling frames before attributing all heat to Three.js.

Check whether your app is rendering continuously

Search the project for requestAnimationFrame, setAnimationLoop, and calls to renderer.render. A loop can be hidden in a framework component, an example copied from a Three.js demo, or a helper that calls itself after every frame.

  1. Count renders. Temporarily increment a counter immediately before the render call and display it or log it once per second. If the number rises while you do not touch the scene, you have a continuous loop.
  2. Check the scheduler. A function that calls requestAnimationFrame again unconditionally is continuous by definition. The same is true of a setAnimationLoop callback that never stops.
  3. Separate updates from drawing. Look for timers, physics ticks, control updates, or data subscriptions that may be changing state even though the visible geometry appears still.
  4. Profile before and after. Use your browser’s performance tools to see whether scripting and GPU activity falls when the loop is removed. Treat a lower activity level as evidence that work stopped, not as a guaranteed temperature or battery percentage improvement.

Render on demand for a static scene

For a scene with no autonomous animation, use one initial draw and a redraw request for each meaningful change. The essential pattern is a coalesced request: many events arriving close together should produce one animation-frame callback, not a queue of redundant callbacks.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

1. Draw the initial state

Set up the renderer, scene, camera, lights, and objects as usual. After setup is complete, request one frame:

let renderRequested = false;

function render() {
  renderRequested = false;
  renderer.render(scene, camera);
}

function requestRenderIfNotRequested() {
  if (!renderRequested) {
    renderRequested = true;
    requestAnimationFrame(render);
  }
}

requestRenderIfNotRequested();

The flag prevents five changes in the same turn of the event loop from scheduling five separate callbacks. The browser still gets a normal animation-frame opportunity to draw, but it does not receive unnecessary duplicate renders.

Rank #2
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter | USB C Dongle with 90W Max Power Delivery, 3×5Gbps USB A Data Ports, for MacBook, Dell, and More (Charger Not Included)
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.

2. Wire every event that can change pixels

An on-demand renderer is only correct if every relevant state change calls requestRenderIfNotRequested(). Common triggers include:

  • OrbitControls or another camera-control interaction.
  • Window or canvas resizing, after updating the camera projection.
  • Textures, fonts, models, environment maps, or other assets completing asynchronous loads.
  • Incoming application data, filtering, sorting, or a selection change.
  • User settings such as material, color, visibility, exposure, or quality.
  • Code that moves the camera, changes a uniform, edits geometry, or modifies a light.

For example, the resize handler should update both the renderer and camera before requesting a frame:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
function resize() {
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;

  renderer.setSize(width, height, false);
  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  requestRenderIfNotRequested();
}

window.addEventListener('resize', resize);

If an asset loader finishes after the first draw, call the same request function in its completion handler. Otherwise the new asset may exist in memory but remain absent from the displayed image until an unrelated event causes a redraw.

3. Connect camera controls without creating a loop

OrbitControls emits a change event when its camera changes. Use that event to request a frame:

controls.addEventListener('change', requestRenderIfNotRequested);

This is the basic static-camera case. Do not call renderer.render synchronously from every control event if several events can arrive together; the coalescing function keeps the work to one scheduled draw.

Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter | 85W Max PD, 2 USB 3.0 & 1 USBC Data Ports, SD/TF Card Reader, for Laptops/Mac and Other Type C Devices (Charger Not Included)
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.

Handle damping and inertia correctly

Damped OrbitControls are not truly static immediately after the pointer or touch ends. The control continues changing the camera for several frames while its inertia settles. During that period you must keep requesting frames; stopping after the input event would freeze the camera before it reaches its final position.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Update the controls inside the scheduled callback, render the resulting camera, and request another callback only when the update reports that the view is still changing. The exact return behavior depends on the controls version, so follow the API used by your project. A representative structure is:

function render() {
  renderRequested = false;

  const changed = controls.update();
  renderer.render(scene, camera);

  if (changed) {
    requestRenderIfNotRequested();
  }
}

Keep the change listener as well so a new gesture starts the process:

controls.addEventListener('change', requestRenderIfNotRequested);

There is a subtle recursion hazard. If controls.update() itself emits a change event, and that event immediately performs a full redraw or calls controls.update() again, the update/event cycle can recurse. Schedule and coalesce the next frame instead of rendering synchronously from the handler. The Three.js manual’s on-demand example discusses this case and the need to let the damping updates settle through scheduled frames; see the official example.

Choose continuous or on-demand rendering

The right strategy depends on whether the scene can change without an external event. Use this decision table before removing a loop:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray | Data transfer & Fast charging for MacBook, iPhone 17/16/15, iPad, Samsung Galaxy, Apple Watch
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
Scene condition Preferred strategy What must trigger a draw
All objects and uniforms remain fixed after setup On-demand Initial setup, controls, resize, and any later state change
Camera damping or another inertia effect is settling Temporary on-demand sequence Keep scheduling while the update changes the view; stop when settled
Video textures, skeletal motion, particles, physics, or timed shader animation Continuous loop Every animation tick, because state changes with time
Data arrives unpredictably On-demand with event requests Each completed data update, coalesced with other nearby changes
Uncertain renderer/API initialization Follow the installed version’s lifecycle Initialize before rendering where that API requires it

A scene can be mostly static but still need a continuous loop for a single animated element. In that case, keep the loop only while that animation is active, or split the animated content into a separate update path if your architecture supports it. Do not assume that an unchanged camera means the whole scene is unchanged.

Use the recommended loop API when animation is real

If the scene genuinely animates, Three.js advises defining the animation loop with renderer.setAnimationLoop(callback) rather than manually wiring requestAnimationFrame for best compatibility. The renderer documentation states this recommendation at threejs.org/docs/pages/WebGLRenderer.html.

renderer.setAnimationLoop(() => {
  updateAnimatedState();
  renderer.render(scene, camera);
});

This API does not make a needless loop demand-driven. It is the appropriate lifecycle for content that must be updated every frame. For a static scene, remove the continuously running callback and use explicit redraw requests instead.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Account for renderer version and initialization

Three.js renderer APIs are version-sensitive. The newer generic Renderer API requires initialization before you call render() outside an animation loop. Consult the documentation for the exact renderer class and release installed in your project; do not copy an initialization sequence meant for one API into another.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The current WebGLRenderer documentation says it uses WebGL 2 and that WebGL 1 is unsupported since Three.js r163. That is a version-specific capability statement, not a guarantee about every older project. Confirm your installed Three.js release and the renderer you instantiate before changing startup code. The relevant references are WebGLRenderer and Renderer.

Best Value
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display | 85W Max PD, 1 Powered USB-C 5Gbps & 2 Powered USB-A 3.0 5Gbps Data Ports, for MacBook Pro, MacBook Air, Dell and More (Black)
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.

Common mistakes when converting a loop

Forgetting asynchronous assets

Removing the loop before a texture or model finishes loading can leave the canvas showing the pre-load frame. Request a redraw in every loader’s completion path, after assigning the loaded resource and updating any materials that depend on it.

Updating the camera without updating its projection

On resize, set the new aspect ratio and call camera.updateProjectionMatrix() before requesting the frame. Otherwise the canvas may redraw with stale projection parameters.

Calling controls.update only on input

With damping enabled, the camera can continue changing after the input event. Run the update from scheduled frames until it reports no further change; then stop scheduling.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Scheduling one callback per event

Mouse movement, touch events, resize notifications, and data updates can arrive in bursts. A renderRequested guard prevents a burst from becoming a burst of renders.

Assuming a static image means no state changes

A shader clock, hidden animation, physics step, video frame, or polling subscription can alter pixels without visibly moving an object at first glance. Audit those sources before switching to on-demand mode.

Diagnose heat after the change

After replacing the unconditional loop, repeat the render counter and performance check while reproducing the original interaction. You should see a draw at startup and additional draws only when you resize, interact, load something, or change application state. If the counter still rises while the scene is untouched, locate another scheduler or event source.

If rendering activity drops but the phone remains hot, investigate other work rather than promising a Three.js-only fix. Check active tabs, video playback, Web Workers, large data transforms, sensor access, network polling, and browser extensions. Also test under the same ambient conditions as the original report. The available Three.js documentation provides no measured battery percentage, temperature threshold, frame-rate figure, or GPU-utilization number, so no responsible article can predict a particular degree of cooling or battery-life gain.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Practical implementation checklist

  • Render one initial frame after scene setup.
  • Guard redraw requests with a flag so nearby events share one callback.
  • Request frames for controls, resize, asynchronous assets, data, settings, and every other pixel-changing state update.
  • Update camera aspect and projection before drawing after a resize.
  • Keep scheduling while damped controls or other inertia are still changing the view.
  • Avoid synchronous redraw/update recursion from control change handlers.
  • Use setAnimationLoop for content that truly changes every frame.
  • Verify initialization and renderer details against the Three.js version in your project.
  • Measure render activity before claiming that a temperature or battery problem is solved.

A motionless-looking Three.js scene should not consume animation-level rendering power by default. Make drawing an explicit response to state changes, and reserve a continuous loop for animation that actually needs it.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.