#!/usr/bin/env python3 """Build static picker thumbnails for avatar decorations. The decorations are animated APNGs (~1 MB each). The settings picker shows static WebP thumbnails instead and only loads the animated file on hover, focus or selection, so browsing the catalog costs a few MB, not hundreds. Usage: python3 scripts/makeDecorationThumbs.py Then upload /*.webp to `${DECORATION_CDN}/thumbs/`. A missing thumbnail is harmless: the picker falls back to the full PNG. Requires Pillow (pip install pillow). """ import sys from pathlib import Path from PIL import Image, ImageSequence SIZE = 144 # 2x the 72px picker cell def best_frame(im: Image.Image) -> Image.Image: # Many animations start (or loop through) an empty frame, so pick the frame # with the most visible pixels rather than frame 0. best, best_score = None, -1 frames = list(ImageSequence.Iterator(im)) step = max(1, len(frames) // 24) for frame in frames[::step]: rgba = frame.convert('RGBA') score = sum(rgba.getchannel('A').histogram()[33:]) if score > best_score: best, best_score = rgba, score return best def main(src: str, out: str) -> None: out_dir = Path(out) out_dir.mkdir(parents=True, exist_ok=True) for png in sorted(Path(src).glob('*.png')): with Image.open(png) as im: thumb = best_frame(im).resize((SIZE, SIZE), Image.LANCZOS) thumb.save(out_dir / f'{png.stem}.webp', 'WEBP', quality=82, method=6) if __name__ == '__main__': if len(sys.argv) != 3: sys.exit(__doc__) main(sys.argv[1], sys.argv[2])