Sept. 5, 2024

makesprite.com is a simple open-source online app I made for generating sprites for games.

animation.gif

The first time you open the app it downloads a set of default prompts and sprite sheets. These are a useful starting point for generating your own. You can click the "Re-run prompt" button and the prompt that was used to generate that spritesheet will be loaded. You can also use the "Copy prompt" button if you want to use it elsewhere. Before you can run a prompt you'll need to go to the settings page and enter an OpenAI key since the app uses the OpenAI API to generate the images. Click "Send" to send the prompt to the API and after a while you will receive a spritesheet back.

This post is available as a video on YouTube:

d457a991b132a5c01f3fdcd299e9c219.png

Once you get the spritesheet it will be stored locally in your browser. You can then tweak the image by using the fill tool to remove any unwanted background colors. Once you find sprites you like you can use the "extract sprite" mode. This will copy the sprite to your clipboard as well as providing an interface to download it. You can also favourite, download, or revert spritesheets to their original form if you make a mistake when removing background.

Makesprite uses OpenAI's DALL-E to generate the images and comes with a bunch of user-interface enhancements to make it easy to organize and extract game sprites. It is a 100% client-side browser app and nothing is stored on the server side. Because it relies on DALL-E for the image generation you'll need an OpenAI key to use it. Future versions may integrate other image generators.

Makesprite doesn't do anything you can't do directly with DALL-E. You can use DALL-E directly with the same prompts. However it does enhance the experience of the sprite-generation workflow specifically:

  • It provides a series of curated prompts that are the best I could come up with for generating sheets of sprites.
  • It provides an interface for removing the background and extracting individual sprite elements. In my experience it is time consuming and fiddly to do this with e.g. Gimp or Photoshop.
  • It keeps your generated sprite sheets together and visible in one place rather than spread throughout your other sessions in the ChatGPT interface.
  • You can create template prompts with variables that can be modified between runs.
  • You can re-use prompts easily and copy them to your clipboard.

Limitations

The sprites generated by DALL-E are limited. They aren't animated. They are pixel based not vector based and aren't always cleanly separated from the background. They suffer the usual gen-AI issues with missing/extra limbs, elements that make no sense, bad reflections, weird shapes and shadows, etc. It is difficult to get any consistency between different generated sprite sheets. DALL-E is really bad at creating pixel art so I've focused on non-pixel-art prompts. Sometimes DALL-E throws things in that have nothing to do with the prompt. Finally, just like Copilot and ChatGPT, DALL-E is probably trained on non-public-domain and sometimes copyright data, and that might pose ethical or legal problems.

All that said, I think these sprites will be good enough for some use-cases.

If you're making a simple game with limited animations, and if consistency doesn't matter that much, or you only need a small number of specific sprites, or if you're only looking for simple flat token images, then makesprite might fit the bill. If you just need placeholder graphics to give your demo or gamejam game the right look or feel it might be good enough. I think makesprite could be great for gamejams where you just need something fast that fits the theme.

If you generate something that is good enough for placeholder graphics you could also take it to a real game artist once your game is ready, and pay them to create real game art using the makesprite output as a reference or inspiration. I'd be really happy if more work for real artists was an outcome from tools like this.

About the tech

I had heaps of fun building this app with ClojureScript. I've built a lot of small web apps with Reagent and CloureScript now and the workflow has only got better. At around 1000 lines of code and 21 days of part time dev this is probably one of the fastest apps I've built. I chose to deploy it to GitHub pages instead of going my usual route of deploying with Piku. As a predominantly front-end app hosting it on GitHub should make it faster due to their CDN.

This was fun to make. I hope you find it useful. Enjoy!

Aug. 13, 2024

Claude AI has a mode where it can generate something called "artifacts". One of the things you can do with this is generate simple single page web applications. It generates the web app and then mounts it in an iframe so you can quickly test it and give feedback. This gives you a fast iterative process using the AI to refine the web app incrementally.

This is pretty cool but I would much prefer a web app written in ClojureScript with Reagent forms instead of JavaScript or React. ClojureScript is more concise and I find it leads to less bugs and is faster to work with.

Note: this post is available as a YouTube video.

Claude AI app artifact generation

There is a version of ClojureScript that runs entirely in the browser called Scittle, created by Michiel Borkent who also created the babashka suite of Clojure utilities. Unfortunately Claude can only use libraries that are available on cdnjs when generating web apps, and Scittle was not available. So I raised a PR with cdnjs and it's now available to use in Claude generated artifacts.

What all this means is you can now prompt Claude to generate small ClojureScript apps and it will generate clean ClojureScript code. I've set up a basic repository with a ClojureScript + Reagent prompt and example HTML file you can give to Claude to get it started.

The best way to use this repository is to create a new project in Claude, and copy the prompt and the example in as the default project prompt. A project is Claude's way of letting you use the same prompt multiple times.

As a simple example, you can generate a basic compound interest calculator using the prompt from the repo and adding the following text to the end:

Please generate a simple compound interest calculator.

You can test the resulting app and see the code here. The code it produces is a single page HTML app with inline ClojureScript and I've shared the cljs part here:

(require
  '[reagent.core :as r]
  '[reagent.dom :as rdom])

(def state (r/atom {:principal 1000
                    :rate 5
                    :years 10}))

(defn calculate-compound-interest [principal rate years]
  (for [year (range 1 (inc years))]
    {:year year
     :balance (* principal (Math/pow (+ 1 (/ rate 100)) year))}))

(defn input-field [label key type]
  [:div
   [:label label]
   [:input {:type type
        :value (get @state key)
        :on-change #(swap! state assoc key (js/parseFloat (.. % -target -value)))}]])

(defn result-table []
  (let [{:keys [principal rate years]} @state
    results (calculate-compound-interest principal rate years)]
    [:table
     [:thead
      [:tr
       [:th "Year"]
       [:th "Balance"]]]
     [:tbody
      (for [{:keys [year balance]} results]
    ^{:key year}
    [:tr
     [:td year]
     [:td (str "$" (.toFixed balance 2))]])]]))

(defn compound-interest-calculator []
  [:div
   [:h1 "Compound Interest Calculator"]
   [input-field "Initial Principal ($): " :principal "number"]
   [input-field "Annual Interest Rate (%): " :rate "number"]
   [input-field "Investment Duration (years): " :years "number"]
   [result-table]])

(rdom/render [compound-interest-calculator] (.getElementById js/document "app"))

I hope this will be useful to people who want to build with LLMs and ClojureScript. Enjoy!

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.

screenshot.png

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.

Results

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.

50c84a0ccb1cd1a42402903e2e291632.png

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.

revenue-2023-annual.svg

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.

revenue-2023.svg

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

c1e49f993cd0f10d0bfc9b99c1ab35b3.png

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

a46e78c5cfbaed150e37cd64e4cbc585.png

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

e82c70380ed75bad76cc6321b2119ac8.png

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

f4463156b6051937d20ea863c963720e.png

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)

d701e63896acc140d4c26a8f97d92c7a.png

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!

Tinkering

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!