This BizHawk Lua script + Node.js bridge allows Neuro-sama (the AI VTuber) to play Pokémon Platinum, by putting her in control of fights. A human player is still needs to navigate outside of battle.
- BizHawk 2.9+
- Node.js (v18+)
- A running Neuro API server (localhost:8000 by default)
- Pokémon Platinum ROM (U version works best)
Place everything in your ROM directory:
Pokemon Platinum/
├── NeuroPlaysPlatinum.lua
├── NeuroPlatinum.lua
├── neuro-bridge.js
├── neuro_inbox/ <- created automatically
├── neuro_outbox.txt <- created automatically
└── your_rom.nds
Open a terminal in the folder and run:
npm install
node neuro-bridge.jsYou should see:
Neuro bridge RUNNING
Connected to Neuro server
- Open BizHawk -> Load Pokémon Platinum (U)
- Tools -> Lua Console
- Script -> Open Script -> select
NeuroPlaysPlatinum.lua
In NeuroPlatinum.lua (line 10), you can configure how items are tracked during battles:
local SMART_ITEMS = true -- or falseTwo modes available:
- How it works: Scans items once at battle start, tracks usage internally
- Pros:
- More efficient (no repeated memory scans)
- Cleaner action registration (only updates when items actually used)
- Less spam in logs
- Cons:
- If items change externally (bag manipulation glitches), won't detect until next battle
- Best for: Normal gameplay, production use
- How it works: Re-scans items from game memory every turn
- Pros:
- Always accurate to actual game state
- Detects external item changes immediately
- Cons:
- More memory reads per turn
- More action re-registration spam
- Best for: Debugging, testing edge cases
Both modes use the same dynamic enum system that prevents Neuro from selecting invalid item IDs. The only difference is when the item lists are updated.
Click "Neuro: ACTIVE" (green) or "Neuro: PAUSED" (red) in the side panel to pause/unpause Neuro's decision-making during battles. Useful for:
- Taking manual control temporarily
- Preventing Neuro from making decisions during cutscenes
- Testing specific battle scenarios
A red "[DEBUG] Force End Battle" button appears in the side panel only during battles. Click it to manually trigger battle cleanup if:
- Battle state gets stuck (e.g., after a crash/reload)
- Neuro thinks a battle is active when it's not
- You need to reset action registrations
What it does:
- Calls
neuro:onBattleEnded()to unregister all battle actions - Resets
battleState, turn counters, and memory flags in Program.lua - Clears battle tracking variables
When to use: Only when things break! Normal battle endings are handled automatically.
Huge thanks to these projects without which this would’ve been impossible:
- Ironmon-Tracker by besteon – the absolute gold standard for NDS Pokémon data reading. This project is built directly on top of its battle parsing and event system.
- Neuro-sama & Vedal – for creating (and being) the most chaotic, brilliant AI VTuber on Earth.
- The Neuro API team – for the websocket system that interfaces with Neuro-sama.
- BizHawk Team – for an actually easy to code in emualator.
- Code in this repository is provided under the MIT License (see
LICENSE). - Third-party components are listed with their licenses in
NOTICE(including Inifile under BSD-2-Clause, json.lua under MIT, and Ironmon-Tracker under MIT). - No ROMs, copyrighted Pokémon assets, or external tools (e.g., BizHawk) are bundled in this repository; users must provide their own copies.