Skip to content

perf(assets): shrink gameplay image payload from ~10 MB to ~90 KB - #28

Merged
merlik787-droi merged 3 commits into
Riddlrealm:mainfrom
Penielka:fix/issue-13-optimize-gameplay-images
Aug 27, 2026
Merged

merlik787-droi merged 3 commits into
Riddlrealm:mainfrom
Penielka:fix/issue-13-optimize-gameplay-images

Conversation

@Penielka

Copy link
Copy Markdown
Contributor

Closes #13

Summary

The gameplay header bundled ~10 MB of uncompressed PNGs (each icon ~1 MB, rendered at 40 px) plus a 2 MB hero image, dwarfing the ~116 KB gzipped JS bundle. This PR re-encodes those images to WebP at ~2× their rendered size, adds an enforced asset budget so it can't regress, and documents the policy.

What changed

Assets — all images re-encoded to WebP at ~2× rendered size (see scripts/optimize-assets.mjs):

Asset Before After
8× GameHeader icons ~874 KB – 1.5 MB each 0.9 – 1.7 KB each (inlined in the Gameplay chunk)
clock.png (timer) ~1 MB 0.9 KB
hero-image.png 2.06 MB 75.7 KB
  • Gameplay image payload: ~10 MB → ~88 KB (≈99% reduction) — well past the 60% target.
  • Icons are now under Vite's inline limit and ship as base64 inside the Gameplay chunk (zero extra requests); the largest emitted asset is hero-image.webp at 75.7 KB.
  • Removed 5 unused multi-MB contributor*.jpg files (not referenced anywhere) that would otherwise trip the new budget.

Delivery — hero-image now uses loading="lazy" + decoding="async" (it is hidden on mobile; browsers still fetch it eagerly when in the initial viewport). Header icons got decoding="async".

Guard — new scripts/check-asset-size.mjs fails when any raster asset in src/assets/ or public/ exceeds 250 KB. Wired into npm run build and as a dedicated CI step in .github/workflows/ci.yml.

Docs — new ASSET_POLICY.md (formats, 250 KB budget, ~2× sizing rule, lazy-loading rule, new-image checklist), linked from the README.

Tooling — sharp added as a devDependency; npm run optimize:assets re-runs the conversion.

CI note

main was already failing npm test (3 failures) and npm run build due to a bad merge: Dashboard.tsx references an undefined leaderboardView, and the AuthService suite leaks localStorage between tests. Since this PR's CI runs the full suite, it includes a small second commit fixing both (useLeaderboard wired back into Dashboard, unused import dropped, localStorage cleared per test). CI is green with these included.

Verification

  • npm test — 51/51 pass
  • npm run lint — clean
  • npm run build — succeeds; no asset in dist/assets exceeds 250 KB
  • npm run check:assets — passes

Penielka and others added 3 commits August 25, 2026 17:32
Re-encode the eight GameHeader icons, the timer icon, and the hero image
to WebP at ~2x their rendered size (icons: 80px, hero: 1400px), cutting
the gameplay bundle from ~10 MB of uncompressed PNGs to ~90 KB total.
Adds a sharp-based optimizer (npm run optimize:assets), a 250 KB asset
size budget enforced at build time and in CI (npm run check:assets), and
documents the policy in ASSET_POLICY.md. Lazy-loads the hero image and
async-decodes header icons. Removes unused multi-MB contributor images
that would trip the new budget.

Closes Riddlrealm#13

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
main's test suite and build are currently broken by a bad merge: Dashboard
references an undefined `leaderboardView` (and an unused mock import), and
the AuthService suite leaks localStorage between cases so a token persisted
by an earlier test masks a fail-closed assertion. Wire Dashboard back to
the live useLeaderboard hook, drop the unused import, and clear localStorage
per test. These fixes are required for CI (npm test) to pass at all, so they
ship alongside the asset work to keep this PR's checks green.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
The committed lockfile was missing entries for the @vitest/coverage-v8
dependency subtree (make-dir, html-escaper, semver), which made `npm ci`
fail with an out-of-sync error in CI. Regenerate with `npm install` and
commit the completed tree; `npm ci` now installs cleanly.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@merlik787-droi
merlik787-droi merged commit 7283cce into Riddlrealm:main Aug 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gameplay header bundles ~10 MB of uncompressed PNGs into the critical bundle

2 participants