Grumpy Gamer

Ye Olde Grumpy Gamer Blog. Est. 2004

Oct 14, 2025

October 28 on Steam

I know you’re thinking the same thing I am: “About f-ing time!”

You won’t even have to fake an illness to take the day off to play because your boss will be spending the day playing Death by Scrolling and won’t notice you’re gone.

Coming soon to Switch, Xbox, and PlayStation. We’re working as fast as we can.

Read Comments
Oct 13, 2025

Who doesn’t enjoy a good history lesson? I know I do. Oh please let there be a test at the end.

Let me take you back to 2018. We had just released Thimbleweed Park, finished all the ports, done an update, and I am thinking about something new.

I was regularly going to Daniel Cook’s Seattle prototyping meet-up and trying to come with a new game to show every two weeks. It was my personal game jam.

I created a lot of odd games, one was a huge multi-screen breakout game, the other was a narrative game about someone being lost in a cave. The cave was procedurally generated and there was literately no way out. It also included a procedural swearing engine.

I was also working on a little top down pixel art rpg game, but is was missing something. I went dinner with some other game designers at PAX that year and buried in a conversation someone said something to how they try and come up with wacky ideas for their new games.

The next morning I woke thinking about the screen always scrolling, never stopping and the player needs to keep up. I hurriedly made those changes but it still didn’t feel right.

Trying to aim and run while the screen scrolled felt like cognitive overload. I switched it so the firing and targeting was all automatic and the player just had to run, avoid enemies, and grab things for upgrades.

There was a frantic energy to the game. The perfect party or steaming game.

I finished up the prototype and took it to the prototyping meet-up and it was a big hit. Lots of laughing as the death was narrowly avoided and the screen never stopped moving.

I was feeling pretty good about the game and decided to move it from a prototype to a real game. I knew I needed an artist but didn’t have the money to afford one.

By pure coincidence I was talking to a new steam-like platform just coming on a scene about Thimbleweed Park and figured I’d ask about this game. I put together a quick video and a pitch email.

You can see the video below.

To my surprise they said yes, gave me some money and I was off.

Side note: I recently did an interview for Death by Scrolling and they wanted to know if I was inspired to make Death by Scrolling after playing Vampire Survivors. Except for the auto-fire this game isn’t much like Vampire Survivors and I have to been working on it since 2018. So… I love Vampire Survivors, but no.

I worked on the game for about 9 months and really struggled with progression. The core game was still a lot of fun but everything I put onto it to make it a deeper game wasn’t working.

It was round this time that the possibility to make Return to Monkey Island came up and it seemed like an opportunity I couldn’t pass up.

I was struggling with the game I called simply called “Runner” and it made sense to returned the money I had taken and move to Return to Monkey Island.

I took all the engine improvements Derek and I had made and built Delores in prep for Return to Monkey Island all based on the Runner engine (but without the tile rendering).

«INSERT MAKING RETURN TO MONKEY ISLAND MONTAGE HERE»

Return to Monkey Island wrapped and I was once again thinking about something new. I had the idea of taking the pixel art tile engine from Runner and making an old school Zelda game (the only Zelda games I like).

I hired an artist, brought on Elissa as a designer and we were off.

A year into the game it became obvious that making an open world RPG was a lot of work and we didn’t have the resources (money) for that.

I thought about Runner, dug up the video and sent it to Elissa and said “What if we made this? We could have it done in a less than a year.”

She loved it and her epiphany was to forget about deep progression and just make it like an arcade game. In and out quickly and retain all the frantic fun of the original.

As I was thinking about the game’s name Elissa died from the scrolling and the text “Death by Scrolling” appeared and she said that should be the name of the game. Perfect.

A quick name change and Death by Scrolling was (re-)born.

The theme of the game being about stuck in purgatory and purgatory being taken over by investment bankers and corporations for profit took hold and provided a nice framework for narration.

A lot came together at the end and it all just made sense.

It’s a game about greed and the never ending grind in life and death for more and more. The absurdity of social media even make an appearance when you die.

The game is mirror into the world we live (and die) in.

Death by Scrolling

Pop quiz

  1. What was the original name of Death by Scrolling?
  2. What city was the prototype meet-up in?
  3. Who did I bring on to help with design?
  4. What game did I make between the prototype and Return to Monkey Island.
Read Comments
Oct 5, 2025

I want to talk about three things that has fundamentally changed my dev-life. There are a lot of things, like ImGUI, that are very amazing and useful but they don’t provide a general solution across many problems.

In no particular order…

Git

I’ve been using Git since 2010 and it really has changed my dev-life. I’d used version control before that, mainly Perforce, SVN and PVSC, but Git felt nice and unobtrusive and I like that everything was local until I pushed to the server.

It’s both nice and annoying that you can’t lock files (like art). You can (kind of) with LFS but that feels tacked on and not ready for primetime. Don’t think so? Try explaining installing and using it to a non-technical artist sometime.

Git can be frustrating if you’re trying to do anything but the basics.

Accidentally check in a secret file months ago and need to scrub it? Good luck with that. There are ways but it requires a lot of Git-Fu.

I mainly use a GUI for git (Fork) and that takes most of the pain away. I do use the command line, but mostly in automation scripts.

Markdown

Before Markdown became the de-facto standard, I used my own custom format. It worked but wasn’t great and only I understood it.

Markdown has it’s issues when you start using the more esoteric features. I’m also annoyed at bold and italics notation. Why is italics *italics* and bold is **bold**? Why not *bold* and _italics_. That would make a lot more sense to me.

I also have issue with it’s creator, John Gruber. He is a highly annoying smug Apple Fanboy. His writing was fine in the early days when Apple was #3, but got intolerable as Apple became the 800lb gorilla. It’s changed recently as Apple has snubbed him but I still can’t read anything he writes.

But, I like his Markdown.

JSON

I use JSON for just about every data file format in my games. JSON was created by Douglas Crockford as a notation for Javascript objects.

I worked with Doug Crockford at Lucasfilm for several years. I always had a lot of respect for Doug and was somewhat intimidated (in a good way) by him. Doug was also the producer for the Nintendo Maniac Mansion.

As much as I love JSON, there are some things about it that annoy me. I dislike that trailing commas are not allowed

"name": [
	"value1",
	"value2",  <- Opps
]

There is no need for this and it makes writing out valid JSON more complex. I also don’t like you that have to wrap keys names in quotes if they are simple ascii.

name: "value"  <- Opps

I wrote a custom JSON parser I use in all my games that relaxes these, but then general JSON readers fail on my data.

Read Comments
Sep 8, 2025

Hi there! I’m Elissa, and I’m the other designer on Death by Scrolling and doing a guest post this week. It’s technically my second project with Ron now, and when I’m not designing my own Roguelike (Dungeons of Freeport), or other games such as Deck & Conn, I’m drinking coffee and fighting drop-bears here here in the sunbaked land of Australia. If you want to follow me on social media, I’m on Mastodon primarily at @vampiress@eigenmagic.net and on Bluesky sometimes at @elissablack.com

A confession to make. I started writing this blog post, got a ways in, and then realized there was a critical problem with it: almost nobody reading the post would have any idea just how Death by Scrolling actually plays, so it’d probably wash right on over them producing a painted-on polite smile.

So here I am, back at the start, suddenly finding myself giving the elevator pitch and basic game play description of the game. It’s also easier now that some game play footage as been released.

Death by Scrolling is a vertically scrolling action-roguelike game.

TesterTron3000 playing Death by Scrolling

You select one of several different characters and progress through increasingly long and densely populated levels full of villainous nasties, treasures, gold coins, traps, collectables, and simple puzzles. At the end of each level you get a brief moment of respite at a camp where you can pick up and buy powerups, take or turn in quests, and go make another tea in the kitchen before returning to your computer before venturing ever-further into the fantastical worlds of Purgatory.

At first glance, the game doesn’t look like a Roguelike. Even in the most loose definition of the term - it’s vertically scrolling and action-driven. If anything, it seems to have more in common with something like River Raid or 1942 than a dungeon crawler. But to me, where it starts to show its lineage is when it comes to do level design in the game.

In terms of my work on the project, I’m designing & writing the game with Ron, but probably the majority of my time is spent doing the level design. As such, I felt like that was a good place to start when writing a guest blog post - I could focus on one of the only things I actually do more than Ron on the game.

In the most superficial sense, the game’s levels are top-down 2d level prefabs designed in Tiled, a very useful open-source tile-based map editor, and stitched together at run-time by the game.

The individual pieces (we refer to them as prefabs) each have different bits of meta data attached to them such as their Land (or biome), what kind of prefab they are, what other prefabs they can attach to and what the probability is that they might appear, what mobs can spawn, etc.

For instance, a very simple, short bit of green grass with a small hill and some simple decorations might be pretty common, and appear regardless of what level you’re at, where-as a more complex prefab featuring a maze may be rare, limited to higher levels only, and might be flagged to only appear once in a level.

Using this metadata we can set it up so that early levels are shorter, simpler, and contain fewer ‘puzzle’ prefabs (what we call the more complex prefabs that have optional mazes, gates or enemy ambushes in them).

If a new player starts on the first level of a run (which is always in the grassy Land), the prefabs that get chosen to assemble the level are different to, say, the 15th level for a player who’s unlocked lots of upgrades and is currently in the Swamp land.

So, to create a single Land means designing the aesthetics, the enemies that occupy its levels, the basic gameplay style, and then, finally, a good hundred or more prefabs that make it up.

Doing those first bits isn’t easy, but it isn’t as time consuming as the weeks and months spent making up all the prefabs. This process usually has three steps.

First step: drinking coffee.

Second step: coming up with basic shapes and paths. This I tend to do in batches, doodling in a notepad or on my tablet, sometimes at a cafe, on a train, or really anywhere that isn’t my work desk (for a change).

With enough of these basic shapes figured out in varying levels of detail, it’s then time for-

Third step: spend days in Tiled, creating first at first the basic layouts, then adding more aesthetic detail.

I usually alternate between doing all three of these critical steps - a few hours in Tiled, then going for a walk to clear my head, get a coffee, and come up with some more prefab ideas.

It’s this design process that to me really drives home how much the game is a Roguelike (or is at least related to them - ask two fans of roguelikes what makes something a roguelike and you will get five different answers).

Just like designing most any other Rogue-adjacent game, it also means that staring at prefabs and their metadata until your eyes go square won’t truly tell if what you’ve built plays well. Great ideas on paper don’t always work. Or maybe they do, but with a few powerups they become too easy (or too hard).

In Tiled, shown above, we have data layers that exist along with aesthetic ones. Different data types (each a unique colour for easy recognition) can be painted on that layer to allow the prefab designer to, for instance, stop a player jumping onto that square, stop power-ups from randomly spawning there, or forcing a square to be non-passible.

Which means built into this prefab design cycle is also a crap-ton of testing. From almost the very start we’ve had regular QA and play-testing done at least a few hours a week. What puzzles are too hard when you’re moving at speed? What other forms end up being fun and should be put into more prefabs?

Even the simple act of adding more prefabs can unbalance the game if we aren’t careful. Add 20 more prefabs to a given Land, and suddenly those rare ones you made might occur less frequently than you’d like.

In the end, it’s meant that designing this game has been a massively cyclic process. Adding features, prefabs, or puzzles, tinkering with them, experimenting, and even removing some if they turn out to have been better left on that scrap of napkin at the cafe down the road from my place.

Read Comments
Sep 6, 2025

“But? Wait?” I can hear you saying, “Isn’t grumpygamer.com a static site built by Hugo? What dark magic did you use to get comments on the static site?”

No dark magic. But it does involve a small php script.

You can embed php in a hugo page and since grumpygamer.com is hosted on my server and it’s running php it wasn’t that hard.

No tricky javascript and since it’s all hosted by me, no privacy issues. All your comments stay on my server and don’t feed Big Comment.

Comments are stored in flat files so no pesky SQL databases. It only took me about a day, so all in all not bad.

I may regret this.

I’m only turning on comments for future posts.

Be nice!

P.S. I will post the code and a small guide in a few days, so you too can invite the masses to critic and criticize your every word. Good times.

Read Comments
Sep 3, 2025

Have I mentioned that you should Wish List Death by Scrolling now, before you finish reading this?

Here is the code the runs TesterTron3000 in Death by Scrolling.

There is some code not listed that does set up, but the following runs the level.

It’s written in Dinky, a custom language I wrote for Delores based on what we used for Thimbleweeed Park and then used in Return to Monkey Island.

TesterTron3000 is as dumb as a box of rocks, but in some ways that’s what makes it fun to watch.

Before we get into code, here is another sample run.

It’s not the best code I’ve written but far from the worst and it gets the job done. TesterTron3000 has run for over 48 hours and not found a serious bug, so I’m happy.

Source code follows, you’ve been warned…

 1function runLevel() {
 2	local last_pos
 3	local reset_time = gametime()+MINUTES(3)  // Reset if level took longer than 3 minutes
 4	local dest
 5	do {
 6		if (PLAYER?.dead) return
 7		if (gametime() > reset_time) return
 8		local pos
 9		if (ROOT(in_camp)) {
10			pos = MAP?.start
11			dest = "start"
12		} else {
13			local targets
14			targets = null
15			if (PLAYER.max_health-PLAYER.health > 1) {
16				print("Looking for heart")
17				targets = entityFindSortedForwardEntities(PLAYER, point(0,1), 10, 360, TYPE_HEART)
18				dest = "heart"
19			}
20			if (!sizeof(targets)) {
21				print("Looking for powerup")
22				targets = entityFindSortedForwardEntities(PLAYER, point(0,1), 10, 360, TYPE_POWERUP)
23				dest = "powerup"
24			}
25			if (sizeof(targets)) {
26				local target = targets[0]
27				pos = entityPos(target)
28				local dist = pos?.y - cameraAt().y
29				if (dist < -6) { // Don't grab powerups near the bottom
30					pos = point(random(5,mapSize(MAP).x-5), entityPos(PLAYER).y+random(5,20))
31					dest = "pos"
32				}
33			} else {
34				pos = point(random(5,mapSize(MAP).x-5), entityPos(PLAYER).y+random(5,20))
35				dest = "pos"
36			}
37		}
38		printf("TesterTron3000 moving to %@ (%@)", pos, dest)
39		dest = pos
40		entityPathTo(PLAYER, dest, 9999)
41		breaktime(0.5) // Need time to finish pathing (happens on a real thread)
42		local bail_time = gametime()+SECONDS(8)  // Seconds to path before changing location
43		while(isPathing(PLAYER)) {
44			if (gametime() > reset_time) return // Player probably stuck somewhere
45			if (gametime() > bail_time) break // Took too long on path
46			if (!entityPos(PLAYER)) return // Something is wrong
47			if (!MAP?.end) return // No end pos, something is wrong
48			if (PLAYER?.dead) return // We died
49			if (entityPos(PLAYER).y >= MAP.end) return // Got to end camp
50			local dist = dest.y - cameraAt().y
51			if (dist < -6) break // Too close to the bottom
52			ROOT(took_step)++ // So powerups will tick
53			PLAYER.last_move_vec <- dirToVec(entityFacing(PLAYER))
54			if (PLAYER?.range_image) { // Spin targeting range around
55				imageRotate(PLAYER?.range_image, angle(point(0,0), PLAYER?.last_move_vec))
56			}
57			if (entityPos(PLAYER) == last_pos) break  // Didn't move, something is wrong
58		 	last_pos = entityPos(PLAYER)
59			breaktime(0.1)
60		}
61		// Choose new destination
62	}
63}
Read Comments
Aug 31, 2025

I first created TesterTron3000 during Thimbleweed Park (hence the name). It was a simple automated tester that randomly clicked on the screen. It couldn’t play the game because it has no knowledge of inventory or puzzles. It did find the odd errors, but was of little real value.

Fast forward to the futuristic year of 2025 and I’m working on Death by Scrolling and need a new automated game play tester.

Death by Scrolling, not being an adventure game, comes along and I need a whole new program to test with, but I like the name so I keep that.

TesterTron3000 is pretty simple, it just runs through the level, looks for power-ups and if its health is low, it looks for hearts. It’s not rocket science. I could make it a lot smarter, but what I really need is tool that stress tests the game so smarts of low on the list.

I can leave it running overnight and it plays thousands of levels and in the morning I see if any errors occurred or if there are memory leaks.

None so far.

Its been a great tool for consoles because we can only do limited testing before sending it to outside testers due to limited dev kits1, so running TesterTron3000 on it for 24 hours is good piece of mind.

There are little animation glitches because it’s not running through the normal controller code and I’ve spotted some missing sfx.

TesterTron3000 is written 100% in Dinky and only about 100 lines of code.

I might ship it with the final game as an attract mode, but it’s kind of buggy, has bad path finding, and really stupid so I worry players would fixate on what it’s not doing right. It’s not a tool for playing the game with any degree is skill, it’s a stress tester and a dev tool.

But, it’s fun to watch.


  1. Something a lot of people don’t know is for consoles you need special dev kits to test with, it’s not like the PC (or even the SteamDeck) where you can use any device. You have to buy (often very expensive) special dev kits, even just to test. It’s really annoying. ↩︎

Aug 13, 2025

I was having a discussion with someone on Mastodon about unit testing games and how it is a next to impossible job. Once clarified, I think we saw eye-to-eye on it, but I do hear about it a lot, mostly from programmers that don’t live in game dev.

Testing games is hard. So much of what fails during testing is due to random behavior by the player. Them doing something you didn’t anticipate.

I break testing down to three groups.

1 - Unit testing

This is what I hear about the most and how this would be a good way to test games. It is not. Unit testing will test code components of your game, but not the game. If you have a sorting routine, this will test that, but it has little effect on testing your game.

I do unit testing, mostly on the engine commands. This get run once a week or when I add a new feature. It’s testing that all the command or functions return correct values, but has little to do with “testing the game”.

It’s also something that would be very hard to run from the build process since the entire engine needs to start up. This is why I run it by hand every so often. If it’s not being run in a real engine environment, it’s not accurate.

2 - Automation

I’ve been using automation since Thimbleweed Park.

I called it TesterTron 3000 it ran through the game and randomly simulated clicks and tried to follow some logic. It found a few things, mostly bugs that would only happen if you clicked very fast.

It was fun to watch and gave mostly peace of mind testing. It often broke because we changed the games logic and it could no longer follow along. If I had a team that did nothing but keep TesterTron 3000 working, it would be more useful but given the limited resources of an indie team, I’m not sure it would have been worth it.

I have something similar in Death By Scrolling, it runs through the levels and randomly picks up things and try to attack enemies.

I could have it follow a set sequence of key strokes, but then it’s only testing what you know works, not the goofy stuff that real bugs are make of. I’ve run into programmers that build something like this and at first it feels good but as the game changes it falls apart and doesn’t get used much after that.

Maybe if you had a simple puzzle game, this might be useful.

TesterTron 3000 a good stress tester and it needs to run overnight to be truly useful.

3 - Human Tester

The most important testing we do is with testers who play the game all day long. They look at the Git history and see what has changed and beat on that. 99% of our bugs are found this way and I can’t emphasis enough how important it is.

Players do odd things that automation never will.

While it is important to test your own code, you will never find the “good” bugs. Programmers are lousy testers because they test what they know, you need to be testing what you don’t know. Be afraid if management that says they don’t need testers because the programmer should test their own code.

I grew up in a world where a bug meant you have to remake a million floppy disks and it would take months to get the change out to players, if they ever got it.

Jul 28, 2025

We just got Death By Scrolling running on the Switch. We had to do some optimization because we were doing stupid stuff with rendering the tile map. Modern PC machines are so fast these days that you can do a lot of stupid stuff and it doesn’t matter. Back in the day (queue angry old man) I had to count cpu cycles and every byte of memory was precious. Nowadays memory is basically infinite.

But it’s different for consoles, they do have a limited amount of memory and you do have to pay attention to performance.

One thing that really bothers me when I play Switch games ported from PC or other consoles is the lack of care over font size. Things that look good on a big monitor or TV are unreadable on the Switch (and the Steamdeck).

We’ve taken great care to make everything big enough to be readable on handhelds, but it’s a real pain. As a designer you want to cram enough information on each screen, especially for RPG-ish games.

People get used to html/css rendering and how good it is at flowing to fill space and around images. Games often don’t have text rendering engines that are that complex (using a html/css engine internally is overkill).

One of the big upgrades I want to do to my engine is better text flow rendering, it will never be as good as html/css in the browser, but it could be a lot better/easier. It’s one of the things I’m envious of Godot.