Today we’d be writing our first WebAssembly module to solve the widely known Conway’s Game of Life.
This article is part of a workshop we run at the WebAssembly London Meetup.
What is WebAssembly?
In a nutshell, WebAssembly is a compile target for the web. It is a very simple low-level language that can run in the browser. For example, you could compile C code to WebAssembly and run a C program in the browser. Awesome, right!?
Getting started… Now!
In order to grasp the feeling of building a WebAssembly module, I recommend starting with a simple online IDE. During this guide, we will use WebAssembly.Studio.
Open the https://webassembly.studio page and create a new TypeScript project.
Building your first module
Now that you have a project, simply click “Build and Run” and contemplate the beauty of your WebAssembly browser VM calculating the Answer to the Ultimate Question of Life, the Universe, and Everything.
At the bottom right corner, you will see the answer printed on the screen, for you… and just for you...
Voila! You compiled your first WebAssembly module.
Conway’s Game of Life
Now, we are going to step up and build a more complex piece of Software. It is based upon an official example.
I will guide you along the way explaining what is what, although bear in mind that all the tools used in this tutorial are kind of experimental yet. Therefore, you could encounter some issues along the way.
Firstly, we need to set up the index.html file adding a canvas tag and very simple styles, so the canvas takes the entire page width and height.
- Let the module know how much memory we’d like to allocate for it.
- Map the input/outputs.
- Orchestrate the module execution.
Compiling TypeScript to WASM
WebAssembly Studio uses Gulp to build the project, so we will stick to that as it is the recommended way to implement the build pipeline.
Note that we need to include the flag --importMemory as we want to have access to the WebAssembly.Memory object within the JS orchestrator.
Now we have all the pieces to write the actual Conway’s Game of Life code.
The actual code
For this example, we will use the following types and built-ins:
- i32 : 32-bit integer. Simple, right?
- u8 : Unsigned 8-bit integer
- usize : If targetting 32-bit WebAssembly (we are), then it is a u32.
- load<Type>(pointer: usize): Loads a value of the specified type from memory. Equivalent to dereferencing a pointer in other languages.
- store<Type>(pointer: usize): Stores a value of the specified type to memory. Equivalent to dereferencing a pointer in other languages when assigning a value.
Now the code:
Build and run
Hopefully, you followed along and properly copied and pasted. Now, if you click the button “Build and Run”, you should see the following:
We could download the code written in WebAssembly Studio, and it should be fairly easy to get it running:
cd DOWNLOADED_FOLDER npm install npm i -D serve npm run build echo "Conway's Game of Life at http://localhost:5000/src/main" \ && npx serve
That should build the .wasm file and serve it using a static files server. If it doesn’t work, you could clone my repository, which should work (fingers crossed).
WebAssembly is widely supported (85% globally at the time of writing).
AssemblyScript surprised me positively because it produces a very small module (about ~450 Bytes!) for our Conway’s Game of Life.
For comparison, I tried to build something similar using Golang 1.11, which has native support to compile to WebAssembly and the produced module size was about ~1.5 MB. It could have definitely been optimized opting out of some Golang features, but that bundle size as it is made the module quite unusable.
Anyhow, the tooling around WebAssembly is maturing very quickly, so we can expect very nice tools in the following months/years.
Regardless, WebAssembly and AssemblyScript are totally valid tools in the developer toolbelt and should be considered when the time comes.