You can try this game out at alchemy.sshh.io
Hey all, it’s been some time since my last post and I wanted to try a new series on some of the side projects I’ve been working on. I built a game a few months ago, called “Infinite Alchemy” that I thought I’d re-share through this blog now that it’s hit 20K monthly users.
Inspiration
Little Alchemy (by Jakub Koziol) was one of my favorite childhood games. To play, you start with the basic elements (air, earth, fire, and water) and you drag-and-drop them on each other to merge into unique new elements. Fire + Earth = Lava, Water + Water = Sea, etc. There’s not really a serious goal and its mostly a game fueled by your own curiosity to find out what various combinations yield and how many unique elements you can create.
While tremendously fun, my biggest pain point was that the combinations and elements (580 total) were limited to what the designers were able to hard-code and design artwork for. This is where I thought it could be cool to build a version that uses a large language model to make all possible combinations “valid” and the total set of elements essentially infinite. The actual icons could then be designed on the fly by a diffusion image generation model. This also adds a fun new part of the game where a player can be the very first person to “discover” a new element.
How It Works
The AI
The LLM part was surprisingly simple and it really just came down to some prompt engineering and calling the OpenAI API. When a user combines 2 or more elements, I format a prompt like this to send to GPT:
You are a powerful alchemist, I will give you two items and you will do your best to describe the outcome of combining them.
Respond only with a single word which is the result item or thing. The results should be items or things. Use lower case unless it's a proper noun.
## Examples
* air + water = mist
...
User: {elementA} + {elementB}
I then use some basic heuristics to see if the returned element is “valid” (if not, I run the prompt again with a higher temperature). For the artwork I use the DALL-E API to generate an image:
image of {result element}, white background
The Frontend
The frontend is just a progressive web app built on React. The most notable (and frustrating part) was that no matter how much I looked, there was no cross-device drag-and-drop API that supported the type of movement used in the game. This meant that all of the drag and drop code had to be implemented from scratch for both the “click” (for users using a mouse) and “touch” (for mobile/tablets) web APIs.
The Backend
For these types of projects, I like to add the additional constraint/challenge of building everything serverless. This has several added benefits:
P(random outage) is substantially reduced by me not trying to host this especially months or years after initial release
Random surges of users are fairly seamless and require little to no manual scaling
Costs, while overall higher, are all pay-as-you-go meaning the game only costs proportional to how much it’s being used
Nearly all hosting boilerplate is abstracted away by the cloud provider, which is perfect for simple apps like this
In this case I used netlify functions to host all of the backend code for this and cockroachlabs for an extremely cheap postgres-like database.
To reduce latency and costs, element combinations are cached so GPT is only invoked for unique element combinations.
Cost Mistakes
I made two major mistakes when I initially released this:
GPT-4 is so much better than GPT-3.5 (10x less $) and I have caching in-place, so it won’t be a big deal
I assumed that for a game like this, people wouldn’t try to reverse engineer the API and abuse it
Unfortunately at the time I happened to be a Tier-5 no-limit OpenAI customer which meant that I at some point clicked a button that let them charge up to $10,000 to my account depending on usage.
Combined, these two mistakes meant that when eventually someone was creative enough to write a script to brute force as many elements as they could — they did.
As a result I ended up:
Switching to GPT-3.5
Restricted the number of new mixtures and placing additional ones behind a Stripe paywall
As of March 2024, I have yet to recoup these costs. However, on a month-to-month basis, enough people are paying for new mixtures to cover server costs completely and pay down this mistake.
Infinite Craft
At the beginning of February 2024 (several months after initial release), there was a surprising surge of users (+10,000%) and all of a sudden I started getting notifications about netlify function limits. At first, I assumed this was bots/abuse, but from the analytics it looked like legit players.
Digging into the referral metrics more it was clear — Neal Agarwal (a web game developer) built a very similar game called “Infinite Craft” that went incredibly viral. It seems so viral (and similar) that people looking for this game where accidentally finding Infinite Alchemy and playing that instead.
It’s a remarkable coincidence and it’s great that the game is getting a resurgence of attention that’s sustained for the past few weeks. To capitalize on the traffic and give my game a bit more of a twist, I also added wordle-like daily changes, which from the analytics, people seem to really like.
Takeaways
Custom drag-and-drop (in the context of this) is surprisingly complex to implement in React
Don’t design even toy apps without API abuse in mind
Pick a good name, because even if someone builds something similar and more popular it just becomes free publicity
Try it out alchemy.sshh.io!
See the code at github.com/sshh12/llm_alchemy
I would be happy if you could make sorting in to infinite alchemy, like atleast sorting on their newness . Like first will be the 5 things you get in start and then when you get new one it always becomes the last one of the list. Thank you for your game.