Three.js workflow
Three.js texture optimization for mobile WebGL
Reduce texture-driven crashes and long first renders by separating download size from GPU memory, choosing map sizes by screen impact, and using KTX2 for delivery.
Reviewed:
Direct answer: Three.js Texture Optimization
A compressed JPG or WebP can still become a large uncompressed texture on the GPU. Audit dimensions and duplicate maps first, keep 4K only where screen coverage proves it is needed, then transcode production textures to KTX2 and test on actual mobile hardware. PLAYTEX AI prepares and validates the source map stack but does not perform the KTX2 transcode.
- First audit
- Pixel dimensions
- Common trap
- Download ≠ GPU memory
- Delivery target
- KTX2 transcoding
Texture failures that hide behind a fast desktop
Desktop testing can mask device limits. Treat each map as runtime memory, not only as a file in the network panel.
| Symptom | Likely cause | Fix |
|---|---|---|
| Mobile tab reloads after entering a scene | The combined decoded texture set exceeds the device budget. | Cut dimensions and unique map count before tuning shaders. |
| First frame arrives late | Many large images decode, upload, and compile at once. | Prioritize visible materials and defer distant or optional textures. |
| A 4K map adds no visible detail | The mesh never occupies enough screen pixels to use it. | Choose size from maximum screen coverage, not source availability. |
| Color is fixed but memory is not | WebP reduced transfer bytes, not necessarily the GPU allocation. | Use GPU-ready KTX2 delivery and measure again. |
A practical mobile budget pass
- Hero surface
- 2K only when screen coverage supports it
- Secondary props
- 512px to 1K starting point
- Repeated materials
- Reuse one texture instance
- Mipmaps
- Keep for minified 3D surfaces
- Compression
- KTX2 with a tested fallback path
- QA
- Real iPhone and Android device
Sources used for this review
- Official: Three.js KTX2Loader
- Official: Three.js repository
- Community: VRAM limits in texture-heavy scenes
- Community: Three.js mobile crash report
From source to reviewed handoff
Inventory dimensions
Record width, height, format, reuse count, and material assignment for every shipped map.
Remove invisible cost
Drop unused channels, deduplicate identical files, and reduce maps that never fill the viewport.
Transcode delivery files
Keep clean masters, then produce KTX2 variants suited to the target GPU families.
Test the weakest device
Measure first render, interaction, and tab stability on the actual phone tier you support.
Allocate resolution by screen impact
These are starting points, not universal limits. Camera distance, UV density, reuse, and device tier still decide the final budget.
| Surface role | Starting point | Watch for |
|---|---|---|
| Hero close-up | 2K when it fills much of the screen | Multiple 2K channels multiply memory |
| Midground prop | 1K for ordinary inspection distance | Shared atlases may beat separate files |
| Small / distant prop | 256px to 512px | Avoid detail the camera cannot resolve |
| UI or color graphic | Exact pixel density for the display slot | Different filtering and color needs than 3D data maps |
Review before export
- List every unique runtime texture
- Compare map dimensions with screen coverage
- Remove unused material slots
- Reuse texture objects across matching materials
- Transcode and test KTX2 on supported browsers
- Watch tab stability, not only average FPS
Load a KTX2 delivery texture
KTX2Loader detects supported GPU formats and transcodes the container at runtime. Its transcoder path must be deployed with the application.
const ktx2 = new KTX2Loader()
.setTranscoderPath('/basis/')
.detectSupport(renderer);
const color = await ktx2.loadAsync('/material_albedo.ktx2');
color.colorSpace = THREE.SRGBColorSpace;
Three.js Texture Optimization FAQ
Why can a small WebP still use a lot of VRAM?
WebP reduces download bytes. After decoding, the GPU allocation depends mainly on pixel dimensions, format, mipmaps, and array or cube usage.
Is 4K too large for Three.js?
Not always, but it should be justified by visible screen coverage. A full PBR set of 4K maps can overwhelm mobile devices quickly.
Should I disable mipmaps to save memory?
Usually not for ordinary 3D surfaces. Mipmaps cost memory but reduce shimmering and sampling cost when a texture becomes small on screen.
Can PLAYTEX AI optimize an existing Three.js project automatically?
No. PLAYTEX AI prepares map sources and engine handoff data. Project-level profiling, transcoding, loading order, and device testing remain application work.