Skip to content

GPUI: faster persistent artwork, any-format grid art, chrome bars and new icons - #709

Merged
aaf2tbz merged 5 commits into
mainfrom
feat/gpui-artwork-cache-and-chrome-icons
Oct 6, 2026
Merged

aaf2tbz merged 5 commits into
mainfrom
feat/gpui-artwork-cache-and-chrome-icons

Conversation

@aaf2tbz

@aaf2tbz aaf2tbz commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Artwork loading and caching

  • Resolved art is recorded in ~/.metalsharp/cache/gpui-artwork/index.json, so relaunches show cards and heroes immediately instead of re-downloading them.
  • Cached art refreshes in the background without blanking the screen: every session for local sources (custom grid art, backend covers), weekly for remote art, and whenever the candidate list changes. Misses are remembered for a day.
  • Fetches run on a dedicated six-thread pool with urgent and background queues and one shared HTTP agent, so slow network chains no longer queue ahead of GPUI's image decoding.
  • A Steam Art Manager change refreshes only the affected appids, including changes made while the app was closed. Before, any change discarded the whole cache.
  • Oversized stills are downscaled to a pixel budget once, at store time. Tilted dock variants are reused across launches, and orphaned files from earlier sessions are swept.

Any artwork format

  • /art/grid serves any image extension Steam Art Manager writes (.gif, .jpeg, .webp, .svg, .ico, .avif, …), not just .png/.jpg. Steam Art Manager keeps the source extension (and renames .webp to .jpg), so those covers were never found.
  • The app sniffs bytes rather than trusting the name. SVG is rasterized with resvg (already in the tree via gpui), formats GPUI can't decode are converted with sips, and animated GIF/WebP/APNG are kept as-is so they animate.

Chrome header and footer

  • Both bars use the website's ink surface, a hue wash, and a spectrum hairline. Dark keeps the site's cyan → blue → violet; every other theme re-hues it around its accent, and the footer Stream icon follows.

Icons (original drawings in the existing 24px style, not the trademarks)

  • Start Steam: Steam-style mark. Launch Ubisoft: Ubisoft Connect-style swirl.
  • Tab switcher: gamepad for Play, sharp sign for Sharp Library, plus matching Collection and Logs icons.
  • Theme menu: fuller moon (Dark), sun (Light), dragonfruit (Dragonfruit).

Testing

  • make -C app/src-c test
  • cargo fmt --check && cargo test in app-gpui (75 passed). New tests cover byte-for-byte storage, downscaling, SVG rasterization, animated GIF preservation, rejection of error pages, and fingerprint stability.
  • python3 app-gpui/inventory-backend-routes.py --check (regenerated; only line numbers and the router hash moved)
  • clang-format --dry-run --Werror on backend.c
  • Installed into /Applications/MetalSharp.app (Developer ID re-signed) and checked against a real library: the tilted dock cards and themed bars render, and the artwork index (14 entries plus the grid signature) persists across quit.

Steam Art Manager keeps the source file's extension when it writes grid
art (and renames .webp to .jpg without converting it), so custom covers
saved as .gif, .jpeg, .webp, .svg, .ico, and similar were never found:
/art/grid only looked for .png and .jpg.

Match <appid>p.*, <appid>_hero.*, and <appid>.* against an allowlist of
image extensions, case-insensitively, which also skips the <appid>.json
logo-position files that share the folder. Unknown extensions elsewhere
keep the image/jpeg default.
Artwork used to live only in memory: every launch re-downloaded each
card and hero, retried known misses, and any grid art change threw the
whole cache away. Fetch chains also ran blocking HTTP on GPUI's
background executor, queueing image decodes behind network timeouts.

- Record resolved art in cache/gpui-artwork/index.json so relaunches
  show it immediately. Entries revalidate in the background without
  blanking the screen: every session for local sources, weekly for
  remote art, and when candidates change. Misses are kept for a day.
- Run fetches on a dedicated six-thread pool with urgent and background
  queues, and reuse one HTTP agent.
- Normalize stored art: rasterize SVG with resvg, convert formats GPUI
  can't decode (AVIF, HEIC, ICNS, ...) with sips, downscale oversized
  stills to a pixel budget, and keep animated GIF/WebP/APNG as is.
- Refresh only the appids whose grid files changed, including changes
  made while MetalSharp was closed (signature saved with the index).
- Name tilted dock variants after their card file so they are reused
  across launches, and sweep orphaned files from earlier sessions.
- Header and footer use the website's ink surface with a hue wash and a
  spectrum hairline. Dark keeps the site's cyan, blue, and violet; other
  themes re-hue it around their accent, as does the footer Stream icon.
- Start Steam gets a Steam-style mark and Launch Ubisoft a Ubisoft
  Connect-style swirl (original drawings, not the trademarks).
- The tab switcher uses a gamepad for Play and a sharp sign for the
  Sharp Library, with matching Collection and Logs icons.
- The theme menu gets a fuller moon, a sun, and a dragonfruit.
GPUI only advances an image's frames when the img has an element id to
keep frame state in, and none of the artwork images had one, so animated
covers from Steam Art Manager showed their first frame. Give library,
dock, hero, uninstalled, and Sharp Library art a stable id per file.

Pre-rendered tilted dock cards are a single still frame and GPUI can't
rotate raster images, so the cache now records animated art and the dock
shows those covers straight (the arch only tilts 3-6 degrees).
The hero drew its art at 62% opacity under a full-frame 31% black wash
plus an 85%-to-15% left scrim, so even the right side of the art showed
at about a third of its real brightness. Draw the art opaque and keep
only a left scrim behind the title and Play button that clears by 72%
of the width; the bottom fade into the dock is unchanged.
@aaf2tbz
aaf2tbz merged commit f091104 into main Oct 6, 2026
7 checks 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.

1 participant