What am I looking at?
The middle image is the block-compressed texture decoded back — exactly the texels a GPU would sample. The right pane is the amplified absolute error, which is where codecs actually differ: BC1 breaks up in smooth gradients (it has 4 colours per 4×4 block), BC7 and ASTC hold together, and ETC2's planar mode does well on gradients but cannot handle channels that move in opposite directions (it modulates R, G and B by one shared offset).
sRGB-aware resize decodes to linear light before filtering. Filtering directly in sRGB darkens what it averages: a black/white checker minifies to ~0.5 sRGB (0.21 linear) instead of 0.5 linear (~0.74 sRGB). Toggle it on a high-contrast image and watch the mid-greys move.
HDR textures cannot go through an 8-bit codec — the values run past 1.0. BC6H and ASTC HDR store half-float endpoints instead, and decode to float. Load a scene-linear EXR (the openexr-images button has plenty) and sweep the exposure: an LDR codec would clip, these do not.
Why BC7 looks fine until you raise the exposure
BC7 is an 8-bit codec: everything above 1.0 is clipped at encode time. At 0 EV that is invisible on many images. Push the exposure up and the highlights that BC6H still holds are simply flat white in BC7 — the data is gone, not merely quantised. That is the whole argument for an HDR codec.
Normal maps are the classic case where PSNR lies. What matters is the angle of the reconstructed normal, not the error in the raw channels — a codec can score well on RGB and still light your surface wrong. The demo derives a tangent-space normal map from the image's luminance, compresses it, and reports the mean angular error in degrees.
Why BC5 wins even though it stores fewer channels
BC5 keeps only X and Y, each with its own endpoints, and the shader rebuilds Z = √(1 − x² − y²). BC7 spends bits on a blue channel that carries no information and shares endpoints across channels, so it is usually worse on normals despite being the "better" codec — a result you can reproduce right here. EAC_RG11 is the mobile equivalent of BC5.
Environment maps for IBL. Load an equirectangular (latlong) EXR and reproject it to a cubemap (6 faces) or an octahedral map, then compress the result with BC6H. Octahedral packing wastes no texels on the seams a cube has, which is why it keeps showing up in modern renderers.
The cubemap is drawn as a vertical strip: +X, −X, +Y, −Y, +Z, −Z. texpipe also does seam-free cubemap LOD (filtering across face borders so the mips do not crack at the edges) — see the docs.
texpipe builds the mip chain from the base image at every level (not by repeatedly halving the previous mip, which compounds filter error), and can apply content-aware passes per level.
Alpha-coverage preservation
Minifying an alpha-tested texture (foliage, chain-link) thins it out: fewer texels survive the alpha test at each level, and the leaves visibly evaporate in the distance. texpipe rescales alpha per level so the fraction of texels passing the test stays put (Castaño's method).