Skip to content

v3.3.0

Choose a tag to compare

@Zheaoli Zheaoli released this 30 May 20:16
· 65 commits to main since this release
d00d7c5

Highlights

v3.3.0 is a major performance release that makes large photo libraries fast and stable on every device. The headline change is a new responsive image pipeline: instead of serving multi-megabyte originals in the gallery, PicImpact now generates and serves content-addressed AVIF/WebP variants sized to the viewport — shrinking image payloads by orders of magnitude and eliminating the lag, jank, and mobile crashes that came from loading 20 MB+ originals.

  • 🖼️ Responsive image pipeline — automatic AVIF/WebP variant generation on upload, an async background preprocessing queue with progress in /admin/tasks, a backfill CLI for existing libraries, and responsive srcset delivery so the grid never loads originals.
  • ⚡ Faster, smoother gallery — virtualized masonry (replaces CSS columns), scroll-adaptive prefetching, animation hygiene with reduced-motion support, and fewer blank cells while fast-scrolling.
  • 🚀 Faster page loads — improved LCP (eager-load + server-side preload of the first image) and lower TTFB via cached public read paths with tag-based invalidation.
  • 📱 Mobile stability — fixed the infinite-scroll crash loop, a WebGL viewer context leak, and a preview double-load regression that could OOM mobile browsers.
  • 🔍 Detail & zoom viewer — loads lightweight variants on demand instead of eagerly fetching the original, while the full-screen zoom panel loads the full-resolution original for true pixel-level detail.
  • ✅ Quality & correctness — EXIF-oriented dimensions, private-bucket presigned reads, accessibility fixes (proper list semantics), and assorted color/cache fixes.

What's Changed

  • fix: mobile infinite-scroll crash loop in InfiniteScroll observer by @Zheaoli in #471
  • feat(images): add image variant pipeline fields (BE-1) by @Zheaoli in #470
  • feat(images): add image variant generator library (BE-2) by @Zheaoli in #473
  • perf: virtualize gallery masonry (replace CSS columns, window large lists) by @Zheaoli in #474
  • perf: animation hygiene (drop box-shadow spring, gate infinite loops, reduced-motion) by @Zheaoli in #472
  • fix(images): use EXIF-oriented dimensions in metadata refresh by @Zheaoli in #475
  • feat: serve responsive image variants in the gallery (fix 20MB-original lag) by @Zheaoli in #476
  • feat(images): expose variant base URL + align next/image sizes (BE-4) by @Zheaoli in #477
  • feat(tasks): image variant preprocessing queue engine (BE-3 parts 1+2) by @Zheaoli in #481
  • feat(settings): add variant storage backend setting (BE-4 follow-up) by @Zheaoli in #483
  • feat(api): preprocess-images task endpoints (BE-3 part 3a) by @Zheaoli in #484
  • feat(scripts): image variant backfill CLI (BE-3 part 3c) by @Zheaoli in #487
  • fix(scripts): resilient backfill CLI + surface failure detail by @Zheaoli in #488
  • fix(images): read originals via presigned URL in preprocessing (private-bucket 403) by @Zheaoli in #489
  • fix: check response.ok when saving variant storage setting by @Zheaoli in #485
  • feat: serve image variants in the tag gallery (no original in grid) by @Zheaoli in #482
  • perf: bound the thumbhash decode cache with an LRU by @Zheaoli in #480
  • refactor(images): extract client-safe variant tier constants by @Zheaoli in #479
  • fix: invalid hsl(oklch) color in sidebar rail box-shadow by @Zheaoli in #478
  • perf(images): decode original once + lower AVIF effort + smarter CLI sleep by @Zheaoli in #491
  • feat(images): auto-generate variants on upload (auto-enqueue) by @Zheaoli in #490
  • feat(images): async background ticker for variant generation by @Zheaoli in #493
  • feat(admin): show variant preprocess tasks in /admin/tasks (reusable TaskRunPanel) by @Zheaoli in #494
  • fix(daily): include variant columns in daily_images materialized view by @Zheaoli in #495
  • feat: serve image variants in the polaroid theme (no original in grid) by @Zheaoli in #496
  • refactor: import variant tier constants from shared module in loader by @Zheaoli in #492
  • fix: reduce blank cells while fast-scrolling the masonry grid by @Zheaoli in #498
  • fix: detail viewer loads variant on demand, not the original eagerly by @Zheaoli in #497
  • fix(preprocess): handle oversized panoramas + slow original fetch by @Zheaoli in #499
  • feat: aggressive, scroll-adaptive pagination prefetch in InfiniteScroll by @Zheaoli in #500
  • fix(gallery): raise default page size 8 → 24 (FU-11) by @Zheaoli in #501
  • fix: persist config across soft navigation (gallery AVIF→preview downgrade on back-nav) by @Zheaoli in #502
  • fix(webgl-viewer): release engine on unmount to stop WebGL context leak (FU-13) by @Zheaoli in #503
  • perf(lcp): eager-load + server preload first gallery image (FU-15) by @Zheaoli in #504
  • perf(ttfb): cache public read path with tag invalidation (FU-16) by @Zheaoli in #505
  • fix(a11y): use role="list" for the masonry container (FU-17) by @Zheaoli in #506
  • fix(viewer): load the original in the zoom panel, not the 2560 variant by @Zheaoli in #507
  • fix(gallery): hydrate variantBaseUrl from server to stop preview double-load (mobile crash regression) by @Zheaoli in #508

Full Changelog: v3.2.0...v3.3.0