viewer: survive block-misaligned KTX2 textures on WebGPU#467
Conversation
WebGPU rejects block-compressed textures whose base dimensions aren't multiples of 4; three's KTX2Loader only warns and transcodes anyway, so a baked GLB carrying one odd-sized user-item texture (e.g. 299x399) poisoned every render pass — endless 'Invalid BindGroup … Invalid CommandBuffer' spam. Route such payloads through a fallback transcode to uncompressed RGBA32 and repackage the pixels as a plain DataTexture (three's WebGPU upload path crashes on a CompressedTexture holding rgba8 data). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d2448ac. Configure here.
| texture.generateMipmaps = true | ||
| texture.minFilter = LinearMipmapLinearFilter | ||
| texture.magFilter = LinearFilter | ||
| texture.needsUpdate = true |
There was a problem hiding this comment.
Repackaged texture omits flipY
Medium Severity
The misaligned path builds a new DataTexture from decoded pixels but only copies colorSpace and filter settings from the transcoded result. Loader-applied fields such as flipY stay at DataTexture defaults, so GLB and catalog textures on this path can render vertically flipped versus the aligned compressed path.
Reviewed by Cursor Bugbot for commit d2448ac. Configure here.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |


What does this PR do?
Fixes the community
/viewerblack-screen + endlessInvalid BindGroup "bindGroup_object"/Invalid CommandBuffervalidation spam on baked GLBs that carry a KTX2 texture with non-multiple-of-4 dimensions (e.g. a 299×399 user-item JPEG that the bake pipeline encoded unresized).WebGPU rejects block-compressed textures whose base dimensions aren't multiples of 4. three's
KTX2Loaderonly warns about such payloads and transcodes them to a block format anyway; the resulting invalid texture then poisons every render pass that binds it, once per frame.ktx2-loader.tsnow exports anAlignmentSafeKTX2Loader: it reads the width/height straight from the KTX2 header for Basis payloads (vkFormat 0), and routes misaligned ones through a fallback loader whose support flags report no compressed formats — the transcoder then emits plain RGBA32, which has no alignment requirement. The decoded pixels are repackaged as a regularDataTexturebecause the loader's RGBA output still arrives wrapped in aCompressedTexture, and three's WebGPU upload path (WebGPUTextureUtils._copyCompressedBufferToTexture) crashes looking up a block descriptor for rgba8. Aligned textures take the unchanged fast path.Companion private-editor PR fixes the bake LOD encoder to power-of-two-resize JPEG sources too, so new artifacts won't contain misaligned KTX2 in the first place; this change is what makes the already-baked prod artifacts render.
How to test
project_dAYO2MJVTHExwsQY(lod0.glb contains one 299×399 ETC1S KTX2 texture): served the GLB locally, pointed a localprojects_bakesrow at it, and drove/viewer/<id>with WebGPU-enabled headless Chromium (--enable-unsafe-webgpu --use-angle=metal). Before: 4,025 GPU validation errors in 60s, black scene. After: 0 errors, scene renders, single console warningKTX2 texture is 299x399 (not multiple-of-4); transcoding uncompressed….bun run check-typesandbunx biome checkpass.Screenshots / screen recording
N/A — non-visual change when textures are well-formed; for the affected artifacts the change is "black screen + error spam" → "renders normally".
Checklist
bun devbun checkto verify)mainbranch🤖 Generated with Claude Code
Note
Medium Risk
Changes the central KTX2 load path for all GLB and catalog textures and relies on private three.js loader internals, though aligned textures are unchanged and the fallback is narrowly scoped to misaligned Basis payloads.
Overview
Fixes WebGPU black screens and per-frame
Invalid BindGroup/Invalid CommandBufferspam when baked GLBs include Basis KTX2 textures whose width or height are not multiples of 4 (e.g. odd-sized user-item images).The shared
ktx2Loaderis now anAlignmentSafeKTX2Loaderthat inspects the KTX2 header and, for misaligned Basis payloads, transcodes via a fallback loader with all compressed formats disabled so output is RGBA32, then wraps the result in aDataTexture(three’s WebGPU path still treats RGBA fromCompressedTextureas block-compressed). Aligned textures keep the existing fast path through stockKTX2Loader._createTexture.Reviewed by Cursor Bugbot for commit d2448ac. Bugbot is set up for automated code reviews on this repo. Configure here.