Getting Cooked by AI – A GameJam story

I have never participated in a Game Jam before so I thought I would give this one a try. I am not expecting to win a game jam, more to learn and have fun building some games.

What is a game jam?

From Wikipedia

game jam is an event where participants try to make a video game from scratch.[1] Depending on the format, participants might work independently, or in teams. The event duration usually ranges from 24 to 72 hours. Participants are generally programmers, game designers, artists, writers, sound designers and others in game development-related fields.[2] While many game jams are run purely as a game-making exercise, some game jams are contests that offer prizes. Some submissions were eventually released as fully-developed games.

The jam I am doing is here:

https://itch.io/jam/playfulai-jam-1

Pre-Jam

My nephew has been interested in making games for some time, I thought I would use this as an experiment on if I could make a game with him in the future. GlitchJack took me a lot of time waiting around and without a lot of progress for long periods of time. I need to be able to create games more quickly. That sounds crazy considering GlitchJack was just a few days.

I hopped on the phone with my nephew who suggested a game where the city is sick and you need to use medicine to cure people. I thought about this overnight and I don’t know a whole lot about mixing medicines to cure people and wasn’t sure how I would do that. I wanted to stick with this theme in honor of my nephew and ultimately after quite a bit of thinking I came up with a variation of that where the city is getting sick from food, and you are a chef that needs to cook recipes to find the bad ingredient.

I landed on this spec right before the jam started

1000 Recipes

You’re the star chef of the city.  The city adores you and your food but there’s a problem.  Something in the city is making people sick and no one knows what it is. They suspect it’s some ingredient in the food.  Testing the ingredients doesn’t seem to work, it’s only when they are mixed together which makes it harder to discover what exactly is making everyone sick.  They’ve turned to you to cook recipes to discover the bad ingredient.

You have 1000 recipes.  For each recipe you cook the city will give you more ingredients to cook more recipes.  The people of the city have discovered eggs are definitely not making people sick.  You start with eggs.  But there’s only one way to see if it makes people sick or not, have people taste it.  Find the bad ingredient and save the city. 

In honor of the time window, I waited until after the start time to begin any work.

Day 1 – Saturday

With GlitchJack I went with a react front end and a golang back end, no database, no authentication just a simple project.

For 1000 Recipes I wanted to use nuxt.js and Phaser for html canvas. Mostly so I could learn more about how to get these working. I stuck with a golang backend as I had good success with that with GlitchJack.

I spent the first couple hours writing my project overview in as much detail as I could about what I wanted to build, but also how to build it. I spent a few more hours just walking through it all with Claude Code.

I started with the back end and Claude seemed to pretty much be able to one shot the back end. It was up and running and seemed to have all the features I wanted, and it worked. When developing games like this, I prefer to be able to play through the entire game with only the back end, and use the front end as just the interface between it. I have been trying to keep game logic out of the front end but that has proven to be difficult.

Then came the nightmare of the front end. I described in the best detail I could on what I wanted the game to be and had Claude try and build the front end. This time from nearly the beginning I utilized a new flow, using playwright and chromium so Claude could screenshot and see the front end itself. This is pretty much a must have for front ends moving forward for me. I was hoping Claude would be able to create something basic that I could use to build on, but alas on its completion message, I went to load the site and it was a blank screen. After many hours of back and forth on getting things working including basic tailwind functionality I finally had a basic website. Adding tests for everything took hours as well.

I started out with a basic design, but it was so terribly bad I had to ask Claude to redo it from scratch which of course took many more hours of changes and fixing tests.

I finally got to a basic game interface at the end of day 1 but it was pretty painful.

I thought I would have learned my lesson that Claude struggles in one shotting and taken more of my own advice to ask it very specific and small steps but I haven’t truly learned that yet!

The game sort of worked. I could actually cook things, but most of the data didn’t work correctly, nor did the animations. I don’t even know what the center thing is? An oven? A pot of boiling water?

For the recipe data itself I tried to use Claude but it really did struggle on generating recipes in any reasonable amount of time. I think I tried for 30-45 minutes and it generated maybe 900 recipes for me, then it told me it was at the maximum context window it could hold and I would have to start a new chat. So I went over to chatgpt and it was able to generate me a full recipe list in mere minutes. A really start contrast on at least this one area.

Claude wrote a lot of code

  • 12,318 total lines of code
  • 7,381 “production” lines of code – whatever that is.
  • 2,389 lines of Vue and front end.
  • 2,030 lines of CSS styles
  • 1,702 lines of go code for the back end
  • 848 lines of api specifications
  • 412 lines of typescript
  • 4,937 lines of test code (about 50/50 go and TypeScript)

Day 2 – Sunday

I didn’t have a whole lot of time to spend on the app this day. I spent a few hours getting the app functional while watching some TV at night. The game was halfway working by the end of day 2. Also Battlefield 6 open beta was live so I had to play that for a few hours.

I also registered 1000recipes.com and got it up and running so when I was ready I could bring the app up easily.

Day 3 – Monday

On the beginning of Day 3 I thought about what I wanted the game to really be, and the interface Claude created for me really wasn’t it. It wasn’t fun, it was tedious and painful. I decided I wanted to move over to canvas and phaser. Originally Claude did ask me if I wanted to stick with html and js or use canvas and I told it to decide, another mistake of mine.

I had it remove the entire center section with a blank html canvas. The good part of the pain of Day 1 and 2 was now I had a great working setup to iterate on. I had clean components, everything* tested and I could manage the UI in a way Claude could understand and change. I thought about what I wanted and then slowly instructed Claude step by step to get there. I had forgotten how much back and forth there needed to be to get things right. The current AI is truly dumb and unreliable, yet amazing at the same time. I keep having to remind claude over and over again the same things but it never remembers, even with using # memory indicators. Very basic things like run the tests before you consider things complete were often skipped.

One thing I do on every major change I make is tell Claude to not assume anything and to ask me questions, and if it did not get an answer, to reprompt me until it does. Then to also wait explicitly for me to confirm it can start working. I am probably just using Claude wrong here, but this simple thing has turned out to be incredibly effective, although long winded. In this approach I get almost everything I want nearly every try.

I continued on the Phaser HTML canvas setup and it was surprisingly easy to convert over to, particularly because all my data structures were already there along with the api. Most of the AIs work was simply synching it into canvas and phaser. I could drag and drop things into the cooking area in just a few minutes. I then slowly started adding and removing features or panels. I had Claude completely remove the achievements section it somehow managed to add without me asking for it.

Towards the late afternoon I was finally able to start working on the actual game mechanics and core gameplay loops and I felt like I was actually starting to work on my game.

But I ran into a pretty fundamental issue. I was trying to get the basic recipe progression going and was really struggling. I had Claude do an analysis of the best possible starting ingredients based off the recipe list and it really struggled. Initially 17 ingredients could not even cook 10 recipes. My game was overly complicated before I even started.

I ended up regenerating a new recipe list with more common/shared ingredients and having Claude re-analyze that. As another example of just not following what I say, it kept trying to generate these large ephemeral python files and no matter what I told it to not do that, it just kept on doing it, even in the same chat. The new recipe list was problematic with generic names so I had to regenerate it again but it was relatively painless once I gave it better instruction. Given it had saved most of the recipe analysis scripts, it was easily able to find the new starting ingredients and recipes.

By Day 3 I wasn’t sure I would even have anything close to submitting by the end of the game jam, but my goal wasn’t really to win anyway. I know some Jams are over a weekend or a few days and I think that would have been very challenging for me.

I’m not sure this recipe generator is going to work well. What the heck kind of recipe is this? Banana Nut Muffins with no Banana and No nuts? Houston, I think I have a problem.

I ended day 3 trying to get my game deployed out to a real url. This was a spectacular failure, several hours by and it was just littered with mistakes in configuration made by claude. Obvious routes not working and nginx configuration mismatches.

But the issue didn’t start there. I told Claude I was going to run on a really low end server with 512MB ram and to adjust its configurations for a low spec environment. This was a big mistake, it then made about 100x more changes than it needed to adjusting all sorts of limits. I went to build the front end and it couldn’t even build locally anymore. It also created 3 different types of deploys with all different ways to do things. I told it that it had made a mess and to streamline everything that worked and let me build locally without limits. It then actually did create a simple deploy.sh script that ultimately did at least get the containers and other files over to the box. But the deploy script was half baked and I had to do quite a bit by hand.

I wanted SSL on this site, a step I skipped with glitchjack. This was actually relatively easy and Claude did set me up with simple instructions that worked to get a certificate.

The next issue was that the backend probe healthchecks weren’t working from inside the docker network so the backend container wasn’t coming up. This took a lot of painful debugging to resolve. Next I was able to get the front end working as well, but for some reason the front end also couldn’t reach the back end. At first I thought it was a data seed issue, which turned out to be another nightmare to try and resolve.

I ended the day feeling defeated. I still had made significantly more progress than I ever could have had without Claude but it was sort of painful every step of the way unless I gave it very explicit instruction and it kept making the same mistakes over and over.

Day 4 – Tuesday

I started the day not feeling great about getting going again. I only had about half a day to work on things today and wasn’t happy with the state of the game and hours and hours lost on production deployment.

I thought I would start out with a more structured approach to debugging the production issue. I started by asking claude exactly how the request path worked in production and confirmed if the front end was calling the back end or if it was my client calling the back end. I confirmed the front end was proxying the calls to the back end and I didnt need to worry about connectivity from my laptop, but in the docker network.

I suspected something was wrong with the config and asked Claude to create a new /debug uri with the appropriate debugging tools. Sure enough, the front end was getting a 500 from the backend.

I see why now a lot of folks when building apps tell Claude to only use docker to test. Probably something I will consider moving forward is just docker native from the start.

After another 2 hours of debugging, my entire application no longer boots or works in production due to a ton of debugging changes claude made. It decided to change the production nginx configuration to work locally, completely disabling the lets encrypt setup.

A this point I think it will be easier to start over, im going to wipe context, wipe all the files and have it build me a fresh docker setup. This is frustrating as I need to be working on game mechanics, not half a day on deployments.

Day 5 – Wednesday

I didn’t have much time to work on the game at all, so only a little progress.

Day 6- Thursday

I started out the day brainstorming again about my game. I wasn’t happy with the UI or the gameplay and most of the ideas I had to improve things moved further away from the merge them of the jam. I spent a lot of time just brainstorming between matching games or mechanics I did like.

I then swapped over from claude to chatgpt and bounced some ideas around and actually ultimately decided I needed to completely rework my game. Before I didn’t think this was really going to be possible but bouncing ideas off the ai really did convince me it was possible.

Day 7 – Friday

I started working with the new ideas and was able to get the backend rebuilt with the new scheme and apis in a few hours.

Then it was on to the front end. I still wasn’t exactly sure what I wanted the front end to look like, which I knew wasn’t a great place to be when working with AI. You need to be specific, but I decided to go forward anyway but with a slightly different approach. I had the AI play the game with me a few times and ensured the right game context was loaded into the AI, and not start a front end from scratch but to rework what I already had. I was hoping that with a good component base, I could actually utilize AI more since UI/UX is not my strong suit.

I sort of felt like I was going to regret this… But I didn’t really have a lot of time left in the jam and didn’t even have a working game.

The UI it came up with is ok! Not perfect but actually not bad for a one shot.

Day 8 – Saturday

I spent the time I had on Saturday trying to get the game into a better state. The game was functional but it wasn’t fun and was too confusing. UI and UX is harder for me. I tried making a lot of changes to the existing UI but it just wasn’t going to work out.

I decided to try and simplify the game a lot.

This was the final interface I decided to stick with. The game was too simplified and varied a lot from my initial vision but was simpler and at least a workable game.

I think what I ended up with was more of a proof of concept than it was an engaging game.

Summary

Making games is hard! While I didn’t end up with the game I wanted I’m happy with giving it a try and I learned a lot. I’m looking forward to taking some of these techniques to a full (non web based) game engine and trying out ChatGPT for coding.

Things I learned:

  • While there are a lot of pitfalls, AI generated code could build things significantly faster than I would be able to without it.
  • AI “hallucinations” do set you back. Sometimes I had to spend hours just undoing or fixing things I didn’t ask for. Without reviewing every line of code things can be easy to miss.
  • Once you have a good basis for an app iteration speed improves by a large margin. When I had my base app together I could try more AI one shots and they actually came out a lot more sane. For me, getting quickly to a good base app, and a set of comprehensive tests made things 10x easier.
  • ChatGPT is a lot better at non coding tasks than claude in almost every thing I tried.
  • On the web interfaces to AI, front end generation seemed significantly better than claude code.
  • Playwright screenshotting for fully automated development of the front end is pretty much a must have.
  • Claude code context is absolutely critical
    • Starting out a task or conversation and having it read all the code was a significant boost away from hallucinations. Harder when there is not an existing codebase.
    • It would often forget about how tests were run despite several memory commitments, multiple README file inclusions and more. Claude would then try invent new ways to do things. I don’t know how many times it would try and create new testing harnesses instead of using the existing. I would have to continually point it at what to use. Same with docker, it would constantly try and create new docker files or container setups or be rebuilding containers even though hot reload was enabled.
  • I spent way too much time on non gameplay elements of the app. Deployments to just a basic server got overcomplicated or broken many times. At one point I wiped the entire configuration and started over building something much more robust from the beginning. Debugging remote host issues is very painful with Claude code.
  • I now get why so many people require all development to be done in Docker via claude. This is pretty much the same reason people use Docker to begin with but it really sunk in with me on how claude understands the context of things, it can go pretty wild some debugging or changes that all work fine locally. Putting in the Docker constraints helped claude reason with things.
  • Nginx configuration and docker networking really cause Claude some trouble. It would tend to make wild nginx changes that weren’t needed. If something wasn’t working sometimes it would just turn things off or comment things out or completely change the routing working around it instead of fixing the issue. Getting claude to utilize all of this locally was a big key for getting things working. Ultimately where I ended up was a pretty good situation. Nginx ssl with lets encrypt all automated and localhost with local certs ended up working better than I thought.
  • I could completely rewrite the front end and backend several times in just a week’s time. Agility with this setup is pretty high. I think this is a real positive for game development.

I certainly didn’t win the GameJam, but I see the power in this type of game development. I think if I had spent a few more weeks on this I could have built the game I envisioned but it would have taken significantly more work.