Jan. 31, 2025

We have a tendency to view things as fungible. That's a fancy way of saying "substitute one thing for another." It's how we make sense of the world. We say "that thing is like that other thing, let's compress them into a single category."

Fungible is a term from the world of economics. When we look at a coin with one value on it and a different coin with the same value, we treat them as the same object. We can swap one for the other and get the same practical outcome. This is also true of most products of capitalism. One Mars Bar is much like another and you can interchange them without worrying too much. This is generally good and helpful and makes things work properly. Capitalism biases us quite strongly towards viewing reality as composed of fungible items.

acorns-2.svg

Even in nature we often treat objects as fungible. If somebody says "go and find two acorns" and we find seven acorns on the ground, we can generally pick any two.

No two acorns are the same though. We just pretend they are for the sake of efficiency. They are the same to within an acceptible tolerance. Two coins aren't the same either. If you're into numismatics you know a slight difference between two coins can mean a lot, and no two coins are actually identical after a while.

At the very least, even if you have two objects that are identical to a very high tolerance, they do not occupy the same physical space. Their locations in the universe are different and so are their histories.

These days the bias towards treating things as fungible is increasing. Maybe it's due to the permeation of economic thinking into every day life. Maybe it's to do with the increasingly virtual experience of the human condition. It's got to the point where we even treat other humans as fungible in many situations. The person who served you your coffee. The driver who picked you up this morning. The actual physical human being who clicked the like button when they saw your post on social media.

oak-leaves.svg

It's probably a bad idea to treat humans as fungible. It probably doesn't lead to the kind of world that is fun to live in. It's even more absurd than treating acorns, coins, or Mars Bars as fungible. Humanity is enumerable. There are a limited number of us and each of us is tremendously complex. Each of us evolved uniquely from millions of iterations of change and environmental influence. Every person alive has a unique genetic signature, phenotype, environmental context, consciousness, psychology, and place in history. They're simply not the same. The person who liked your social media post, drove you to your destination, served your coffee. All completely unique and deeply complex entities.

It's true that most of us will be forgotten. It's true that we might not be well known by many people in our time. So what? It's also true that we are physically unique and literally special (definition: "distinct among others of a kind").

In the film Fight Club the main character Tyler Durden says "you are not a beautiful and unique snowflake." I think that's wrong. Every snowflake is unique, every coin is unique, every acorn is unique, and every human is unique. You are distinct among others of your kind.

I'm trying to remember this when I interact with people each day.

Jan. 5, 2025

ClojureScript Tiny Slides is grug-brained presentation software.

  • Write your slides in Reagent Hiccup.
  • Static web app you can upload to any web host.
  • Tiny hackable codebase.
  • No setup or config, just clone the repo to start.

It's built with Scittle so it is developed and runs 100% in the browser.

Source code: https://github.com/chr15m/clojurescript-tiny-slides

I made a video about it.

cljs-tiny-slides.gif

Origin story

Recently I was at Barcamp London and I decided to give an impromptu talk. I had most of a talk written already, but no slides. For the Nth time I evaluated the available presentation software and I couldn't find any which fit my admittedly strange set of preferences. So I did what any sane developer would do and built my own presentation software in the 15 minutes available. 😅 This was only possible because of the amazing tooling available in the Clojure ecosystem.

By the way, Barcamp London is a fantastic unconference and definitely worth checking out!

Dec. 2, 2024

Developers optimize for different things in different situations. Developers at big companies with big teams optimize for process and unit tests and scaling. I optimize for building web apps fast and getting them out into the world.

PHP Logo

One of the best ways to do this in the 2000s was with PHP. You could very quickly build a small web app and get it live on the internet. It would be good if we could bring some of these features back to modern development.

What was good about PHP?

  • Excellent searchable documentation.
  • Batteries included. Any time you wanted to do something there was a function for it.
  • Simple deployment. Copy a file to the server to deploy.
  • No configuration or boilerplate. Each file was one route and the file was simply executed.
  • No build step.

These features meant all you needed was your text editor and a webserver and you could quickly turn your idea into reality with minimum overhead.

Nov. 4, 2024

Asterogue header graphic

tl;dr: you can play the new version in your browser here 👉️ https://asterogue.com

This is just a quick note to let you know I re-released my sci-fi roguelike Asterogue for the web, so you can now play it in your browser. It works on phones and desktop browsers. The first few levels are free to play.

Asterogue is a "juicy" graphical coffeebreak roguelike that is pretty much directly inspired by the original Rogue in terms of scope and features. You descend 17 levels into the heart of an asteroid to find The Orb and save the universe. There are a bunch of different monsters which get progressively harder as you descend. Instead of magic there is technology and you can pick up nanotech items and beakers of chemicals to buff your character (or hurt them if you get unlucky).

I received a lot of feedback from players since the first release for Android and Windows and this release includes some changes based on that. Here's a list of quality of life improvements and major features that were added:

  • 💾 Game progress is now auto-saved.
  • 🛠️ Fixed unwinnable level generation.
  • 🍫 Added hunger indicator.
  • 💯 Added a high scores table (tombstones).
  • 🔊 Volume control for music & SFX.
  • 📱 Mobile: fixed pixel UI issues.
  • 📱 Mobile: fixed layout on tiny screens.
  • 📱 Mobile: improved touch controls & UI scaling.
  • 🔙 Support cross platform back button behaviour.
  • 🔃 Ability to exit to the menu and resume.
  • ❎ Dismiss messages by tapping.
  • ⚒️ Many many bug fixes.

Thank you to Andry Bethpalko who helped implement some of the new features. 🙏

The game was always built with web tech but I only released it on Android and Windows at first because that seemed to be the right way to release a game. Well I realized maybe the right way is the wrong way. Rogule does well on the web so why wouldn't my other roguelike game? Now I'm trying out a web release to see if I can make it easier for more people to play Asterogue. So far this is working well and the game is getting more daily players than it ever did as a native app. I'm super grateful for that!

Asterogue initial release analytics

(It's a post for another time but I am increasingly of the view that native apps are past their prime and web based apps are the future. Yes I know PWA enthusiasts have been saying this for a long time, but after seeing stats on how much people dislike installing native apps versus visiting web pages, I think we may actually already be in this world and nobody noticed.)

Another big change is the payment model. The original Asterogue was like most other games in that you simply buy it in the app store or on Itch and download the game. This time I am trying a new experiment with this and instead of buying a downloadable binary, you can play the first few levels free in your browser and then you pay one-time to unlock the full game online if you want to continue. I think this strikes a nice balance for players as you get to try it out and only continue if you're actually into the game once you have picked up the vibe. I haven't really seen this done before with web based games so it's all a bit of an experiment.

Thankfully it seems this model is working for people as the game is making sales already. People seem to be ok with paying one-time to unlock the full game in the browser. Most of all though I am just happy to have people playing and enjoying the game instead of it sitting forgotten and lost in the app store piles. As I said I'm feeling very grateful my little game has new life. Thanks to everybody who has tried it! 🙏

Thanks for reading and I hope you enjoy playing it!

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!