Two Years After Celeste Classic on Playdate


Today marks the second anniversary since the release of my unofficial port of Celeste Classic from PICO-8 to Playdate. I wanted to share what I’ve been up to since and what’s next.

First, I’m very thankful for all the positive feedback I got after the release of this port and especially all the media cover. From Gamespot to Rock Paper Shotgun to The Verge to Panic themselves, I feel blessed for having something I put my heart into shared by so many. But then the impostor syndrome kicked very hard. A lot of gamers understood this was a port of the original Celeste Classic game by Maddy Thorson and Noel Berry. But some thought this was a demake of the fully fledged Celeste game (hello Gamespot 👋). And some thought my name was PICO-8 (hello Gamespot 👋).

I made this port because I wanted to learn how a “real” platformer game worked. And boy did I learn a ton doing this project! But even after publishing the first release of the game, I admit there were a few missing parts I blindly ported without really understanding them.

After releasing my port, I wanted to solve this and I had a few ideas of updates I could bring to the game, including:

  • Make the game truly full screen on Playdate. The original PICO-8 game has a resolution of 128×128. The Playdate console offers a resolution of 400×240. In my port, I doubled the resolution and hid four pixel lines on both top and bottom, making it 256x240. I always thought making the game widescreen would look very cool on Playdate.
  • Make the game compatible with speed run. While I did include a local scoreboard of your best runs, there were a lot of speed runs techniques I wasn't familiar with then and that got lost in my port. I wanted to fix that and make the game as faithful as possibleto the original.
  • Make the game moddable. Or at least make it easy to port existing mods.
  • Publish the game on Catalog (the Playdate’s official “app store”). In my wildest dreams, I could get the approval of the game’s original dev and publish the game for free there, making it available to even more people.

Full Screen

My first thought for making the game full screen was to use some sort of static overlaid frame made apart from the game. (Kind of how certain Game Boy games had specific frames when played on the Super Game Boy, like Donkey Kong.) This would have been easy to make but wouldn’t allow the player to move beyond the viewport of the original game. And editing the data of the levels themselves would have been difficult as I just had arrays of sprites indexes spit out of PICO-8. Without making my own level editor, that would have been tedious.

This is where I thought about an actual level editor I previously used and enjoyed: LDtk. And so I went and recreated all thirty-two levels of the original game inside LDtk. Every level is built on three different layers:

  • The background, with all the tiles drawn behind the player. Having these on their own layers then allows to draw them with a custom dithering on the Playdate.
  • The foreground, with all the tiles in front with the player.
  • The entities, with all the dynamic objects (the player, the strawberries, springs, spikes, …).

A bonus of using LDtk like this is I could set it up to use a colored sprite sheet for editing the levels and a 1bit version once loaded on the Playdate (using NicMagnier’s great PlaydateLDtkImporter class.)

Here are actual screenshots from the first three levels of the game at 400×240.

One awesome side effect of using LDtk for this is it pretty much opens the door wide open for modding! And it also eliminates constraints from PICO-8 (like the limit of levels or sprites we can use).

Catalog

Halfway through my fumblings, I submitted the game to Playdate’s catalog. (I knew we could submit games before they were actually done, and I knew Panic was pretty long to provide an answer for submissions, so I gave it a shot.) A month later, I received an email asking for clarification about the price:

We're writing back because your suggested price was "FREE". At this time, we're trying to limit the number of "FREE" titles in Catalog, to do everything we can to keep the value of Catalog games high. (We're afraid of the proverbial race to the bottom!). If you get a chance, please write back to this message and let us know if you'd be willing to charge for your title! If not, we may need to revisit in later.

Kudos to Panic for gatekeeping their platform in an actual good way. But given this is a port and I’m not the creator of the original game, there was no way and no intention from me to ever make this a paid game. And so there went an item from my check list.

Speed Run

One reason I wanted to get the game on Catalog was to be able to use the Catalog exclusive Leaderboard feature (where players can share and compare their score). Which leads us to speed run. In order to make the game fit for speed run, I wanted to make sure it was on par with its original version. And oh boy was it not. Turns out that by porting and changing significant things in the code, a lot of (then unknown to me) tricks were removed as well.

To fully realize this, I needed a way to run TAS (Tool-Assisted Speedruns). A TAS is a pre-recorded run containing the inputs needed for a perfect playthrough. Luckily, the PICO-8 Celeste Classic community has a whole site dedicated to TAS and even a TAS editor to create and edit runs (built in Lua with Love2D).

Here’s what a TAS file  looks like:

[0.636,]2,34,0,0,0,0,0,16,2,2,2,2,2,2,2,38,0,0,0,0,0,0,0,0,0,38,0,0,0,0,0,0,0,0,16,0,0,16,0,0,0,16,0,0,16,0,0,0,

The first array sets a dedicated value to objects whose position depends on Random Generated Numbers (like clouds or balloons). And the rest of the file is a list of inputs for each frame the game is running. Each number is a binary representation for the six possibles inputs at a given time (Jump, Dash, Left, Right, Up, Down).

Implementing this was not so difficult. For player inputs, the PICO-8 game calls a btn() function with a number matching the desired input. My initial implementation was to make a function that matches this to the Playdate SDK’s buttonIsPressed() function.

pico8.btn = function(i)
    return pd.buttonIsPressed(i)
end

What I did then was override this function when a TAS is running.


    pico8.btn = function(i)
        if self.keypresses[pico8.frames] ~= nil then
            if i == k_left and self.keypresses[pico8.frames][0] then
                return true
            elseif i == k_right and self.keypresses[pico8.frames][1] then
                return true
            elseif i == k_up and self.keypresses[pico8.frames][2] then
                return true
            elseif i == k_down and self.keypresses[pico8.frames][3] then
                return true
            elseif i == k_jump and self.keypresses[pico8.frames][4] then
                return true
            elseif i == k_dash and self.keypresses[pico8.frames][5] then
                return true
            end
        end
        return false
    end

I implemented a little key press visualizer (like in the Love2D’s TAS editor). And here’s what it looks like for now.


Now what?

I’m stuck.

The TAS revealed a lot of issues on the code that go way over my head. I've also revamped my entire code to be more object oriented (with the use of proper object classes from the Playdate’s SDK) only to realize this also has a negative impact on performance.

I'm at a point where I've worked on this all alone for so long now that I don’t feel motivated to go any further. I haven't touched my code since last november. Instead, I’ve been working on other little side projects like the restoration of the Crash Bandicoot 3 website or a WebArchive file viewer.)

So here I am.
Perhaps this post will spur a new boost of motivation in me.
Or maybe someone else can pick up on the project. (All my work in progress is available on GitHub in a develop branch.)
Or maybe this will mark a closure to this fun little side project.

For now, I’d like to get back to Playdate development by updating my video Player, Playorama, for the upcoming 2.7 SDK release with network streaming support.

Files

Celeste.1.0.3.zip 2 MB
Sep 21, 2023

Get Celeste Classic

Download NowName your own price

Comments

Log in with itch.io to leave a comment.

Super interesting read, and mad props to Panic for their stance on Playdate games!

(+1)

Really interesting! Thank you for sharing! I love the port so much