# [Windows]Use Electron to deploy output RPG Maker MV/MZ games
:::danger
![](https://i.imgur.com/XKmDnbq.png)
:::
:::warning
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> This article was translated using "[DeepL Translator](https://www.deepl.com/translator)".
:::
This article will teach you to deploy your RPG Maker MV/MZ games using Electron.
This tutorial will use Windows 10 (1909) operating system.
:::danger
<i class="fa fa-times-circle" aria-hidden="true"></i> Electron does **not** currently support **Windows Vista** and older versions of operating systems.
:::
:::info
**<i class="fa fa-info-circle" aria-hidden="true"></i> Update Info**
**2022/05/03** Update part of the article.
**2022/05/01** Fix some contents of package.json.
**2022/01/04** Add block the feature of capturing screen.
**2021/11/12** Added encrypted content about asar files.
:::
1.First, download Node.js for Windows OS from the following URL and install it on your computer.
https://nodejs.org/en/download/
![](https://i.imgur.com/2OEuO7c.png)
2.After the installation is complete, type `CMD` at the beginning to run the "Command Prompt", and type `node -v` and `npm -v` respectively to check if the installation is successful.
![](https://i.imgur.com/5Xc1hVn.png)
![](https://i.imgur.com/4NezzZ0.png)
3.After creating a folder, and add a new file named “package.json” and edit the file to add the following syntax content.
:::warning
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> After adding the following syntax, remember to remove **//** and the comments that follow.
:::
```json=
{
"name": "RPG_Game", //The project name used for the output.
//It must be alphanumeric and not contain any half-space.
"version": "1.0.0", //Version number.
//The format must be in the numeric format X.X.X.
"description": "This is the Electron Deployment Test.", //File description.
"main": "index.js",
//[RPG Maker MZ]
"chromium-args": "--force-color-profile=srgb",
//[RPG Maker MV]
"js-flags": "--expose-gc",
"build": {
"appId": "com.rpgmaker.game", //Application ID.
//*You can usually enter com.xxxxx.yyyyy in alphanumeric format.
//xxxxx is the English name of your game title.
//yyyyy is the author's/team's name.
"productName": "Game", //Game Title.
"asar": true, //It is recommended to set this item to true if you need to seal the game content...
"afterPack": "./myAfterPackHook.js", // * If you need to use the "asarmor" encryption suite, please make sure to include this parameter.
"win": {
"icon": "icon/icon.ico", //Game icon, the image format is ico format.
//* Use the png to ico online conversion site and place the ico format image in the icon folder.
"target": {
"target": "dir"
}
}
},
"scripts": {
"start": "electron .",
"pack": "electron-builder --dir",
"dist": "electron-builder"
},
"author": "Mirai", //The author's/team's name.
"copyright": "Copyright © 2021 ${author} All rights reserved.", //Copyright Notice.
"devDependencies": {
"electron": "^11.5.0",
"electron-builder": "^22.5.1",
"asarmor": "^2.0.0" // * If you need to use the "asarmor" encryption suite...
}
}
```
:::info
<i class="fa fa-info-circle" aria-hidden="true"></i> If you need to use the "asarmor" encryption suite, create a file called "myAfterPackHook.js" and put the following code into this file and save it in this output folder.
```javascript=
const asarmor = require('asarmor');
const { join } = require("path");
exports.default = async ({ appOutDir, packager }) => {
try {
const asarPath = join(packager.getResourcesDir(appOutDir), 'app.asar');
console.log(`applying asarmor patches to ${asarPath}`);
const archive = await asarmor.open(asarPath);
archive.patch(); // apply default patches
await archive.write(asarPath);
} catch (err) {
console.error(err);
}
};
```
:::
**[Demo]**
![](https://i.imgur.com/F14E5fG.png)
Then use the `cd` command on the "Command Prompt" to specify the path to the folder, and enter the `npm install` command on the "Command Prompt" to install the required package.
:::warning
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Remember that folder names can only be alphanumeric and do not contain a half-line margin. If you need to use a half-line margin, please replace it with a ( _ ).
:::
4.Open the RPG Maker MV/MZ game project and click "File" → "Deployment...", select "Web Browsers / Android / iOS".
When using RPG Maker MV, select "Web Browsers" and then click "OK" to wait for the deployment to complete.
**[RPG Maker MZ]**
![](https://i.imgur.com/ds3WuKk.png)
**[RPG Maker MV]**
![](https://i.imgur.com/FS6qsyO.png)
5.Create an "index.js" file ,and enter the following:
```javascript=
const { app, BrowserWindow, ipcMain, shell } = require('electron');
function createWindow() {
const win = new BrowserWindow({
width: 816, //Screen Width
height: 624, //Screen Height
icon: 'icon/icon.png',
useContentSize: true,
autoHideMenuBar: true,
backgroundColor: '#000000',
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
})
const isTest = false; //Whether it is a test mode.
const testString = isTest ? '?test' : '';
app.allowRendererProcessReuse = false;
win.loadURL(`file://${__dirname}/index.html${testString}`);
if (process.platform !== 'darwin') {
win.setMenu(null);
}
require('electron').ipcMain.on('focusMainWindow', function (e) {
win.focus();
});
require('electron').ipcMain.on('openDevTools', function (e) {
win.webContents.openDevTools();
});
require('electron').ipcMain.on('openExternal', function (e, arg) {
shell.openExternal(arg);
});
//* Required with NekoGakuen_BlockedCapture.js plugin.
require('electron').ipcMain.on('setProtection', function (e, arg) {
win.setContentProtection(arg);
});
};
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
app.quit();
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
```
6.Go to the output folder ,and copy all the files except "package.json" and paste them into the output folder for this of Electron.
**[RPG Maker MZ]**
![](https://i.imgur.com/OgrgQPr.png)
**[RPG Maker MV]**
![](https://i.imgur.com/nFDZU8t.png)
7.Next, we will divide it into two projects and modify some of the contents in the js folder.
**[RPG Maker MZ]**
Modify "main.js", "rmmz_core.js" and "rmmz_managers.js" to the following.
## main.js
```javascript=
isPathRandomized() {
// [Note] We cannot save the game properly when Gatekeeper Path
// Randomization is in effect.
return (
Utils.isNwjs() &&
process.mainModule.filename.startsWith("/private/var")
);
}
```
Replace..
```javascript=
isPathRandomized() {
// [Note] We cannot save the game properly when Gatekeeper Path
// Randomization is in effect.
if (Utils.isElectronjs()) {
return (__filename.startsWith("/private/var"));
} else {
return (Utils.isNwjs() &&
process.mainModule.filename.startsWith("/private/var"));
}
}
```
## rmmz_core.js
```javascript=
Utils.isNwjs = function() {
return typeof require === "function" && typeof process === "object";
};
```
Replace..
```javascript=
Utils.isNwjs = function() {
return typeof require === "function" && typeof process === "object";
};
Utils.isElectronjs = function () {
return window && window.process && window.process.versions && window.process.versions['electron'];
};
```
---
```javascript=
Utils.isOptionValid = function(name) {
const args = location.search.slice(1);
if (args.split("&").includes(name)) {
return true;
}
if (this.isNwjs() && nw.App.argv.length > 0) {
return nw.App.argv[0].split("&").includes(name);
}
return false;
};
```
Replace..
```javascript=
Utils.isOptionValid = function (name) {
const args = location.search.slice(1);
if (args.split("&").includes(name)) {
return true;
}
if (this.isElectronjs()) {
if (process.argv.length > 0) {
return process.argv[0].split("&").includes(name);
}
} else {
if (this.isNwjs() && nw.App.argv.length > 0) {
return nw.App.argv[0].split("&").includes(name);
}
}
return false;
};
```
## rmmz_managers.js
```javascript=
StorageManager.fileDirectoryPath = function() {
const path = require("path");
const base = path.dirname(process.mainModule.filename);
return path.join(base, "save/");
};
```
Replace..
```javascript=
StorageManager.fileDirectoryPath = function () {
const path = require("path");
if (Utils.isElectronjs()) {
const base = path.dirname(__filename);
return Utils.isOptionValid('test') ? path.join(base, "save/") : path.join(base, '../../save/');
} else {
const base = path.dirname(process.mainModule.filename);
return path.join(base, "save/");
}
};
```
---
```javascript=
SceneManager.reloadGame = function () {
if (Utils.isNwjs()) {
chrome.runtime.reload();
}
};
SceneManager.showDevTools = function () {
if (Utils.isNwjs() && Utils.isOptionValid("test")) {
nw.Window.get().showDevTools();
}
};
```
Replace..
```javascript=
SceneManager.reloadGame = function () {
if (Utils.isElectronjs()) {
location.reload();
} else {
if (Utils.isNwjs()) {
chrome.runtime.reload();
}
}
};
SceneManager.showDevTools = function () {
if (Utils.isElectronjs()) {
if (Utils.isOptionValid("test")) {
require('electron').ipcRenderer.send('openDevTools');
}
} else {
if (Utils.isNwjs() && Utils.isOptionValid("test")) {
nw.Window.get().showDevTools();
}
}
};
```
**[RPG Maker MV]**
Modify “rpg_core.js” and “rpg_managers.js” to the following.
## rpg_core.js
```javascript=
Utils.isNwjs = function() {
return typeof require === 'function' && typeof process === 'object';
};
```
Replace..
```javascript=
Utils.isNwjs = function() {
return typeof require === 'function' && typeof process === 'object';
};
Utils.isElectronjs = function() {
return window && window.process && window.process.versions && window.process.versions['electron'];
};
```
---
```javascript=
Utils.isOptionValid = function (name) {
if (location.search.slice(1).split('&').contains(name)) { return 1; };
if (typeof nw !== "undefined" && nw.App.argv.length > 0 && nw.App.argv[0].split('&').contains(name)) { return 1; };
return 0;
};
```
Replace..
```javascript=
Utils.isOptionValid = function (name) {
if (location.search.slice(1).split('&').contains(name)) { return 1; };
if (this.isElectronjs()) {
if (this.isNwjs() && process.argv.length > 0 && process.argv[0].split('&').contains(name)) { return 1; };
} else {
if (typeof nw !== "undefined" && nw.App.argv.length > 0 && nw.App.argv[0].split('&').contains(name)) { return 1; };
}
return 0;
};
```
---
```javascript=
Input._wrapNwjsAlert = function() {
if (Utils.isNwjs()) {
var _alert = window.alert;
window.alert = function() {
var gui = require('nw.gui');
var win = gui.Window.get();
_alert.apply(this, arguments);
win.focus();
Input.clear();
};
}
};
```
Replace..
```javascript=
Input._wrapNwjsAlert = function () {
if (Utils.isElectronjs()) {
var _alert = window.alert;
window.alert = function () {
_alert.apply(this, arguments);
require('electron').ipcRenderer.send('focusMainWindow');
Input.clear();
};
} else {
if (Utils.isNwjs()) {
var _alert = window.alert;
window.alert = function () {
var gui = require('nw.gui');
var win = gui.Window.get();
_alert.apply(this, arguments);
win.focus();
Input.clear();
};
}
}
};
```
## rpg_managers.js
```javascript=
StorageManager.localFileDirectoryPath = function() {
var path = require('path');
var base = path.dirname(process.mainModule.filename);
return path.join(base, 'save/');
};
```
Replace..
```javascript=
StorageManager.localFileDirectoryPath = function () {
var path = require('path');
if (Utils.isElectronjs()) {
var base = path.dirname(__filename);
return Utils.isOptionValid('test') ? path.join(base, 'save/') : path.join(base, '../../save/');
} else {
var base = path.dirname(process.mainModule.filename);
return path.join(base, 'save/');
}
};
```
---
```javascript=
SceneManager.initialize = function() {
this.initGraphics();
this.checkFileAccess();
this.initAudio();
this.initInput();
this.initNwjs();
this.checkPluginErrors();
this.setupErrorHandlers();
};
```
Replace..
```javascript=
SceneManager.initialize = function () {
this.initGraphics();
this.checkFileAccess();
this.initAudio();
this.initInput();
if (!Utils.isElectronjs()) {
this.initNwjs();
}
this.checkPluginErrors();
this.setupErrorHandlers();
};
```
---
```javascript=
SceneManager.onKeyDown = function (event) {
if (!event.ctrlKey && !event.altKey) {
switch (event.keyCode) {
case 116: // F5
if (Utils.isNwjs()) {
location.reload();
}
break;
case 119: // F8
if (Utils.isNwjs() && Utils.isOptionValid('test')) {
require('nw.gui').Window.get().showDevTools();
}
break;
}
}
};
```
Replace..
```javascript=
SceneManager.onKeyDown = function (event) {
if (!event.ctrlKey && !event.altKey) {
switch (event.keyCode) {
case 116: // F5
if (Utils.isElectronjs()) {
location.reload();
} else {
if (Utils.isNwjs()) {
location.reload();
}
}
break;
case 119: // F8
if (Utils.isElectronjs()) {
if (Utils.isOptionValid('test')) {
require('electron').ipcRenderer.send('openDevTools');
}
} else {
if (Utils.isNwjs() && Utils.isOptionValid('test')) {
require('nw.gui').Window.get().showDevTools();
}
}
break;
}
}
};
```
:::info
<i class="fa fa-info-circle" aria-hidden="true"></i> If the above is very complicated, you can also download quick start template directly from the following GitLab.
https://gitlab.com/mmmm748748/rpg_maker_mv_and_mz_electron/-/tree/en_US/
:::
8.Go back to "Command Prompt" and type `npm start` to check if the game can run normally. If the game runs OK, type `npm run dist` to run the deployment output.
9.Finally, after the deployment is finished, you can find the contents of the deployment in the "dist/win-unpacked/" folder and run Game.exe.
### <i class="fa fa-link" aria-hidden="true"></i> Reference Material
https://www.electronjs.org
https://github.com/electron/electron-quick-start
https://qiita.com/RaTTiE/items/63f2e351a93f81bc8039
https://a091234765.pixnet.net/blog/post/402450719-%5Belectron%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98%5Delectron%E5%AE%89%E8%A3%9D%E6%AA%94%E6%89%93%E5%8C%85%E6%94%BB%E7%95%A5%E8%A3%9C%E5%85%85_el
https://www.electron.build
https://www.npmjs.com/package/asarmor
Mirai - Patreon:
https://www.patreon.com/MiraiDiary
Mirai - Twitter(X):
https://twitter.com/Mirai_so_Sad
Mirai - itch.io:
https://miraisosad.itch.io
Mirai - Instagram
https://www.instagram.com/miraisosad/
###### tags: `貓咪學園` `NekoGakuen` `RPG Maker` `RPG Maker MV` `RPG Maker MZ`