June 6, 2024

Last week I installed Xubuntu 22.04 on a Dell XPS 13 (9305). It was flawless. Everything just works out of the box. 🤯

This is completely amazing for me because I have been installing GNU/Linux on computers since some time in the 1990s when Pentium was a thing. I remember staying up all night tweaking xfree86 modeline configs just to try and get a terminal window to appear without looking squashed or destroyed by scanlines, worried about the warnings that I could permanently damage my parents' monitor. I have spent a ridiculous amount of time, often at 2am, tearing my hair out in a tumultuous relationship with Linux over the years. Lets not even get into WiFi drivers or printers. 😅 So when I get to run my favourite operating system without the tradeoff of having to put up with the difficult parts, it feels like magic.

Last week was the first time I can remember that I have installed Linux and not had to edit a config or run a script to get something working. Everything just works, first time, no issues. It's wonderful, and I feel incredibly grateful for the millions of volunteer person-hours put into making this operating system and software stack. ❤️ You people are amazing!

I'm going to celebrate by showing you a screencast of how fast various applications start up under Xfce on Xubuntu on this 3 year old second hand Dell XPS 13. I see posts these days about the dire situation on Mac and Windows where startup times have got really bad and people are lamenting the good old days when apps were snappy. Well guess what? You can have those good old days. You just have to run lean software (yes with all the tradeoffs and caveats that entails, but you might be surprised by what you can run under Linux these days).

In this screencast I'm launching a bunch of different applications. The keys I am pressing show up at the bottom of the screen. First I use a key combination (alt-tilde) to launch the Xfce terminal but it's so fast that you can't actually see the time between when I press the keys and when the terminal shows up, so they appear to happen simultaneously.

Then I use Application Finder to launch various applications by name. The time between hitting Enter and the window showing up is what to look out for. For the record the slowest application on my system is Thunderbird email client which takes 3 seconds to launch. Enjoy the show!

May 5, 2024

tl;dr: check out LuaVST on ChatGPT if you want to generate some VST plugins.

I've been doing weekly beats this year and it has been a lot of eustress fun (my best song so far is "smectite canyon gambit"). I found a nice positive feedback loop between composing electronic music and writing software for dopeloop.ai. Composing helps me figure out which features are important on the software side.


In recent weeks I've been tinkering with Protoplug. It's a piece of open source software which allows you to write VST plugins in Lua. It turns out Lua is efficient enough to do DSP processing on modern CPUs. You can write the code interactively in the embedded editor, which makes for a smooth iterative workflow. I am using Protoplug with OpenMPT as a host running on Wine and really enjoying it.

After tinkering for a bit I had the idea to take the Protoplug API and some examples and feed them to ChatGPT to see if it could generate plugins from a written description. If you want to try it yourself you can go here: LuaVST GPT. Note, I am using GPT-4 and I haven't tested this with GPT-3.5. You will need to install the Protoplug VST into your host and then copy the code from the chat session into the VST's built-in editor.


So how good is it? I don't like AI hype. I'm going to try to be objective and honest.

  1. Good: it can generate plugin boilerplate really well. If you just want to get something up and running that is a bit more tailored than copy-pasting one of the examples then it works well. You can say something like "create me a plugin that pitches all incoming MIDI notes down by one octave" or "create me a plugin that generates a pure sine tone at 440Hz" and it will do a resonable job that is usually bug-free.
  2. Okay: it can modify your existing code. If you can't be bothered looking through the API for how to implement something you might get a pretty good first pass out of it by pasting your code in and asking for a change. For more complex changes to the code it is probably going to create a lot of bugs. One thing that would significantly improve this would be automatically feeding any errors back to the GPT. At the moment you have to copy-paste errors and often you will figure out what is wrong faster than the AI will.
  3. Bad: asking it to do something complex like "simulate a full TB-303 with incoming MIDI and take into acount the non-linearities as documented by Devilfish creator Robin Whittle in 1999" it is going to do a very poor job. Even the first part of that ("simulate a TB-303") is going to be too much to ask of it. I tried with a few different prompt variants and it couldn't get there. I think this is where the hype of AI falls down. At this point in time only a human practitioner with years of experience, a nuanced understanding, and the ability to iteratively listen to the output as they code, is able to work their way towards a really good bug-free implementation of a complex plugin.

An example of a session that went well was when I used an online graphing calculator to come up with a distortion algorithm, and then I gave the equation to the GPT and asked it to write a plugin. I tweaked the code a little bit but on the whole it was a good implementation and did what I wanted. A distortion algorithm is one of the simpler types of plugins to code from scratch of course.

In the end building this has saved me some time and typing. I am able to work with the output from the GPT and get fairly useful advice from it without having to keep the whole API in my own head. This feels like a microcosm of the larger usefulness of modern LLMs. Productivity boosting but not job destroying.

March 24, 2024

On the last day of 2023 we hopped on a plane to London. We've been here two and a half months now. Michelle and I lived here in 2009 and we've come back again with kids. I guess you could call this a kind of digital nomadism, except we're doing it the wrong way around moving to a country with a higher cost of living. We've already had some wonderful experiences exploring the UK and Italy, and we're looking forward to more! I feel very lucky to be able to do this with my family.


2023 was a good year for me in software development. Here's a recap of things I shipped. Most of these things are built with ClojureScript.

Open Source

I started the year building a new open source Pocket Operator sync app called PO Sync (source code on GitHub). It's a ClojureScript web app which I ported to iPhone and Android native using Cordova (Capacitor is what I'd use today). I did this to get warmed up for what I thought was going to be a year of shipping small music apps. More on that later.

In March I open sourced Roguelike Browser Boilerplate (source on GitHub). Sales of the boilerplate fell after I did this but I don't mind. It feels better to have this available as an open source project.

At the start of February I open sourced TweetFeast (source code here) in response to the catastrophic failure of that micro-startup. I thought releasing the source might be a way to salvage something from the experience. Hilariously TweetFeast actually went on to generate some revenue after it "failed" which was a big learning experience for me. More on that below.

At the end of February my open source web game Rogule went viral and started to get thousands of players per day. That kicked off after I listed it on /r/webgames and then it was picked up by Hacker News, re-tweeted by the GitHub twitter account, and got some press in Japan. I wasn't really sure what to do about going viral so I just watched and made a few small updates to fix things throughout the year.

What's interesting is Rogule had sat dormant for one full year with only a few players per day. There was no change to the software when it went viral. I learned a big lesson from this which is sometimes you don't need to add more code or features to make something work, you just have to get it in front of the right people. In other words, marketing. I've got some big plans for Rogule but haven't been able to give it much attention lately.

In the middle of 2023 I shipped livereload.net which is a fully client side web development live reloading utility. This is similar to Slingcode but more stripped back. Neither of these utilities get very much use but I learned a lot and honed my craft so all good.

In August I released a little utility called aish which is an AI shell command helper. I use this quite a lot on the command line. It has saved me many hours of looking things up when doing sysadmin type of things. Building this simple bash script was one of my first forays into ChatGPT's API. Interfacing with a proprietary 3rd party API is not my favourite thing and I'm looking forward to a future where it's easy to install and run local open source GPTs on our laptops and servers.

At the very end of the year I re-released SVG Flipbook. It's an online app for doing Inkscape animation. A couple of years ago I tried to commercialize this but it didn't work out. I decided to remove the website and just point people directly to the open source version of the app.

Throughout the year I put out several releases of Sitefox, a backend web framework for ClojureScript in the pattern of Django, Rails, etc. I really didn't want to build Sitefox but I had to. I'm all in on full-stack ClojureScript now and I needed something to replace Django. Biting the bullet and building it in the end turned out to be a good decision as just about everything I built this year was built on top of Sitefox. Even if nobody else uses this project it has saved me so much time as to be more than worth it.

Finally this year I open sourced a couple of libraries I am using to build apps for dopeloop.ai. The first is a small collection of music making UI elements for ClojureScript and the second is a collection of webaudio functions for ClojureScript. Both of these are fairly specific to the work I am doing on Dopeloop but I wanted to have them out there as a reference for anybody else building music stuff with cljs.

Micro-SaaS bootstrapping

In 2023 I contined my adventures in bootstrapping small online business projects. I learned a ton and managed to double the revenue from these projects over the previous year.


The projects averaged $700 MRR overall and I managed to do my first $1k AUD month at the end of 2023. This trend has continued into 2024 and I've managed to do $1k MRR in January and February. I am not sure if I'll be able to double the annual revenue again in 2024 but that's my goal.


With the $1k MRR milestone it feels like I've unlocked something fundamental about how online businesses work. I think I've got a grasp now on the full suite of skills you need as a solo developer to ideate, build, launch, market, and sell software online. NOw bUy mY eBoOk!!! Just kidding.

Anyway, here is some detail about where the revenue came from in 2023.

Hosted Gitea


Hosted Gitea is a hosting service for Gitea, an open source git code sharing web app. Hosted Gitea is an alternative to GitHub for people who want to get away from big corporation run code hosting. In 2023 I made 172 commits which included many improvements to security, stability and user experience. Probably the biggest user-facing change was introducing tiers for larger machines with more disk space etc.

The MRR grew by 200% during the course of the year. This basically comes down to search traffic. I don't do much marketing for this site, mostly just making improvements to the service.

Sfxr Pro


Jsfxr Pro is an online app for generating retro sound effects. It also grew 200% last year and continues to grow this year too. I am thinking about adding this app to the dopeloop.ai suite of apps. The way it would work is everybody with a Sfxr Pro subscription or a Melody Generator subscription would get full use of the other apps as well. It's a bit of work to make this happen but hopefully I'll get to it later in the year.



TweetFeast was a micro-SaaS for downloading tweets and follower data.

I learned a really valuable lesson with TweetFeast. A few months after shutting down the app I started thinking about it again. There had been changes at Twitter. I saw that there was still traffic coming to the site from the "download followers" search term, which meant people still wanted to export their follower lists. So I spent a day ripping out all of the other functionality except the follower downloads, and applied for a new API key.

Hilariously, people started to pay for it and months later after "failing" it became a profitable app, reaching $100 MRR for a couple of months. All up it made $600 USD before further changes to Twitter APIs caused it to break again. This was a big surprise to me. I learned there may still be latent potential in time invested in failed business ideas. There's always the possibility I missed something the first time around so I shouldn't give up too easily.

Later I tinkered with an AI tweet generator but that never really took off. I'll probably sit on this domain name for a couple of years until I think of something else to do with it.

Transcript generator


I thought of the idea for Transcript Generator a while back when I first started tinkering with these new GPTs. There is a lot of hype around AI, and LLMs have many issues, but one of the things they are good at is summarizing and editing existing existing text. I record YouTube videos periodically and I thought it would be interesting to generate articles from those videos.

I sat on this idea for a while and then I realized it could be something useful to other people bootstrapping online businesses. Creating content to rank well in search engines is a difficult part of bootstrapping so this could be helpful. After I started looking at the tech I realized it would not be hard to bang this together and ship something. So I did that and shipped the first version at the start of September. Then I left it alone for a while to see what would happen.

The visitor numbers went in the right direction and so near the end of the year I decided to spend "just a week" shipping a paid subscription version. The transcript download features would be free but users would pay for the AI features like article generation.

Of course it took me longer than a week (programmer estimate!) but I finally shipped the paid version in early 2024. You'll have to wait to find out what happened but basically there are now customers paying for this utility.

Dopeloop (Melody Generator)


The smartest thing I did all year was shipping a Pro version of Melody Generator.

At the end of May I was making updates to the audio engine and general improvements. I had been vaguely thinking about a paid version of Melody Generator but something was holding me back. At the end of 2022 what had looked like the smartest idea was building music apps for Android and iOS and I thought that was the right way to go.

What finally pushed me over the line was this thread from Danny Postma where he talks about how much traffic you need to make a sustainable online business. He was talking about search results per day in the hundreds, but the term "melody generator" had thousands, and I was already capturing a good proportion of that traffic. What's more my numbers were going up.

So I abandoned my idea of working on on native music apps and started working on a Pro subscription version of Melody Generator. I shipped it on July 27th and immediately started seeing sales. It's not huge yet by any means but I can see a clear path forward to good healthy numbers with Melody Generator and the dopeloop.ai suite of online music apps.

What is wonderful about this is I found a way to avoid building native apps. I've always been uncomfortable with shipping software for the walled garden ecosystem of app stores. I don't think it's good for developers or for users. The open web is much better. The problem is that it's easier to reach paying users through an app store. Now that I've got the web app revenue above what I was making in the app stores though, it also makes economic sense to avoid them. Much better to ship pure web apps that people can use without installing anything.

Later in 2023 I also worked on a new style guide for Dopeloop apps. I also got a new app called Beat Generator pretty far along. I'm not yet ready to launch that one yet so keep it under your hat. I'm excited to finish it and ship in 2024!


Aside from these open source and commercial projects I also tinkered on a whole bunch of pie in the sky tech. Algorave stuff generating impulse tracker modules, Bluetooth LE sync for music apps, PNG metadata hyjinx, generating game assets with AI, a tiny browser game engine, a joplin blogging plugin, and a variety of ClojureScript experiments.

Hopefully this year I'll find some time to write up the results of those experiements where they could be more widely useful.

Plans for 2024

Now that we're a bit more settled in London I've been thinking about the year ahead. Work has continued apace on my existing projects and client work of course. My goal is really to not start anything big and new but to drill down into growing these projects. I want to focus on growing dopeloop.ai and the "online sound making apps" side of things as a whole.

I also have a weird idea about a way to ship open source web apps with a one-time license for pro features. Shipping web based software means people don't need to install any app, either client or server, and making it open source means they can avoid various bad failure modes (such as companies shutting down or selling user data). Making money doing this means it becomes a sustainable activity that it's easy to find time and energy for.

Some people are surprised to discover that even the Free Software Foundation is in favour of selling to make projects sustainable.

Many people believe that the spirit of the GNU Project is that you should not charge money for distributing copies of software, or that you should charge as little as possible—just enough to cover the cost. This is a misunderstanding.

Actually, we encourage people who redistribute free software to charge as much as they wish or can.

For me that is a kind of holy grail. To build free and open source software and to make money doing so. I think the world would be a better place if more people were able to do this and it's something I continue to aspire towards.

Anyway, for the short term I am plan to continue focusing on what is working. Thanks for reading, and have a great 2024!

Oct. 10, 2023

tl;dr: have some CSS animations to make your browser games juicy!


My favourite game engine is the browser. You get so many batteries included when you use the browser as your runtime. Sprites, animation, sound, mouse, keyboard, touch, gamepad, fonts, text handling, localization, concurrency, networking, 2d, 3d, and a weird XML based scene-graph called "The DOM". The list goes on.

I'm not even talking about canvas based games. These days when I build games like Rogule, Asterogue, and Smallest Quest, I sometimes use <canvas> but I always use the DOM.

One cool thing I've discovered about using the DOM as your 2d game's scene graph is you can offload a lot of CPU intensive effects to a high performance declarative graphics language called CSS. This frees you up to write far less code, and do the more interesting stuff with game logic in your procedural code.

Smallest Quest

It was Juice It or Lose It that inspired me to put more juice into my games. The talk makes the case that "game feel" is a major part of what makes games fun. Game feel is a mixture of animation and sound in response to interactivity and in-game events. It's the difference between a flat game and one that pops.

When I started building Asterogue (a solo-developed space based sci-fi roguelike) I got to wondering - is CSS good enough for video games? I was using web tech to build the game already. Could I do all of the visual effects using only CSS animations?

Asterogue game play

I put together this collection of juicy CSS game-feel animations as a test and I've been building on them ever since. Feel free to use them in your own browser games!


Before I made Asterogue I would have used JavaScript to manually script sprite animations. Manually coding animations takes a lot of time and effort. It's also not very performant. That means the game ends up less juicy than it should be. Why not speed the process up using the domain specific animation language built right into browser?


It turns out CSS is absolutely good enough for a large class of browser based 2d games.

In the end I was able to build and ship a juicy graphical roguelike in about 1.5 months. I used Electron and Cordova to build the Asterogue binaries for desktop and mobile. I used plain old CSS animations for game feel. I saved on code using pure JavaScript with just one library (rot.js). Asterogue is only 2k lines of code which helped a lot with debugging and development speed. Browser based debugging tools are also absolutely fantastic during game development.

I would highly recommend this path to anybody making 2d games. The browser is a killer game engine.


Have fun!

Sept. 10, 2023

Today I put together a small test repo to check how much space is saved when replacing React with Preact in a ClojureScript project.

I used npm init shadowfront prtest to get a basic project up and running. This creates a simple one page Reagent app with a button you can click.

(ns prtest.core
    [reagent.core :as r]
    [reagent.dom :as rdom]))

(defonce state (r/atom {}))

(defn component-main [_state]
   [:h1 "prtest"]
   [:p "Welcome to the app!"]
   [:button {:on-click #(js/alert "Hello world!")}
            "click me"]])

(defn start {:dev/after-load true} []
  (rdom/render [component-main state]
               (js/document.getElementById "app")))

(defn init []

I made a build to check the size of the resulting js binary. Then I uninstalled react and react-dom and installed preact@8 and preact-compat. Then I updated shadow-cljs.edn to add the following clause into the :app build:

:js-options {:resolve {"react" {:target :npm :require "preact-compat"}
                       "react-dom" {:target :npm :require "preact-compat"}}

This asks shadow-cljs to alias those React modules to the Preact compatibility layer throughout the whole stack.

I ran make to build the project before and after the change and got the following results:

  1. With React = 292k
    $ du -hs build/js/main.js 
    292K    build/js/main.js
  1. With Preact = 172k
    $ du -hs build/js/main.js 
    172K    build/js/main.js

A 41% size reduction (120k) for a simple one page app seems pretty good. Most of the remaining 172k would be ClojureScript core and libraries such as Reagent.

Update: shadow-cljs lets us generate a build report. Here's a build report with React and then Preact:

React ClojureScript build report

Package Weight %
react-dom @ npm: 18.2.0 128.22 KB 45.8 %
org.clojure/clojurescript @ mvn: 1.11.60 115.71 KB 41.4 %
reagent @ mvn: 1.1.0 22.93 KB 8.2 %
react @ npm: 18.2.0 6.49 KB 2.3 %
scheduler @ npm: 0.23.0 3.96 KB 1.4 %
org.clojure/google-closure-library @ mvn: 0.0-20230227-c7c0a541 1.12 KB 0.4 %
Generated Files 932 0.3 %
src 490 0.2 %

Preact ClojureScript build report

Package Weight %
org.clojure/clojurescript @ mvn: 1.11.60 115.61 KB 71.4 %
reagent @ mvn: 1.1.0 22.94 KB 14.2 %
preact-compat @ npm: 3.19.0 9.24 KB 5.7 %
preact @ npm: 8.5.3 8.18 KB 5.1 %
preact-context @ npm: 1.1.4 2.55 KB 1.6 %
org.clojure/google-closure-library @ mvn: 0.0-20230227-c7c0a541 1.12 KB 0.7 %
Generated Files 931 0.6 %
prop-types @ npm: 15.8.1 801 0.5 %
src 490 0.3 %