Working with Textures

Sampler settings — what to actually change#
Every image texture carries a per-asset sampler record (SceneTexture in
packages/shared/src/sceneEditor.ts) that the runtime applies whenever it loads the texture.
The defaults are correct for most table assets; the ones worth touching deliberately:
- Filtering — leave on linear for anything photographic (card faces, wood/felt surfaces). Switch to nearest only for pixel-art assets, where linear filtering blurs the crisp edges you designed around.
- Anisotropy (1–16) — raise it for a texture viewed at a steep angle relative to the camera (a table surface, a floor) to keep it sharp toward the horizon; leave it at the default for a texture that's usually viewed face-on (a card, a token top).
- Address U/V (repeat / clamp / mirror) — repeat for a tiled surface texture (wood planks, felt) paired with a Tiling value above 1; clamp for anything that should never visibly seam, like a card face or a poster.
- sRGB — on for color/albedo maps, off for data maps (normal maps, roughness/AO) if you're hand-authoring a material rather than using a built-in preset.
- Mipmaps — leave on. Turning it off only makes sense for a texture you know is always viewed at native resolution (a full-screen UI backdrop), which is rare on a 3D table.
Changes apply live — there's no separate save step, the same as every other Inspector field.
KTX2/Basis compression — why bother, and why it's safe#
Compress to Basis, on the Texture editor
tab, produces a .ktx2 copy beside your original (never replacing it) in one of two codecs —
ETC1S for color/albedo maps, UASTC for normal maps and other detail-sensitive maps. The payoff
is GPU-resident compressed storage: a KTX2 texture uploads to VRAM compressed and stays that
way, instead of being decompressed to a full RGBA texture the GPU has to hold uncompressed —
worth doing for a texture every peer loads repeatedly (a shared table surface, a common card
back) more than for a one-off asset only you'll ever see.
It's per-device safe because every peer transcodes the same .ktx2 source to whatever
format their own GPU actually supports at load time (basisTranscode, with an RGB565/RGBA4444
fallback) — nobody downloads a format baked for someone else's hardware. Compression itself runs
on the main thread in your browser; on a texture 2K or larger it briefly blocks the tab — see
Troubleshooting
if that catches you off guard.
The known .ktx2 explorer gap#
⚠ A .ktx2 asset drags and assigns onto any texture slot from the asset explorer grid —
material maps, surface textures, posters — exactly like any other texture, because assignment
only needs the asset id. What it does not do is show up in a texture's own Textures tab
list, or open with Sampling/WebP controls in the Texture
editor: the tab only lists assets that
pass isSupportedTextureContentType, and a compressed KTX2 container isn't a browser-decodable
image, so it's excluded from that check by construction, not by a bug in the listing. If you're
looking for a .ktx2 you know you compressed and can't find it in the Textures tab, it's still
there — check the asset explorer grid instead. See
Troubleshooting
for the same note in the troubleshooting index.
Common mistakes#
- Compressing a texture you'll only assign once. Basis compression is worth it for shared, frequently-loaded textures; for a one-off it's main-thread work for no real payoff.
- Leaving Address mode on repeat for a card face or poster. A non-tiling texture on repeat can show a visible seam at its edge under certain UV setups — use clamp.
- Looking for a compressed texture in the Textures tab. It won't be there. Look in the asset explorer grid, where it drags and assigns like any other texture.
- Re-encoding to WebP on an asset with no preserved original. An asset uploaded before WebP conversion existed has nothing to re-encode from — the Texture editor's button stays disabled and says so.
See also#
- Item editors: Texture — the full panel reference
- Item editors: Model — embedded-texture replace inside a GLB
- Troubleshooting
