Custom Mod Card Guide

Create custom mod cards for GPU Selector to distribute and install your mods easily.

Example Cards Website: blueskydefender.github.io/GPU-Selector-Cards
  1. Ready-made cards from beginner to expert, to try and to copy.
  2. This guide, online.
  3. The files on GitHub, with the source of the DOOM card's 3D fix: github.com/BlueSkyDefender/GPU-Selector-Cards

Overview

Custom mod cards allow mod authors to create downloadable, installable mod packages that integrate directly with GPU Selector. Users can load multiple cards simultaneously from URLs or local files, and each card appears in the Mods tab with its own download, install, and launch capabilities.

Key Features:
  • Automatic download with AMSI malware scanning
  • ZIP extraction to safe locations
  • Game targeting: link your mod to specific games from the user's library
  • Custom UI elements (dropdowns, radio buttons, checkboxes, text inputs)
  • Update checking from source URL
  • Custom button colors and branding
  • Open folder button to access mod files
  • Searchable: users can find your card by mod name or game name
  • Multi-card: load multiple cards at once, each with independent state
  • Organizer cards: cards with empty versions can highlight and group games without downloads

Multi-Card Support

GPU Selector supports loading multiple mod cards simultaneously. Each card operates independently with its own download state, install tracking, detection, and UI elements.

Card Name = Unique ID

The name field is the card's unique identifier. Two cards cannot share the same name. Card names cannot be renamed after creation: the backend uses the name to key mod folders, download tracking, and install manifests.

Important: Choose your card name carefully! Changing it later would orphan all downloaded files and install manifests. If you need a different name, create a new card.

Built-in Cards

Some cards are built into GPU Selector (e.g., Windower 4). Built-in cards are special:

Locked Cards

Mod authors can set "locked": true in their card JSON to hide the View/Edit JSON option from the gear menu. This is useful for cards distributed to end users where you don't want them accidentally editing the raw JSON.

{
  "cardVersion": "1.0",
  "name": "My Mod",
  "locked": true,
  ...
}
Note: locked only hides the JSON editor from the UI. The card can still be deleted and re-added. It does not provide security: it's a convenience feature to reduce support requests from users who break their card JSON.

Organizer Cards (No Downloads)

Cards with an empty "versions": [] array are valid. These "organizer" cards highlight and group games from the user's library without offering any downloads. They're useful for:

{
  "cardVersion": "1.0",
  "name": "DOOM",
  "description": "Highlights your DOOM games",
  "tagline": "Rip and Tear",
  "versions": [],
  "targetGames": [
    {"match": "contains", "name": "DOOM"}
  ],
  "ui": {
    "buttonColor": "#b91c1c",
    "buttonHoverColor": "#991b1b"
  }
}

Per-Card State Isolation

All runtime state is isolated per card. Each card maintains its own:

This means two cards can both target the same game without interfering with each other.

Play Button Behavior

The play button (▶) next to each game in a mod card uses the game's full launch settings from the Games tab: including GPU selection, monitor preferences, launch arguments, pre/post scripts, and all other per-game settings. It does not bypass any game configuration.

Where Cards Live: Custom Cards or Modding Cards

  1. Cards people add go to Custom Cards on the Mods tab.
  2. In the + Add Mod window, Put them in picks the place: Custom Cards (default) or Modding Cards.
  3. It works for all three ways to add a card: Load from URL, Load from File and Cards on the House.
  4. Load from URL takes a card (.json) or a card package (.zip or .7z).
  5. Move a card later: right-click it.
  6. Built-in wrappers (ReShade, DXVK, dgVoodoo, Zink) are in Modding Utilities.

Modding Utilities

Graphics wrappers, shader injectors, and add-on managers. Built-in cards maintained by GPU Selector.

Custom Cards or Modding Cards ← Your cards go here

Cards loaded with + Add Mod. You pick the place with Put them in.

Users switch between the two layers by clicking the title in the header. The Modding Cards layer includes:

Targeting Specific Games

The targetGames field lets you link your mod to specific games from the user's library. When a user has matching games installed, a scrollable game list appears on your card showing each matched game with per-game Install, Unload, and Play buttons.

How Game Matching Works

Each entry in targetGames supports several match types, from most precise to broadest:

"targetGames": [
  {"match": "exe_hash", "hash": "a1b2c3d4e5f6...64chars..."},
  {"match": "id", "name": "steam_379720"},
  {"match": "exact", "name": "DOOM", "store": "Steam"},
  {"match": "contains", "name": "DOOM"},
  {"match": "startsWith", "name": "DOOM"},
  {"match": "pattern", "name": "*Dark Souls*"}
]
Match TypeBehaviorExample
"exe_hash"Matches the SHA-256 hash of the game's executable (absolute precision)Targets one specific game binary, regardless of name or store
"id"Matches the game's unique internal ID"steam_379720" targets exactly one game
"exact"Game name must match exactly (case-insensitive)"DOOM" matches only "DOOM"
"contains"Game name must contain the word as a whole word (word-boundary)"DOOM" matches "DOOM Eternal" but not "GOSDOOMA"
"startsWith"Game name must start with the target string"DOOM" matches "DOOM" and "DOOM Eternal"
"pattern"Wildcard matching with * (broadest)"*Souls*" matches "Dark Souls III", etc.

Exe Hash Matching

The "exe_hash" match type uses a SHA-256 hash of the game's executable file for absolute precision targeting. This is the most reliable way to identify a specific game, especially for non-store games or custom executables where names and IDs may vary between users.

{"match": "exe_hash", "hash": "a1b2c3d4e5f6..."}
How to get a hash: Right-click any game card in the Game Library and select Extract Exe Hash. The SHA-256 hash of the game's executable will be copied to your clipboard, ready to paste into your mod card JSON.
Note: Exe hashes change when the game updates. If the game receives a patch that modifies its executable, the hash will no longer match. For games that update frequently, consider combining "exe_hash" with a name-based fallback like "contains".
Store Filter: Any name-based match type can include an optional "store" field to restrict matches to a specific store. For example: {"match": "exact", "name": "DOOM", "store": "Steam"} will only match DOOM from Steam, not from GOG or Epic.
Game IDs: IDs follow the format store_identifier (e.g., steam_379720, gog_123456, epic_DOOM). The "id" match type is useful when multiple games share the same name across different stores. For non-store games, use "exe_hash" or "exact" with "store": "Custom".
Search Integration: When your card specifies targetGames, users can find it by searching for game names in the search bar. For example, if your card targets "Elden Ring", typing "elden" in the search will show your card.

What the User Sees

When targetGames is defined:

Per-Game Install Actions

Each target game entry can define its own installActions for game-specific files:

"targetGames": [
  {
    "match": "exact", "name": "FINAL FANTASY VII REMAKE",
    "installActions": [
      {"type": "copy", "from": "ff7r/dxgi.dll", "to": "{game}/dxgi.dll"}
    ],
    "skipDefaultActions": true,
    "logPatterns": ["*.log", "crash_*.txt"]
  },
  {"match": "contains", "name": "FINAL FANTASY"}
]
FieldDescription
installActionsArray of game-specific install actions (max 5). Appended to top-level installActions.
skipDefaultActionsIf true, skips the top-level installActions for this game (only uses per-game ones).
logPatternsArray of glob patterns for mod log files (max 10). Used for auto-cleanup on unload.
reshadeSuggested ReShade modes for this game: {"proxy": true, "opengl": "on", "vulkan": "off"}. Each game row has injection (Auto or Proxy), GL and VK buttons (the game's own settings); a suggestion that isn't set yet gets an amber dashed edge. Add "lock": true when you know the game's API: the modes are set for the user and locked on the card.
hdrtrue when the game needs Windows HDR (an HDR mod). When the user turns the card's add-on on for the game, its HDR box is ticked, so GPU Selector turns HDR on when it starts. It never unticks it.
notesUp to 8 short lines about this game, like settings it needs: ["Set Color Precision to High."]. The game's row gets a Notes button that opens them. Only people who have the game see them.

Unload & Cleanup

All files installed to game folders are tracked in an install manifest. Users can:

Limit: A maximum of 25 target games per card is enforced. If you need to support all games, omit the targetGames field entirely.

Exe Launch Security

When launchExe is set, users see a security warning before the executable runs. This protects users from unexpected program launches. The warning shows the executable name and requires explicit confirmation.

JSON Schema Reference

{
  "cardVersion": "1.0",
  "name": "Example Mod",
  "author": "Example Author",
  "authorUrl": "https://github.com/example-author",
  "website": "https://example.com",
  "icon": "https://example.com/icon.png",
  "backgroundArt": "https://example.com/background.jpg",
  "description": "Smoother frame pacing and better input for your games",
  "tagline": "A made-up mod, to show every field",
  "license": "MIT License",
  "licenseUrl": "https://github.com/example-author/example-mod/blob/main/LICENSE",
  "sourceUrl": "https://github.com/example-author/example-mod",
  "locked": false,

  "versions": [
    {"version": "1.1.0", "url": "https://example.com/example-mod-1.1.0.zip", "filename": "ExampleMod.zip", "password": ""},
    {"version": "1.0.0", "url": "https://example.com/example-mod-1.0.0.zip"}
  ],

  "targetGames": [
    {"match": "exact", "name": "Elden Ring"},
    {"match": "pattern", "name": "*Dark Souls*"},
    {"match": "pattern", "name": "Sekiro*"}
  ],

  "installActions": [
    {"type": "extract", "from": "ExampleMod64.dll", "to": "{game}/dxgi.dll"},
    {"type": "copy", "from": "default_ExampleMod.ini", "to": "{game}/ExampleMod.ini"}
  ],

  "launchExe": "ExampleModLauncher.exe",
  "launchArgs": "",

  "ui": {
    "buttonColor": "#10b981",
    "buttonHoverColor": "#059669",
    "downloadedButtonColor": "#22c55e",
    "downloadedButtonHoverColor": "#16a34a",
    "useRainbowButton": false,
    "dropdowns": [
      {"id": "wrapper", "label": "Wrapper DLL", "options": ["dxgi.dll", "d3d11.dll", "d3d9.dll"]}
    ],
    "radioGroups": [
      {"id": "installType", "label": "Install Type", "options": ["Per-Game", "Global"]}
    ],
    "textInputs": [
      {"id": "customPath", "label": "Custom Install Path", "placeholder": "Leave empty for default", "required": false}
    ],
    "checkboxes": [
      {"id": "backup", "label": "Backup existing DLLs", "default": true}
    ]
  }
}

Field Descriptions

FieldRequiredDescription
cardVersionYesCard schema version: "1.0", or "1.1" for cards with downloads, addons or modes
nameYesMod name (displayed in card header)
authorNoWho made the mod or project (shown as "by ...")
cardByNoWho made the card itself. Shown small in the bottom right as "Card by ..."
cardByUrlNoLink for the "Card by" name (HTTPS only), for example your GitHub page
authorUrlNoLink to the author's page (HTTPS only)
websiteNoLink to mod homepage (HTTPS only)
iconNoURL to mod icon (PNG/JPG, max 128x128 recommended)
backgroundArtNoURL to card background image
descriptionYesBrief description of mod functionality
taglineNoA short line shown after the author in the card's header (up to 100 characters)
licenseNoLicense name (e.g., "MIT License", "GPL-3.0")
licenseUrlNoURL to full license text (HTTPS only)
sourceUrlNoURL to source code repository (HTTPS only)
versionsYes (leave it out when you use downloads)Array of available versions (newest first). Can be empty [] for organizer-only cards. Give each version a "sha256" (the file's SHA256) so GPU Selector can check the download. Without one, only GitHub release downloads are checked (by GitHub's own checksum).
targetGamesNoArray of games this mod supports (max 25, supports per-game installActions)
installActionsNoArray of file operations after extraction (max 5)
noticeNoA box near the top of the card, on every tab. For a disclaimer or an important warning (max 400 characters, plain text, \n for a new line)
launchExeNoExecutable to launch from card (relative to mods folder)
launchArgsNoCommand line arguments for launch exe
allowCustomDriveNoNot used. Kept so older cards still load.
lockedNoIf true, hides the View/Edit JSON option from the gear menu
uiNoCustom UI elements configuration (also modes). The controls (dropdowns, radio buttons, checkboxes, text boxes) pick between your card's own options with "when". They don't change a legacy installActions install.
ui.buttonColor, ui.buttonHoverColor, ui.downloadedButtonColor, ui.downloadedButtonHoverColorNoThe main button's colours, as 6-digit hex like "#10b981".
ui.hoverBorderColorNoThe card's edge colour when the mouse is over it (6-digit hex). Catalog cards also use it as their accent colour.
ui.labelsNoRename your card's buttons and headings: {"install": "Add", "play": "Start", "targetGames": "Games"}. Up to 30 characters each. Keys: targetGames, install, unload, play, cleanAll, cleanLogs, version, installation, download, getLatest, installAddons, reinstallAddons, installShaders, remove, checkUpdates, saveConfig, loadConfig, launch, guide, cardBy ("Card by"), by, chooseGames, found (the word in "5 found"), searchGames, notes, preset, installed, notInstalled, searching, guideTitle (the name of a step guide in guides that has no title). guide names the Guide button and the guide page. A key you leave out keeps its usual word.
ui.tooltipsNoThe hover tips of your buttons, with the same keys as ui.labels: {"play": "Start the game"}. Up to 120 characters each.
ui.colorsNoYour card's colours, each like "#38bdf8". Keys: title, author, link (links on hover), accent (step numbers, the Target Games icon, notes), install, unload, play, save, load, notice.
ui.orderNoThe order of your card's parts: ["games", "description"]. Parts: description, guides, catalog, games, controls, detection, version. Parts you leave out keep their usual order after yours.
ui.websiteNo{"show": false} hides the website link (your modes' links too). {"label": "Our Site"} shows a name instead of the address of your website. A mode's own link shows its site's address.
ui.iconShapeNorounded (default), square, circle or none.
ui.noticeStyleNoThe look of your notice box: warning (amber, default), info (blue) or tip (green).
ui.backgroundFadeNoHow much your backgroundArt is darkened behind the text: none, light, normal (default) or strong.
ui.listRowsNoHow many games the Target Games list shows before it scrolls: 2 (default) to 6.
ui.modesStyleThe look of your tab switch: {"shape": "bar"} (default) or "pills", "offColor" (tabs not picked), "borderColor".
ui.guideStyleThe look of your step guides (guides): "titleColor", "textColor", "badge": circle (default), square or none.
ui.rowButtonsThe order of the buttons on each Target Games row: ["play", "install", "modes"]. Default: install, modes, play.
ui.cleanAllWhere Clean All goes: left (default), right or hidden. People can still remove a mod from one game with Unload.
ui.cardByPositionNoWhere "Card by" goes: right (default), left or hidden.
ui.guideNoYour card's own guide: a Markdown file in your card's package. A Guide button shows at the bottom of the card. See Your card's guide.
ui.gameLetterNoOne letter, A to Z, shown next to HDR on the games your card makes in the Games list, like "D". A mix always shows M.
ui.font, ui.appThemeNoCatalog cards only (see Catalog Cards).
detectionNoFinds a program the user already has: {"installDirHint": "MyTool", "methods": [{"type": "path", "paths": ["C:\\MyTool"], "exe": "MyTool.exe"}, {"type": "process", "processName": "MyTool.exe"}]}. Shows an Installation box. Add "configFiles": [{"name", "path" or "relativePath", "format"}] for Save/Load Config: only config files (like .ini, .xml, .json), in the program's folder or the user's AppData, Documents or Saved Games.
downloadsNoFiles to get from GitHub (see Add-on Packages)
addonsNoReShade add-ons made from the downloads
launchNoA program from the downloads, with a Launch button (see "launch")
requiresNo{"reshade": "6.8.0"}: the ReShade version the card needs
shaderReposNoShader packs installed through Shader Repositories
guidesNoCollapsible step guides (max 12; see Collapsible Guides). "position": "bottom" on a guide puts it at the very bottom
ui.modesNoTabs (see Mode Switch). "position": "top" goes on ui.modes
ui.listCornersNo"rounded" (default) or "square": the corners of the card's game list
ui.autoColorNotrue: colors from the project's GitHub picture. A tab's own color still wins for that tab

Old cards use versions and installActions (copy files into folders). New cards use downloads and addons. Don't mix the two systems in one card.

Version Object

FieldRequiredDescription
versionYesVersion string (e.g., "1.0.0", "24.1.1")
urlYesDownload URL (HTTPS only, must be ZIP)
filenameNoLocal filename (defaults to mod name + version)
passwordNo"login" or "ask": the download is locked, and the user types the key when they download it (see Locked Cards). A password written here is not secret: anyone can read the card.
passwordHelpNoOne line shown in the unlock box, like where to get the key (up to 200 characters).

Target Game Object

FieldRequiredDescription
matchYesMatch type: "exe_hash", "id", "exact", "contains", "startsWith", "pattern", or "preset" (games with a ReShade preset)
nameDependsGame name, ID, or pattern (required for all types except exe_hash)
hashDepends64-character SHA-256 hash of the exe (required for exe_hash)
storeNoOptional store filter: "Steam", "GOG", "Epic", "Custom", etc.
installActionsNoPer-game install actions (max 5). Appended to top-level unless skipDefaultActions is set.
skipDefaultActionsNoIf true, skips top-level installActions for this game entry
logPatternsNoGlob patterns for mod log files to clean on unload (max 10, e.g., "*.log")
reshadeNoReShade modes for this game: {"proxy": true, "opengl": "off", "vulkan": "off", "lock": true}. opengl and vulkan take "on", "off" or "auto". proxy true: ReShade loads as a DLL next to the game for that launch instead of being injected (only for games injection can't reach). opengl/vulkan "off" for DirectX games. lock: the user can't change them on the card
hdrNotrue: turning the card's add-on on for this game also ticks its HDR box
launchArgsNoStart options for this game when your card's Play starts it, like ["-dx11"]. Plain words only. The user's own start options stay; yours are replaced each time.
notesNoUp to 8 plain text lines (200 characters each) shown under the game's Notes button. Plain text: links are not clickable, so write them like hdrmods.com/Cyberpunk
eacBypassNotrue: the game starts offline, without Easy Anti-Cheat, while it uses the card's add-on (needed for add-ons in EAC games). The row shows an Offline chip; the user can turn it off. Online play is off while it is on
reEngineBypassNotrue: GPU Selector's RE Engine bypass for this game, so ReShade can load (RE Engine games GPU Selector knows, like Resident Evil 4). The row shows an RE chip; the user can turn it off
whenNoOnly on some tabs or choices (see Mode Switch)
  1. A game that matches several entries (a Steam ID entry and a name entry) is listed once. Its notes from all of them are joined, and hdr counts if any entry has it.
  2. Use a Steam ID entry and a name entry for each game: the name entry finds other stores.

Install Action Object

FieldDescription
type: "extract"Extract file from ZIP to destination
type: "copy"Copy file to destination
fromSource file (relative to extracted ZIP)
toDestination path (supports placeholders)

Path Placeholders

Use these placeholders in installActions to target common locations:

PlaceholderResolves ToExample
{game}Selected game's install folderC:\Games\Elden Ring
{mods}%LOCALAPPDATA%\GPUSelector\Mods\{ModName}\...Mods\Example Mod\
{appdata}%APPDATA%C:\Users\...\AppData\Roaming
{localappdata}%LOCALAPPDATA%C:\Users\...\AppData\Local
{documents}User's Documents folderC:\Users\...\Documents
{desktop}Desktop folderC:\Users\...\Desktop
{programdata}%PROGRAMDATA%C:\ProgramData
{reshadeShaders}GPU Selector's shared ReShade shaders. Inject Mode loads them in every game. Shader files only (.fx, .fxh)...GPUSelector\Mods\ReShade\Injector eshade-shaders\Shaders\Custom
{reshadeTextures}The same, for textures (.png, .dds and so on)...reshade-shaders\Textures\Custom
{programfiles}%PROGRAMFILES%C:\Program Files (shows warning)
Blocked Locations: {windows}, {system32} and path traversal (..) are blocked for security.

Custom UI Elements

Add custom controls to your card (max 5 of each type):

Dropdowns

"dropdowns": [
  {"id": "variant", "label": "Variant", "options": ["Standard", "Lite", "Full"]}
]

Radio Buttons

"radioGroups": [
  {"id": "installType", "label": "Install Type", "options": ["Global", "Per-Game", "Portable"]}
]

Text Inputs

"textInputs": [
  {"id": "customPath", "label": "Custom Path", "placeholder": "C:\\Games\\...", "required": false}
]

Checkboxes

"checkboxes": [
  {"id": "createShortcut", "label": "Create Desktop Shortcut", "default": false},
  {"id": "backupFiles", "label": "Backup existing files", "default": true}
]

Button Colors

"ui": {
  "buttonColor": "#10b981",
  "buttonHoverColor": "#059669",
  "downloadedButtonColor": "#22c55e",
  "downloadedButtonHoverColor": "#16a34a",
  "useRainbowButton": false
}

Set useRainbowButton: true for an animated rainbow gradient effect.

"listCorners": "square" gives the Target Games list square corners. The default is "rounded".

Let GPU Selector Color the Card

Don't want to pick colors? Add one line:

"ui": { "autoColor": true }
  1. GPU Selector takes the GitHub owner's picture, like it does for shader repo cards.
  2. It colors the card's background, border and main button from that picture.
  3. If the card has no icon, the picture is used as the icon too.

Which GitHub project it uses:

  1. "autoColor": "owner/repo" picks one yourself.
  2. Else the card's sourceUrl or website, when it is a github.com link.
  3. Else the first download with "github".

A card's backgroundArt stays when it has one. useRainbowButton keeps the rainbow button.

Button behavior after download:

Loading Your Card

Users can load cards in three ways:

Security Confirmation

When users click Download, a security warning dialog appears showing the mod name, author, download URL, and source. Users must confirm before any file is downloaded. This protects users from unverified content.

Writing Card Text

Use \n for a new line in description. GPU Selector lays the text out for easy reading:

  1. The first line is a short lead, shown a little brighter.
  2. Lines that start with 1., 2. ... become numbered step boxes, like the 3DConsoleBridge card. They take the picked mode's color.
  3. A line that starts with spaces joins the line above it.
  4. An empty line adds space.

Keep it short: one idea per line, about 5 to 10 lines. Use tabs for more.

Style Guide

These cards follow these rules: SR Loom, Windower 4, 3DConsoleBridge, Neural Rendering and RenoDX HDR. Use them as your style examples, so every card feels the same.

The Card Feature Test card only tests features. It is not a style example.

Words

  1. Simple English. Short numbered lines, one idea per line. Many readers have dyslexia: no walls of text.
  2. No em dashes. Use a period, a colon or a new line.
  3. Never start a line with spaces: it joins the line above it.
  4. Only write what you found in the project's own docs, or what you tested. Not sure? Leave it out.
  5. Say what GPU Selector does for the user, and how: "GPU Selector sets X=3 for you, if it is not set yet."
  6. 3D projects: "turns your games into 3D". Never "real 3D".

The description, in this order

  1. What it needs: "Needs an NVIDIA RTX 20, 30, 40 or 50 card."
  2. Which games: "For 64-bit DirectX games WITHOUT a DLSS option."
  3. Which tab to pick, when there are several: "Not sure which tab? ..."
  4. What it installs, and that each part is needed.
  5. The steps, numbered (like effect order in ReShade).
  6. What GPU Selector sets for the user.

Tabs

  1. Use "position": "top" and short labels (one or two words).
  2. One tab per hardware or setup: NVIDIA | NVIDIA + DLSS | AMD.
  3. Or one tab per part of the card: HDR Mods | Setup | Game Notes, or About | Head Tracking | Keys.
  4. The first tab is the one people use most. The game list and the install button live there.
  5. Each tab must be different: its own text, games or button. Not the same tab twice with new words.
  6. Several topics? Give each one its own tab, like About | Use | Notes. Don't stack guides or one long list instead.

Where long text goes

  1. Notes for one game: that game's notes (its Notes button).
  2. A tab whose games are all on other tabs shows no game list. That is fine for Setup or Notes tabs.
  3. One-time setup: a Setup tab.
  4. Notes for every game: a Game Notes tab, or a guide with "position": "bottom".
  5. At most one short guide per tab. More to say? Use a tab.
  6. "notice": only for a real, important warning from the project's own docs. Never a notice you made up, like "made by AI" or "untested".
  7. A card may be up to 625 pixels tall. The game list shows about two games and scrolls.

Pictures and colors

  1. Icon: the project's own logo (from its repo or website), as a PNG about 128 pixels. Background: its wide logo or art, as a JPEG about 960 pixels wide.
  2. Never use a screenshot of the program as the background. No fitting art? Leave backgroundArt out.
  3. Never a company's logo (NVIDIA, AMD...) on someone else's project.
  4. No logo? Leave icon out. Keep the project's github (it opens the project page): when its owner has no picture, GPU Selector draws a name icon in the card's color. Leave github out only when the project has no repo.
  5. Colors come from the project's logo. Tabs, step numbers and the hover border use its main color. The button uses a darker shade, so its white text is easy to read.
  6. Not sure? Use "autoColor": true.
  7. Keep the whole card file small (under 1 MB is plenty).

Credits

  1. author (and each tab's author) is who made the project. Never yourself.
  2. cardBy and cardByUrl are you, the card maker. They show as "Card by" at the bottom right.
  3. A tab's github is the project that tab installs. Never another person's repo.

Games

  1. Each game twice in targetGames: its Steam ID ("match": "id") and its exact name (other stores).
  2. hdr: true for HDR mods. reshade locks only when you know the game's API.
  3. Leave out games the mod can't be used in safely (online-only games with anti-cheat), and say why in the notes.

Locked Cards (a key for your supporters)

Lock a card's download so only people with your key can install it, like your Patreon supporters or testers. You lock the file. GPU Selector only asks for the key.

How it works

  1. You lock your mod in a .7z file with a password (7-Zip, AES-256).
  2. You put the locked file online, anywhere: a GitHub release, your own site.
  3. Your card says the download is locked. It never holds the key.
  4. You give the key to your people however you like: a Patreon post, Discord, email.
  5. When someone downloads, GPU Selector asks for the key. It is used once to unpack the file, then forgotten. It is never saved, sent anywhere, or written in the log.

The base key in the JSON

Card typeFieldWhat it does
A card with versions"password": "login"Asks for a username and a password. The file's real password is username:password (like shrimp:shrimp).
"password": "ask"Asks for one password.
"passwordHelp"One line in the unlock box, like "Get your key on my Patreon."
A card with downloads"locked": "login" or "password"The same, for that download.
"lockHelp"One line in the unlock box.
"versions": [
  {
    "version": "1.0",
    "url": "https://example.com/ExampleMod.7z",
    "filename": "ExampleMod.7z",
    "password": "login",
    "passwordHelp": "Get your username and password on my Patreon."
  }
]

Create the locked file

With 7-Zip (free, 7-zip.org):

  1. Right-click your mod's files, pick 7-Zip, then Add to archive...
  2. Archive format: 7z.
  3. Enter password: your key. For "login" type username:password, like shrimp:shrimp.
  4. Encryption method: AES-256.
  5. Tick Encrypt file names, so nobody can even see what is inside.
  6. Press OK. Upload the .7z and put its link in your card.

Or on the command line: 7z a -t7z -mhe=on -p"shrimp:shrimp" ExampleMod.7z ExampleMod.fx

Keys can't have quotes in them. A new key means a new locked file: make one, upload it, and give out the new key.

What a key can and can't do
  1. Everyone with the key can unpack the file, and people can share keys. For one key per person you need your own server: the guide's example cards repository shows ideas.
  2. Anyone can read your card. Never write the real key in it.
  3. The lock is the file's own encryption. Without the key the file can't be opened, wherever it is hosted.
  4. Some sites refuse locked files: Nexus Mods quarantines password-protected archives. Use a GitHub release or your own site.

Example: the Locked Card Example in GPU Selector's example cards (cards/testing/locked-card-example). Its prize is Shrimp Vision, a small ReShade shader. Username shrimp, password shrimp.

Card Sites (log in to your own site)

Have your own website for your mods? A card can log in to it, show the files that user may get, and install them. You host the site. GPU Selector hosts nothing.

What the user sees

  1. A box with your site's name, a username, a password and Log In.
  2. After logging in: your files, each with its title, version, size, a short line and Download.
  3. Download gets the file, checks its SHA256, Windows Security scans it, and your card's installActions put it in place.
  4. Refresh asks your site again. Log Out forgets the login.

In the card

"site": {
  "url": "https://mymods.example",
  "name": "My Mods",
  "help": "Supporters: use your Patreon email and the password I sent you."
},

"installActions": [
  {"type": "copy", "from": "MyShader.fx", "to": "{reshadeShaders}/MyShader.fx"}
]
FieldWhat it is
urlYour site. HTTPS only. For testing on your own PC, http://127.0.0.1:port or http://localhost:port works too.
nameIts name in the box (up to 60). Default: the site's address.
helpOne line under the login, like where people get an account (up to 200).

What your site must answer

Three addresses under your url. All answers are JSON, except the file itself.

RequestYour answer
POST /gpuselector/login
body: {"username": "...", "password": "..."}
{"ok": true, "token": "...", "message": "Welcome back!"}
or {"ok": false, "message": "Wrong password."}
GET /gpuselector/files
header: Authorization: Bearer <token>
{"files": [{"id": "shrimp-vision", "title": "Shrimp Vision", "version": "1.0", "short": "A shrimp for your game.", "file": "ShrimpVision.zip", "size": 1234, "sha256": "..."}]}
401 when the token ran out.
GET /gpuselector/download/<id>
header: Authorization: Bearer <token>
The file itself (.zip or .7z). 401 when the token ran out.
  1. Each file needs an id (letters, numbers, - and _), a title, a file name ending in .zip or .7z, and its sha256. Up to 100 files.
  2. Show each user only the files they may get. The list is all GPU Selector shows.
  3. Make tokens run out (a few hours is fine). When one does, GPU Selector asks the user to log in again.
  4. No redirects: GPU Selector refuses them, so a token can never be sent to another site.

A free starting point: the example cards repository has a Cloudflare Worker template (source/site-login-template). You run it on your own Cloudflare account.

How GPU Selector keeps logins safe
  1. The username and password only go to your card's url, once, when the user presses Log In.
  2. Your site's token stays inside GPU Selector while it runs. It is never saved, never written in the log, and never sent anywhere but your site.
  3. GPU Selector builds every address from your url itself. Your site can't send it somewhere else.
  4. Your site's text is shown as plain text, never as a web page, so it can't run anything.
  5. Every file is checked against the SHA256 your site gives, and scanned, before anything is installed.

Collapsible Guides

Longer how-to steps can go in a guide: a closed "Setup Guide" row that opens into numbered step boxes, like the 3DConsoleBridge card. Use at most one per tab. Separate topics go in tabs (see Mode Switch), not in more guides.

"guides": [
  {
    "title": "Setup Guide",
    "when": {"setup": "nv"},
    "steps": [
      {"title": "Connect your hardware", "text": "Plug the capture card into a USB 3 port.\nTurn the console on."},
      {"title": "Play", "text": "Start a 3D game."}
    ]
  }
]
  1. Guides start closed, so they don't count toward the card's size. An open guide may make the card taller.
  2. One level only. A step is a title and plain text. It can't hold another guide.
  3. "position": "bottom" puts a guide at the very bottom of the card, below the buttons. Good for notes people only need sometimes.
  4. Limits: up to 3 guides show at once (12 in a card, using "when" per tab), 8 steps per guide, guide title 60 and step title 80 characters, step text 600 characters.
  5. "when" shows a guide only for some choices, like a mode.

Mode Switch (one card, several setups)

A card can have a mode switch: a row of tabs under its name, like the 3D | AR | SR switch on the 3DConsoleBridge card.

  1. Each mode can have its own description.
  2. Controls, downloads and add-ons can belong to one mode with "when".
  3. Up to 4 modes show at once. With more, a small arrow button shows the next 4.
  4. 2 to 12 modes are allowed.
  5. "position": "top" (on ui.modes) puts the switch in the top right, next to the folder button (like 3DConsoleBridge). Use it for short tab names. Without it, the switch gets its own row.
  6. Give modes a "gpu" and the switch starts on the one for the user's graphics card.
  7. Add-ons that only come from tabs with a "gpu" belong to that brand. They only load in games that run on it (the GPU the game is pinned to, or the primary GPU). Users can install every tab, and each game gets the right add-on.
  8. Two tabs of the same brand (like "NVIDIA" and "NVIDIA + DLSS"): both can be installed, and the user ticks per game which add-on it uses. Say in each tab which games it is for.
  9. Add-ons on the same tab are a team: ticking one ticks the add-ons it needs. "Needs" means: the other add-on is on every tab this one is on. Example: dlss5-feed is only on the NVIDIA tab, where renodx-dlss5 also is, so it needs renodx-dlss5. renodx-dlss5 is also on the NVIDIA + DLSS tab, without the Feeder, so it needs nothing. An add-on with its own "games" is never part of a team.
  10. Each tab can have a Remove button: it removes that tab's add-ons, but keeps one another installed tab still uses.
"ui": {
  "modes": {
    "id": "setup",
    "options": [
      {"value": "nvidia", "gpu": "nvidia", "label": "NV", "icon": "🟩", "title": "NVIDIA RTX", "color": "#76b900",
       "description": "Text shown on the card while this mode is picked."},
      {"value": "amd", "gpu": "amd", "label": "AMD", "title": "AMD Radeon", "color": "#ed1c24",
       "description": "Another description."}
    ]
  }
}
FieldDescription
idThe name "when" uses to read the picked mode
valueRequired. What "when" compares against
label, iconWhat the button shows (short!)
titleTooltip
colorColor of the button while picked
descriptionReplaces the card's description while picked
authorWho made this mode's project. Replaces the card's "by" name while picked
headingReplaces the card's shown name while picked (max 60 characters). The card's real name stays its ID
taglineReplaces the card's tag line while picked (max 100 characters)
github"owner/repo" of the project the tab installs (leave it out when the project has no repo of its own: the card then draws a name icon; never use another person's repo). While picked, the card's link opens that project and the main icon is its owner's GitHub picture (and with autoColor, the card's colors too)
imageA PNG or JPG (https or data:image) shown as the card's main icon while picked
gpu"nvidia", "amd" or "intel" (or a list). The switch starts on the first mode that fits the PC's primary GPU

"when": show or use something only for some choices

Put "when" on a dropdown, radio group, checkbox, text input, download or add-on.

  1. Keys are control ids (or the mode id).
  2. Values are what must be picked. A list means "any of these".
  3. Checkboxes use true or false.
  4. Every key must match.
  5. It works on target games, downloads, add-ons, shader repos, launch, guides and controls. So each tab can have its own games and its own install button (or none).
"when": {"setup": "nvidia"}
"when": {"setup": ["nvidia", "nvidia-dlss"], "extras": true}
  1. "when" reads the card's choices only. It never reads the PC's real graphics card (that is the mode's "gpu" field).
  2. Choices are read when the user presses Install. Dropdowns and radio groups start on their "default", else their first option.
  3. Install gets only the downloads and add-ons of the tab picked now. To get another tab, pick it and press Install again. Add-ons from earlier tabs stay.
  4. Target games, ReShade locks and hdr still work when the user installs from another tab of the card.

Add-on Packages from GitHub

A card can download files from GitHub and add ReShade add-ons to GPU Selector. The card's button then says Install Add-ons.

  1. GPU Selector downloads every file the card lists.
  2. It checks each file with the SHA256 GitHub lists for it.
  3. Windows Security scans each file up to 50 MB. Bigger files are not scanned, but are still checked with their SHA256.
  4. Zip and 7z files are unpacked.
  5. The add-ons go into the user's add-on list (Manage Add-ons).
  6. The user picks the games: the card's own games, all games, or games they pick.
  7. The add-ons only run in those games, through ReShade Inject Mode.
The rules GPU Selector follows:
  1. Nothing is copied into a game folder for good. Add-ons are copied for each launch and removed after.
  2. A file Windows Security flags stops the whole install. GPU Selector never asks for exclusions or works around Windows Security.
  3. A file with no SHA256 is only downloaded after the user agrees.
  4. A card can't replace an add-on it did not install, or one of GPU Selector's own.
  5. Downloads must use https. Only download from where the project's author publishes the files (their GitHub releases, or a host their own installer uses). Never mirrors or re-uploads.
  6. Links that redirect are followed.

"downloads"

Up to 10. Each has an "id". Files of a download are unpacked into a folder with that id.

"downloads": [
  {"id": "feeder", "github": "owner/repo", "asset": "MyAddon-*.zip"},
  {"id": "loose", "github": "owner/other-repo", "asset": ["*.addon64", "*.addon32", "*.fx"]},
  {"id": "runtime", "url": "https://github.com/owner/repo/releases/download/v1.0/runtime.zip"},
  {"id": "pinned", "github": "owner/repo", "tag": "v2.1.0", "asset": "*.zip", "when": {"setup": "nvidia"}}
]
FieldDescription
idRequired. Letters, numbers, - and _. Can't start with repo_
githubowner/repo. Uses its newest release (test versions and drafts are skipped), or tag. Best choice: GitHub lists a SHA256 for each file, and the card can tell the user about updates
assetFile name pattern, or a list of them. * = anything. Default *.zip. A pattern that matches no file stops the install with an error
tagPin one release instead of the newest. Use it for repos that hold several products (like RankFTW/rhi-repo: dlss-, dlssnr-, renodx-dlss5- releases), so "newest" is not another product's release. A tag can also pin a test version (like RenoDX's snapshot, which "newest" skips)
urlA fixed https link instead of github. GitHub release links (github.com/owner/repo/releases/download/...) still get GitHub's SHA256. Other links (github.io pages, raw files, other hosts) need sha256, or the user must agree to each file. The file keeps the last part of the link as its name (.../dlssnr_amd_pass1.dll stays dlssnr_amd_pass1.dll), so "from": "<id>/dlssnr_amd_pass1.dll" finds it
sha256Optional. The file's SHA256, for links GitHub lists none for
whenOptional. Only for some choices

A download can be locked too: "locked": "login" (or "password"), with "lockHelp" for the line in the unlock box. See Locked Cards.

"addons"

Up to 10. Paths are "<download id>/<pattern>".

  1. A pattern with no / matches a file name anywhere in that download.
  2. A pattern with / matches the path inside the download.
  3. Upper and lower case don't matter.
"addons": [
  {
    "name": "MyAddon",
    "from": "feeder/myaddon.addon*",
    "shaders": ["feeder/*.fx", {"from": "feeder/shaders/include/*.fxh", "to": "include"}],
    "besideAddon": ["runtime/helper.dll"],
    "nextToGame": [],
    "when": {"setup": "nvidia"}
  }
]
FieldWhere the files go
nameThe add-on's name in GPU Selector. Letters, numbers, - and _. Use the add-on's own file name without the extension (renodx-dlss5, dlss5-feed): in each launch the file is named <name>.addon64, and some add-ons find each other by file name. The same add-on on two tabs: same name, same files
fromThe add-on: .addon64, .addon32 or .addon (both kept). Only list .addon32 when it works alone in 32-bit games. Add-ons that need a 64-bit helper program for 32-bit games: list only .addon64, and say on the card that 32-bit games are not covered
shadersShaders and textures. Copied to the launch's add-on shader folder, which ReShade searches
besideAddonFiles that must sit next to the add-on (for example a DLL it loads from its own folder). Copied for each launch
nextToGameFiles that must sit next to the game's exe. Put there for that launch only. A game file with the same name is renamed to .gpusel_off and put back when the game closes

Each list takes plain patterns, or {"from": ..., "to": "subfolder"} to keep a subfolder. Max 40 files per list.

besideAddon or nextToGame? Read this before you follow a project's install guide.
  1. Most install guides say "put everything next to the game's exe". They assume the add-on sits there too.
  2. In GPU Selector the add-on sits in a launch folder, not next to the game.
  3. Files the add-on opens from its own folder: besideAddon. Example: DLSS5-Feeder starts NVIDIA NGX with its own folder, so it needs nvngx_dlss.dll and nvngx_dlssnr.dll beside it.
  4. Files the game, the graphics driver, or the add-on load from the game's exe folder: nextToGame. Example: RenoDX DLSS5 loads nvngx_dlssnr.dll from the game folder, and the AMD neural add-on its runtime and weights.
  5. Not sure? Put the file in both lists. That is safe: it is the same file, and both copies are removed after the launch.
  6. Depth: GPU Selector always loads a depth add-on (Generic Depth or Generic Depth Mod). An add-on that needs ReShade's depth gets it without anything on the card.
  7. Unreal games: GPU Selector finds the exe that really runs (Binaries\Win64\*-Shipping.exe) and puts the files there.

One add-on per game: "games"

An add-on made for one game (like an HDR mod) can name its games, in the same format as targetGames:

{"name": "RenoDXCyberpunk", "from": "renodx/renodx-cp2077.addon64",
 "games": [{"match": "id", "name": "steam_1091500"}, {"match": "contains", "name": "Cyberpunk 2077"}]}

When the user picks Its Games after installing, each add-on is turned on only for its own games. Games I Pick then lists only these games, each with its add-on.

List the same games in targetGames too. That list is what shows on the card, with each game's notes, hdr and ReShade locks. An add-on's games only decide where it is turned on.

Tip: Use nextToGame only when the add-on really needs it. besideAddon keeps game folders untouched.

What a card can't do yet

Some mods need things a card can't express. Don't work around these. Write the card for the parts it can do, and say the rest clearly.

The mod needsWhat the card does instead
A DLL next to the game that is not a ReShade add-on (a "proxy" like version.dll, winmm.dll or dxgi.dll), or a file renamed to such a nameNot possible yet: a card only puts files next to the game as part of a ReShade add-on (nextToGame), with their own names. Leave that version out of the card, or make it a tab with only text: give the tab the project's github, so the card's link opens its page. Never tell users to copy files into the game folder by hand.
A DLL loaded into the game next to ReShade that is not a ReShade add-onNot possible yet. Build it as a ReShade add-on if you can (see "Research first"). If not, tell the person it is missing.
A button on each game that runs a program for that game (with the game's ID or exe)Not possible yet: launch has fixed start options. Explain the steps in the program itself, or in the card's text.
More than one program button, or running something before PlayNot possible yet: one launch per card. Pick the most useful one.
A download with no add-on and no launchNot possible: Install stops with "Nothing matched". Every install needs an add-on or a program.
A value in another program's .ini, or a ReShade.ini setting (like early add-on loading)Not possible: only effect values in the preset (preprocessor). Write the setting as a step or a game note.
A GPU series (RTX 20/30 vs RTX 40, RDNA3 vs RDNA4)gpu only knows the brand. Make one tab per series, put the series in the tab label, and start the description with "Needs an RTX 40 card."
A Windows setting or driver version (HAGS, a minimum driver)A numbered step: "Turn on Hardware-accelerated GPU scheduling in Windows Settings > Display > Graphics."
A game launch option (like +r_allowBlackListedLayers 1)That game's notes.
"Only one of these mods per game"Say it in notice and in the tab text. GPU Selector can't block other mods.
A file in another folder of the game (not next to the exe), or a nextToGame file the user can chooseNot possible: nextToGame files always go next to the exe that runs. Write it as a step or a game note.
A project with no release files (only files in the repo)A url to the raw file pinned to one commit (raw.githubusercontent.com/owner/repo/<commit>/file) with its sha256. It gets no update notices.

Notes on a game that is on several tabs: the card shows the notes of the open tab's entries.

"launch": a program the card downloads

For a tool or app (not an add-on), download it and give the card a Launch button:

"downloads": [{"id": "app", "github": "owner/repo", "asset": "MyTool.exe"}],
"launch": {"from": "app/MyTool.exe", "label": "Launch My Tool"}
  1. The button says Download, then Get Latest. A Launch button shows once it is downloaded.
  2. The program is checked and scanned like every download, and kept in the card's own folder.
  3. The first Launch each time GPU Selector runs asks the user first.
  4. A card can have launch and addons together, or only launch.
  5. Start options: "launch": {"from": "app/MyTool.exe", "args": ["--game", "quake"]}. Plain words only.
  6. from starts with a download's id: a card only launches a file from its own downloads. A helper you made yourself must be in a GitHub release first.
  7. One launch per card. Give it "when" to show it only on some tabs.
  8. "app/MyTool.exe" finds that name in any folder of the download. More than one? The one nearest the top wins. "app/bin/MyTool.exe" finds only that path.
  9. Zips keep their folders. Look inside the zip and read the app's docs, so the Launch button starts the right file (not a helper or a command-line tool that closes at once).
  10. Once it is downloaded, an Uninstall button shows next to Launch. It moves the card's download to the Recycle Bin, and the card shows Download again. Rename it with ui.labels.uninstall.
  11. A card package installs ReShade add-ons (.addon32 / .addon64) and programs with launch. Other mod files (like a game's .pak files) use a catalog card, or installActions.

"requires": the ReShade a card needs

"requires": {"reshade": "6.8.0"}
  1. Every card with add-ons needs ReShade with add-on support. GPU Selector checks that by itself.
  2. "reshade" also asks for that version or newer. Write it as three numbers, like "6.8.0". Use the version the project's install guide asks for.
  3. GPU Selector reads the ReShade card's version and build. When they don't fit, the card shows a warning and says what to change. The install dialog says it too.

Games with a ReShade preset: "match": "preset"

A shader card can list every game that has a ReShade preset, and help it get the shaders the preset needs:

"targetGames": [{"match": "preset"}],
"shaderRepos": ["CeeJayDK/SweetFX", "prod80/prod80-ReShade-Repository"]
  1. GPU Selector looks in each game's folder for presets: the one the game's ReShade.ini points to (PresetPath), and any other .ini that is a preset, whatever its name. A file is a preset when its top part has a Techniques= line.
  2. It reads which effect files (.fx) the preset turns on, and which of them no shader folder has (GPU Selector's, or the game's own reshade-shaders).
  3. The game's row shows Preset: name.ini (3 missing). Pressing it lists the missing effects, and which of the card's shaderRepos hold them.
  4. Install missing packs installs only those packs. Effects no pack holds are listed as "not in this card's packs".
  5. The card never downloads anything it has no link for. To cover more presets, add the shader packs' GitHub repos to shaderRepos (only packs whose authors allow it).

"shaderRepos": shaders from Shader Repositories

Need a shader pack? Don't download it yourself. List its GitHub repository (or a Shader Repositories key):

"shaderRepos": [
  "owner/some-shader-repo",
  {"repo": "owner/other-shader-repo", "when": {"setup": "nv"}}
]
  1. It installs exactly like pressing Install on that repo in Shader Repositories.
  2. Only list shaders whose authors allow it. Some ask that their shaders are not shared or linked by other tools.
  3. A GitHub repo that isn't in the list yet is added there first.
  4. The user can update or remove it there later, like any other shader repo.
  5. A card can have only shaderRepos, with no downloads.
  6. A full link works too: "https://github.com/owner/repo". The card shows each pack's result.

"repoShaders": only the shaders an add-on needs

Does your add-on need one effect from a built-in shader repo? Put this on the add-on instead of shaderRepos:

"repoShaders": {"repo": "lumenitefx", "files": ["lumenite_Kernel.fx"]}
  1. Only the listed effects come with the add-on, plus the headers and textures they use.
  2. They only load in games where the add-on is on.
  3. If the user installed the full repo from its own card, their copy is used, with all its effects.
  4. Built-in repos only, for now: lumenitefx. GPU Selector downloads it from its own link.
  5. One object per add-on. Two add-ons (or two cards) can ask for the same effect: it is shared.
  6. ReShade.fxh and ReShadeUI.fxh are always there. Don't ship them.

"preprocessor": shader settings the add-on needs

Does an effect need a preprocessor value set for your add-on? Put it on the add-on:

"preprocessor": {
  "lumenite_Kernel.fx": {"IMAGE_SPACE": "1"},
  "AMD_Neural_Feed.fx": {"AMDNR_MV_PROVIDER": "3"}
}
  1. At launch, GPU Selector writes them into that game's ReShade preset.
  2. Only in games where the add-on is on.
  3. Only when the value is not set yet. A value the user set stays.
  4. Plain names and values only (letters, numbers, _ . + -). Up to 10 effects, 10 values each.
  5. Find the values in the project's install guide. The example is the Neural Rendering card: AMDNR_MV_PROVIDER 3 means "LumeniteFX Kernel gives the motion", and Kernel's IMAGE_SPACE=1 makes it work from the color picture, with no depth needed. The card sets IMAGE_SPACE=1 on both the NVIDIA (DLSS5-Feeder) and the AMD tab: tested in games, it is needed on both.
  6. Say on the card that GPU Selector sets them "if they are not set yet".
  7. GPU Selector can't turn effects on or set their order. Write the order as numbered steps on the card.

What the user sees

  1. A warning that lists every download and where files go.
  2. Progress while it downloads, checks and unpacks.
  3. A question: which games should use the add-ons.
  4. The card then shows what is installed. The button changes to Reinstall Add-ons (gets the newest releases).
  5. A card with no target games: Games I Pick opens Manage Add-on Games.
  6. About every 12 hours the card checks GitHub. It says when a file it installed was rebuilt (same release, new file) or when a newer release of the same product exists.

Built-in protection

GPU Selector applies these to every card. A card can't turn them off.

  1. Every download is scanned by Windows Security, then its fingerprint (never the file) is checked against two known-malware lists (CIRCL hashlookup and Team Cymru). A file on a list is not installed.
  2. Check Updates: once every 5 minutes per card.
  3. A card update shows its new download links and add-ons before it replaces the card. A card can't change its name in an update.
  4. Install: one card at a time, and a 30 second rest after each install.
  5. One download: 2 GB at most. Unpacked: 8 GB and 20,000 files at most.
  6. A card file: 2 MB at most (pictures included). 40 custom cards at most.
  7. Text: name 60, description 1500, mode label 24 characters at most.
  8. GitHub allows 60 lookups an hour without an account. When they run out, the card says so.
  9. Card names: 1 to 60 characters, with a letter or number, and none of < > " ' ` \ &. A name can't collide with another card or a built-in one.
  10. Colors must be color codes like #10b981. Links and pictures must be clean https links or PNG/JPG data pictures.
  11. Lists: up to 20 dropdown options, 10 radio options, 20 versions, 25 target games. Labels and placeholders have length limits too.
  12. nextToGame can't hold programs: .exe .bat .cmd .com .scr .ps1 .vbs .js .msi .lnk .pif .hta .reg, or ReShade's own ReShade.ini and ReShadePreset.ini. DLLs are allowed. The install dialog names every file that goes next to the game and every program file.
  13. Add-on names GPU Selector keeps for its own add-ons: anything with gamebridge, srreshade, xinp, genericdepth, generic_depth, depth3dcursor or sd3dcursor in it.
  14. detection.configFiles may only read files inside the folder it detected.
  15. A card that breaks these rules is not shown, even if it was added before the rules existed.
  16. Every card update is confirmed and lists what changes, including new links, different files, a missing SHA256 or an older release.

Catalog Cards (a list of mods for any game)

A catalog card lists mods for a game. People install, mix and play them one by one. The DOOM card is the big example. Copy the parts you need.

  1. Add a "catalog" object to the card.
  2. Pick the engine:
    • "engine": "doom" (the default): DOOM-engine games. GPU Selector knows DOOM's game files (WADs), its ports and idgames.
    • "engine": "generic": any other game. You tell GPU Selector which game files to find, which file types are mods, and how to start the port (see Any game).
  3. The card gets these pages: Your Games, Engine Games, Mods and Options.
  4. Show them in the card's tab switch with ui.modes: values games, engine, mods, options, and "position": "top". Leave out a page you don't need.
  5. No ui.modes? The catalog draws its own tab row. Pick its tabs, order and names with "tabs": [{"id": "mods", "label": "Mods"}, {"id": "games"}], and where it sits with "tabsAlign": left, center or right (default).
  6. Hide a tab only if your card doesn't need it:
    • games has Look Again and Pick a File. Without it, people can't fix "Needs ..." on a mod.
    • options has 3D Settings and Reset 3D. Without it, the 3D button still works, with your stereo values.
  7. Number the tabs in setup order, like "1. Your Games". The card opens on the first one.
  8. Options has these sub cards, in this order (change it with "optionsOrder": ["ports", "stereo", "yours", "look"]):
    • 3D Settings (hide it with "options": {"stereo": false}; the colours of "3D" with "stereoTitleColors": ["#ef4444", "#3b82f6"], or false for plain text)
    • Your WADs and Add-ons: people add their own files or folders, and their own add-ons for the Mix view (the add-ons part only when Mix is on; the name follows the engine)
    • Source Ports
    • Parental, Theme and Font: Parental Settings (only when an item has "adult": true), and the theme and font (only when the card has ui.appTheme or ui.font)
  9. The card stays within 625 pixels. A long page or open sub card grows to that size, then scrolls inside itself.
  10. GPU Selector finds the game files, downloads the mods and builds the command line. The card only lists things.
  11. Ports come from the Modding Codex, or the user installs one ("own": true). The Codex shows "Used by" with your card's name.
  12. Play adds the mod to the Games list, so GPU Selector's settings work for it (GPU, Inject Mode, SuperDepth3D).
  13. A port with "stereo": true (GZDoom family) gets a 3D button on each mod: the 3D mode, Depth and ZPD come from 3D Settings.

The catalog fields

FieldWhat it is
engine"doom" (default) or "generic".
itemsThe mods (up to 500). See One mod.
categoriesThe chips on the Mods page: [{"id":"tc","name":"Total Conversions"}] (up to 24). A chip with no items is hidden.
portsThe programs that run the mods (up to 32). See Ports.
gameDataThe base games mods need (up to 20):
  1. {"id":"doom2","title":"DOOM II","file":"DOOM2.WAD","steam":2280}
  2. file is the name shown to the user. steam is its Steam app id.
  3. For "engine": "generic", add "files" (see Any game).
  4. "group": games that can stand in for each other (like the DOOM games). A game in another group is never offered for a mod.
freeDataA free stand-in that installs like a mod (Freedoom):
  1. {"id","title","download","replaces"}
  2. replaces maps each base game to the free file: {"doom2":"freedoom2","doom":"freedoom1"}.
  3. The button says: Get <title> (free).
steamGamesGames for the Your Games and Engine Games pages (up to 300):
  1. {"appid","name","group","engine"}. Add "stereo": true for a game that can start in 3D.
  2. "fixFrom": "uzdoom": the game can use that port's "adds" fix too (like the 3D crosshair dinput8.dll).
    • Before the first 3D Play, the user is asked once for that game. Nothing is added without a yes.
    • The file goes next to the game's own program. A file with that name that is not the card's is left alone.
    • The row then gets a trash button that takes it out again.
  3. "stereoSoon": "note" (or true): its 3D is not ready yet. The row shows "3D coming soon" with your note on hover, and no 3D button.
  4. You pick how each game turns 3D on:
    • Nothing more: a game made with GZDoom (GZDoom's own 3D, started in OpenGL).
    • "stereoPort": "lzdoom": the 3D of one of your ports (a ZDoom-family port, or a custom port with stereoArgs).
    • "stereoArgs", "stereoOffArgs", "stereoModes": the game's own 3D options, written like a custom port's (see Any game).
    • "stereoExtraArgs": the words added with GZDoom 3D instead of the OpenGL switch ([] for none).
    • "stereoOffOnce": false sends stereoOffArgs on every launch with 3D off (default: once, after 3D was on).
  5. GPU Selector checks the user's Steam library on this PC. Nothing goes online.
  6. "delisted": true shows a game only to people who own it.
steamGroupsThe headings for steamGames (up to 6): {"id","name","note"}. Group engine goes on the Engine Games page. Group family gets its own switch on Your Games. Pick the page yourself with "tab": games, engine or family. Add "wip": "note" (or true) for a small WIP tag in the middle of the card's footer while that page is open, with the note on hover.
codexGames, codexGamesTitleFree games from the Modding Codex for the Engine Games page (up to 20): {"codex","name","engine","short","page"}. Add "args" (plain words) for its start options, and "stereo": true with "stereoPort" or "stereoArgs" for 3D, like steamGames.
mixesPreferred Mixes (up to 30). See Mixing mods.
addonSetsAdd-on Sets (up to 20): ready-made add-on bundles for any game, total conversions too. Each: {"id", "name", "note", "picks": [add-on ids]}. Picking a set ticks the add-ons that fit the game in the Mix.
mixHow Mix works on your card (only your card):
  1. "enabled": false: no Mix on this card (no M, no Mix button).
  2. "perGame": false: one shared mix, not one per game.
  3. "categories": ["maps","official"]: only rows in these categories can be a mix's game.
  4. "label": "Loadout": the button's name (up to 20 characters).
optionsHide an Options sub card on your card: {"stereo": false}. Keys: stereo (3D Settings), yours (Your WADs or Your Files), addons (Your Add-ons), ports, look (Theme and Font). Parental Settings always shows when a mod has "adult": true.
optionsOrderThe order of the Options sub cards: ["ports", "stereo", "yours", "look"]. Ones you leave out come after, in the usual order.
tabsYour catalog's own tab row (only without ui.modes): [{"id": "mods", "label": "Mods"}, {"id": "games"}]. Ids: games, engine, mods, options. The first one opens first. A tab without a label gets its number and usual name.
colorsColours inside your catalog, each like "#10b981". Keys: chipOff, chipOffText, chipOnText (chips and tabs), secondaryButton (the grey buttons), installed (the dot and "Installed"), busy, error, uses, needs (default: your accent), mixOn, mixHalf, mixOff (the M), stereo3, stereoD, stereoOff (the 3D button).
listHeightsHow tall the lists are before they scroll, in rem (6 to 40): {"mods": 16, "mix": 15, "games": 13, "idgames": 8} (these are the defaults).
searchBar{"position": "belowChips"} (default) or "aboveChips"; "mixToggle": "right" (default) or "left"; "showCount": false hides "320 mods".
chipsOrderThese chips first, in this order: ["preferred", "installed"]. Chip ids: installed, preferred, favorite, cult, yours, and your categories ids.
chipsHiddenThese chips don't show: ["cult"].
portsShowAlltrue: each mod's port list shows every port of your card. Ports that don't run that mod are greyed out and can't be picked. Default: only the mod's own ports.
yoursLayoutHow Your WADs and Your Add-ons sit together: auto (default: side by side when there is room, else stacked), side or stack.
yoursDividerfalse takes away the line between them. Default: true.
tabsAlignWhere that tab row sits: left, center or right (default).
stereoTitleColorsThe colours of "3D" in 3D Settings: ["#ef4444", "#3b82f6"], or false for plain text. Not used when you rename it with text.stereoHeading.
gameSuffixThe name after a played mod in the Games list, like Eviternity (DOOM).
textChange the page's words. See Any game.
search"idgames" (the DOOM mod archive) or "none". Default: "idgames" on DOOM cards, "none" on other cards.
searchLinksOther sites to search when a mod is not in your list (up to 4): [{"name": "Nexus Mods", "url": "https://www.nexusmods.com/games/quake/mods?keyword={query}"}]. A button opens that search in the browser.
yourFilesPortsThe ports that play the user's own files: ["mygame-port"]. Default: UZDoom, GZDoom and DSDA on DOOM cards, every port on other cards.
idgamesMirrors, idgamesCategory, idgamesPortsFor the idgames search: the mirrors to try, and the category and ports a found mod gets.
stereoYour 3D Settings (only your card):
  1. "modes": ["sbs","tab"]: the 3D modes to offer (sbs, sbs-full, tab, interlaced, anaglyph).
  2. "depth": 25, "zpd": 0.025: the starting values.
  3. "fov": 90, "fovMin": 60, "fovMax": 130: the FOV bar.
  4. "crosshair": false hides "Hide crosshair". "fovOption": false hides "Set FOV".
  5. "extraModes": [{"id": "checker", "name": "Checkerboard"}]: your own 3D modes, for custom ports (give each a word in their stereoModes).
addonGroupsYour add-on groups in the Mix view, by addonSlot: [{"upTo": 20, "name": "Textures", "beforeBase": true}, {"upTo": 101, "name": "Extras"}]. beforeBase: that group loads before the game. Default: Textures, Fonts and Sprites, HUD, Lights, Weather, Music.

Ports

  1. A port: {"id","name","codex","family"}. codex is the Codex entry's exact name.
  2. family tells GPU Selector how to start it:
    • zdoom (UZDoom, GZDoom, LZDoom), zdoomrt, prboom, mbf, chocolate, helion, doom64, doomsday
    • plain: only -iwad and -file
    • custom: any program. You list its options in args (see Any game).
  3. "stereo": true: the port has its own 3D. It works for the zdoom and doomsday families (GPU Selector knows how to turn it on), and for a custom port with stereoArgs.
  4. A custom port with 3D: "stereo": true plus "stereoArgs", groups like args with {mode}, {depth} (0-100), {zpd} (0.000-0.250), {swap} (1 or 0), {fov} and {crosshair} (0 to hide it in 3D, 1 to give it back once).
    • "stereoModes": {"sbs": "4", "tab": "11"}: your port's word for each 3D mode ({mode}).
    • "stereoOffArgs": what to send when 3D is off.
    • Without stereoArgs a custom port gets no 3D button.
  5. "label": the exact text in the dropdown (see ports in One mod).
  6. "extraArgs": the words always added for this port, instead of its family's. The ZDoom family adds +vid_preferbackend 0 +queryiwad 0 (OpenGL, no game picker); "extraArgs": ["+queryiwad", "0"] keeps Vulkan. [] adds nothing.
  7. "note": a few words after its name, like "best for 3D".
  8. "exe": when one download has a program per game, the one to start (like "inter-hexen.exe").
  9. A port the Codex can't download:
    • "own": true and "page" (HTTPS) instead of codex. The user installs it and picks its program once.
    • Give it a "download" (like a mod's, with sha256) and the card can install it. "exe" is then the program's name inside.
  10. "fix": a file the card brings for its own port or a Modding Codex port (checked by SHA256 both ways), like the DOOM card's 3D fix for Doomsday:
    • {"file","sha256","replaces","original","keepOriginalAs"}
    • Put the file in the card's files folder (see Card packages).
    • GPU Selector checks the SHA256, Windows Security scans it, and the user is asked once before it is used.
    • It only replaces the exact original file (its SHA256) in the card's own copy of the port. That file is kept as keepOriginalAs.
    • Or add a new file next to the port's program: {"file","sha256","adds"} (like the DOOM card's 3D crosshair, dinput8.dll).
      • A file with that name that is already there is left alone, unless it is an older version: list their SHA256s in "oldVersions".
  11. 3D sound: cards with a zdoom or doomsday port get a 3D sound switch in 3D Settings by themselves. It turns on the port's own 3D sound for headphones (OpenAL with HRTF in the ZDoom family, sound-3d in Doomsday). Turning it off gives the port its own setting back.
  12. "crosshairDot": true: the port's fix brings the 3D crosshair (laser dot). 3D Settings then offers the laser dot, mini circle, cross, and the game's own crosshair at depth, with Color, Dot Size and Dot Hover.
  13. "mix": true (custom ports only): the port can load several mods, so it can play a mix.

Any game: "engine": "generic"

  1. Set "engine": "generic" in the catalog.
  2. Game files: give each gameData entry "files" (up to 10):
    • "files": [{"name":"duke3d.grp","minSize":10000000}]
    • name is the file name. minSize, maxSize (bytes) and sha256 are optional checks.
  3. Where to look: "steamFolders": ["Duke Nukem 3D Twentieth Anniversary World Tour"] (folder names in steamapps\common). GOG games and the folders the user picks are searched too.
  4. More places: "gameFolders": [{"env": "QUAKEDIR"}, {"registry": "HKLM\\SOFTWARE\\Vendor\\Game", "value": "InstallPath"}, {"known": "Documents", "sub": "My Games\\Game"}]. known: Documents, SavedGames, ProgramFiles, ProgramFilesX86, LocalAppData, AppData, always with a sub folder. GPU Selector only reads these folders.
  5. Mod files: "fileTypes": [".grp", ".zip", ".map"]. Program types (like .exe and .dll) are never mod files.
  6. The port: "family": "custom" with "args", plus "codex" (a Modding Codex entry) or "own": true and "page" (the user installs it). "args" is a list of groups:
    • "args": [["-iwad","{game}"], ["-file","{files}"], ["-savedir","{saves}"]]
    • {game} = the game file. {gamedir} = its folder. {files} = the mods, in load order. {saves} = a save folder for each mod. {portdir} = the port's own folder.
    • {file} = one mod file: its whole group repeats for each file, like ["-g","{file}"] gives -g a.grp -g b.grp.
    • {moddir} = the mod's own folder, {modname} = its folder name. For mods that are folders, like Quake's ["-game","{modname}"].
    • A group is left out when its placeholder is empty (no mods: no -file).
    • Other words must be plain: letters, numbers and - + _ . / : = ,. GPU Selector adds the quotes.
  7. The words on the pages: "text": {"yourFiles": "Your Mods"}. Keys you can set: yourFiles, filesWord, yourFilesInfo, addFilesTip, addFolderTip, looking, noneFound, gameFilesInfo, pickFileTip, pickFileExample, anyGame, fovNote, officialToggle, officialTip, familyToggle, familyTip, officialHeading, engineHeading, codexGames, engineFreeTip, engineStoreTip, modsUsually, gameName, zpdHelp, chipInstalled, chipPreferred, chipFavorite, chipCult, searchHint, modWord, modsWord, gameFilesHeading, gameFilesWhere, portsHeading, portsInfo, mixGameHelp, addonsHelp, mixTcNote, mixWarnNote, yourAddonsInfo, yourFileAuthor, yourFolderAuthor, and the Options headings: stereoHeading, yoursHeading, yourAddonsHeading, addonsWord, inCodex, lookHeading, parentalHeading, themeHeading, fontHeading. Words on the mod rows and buttons: uses, needs, soldOnSteam, noGameFiles, comingSoon, installOnSteam, steamStore, playsInMix, btnInstall, btnPlay, btnInstallPlay, btnDownload, btnInstallDownload, btnGetIt. Mix: preferredMixes, backToMods, playMix (default: "Play" and your Mix name), change, clear, noAddons, noAddonsTc, mixMark (the M: 1 or 2 characters). Your Games, Steam and ports: noneYet, lookAgain, pickFile, getFree ({title} is the free game's name), installedWord, inLibrary, store, free, ready, failed, has3d, no3d. 3D Settings: depthLabel, depthHelp, zpdLabel, fovLabel, reset3d, swapEyes. Up to 300 characters each.
  8. A generic card has no idgames search (it is for DOOM). Leave search out, or set it to "none".
  9. Colours: set ui.hoverBorderColor (the accent) and ui.buttonColor. Without them, DOOM cards are red and other cards are green.
  10. Test it: load the card, press Look Again on Your Games, and play a mod.

One mod (an item)

FieldWhat it is
idLetters, numbers, - and _ (up to 40). It is also the mod's folder name.
title, author, year, shortWhat the row shows. Title up to 100, author up to 80, short up to 200 characters.
categoryOne of the categories ids.
needsThe base game it needs (a gameData id), "standalone" when it brings its own, or "any". Default: doom2 (DOOM cards) or the first gameData (generic cards).
iwadFileFor standalone mods: its own game file, like boa.ipk3.
portsThe ports in this mod's dropdown, best first:
  1. "ports": ["uzdoom", "gzdoom", "lzdoom"]. The first one is picked for the user. Put the port with 3D first.
  2. Each port shows its name. A port with "stereo": true shows "3D" after its name (like "UZDoom 3D").
  3. Want your own text? Give the port "label": "UZDoom - best". Then exactly that is shown (up to 40 characters).
  4. GPU Selector shows a port in grey when it is not downloaded on this PC yet. Play gets it.
  5. Only list ports that really run the mod: a short list is easier to pick from.
filesLoad order, when it matters: ["mod.pk3","maps.wad"].
  1. A .zip with no mod file inside, whose own files are the mod (like zscript, gldefs, textures), is kept whole as a .pk3.
  2. That also works when all of it sits in one folder at the top of the zip.
complevelFor Boom-style ports, as text: "2", "3", "4", "9", "11", "21", "vanilla", "boom", "mbf" or "mbf21".
download
  1. {"urls":[...],"size":123,"sha256":"..."}: up to 8 links, tried in order. HTTPS only.
  2. Or {"github":"owner/repo","asset":"name-*.zip","tag":"v1.0"}: checked against GitHub's SHA256.
  3. With sha256 the file is checked and not asked about. Without it, GPU Selector asks first.
pageIts web page. With no download, the row shows "Get It": the page opens, then the user picks the file they downloaded.
browserFor sites that make a new link per click (ModDB, itch.io):
  1. {"open":"https://...","fileName":"Mod.zip","size":123,"md5":"..."}
  2. Get It opens open in the browser.
  3. Install Download looks once for fileName in Downloads (or opens the picker there), then checks the size and MD5.
  4. GPU Selector never downloads from these sites itself.
installAsRows that share one download (like the three Ashes games): the id of the row that holds the install.
preferred, favorite, culttrue puts the mod in the Preferred, Fan Favs or Cult chip. Preferred mods come first.
steamA Steam app id: the row shows Install on Steam or the store page instead.
basetrue for the original game itself (nothing to download).
status"soon" shows "Coming soon".
adulttrue for adult mods. They stay hidden everywhere (list, chips, counts, Mix) until the user picks Yes in Options, Parental Settings ("Are you 18 or older?"). The default is No.
mixRole"gameplay" or "addon". Category gameplay or addon sets it too. See Mixing mods.
addonForAn add-on: the gameplay mod ids it fits. Leave it out (or ["*"]) for any. Add "none" when it fits a mix with no gameplay mod (like voxel monsters, which only work with DOOM's own monsters).
addonSlotAn add-on's load order, 0 to 100 (default 60). Under 20 loads before the map (textures). 20 to 49 fonts and sprites, 50 HUD, 60 lights, 70 weather, 80 and up music. The gameplay mod is 30.
tctrue: this is a total conversion (it takes no gameplay mod in a mix). Default: category tc or "needs": "standalone".
mixTctrue: the add-on also fits total conversions (like lights and weather).
requiresItem ids it needs too. Play Mix waits until they are picked.
conflictsWithItem ids that do the same job. Picking one removes the other.
stackstrue: a gameplay mod that goes on top of another (like Corruption Cards).
mixSafeOn a map pack: "warn" (its own monsters, a gameplay mod can break it) or "no" (no M on its row) or "yes" (never warn). On DOOM cards, DEH files and MBF21 maps get "warn" by themselves.

Mixing mods (the Mix view)

  1. On the Mods page, rows that can mix have an M left of their buttons, under 3D.
  2. A grey M is off. A half white, half grey M is in your mix. Press it to change.
  3. Rows with an M:
    • every gameplay mod,
    • map packs, total conversions and official games that a mix port can play (GZDoom family, or a custom port with "mix": true).
  4. A mix has one game and one gameplay mod. A new one replaces the old one. A stacks mod can go on top.
  5. Press Mix (right of the mod count) to see your mix. Add-ons are picked there, grouped by what they do.
  6. Only mods that fit are listed:
    • a gameplay mod must share a port with the game,
    • a total conversion ("category": "tc" or "needs": "standalone") takes no gameplay mod, only add-ons with mixTc.
  7. The load order is set for you. Press Play Mix.
  8. Add-ons ("category": "addon") are not in the mod list. They only show in the Mix view.
  9. People can add their own add-ons in Options, Your Add-ons (files or folders). They show under Your Add-ons in the Mix view, for every game.
  10. The add-on list has a search box and group buttons (your addonGroups). Each add-on is one line.
  11. Clicking an add-on's name opens its page. Clicking the rest of the line ticks it.
  12. Preferred Mixes, a drop-down at the top of the Mix view:
    • "mixes": [{"id","name","base","picks":[...],"note"}]
    • base is the game's item id. picks are item ids (up to 20). Name up to 40, note up to 200 characters.
    • A mix with a hidden item (like an adult mod) is hidden too.
  13. Add-on Sets, a drop-down next to it ("addonSets"):
    • [{"id","name","note","picks":[add-on ids]}], up to 20 sets of up to 12 add-ons.
    • Unlike a Preferred Mix, a set fits any game, total conversions too.
    • Picking a set ticks only the add-ons that fit the game. Hidden ones (like adult add-ons) are skipped.
    • When an add-on in the set clashes with one already picked (conflictsWith), the set's one replaces it.

Your card, your rules

  1. Everything you set in your card (mix, options, text, engine, tabs, ui.colors, ui.order) only changes your card.
  2. You pick almost everything: words, hover tips, colours, the order of parts, where buttons go. What stays with GPU Selector: safety checks, and what only it can know (what is installed on this PC).
  3. Each card keeps its own saved choices: mixes, picks, the Parental Settings answer, the font switch.
  4. A card can never change another card. It can offer GPU Selector's theme (ui.appTheme), but only the user turns it on.

Card packages (.zip) and files

  1. A card can bring files: a port fix (DLL) or its font.
  2. Put them in a folder next to the card named <card file name>_files: doom_card.json + doom_card_files\.
  3. Zip the card and that folder together: doom_card_package.zip (a .7z works too). People load it with Load from File, or with Load from URL and a link to the package.
  4. Load from URL asks "Are you sure this is safe?" first, for every card from a link. A package is scanned by Windows Security before it is opened.
  5. The zip is 256 MB or less, and Windows Security scans it.
  6. Each file is checked by the SHA256 the card gives.
  7. A zip with a program file (DLL, EXE) always shows a warning first. Cards can't turn this off.
  8. Cards on the House only loads cards from the GPU-Selector-Cards site that match their SHA256.

Rules

  1. Only link files you may share. Link the page when a site makes download links per click (itch.io, ModDB).
  2. Files with a SHA256 (from the card or from GitHub) are checked. Other files: GPU Selector asks first.
  3. Windows Security scans every download up to 50 MB before it is unpacked.
  4. A mod download with a DLL, EXE or script always asks the user first ("This Download Has a DLL").
  5. Mods unpack into the card's own folder. Nothing is copied into a game folder.
  6. The page never sends a command line. GPU Selector builds it from checked paths and the port's family.

GPU Selector's theme: "ui.appTheme"

  1. A card can offer one of GPU Selector's built-in themes: "ui": {"appTheme": "doom"}.
  2. The card's Options page then has a GPU Selector Theme sub card to turn it on or off. The choice is remembered.
  3. Themes you can use: starwars, alien, terminator, bladerunner, tron, dune, doom, quake, halflife, portal, bioshock, metalgear, darksouls, minecraft, residentevil, silenthill, castlevania, pacman, tetris, mario, pokemon, cyberpunk, witcher, skyrim, morrowind, halo, crysis, masseffect, eldenring, godofwar, gta, win95, dos, vaporwave, asheronscall, konami, osu, classicsteam, anaglyph, depth3d, unsc, blood, link, zelda, sonic, majora, matrix, fallout.
  4. Not allowed: the two special themes, lotr and warhammer40k. A card that names them is not loaded.

Your card's guide: "ui.guide"

  1. Write a Markdown file, like GUIDE.md, and put it in your card's files folder (see Card packages).
  2. In the card: "ui": {"guide": {"file": "GUIDE.md", "sha256": "..."}}. Get the SHA256 with Get-FileHash GUIDE.md in PowerShell.
  3. A Guide button shows at the bottom of your card. It opens your guide in the browser, in your card's colour and font.
  4. Pick where the button goes with "position": "left" (the default, after your card's buttons) or "right" (next to "Card by").
  5. What works: # headings (3 sizes), numbered lists, - lists, > tip boxes, **bold**, `code`, --- lines, and https links. Nothing else runs: no pictures, no scripts.
  6. Rename the button with "ui": {"labels": {"guide": "Manual"}}.
  7. 200 KB or less. Update its sha256 every time you change the file.
  8. GPU Selector reads the guide from your card's files folder: next to the .json on your PC, or inside your card package (.zip). From a link or Cards on the House, use a package. If the file can't be found, GPU Selector tells you. The same goes for ui.font.

Write a guide that is easy to follow

  1. Start with a 1-line short version, then 3 steps that get people playing.
  2. One idea per line. Short sentences. Simple words.
  3. Number every step. Put button names in bold, exactly as they read on the card.
  4. Use headings so people can jump to what they need. Use tip boxes (>) for the one thing to remember.
  5. End with "Something went wrong?": each problem in bold, and its fix.
  6. A little flavour from your game is fun (the DOOM card's guide is a "Field Manual"). Keep it light.
  7. No em dashes. No walls of text. Look at the DOOM card's GUIDE.md as an example.

The card's own font: "ui.font"

  1. Best: a font file in the card's package. "font": {"file":"MyFont.woff2","sha256":"...","name":"DOOM","credit":"...","license":"https://..."}.
  2. The file goes in the card's files folder (see Card packages). WOFF2 only, 220 KB or less.
  3. Or put it inside the card: "src":"data:font/woff2;base64,..." (300 KB or less).
  4. name is shown in Options, like DOOM font.
  5. Only free fonts, with their credit and license link.
  6. It only changes this card's headings. The Options page can turn it off.
  7. Off at first: add "startOff": true. Users can turn it on in Options.

Making a Card with an AI

The goal: a card brings a project's good features into GPU Selector. It is more than a download button.

Research first

Before making the card, start a separate agent to research the project, in this order:

  1. Is it safe? Its age, makers, license, issues, how its releases are built, and what people report. Not safe? Stop and tell the person. Also find out, from its docs and code:
    • Does it put files in game folders (like a d3d12.dll or dxgi.dll)? That clashes with ReShade and GPU Selector's own DLLs.
    • Does it touch games with anti-cheat? Could someone be banned?
    • Does it start with Windows, send data, or need admin rights?
    Every real risk you find goes on the card: in "notice" for the big ones (bans, broken ReShade), in the text for the rest.
  2. Does it have source code? Then maybe make a simple app from that code, with only the feature GPU Selector needs. Keep the license, credit the author, and publish it in your own GitHub release.
    • Can the whole app become a ReShade add-on? That is a good option too: it then runs inside the game with ReShade, and needs no separate program.
    • Does the project put a DLL into the game (like a d3d12.dll recorder or hook)? Build that part as a ReShade add-on (.addon64) instead. GPU Selector loads it with ReShade through Inject Mode, only in the games the user picks, and nothing stays in the game folder. The card installs it with addons.
    • Can't it be an add-on? A separate DLL that GPU Selector injects next to ReShade is the other way. Cards have no field for that yet: tell the person it is missing.
  3. No simple app? Can the app be driven from outside? Look for start options, a command-line mode, or config files. The card's buttons can use those.
  4. None of that? Make sure the card starts the app properly. Read the app's own docs for the right file, and look inside its zip.

The research decides the card: what it downloads, which file it starts, its buttons, its tabs and its text. Write down what you found, and build the card from that.

Something the card needs but this guide has no field for? Don't work around it. Tell the person which part is missing.

You can ask an AI to make a card. Tell it:

  1. Read this guide.
  2. Read the project's GitHub page, its install guide and its release files. A manager app's GitHub (like RHI) is a good source of the right download links.
  3. Make the card download and install what the project needs. Come up with the tabs and text.
  4. Say if it should turn on in all games or only in certain games.

Checklist for the AI

  1. Links: every download must already exist. Never point to a repo or release that isn't made yet. If the card needs a helper you made, the person publishes it first.
  2. Credits: cardBy is the person making the card, never "AI".
  3. Checking: nothing outside GPU Selector checks a card. Loading it with Load from File is the check: a card with a mistake is not loaded, and GPU Selector says why.
  4. Downloads: use GitHub release files (github + asset, or a releases/download link). They have a SHA256 and get update notices. Avoid github.io and raw links. Other hosts only when the author's own installer uses them, with sha256.
  5. Several products in one repo: pin each with tag.
  6. Names: each add-on's name is its own file name without .addon64.
  7. Where files go: read "besideAddon or nextToGame?" above. Install guides that say "next to the exe" assume the add-on is there. When unsure, use both lists.
  8. Shaders: ship the project's own .fx files with shaders. For LumeniteFX use repoShaders. Never download a shader pack whose author does not allow sharing.
  9. Shader settings: put the values the install guide asks for in preprocessor.
  10. Effect order: GPU Selector can't set it. Write it as numbered steps.
  11. Graphics cards: one tab per brand with "gpu". Say which card series work, from the project's own notes.
  12. Games: an add-on made for some games gets games. Put the same games in targetGames, with notes for game settings, hdr for HDR mods, and reshade locks when the API is known.
  13. Anti-cheat games: add-ons only load offline. Give the game "eacBypass": true and say so in its notes. Online-only games: leave them out. RE Engine games: "reEngineBypass": true.
  14. Text: short numbered lines, one idea per line. No em dashes. Only claims you found in the project's docs or in GPU Selector's own behaviour (like anti-cheat games needing offline mode). When sources disagree, follow the author's newest file (installer payload over an older README).
  15. Test: load it with + Add Mod and Load from File. A card with a mistake shows what is wrong.

The example cards were made this way. Point the AI at GPU-Selector-Cards: it has every example card by level, and AI.md tells an AI where to start.

Check what the AI wrote. Look at every download link before you press Install.

Custom Cards and Card Size

  1. Cards you add go to Custom Cards, away from the built-in cards. Pick Modding Cards with Put them in, in the + Add Mod window.
  2. Open it with the cards button next to Sort in Modding Cards.
  3. To remove a card: its gear button, then Delete. If it installed add-ons or downloads, you pick Keep Them or Remove Them Too.
  4. 625 pixels at most.
  5. A card grows to fit its text, up to 625 pixels. Past that, its description scrolls inside the card with the mouse wheel. The card itself never scrolls.
  6. Long lists, like Target Games, scroll inside their own box (about 2 rows show), with the mouse wheel and no scroll bar.
  7. Cards never scroll sideways. Long words and links wrap.
  8. Tips to fit: short descriptions, a mode switch instead of long lists, and 5 lines or fewer per mode.

Example Cards

Minimal Card (with download)

{
  "cardVersion": "1.0",
  "name": "My Simple Mod",
  "description": "A basic mod that does something cool",
  "versions": [
    {"version": "1.0.0", "url": "https://github.com/user/mod/releases/download/v1.0.0/mod.zip"}
  ]
}

Minimal Card (organizer only)

{
  "cardVersion": "1.0",
  "name": "DOOM Collection",
  "description": "Highlights all your DOOM games in one place",
  "tagline": "Rip and Tear",
  "versions": [],
  "targetGames": [
    {"match": "contains", "name": "DOOM"}
  ],
  "ui": {
    "buttonColor": "#b91c1c",
    "buttonHoverColor": "#991b1b"
  }
}
Organizer cards have an empty versions: [] array. They show matched games with play buttons but no download button. The play button uses each game's full launch settings from the Games tab.

Visual Install Examples

🎯 How Install Actions Work:

Your ZIP file contains folders. Each installActions line tells GPU Selector:
"Take files FROM this folder in my ZIP, put them TO this location on the PC"
⚠️ FILE REPLACEMENT BEHAVIOR:

If a file already exists at the destination, IT WILL BE OVERWRITTEN.

📁 BEFORE Install

Game Folder:
  +-- dxgi.dll (original)
  +-- game.exe

📁 AFTER Install

Game Folder:
  +-- dxgi.dll (YOUR mod) ✨
  +-- game.exe

⚠️ No automatic backup! Tell users to back up files first. GPU Selector does not back them up for this kind of install.

✅ SIMPLE: One Location Install

Everything goes into the game folder. Easy!

📦 STEP 1: Your ZIP File

perfmod.zip
    |
    +-- dxgi.dll        (your mod file)
    +-- perfmod.ini     (config file)

⚙️ STEP 2: The Install Action

"installActions": [
    {
        "type": "extract",
        "from": "*",           <-- Take ALL files
        "to": "{game}"         <-- Put in game folder
    }
]

🎮 STEP 3: What Happens


  YOUR ZIP                          GAME FOLDER
  --------                          -----------
                                    C:\Games\Elden Ring\
  perfmod.zip                              |
       |                                   |
       +-- dxgi.dll     ============>      +-- dxgi.dll
       +-- perfmod.ini  ============>      +-- perfmod.ini
                                           +-- eldenring.exe
                                           +-- (other game files)
📄 Click to see FULL JSON for this example
{
  "cardVersion": "1.0",
  "name": "Performance Boost Mod",
  "author": "ModAuthor",
  "description": "Improves game performance by 20%",
  "icon": "https://raw.githubusercontent.com/user/perfmod/main/icon.png",
  "backgroundArt": "https://raw.githubusercontent.com/user/perfmod/main/banner.jpg",
  "versions": [
    {"version": "1.2.0", "url": "https://github.com/user/perfmod/releases/download/v1.2.0/perfmod.zip"}
  ],
  "targetGames": [
    {"match": "exact", "name": "Elden Ring"}
  ],
  "installActions": [
    {"type": "extract", "from": "*", "to": "{game}"}
  ]
}

🔀 ADVANCED: Multi-Location Install

Files go to DIFFERENT folders on the PC. Use subfolders in your ZIP!

💡 Key Concept: Organize your ZIP with subfolders. Each subfolder = one destination.

📦 STEP 1: Organize Your ZIP with Subfolders

gfxmod.zip
    |
    +-- game_files/              <-- Folder 1: goes to game
    |       +-- Data/
    |       +-- SKSE/
    |
    +-- enb_preset/              <-- Folder 2: also goes to game
    |       +-- enbseries.ini
    |
    +-- user_config/             <-- Folder 3: goes to Documents
    |       +-- Skyrim.ini
    |       +-- SkyrimPrefs.ini
    |
    +-- cache_data/              <-- Folder 4: goes to AppData
            +-- shaders/

⚙️ STEP 2: One Install Action Per Destination

"installActions": [
    {"type": "extract", "from": "game_files/*",   "to": "{game}"},
    {"type": "extract", "from": "enb_preset/*",   "to": "{game}"},
    {"type": "extract", "from": "user_config/*",  "to": "{documents}/My Games/Skyrim"},
    {"type": "extract", "from": "cache_data/*",   "to": "{localappdata}/Skyrim"}
]

from: folder name in your ZIP + /* (means all files inside)
to: where to put them on the user's PC

🗺️ STEP 3: Visual Map: Where Files End Up


  ZIP FOLDER                    DESTINATION ON PC
  ----------                    -----------------

  game_files/*    ==========>   C:\Games\Skyrim\
       +-- Data/                     +-- Data/
       +-- SKSE/                     +-- SKSE/

  enb_preset/*    ==========>   C:\Games\Skyrim\
       +-- enbseries.ini             +-- enbseries.ini

  user_config/*   ==========>   C:\Users\You\Documents\My Games\Skyrim\
       +-- Skyrim.ini                +-- Skyrim.ini
       +-- SkyrimPrefs.ini           +-- SkyrimPrefs.ini

  cache_data/*    ==========>   C:\Users\You\AppData\Local\Skyrim\
       +-- shaders/                  +-- shaders/

📄 Click to see FULL JSON for this example
{
  "cardVersion": "1.0",
  "name": "Ultimate Graphics Overhaul",
  "author": "GraphicsTeam",
  "description": "HD textures, ENB preset, and optimized configs",
  "icon": "https://raw.githubusercontent.com/user/gfxmod/main/icon.png",
  "backgroundArt": "https://raw.githubusercontent.com/user/gfxmod/main/card-bg.jpg",
  "versions": [
    {"version": "3.0.0", "url": "https://github.com/user/gfxmod/releases/download/v3/gfxmod.zip"}
  ],
  "targetGames": [
    {"match": "exact", "name": "Skyrim Special Edition"},
    {"match": "pattern", "name": "*Skyrim*"}
  ],
  "installActions": [
    {"type": "extract", "from": "game_files/*", "to": "{game}"},
    {"type": "extract", "from": "enb_preset/*", "to": "{game}"},
    {"type": "extract", "from": "user_config/*", "to": "{documents}/My Games/Skyrim Special Edition"},
    {"type": "extract", "from": "cache_data/*", "to": "{localappdata}/Skyrim Special Edition"}
  ]
}

🔄 EDGE CASE: Rename a File During Install

Your ZIP has one filename, but the game needs a different name.

✏️ Example: Rename DLL

YOUR ZIP                              GAME FOLDER
--------                              -----------

mymod.zip                             C:\Games\SomeGame\
    |                                        |
    +-- ExampleMod64.dll  ==========>        +-- dxgi.dll    (RENAMED!)
"installActions": [
    {
        "type": "extract",
        "from": "ExampleMod64.dll",    <-- Original name in ZIP
        "to": "{game}/dxgi.dll"        <-- New name on PC (include filename!)
    }
]

📂 EDGE CASE: ZIP Has Extra Parent Folder

Sometimes ZIPs have an extra folder wrapping everything. Handle it!

🤔 Problem: Unwanted Parent Folder

BAD ZIP STRUCTURE                     WHAT YOU WANT
-----------------                     -------------

mymod-v1.0.zip                        Game Folder:
    |                                     +-- dxgi.dll
    +-- mymod-v1.0/     <-- Extra!        +-- config.ini
            |
            +-- dxgi.dll
            +-- config.ini
"installActions": [
    {
        "type": "extract",
        "from": "mymod-v1.0/*",        <-- Include the parent folder name + /*
        "to": "{game}"
    }
]

The /* means "everything INSIDE this folder". The parent folder itself is skipped.

📁 EDGE CASE: Install to a Subfolder

Files need to go into a specific subfolder of the game.

🎯 Example: Install to Game's "Mods" Subfolder

YOUR ZIP                              GAME FOLDER
--------                              -----------

textures.zip                          C:\Games\Fallout4\
    |                                        |
    +-- rocks.dds                            +-- Data/
    +-- trees.dds                            |     +-- Textures/    <-- Target!
    +-- grass.dds                            |           +-- rocks.dds
                                             |           +-- trees.dds
                                             |           +-- grass.dds
                                             +-- Fallout4.exe
"installActions": [
    {
        "type": "extract",
        "from": "*",
        "to": "{game}/Data/Textures"   <-- Add subfolders after {game}
    }
]

❌ COMMON MISTAKES

❌ WRONG vs ✅ RIGHT

❌ WRONG: Forgetting the /*

"from": "game_files"      <-- Missing /* = copies the folder itself!

✅ RIGHT:

"from": "game_files/*"    <-- With /* = copies contents only

❌ WRONG: Missing quotes in JSON

{from: "files/*", to: {game}}     <-- Keys need quotes!

✅ RIGHT:

{"from": "files/*", "to": "{game}"}

❌ WRONG: Backslashes in paths

"to": "{game}\Data\Textures"      <-- Backslashes break JSON!

✅ RIGHT:

"to": "{game}/Data/Textures"      <-- Always use forward slashes

❌ WRONG: HTTP instead of HTTPS

"url": "http://example.com/mod.zip"   <-- Blocked for security!

✅ RIGHT:

"url": "https://example.com/mod.zip"  <-- HTTPS required

✅ QUICK CHECKLIST BEFORE PUBLISHING

☐ All URLs use HTTPS (not HTTP)
☐ JSON is valid (test at jsonlint.com)
☐ ZIP file downloads correctly
☐ Icon is 128x128 PNG
☐ Background is about 960x480 JPG, under 500 KB
☐ Tested install on your own PC first
☐ Paths use forward slashes: /
☐ "from" paths end with /* for folders

📍 Path Placeholders: Quick Reference

{game}
The game's install folder
Example: C:\Games\Elden Ring\
{documents}
User's Documents folder
Example: C:\Users\You\Documents\
{localappdata}
User's AppData\Local folder
Example: C:\Users\You\AppData\Local\
{appdata}
User's AppData\Roaming folder
Example: C:\Users\You\AppData\Roaming\

Setting Up Your GitHub Folder

Your GitHub Repo Structure

your-mod-repo/
    |
    +-- mod-card.json            <-- Your card definition
    |
    +-- icon.png                 <-- Card icon (128x128)
    |
    +-- card-background.jpg      <-- Card background (about 960x480)
    |
    +-- releases/
            +-- mymod-v1.0.zip   <-- Your mod ZIP file

How to Link Images in Your JSON

{
  "icon": "https://raw.githubusercontent.com/YOUR-NAME/YOUR-REPO/main/icon.png",
                                  =========       =========
                                  Your GitHub     Your repo
                                  username        name

  "backgroundArt": "https://raw.githubusercontent.com/YOUR-NAME/YOUR-REPO/main/card-background.jpg"
}

ICON

128x128

PNG format
Square shape
Transparent OK

BACKGROUND

960x480

JPG format
Wide rectangle
Under 500KB

Hosting Your Card

GitHub (Recommended)

  1. Create a mod-card.json file in your repository
  2. Get the raw URL: https://raw.githubusercontent.com/user/repo/main/mod-card.json
  3. Users paste this URL to load your card

GitHub Gist

  1. Create a new Gist at gist.github.com
  2. Name the file with .json extension
  3. Copy the "Raw" URL

Any HTTPS Server

Host the JSON file on any server that supports HTTPS. Ensure proper CORS headers if needed.

Tip: Host your ZIP files on GitHub Releases for reliable, fast downloads.

Security Guidelines

For Mod Authors:
  • Always use HTTPS for all URLs
  • Host files on trusted platforms (GitHub, etc.)
  • Don't include harmful code. Files are scanned with Windows Security.
  • Avoid installing to system directories
  • Test your card thoroughly before distribution
Security Features:
  • HTTPS required for all downloads
  • AMSI malware scanning before extraction
  • Blocked system directories (Windows, System32)
  • Path traversal protection
  • JSON-only format (no executable code in card)
  • User warnings before loading external cards

Limits


GPU Selector: Custom Mod Card System