You too can sideload levels in your Playdate game
A quick guide to importing custom user data, what I've been playing, and some assorted links
Hello! It’s been a while. This occasional newsletter wasn’t meant to be quite so infrequent. I haven’t had much time to work on gamedev related stuff, so I’ve been prioritising development on my next game, Otto’s Galactic Groove!!, which I’m pleased to say is coming along nicely.
But in the spirit of writing a little more often, I wanted to bring this thing back to life and share few insights gleaned from my recent work.
A guide to adding sideloading to your game
Unlike most commercial games consoles, the Playdate provides owners with disk access — as anyone who might have sideloaded games from their computer will already know. This also opens the possibility for sideloading not just games, but content too!
What do I mean by content? Anything you want, really. Puzzle game Soko allows users to import custom level packs downloaded from the web. P-Racing uses the feature for sharing your time trial ghosts with others. And there are even apps like MP3 player Kicooya that is entirely designed around playing external audio files.
In case you haven’t tried already, sideloading data is as straightforward as the process for games. Simply boot your Playdate to disk mode while connected to a computer, and copy files into a game-specific data folder.
Games can then read the files directly from the disk using a handful of SDK functions. The ones I find most useful are:
playdate.file.listFiles to see what’s in the data folder1
json.decodeFile for reading JSON files
playdate.file.exists for one-off checking that a file is present
In my game, I’m using all of these so players can import their own custom levels. I use listFiles to find all JSON files in the game’s data folder; then use json.decodeFile to read each file. Each level includes names of related audio files, and to check if those have been imported too, I use file.exists. If that happens to return false, I show a helpful error message.2
Of course, before you get to that stage, we have to make sure the player has usable files in the first place. JSON is a flexible and useful file format, ideal for level layouts and other data. But it can be difficult to edit by hand, especially for non-developers. And audio files that are not converted to PDA audio format are more CPU-intensive and can affect gameplay.
So to allow users to create the files they need, I’ve created a web-based level editor specific to my game and an audio conversion tool (it’s open source!). I’ll go into those in greater depth in a future newsletter — they are way more complex than any of the sideloading stuff mentioned here.
What I’ve been playing


After months of my gaming time being dominated by Zelda, Metroid (Prime) and Mario (Wonder), I’m finally playing something non-Nintendo.
Neon White is a fast-paced first-person platformer where every level is under 30 seconds long and designed to coach you into being a speed runner. The dating sim aspects are questionable but the core gameplay is sticky as glue.
On Playdate, I just bought Pullfrog Playdate Deluxe, another curious platformer hybrid that’s like… if mr driller could jump. And match blocks like Tetris.
That’s it!
A short newsletter this time. Elsewhere:
I’ll be watching the Playdate Community Awards on Friday. There might even be a trailer of mine in there!
Playdate OS 2.4.0 introduced an experimental “/Shared” data folder that any game can access. I’m excited to see what ideas people come up with for it!
The developer of P-Racing open sourced their 3D library. Finally I can make Cat World Kart a reality.
I continue to enjoy reading other Playdate devlogs, like the latest one for Comet.
Oh and there’s a Catalog sale starting this week. Skwish will be among those on sale.
Thanks for reading!
Elliot/Pawprints
Keep in mind that these functions read from the root of your game’s app bundle (i.e. the packaged PDX) and the game-specific data folder at the same time, and doesn’t distinguish between them. More info here.
These file reading operations are pretty slow! My level select screen currently take a few seconds to appear — I will need to optimise that somehow.