Discord Rich Presence for games played on a real, modded Nintendo DSi or 3DS. While you play, the console reads the game's memory and sends it over Wi-Fi to your PC, which shows what you're doing as your Discord status.
Pokémon Platinum (USA, Rev 1) gets the full presence: where you are, your party, your badges, and who you're battling, with animated sprites. Any other DS game shows its name, box art and a picture of your console, plus its RetroAchievements rich presence ("Racing in Figure-8 Circuit") when it has one. Every game's achievements are checked while you play, even offline, and an optional overlay window shows your party and battles (or any other game's progress) for streaming.
| Overworld (Playing) | Battle (Competing) |
|---|---|
| "Exploring Route 209", badges and Pokédex count, your trainer walking in the direction you face, your lead Pokémon, party fraction | "Battling rival Barry", "Blucifer is fighting Buizel", foe and your Pokémon as sprites (shiny-aware), HP on hover |
- A DSi or 3DS with TWiLight Menu++
installed, and your games as
.ndsfiles on its SD card. - The console's Wi-Fi set up for the same network as your PC. On a DSi, a WPA2 network has to be saved in connection 4, 5 or 6 (System Settings > Internet > Connection Settings > Advanced Setup).
- A 64-bit Windows 10 or 11 PC with the Discord desktop app.
- Download
DSiRPC-<version>-windows.zipfrom the Releases page. It has everything: DSiRPC with its own copy of Python (nothing to install), the two files for your SD card, and aREADME.txtwith these steps. - On the PC: unzip it somewhere you can write to (Documents, the Desktop; not Program Files). If Windows says it "protected your PC", right-click the zip > Properties > tick Unblock, and unzip it again.
- Double-click
Setup.batand answer its questions; Enter takes the suggested answer. If the download comes with a Discord application, press Enter there too. Signing in to RetroAchievements is optional. - Double-click
DSiRPC.bat. DSiRPC's icon appears in the taskbar's notification area, by the clock. When Windows asks about the firewall, allow access on private networks, or DSiRPC never hears from the console. - On the SD card: copy the
DSiRPCfolder from the zip'sSD cardfolder to the root of the card, so you havesd:/DSiRPC/dsirpc-launcher.ndsandsd:/DSiRPC/nds-bootstrap-dsirpc.nds. Keep the two together.
- PC: start DSiRPC (
DSiRPC.bat), or turn on Start with Windows in its menu so it's always there. Turn off any other Rich Presence plugin (like Vencord's CustomRPC), or Discord shows two activities. - Console: open
DSiRPC/dsirpc-launcher.ndsfrom TWiLight Menu++. It connects to Wi-Fi in DSi mode (it tries up to 3 times by itself) and shows the console's IP address. If it says it's running in DS mode, set it to DSi mode in TWiLight Menu++'s per-game settings. Away from your PC? Press B while it connects to play offline. - Press START and pick your game: A opens a folder or picks the game,
B goes up a folder (the browser opens in the
DSiRPCfolder, so press B to get to your games). The launcher starts it, still connected. (SELECT disconnects and goes back instead.) - Within about 15 seconds, Discord shows what you're playing, and the tray icon's dot turns green.
A game you've never started from TWiLight Menu++ has no save file yet; the launcher says so. Start it once from TWiLight Menu++, then use the launcher.
When you close the game, DSiRPC clears the presence after about 30 seconds and waits for the console again, so switching games or restarting needs nothing on the PC.
Away from your PC (or your Wi-Fi), the launcher still starts your games: press B while it connects, or START when it says it couldn't connect. Wi-Fi stays off and the game runs as usual, just without Discord or the overlay.
Whenever the launcher is connected and DSiRPC is running, it syncs with it, once when it connects and again when you start a game (B skips that):
- DSiRPC sends it the achievement sets you have, and
downloads the set of the game you're starting if it can. The launcher keeps
them in
sd:/DSiRPC/sets, each with only the achievements you haven't unlocked yet, already turned into what the console runs (DSiRPC does that with rcheevos, RetroAchievements' own library). - The launcher hands DSiRPC the achievements unlocked while playing offline, and DSiRPC sends them to RetroAchievements (if sending unlocks is on in setup), with the time you unlocked them, and tells you in a notification.
While you play, the console checks the game's achievements itself, Wi-Fi or not, in the time the game leaves its second processor idle. The ones that need every frame (a move that only counts on the exact frame it happens, a challenge that a single slip resets) are checked every frame, as on an emulator; small sets are checked that way whole, big ones as many as fit, and the rest many times a second.
Each unlock is saved to the SD card (sd:/RPCUNLK.BIN) right away, with
when it happened, read from the console's clock (so a nap with the lid
closed doesn't make an unlock look older than it is). The
next time the launcher finds DSiRPC it hands them over, and DSiRPC sends the
ones it didn't already have. This works for games started from the
launcher, which puts the set and the unlock file on the SD card. With Wi-Fi
and DSiRPC running, the console also reports to DSiRPC's log
(Console: its checker unlocked achievement ..., Console: saved 1 unlock(s) to its SD card for DSiRPC), next to DSiRPC's own unlocks, so the
two can be compared.
On a DSi, the console shows new unlocks itself too: the LED picked by
TWiLight Menu++'s ROM read LED setting (ROMREAD_LED in
nds-bootstrap.ini: the Wi-Fi, power or camera LED) pulses while there are
achievements from this game you haven't seen yet (the power LED pulses
purple). Opening nds-bootstrap's in-game menu (L + Down + SELECT by
default) counts as seeing them. It's also a quick way to tell the console's
checker is working without DSiRPC. With DSiRPC's nds-bootstrap that LED no
longer flashes for ROM reads; set the setting to None to turn the
achievement LED off. A 3DS has no LED for this (TWiLight Menu++ has no LED
setting there); the in-game menu shows the new unlocks instead.
The in-game menu shows them too, on a DSi and on a 3DS. When you open it, it says how many new achievements there are since you last looked, with their names, and how many of the game's you've earned. Its Achievements item lists them all: the ones you've earned first, newest first with the date and time (in lime if this console earned it and DSiRPC hasn't had it yet, with NEW on the new ones), then the ones still to get, with the highlighted one's description at the bottom. Up/Down move, L/R turn the page, B goes back. The list comes with the set at each sync, so it includes what you'd already earned on RetroAchievements.
This works on hardware since 2026-10-08 (an offline unlock in Tetris DS reached RetroAchievements at the next sync, and the in-game menu works on a DSi and a 3DS), but it's new: see the roadmap.
Right-click it for the menu:
| Item | What |
|---|---|
| The first lines | What's running, what Discord shows, and your RetroAchievements progress |
| Discord presence | Show the game on Discord, or not |
| Console icon | The picture Discord shows for games without their own presence: DSi XL, New 3DS, or none |
| Overlay window | The stream overlay (a left click on the icon toggles it too) |
| Start with Windows | Start DSiRPC in the tray when you sign in |
| Setup... | Runs setup again, to change an answer |
| Open log / Open DSiRPC folder | logs\dsirpc.log, and the folder DSiRPC is in |
| Quit | Stops DSiRPC |
The dot is green while the game answers, amber while DSiRPC waits for the console, and red if Discord can't be reached (or there's no Discord application yet).
DSiRPC checks a game's achievements against the console's memory with
rcheevos, RetroAchievements'
own library. When you unlock one you get a notification and a banner in the
overlay window, and it's added to logs\achievements.log.
Each game's achievements and rich presence come in a set, kept in the ra
folder. Sets come from:
- RetroAchievements itself, once you've signed in with
Setup.bat(only a login token is saved, never your password). DSiRPC works out which game is running and downloads its set by itself. Setup can also take a folder of your game files (for example the ones you play in RALibretro): with it, DSiRPC knows the exact game and version, the way RA emulators do. Without it, DSiRPC goes by the game's title, and setup can pick a set for a game it can't tell (search by name). - RALibretro's cache: RALibretro keeps the set of every game you've played in it, and DSiRPC can copy them from there, without an account.
Signed in, DSiRPC also shows what you're playing on your RetroAchievements profile, and Discord's hover text shows your progress ("12 of 132 unlocked"). Sending your unlocks to RetroAchievements is a separate choice in setup, off unless you turn it on, and always softcore:
- Not every achievement is checked every frame like on an emulator. A game started from the DSiRPC launcher has the ones that need it checked every frame on the console (all of them, for a small set); DSiRPC itself checks every frame as many as fit in the eight values the console can record every frame, and the rest about once a second. Achievements about things that last (a flag set, a cup won) work the same either way; ones about split-second moments, when they aren't checked every frame, can unlock late, not at all or, rarely, when they shouldn't.
- RetroAchievements doesn't officially support playing on original hardware. DSiRPC tells it honestly what it is, so it only ever counts these unlocks as softcore.
Unlocks that can't be sent right away (no internet) are kept and sent later.
A game started from the DSiRPC launcher is also checked by the console
itself (it's what makes offline play work). DSiRPC then
leaves the achievements the console checks to it, and checks only the rest.
When DSiRPC hears the console unlock an achievement, that counts right away,
like its own unlocks (the log says by the console's checker), and DSiRPC
tells the console about the ones it unlocked itself, so nds-bootstrap's
in-game menu shows those too.
The overlay window (tray menu > Overlay window) shows your party, and switches to a battle view when a battle starts, in a pixel-art style inspired by the DS games. The battle background follows the DS clock, the location and the weather; Pokémon slide in, flash when hit and sink when they faint; every move gets its "X used MOVE!" line and an animation that fits it (a fist for punches, jaws for fangs, a wave for Surf, a quake that shakes the screen, ...) in its type's colours; stat changes and conditions show on the HP boxes and Pokémon; and the bottom box shows your moves with PP and how effective each one is. Banners pop up for shiny encounters, level-ups, fainting, new badges and achievements.
Pokémon Black and White (US) get a view of their own, in the games' look: the party in the party screen's panels, an achievements panel with your latest unlock and the next one to earn, your trainer, money and the Unova badges, the season, and battles in the games' own style (their HUD, a background with Black and White's detail, the field's weather, the game's clock for day and night, and Gym Leaders, the Elite Four and the Champion named and making their entrance). The view dresses for Unova's seasons (petals, sun rays, falling leaves, snow piling up), shows your Repel steps and the trainers and items left where you are, your badges as polished as on your trainer card, and panels of their own in the Battle Subway, the Battle Institute and the Elite Four's rooms; catches get a "Gotcha!". Discord shows the foe standing on the same turf as the battle view and your trainer walking on the place's turf. It's new and not tried on a console yet (if the memory doesn't look right, they get the game card).
Every other game gets a game card in the same style: its name and how long you've been playing, what you're doing in it (its RetroAchievements rich presence), a progress bar for its achievements with your latest unlock and one still to earn side by side, and how many achievements and points you have. While the console isn't connected, the window says what to do and shows the last game you played.
It draws at the DS's 256x192 and scales up by a whole number, so the pixels
stay crisp. Add it to OBS with Window Capture, or share the window on
Discord. Keys 1-6 change its size, and V opens the party screen
(all six Pokémon with their moves, PP, nature and held item; the window's
title says when it's showing) and goes back again: to the battle during a
battle, otherwise to the main view. A battle starting or ending always goes
back to its own view. For OBS's Chroma Key filter, set
chroma (a colour like 00FF00) in dsirpc.cfg. The sprites are downloaded
the first time they're needed, then kept.
| Problem | Try |
|---|---|
| Nothing on Discord | Right-click the tray icon: its first lines say what DSiRPC sees. The PC and the console must be on the same network, and the firewall must allow DSiRPC on private networks (Windows Security > Firewall > Allow an app: python.exe and pythonw.exe in DSiRPC's python folder). |
| The tray dot is red | Discord isn't running, or there's no Discord application yet: run setup. |
| The launcher can't connect | Check the console's Wi-Fi settings (on a DSi, WPA2 needs connection 4, 5 or 6). |
| Discord stopped after the DSi's lid was closed | That's on purpose: the console turns its Wi-Fi off when the lid closes, because a DSi that sleeps while connected switches itself off. Achievements are still checked and saved. Start the game from the launcher again to reconnect. |
| The launcher says "DSiRPC wasn't found" or "can't be reached" | DSiRPC isn't running, or the firewall blocks it (the same fix as "Nothing on Discord"; the sync uses port 4245). The game still starts; unlocks wait on the SD card until the next sync. |
| "This game has no save file yet" | Start the game once from TWiLight Menu++, then use the launcher again. |
| Two activities on Discord | Another Rich Presence tool (like Vencord's CustomRPC) is still on. |
| A game shows only its name | It has no achievement set yet; the tray menu's RetroAchievements line says why. Run setup while the game runs to pick its set. |
| The in-game menu says "no set loaded" or "another game's" | Start the game with START in the launcher (not Y, and not from TWiLight Menu++): that's what puts its set on the SD card. |
More, including what the console sends and how to read it, is in
docs/DOCUMENTATION.md, section 11.
The log is logs\dsirpc.log in DSiRPC's folder.
For testing achievements without your real progress getting in the way,
DSiRPC takes these flags. Quit it in the tray first, then run it from its
folder in a command prompt: python\python.exe dsirpc.py in a release
download, .venv\Scripts\python.exe dsirpc.py from the source code (add
tray to run it in the tray). The flags combine.
| Flag | What it does |
|---|---|
--dry-run |
Sends nothing anywhere: the Discord presence is logged instead, and nothing goes to RetroAchievements. DSiRPC acts as if your account had nothing unlocked (like --blank-ra), and unlocks waiting on the console stay there (the launcher says so). |
--blank-ra |
Acts as if your RetroAchievements account had nothing unlocked: every achievement is checked, the console gets whole sets, and every unlock is sent (RetroAchievements answers that you already had the ones you had). What's really unlocked stays recorded in ra\cache\unlocked.json. |
--clear-ra |
At the console's first sync, throws away the unlocks waiting on it (nothing is sent) and sends it every set again. Later syncs in the same run are normal. |
For example, python\python.exe dsirpc.py --blank-ra while you collect
test unlocks, then python\python.exe dsirpc.py --clear-ra once to put the
console back to your real state (add --blank-ra to give it whole sets
instead).
To update, unzip the new release over your DSiRPC folder (replace the files
when asked): your settings (dsirpc.cfg) and achievement sets stay. Copy the
new SD card files over the old ones too. To remove DSiRPC, turn off Start
with Windows, quit it, and delete its folder.
Console: dsirpc-launcher.nds connects to Wi-Fi in DSi mode, then starts the
| game you pick with our nds-bootstrap, still connected
v
our nds-bootstrap --boots--> the game
a small memory server in its ARM7 code
answers "read N bytes at X" <--- UDP 4244 ---> PC: DSiRPC (tray)
broadcasts a hello every second reads and decodes the game's state,
checks achievements
| |
v v
Discord Rich Presence overlay window
The launcher also syncs with DSiRPC on port 4245 (UDP to find it, then TCP), for offline play.
The console side stays simple: it only answers "give me these bytes" (and, for offline play, runs the achievement program DSiRPC prepares). Everything else (decrypting the party, working out the location, deciding what Discord shows) happens on the PC, so new features never need a console update. The full technical reference is docs/DOCUMENTATION.md; building and running from the source code is in docs/DEVELOPMENT.md.
- Fix graphical glitches in Pokémon Platinum (for example, the first time the pause menu opens).
- Location artwork for the big image, and more overworld states (running, biking, surfing, browsing the PC). Leads are in docs/research.md.
- Handle WPA2 group-key renewal in game, if your router ever disconnects the console on a schedule.
- Full presence for more games and versions: for now every DS game gets its name, box art and RetroAchievements rich presence (and the overlay's game card), and only Platinum USA Rev 1 gets the full presence and the overlay's party and battle views. Pokémon Black and White (US) now have their own overlay views and Discord presence (new, not tried on a console yet); ordinary trainers' names in battle are still to come.
- Achievements checked every frame, for the timing-sensitive ones: on the console (a set's frame lane) and by DSiRPC (what fits in the console's per-frame record). New, tested on a PC against rcheevos frame for frame, not yet tried on hardware.
- Achievements while playing offline: the launcher keeps the sets on the SD card and syncs unlocks with DSiRPC, and the console checks them in game, saves its unlocks to the SD card, pulses an LED (DSi) and lists them in nds-bootstrap's in-game menu (works on hardware since 2026-10-08; more games to try). Unlock times now come from the console's clock, which is new and not tried on hardware yet.
- More for the overlay: encounter and shiny counters, a Nuzlocke mode, browser-source panels for OBS.
- RetroAchievements: achievements (softcore unlocks are opt-in), sets downloaded by themselves, rich presence on the RA profile.
- One app on the console: the launcher connects and starts the game.
- A Windows download that needs nothing installed.
- Games' own Wi-Fi features don't work while playing through DSiRPC.
- On a DSi, closing the lid turns the console's Wi-Fi off until a game is started from the launcher again (a DSi that sleeps while connected switches itself off). Achievements are still checked and saved for the next sync.
- DSi-enhanced games (Pokémon Black and White, and later) need to run in DS mode (TWiLight Menu++'s per-game settings).
- Pokémon sprites from PokeAPI (sprites repository).
- More sprites used from spriters-resource.com
- Overworld assets by PurpleZaffre.
- nds-bootstrap by DS-Homebrew (GPLv3), which hosts the in-game side.
- BlocksDS and DSWiFi (MIT) for the launcher and the DSi-mode Wi-Fi code; devkitPro's nds-bootloader and NDS Homebrew Menu's bootstub (GPLv2+) for starting the game from it.
- pret/pokeplatinum for struct layouts, the save layout and the name tables.
- RetroAchievements code notes (game 11732) and ProjectPokemon's notable breakpoints for memory addresses.
- pypresence for Discord IPC, pystray for the tray icon, pygame-ce for the overlay.
- rcheevos (MIT) and RetroAchievements' set authors for other games' rich presence; GameTDB for box art and game titles.
DSiRPC's own code is MIT licensed (see LICENSE). The
nds-bootstrap/ folder is GPLv3 (see nds-bootstrap/LICENSE).
launcher/loader/ (devkitPro's nds-bootloader and NDS Homebrew Menu's
bootstub) is GPLv2 or later, and so is the built dsirpc-launcher.nds,
which includes it. The Windows download's licenses folder lists everything
it bundles.
Pokémon is © Nintendo / Creatures Inc. / GAME FREAK inc. This is an unofficial fan project and isn't affiliated with or endorsed by them.