Kirin: running RPG Maker XP on Android
How an engine born for Windows can run on modern Ruby, ARM64 and the GPUs inside Android devices.
RPG Maker XP was born for a very different era.
When it arrived, its natural environment was Windows. Games created with it were designed to run on a PC, with a desktop architecture, Windows-specific APIs and a Ruby interpreter integrated through RGSS. Even the official RPG Maker XP requirements were built entirely around Windows.
More than two decades later, trying to run one of those same games on an Android phone presents an interesting problem.
Android does not understand RPG Maker XP.
It has no RGSS. It does not use the same Windows APIs. Its file system behaves differently. Touch input is nothing like a keyboard. Audio is handled through another stack. The GPU sits behind interfaces designed for mobile devices. And much of the code in games built with Pokémon Essentials is written in Ruby under the assumption that it will run inside a Windows environment.
That is where Kirin begins.
This is not Windows emulation
The first solution might seem obvious: emulate an entire PC inside the phone.
Kirin takes another path.
Instead of reproducing all of Windows, it builds the environment the game needs directly on Android.
This greatly reduces the number of components that must be reproduced. The game continues to use its original maps, events, sprites, scripts and resources, while a modern engine implements the features that previously depended on the RPG Maker XP environment.
The historical foundation is mkxp and, later, mkxp-z. The latter is a heavily modified version of mkxp built around one of the hardest problems in the RGSS ecosystem: running complex projects, particularly games based on Pokémon Essentials. The mkxp-z project explains that this was one of its original goals because Essentials depends so heavily on Windows APIs.
But mkxp-z is not Kirin. The upstream project advertises support for Windows, Linux and macOS, not Android. Kirin begins with that work and evolves it for a specific mobile environment.
That distinction matters. Kirin neither distributes games nor replaces their files: it provides the environment for running compatible projects that the user already owns on Android.
The first major problem: Ruby
In a conventional game, it is tempting to assume that most of the work happens on the GPU. That is not always true in RPG Maker XP.
A huge amount of Ruby code is constantly running behind what appears on the screen:
- Move the player
- Update an event
- Open a menu
- Calculate a battle
- Update a sprite
- Check a collision
- Run an animation
- Process an NPC
All of that can pass through Ruby. Pokémon Essentials takes this characteristic much further: on top of RPG Maker XP, its scripts build battle systems, creatures, moves, items, maps, interfaces and many additional mechanics.
A game can therefore show a relatively simple 2D scene while the processor performs thousands of Ruby operations behind it. This is why a more powerful GPU does not necessarily fix a slow game.
Ruby takes too long → the next frame cannot begin → the GPU waits → FPS drops appear.
This is where Kirin starts to move even farther away from the original RPG Maker XP environment.
From an old Ruby to a modern Ruby
The code in many RPG Maker XP games was written for extremely old Ruby versions. Running an interpreter from that era forever, however, also means giving up more than twenty years of improvements to the language and its virtual machine.
Kirin aims to preserve the behavior the game expects while using a modern CRuby/MRI foundation. This is not simply a version-number change.
Updating Ruby can break old behavior. Methods have changed, some parser tolerances disappeared, string encoding works differently, and certain scripts rely on behavior that was never documented in the first place. Pokémon Essentials also contains an enormous amount of code accumulated over many years.
Kirin compatibility is therefore more than using a newer Ruby. It means making software written for an old Ruby continue to behave correctly on a modern one. mkxp-z already follows the path of using MRI as its Ruby implementation; Kirin brings that approach to Android and combines it with different runtime profiles according to each project's needs.
From interpreting Ruby to compiling it while the game runs
This is where one of the most interesting differences between RPG Maker XP-era Ruby and modern Ruby appears. Code no longer has to remain interpreted at all times.
Ruby now has JIT, or Just-In-Time, compilers that can identify frequently executed code and transform it into native machine code.
This is particularly interesting for a modern phone. Most current Android devices use ARM64 processors. Both YJIT and CRuby's new ZJIT have upstream ARM64/AArch64 support, although the official ZJIT documentation currently lists macOS, Linux and BSD, not Android. Making them work correctly inside Kirin requires specific integration work; it is not a matter of flipping a switch.
YJIT is the established option in modern Ruby and is already part of one of Kirin's runtimes. ZJIT represents a new generation still under development: a method-based compiler driven by execution profiles and an intermediate representation designed for increasingly aggressive optimizations. In Kirin, ZJIT is an integration and experimentation path, not a promise of automatic speedups for every game.
This opens a possibility that RPG Maker XP never had: the Ruby code inside a game can be dynamically transformed into native code for the phone's processor while the player is playing.
A JIT has a cost. It must observe the program, identify hot code, compile it and reserve executable memory. Games, however, have one particularly favorable trait: they repeat the same paths over and over. The same update method, the same sprite system, the same event or battle code, the same update, frame after frame, for minutes or even hours.
That kind of workload is precisely where a JIT can become interesting.
But Ruby is only one part
Even if every line of Ruby could run instantly, another problem would remain: the game still has to be drawn.
RPG Maker XP was born for a Windows PC. Kirin runs inside a phone whose GPU may be Mali, Adreno, PowerVR or another mobile architecture. Something must translate between those two worlds.
The game continues to think in RGSS concepts: Bitmap, Sprite, Viewport, Tilemap, Plane and Window. The phone, however, ultimately needs commands that its GPU can execute.
Kirin's current production path does that work through a native renderer based on OpenGL ES 3. Vulkan represents a possible future evolution, not a technology this article presents as finished. That distinction matters: changing graphics APIs does not replace compatibility work and cannot guarantee better performance by itself.
- Pokémon Essentials
- Ruby scripts
- CRuby / YJIT / ZJIT experiments
- Kirin bindings
- Engine derived from mkxp-z
- Android-adapted renderer
- OpenGL ES 3
- GPU driver
- Screen
Every arrow in that chain is a place where a performance or compatibility problem can appear. That is the real work of Kirin: not simply making RPG Maker XP “open” on Android, but allowing an ecosystem built around technology more than twenty years old to coexist with modern Ruby, ARM64, JIT compilation and mobile GPUs without rewriting the game from scratch.
What really happens during one frame in Kirin
To understand where time is spent, we need to look at a single turn of the game loop. A frame does not begin at the GPU; it begins by collecting the state of the world.
1. Android collects input
The touchscreen, a physical controller or the virtual keyboard produces Android events. Kirin converts them into the actions RGSS expects: directions, confirm, cancel, open a menu or run an assigned function. That translation must preserve holds, repeats and diagonals consistently.
2. Ruby updates the game
The project loop runs the logic for the current scene. It checks events, switches and variables; updates characters and NPCs; calculates collisions; processes the interface; and decides what changed. In a large project, this stage can call an enormous network of Ruby methods before anything is drawn.
3. RGSS updates the visual scene
Scripts modify graphics objects. A sprite changes position or bitmap, a viewport alters its tone, a tilemap advances its autotiles, and a window redraws its contents. Kirin's bindings translate those Ruby operations into native structures the renderer can use.
4. The renderer organizes the work
The engine sorts elements by depth, applies clipping and transforms, prepares textures, selects shaders and groups operations that can be submitted together. Reducing duplicate loads, state changes and data transfers is essential on a mobile GPU, especially in maps with many sprites and layers.
5. The GPU composes the image
OpenGL ES sends commands to the driver. The GPU processes vertices, textures, blending, tones and effects until the final image is ready. Android then presents that image on the screen, and the cycle starts again.
Every stage shares the same time budget. If Ruby logic arrives late, the GPU may sit idle. If the renderer creates too much work, optimizing Ruby will not be enough. If the driver stalls, the time saved in previous layers disappears.
This is why Kirin does not pursue only a high FPS counter. RPG Maker XP ties much of its logic to a particular update cadence; stable timing helps movement, animation, audio and control response stay synchronized. One fast frame followed by a very slow one can feel worse than a slightly lower but consistent sequence.
YJIT, ZJIT and the real bottleneck
YJIT and ZJIT target the Ruby portion of the chain, but they do so with different designs. YJIT compiles frequently used blocks and can return to the interpreter when it encounters a case it has not specialized. ZJIT works at the method level and uses profiles to build an intermediate representation on which it can apply optimizations.
The useful question for Kirin is not which one produces the biggest number in an isolated benchmark. Warm-up time, memory use, the amount of game code that remains inside the JIT, ARM64 stability and compatibility with real scripts all matter. One fangame may spend most of its time repeating a few methods; another may follow many different paths and offer fewer compilation opportunities.
Measurement must cover the entire frame. If Ruby dominates CPU time, a JIT may create headroom. If the load sits in tilemap preparation, texture uploads or the graphics driver, the solution belongs at another level. Kirin can improve precisely because it controls the whole chain, from the selected runtime to image presentation.
Compatibility and performance move together
Pokémon Essentials shows how far an RPG Maker XP project can go. Its generations, community plugins and the systems created by each fangame form ecosystems of their own. A correction that is valid for one version may be unnecessary—or even wrong—for another.
Kirin combines general compatibility with targeted adjustments when a project uses a known pattern. It may adapt a missing call, correct a Windows assumption or accelerate a path that runs many times per frame. These changes are evaluated with the aim of preserving the game's rules, data and identity.
There are deliberate boundaries as well. Kirin is a runtime, not a store: it does not include third-party projects, graphics, music or data. Every player must use files they have the right to use. Keeping the application separate from games makes clear what Kirin provides and what belongs to each project's authors.
Two generations of software, one screen
When a Pokémon Essentials game begins running in Kirin, two generations of software work at the same time: code from an engine born for Windows more than twenty years ago, and a modern Android platform running it on hardware that RPG Maker XP could never have imagined.
Ruby must understand old and modern scripts. RGSS needs a compatible implementation. The graphics engine must speak to a mobile GPU. Input, audio and files must integrate with Android. Kirin brings those pieces together, absorbs their differences and translates them so the project can focus on what has always mattered: the game.
Try Kirin on Android
Read the installation guide and add a compatible project to your library.
View installation guide