# Thumbnails sized for the tile's width at 2x, not 512 on the long side _2026-09-23. Operator on sindra-nude-final: "the images look blurry until they're selected and blown up." Commits `c2b1454`, `c19d8c9`, merged `1d31ab0`._ ## The measurement - The cap was 512px on the LONGEST side. Tiles are sized by WIDTH (`width:100%; height:auto`). - Chromium put desktop tiles at 321-361 CSS px (3 columns, 1440px viewports and up), 324-472 at 2 columns, and up to 650 at 1 column (measured across a 360-2560 viewport sweep). - A 704x1408 portrait got a 256-wide thumbnail: stretched 1.4x at 1x density and 2.8x on a 2x screen. - The live sizes are mostly 704x1408, 896x1216, 832x1216 and 1024x1024 portraits (368 images sampled). ## The rule - `THUMB_WIDTH = 768` (2x the widest desktop tile) and `THUMB_HEIGHT_MAX = 4096`. - An original that fits is served as-is only when it's also light (<=64 KB; 768-wide thumbnails average 39 KB) or animated. - `tests/test_thumbs_browser.py` binds 768 to the rendered grid at 1440, 1920 and 2560. - Cost across all 381 live images: 4.8 → 14.2 MB at 768; 1024 would have been 18.5 MB. Live rebuild: 14.5 MB, 369 webp and 12 originals, 9 s. - **The operator kept 768 (2026-09-24).** ## heid bug-hunt (4/4, five seat-executed probes) → `c19d8c9` - A cache hit must be a REGULAR file with its source's EXACT mtime. A planted directory was served as the thumbnail, and `cp -p` pinned stale ones forever. - The cache dirs are made component by component without following links. A `.thumbs` link put the cache outside the booth. - The temp file is mkstemp. `..tmp` was plantable as a link: 600 B became 316,400 B. - Palette transparency survives. This one was INTRODUCED by `c2b1454`'s fits-but-heavy branch. - EXIF orientation is honoured. - A 64 MP decode budget. - The whole rule is in the cache name: `.768x4096q78v2.webp`.