Starfait is a re-implementation of GameMaker: Studio's runner (YoYo Runner) in Kotlin, targeting Undertale v1.08 (WAD Version 16).
To keep the project's scope simple, Starfait only supports Undertale v1.08 and NOTHING ELSE. I may add support for DELTARUNE later if I'm feeling fancy.
Undertale's True Pacifist route is playable in Starfait, with some minor graphical glitches due to missing builtins.
By virtue of it being a GameMaker runner re-implementation, other games do work as long as they were built with GM:S 1.4.1773..1.4.9999 and only use the same features and builtins that Undertale uses.
I'm not planning on going out of my way to support any other games, because that's a recipe for burnout. Supporting all games is hard because GameMaker has TONS of builtin functions and features. Re-implementing the runner is more akin to Wine or a high-level emulator than to a console emulator.
Warning
Starfait requires Java 27! (with the exception of the AppImage build)
| Linux | Download | |
| Linux (AppImage) | Download | |
| Windows | Download | |
| macOS | Download | |
| FreeBSD | Download |
I only test and use the Linux build, so experience with other platforms may vary.
If you run Starfait without specifying a WAD file, a file picker will open to let you select which Game WAD you want to run.
Usage: starfait-runner [<options>] [<wadfile>]
Options:
--print-game-objects=<regex> Prints the game objects' fields to the console and exits
--print-backgrounds=<regex> Prints the backgrounds' fields to the console and exits
--print-sounds=<regex> Prints the sounds' fields to the console and exits
--print-fonts=<regex> Prints the fonts' fields to the console and exits
--print-rooms=<regex> Prints the rooms' fields to the console and exits
--print-scripts=<regex> Prints the scripts' fields to the console and exits
--print-codes=<regex> Prints the codes' fields to the console and exits
--print-variables=<regex> Prints the variables' fields to the console and exits
--print-functions=<regex> Prints the functions' fields to the console and exits
--print-texture-pages=<text> Prints the texture pages' fields to the console and exits
--print-sprites=<text> Prints the sprites' fields to the console and exits
--print-unimplemented-functions Prints the unimplemented functions that the game uses
--print-object-tree=<text> Prints the object tree
--dump-sprites=<path> Dumps all the game's sprites to a specific folder
--dump-sprite-masks=<path> Dumps all the game's sprite masks to a specific folder
--dump-tiles=<path> Dumps all the game's tiles to a specific folder
--trace-opcodes=<text> Traces opcodes
--trace-function-calls=<text> Traces function calls
--trace-alarms=<text> Traces alarms
--trace-events=<text> Traces events
--trace-variable-reads=<text> Traces variable reads
--trace-variable-writes=<text> Traces variable writes
--trace-frame-duration=<text> Traces frame durations
--trace-code-execution=<text> Traces code execution
--enable-collision-rendering If enabled, enables the collision rendering debug overlay by default (can be toggled during runtime using F5)
--draw-invisible-instances If enabled, draws invisible instances by default (can be toggled during runtime using F6)
--record-inputs=<path> Records your inputs to a file
--playback-inputs=<path> Playbacks inputs from a file
--screenshot=<path> Sets the name of the screenshot file, if the filename contains %d the %d token will be replaced with the current frame count
--screenshot-at-frame=<int> Screenshots the runner at a specific frame
--exit-at-frame=<int> Automatically exit the runner at a specific frame
--exit-when-playback-ends Automatically exit the runner when the input playback is finished
--speed=<float> Changes the game speed
--fast-forward-speed=<float> Changes the game speed when fast-forwarding, toggle fast-forward mode by pressing TAB
--run-full-speed-until-frame=<int> Runs the game at full speed until a specific frame
--pause-at-frame=<int> Automatically pauses the runner at a specific frame
--headless Runs Starfait in headless mode
--replace-room=<text> Replaces a specific room with another one, uses the following format: RoomNameOrIndexToBeReplaced=RoomNameOrIndexToBeTheNewRoom
--dump-state=<path> Sets the name of the runner state dump file, if the filename contains %d the %d token will be replaced with the current frame count
--dump-state-at-frame=<int> Automatically dump the runner state at a specific frame
--disassemble=<text> Disassembles bytecode
--master-volume=<float> Controls the master volume of the game
--seed=<int> Changes the seed of the game, useful for reproducible runs
--save-folder=<text> Sets where the game's saves will be saved, by default it is saved to "saves/GameName/"
-h, --help Show this message and exit
- Page Up: Goes to the previous room
- Page Down: Goes to the next room
- F4: Restarts the runner
- F5: Toggles the collision rendering debug overlay
- F6: Toggles invisible instances
- F10: Resets the
global.interactvariable in Undertale back to0 - F11: Dumps the current runner state to a file
- F12: Jumps to a room of your choosing by typing the room name into a input box
- P: Pauses the runner
- O: If paused, steps one frame
- TAB: Toggles fast-forward
If you don't specify the lwjglNativesPlatform Gradle property the runner will default to natives-linux.
./gradlew :starfait-runner-sdl3:installDist -PlwjglNativesPlatform=natives-linuxThings that I learned along the way while developing Starfait.
- Walking Through a Real Bug
- Bytecode
- Precise Collision Masks
- Quirks and Miscellaneous Things
- WinPack/TranslaTale WADs
- TinyGameMakerVM
Something something but the JVM is slow!! I don't give a damn
Butterscotch already exists for that use case.
If you want to see a what-if scenario, here's what Starfait would look like if it was written in C.
Butterscotch was already taken, Cinnamon was already taken, so why not Starfait?
- GameMaker-HTML5 - GameMaker's HTML5 runner, has references of how the runner logic works and has builtins implementations.
- UndertaleModTool - Very useful to check what Undertale's decompiled code looks like compared to what the bytecode looks like.
- Ghidra - For decompiling the YoYo Runner's code for references.
- Toby Fox - For creating Undertale and DELTARUNE!



















