Repository navigation
feat(games): every game pill shows the game's app icon, or a monogram - #404
Merged
Merged
Conversation
"Your games" drew IGDB box art for Rocket League, Valorant, League of
Legends, Dota 2 and Trackmania. Two causes: a pack installed from the
catalog before its game had an icon hid the icon the image ships for the
same game (only bundled installs fell back to the snapshot), and a game
saved from IGDB was only ever matched to a module or pack by exact slug.
Linking. A stored game is matched to the module or pack for the same game
by IGDB id, then slug, then a slug alias, then its normalised name. Packs
and module catalogue entries may name `igdbId`; the bundled index carries
it too, so a pack installed before its file had one still links. An alias
or name match is refused when both sides know different IGDB ids
("DeadLock" 2021 is not Valve's Deadlock). CS2 names 242408.
Any pack now falls back to the snapshot's icon for its game, whoever
installed it, on the pill and on /api/packs/:slug/app-icon and the catalog
route.
Steam client icons for any game on Steam, with no key: the Steam app id
comes from IGDB's Steam external game (search now asks for it) or from
Wikidata P1733; the icon from steamcmd.net's `clienticon` and
shared.fastly.steamstatic.com (the old Cloudflare path is the fallback; it
404s for new games such as Battlefield 6). The largest frame of the .ico
is scaled to 128 px in pure JS (pngjs, bundled; the release image has no
node_modules, so no sharp) and stored as PNG under DATA_DIR/game-icons,
named by its hash, served from /api/games/icons/:file with a year-long
immutable cache and recorded on the games row (steam_app_id, icon_url,
icon_source, icon_checked_at). It runs in the background after searches,
saves and startup: one pass at a time, 1 s between requests, 6 s timeouts,
failures retried after 14 days. A frame under 48 px is not used.
The pill never draws a cover: no icon means the game's first letter on a
neutral tile (`GameMark neutral`).
Bundled packs synced from Auto-Tournament/packs: igdbId on 32 packs, new
app icons for Battlefield 6, League of Legends, StarCraft II and Chess.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
On the test box, "Your games" drew IGDB box art for Rocket League, Valorant, League of Legends, Dota 2 and Trackmania.
bundledfell back to the icon the image ships, so these packs showed no icon, and the popular-list fallback never ran because the installed pack had already claimed the slug.What changes
Linking (
gameCatalogService.linkBuiltin). A stored game is matched to its module or pack in this order:Packs and module catalogue entries can now carry
igdbId. The validator accepts it. The bundled index carries it too, so a pack installed without it still links. CS2 is242408.An alias or name match is refused when both sides know their IGDB id and the ids differ. For example, "DeadLock" (2021) is a different game from Valve's Deadlock.
Any pack falls back to the snapshot's icon, whoever installed it. This applies to the pill,
/api/packs/:slug/app-iconand the catalog app-icon route. This alone fixes the test box, with no pack update needed.Steam client icons for any game on Steam, with no key:
external_games), or from Wikidata P1733 when IGDB isn't set up.steamcmd.netcommon.clienticon.shared.fastly.steamstatic.com/community_assets/.... The old Cloudflare path is the fallback; it 404s for new games such as Battlefield 6..icois scaled down to 128 px and stored as PNG underDATA_DIR/game-icons/<sha256-16>.png. It's served fromGET /api/games/icons/:filewithmax-age=31536000, immutable. Frames under 48 px are not used.node_modules, so sharp can't come along. pngjs (pure JS, already in the lockfile) is bundled instead, and there is no pure-JS WebP encoder worth shipping.gamescolumnssteam_app_id,icon_url,icon_source,icon_checked_at, added by the schema's automatic ADD COLUMN.GAMES_ENRICH=off); the specs force it against a fake Steam.The pill never draws a cover. With no icon, it shows the game's first letter on a neutral tile (
GameMark neutral). OtherGameMarkuses (teams, tournaments) are unchanged.Bundled packs synced from Auto-Tournament/packs#8:
igdbIdon 32 packs, and app icons for Battlefield 6, League of Legends, StarCraft II and Chess. Every popular title now has an icon with no keys set.No SteamGridDB and no new setting: everything above works with zero keys.
Merge order
igdbId.The CS2
igdbIdreaches the installed CS2 module with its next release. Until then, CS2 still links by slug.Checks
eslint .: 0 errors/api/games/icons/:file)tests/api/game-icons.spec.ts(16 tests):igdbIdvalidation, and that the bundled index matches the pack files.icodecoding for PNG and BMP frames, never scaled up, small frames rejectedapp-icons.spec.tsupdated: League of Legends now has an icon.🤖 Generated with Claude Code