TL;DR: I built an external mod manager in Electron that intercepts asset requests and swaps them with NSFW versions from a local folder before they hit Phaser 3 or React. No NSFW content baked into the Steam build, and no code changes required to add new mods. Open source repo and code snippets below.
Hi r/nsfwdev,
I’ve been working on Desire's Burgers — a VN + cooking + rhythm game — since Nov 2024.
To be completely honest, after looking at the current state of the indie market, I got a bit discouraged. I decided to pivot and add an external NSFW patch to increase the game's chances of success.
Since this is my first PC game, I wanted to stick to what I know. I’ve been coding in JS for 19 years, so instead of fighting the learning curve of a new engine, I went with Phaser 3 + React + Electron. It’s fast, familiar, and perfect for 2D.
The Goal: Keep the base game 100% SFW
I didn't want any NSFW assets baked into the vanilla Steam build. I needed a lightweight patch that only swaps assets on the fly.
I created an open-source mod installer that simply drops files into %userData%/DesireBurgers/mods/<modId>/assets/... (mirroring the game’s internal folder structure).
On startup, Electron scans that folder, builds a map of overrides, and whenever the game loads an asset, it asks: "Hey, is there a mod file for this path?"
Here is how I handled the logic across the stack:
1. Electron — Resolve the asset or fallback to vanilla
JavaScript
// main process
ipcMain.handle("get-assets-from-mods", (_event, assetPath) => {
const assetMap = modManager.getUniqueAssetMap();
// mod stores: rhythmic/scenes/day2.scene.json
// game asks: assets/rhythmic/scenes/day2.scene.json
const found = assetMap[assetPath.replace("assets/", "")];
const finalPath = (found?.fullPath || assetPath).replace(/\\/g, "/");
if (path.isAbsolute(finalPath)) {
return `file://${finalPath}`; // mod hit
}
return finalPath; // vanilla fallback
});
Basically: if the mod folder has the exact same relative path, serve that file. If not, serve the vanilla game asset.
2. Phaser 3 — The Rhythm Scenes
Each rhythm track consists of audio, a chart, and a scene JSON. All three pass through the mod resolver before hitting the Phaser loader:
TypeScript
const song = await window.electronAPI.getAssetsFromMods(`assets/audio/ddr/${track.audioFile}`);
const chartUrl = await window.electronAPI.getAssetsFromMods(`assets/rhythmic/charts/${chartFileName}`);
const sceneSpec = await window.electronAPI.getAssetsFromMods(`assets/rhythmic/scenes/${track.sceneFile}`);
this.load.audio("song", song);
this.load.json("chart", chartUrl); // notes / timing
this.load.json("sceneSpec", sceneSpec); // stage / anims / timeline
Every image or spritesheet referenced inside the scene JSON also goes through this check. This means a modder can replace the entire stage background and animations without touching a single line of gameplay code.
3. React — The Visual Novel (VN) Images
For the UI and VN segments, I wrote a custom hook that does the exact same check:
TypeScript
export function useModdedAsset(assetPath: string, defaultPath: string) {
const [asset, setAsset] = useState(defaultPath);
useEffect(() => {
(async () => {
if (!window.electronAPI?.getAssetsFromMods) {
setAsset(defaultPath);
return;
}
const fromMod = await window.electronAPI.getAssetsFromMods(assetPath);
setAsset(fromMod || defaultPath);
})();
}, [assetPath, defaultPath]);
return asset;
}
// usage
const src = useModdedAsset(spriteUrl, spriteUrl);
<img src={src} />
Expanding Gameplay via JSON
Because the mod can swap JSON files, it can actually change game logic without changing source code.
For example, a modded rhythm scene JSON can enable a freeMode flag. After the song ends, if that flag is detected, the game unlocks a post-scene where the player can adjust animation speed and loop it indefinitely.
What the patch currently supports:
- Full VN image replacements
- Rhythm charts & logic (via JSON)
- Stage assets (spritesheets, backgrounds, SFX)
If anyone else is building games with web tech (Phaser/Electron) and trying to figure out modding architecture, I'm happy to answer any questions!
Mod Github: https://github.com/partyhardio/desireburguers-mod-installer
Game: Desire's Burgers
P.S. A quick note on the title ("no AI involved"): I want to clarify that I’m not anti-AI at all! When I built this modding architecture back in 2024, the AI coding tools we have today either didn't exist or I just wasn't aware of them. I actually only started integrating AI into my workflow recently in 2026. Full disclosure: I even used AI to help me polish the English and structure of this very Reddit post (I can share screenshots of my original chaotic draft if anyone wants a laugh 😂). I just wanted to point out that this specific asset-swapping system was hand-coded the old-fashioned way.