The Hidden Culprit: Download Size vs. GPU VRAM
Many web developers assume that if their 3D model is 4MB on disk, it only consumes 4MB of RAM. That comparison is misleading. PNG, JPEG, and WebP delivery bytes are typically decoded before a WebGL texture upload. An RGBA8 representation is a useful budgeting example, but the actual channel format, copies, and GPU allocation depend on the implementation.
1. The PNG/WebP Trap in Real-Time WebGL

A small encoded download can expand substantially when decoded for rendering.
When a mobile browser loads a standard GLB file containing four 2K PNG textures (BaseColor, Normal, ORM, Emissive), here is what happens under the hood:
For the following estimates, MB uses decimal units (1 MB = 1,000,000 bytes): 16.78 MB is approximately 16.0 MiB, and 22.3 MB with mipmaps is approximately 21.3 MiB. The roughly 90 MB total is approximately 85.8 MiB.
2048 x 2048 Pixels: Equal to 4,194,304 pixels.
32-Bit RGBA8: 4 bytes per pixel (Red, Green, Blue, Alpha).
Decoded RGBA8 pixel data per 2K texture:
4,194,304 x 4 bytes = 16.78 MB.With a full mip chain:
16.78 MB x 1.33 = about 22.3 MB.Four texture maps: About 90 MB of decoded RGBA8 pixel data under these assumptions. Browser and driver allocation can differ.
On memory-constrained mobile devices, large decoded textures can create memory pressure and may cause WebGL context loss or a tab reload. Practical limits vary by device, OS, browser, and competing page resources.
2. What Is KTX2 & How Does GPU Compression Work?

KTX2 delivery is transcoded to a format supported by the active GPU.
KTX 2.0 (Khronos Texture Container) paired with Basis Universal is a unified texture compression architecture designed specifically for modern GPUs.
A. The Magic of GPU Hardware Sampling
Unlike PNG or WebP, supported native block-compressed texture formats can remain compressed in GPU memory. Block dimensions and storage depend on the format; ASTC, for example, is not restricted to one 4x4 block choice. The GPU graphics chip decompresses individual blocks in hardware on-the-fly as texels are sampled during rendering.
After transcoding to a GPU-supported block-compressed format, the texture can remain compressed in GPU memory. The actual memory saving depends on the selected target format, mipmaps, dimensions, and alpha requirements.
3. ETC1S vs. UASTC: Choosing the Right Mode
Basis Universal provides two distinct compression engines within the KTX2 specification:

ETC1S prioritizes compact delivery, while UASTC is a higher-fidelity intermediate representation.
Compare delivery encoding with the chosen runtime format
| Input | Transfer consideration | Runtime consideration |
|---|---|---|
| PNG, JPEG, or WebP | Encoded image size varies with content and settings. | Decoded pixel format and mip levels determine texture storage. |
| KTX2 with ETC1S | Often useful when compact delivery is the priority. | Actual transcode target and quality need inspection. |
| KTX2 with UASTC | Often a useful candidate for detail-sensitive data. | Target format, mip levels, and fallback behavior still determine storage. |
For a 2048 × 2048 RGBA8 base level, the arithmetic is 16 MiB. A hypothetical 8-bit-per-pixel GPU block format at the same dimensions uses 4 MiB for its base level. Those are format calculations, not measured allocations or universal ETC1S and UASTC memory values. Include mip levels and other copies separately.
Keep the Three.js transcoder assets compatible with the loader version. The code below assumes an existing scene and application lifecycle. Release KTX2Loader's workers when the application will make no further loads through that loader, not immediately after the first model if other requests still depend on it. Model textures and geometry require their own ownership-based disposal.
4. Why KTX2 Matters for WebAR & Spatial Web

Texture memory is one part of the device budget alongside camera and tracking work.
Browser-based WebXR and Android Scene Viewer share device resources with camera and tracking workloads, making texture memory especially important. Apple Quick Look uses USDZ and needs its own compatible texture pipeline; a KTX2-enabled GLB is not a drop-in Quick Look asset.
When textures are encoded in KTX2:
Smaller texture uploads: GPU-native block compression can reduce upload size and memory bandwidth, although decoding, transcoding, and upload work still exists.
Lower bandwidth pressure: Compressed textures can reduce memory traffic; sustained thermal behavior still depends on the complete scene and device.
Faster readiness potential: Smaller payloads and uploads may shorten time-to-interaction, which should be recorded separately from AR tracking initialization.
5. Implementing KTX2Loader in Three.js
Setting up KTX2 in modern Three.js applications is straightforward with KTX2Loader and Web Workers:

KTX2Loader detects supported targets before GLTFLoader uses the transcoded textures.
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js';
import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js';
// 1. Initialize WebGL Renderer
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.outputColorSpace = THREE.SRGBColorSpace;
// 2. Configure KTX2 Transcoder (runs in background Web Workers)
const ktx2Loader = new KTX2Loader()
.setTranscoderPath('/vendor/three/examples/jsm/libs/basis/')
.detectSupport(renderer);
// 3. Attach KTX2 & Meshopt Decoders to GLTFLoader
const gltfLoader = new GLTFLoader();
gltfLoader.setKTX2Loader(ktx2Loader);
gltfLoader.setMeshoptDecoder(MeshoptDecoder);
// 4. Load the optimized asset, then measure decode/upload time
gltfLoader.load('./models/smart-device-ktx2.glb', (gltf) => {
scene.add(gltf.scene);
console.log('[Loaded] KTX2 model ready in scene');
});
Key Takeaway for 3D Technical Artists
Treat KTX2 as a strong production option, not a universal rule. ETC1S often suits color maps where compact delivery matters; UASTC is often preferable for normal maps and other detail-sensitive data. Test visual error, download size, transcode time, and GPU memory on the devices you support, and keep a fallback when your delivery stack requires one.
Frequently Asked Questions
Why can PNG or WebP textures create memory pressure in mobile 3D?
PNG, JPEG, and WebP reduce download size, but a typical WebGL upload uses decoded texels. Four 4K RGBA8 textures require about 256 MiB before mipmaps, although the actual allocation depends on channel count, internal format, mipmaps, and browser implementation. That pressure can contribute to WebGL context loss or tab reloads on constrained devices; there is no single reliable per-tab limit across iOS hardware and releases.
What is the difference between ETC1S and UASTC modes in Basis Universal?
ETC1S prioritizes compact delivery and often works well for color data. UASTC uses a higher-bitrate intermediate representation and is usually a better starting point for normal maps or detail-sensitive textures. Compare artifacts, encoded size, transcode target, and GPU allocation for the material rather than relying on a universal percentage.
How does KTX2 transcode textures in real-time on client devices?
KTX2Loader detects capabilities exposed by the active renderer and selects a supported target for the encoded Basis data. The target is not determined by an operating-system name alone. Inspect the actual transcode result and any uncompressed fallback before calculating runtime memory.
Does GLB Studio Pro support inspecting and baking KTX2 textures?
GLB Studio Pro can detect KTX2 resources and load supported KTX2 textures through Three.js for viewing. The Baker can preserve existing binary resources while packing or unpacking, but it does not currently provide a general-purpose KTX2 encoder. Verify any replacement workflow with the exported GLB and Khronos validation tools.