Documentation Index
Fetch the complete documentation index at: https://mintlify.com/smogon/pokemon-showdown-client/llms.txt
Use this file to discover all available pages before exploring further.
The Pokémon Showdown desktop application is built on top of NW.js (formerly known as Node-WebKit), which bundles a Chromium browser and a Node.js runtime into a single native executable. The desktop/ directory contains all the packaging assets — index.html, package.json, installer scripts, and icons — needed to ship the client as a standalone app on Windows and macOS.
Application Structure
The desktop app configuration lives entirely inside desktop/:
desktop/
├── DESKTOP.md # Packaging instructions
├── Info.plist # macOS app metadata template
├── index.html # App entry point
├── package.json # NW.js app manifest
├── icons/ # Platform-specific icons
│ ├── icon_32x32.png # PNG icon (used on Windows for window chrome)
│ ├── installerbg.bmp # Background image for the NSIS installer
│ └── pokemonshowdown.ico # Windows executable icon (applied via Resource Hacker)
├── make-nsis-script.js # Generates the NSIS installer script
├── nwjs-entitlements.entitlements # macOS Hardened Runtime entitlements
├── pokemonshowdown.nsi # NSIS installer script (Windows)
└── sign-mac-app # Shell script for macOS code signing
The desktop/package.json manifest tells NW.js how to launch the app:
{
"name": "Pokemon Showdown",
"version": "0.3.0",
"main": "index.html",
"node-remote": "https://play.pokemonshowdown.com/*",
"window": {
"icon": "icons/icon_32x32.png",
"title": "Loading...",
"toolbar": false,
"show": false
},
"webkit": {
"plugin": true
}
}
NW.js does not support normal window icons on Windows (the icon shown in the title bar and taskbar). A PNG icon is used instead to avoid ugly scaling artefacts. The .ico file is only applied to the executable itself via Resource Hacker.
For performance, the app assets are not zipped on either platform. On Windows, index.html and package.json are dropped directly into the install directory. On macOS, they go inside Resources/app.nw.
The graphics-src directory at the repository root contains the authoritative icon sources:
showdown.ico — Windows executable icon (multi-size .ico file)
showdown.icns — macOS app icon bundle
These are used whenever platform-native icons are needed during the packaging steps below. The desktop/icons/pokemonshowdown.ico file (used in the Windows packaging step) is a copy derived from graphics-src/showdown.ico.
Packaging
The Windows build produces a .exe installer built with NSIS. The steps below assume you have already built the client with node build.Copy NW.js into the desktop folder
Download the NW.js prebuilt binary from nwjs.io and extract it into the desktop/ folder. The folder should now contain nw.exe alongside index.html and package.json. Rename the executable
Rename nw.exe to pokemonshowdown.exe:mv desktop/nw.exe desktop/pokemonshowdown.exe
Replace the icon with Resource Hacker
Open pokemonshowdown.exe in Resource Hacker and replace the embedded NW.js icon with icons/pokemonshowdown.ico (located inside the desktop/icons/ folder). Save the file.Resource Hacker is a Windows-only GUI tool. This step cannot be automated without additional tooling.
Update the NSIS script if necessary
If the file layout of the desktop/ folder has changed since the last release, update pokemonshowdown.nsi accordingly. Refer to make-nsis-script.js to regenerate the script:node desktop/make-nsis-script.js
Build the installer with NSIS
Compile the installer using NSIS:makensis desktop/pokemonshowdown.nsi
This produces the final .exe installer that users can download and run. The macOS build produces a .app bundle. Code signing and notarization are required to pass Gatekeeper and allow the app to run on users’ machines without warnings.Without code signing and notarization, macOS Gatekeeper will refuse to run the app and display a warning to the user. Completing steps 8–18 requires an Apple Developer account, which costs $99/year.
Get a copy of NW.js
Download the NW.js prebuilt binary for macOS from nwjs.io and extract it. You will have a .app bundle to work with. Rename the app bundle
Rename the extracted .app bundle:mv nwjs.app "Pokemon Showdown.app"
Update Info.plist
Edit Pokemon Showdown.app/Contents/Info.plist and change the following keys:| Key | Value |
|---|
CFBundleIdentifier | com.pokemonshowdown.pokemonshowdown |
CFBundleName | Pokemon Showdown |
CFBundleDisplayName | Pokemon Showdown |
CFBundleShortVersionString | Current version, e.g. 0.11 |
CFBundleVersion | A version code (the git commit hash works) |
Also empty the arrays for CFBundleDocumentTypes, CFBundleURLTypes, NSUserActivityTypes, and UTExportedTypeDeclarations so they read <array></array>. This prevents NW.js from registering itself as a handler for arbitrary file types and URLs. Update InfoPlist.strings
Edit Pokemon Showdown.app/Contents/Resources/en.lproj/InfoPlist.strings and update:
CFBundleName → "Pokemon Showdown"
CFBundleDisplayName → "Pokemon Showdown"
CFBundleGetInfoString → e.g. "Pokemon Showdown 0.11, Copyright 2011-2024 Guangcong Luo and contributors."
NSHumanReadableCopyright → e.g. "Copyright 2011-2024 Guangcong Luo and contributors."
Then delete all other *.lproj folders inside Resources/ (except en.lproj) to prevent NW.js’s localised name from appearing instead of “Pokemon Showdown” in other locales. Replace the app icons
Copy the .icns file from graphics-src over the two placeholder icons:cp graphics-src/showdown.icns \
"Pokemon Showdown.app/Contents/Resources/app.icns"
cp graphics-src/showdown.icns \
"Pokemon Showdown.app/Contents/Resources/document.icns"
Add the app content
Create the app.nw folder inside Resources/ and place the app files in it:mkdir -p "Pokemon Showdown.app/Contents/Resources/app.nw"
cp desktop/index.html "Pokemon Showdown.app/Contents/Resources/app.nw/"
cp desktop/package.json "Pokemon Showdown.app/Contents/Resources/app.nw/"
Obtain a Developer ID certificate
Log in to your Apple Developer account and create a Developer ID Application certificate:https://developer.apple.com/account/mac/certificate/certificateList.action
Download the certificate and install it by dragging the file into Keychain Access. Note the identity string shown in parentheses next to the certificate name — you will need it in the next step. Sign the app with Hardened Runtime
Edit the desktop/sign-mac-app script, setting APP to the path of your .app bundle and IDENTITY to the certificate identity string from the previous step. Then run it:bash desktop/sign-mac-app
This signs the binary with the Hardened Runtime entitlements defined in desktop/nwjs-entitlements.entitlements.Verify the signature afterward:codesign --verify -vvvv "Pokemon Showdown.app"
Create a zip for notarization
Compress the signed app (right-click → Compress in Finder, or via command line):zip -r "Pokemon Showdown.zip" "Pokemon Showdown.app"
Submit for notarization
Send the zip to Apple’s notarization service. Replace [USERNAME] with your Apple Developer email address and [PASSWORD] with an app-specific password (generated at appleid.apple.com):xcrun altool --notarize-app \
--primary-bundle-id "com.pokemonshowdown.pokemonshowdown" \
--username "[USERNAME]" \
--password "[PASSWORD]" \
--file "Pokemon Showdown.zip"
The output will include a RequestUUID. Save it — you need it to check the notarization status. Wait and check notarization status
Notarization typically takes around 10 minutes. Poll the status with:xcrun altool --notarization-info [RequestUUID] -u "[USERNAME]"
The Status field will be one of:| Status | Meaning |
|---|
in progress | Try again in ten minutes |
Package Approved | Proceed to the next step |
Package Invalid | Check the LogFileURL in the output for error details |
Staple the notarization ticket
Once approved, staple the notarization ticket to the app so it can be verified offline:xcrun stapler staple "Pokemon Showdown.app"
Validate the result:spctl -a -vvvv "Pokemon Showdown.app"
Create the final distribution zip
Delete the un-stapled zip from step 9 and create a fresh one from the now-stapled app:rm "Pokemon Showdown.zip"
zip -r "Pokemon Showdown.zip" "Pokemon Showdown.app"
This is the file you distribute to users. Apple’s own documentation on the command-line notarization workflow is available at developer.apple.com, but it does not cover Hardened Runtime setup for existing apps. The sign-mac-app script in the repository handles this correctly.