How To Port Your HTML5 Game to Steam

A few months ago I decided to port one of my game to steam. It was obvious that most of my games aren’t worth uploading on steam. This is normal I think because all of them are web games developed less than a month. The most detailed game I developed in my life is Rookie Bowman. I spent part time 3 months on it, I developed it something like 3.5 years ago. If I am not misremembering, it was the first game I developed with Phaser.

Well enough history I think, let’s focus on how I ported the game to steam. As I mentined above I developed my game with phaser but you can use any framework. The steps should be identical. As a first step we need a way to port our HTML 5 game to executable file. For this you can either use Electron.js or NW.js. I decided using Electron, I have heard about it in the past so it seems more reliable to me. So, this tutorial focuses on electron.

Before starting using Electron.js you should install Visual Studio and a few packages. (This will be necessary when we try to use steam SDK).

After installing Visual Studio, you should open Visual Studio Installer (Tools > Get Tools and Features). You need to install Phyton Development, C# and Visual Basic Roslyn compilers, C++ 2019 Redistributable MSMs. I am not sure does all of this necessary but I got weird errors before installing all of these. Here are the pictures of what you need to install:

Installing Electron

Follow the quick start tutorial to prepare your electron project. You should follow all the steps in the tutorial. Once you are done with it, copy your game to www folder, make the necessary changes like renaming your main html file as index.html. And make sure you are loading the correct html file.

mainWindow.loadURL('file://' + __dirname + '/www/index.html');
Code language: JavaScript (javascript)

At this step, when you run npm run make you should be able to play your game from the exe file located at the out>gameName>gameName.exe. If your game doesn’t start or you get an error you should check the quick start guide. You are probably did something wrong. You can also ask me on the comments.

Here is a few tips for the electron:

-This is the config file I used in Rookie Bowman. The icon I use is 512×512 png file. I will mention about the preload.js file soon. The others are self explaining I think, like the fullscreen, frame etc.

mainWindow = new BrowserWindow({ width: 800, height: 600, frame: false, icon: __dirname + '/build/icon.png', fullscreen: true, titleBarStyle: 'hidden', webPreferences: { nodeIntegration: true, preload: path.join(__dirname, 'preload.js') } });
Code language: JavaScript (javascript)

-To open the console panel in the electron environment you should use the code below. It is the normal chrome console we use day to day.

mainWindow.webContents.openDevTools();
Code language: CSS (css)

-preload.js is a file that helps to communicate between electron and our game code. Normally you can’t reach window object or any other code inside electron. To achieve the communication between electron and our game we use preload.js. I use this mostly for saving, loading the game, steam achievements etc.

To achieve this, you should import ipcMain in your main.js file(it is the file where you initialize electron)

const { ipcMain } = require('electron');
Code language: JavaScript (javascript)

Then you can receive messages

ipcMain.on('message', (event, arg) => { console.log(arg); });
Code language: JavaScript (javascript)

To send a message we use

mainWindow.webContents.send('message', "hello");
Code language: JavaScript (javascript)

That’s all for the main.js file, now we will implement a similiar logic in preload.js file. This time we will import ipcRenderer. Open preload.js file and type

const { ipcRenderer } = require('electron')
Code language: JavaScript (javascript)

Now we can send a message with

ipcRenderer.send('message', {name:"skor",value:1});
Code language: JavaScript (javascript)

And we can receive a message similiarly

ipcRenderer.on('loaded', function (evt, message) { console.log(message); });
Code language: JavaScript (javascript)

Now we can send a message from our game to preload.js. As you can see the preload.js is some sort of bridge between our game and electron. Here is how you do it

const { contextBridge, ipcRenderer } = require('electron') contextBridge.exposeInMainWorld( 'electron', { sendMessage: (name, value) => { ipcRenderer.send('message', {name,value}); }, anotherFunction: () => { } } )
Code language: JavaScript (javascript)

Now in your game code you can call these functions

window.electron.sendMessage("name", "message");
Code language: JavaScript (javascript)

That’s all for the preload.js I think. One last thing is you can reach the window object in preload.js file.

Implementing Steam SDK

For me the most difficult part of porting the game to steam was adding the SDK. There is an npm package named greenworks, we will use it to add steam SDK. Thanks to greenheartgames, without such a package I probably won’t be able to port my game to steam.

You can check the steps for NW.js here. The same steps apply for the electron version. But the prebuilt binaries are out of date. You should build your own binaries. This step is still confusing me 😀 I am not exactly sure how I managed to do it but I will try my best to explain the steps I follow. The phyton and C++ installation was necessary for this step. So, if you didn’t install them you should install them now. If you are on mac, you should install Xcode too. I found these steps from the github issues here. It may help you too.

-You need to install electron quick start again in another folder. Same as we did before.

-Install greenworks with this parameters npm install –save –ignore-scripts git+https://github.com/greenheartgames/greenworks.git

-Download the latest Steamworks SDK from your steam dashboard. Copy the SDK files to node_modules/greenworks/deps and rename the sdk folder as steamworks_sdk.

-Install electron-rebuild package by running npm install –save-dev electron-rebuild

-And then run it node_modules/.bin/electron-rebuild

Now you should see the binaries at node_modules>greenworks>build>Release folder. Just copy all of the files to our project. Create a folder in your project named greenworks. Under that folder create another folder named lib and copy all of the files there. You can also use the files I generated. You can download them here. There may be some unnecessary files but I just copied them all 😀

Now if we went back to our electron code here is how you initialize steam SDK

let greenworks = require('./greenworks/greenworks'); if (greenworks.init()){ }
Code language: JavaScript (javascript)

Now you can use greenworks to communicate with steam. Here are some of the functions I used in my game

////activate steam overlay greenworks.activateGameOverlay("Friends"); greenworks.activateGameOverlay("Community"); greenworks.activateGameOverlay("Settings"); greenworks.activateGameOverlay("Achievements"); greenworks.activateGameOverlay("Stats"); greenworks.activateGameOverlay("OfficialGameGroup"); ///unlock achievement greenworks.activateAchievement("someAchievement", ()=>{ console.log("achievement unlocked!"); }, (error)=>{ console.log(error); } );
Code language: JavaScript (javascript)

There is a one little thing about the steam overlay screen, it doesn’t work until you add this code in main.js file

var os = require('os'); if (os.platform() === 'win32' && parseInt(os.release().split('.')[0]) >= 8) { app.commandLine.appendSwitch('in-process-gpu'); }
Code language: JavaScript (javascript)

The if condition is added because in-process-gpu crashes on windows 7 as far as I heard.

That’s all I think. Let me know if you manage to port your game to steam and whether this little guide help you or not.

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top