Skip to content

Templated platform guide

Wesley edited this page Aug 18, 2026 · 16 revisions

Templated platform guide

Most platforms are defined in Platforms.json. Steam is the main exception; it has a dedicated switcher.

Video guide:

Adding platforms video

Files

File Purpose
Repo Platforms.json Catalog embedded at build time
{UserData}/Platforms.json Live catalog used by the app
{UserData}/Platforms.custom.json Local overrides

Set a custom catalog path in Settings -> System.

Top-level shape

{
  "Platforms": {
    "Escape from Tarkov": { },
    "Steam": { }
  },
  "Platform-WIP": { }
}

The platform object key is the display name. It should match the SVG filename in frontend/public/img/platform/.

Required keys

Identifiers

Array of CLI/protocol names. The first entry is the primary short name, such as s or b. Identifiers must be unique.

ExeLocationDefault

Default launcher exe path. This can be a string or a fallback array. Environment variables such as %ProgramFiles% and %LocalAppData% are supported.

ExesToEnd

Process names to close during a swap. Prefix a name with SERVICE: for Windows services.

PathListToClear

Paths removed during the Add New/logout flow. Use "SAME_AS_LOGIN_FILES" alone to mirror the LoginFiles keys.

LoginFiles

Maps live system paths to relative cache paths under LoginCache/{Platform}/{accountId}/.

Form Meaning
%AppData%\file File or folder
path\* Recursive copy/delete
path\data_* Non-recursive wildcard
REG:HKCU\Path:ValueName Registry string value
JSON:file::query JSON file field
JSON_SELECT_FIRST,: First segment of a delimited string
JSON_EMPTY_VALUE::file::query Clear JSON field on switch
SQLITE:file::query SQLite scalar query
leveldb:path:key LevelDB value

If AllFilesRequired is true, missing entries stop the swap.

Unique account id

Each platform needs a stable id for the active account.

Key Use
UniqueIdFile File, registry, JSON, SQLite, or LevelDB reference
UniqueIdMethod Reader type
UniqueIdRegex Optional regex on file contents

EMAIL_REGEX is a built-in regex preset.

For file and registry readers, include UniqueIdFile in LoginFiles so the value is restored on swap.

Supported methods:

  • CREATE_ID_FILE
  • REGKEY
  • LEVELDB
  • BUILTIN
  • STEAM
  • FILE_MD5
  • JSON_SELECT
  • JSON_SELECT_FIRST
  • JSON_SELECT_LAST

Optional keys

Key Use
DisabledByDefault Keep the platform off the home screen on first run, even when it is installed. Users still add it from Manage platforms
ExitBeforeInteract Close platform before reading account data
ExitBeforeSave Close platform before writing cache
RegDeleteOnClear Delete registry values instead of clearing
ExeExtraArgs Extra launcher arguments
GetPathFromShortcutNamed Resolve install folder from a Start Menu shortcut

Extras

Key Use
CachePaths Enables Clear cache
BackupFolders Enables backup/restore tools
BackupFileTypesInclude / BackupFileTypesIgnore Filters partial backups
ShortcutFolders Scans for .lnk and .url shortcuts
ShortcutIgnore Filters shortcuts by substring
ShortcutIncludeMainExe Shows or hides the launch-platform tile
SearchStartMenuForIcon Resolves icon from Start Menu
ClosingMethod Combined, Close, or TaskKill
ForceClosingMethod Skips fallback close logic
QuitArgs Arguments that ask the launcher to shut itself down, e.g. -shutdown. See Closing a launcher that ignores WM_CLOSE
ProfilePicPath / ProfilePicFromFile / ProfilePicRegex Resolves avatars
BuiltInUsernameFile / BuiltInProfileImageFile / BuiltInUserId Template-based user fields
variables Named resolvers for templates

Closing a launcher that ignores WM_CLOSE

By default a swap asks the launcher to close by sending its windows WM_CLOSE, waits up to five seconds, then force-kills whatever is left.

Plenty of launchers never exit on WM_CLOSE. A launcher that minimises to the tray when you click the X treats the message as "hide", not "quit" — so the wait can only ever run out, and every swap pays those five seconds before force-killing anyway. Steam and the Epic Games Launcher both behave this way.

You have two ways to fix that in the descriptor.

Extras.QuitArgs — ask the launcher to quit itself

If the launcher has a command-line switch that shuts it down, name it:

"Extras": {
  "QuitArgs": "-shutdown"
}

The arguments are passed to the same executable the descriptor already launches, so you cannot point this at some other program. The swap runs it once, then waits for the processes in ExesToEnd to exit, and returns the moment the last one does.

This is the better option where it exists: the launcher shuts down in its own time and writes its config out properly, instead of being killed part-way through. Steam uses -shutdown and closes in roughly 1.5 seconds instead of 6.5.

Extras.ClosingMethod: "TaskKill" — skip straight to the kill

If the launcher has no such switch, there is nothing to wait for. TaskKill force-closes it immediately, reaching the same end state as the five-second wait without the wait. Epic Games uses this.

Which one do I need?

Close the launcher by clicking the X on its window, then check whether the process is still running in Task Manager.

What happens What to set
Process exits Nothing — the default already works
It sits in the tray, and the launcher has a documented shutdown switch QuitArgs
It sits in the tray with no shutdown switch ClosingMethod: "TaskKill"

Helpers with no window of their own — background services and the like — need neither. The swap detects that there is nothing to send WM_CLOSE to and does not wait on them.

Neither key overrides a closing method the user has already chosen in platform settings, unless you also set ForceClosingMethod.

Environment variables

Variable Expands to
%AppData%, %LocalAppData%, %ProgramFiles% Standard Windows folders
%Platform_Folder% Directory containing the platform exe
%TCNO_UserData% User data root
%TCNO_AppData% Install directory
%Documents%, %Music%, %Pictures%, %Videos% User folders
%StartMenu%, %StartMenuAppData%, %StartMenuProgramData% Start Menu folders
%UniqueId% Current account id
%LARGEST% Largest file in a folder

If LoginFiles writes under %TCNO_AppData%, the app may need to restart as administrator.

Username JSON for profile images

Display names can include avatar metadata:

MyName:{"image":"https://example.com/avatar.png"}

This is parsed by the account-name handling in internal/basic.

Custom platform workflow

  1. Copy a similar platform block.
  2. Adjust paths using Help code a platform research.
  3. Test through Platforms.custom.json.
  4. Add the SVG icon.
  5. Submit a PR.

Code references

Topic File
Descriptor parsing internal/platform/descriptor.go
Swap/save flow internal/basic/flow.go
Unique id readers internal/basic/unique_id.go
Variable transforms internal/basic/var_transforms.go
Regex helpers internal/basic/helpers.go

Old wiki links to Globals.cs and BasicSwitcherFuncs.cs refer to the retired C# codebase.

Clone this wiki locally