Parent
#32 (asset pipeline migration milestone)
Problem
scripts/compress-team-photos.js (introduced in #41) only walks assets/team/*.{jpg,jpeg}. The other asset categories — assets/clients/, assets/posts/<slug>/, assets/stories/, assets/jobs/, assets/tools/, assets/legal/ — receive arbitrary-sized images from non-tech contributors and have no automated optimisation step.
Doing this before #36 (push cleaned assets to new store) avoids pushing un-optimised bytes to the new blob store and re-doing the work later.
What to build
Rename / generalise to scripts/optimize-assets.js:
- Walks
assets/**/*.{jpg,jpeg,png,webp}
- Per-extension pipeline:
- JPEG: resize to fit configurable max dimension (default 1600x1600), quality 80, mozjpeg encoder
- PNG: skip unless above threshold; if above, run through
sharp.png({ quality, compressionLevel: 9, palette: true }) and only keep the result if smaller than original (size-regression guard)
- WebP: quality 80
- Per-directory overrides via a small config map:
team/ → max 800x800 (portrait avatars)
clients/ → max 400x400 (logos)
posts/, stories/ → max 1600x1600 (blog covers / story images)
- default → 1600x1600
- Dry-run by default,
--write executes (atomic write-then-rename, already in the existing script)
- Per-file output:
category/file before → after (saved X%) or skip (under threshold) / skip (no gain)
- Summary: total before / after / saved, broken down by extension
Keep the existing scripts/compress-team-photos.js callable as a thin wrapper or delete it once the generalised version covers the same case.
Acceptance criteria
Blocks
Blocked by
Notes
DX follow-up from #41 — raised because future non-tech contributors will push arbitrary-sized images across all categories, not just team photos. Pair with the CI auto-fix issue for the full DX story.
Parent
#32 (asset pipeline migration milestone)
Problem
scripts/compress-team-photos.js(introduced in #41) only walksassets/team/*.{jpg,jpeg}. The other asset categories —assets/clients/,assets/posts/<slug>/,assets/stories/,assets/jobs/,assets/tools/,assets/legal/— receive arbitrary-sized images from non-tech contributors and have no automated optimisation step.Doing this before #36 (push cleaned assets to new store) avoids pushing un-optimised bytes to the new blob store and re-doing the work later.
What to build
Rename / generalise to
scripts/optimize-assets.js:assets/**/*.{jpg,jpeg,png,webp}sharp.png({ quality, compressionLevel: 9, palette: true })and only keep the result if smaller than original (size-regression guard)team/→ max 800x800 (portrait avatars)clients/→ max 400x400 (logos)posts/,stories/→ max 1600x1600 (blog covers / story images)--writeexecutes (atomic write-then-rename, already in the existing script)category/file before → after (saved X%)orskip (under threshold)/skip (no gain)Keep the existing
scripts/compress-team-photos.jscallable as a thin wrapper or delete it once the generalised version covers the same case.Acceptance criteria
scripts/optimize-assets.jswalks all ofassets/**and handles.jpg,.jpeg,.png,.webp--writeperforms atomic in-place rewriteassets/size reduced (target: ≥ 30% global, but the win is on the long tail of large blog images, not the already-compressedteam/)Blocks
Blocked by
Notes
DX follow-up from #41 — raised because future non-tech contributors will push arbitrary-sized images across all categories, not just team photos. Pair with the CI auto-fix issue for the full DX story.