Postmortem: Sunless Horizon


For my thesis I recently read two very good postmortems by Double Fine’s Caroline Esmurdoc (Psychonauts) (Brütal Legend) and thought it would be funny to handwavily apply their structures to this one. 

Game Data

  • Jam Submission Date: 2023/02/05 (https://itch.io/jam/gdb-juice-jam-ii)
  • Post-Jam Release: 2023/02/13
  • Genre: Open-World Exploration Dialogue thingy
  • Project Length: 8 days (including several (near-)dead days bc procrastination)
  • Project Budget: our time, a bit of food and energy drinks, and tea
  • Peak Team Size: 2 (covvboyy and me)
  • Hardware Used: Our epic gamer gaming pcs 
  • Software used: Godot 3.5.1, Clip Studio Paint
  • Websites: freesound.org, cloudconvert.com

One more common structure for postmortems (including the ones I mentioned above) is to include equally-sized “what went right” and “what went wrong” sections. However, because basically all good things here have a massive asterisk behind them that absolutely blew up in our faces, I’ll talk about a couple of features / moments instead, and tell you how they are good and not-so-good.

Assets and their massive file sizes

I (Snek) did all of the visual assets. Because I am a stupid little reptile with no regard for efficient development practices, all the textures are MASSIVE. 

  • Each planet is ~9 MB, with around 2800 px in each dimension
  • All endings have a parallax effect, and between 5 (Fool and Tower) and 11 (Empress) layers, each one at 2880 x 1620 px, making each singular layer between 0.2 and 5 MB (A total of 50 mb for all endings)

The implication of this was however, that the build was too big for a browser-playable version, so we had to use an downloadable exe. Now is this objectively bad? Of course not! There are two counter points I’d like to objections to this development practice:

  • It’s what I’m most comfortable with, leading to faster results (which is good if the visuals are not the focus of the gamejam, which they were not.)
  • I’m blaming cisheteronormativity (This sounds like a joke but hear me out.) For a more eloquent take, I highly recommend this essay by Eric Freedman (Engineering Queerness in the Game Development Pipeline) But the tldr is that the historical baggage of how games are produced ties into restrictions of the game development pipeline, which can be improved and made more flexible with queer analysis techniques. This also ties into the concept of boundary objects (A good intro is “Forthcoming in Games and Culture: What Can We Learn from Studio Studies Ethnographies? A ‘messy’ account of game development materiality, learning, and expertise” by Jennifer R. Whitson). As developers we need to negotiate with software when interacting with other people within development, thusly compromising and re-casting our language and practices into a common lexicon and set of behaviors.

So tldr: I might try to produce better files next time but also I’m letting the violence of crushing scaling my textures down to 11% trans my gender without compromising on the artistic nature of queer video game production sooo ¯\_(ツ)_/¯

(The endings look sweet af tho, hmu if you want them as desktop wallpapers)

The Code Architecture

Oh my god my code is so so bad. 

Well, really it’s just one big mistake that permeates throughout the entire project, and that is information hiding. Most relevant instances (Player, Level, HUD, etc.) can be referenced via a singleton script, which leads to horrible spaghetti code. The level scene has a block in its _process function (called every frame) that is contingent on a condition in the HUD. Directly accessed. Kill me now. 


I know other projects can pull it off but they implement this pattern sparingly and with very careful and surgical usage. I just used a sledgehammer and put everything in a global scope. (Learning experiences, hey?)

That is also the reason why we cannot put a restart button in the game, unless with major refactoring, because when calling get_tree().reload_current_scene(), we’d still be accessing a bunch of now-invalid references in that singleton. It was a mess and not nearly enough time to figure out how to work around it, but ultimately we got lucky with the type of game we made because it is kinda sweet in a narrative sense. You can only restart the game by reloading the page :3

But yes, information hiding can be a useful programming paradigm actually and I’m gonna have to read up on how to use it better >.<

The Dialogue System

Within 24 hours (like 3 hours of actual work) I crafted the barebones dialogue system. Over the course of the jam, I grafted more features to it, such as a very cumbersome method of dialogue tree traversal, and the ability to trigger sounds and trigger the ending cutscene. (Actually we could define an arbitrary amount and kinds of events if we wanted to.) It had a few bugs, like some checks having a delay until the dialogue system registers them (which is e.g. why the ending takes several dialogue scenes to actually start) but overall I was pretty happy with the extent to which we could work with it!

If I find the time, I’d love to actually make a small tool to re-use in future projects where dialogue is needed and then share it with all of you!!

Time Management

For varying reasons, we didn’t really do much for the first few days of the jam. I’d say about 60% of what you can play came together in the last two days. This obviously meant a lot of crunch and stress towards the end of the jam, which itself isn’t unusual for jams but it was especially bad this time.

The most egregious consequence of this was that we couldn’t test the executable. Because of the large resource files, the web build is too large for itch.io to handle, but it only told us once it was uploaded, meaning we had to quickly compile and upload an executable within 5 minutes of the submission deadline. (The browser build upload took around 20 minutes.) The awful consequences of that are discussed in the next section.

As a lesson, I’ll try and enforce some testing of the release build 2 hours before the deadline in the future, just to catch critical compilation bugs.

One of three ways to check for file existence is correct. I chose incorrectly.

Sooo there’s a postjam version of Sunless Horizon. That version has a few minor improvements and one critical bug fix: Actually loading the different layers for card art and endings. If you played only during the jam, I highly encourage you to take 5 minutes and explore the postjam version!


Why did this happen? The artworks have different amount of layers (9 of Swords has 2, Knight of Swords only 1, 2 of Wands has 4, etc.), so we dynamically iterate over the resource directory until we find that no next layer exists. Godot has three ways of checking if a file exists, with File.file_exists(path), Directory.file_exists(path), and ResourceLoader.exists(path), all of which take in a filepath starting with “res://”. What I only discovered after the submission deadline was behind us, was that the first two only work when launching from the editor directly, and the third option only exists because someone else ran into the same issue and implemented ResourceLoader.exists(path) themselves. (And that can also check for the existence of any resource within a compiled executable. Thank you chanon from this github issue.)

To Do: Read the fucking docs of the functions you use. 

Also, this could’ve been done with texture regions instead of individual pngs. But we don’t talk about that. (I may sometimes forget features of Godot -.-)

Conclusion and discussion of the jam result


We placed in the top 20% of the PRESENTATION category, even tho like 30% of our visuals weren’t even there lmao. Thanks for that everyone! All categories are in the upper 50%, with the worst one being FUN at position 90/211. Sooo it’s not the best result but I’m happy people like the visuals and writing, which we put a lot of effort into! Maybe this finally concludes my tarot-obsession arc for now. Gonna focus on other systems next >:3

I'd like to thank all the people on freesound.org for posting CC0 sfx, Nomax for their lovely bursh set, everyone who played and/or rated Sunless Horizon, my co-dev for crafting characters that make people go "I like them", and you for reading this postmortem!

Cheers, stay uwu

Get Sunless Horizon

Leave a comment

Log in with itch.io to leave a comment.