As of Feb 2023, itch.io supports SharedArrayBuffer on Firefox, so this document should be unnecessary.
Itch.io has recently implemented the ability to use SharedArrayBuffer on its site, which means you can export games with Threads enabled for HTML5. You can learn more about this here. This is great for Godot, as it helps to improve/fix the sound laggyness that sometimes occurs in web builds. It is also now required for Godot 4.
Unfortunately, the current implementation only works on Chrome. If you just enable it normally, your Godot game will only run on Chrome and will fail to load on some other browsers like Firefox. There are a couple work-arounds to this: you can pop out the game into a new window, or you can include a fallback wasm that doesn't have threads enabled.
The first, and easiest, option is to just pop out the game into a new tab when it starts. This will break it out of the iframe, which will allow Firefox to enable SharedArrayBuffer without a problem. This is also the only choice if using Godot 4, which does not have a build that works without SharedArrayBuffer.
Just add the following to the "Head Include" section of your export:
<script>
if (!window.SharedArrayBuffer && location.host == 'html.itch.zone') {
let id = location.pathname.split('/')[2];
let url = '//itch.io/embed-upload/' + id + '?color=303333';
window.open(url);
window.addEventListener('load', () => {
document.getElementById('canvas').remove();
document.getElementById('status').innerHTML = '<button type="button" onclick="window.open(\'' + url + '\')">Play</button>';
document.getElementById('status').style.visibility = 'visible';
});
}
</script>
This will check if SharedArrayBuffer is available, and if not, it will pop out into a new tab. This allows Firefox to enable SharedArrayBuffer support because it's no longer embedded in the iframe.
When you upload your game to itch.io, enable SharedArrayBuffer support in the "Embed options" section (it says SharedArrayBuffer support — (Experimental) This may break parts of the page or your project. Only enable if you know you need it.
).
That should be all you need to do! If you run the game in Chrome, it will run normally. If you run it in Firefox, it will pop open a new tab instead and run there. This should also be future-proof, so if Firefox starts working on itch.io normally, it will not pop-out the window anymore.
This method will not work with Godot 4, which requires SharedArrayBuffer (it does not have a non-threads build).
This is the fallback method. By including both wasm versions in the zip, you set up the Javascript to choose the correct one based on whether SharedArrayBuffer is available. It will fall back to the Regular non-thread version if SharedArrayBuffer is not available. This method should also be compatible with future changes, so if SharedArrayBuffer starts to work on Firefox, it should automatically work with no changes needed.
First, export your game twice into the same folder, once as Regular
and once with Threads
. This document will assume you've exported the Regular
version as game.html
and the Threads
version as game_threads.html
.
You can go into the export folder and delete the game_threads.pck
file, the game_threads.html
file, and any game_threads*.png
files (but leave the other game*.png
files).
Start by renaming game.html
to index.html
, which is required by itch.io. This also allows you to export again later without overwriting the changes we're about to make to index.html
.
Now open your index.html
file in a text editor (I usually use Notepad++). Look for this line, which should appear a little over halfway down:
<script type='text/javascript' src='game.js'></script>
You need to delete this line entirely.
Now the very next line should look like this:
<script type='text/javascript'>//<![CDATA[
You will need to add some code after that, so that your file now looks like this:
<script type='text/javascript'>//<![CDATA[
const THREADS = "SharedArrayBuffer" in window;
if (THREADS) console.log('SharedArrayBuffer is available!');
let script = document.createElement('script');
script.setAttribute('src', THREADS ? 'game_threads.js' : 'game.js');
script.addEventListener('load', function() {
This code will selectively load the correct Javascript file based on whether SharedArrayBuffer is available in the browser.
Now, the next line should currently look something like this:
const GODOT_CONFIG = {"args":[], "canvasResizePolicy":2, "executable":"game",
"experimentalVK":false, "fileSizes": {"game.pck":8608208, "game.wasm":14301008},
"focusCanvas":true, "gdnativeLibs":[]};
We need to modify this line to use the correct wasm based on whether SharedArrayBuffer is available. We will also specify the pck file, so that we don't need to include both versions in the zip file later. Change it to look something like this:
const GODOT_CONFIG = {"args":[], "canvasResizePolicy":2, "executable":THREADS?"game_threads":"game",
"mainPack":"game.pck", "experimentalVK":false, "fileSizes":
{"game.pck":8608080, "game.wasm":14301008, "game_threads.wasm":14620719},
"focusCanvas":true, "gdnativeLibs":[]};
You will want to make sure those file sizes are correct for your own pck and wasm files. The wasm sizes in this example are from 3.5.beta4, and will be different if you use a different version. You can either find them in your file system, or open your other html files and copy and paste the sizes from there. Also, be sure to update the pck filesize if you make changes and re-export later!
Now, scroll down to the end of the file, where you will find something like this:
})();
//]]></script>
We're just going to add a bit of extra code so it looks like this:
})();
});
document.body.appendChild(script);
//]]></script>
We're now done with the edits!
When selecting which files to put into the zip file, you need to make sure to include:
- The
index.html
we just edited game.pck
- Both
.wasm
files - Every
.js
file - The
game*.png
files (though you shouldn't need to include thegame_threads*.png
files)
You do not need to include game_threads.pck
, as it is the same as game.pck
(this should have been deleted in step 2). You also do not need to include the other .html
files.
Go ahead and upload your zip file to itch.io. In your Edit project
page, be sure to enable SharedArrayBuffer support in the Embed Options section (it says SharedArrayBuffer support — (Experimental) This may break parts of the page or your project. Only enable if you know you need it.
). Be sure to test in both Chrome and other browsers to make sure it loads correctly.
If you make changes to your game, you should only need to export the Regular
version, as the wasm
file for the Threads
versions should still be in your export folder. You should also go into the index.html
file and update the file size for the new pck
file. As long as you continue to export as game.html
(or whatever you choose) and not index.html
, your changes should remain intact so you do not need to do them again.
If you choose to change Godot versions, you will of course need to do both exports again to get the new wasm files.
Be sure to read the information from itch.io regarding this feature. It adds a lot of browser security restrictions that may affect your game, so you will want to test thoroughly. In particular, if you are trying to download resources from other domains, those may fail unless they are set up correctly.
For the record, leaf from itch.io got the domain enabled for Firefox's Origin Trial for the
COEP:credentialless
feature which itch.io uses when enabling the experimental SharedArrayBuffer support: https://wiki.mozilla.org/Origin_TrialsSo projects hosted on itch.io with SharedArrayBuffer enabled should work fine on Firefox now too.