Skip to content

Load covers through the asset protocol instead of base64 over IPC - #3

Merged
firsttris merged 2 commits into
mainfrom
claude/perf-assets
Oct 5, 2026
Merged

firsttris merged 2 commits into
mainfrom
claude/perf-assets

Conversation

@firsttris

Copy link
Copy Markdown
Owner

What / why

Covers over the asset protocol. get_game_cover and get_game_icon used to read the whole cached image and send it as a base64 data: URL over IPC, which is about a third larger plus encoding and decoding on both sides. GameCard and GameListRow then refetched it on every games refresh, because their $effect depended on the whole game object, and each refresh creates a new object.

  • Both commands now return the path of the cache file. The frontend turns it into an asset:// URL with convertFileSrc (src/lib/stores/steamgriddb.ts).
  • tauri.conf.json turns on app.security.assetProtocol with its scope limited to $APPDATA/artwork/*, the cover/icon cache dir, top level only. This needs the protocol-asset feature on tauri, which adds a single new crate, http-range, to Cargo.lock. I edited the lock by hand so the rest of it stays untouched; --locked accepts it.
  • The URL carries ?v=<grid id>, so a newly chosen image is not shadowed by the webview cache. The asset protocol ignores the query.
  • The cards now depend only on id, cover_url and cover_grid_id (via $derived) and drop results from outdated requests.
  • Cover <img>s get loading="lazy" and decoding="async".
  • Removed image_data_url and image_mime along with their tests. The base64 crate stays because icons.rs uses it.

Static cleanup. Removed the unused template files static/svelte.svg, tauri.svg and vite.svg. A grep found no references outside .git.

Measured

  • IPC payload per cover: before, the full image as base64 (about 1.33× the file size, so tens to hundreds of KB per grid image). After, only the path (about 100 B). The webview reads the file itself and caches it.
  • Refetches: before, one get_game_cover call per card on every refreshGames(). After, a call only when the id, cover URL or grid id changes.

How tested

  • bun run check: 0 errors, 0 warnings.
  • bun run test and bun run build pass.
  • cargo test --locked: 128 passed. A cargo build --locked (dev profile) has no warnings, and tauri-build accepts the feature and config combination.
  • Not run here: cargo build --release (too little disk space in the sandbox; CI covers it), and a manual check in the running app since there's no display. Worth a quick look that covers show up in the grid and list views and that switching a cover updates the card.

🤖 Generated with Claude Code

https://claude.ai/code/session_019UYcbUoJWjGexas7Tjz9Ko


Generated by Claude Code

claude added 2 commits October 5, 2026 10:44
get_game_cover and get_game_icon read the whole cached image and sent it
base64-encoded over IPC (a third larger, plus encode/decode), and every
games refresh refetched it because the cards' $effect depended on the
whole `game` object.

- Both commands now return the cache file's path; the frontend turns it
  into an asset URL with convertFileSrc. The asset protocol is enabled
  with its scope limited to $APPDATA/artwork/* (tauri feature
  protocol-asset, which adds http-range to Cargo.lock)
- The URL carries the grid id as ?v= so a newly chosen image is not
  shadowed by the webview cache
- GameCard/GameListRow only depend on id, cover_url and cover_grid_id
  and ignore results of outdated requests
- Cover images are loaded lazily and decoded asynchronously

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019UYcbUoJWjGexas7Tjz9Ko
svelte.svg, tauri.svg and vite.svg came with the project template and
are referenced nowhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019UYcbUoJWjGexas7Tjz9Ko
@firsttris
firsttris merged commit 7856e15 into main Oct 5, 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.

2 participants