Devlog

Russel Part 1: I'm building a static site builder - this is it.

I'm building a "static site generator" - Russel - in fact, I used it to build this site! Yes, I know there are already a million ways to build websites but they just weren't to my taste and in my opinion that's all the justification I need. Regardless, this gives me some content for a couple of posts to kick off this blog.

So away I go into the land of already solved problems - a place I feel very much at home - and I want to approach this in a way that keeps this fun and focused. With this in mind I plan to build Russel functionally and I don't mean as a coding paradigm, I mean at a design level. To do this I will be encapsulating the interactions with Russel as functions building them up from the simplest workable behaviours to something more usable but inevitably more complex.

This means that I am going to model the user experience of Russel as functions, I feel this fits nicely into the static site generator domain. The output is obviously a deployable static site - some html, css and maybe js. And the input is something I plan to iterate on, starting with the simplest thing I can think of and generally moving towards something I enjoy using, with precisely the features I plan to use. In general, I think this is how I approach problem solving anyway but the idea really crystallised when I was watching Logan Smith talking about macros in Rust, in which he models a developer as a function ( definitely worth watching the whole video but that section starts around 5 minutes in ).

Now with all that boring stuff out of the way we can talk about the very small amount of tech that has gone into this first version of Russel. As I said the page you are writing was "generated" by Russel, version Russel version 0.0.3 to be exact ...and it is rough to say the least. By the time you are reading this - if anyone ever does - I will hopefully have improved the tooling and prettified this site but for posterity here is what it looks like as I dev:

Russel at v0.0.3

Don't be alarmed, this simplicity is by design and is due to the modelling I spoke about. I started with the following general functional definition of static site generator (using the notation from Logan Smith's video above):

type StaticSiteGenerator: fn(UserCreatedFiles) -> BrowserRenderableSiteFiles

Which is pretty descriptive except for the rather vague "UserCreatedFiles" which makes sense as this is where I'm planning on doing the vast majority of my iteration, with each change aiming to simplify what these "UserCreatedFiles" represent. So with that in mind, for the first release, i.e. this release, I have created the simplest function definition I can for this - the identity function:

type IdentityStaticSiteGenerator: fn(BrowserRenderableSiteFiles) -> BrowserRenderableSiteFiles

This function does nothing to the input, it just spits it back out. In practice this means Russel just takes the files you put in the "./content/" directory and copies it to the "./site/" directory, which can then be statically hosted, more or less, wherever you like. This does mean you have to write all your html, css and maybe js yourself ( yes that is still a possibility in 2025 framework fans ) but it also has the upside of meaning you can build any site with Russel, literally. Just look at my editor right now the world is my oyster:

Russel at v0.0.3

So yeah that's Russel, check it out on crates.io if you want to, I've not pushed the repo yet because I haven't got around to it and it isn't really that interesting. I built it for myself anyway and it only builds your site (copies files), initialises a site (creates and empty "content" directory), and runs a dev server (that just serves the built "site" directory). When it's more interesting and at all good I might publish it to Github but for now it's just mine.

Hopefully I'll write a Part 2 soon with a much nicer setup, or I'll get bored and build something else.