Renplay documentation
Engines
Which game engines Renplay plays, and how an engine is added.
Renplay is a player for Ren’Py games. Other engines are second-class citizens, shown as Beta in the app: Renplay recognizes them, installs the ones a browser can run, and gives them the features that come cheap. When a feature works for Ren’Py and not for another engine, that is fine.
The focus is Ren’Py, plus engines whose normal download plays easily: HTML games today. Unity WebGL and Godot web builds install and play too, but games rarely offer them as a download (on itch.io they are the in-browser versions), so the catalog and the website leave them out.
Support
Section titled “Support”| Engine | Recognized | Installs | Notes |
|---|---|---|---|
| Ren’Py 8, and 7 on the 8 engine | yes | yes | Everything: saves on the server, streaming, phones, mods |
| HTML: Twine (SugarCube, Harlowe), RPG Maker MV and MZ, TyranoScript, Construct, plain pages | yes | yes (2.6) | Web pages already. Tested with Twine (SugarCube); RPG Maker MV/MZ, TyranoScript and Construct take the same path but are untested |
| Godot 4 web builds | yes | yes (2.9) | The developer’s single-threaded web export (on itch.io, the version that plays in the browser). Tested with a Godot 4.7.1 game. Threaded web builds need SharedArrayBuffer, which the sandbox cannot give |
| Godot 4 PC builds | yes | planned | Godot’s own web template loads a PC .pck (tried), but games with native plugins (GDExtension) or C# cannot run in browsers |
| Unity WebGL builds | yes | yes (2.9) | The developer’s WebGL build, served as it is. Tested with a Unity 6 game |
| Unity PC builds | yes | never | Compiled for one system; a browser cannot run them |
| RPG Maker XP, VX, VX Ace; Wolf RPG; Kirikiri; GameMaker; Unreal | yes | never | Windows (or PC) programs |
Flash (.swf) | yes | maybe | Ruffle plays many Flash games in a browser |
server/src/pipeline/family.ts does the recognizing (detectEngine), from the file names in an
archive and a few bytes of its files: Godot’s pack header gives the version, a Twine page names its
story format, RPG Maker’s core script its version, Unity’s globalgamemanagers its version.
INSTALLABLE lists the families this version installs. Add games shows every download with what
made it, and the reason when it cannot be installed.
Ren’Py 7 games
Section titled “Ren’Py 7 games”Renplay builds games made with Ren’Py 7 (and older) on the Ren’Py 8 engine, which loads their
compiled scripts. A game that starts has no Python 2 syntax left to trip on; what can still fail
is Python 2 behaviour, such as xrange, iteritems or unicode, or sorting numbers together
with text. If such a game stops with a Python error, check the catalog for a note, and
see Troubleshooting.
Renplay picks the engine for a game from its recipe, then RENPLAY_ENGINE, then the newest engine
of the game’s major version. See Configuration.
How an engine plugs in
Section titled “How an engine plugs in”This part is for developers.
Each engine needs four things; everything else (library, covers, the player’s toolbar, saves panel, fullscreen, mute, wake lock, phones) is shared.
- Detect (
family.ts): family, version, the folder the game lives in, its start file. - Build: put the game’s files into a build (
assets.packand its index, as for Ren’Py), so they are served with byte ranges and long caching. Converting images to WebP works for any engine that loads images by name; streaming on demand works only where the engine fetches files itself (HTML games do; Godot and Unity load one big pack). - Runtime: a small script in the game’s frame that tells the player when the game is ready,
keeps its saves on the server, and handles mute. Ren’Py’s is
runtime/renplay-runtime.js. - Player: the shared player, with the features the runtime supports.
| Feature | Ren’Py | HTML | Godot | Unity WebGL |
|---|---|---|---|---|
| Saves on the server | yes | localStorage synced | user:// (IndexedDB) synced | IndexedDB synced (/idbfs, the game’s own) |
| Streaming files on demand | yes | yes (the page fetches them) | no (one pack) | no (one data file) |
| WebP images | yes | yes | no (imported into the pack) | no |
| Mute | yes | yes (Web Audio and media elements) | yes (Web Audio) | yes (Web Audio) |
| Phones | yes | depends on the page | depends on the game | rarely |
| Mods, script cache, Python stand-ins | yes | no | no | no |
Security
Section titled “Security”A Ren’Py build runs Ren’Py’s engine, which Renplay ships. Other engines run the game’s own
JavaScript. In a frame on Renplay’s origin, that code could call Renplay’s API (delete saves,
uninstall games). So games of other engines run in a sandboxed frame (sandbox="allow-scripts",
no allow-same-origin): an opaque origin with no access to Renplay’s cookies, storage or API. The
runtime talks to the player only with postMessage.
An opaque origin has no localStorage or IndexedDB either, so the runtime provides them:
- HTML games: a
localStoragestand-in backed by the server’s save store, loaded before the game’s scripts run (SugarCube and RPG Maker keep saves there). - IndexedDB: Godot and Unity keep files in it through Emscripten’s IDBFS (Godot’s
user://at/userfs, Unity’s at/idbfs), and games keep their own databases there too (a Unity game, RPG Maker MZ through localforage). The runtime puts an in-memory IndexedDB in place (runtime/vendor/fake-indexeddb.js, bundled byruntime/vendor/build.sh), restores the stored databases before the game’s scripts run (IndexedDB serves a database’s open requests in order, so the game’s wait for these), and after every write sends a snapshot (indexedDB.jsonin the save folder; binary data, dates and the like keep their type). Unity’s download cache (UnityCache) is refused, so the game fetches again instead of holding it in memory. - Cache Storage (
window.caches) throws in a sandboxed frame; the runtime makes it absent, which loaders such as Unity’s treat as no caching.
Ren’Py games can also run JavaScript (Ren’Py’s emscripten module), so moving them into the same
sandbox is worth doing later; their saves already go through the runtime.
Catalog schema 3
Section titled “Catalog schema 3”Recipes say which engine made the game. Schema 3 names (index.v3.json, Renplay 2.6 and later):
engine: godot # renpy (default) | html | godot | unityruntime: 4.6.2 # web runtime to build with, from renplay-org/engines (optional)releases: - version: "0.17.0" madeWith: 4.6.2 # version of the engine the game was made with runtime: 4.6.2 # per release, instead of the recipe's (optional)saveDir keeps its name; what it means depends on the engine (Ren’Py’s config.save_directory, a
Godot project’s user:// folder name, a SugarCube story’s save id). The catalog still publishes
schema 2 as index.json for Renplay 2.5 and older: Ren’Py games only, with the runtime as
engine and a release’s madeWith and runtime as renpy and engine. normalizeRecipe in
catalog.ts reads both.
The engines repository will list other runtimes (Godot’s web export templates, one per version)
with a family field; entries without one are Ren’Py.
-
Recognize (done in 2.6): detection, schema 3, Add games lists other engines with reasons.
-
HTML (done in 2.6 for Twine):
pipeline/html.tspacks the game’s folder (images as WebP under their own names); the page is served from the pack withruntime/renplay-html.jsand the storedlocalStorage(<save folder>/localStorage.json) inlined first; the player sandboxes the frame and stores what the runtime sends. Tested with a SugarCube 2.36.1 game: plays in Chromium and WebKit, a save made in one browser loads in another, the game cannot reach Renplay’s API. Next: an RPG Maker MV or MZ game (MZ keeps saves with localforage, which falls back tolocalStoragewhen IndexedDB is missing). -
Godot 4 (web builds done in 2.9): a single-threaded web export is a page with the engine (
<name>.wasm,<name>.js) and the pack (<name>.pck); it installs like an HTML game, and the IndexedDB stand-in keepsuser://. Tested with a Godot 4.7.1 game: plays, and its settings saved in one browser load in another. Threaded web exports need cross-origin isolation (SharedArrayBuffer), which the sandboxed frame does not have; they are refused with that reason. PC builds are planned, as follows.PC builds: the single-threaded web template per version, picked from the pack header. Tried on 2026-11-03 with Godot’s official 4.6.2
web_nothreads_releasetemplate and the Windows.pckof a game (4.6.2, 1.2 GB), unchanged: the engine starts, renders with the Compatibility renderer (WebGL 2) and loads the game’s scenes, so a PC pack works as it is. That game cannot run, though: its core is a native plugin (phone_core, classKpsPhoneCore) with no web build, and the start crashes without it. The whole pack is held in memory (1.3 GB of JavaScript heap for a 1.2 GB pack), so big packs will not fit on phones. Needs a Godot game without native plugins to finish this phase; detection already warns about plugins and C#.web_dlink_nothreads_releaseloads GDExtensions, but only ones compiled for the web, which games do not ship.What building it takes, from that try:
- Runtime pack: renplay-org/engines builds
godot-<version>from the officialGodot_v<version>-stable_export_templates.tpz(checked against the release’s SHA512-SUMS):godot.js,godot.wasm(gzipped), the two audio worklets and Godot’s license. The index lists them under a separateruntimeskey withfamily: "godot", so Renplay 2.7 and older, which readengines, never mistake them for Ren’Py. Pick the pack matching the.pckheader’s version, else the newest of the same minor version. - Build: the
.pckgoes into the assets pack asgame.pck; the page is Renplay’s own, startingnew Engine({ executable, mainPack: 'game/game.pck', persistentPaths: ['/userfs'] }). - Sandbox: the engine files under
/engine/needAccess-Control-Allow-Origin: *(the sandboxed frame fetches the wasm and adds the audio worklets from an opaque origin). - Saves: the IndexedDB stand-in (done, see Security) covers
user://.
- Runtime pack: renplay-org/engines builds
-
Unity WebGL (done in 2.9): the build is served as it is and installs like an HTML game. One game’s build from itch.io names its files
.brbut holds them uncompressed (itch.io unpacks uploads), so files ending in.bror.gzget the type of the name underneath and no encoding; Unity’s loader takes them either way. Its photo bundles inStreamingAssetsare fetched by the game itself. Tested: plays, and its progress saved in one browser loads in another. Unity PC builds cannot run in a browser.
Later candidates, by how many adult games use them: TyranoScript and Construct (HTML, so phase 2 may cover them), Flash through Ruffle, NW.js and Electron apps whose content is a web page.