Doom: GTM edition!
The classic 1993 video game Doom has had an amazing life over the last 30 years. Not only are there people still adding new levels via offical add-ons, but the modding community is going strong. For example, check out Beautiful Doom HD!
The other side of the Doom fandom lies in porting the game to all sorts of weird and unlikely screens. It has been ported to a pregnancy test, a graphical calculator, a MacBook Pro touch bar, and even on a tractor. Someone has even got Doom running inside of Doom itself, because why not.
My skills lie in Google Tag Manager (GTM), so I thought I’d give it a go to see how I can get Doom running on any website. I also used the Konami Code to hide it on a web page, so only those who know can find and play it!
Give it a go youself by typing in the Konami Code (↑↑↓↓←→←→BA) on this page or on our homepage!
Custom HTML tag
Below is the final code for the Custom HTML tag I used. It works for our site, but bear in mind it may need some tweaking if it doesn’t work for yours right away.
<script src="https://js-dos.com/6.22/current/js-dos.js"></script>
<style>
canvas {
width: 100%;
height: 100%;
margin: auto;
padding: 0;
}
.dosbox-container {
width: 640px;
height: 480px;
margin: auto;
padding: 0;
}
#controls-heading, #controls-list {
padding-left: 50px;
}
</style>
<script type="text/javascript">
var els, i, len, title;
var konamiCode = '38,38,40,40,37,39,37,39,66,65';
var keyPresses = [];
var checkKonami = function (e) {
keyPresses.push(e.keyCode);
if (keyPresses.slice(keyPresses.length - 10).join() === konamiCode) {
runKonami();
}
};
var runKonami = function () {
console.log('konami code activated!');
dataLayer.push({
'event': 'doom_launched'
});
// Create new site section
var doomSection = document.createElement('section');
doomSection.setAttribute('id', 'doomSection');
// Create and append dosbox container
var dosboxContainer = document.createElement('canvas');
dosboxContainer.setAttribute('id', 'jsdos');
doomSection.appendChild(dosboxContainer);
var div1 = document.createElement('div');
div1.setAttribute('class', 'row no-gutters');
doomSection.appendChild(div1);
var div2 = document.createElement('div');
div2.setAttribute('class', 'col-md-7 left-fullwidth-block white-bg my-auto ');
div1.appendChild(div2);
var div3 = document.createElement('div');
div3.setAttribute('class', 'content-center');
div2.appendChild(div3);
// Create and append controls list
var controls = ["Move: UP, DOWN, LEFT, RIGHT", "Use: W", "Fire: S", "Speed on: SPACE", "Strafe on: ALT", "Strafe: A, D"];
var controlsHeading = document.createElement('h3');
controlsHeading.setAttribute('id', 'controls-heading');
controlsHeading.innerText = 'Controls';
var controlsList = document.createElement('ul');
controlsList.setAttribute('id', 'controls-list');
for (var i = 0; i < controls.length; i++) {
var item = document.createElement('li');
item.appendChild(document.createTextNode(controls[i]));
controlsList.appendChild(item);
}
div3.appendChild(controlsHeading);
div3.appendChild(controlsList);
// Create and append Fullscreen button
var doomFullscreenBtn = document.createElement('button');
doomFullscreenBtn.setAttribute('id', 'fullscreenBtn');
doomFullscreenBtn.setAttribute('onclick', 'ci.fullscreen()');
doomFullscreenBtn.innerText = 'Fullscreen';
div3.appendChild(doomFullscreenBtn);
// Inject section
document.querySelector('body > main').prepend(doomSection);
// Run dosbox and extract + load DOOM
Dos(document.getElementById("jsdos"), {
wdosboxUrl: "https://js-dos.com/6.22/current/wdosbox.js",
// cycles: 1000,
// autolock: false,
}).ready(function (fs, main) {
fs.extract("https://js-dos.com/cdn/upload/DOOM-@evilution.zip").then(function () {
main(["-c", "cd DOOM", "-c", "DOOM.EXE"]).then(function (ci) {
window.ci = ci;
});
});
});
};
document.addEventListener('keyup', checkKonami);
</script>
Code language: JavaScript (javascript)
Breaking down how it works though, the first piece of HTML that we need is the js-dos library (we’ve used v6.22):
<script src="https://js-dos.com/6.22/current/js-dos.js"></script>
Code language: JavaScript (javascript)
Following this, the next piece of HTML will be the Konami Code example from Simo’s blog (see useful links below). This will set up the necessary mechanisms for logging the keypresses and checking their keycode values to see if they resemble the same ones as the Konami Code.
The next part is to replace the code within the runKonami()
function declaration. This will be where the Dosbox emulator will be injected into the page.
In order to proceed, an element needs to be referenced on the page. This can either be an existing element or a brand new one can be created. For our website, a brand new section is built using JavaScript utilising document.createElement()
commands and then prepended to the beginning of the body using Element.prepend()
.
Now that an element on the page is available, the Dosbox emulator can be initialised. To do this, see the link to the js-dos v6.22 examples below. However, the following key changes (highlighted) were made.
1) The first argument in the Dos()
command points to the element that will hold our emulator:
Dos(document.getElementById("jsdos"), {
wdosboxUrl: "https://js-dos.com/6.22/current/wdosbox.js",
cycles: 1000,
autolock: false,
})
Code language: JavaScript (javascript)
2) This points to the hosted version of DOOM available on a js-dos.com CDN. This could be replaced with a different game ROM if you like:
fs.extract("https://js-dos.com/cdn/upload/DOOM-@evilution.zip")
Code language: JavaScript (javascript)
3) These are the MS-DOS commands that we need the emulator to execute after it has finished extracting the ROM (navigate to the DOOM directory and run DOOM.EXE):
main(["-c", "cd DOOM", "-c", "DOOM.EXE"])
Code language: JavaScript (javascript)
Trigger
This new Custom HTML tag needs a trigger. The tag would need to be executed on one of the page load triggers, either DOM Ready at the earliest, or Window Loaded at the safest. This is to ensure that the page is ready to have its visible features changed.
Note: If possible, try to restrict the trigger to fire on either specific pages, or the presence of specific page elements.
Hit publish, then give it a go! Here is what it looks like on our website:
Try it out for yourself on our homepage or this blog page!
Google Analytics tracking
Of course I wanted to track how many times the Dosbox emulator was initialised, so I added a data layer push within the runKonami()
function:
var runKonami = function () {
console.log('konami code activated!');
dataLayer.push({
'event': 'doom_launched'
});
// some other stuff
};
Code language: JavaScript (javascript)
Then set up your trigger in GTM based on the dataLayer event name you’ve used:
And then set up your GA event tag using the trigger from the previous step:
We’ve used the GA4 event tag here, but you can trigger any tag from this dataLayer push.
References
Adding The Konami Code To Your Site via GTM (by Simo Ahava)
https://www.simoahava.com/gtm-tips/add-konami-code-to-your-site/
Simply follow the instructions in setting up the Custom HTML tag. The example included will reverse any of the text in an <h2> element, but the contents of the runKonami() function can be changed to run any arbitrary JavaScript code.
DOOM with js-dos example
The above example uses an obsolete version of js-dos (This version worked fine locally, but only loaded a grey square on the Measurelab site, switched to v6.22 – see below).
The source code example imports a locally sourced DOOM rom file in an upload/ directory. I instead found a copy hosted on a js-dos CDN available here: https://js-dos.com/cdn/upload/DOOM-@evilution.zip.
js-dos 6.22
https://js-dos.com/6.22/examples/
The primary js-dos library that is used in the Custom HTML tag (line 1):
<script src="https://js-dos.com/6.22/current/js-dos.js"></script>
Code language: HTML, XML (xml)
This version of js-dos has different syntax to the original example in the DOOM page above.