A Deep Dive into Embedding Unity WebGL Apps

The basics of embeding a Unity WebGL app. This is probably straight-forward for most people. but you never know; plus this post helps complete my Unity WebGL cookbook.

TL;DR

For anyone who just needs to get to the point, here’s the gist,

<link rel="stylesheet" href="TemplateData/style.css">
<script src="Build/UnityLoader.js"></script>
<script>var gameInstance = UnityLoader.instantiate("gameContainer", "Build/WebHalt.json");</script>
<div class="webgl-content">
    <div id="gameContainer" style="width: 960px; height: 600px"></div>
</div>

Throw that into your HTML’s body. Some names will change depending on the specific name of your project (WebHalt) and the name of the folder you build the project (in this case, also WebHalt). The first parameter should match the id of the div at the bottom. Make sure the exported build folder is uploaded to the server – and all json and js files should be changed to valid locations on the server, and you’re set. It will start up as soon as the page loads.

Here’s an example of that code. (The paths of the *.js and *.json files have been changed to match where they are on this server.)

A screenshot of the WordPress HTML block used to embed the Unity WebGL app above.

Now that the TL;DR is out of the way, for everyone who wants to take a deeper-dive into the subject, enjoy the rest of this post!

First Thing to Notice

When a WebGL project is built from Unity, a folder hierarchy is created with a index.html web page that has sample HTML and Javascript code for how to embed your newly-built app into a web page.

The HTML will look something like this:

<!DOCTYPE html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Unity WebGL Player | WebHalt</title>
    <link rel="shortcut icon" href="TemplateData/favicon.ico">
    <link rel="stylesheet" href="TemplateData/style.css">
    <script src="TemplateData/UnityProgress.js"></script>
    <script src="Build/UnityLoader.js"></script>
    <script>
      var gameInstance = UnityLoader.instantiate("gameContainer", "Build/WebHalt.json", {onProgress: UnityProgress});
    </script>
  </head>
  <body>
    <div class="webgl-content">
      <div id="gameContainer" style="width: 960px; height: 600px"></div>
      <div class="footer">
        <div class="webgl-logo"></div>
        <div class="fullscreen" onclick="gameInstance.SetFullscreen(1)"></div>
        <div class="title">WebHalt</div>
      </div>
    </div>
  </body>
</html>

And let’s strip out all the non-essential parts and talk about what’s left.

<!-- Load the code to intantiate the Unity App loader (the UnityLoader class) and define the UnityProgress function -->
<script src="TemplateData/UnityProgress.js"></script>
<!-- Tell the app to actually download the game and start it. -->
<script>
  var gameInstance = UnityLoader.instantiate("gameContainer", "Build/WebHalt.json", {onProgress: UnityProgress});
</script>
<!-- Where the game will be in the HTML document -->
<!-- Note how the div id matches the first parameter of UnityLoader.instanciate() -->
<div id="gameContainer" style="width: 960px; height: 600px"></div>

All you need is the app loader, a snippet of JavaScript to start the app loader to loader and start your application, and a location in the document where it should be.

The problem with this is that you don’t get the download screen when the app first starts. For that, you’ll need to include the CSS document and wrap your application’s div element in another div element referencing the webgl-content class (defined in the TemplateData/style.css file).

<!-- Some styles. Can be omitted, but is needed if you want the app download progress bar -->
<link rel="stylesheet" href="TemplateData/style.css">

<script src="TemplateData/UnityProgress.js"></script>
<script>
  var gameInstance = UnityLoader.instantiate("gameContainer", "Build/WebHalt.json", {onProgress: UnityProgress});
</script>

<!-- An additional container with the webgl-content class defined in the CSS file to enable the download screen -->
<div class="webgl-content">
    <div id="gameContainer" style="width: 960px; height: 600px"></div>
</div>

Something to also mention is that everything can go in the HTML body element. While the demo will separate JavaScript and CSS referencing into the head of the HTML, it doesn’t have to be. It may be more correct to do so, but sometimes it’s easier not to – for instance, when adding HTML to a WordPress post to embed your application.

Trying to Run it From File?

If you’re not a web developer, the first rude surprise you’ll probably run into is that most web browsers won’t let you just double click that index.html and open that page locally in your browser and preview it. Well, it will, but loading your application will fail. Why? Because that would be too simple. (joking)

When you build your Unity WebGL app, Unity will open the directory for you when it’s finished building. You might be mighty-tempted to just double click the index.html page and have your web browser directly view the file.

The reason is because there are security concerns with running the page locally. It’s nothing personal, browsers just have general security rules and it won’t make an exception for your game. Because technically the page doesn’t actually have the app when it’s first opened, instead what is has is a placeholder for where it eventually will go and JavaScript code to download and run it. The security measures are for JavaScript functions that download the app to the browser. The solution to this is to host the page containing your app in a web server. and access it over the web.

A failure to execute the WebGL app when running the sample page from file instead of from a server.

Here is an excerpt in UnityLoader.js[beautified] of where an error is coming from. Notice the JavaScript error is for the failure to download HTTP content.

...
var t = new XMLHttpRequest;
t.open("GET", r.url, !0), t.responseType = "text", t.onerror = function()
{
    n.print("Could not download " + r.url), 0 == document.URL.indexOf("file:") && alert("It seems your browser does not support running Unity WebGL content from file:// urls. Please upload it to an http server, or try a different browser.")
}, t.onload = function()
{
    var o = JSON.parse(t.responseText);
    for (var a in o) "undefined" == typeof n[a] && (n[a] = o[a]);
    for (var i = !1, s = 0; s < n.graphicsAPI.length; s++)
...

All you need is a simple HTTP file server. If you don’t have a preference and you don’t know of any, I recommend the extremely simple one from AnalogX. If you’re being bare bones about it, you don’t even need PHP or any other kind of server-side scripting, just something that serves files. It’s the browser that’s imposing the restrictions (not the server) and all it wants is to access the page over the web through HTTP. You don’t even have to host a DNS or make the server publicly accessible or make an opening in any firewall; loopback (aka localhost, aka 127.0.0.1) is fine.

Fullscreen Button

In the Unity sample, there is a button that allows the application to be run at fullscreen.

 <body>
    <div class="webgl-content">
      <div id="gameContainer" style="width: 960px; height: 600px"></div>
      <div class="footer">
        <div class="webgl-logo"></div>
        <div class="fullscreen" onclick="gameInstance.SetFullscreen(1)"></div>
        <div class="title">WebHalt</div>
      </div>
    </div>
  </body>

This works by calling the SetFullscreen() function in JavaScript, that was provided by the application.

While optional, you don’t need to implement exiting fullscreen. Unity requests to your browser that it makes the application fullscreen. And as a safety measure, for anything the browser allows to be fullscreen, it adds built in features to exit fullscreen mode, regardless of if you didn’t explicitly implement a way to exit fullscreen in your application. For Chrome, pressing escape will exit fullscreen.

Inline Content

The last thing I want to mention, is the default CSS class webgl-content.

In style.css, .webgl-content has the definition:

.webgl-content {position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%);}

While the simple index.html sample may appear fine, you’ll notice an issue when more content is placed around it.

In the sample index.html, if I place some text and horizontal rules around in,

  ...
  Some text<hr>
  Some text<hr>
  <body>
    <div class="webgl-content">
      <div id="gameContainer" style="width: 960px; height: 600px"></div>
      <div class="footer">
        <div class="webgl-logo"></div>
        <div class="fullscreen" onclick="gameInstance.SetFullscreen(1)"></div>
        <div class="title">WebHalt</div>
      </div>
    </div>
	Some text<hr>
	Some text<hr>
	Some text<hr>
	...
The default CSS style for webgl-content will overlap content.

I don’t know why Unity made the default this way, but to make it inline, just gut out the definition of .webgl-content in the CSS.

/*Old definition */
/*.webgl-content {position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%);}*/

.webgl-content {}
Removing the styles of .webgl-content to make the embedded app layout correctly.

In Conclusion

The Unity WebGL sample is pretty clear cut and easy to understand, but may have some parts that need a bit of explaining. Make sure the Build folder that was compiled is moved to the server, is accessible, and properly referenced in your HTML.

There are generic security restrictions for HTTP download calls in JavaScript that will affect your ability to preview your app when using the browser to open the page from file. Host the page on a server and access it with an http address to satisfy these safety restrictions.

– Stay strong, code on. William Leu

More articles here. More articles about Unity WebGL here.