---
# System prepended metadata

title: '[macOS]Use Electron to deploy output RPG Maker MV/MZ games'
tags: [RPG Maker MV, NekoGakuen, RPG Maker, macOS, 貓咪學園, RPG Maker MZ]

---

# [macOS]Use Electron to deploy output RPG Maker MV/MZ games

:::danger
![](https://i.imgur.com/nP2hqYl.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 the Intel-based macOS 10.15.7 (Catalina) operating system.


:::danger
<i class="fa fa-times-circle" aria-hidden="true"></i> Electron does **not** currently support **OS X 10.10 (Yosemite)** 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 macOS from the following URL and install it on your computer.


https://nodejs.org/en/download/

![](https://i.imgur.com/EaCv8U9.png)




2.After the installation is complete,  for "Spotlight search"  the upper right corner,and Run "Terminal", then type `node -v` and `npm -v` respectively to check if the installation is successful.

![](https://i.imgur.com/B9gUl9k.jpg)


![](https://i.imgur.com/8iGB6gM.png)

:::info
<i class="fa fa-info-circle" aria-hidden="true"></i> Then, because the "Xcode Command Lines Tool" is needed to deploy the game on macOS, type `xcode-select --install` in the "Terminal" to download and install this tool.
:::

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",
    "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.
    "mac": {
      "category": "public.app-category.role-playing-games",
      "icon": "icon/icon.icns", //Game icon, the image format is icns format.
//* Use the png to icns online conversion site and place the icns format image in the icon folder.
      "target": {
        "target": "dir",
        "arch": "universal" //When "universal" is specified, it is compatible with both x64 (Intel) and arm64 (Apple Silicon).
      }
    }
  },
  "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/LoHs6xj.png)

Then use the `cd` command on the "Terminal" to specify the path to the folder, and enter the `npm install` command on the "Terminal" 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/opxJ4ls.png)


**[RPG Maker MV]**

![](https://i.imgur.com/ihLI1Mx.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 gametitleString = "Game Test"; //Game Title

    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);
    } else {
        var { Menu } = require('electron');

        var menu = Menu.buildFromTemplate([
            {
                label: 'Electron',
                submenu: [
                    {
                        label: `About ${gametitleString}`,
                        selector: 'orderFrontStandardAboutPanel:'
                    },
                    {type: 'separator'},
                    {
                        label: `Hide ${gametitleString}`,
                        accelerator: 'Command+H',
                        selector: 'hide:'
                    },
                    {
                        label: 'Hide Others',
                        accelerator: 'Command+Alt+H',
                        selector: 'hideOtherApplications:'
                    },
                    {
                        label: 'Show All',
                        selector: 'unhideAllApplications:'
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: `Quit ${gametitleString}`,
                        accelerator: 'Command+Q',
                        click: function() { app.quit(); }
                    }
                ]
            }
        ]);

        Menu.setApplicationMenu(menu);
    }
    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/KWmEV1y.png)


**[RPG Maker MV]**

![](https://i.imgur.com/tf5tac8.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/MiraiSoSad/rpg_maker_mv_and_mz_electron/-/tree/en_US
:::


8.Go back to "Terminal" 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/mac-universal/” folder and run Game.app.

:::info
<i class="fa fa-info-circle" aria-hidden="true"></i> If the error message "Please move the Game.app to a different folder." pops up on the game screen when you first run the game, you can create a folder and move Gamp.app to this folder and run the game again.
:::


### <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` `macOS` `RPG Maker` `RPG Maker MV` `RPG Maker MZ`