JS13KGames 2018 Post Mortem

And another JS13KGames competition is over. This year’s theme was ‘Offline’. Since BabylonJS was allowed too in the WebXR category this time and I had been looking into Babylon lately, I decided to go with that. At the JS13kGames website you can play my entry, Lasergrid .

The first concept I had in mind was in a factory setting where the player gets an order on a display in the form of a selection of different colored objects. The player then has to look at the conveyor belt and push everything that’s not in the order off. The problem that I ran into very quickly was that I couldn’t use the default physics with Babylon. Although there’s a library for physics available for Babylon, it’s an external library that I couldn’t fit into the allowed 13kB. So I went with my second idea, a laser grid in which the player has to turn object and make the laser get from the start to the finish.


BabylonJS and Virtual Reality

Setting BabylonJS up for Virtual Reality is very easy. It’s not ‘on’ by default, but there’s a helper function to add everything including the icon to switch to VR. It is usually called right after initializing the scene: this.vrHelper = scene.createDefaultVRExperience();. Moving around in the browser works right out of the box. Teleportation in VR is also very simple to add. I created a mesh for the ground and called enableTeleportation:

    floorMeshName: ground.name

With that out of the way, I added a simple data structure for the puzzles and created a few basic cubes as objects to work with. When these are clicked in the browser they would rotate.

With this part working I was confident enough to start working on the full game.

Challenge 1 - Textures

Since even a PNG gets larger than 13kB very quickly texturing is always a challenge. When you try to shrink down images you quickly end up with a pixel art look. So that was the look I went for. Of course, I used my favorite pixel art tool PyxelEdit. PyxelEdit Applying the textures to the models was giving me some issues as well, which actually takes me to the next challenge:

Challenge 2 - Models

The models for the game would exist of very simple objects. In the proof of concept, I used a box and an extruded triangle. At first, this worked fine. When texturing the models I learned that Babylon stores the UVW information in the vertices, and not in the faces as I expected. This meant I could not map the textures per face. Getting the UVWs for 1 face right meant breaking another. I ended up ‘modeling’ in 3D Studio. I needed the UVW information so I recreated the simple meshes in 3D Studio and detached some faces to give them their own vertices and UVWs. I wrote a custom script to extract all information about vertices, faces, and UVWs to simple JavaScript objects. Since I was working with 3D Studio already, this gave me the idea to use this for puzzle design as well. So I created another MaxScript to export a scene from 3D Studio to JSON. The scenes are very simple. I just add some cubes in various colors by setting the material ID. This gave me the possibility to rotate the cubes and build entire walls out of them without any problems. I included these scripts in the GitHub project as well, by the way. In case anyone wants to have a look.

Challenge 3 - Laser

I needed to find a way to calculate the laser beam. I decided to go with casting some rays. Every object has a rotation value, I used that. The first ray is cast from the transmitter object. If it hits an object I call a method on that object that returns 1 of 4 possible values: Stop processing; Go left; Go right; Hit target. I planned on extending that list with other constants but never got to that. The laserbeam repeated that process until it hit nothing, a wall or the target. Every time it hit something it adds a new coordinate to an array. The array is then used to create a tube. I ended up adding a glow effect to the tube to make it a bit more like a laser.

Challenge 4 - Controls

To make the game into a real VR game I wanted to add Oculus Rift support. I wanted to be able to rotate the blocks and move around using the Oculus Touch controls. Babylon.js has some very simple function to add interactions and teleportation. That is until you really want to do something with it. There is a mesh selection event you can use. This has a filter to limit exactly what you can select in the game. Unfortunately, this event triggers when you point your controller to the object, without even pushing one of the buttons on the controller. I ended up having to track what the user is pointing at and have the controller respond to that. Another this is that the trigger for the Oculus Touch controllers are not boolean values, but can be anything between 0 and 1. As soon as you slightly touch the trigger this value changes and the event is fired. And whenever you slightly change the amount you are touching the controller this value changes. I fixed this by adding some more status values. And although it’s working it is by far an elegant solution.

Challenge 5 - Finishing

Finishing the game turned out to be the biggest challenge. I started working on the project as soon as I could, during my summer vacation in France. I was making some progress but got struck by the flu. This took me out for a whole week. I also had to finish some presentations and a workshop. I did learn a lot though. I wasn’t planning on continuing to finish the game, but after using the game in a demo at our local WebXR NL Meetup people convinced me to continue working on it. I try to stream as much as possible on my Twitch Channel and upload it my Youtube Channel .


The main reason for me to work on compos like JS13kGames is just to have a fun project to work on and learn a lot in the process. The constraints force you to think outside the box. And although I got sick, I managed to create something playable, learn a lot and had fun.

@end3r, thank you for hosting this great compo every year! Already looking forward to the next.

JS13k Games Post Mortem | A JavaScript WebVR game using A-Frame for the Js13KGames jam

On the 13th of September, the JS13k Games jam 2017 has ended. The challenge in this contest is to build a game in JavaScript that fits in a .zip file of 13k in one month. New this year was the A-Frame category. A-Frame is a web framework for building virtual reality experiences on the web. I love 3D and VR, programming in JavaScript and a challenge, so I decided to participate (again) this year. Eventually, the biggest challenge turned out to be time. I ran out of time, with about 5kb left of the 13kb.

Since I always wanted to try creating a roguelike game that was going to be my game type, and that I would love as much as I love the no game throws from P4rgaming. The world should be generated randomly, with monsters and loot. You should search for pieces of you spaceplane that crashed onto this planet. At first, I wanted to create portals to go from level to level until the player would have found all pieces. I later, due to the time constraint, changed to 1 level with 5 pieces you have to find. I wanted a ‘low res' pixel-arty Minecraft-like look.


A-Frame uses a declarative HTML syntax which makes it very easy to understand (and to copy-paste). A-Frame supports all the major virtual reality devices, mobile devices, and the desktop. It is built on top of  three.js . This way you can leverage the full potential of 3D on the web.

A-Frame works by writing components to use in combination with the markup. The way this worked reminded me a lot of the way games are built in Unity3D: Creating a ‘script' and attach it to a game element. It took me a few days to get into this mindset, but when it hit I started creating components for every element of the game, like the player, the mobs, ground tiles and the materials.

For moving around I chose to limit to a ‘gaze' at the tile next to your character to move to that tile. This feature is implemented in A-Frame and could be handled by having a ‘click' event handler on a ground asset. This even could be filtered by using a css class on the ground elements.

Map Generator

A hard part to build was the map generator. Though there is a lot of information on the web on building a dungeon generator on the web, pretty much all of them are too complex for the 13kB limit.

One thing I kept in mind is the fact the 13kB limit is the zipped version of your game. Having some very repeating data inside the game should theoretically be compressed quite a lot.  I decided to go for a type of generator that would place and connect various ‘rooms'. The rooms are constructed from 2D arrays containing 0s, 1s and 2s. Where 1s are floors and 2s are exits. I also wrote a function that mirrors the rooms horizontally and vertically.

To save bytes on holding the generated map in memory, I used a canvas instead of an array. The canvas has every function I need to write and read data for the map.

Every tile in the game is represented by a pixel on the map. Each pixel is made of 4 bytes. I used the first to represent the floor, the second to represent an item and the third for a mob. The actual value of these bytes varies per type of mob or item. The best side effect of using a canvas is that I added it to the DOM to debug the map generator. Below is an image from the map. You can clearly see the bright green pixels, which are the pieces of the plane.

The next step after generating the map is to write it to the 3D scene. In this, I used a couple of for loops to look at each pixel and draw a floor tile if the first byte is a not- zero value. I also gave the A-Frame entities an ID with the position on the map. That way it became very easy to find an entity based on its position on the map.

Shaders and Art

To get the game to look the way I wanted I wrote a couple of shaders. Two vertex shaders and a fragment shader. The first vertex shader is pretty simple, it only transforms the vertices to 2D space and calculates the UV coordinates for the sprites. The second vertex shader is slightly more complex. It is used to billboard the sprites. They are rendered that they always face the 3D camera. The fragment shader is used to render the sprites and uses a few tricks.

Speaking of sprites. The sprite sheet I used is this:

Note that there are colored floor tiles, mobs or items in there. The shader I wrote is replacing the gray colors of these with a color from a second sprite sheet.

I was planning on creating a lot more ground tiles in different variations. The plan was, for example, to have a grassy biome. This biome would have all kinds of variations of grass tiles. Some all green, some with yellow flowers and some with stone tiles. I even thought of doing animations on lava and water by cycling through a couple of different rows from the palette. But, again, I didn’t have the time to do so.

For creating and testing the shaders I used ShaderTool  and FireFox. ShaderTool makes it very easy to write you GLSL code and test it by wiring up the inputs. I used FireFox for fine-tuning and debugging. The GLSL dev tools in FireFox let you modify the shader while running. Very handy.

The biggest issue I ran into while creating the shaders was handling the opacity correctly. I eventually added a parameter as a cutoff value. If the alpha drops below this threshold, the pixel is discarded.


Near the end of the contest, someone mentioned on Slack that the a-text component was downloading a font. Since using external stuff besides the A-Frame library was prohibited, using the a-text component wasn’t allowed as well. I solved this issue by creating a new component that renders a text on a canvas and uses this as a texture on a plane entity. Too bad this took some time to build and caused other items on my todo list to be removed.


You can play the game at  JS13KGames  or at my GitHub . You can find the source there as well. Since the game isn’t entirely finished I’m thinking of continuing working on it. A few features I’d like to add are a better following camera, more intelligence on the mobs, an inventory for the items and durability on them so they break and better biomes.

Just want to close by thanking Andrzej Mazur and c9bets for having this great jam every year!