If you haven’t seen it yet, I’ve made a simple Pong implementation in Python that you can recompile live in the browser. You can find it in the how to use course. In this blog I’ll go further into the details of all the technology used to create this site.

Backend

First of all, this site wouldn’t be possible without Hugo. The site is completely static, that means there is no database on the backed to store anything. This setup makes the site really easy on the backend: there is none!

Frontend

For the frontend I started out with a theme called hello-friend-ng. I’ve changed some code to update the blog format for the courses, but most of the basics stem from this theme. For other features like interactive spoiler tags and buttons I’ve used Bootswatch. I’m very grateful that I’m able to use all of this for free, it makes building this website so much faster!

In order to make the code interactive I’ve used CodeMirror. There was a bit of a learning curve to get it working, so I’m still using version 5 instead of the latest. I’ve made my own CSS to theme both the CodeMirror blocks and normal code blocks to use the tokyonight-night theme (or at least, as close as possible!).

Python

Onto the first programming language: Python. Skulpt is what made me start this site. It’s amazing to write code straight into the browser and be able to compile it without needing anything else installed.

That’s basically all we need to get python up and running, creating an editor with CodeMirror and using Skulpt to compile it as soon as we press Run we get the following:

C++

Now this is where the complexity starts. Nothing too crazy, but a lot of this was made possible by Ben Smith’s Clang in WebAssembly. Using WebAssembly he compiled clang in order to compile C++ code on a web page. There is a lot to be said about this piece of technology, and luckily there is a presentation on it!

So once clang is compiled, there’s a couple of files to load in order to get it running. I’ve hosted all of these on a github repo so I can update and load those in separately. There hasn’t been a need to update these at all in the past 3 years as you can see in the repo.

When executing the code you see a couple of different steps happening:

  • Before we do anything, we load in memfs.wasm which is a virtual filesystem. In here we can load all of the files we want to compile and link together.
  • Once that’s done we can load in some files in the filesystem: we load the C++ standard headers and libraries from sysroot.tar
  • Fetching and compiling clang: this is where we download the clang.wasm file and run it.
  • Fetching and compiling lld: we also need to load the lld.wasm, the LLVM linker
  • Compiling code: We add the user code to the filesystem and compile it using clang.
  • Running code: After compiling and linking it all together we can run the generated executable.

Drawing

As seen on the your first raytracer post, I can also draw some animations. This is nothing unique and available on the web everywhere using the canvas and some javascript.

We can also draw similar results in the canvas using either Python or C++ as you can see on the vectors course. For Python we can use processing library that’s already ready to use in Skulpt! For C++, Ben already added some support to add canvas calls from C++. So with both of those languages supporting the processing library, we can easily render canvas elements interactively from code that we can recompile:

Writing the pages

On the backend all I have is one markdown file per article. In this file there are formatting rules for the text, like two ** to make text bold **. You can find all of them on on the wiki page.

Other additions to the markdown page are done using Hugo’s shortcodes. The above code editor for python is written as follows:

{{< editor id="python" type="python" >}}
{{< editorcode id="python" type="python" >}}
print('Hello world!')
data = ['Test', 1, 'Yellow', 'Banana']
for element in data:
    print(element)
{{< /editorcode >}} 
{{< /editor >}}

And the canvas animation:

{{< canvas id="ray" width="500" height="150" >}}
var render = function()
{
    // Javascript code
}
{{< /canvas >}}

Spoilers:

{{< spoiler id="spoiler" name="Show spoiler" >}}
{{< /spoiler >}}