Slow Rush Studios logo,
    depicting an apprehensive-looking snail rushing forward

Slow Rush Studios

◂  Mine Your Own Business
News index

Writing These Updates

Contents

A surprisingly common question I get is "what are you using to send out those emails?".

So I figured I'd share a little of what goes on behind-the-scenes for these weekly updates.

Website Tech

I am fairly skeptical of web-based rich text editors,1 so I write each update in Markdown: a simple plain text format where you put * characters around text to bold, use [syntax](like-this) for links, etc.

This Markdown is processed by a "static site generator" called Zola which converts it into HTML, much like the better-known Jekyll or Hugo. 2

To make the website look a little nicer, it's styled with a custom theme: I drag-and-dropped the Slow Rush snail logo onto ChatGPT and asked it to write some styling code with matching colors - and suprisingly it actually worked.3

All the HTML code and whatnot is then checked for dead links4 and uploaded to Cloudflare Pages, which hosts the website for free.5

Over time I added a few more bells and whistles:

All Those Videos

My weekly updates include a lot of "work in progress" videos, and initially I was recording them by hand with a screen recorder each time.

But that was super painful! I had to resize the window I was recording to the perfect size, and then there's a cursor in the way, and I have to quickly click the stop button when I'm done.

Then I had to re-encode the video to a web-friendly appropriately-compressed format,7 copy-paste the output into the subdirectory for that week's update in the website, re-encode it again to an animated gif image (for the email newsletter), copy-paste that output too, and then type out the name of the video file in the markdown file. Phew!

Over time I've refined it to this:

  1. Start the game.
  2. Press F11 to automatically resize the game window to the perfect size.
  3. Press F12 to start recording a capture, do the thing, then press F12 to stop; each rendered frame gets saved as a PNG image.
  4. Swap to my text editor and trigger an import command; the import script then:
    1. Asks me which capture to import, and whether I want it as a video or still image.8
    2. Does the necessary double encoding and copying of files.
    3. Copies the code to embed the video (or still image) to my clipboard.
  5. I press Ctrl+V and the video (or image) magically appears in my update!

LLMs like ChatGPT are truly amazing for writing (the first 80% of) these little time-saver scripts;9 the faster you can automate a thing, the more things you can automate. 10

The Game Builds

I've been publishing a weekly game build almost every week, and the magic of how I deliver those is remarkably straightforward:

  1. I compile the game to Web Assembly.
  2. I make a .zip file of all the assets (art & levels) the game needs.
  3. I take the resulting .wasm and .zip files and stick them in that week's subdirectory.
  4. I write a little snippet to load them into that week's update, which loads some JavaScript that gets the game running.11

Naturally this is also automated via an import script nowadays, which also includes the current version number of the game (for my records).12

Large Files Hurt

One difficult thing about publishing lots of videos and a copy of the game each week is that the website grows pretty quickly!

Despite my game being tiny and my videos being short, I have over 700MB of content already - and if you count the "old versions" of data, then it's 3x as much.

Initially I had started out by doing "the right thing": I stored the big files using Git LFS, so working with my site's Git repository (storage of backups) wouldn't slow down over time - and I had automations set up which publish a new version of my website to Cloudflare each time I uploaded a change.

But when my website reached 100MB in size, I realized Github has quite a low bandwidth limit for LFS files: only 1 gigabyte can be transferred per month! Beyond that you have to pay - so just a few automated publishing runs of my website would quickly burn through that limit.

So now I store all the files the naive way, as regular Git files, and just accept that the repository is a bit slower to work with. Since I'm the only one working with the repository, it's actually not so bad.

Eventually this naive approach might stop working because Cloudflare Pages has a maximum filesize limit, but I haven't hit that yet so we'll burn that bridge when we cross it.

Sending Email Updates

I have a little bit of experience sending emails at scale, which made me keen to outsource this from the get-go.

So I pay Buttondown $9 a month for the privilege of never having to worry about email deliverability. They're a small outfit with great support and seem to listen to their customers; I made some suggestions and got a personal response from the founder.

Best of all, they support Markdown, so I have a small script that converts my custom Markdown flavour (with video and playable game embeds) to their Markdown flavour (with gifs instead of videos and sadly no playable game embeds, jeez, get with it already Gmail, we all know The People want games in their inbox) and uses their API to create a newsletter.

Buttondown does actually have a "host your newsletters online for you" offering, but I don't use that because I can't host the playable builds of the game that way.

The Todo List

For this website:

But, I also know I need to branch out.

Y'all seem to like the nonsense I write about here (based on an unfashionably-high newsletter open rate), but I need to find some ways to get some new friends on board too.

That means swapping some update-writing time for Youtube devlog recording, maybe writing short texts for some Twits,14 or perhaps even sending videos to some clocks.

No concrete plans here yet, but I'll share 'em when I've got em.

PS. Sorry, no updated demo this week: I'm taking a few days off to go camping in this beautiful spring weather.


2

Except unlike Jekyll, Zola is always fast, and unlike Hugo, Zola uses a sane templating language (Tera rather than Go-lang's templates).

Of course that's all incidental detail, because its primary feature is that it is Written In Rust™.

1

A fancy term for "like Microsoft Word".

And yes, my skepticism comes from repeatedly sufferring Atlassian's homegrown text editor freezing horribly on sufficiently big pages.

(I know you're doing the best you can, my editor friends!)

3

Well, I started with the Bear Blog theme, messed with it a bit, then got ChatGPT to update the color choices. Then messed with it some more.

"AI" is nice but it ain't a silver bullet.

4

Using Lychee.

And yes, it's written in Rust.

6

I was expecting to use this a lot more! Turns out I've used it exactly once since adding it, which is a terrible ROI.

7

That's an MP4 container with H.264 encoding. I did try WebM because of H.264 being patented, but Safari on iOS doesn't support decoding them (classic Apple). It was also slow to encode because my CPU doesn't support hardware encoding to it. So after a few months I dropped that and nobody complained about only having MP4 videos, so I guess it's fine.

5

Obviously I'm only using Cloudflare here because they use a lot of Rust.

You hear me Cloudflare? If you bail on Rust you better count on losing my (loss-leading) business too!

8

Using fzf. It's not written in Rust, but sadly the Rewritten-in-Rust version isn't as good yet.

I do occaisionally make decisions for non-religious reasons.

9

Especially for wrangling FFmpeg's million command line options.

10

As illustrated by the classic XKCD: Is It Worth the Time?.

11

It's slightly complicated by versioning: there's actually a separate version of the JavaScript for each separate version of the game framework (Macroquad) I'm using.

I handle that in most naive way possible: I just have a separate snippet for each version that loads the right JavaScript file, and when I upgrade then I find-and-replace embed_game(...) into embed_game_v0_4_4(...) (or similar) before adding the new version.

12

The version is useful because the old builds are useful for quickly checking how long freshly-discovered bugs have been around!

13

In fact I'm taking Friday off this week, so for this update I'm publishing it early on the website.

We'll see whether anyone notices - if not, I guess I can strike this from my todo list?

14

Err, Tweets. I mean Tweets. Or do I mean Xes? Exen? Who even knows these days.

◂  Mine Your Own Business
News index