Drawize

blog

How to bring an HTML5 game to Steam

It is our short story on making Drawize available on Steam. We hope it will help other developers who might be trying to do the same with theirs HTML5 games

Published: 02/24/2022

Drawize became quite popular in the five years of its existence; over 4 million people made more than 50 million drawings through our game. We are proud of that and decided to make something big to celebrate. We decided to put Drawize on Steam!

If you would like to give it a try, you can get it for $6.99 on Steam here

Why was it challenging?

Drawize is an HTML5 browser game, and in its five years of existence, it has grown massive. There are many features and quite a lot of code; rewriting it as a native application would require a lot of work, introducing new bugs, and requiring a lot more time to test and fix them all.

On the other hand, there is no official Steam support for HTML5 applications, and we wanted to have propper Steam integration, including Steam overlay, achievements, and matchmaking. We have found Greenworks library, a Node.js addon that brings Steamworks API to javascript. It is good, but quite old and with some caveats.

What libraries did we use?

We experimented with various versions and found this combination working fine, including Steam Overlay on most systems.

  • Electron v16.0.2
  • Greenworks v16.0.0-alpha.1 (Electron prebuilt node modules are available here: Greenworks prebuilt libs)
  • Steamworks 1.5

NOTE: we released only for Windows 64 bit systems as this covers more than 95% of all Steam players (Steam usage stats). We may consider releasing to more systems in the future, but we decided to focus on the most used one in the beginning since there are already challenges to make it work as smoothly as possible.

Game architecture

We made Drawize in the first place to be easily packaged as a standalone product: it is a single-page app with all routing done in JS, backend communication is all done through messages using a single WebSocket endpoint. Because of that, creating an Electron app out of it was simple:

  • Create a new electron app.
  • Copy all the code to the project root.
  • Make main.js create new Browser Windows and load our root HTML file into it.

In reality, it was a little more complex than that; we had to correct some paths change how some files are loaded and how external windows like Facebook login or file downloads are handled. But all that was not anything to worry about.

Steam integration

We have seen some examples calling Greenworks code directly from the web app, but that is not working fine in a newer version of Electron. We used another approach; all Greenworks code lives in the main Node.js process, and all Steam integration is done there.

Since we need to call some of that code in response to frontend action, we used Electrons IPC to send messages back and forth between the web app and Node backend. For example, when the user wants to invite his friends into the game, we send a message to the Node app, which then invokes Steam's Invite dialog.

Use --in-process-gpu flag for Chromium

After some experimenting, we found out using this flag will increase the number of players who will actually see the overlay.

Integration problems

Steam Overlay

The main issue is around Steam Overlay - it is part of the Steam interface rendered over the main game window, and it is the primary source of the app crashing randomly.

We noticed overlay is not rendered on some systems, and it is a problem for us: if there is no overlay, some game functionalities look broken. The biggest problem was with the friend invites, the player clicks the invite button, and nothing happens.

After quite some time, we figured out how to force Overlay to show, add --ignore-gpu-blacklist to chromium launch command. However, later we found out some GUP-s were not blocked for no reason :( Steam overlay renders on all systems with that flag on, but the game crashes randomly. So, it was time to ditch that option..

In the end, we have to accept the fact that Steam overlay will not render for all users. Our workaround for that was to reimplement some of the features of that overlay in our UI. We did that for friend invites; when the user clicks the invite button, we listen for an overlay-shown event, and if it is not fired in a reasonable time, we consider the overlay is broken. Then, we use other API functions to get the user's friend list, show that list in our interface together with invite buttons, and invite users again through the Greenworks friends API.

Overlay rendering glitching

It is a known issue described in Greenworks docs - if you don't repaint the screen constantly while the overlay is visible, it will not render correctly. So, we added two small HTML5 canvases in the top-left and bottom-right corner of the screen, and we repaint them with transparent color on each requestAnimationFrame. (this is CPU intensive, so we do that only when we expect overlay is visible)

Fetching player's avatar

When fetching the avatar using Greenworks API, we always receive just an empty image. Our workaround was to call our backend and fetch the avatars using Steam Publisher Web API.

Conclusion

It was not easy to make it work, we had to invest a lot of time to make it playable, but as it is evident from the article, it is far from perfect. We hope better integration support for HTML5 games will emerge in the future, but we want to thank a lot Greenheart games for making the Greenworks library - without it, we would not be able to release the game on Steam.

We wish a lot of luck to other developers who might take an approach similar to ours. And, if you find a better solution, please do share your story :)