Submission #6217: buhbai, fishmcmuffins, keylie, DevilSquirrel, EuniverseCat, KT's Linux Celeste in 27:04.43

Console Linux Emulator libTAS v1.3.2
Game Version any Frame Count 97466
ROM Filename Celeste.bin.x86_64 Frame Rate 60
Branch Rerecord Count 0
Unknown Authors buhbai, fishmcmuffins, keylie
(Additionally: DevilSquirrel, EuniverseCat, KT)
Game Celeste
Submitted by keylie on 1/4/2019 4:04:42 PM

Submission Comments
Celeste TASing has been made possible thanks to DevilSquirrel, by modifying the game to read inputs from a file, as well as showing useful values and providing a friendly input editor. This game has been featured during the TAS block at SGDQ 2018. Since then, the any% TAS has been improved by almost two minutes, and inputs were converted to libTAS to make this submission possible.

Game objectives

  • Emulator used: libTAS 1.3.2
  • Aims for fastest in-game time
All movement techniques are described in the game resource page. This submission text only focuses on specific tricks.

libTAS conversion

The input conversion between Celeste TAS tool and libTAS did not cause any issue. Inputs from each level were converted separately, and inputs outside level (intro, hub, etc.) were done inside libTAS. Indeed, Celeste TAS tool ignore loadings, it feeds inputs only when pulled by the game engine.
There was only one desync at the end of stage 7A, where one frame needed to be deleted. Because it happened after a feather section, we suspect that this has to do with analog input conversion. Indeed, Celeste TAS tool input format contains analog inputs described as a stick angle in integer degrees (0 - 359), and feeds the converted X/Y coordinates to the high-level game code (into XNA/FNA game controller struct). On the contrary, libTAS feeds raw analog inputs as 16-bit X and Y coordinates, before any processing (such as deadzone) is performed by the XNA/FNA framework. So the script that converts Celeste TAS tool inputs to libTAS inputs requires some floating point operations, which could lead to small differences in the obtained analog inputs.
Also, Celeste TAS tool does not keep track of rerecords, so this value was set to 0.

In-game vs real-time

This TAS aims for fastest in-game time. This follows the convention for unassisted speedruns, as the game was designed with speedrunning in mind, providing a robust in-game timer, as well as displaying individual level times. Moreover, optimizing this game for real time would lead to differences, because several animations such as dashing, crystals or bounces freeze the stage and the in-game timer for several frames. A TAS aiming at real time would limit the use of dashes, resulting in slower movement but less freeze frames.


The normal way of unlocking a chapter in this game is by completing the previous chapter. However, each chapter holds a secret cassette, which unlocks a special stage called B-side. By unlocking and completing the B-side of a chapter, the next chapter is unlocked. In this category, it is in fact faster (in-game time) to unlock and complete the B-side of chapters 5 and 6 instead of doing the levels normally.

Stage by stage comments


The main optimization of this stage is using double corner boosts.


We avoid most of the springs because it reset our speed.


We use the cutscene warp to place us directly into the dream block to save a bit of time. When getting out of dream blocks, we can jump twice for some horizontal boosting. We can also dash diagonally downward and jump at the same time to execute an instant hyper dash. Collisions inside dream blocks have a bit of leniency, so we can cut through corners. The end of the stage features several ultra dashes.


This level features a lot of crouched dashes to go through dust bunnies. When getting near Oshiro during the escape, time is slowing down but the in-game timer still runs at full speed, so we must avoid getting close to him, or knock him off.


The wind adds (or remove) a constant value to our movement, except when dashing. Thus, we try to dash as much as possible when the wind is against us, and to avoid dashing when the wind is pushing us forward. The snowballs cancel our dash, which is very handy. However, we don't have much freedom to manipulate where they are appearing.


We head to the cassette to unlock 5B. Inside the cassette screen, red/blue blocks are synchronized with the music. As a consequence, they are not delayed when the timer is frozen by a dash. So, to save in-game time, we have to dash as much as possible when we are waiting for red/blue blocks.


Grabbing Theo cancels our dash, so we can setup a grounded ultra dash and grab him to conserve this speed. However, grabbing Theo takes a lot of time, which makes this section very difficult to optimize.


Analog stick is used when in feather form for more precise movement.


Bumpers send us further if we press the direction away from them when bounced.


When the wind is pushing downward, we can jump on spikes if at a precise position. This is due to the order of steps in the game engine, we get pushed downward after the check for spikes, and we can jump away from the spikes during the next frame.


Huge thanks to all Celeste speedrunners and the Celeste discord for all the suggestions and feedback.

feos: Judging...
feos: Replacing the movie with a 1565 frame improvement. Also I cleared the rerecord count (per author agreement), fixed a path, and reordered a sentence in the annotations.
feos: This games works the same as SteamWorld Dig 2 in terms of level loading: it spawns threads in-between levels, and libTAS can't control them. The situation is exactly the same, no gameplay trick is related to this, as no gameplay is there when loading happens. And the movie also aims for in-game time, which only counts gameplay times.
So exactly like that other submission, this movie relies on mid-level time pauses, and for exact same reasons I consider it acceptable. See my judgment there for all the details.
Great feedback, accepting to Moons (similar in that regard too).
fsvgm777: Processing.

Last Edited by on 1/1/2022 6:13 PM
Page History Latest diff List Referrers