Search documentation

Find pages, sections, and content across all docs.

WavedashDocs

Ren'Py

Publish Ren'Py visual novels with the built-in HTML5 web build target.

Ren'Py supports web builds through its Emscripten-based HTML5 export. The output is a folder of HTML, JS, WASM, and game data that Wavedash hosts directly. Wavedash detects Ren'Py automatically and drives the loading overlay from the engine's boot phases; calling the SDK from inside your script is done through renpy.emscripten.run_script(...).

View example project on GitHub Playtest the example project

Prerequisites

  • Ren'Py SDK (8.x)
  • The Ren'Py web platform package installed into the SDK (download from the same page; it unpacks a web/ folder into the SDK root)

Build for web

From the Ren'Py launcher: select your project → Build Distributions → check Web → build to a destination folder.

From the command line:

"$RENPY_SDK/renpy.sh" launcher web_build ./my-project --destination ./build

The output contains index.html, renpy.wasm, renpy.js, game.zip, and icons. Point upload_dir at that folder.

Loading progress

You don't have to wire this up — Wavedash detects ?engine=RENPY from the iframe URL and installs a progress shim that watches Ren'Py's own boot phases (engine download, game data download, unpacking, script load). The Wavedash loading overlay tracks them automatically.

Initialize the SDK

Calling Wavedash.init() is required. It opts your game into Wavedash platform features and dismisses the loading overlay. Call it from before_main_menu, which is the earliest hook where the game is interactive.

game/00_wavedash.rpy

default wavedash_inited = False

init -100 python:
    def wavedash_init_once():
        if store.wavedash_inited:
            return
        store.wavedash_inited = True

        if not renpy.emscripten:
            return

        renpy.emscripten.run_script("""
            if (window.Wavedash) {
                window.Wavedash.init({ debug: true });
            }
        """)

label before_main_menu:
    $ wavedash_init_once()
    return

renpy.emscripten is the documented Ren'Py module for web JS interop. On desktop builds it's None, so the truthy check doubles as a platform guard.

Calling SDK methods

Inline more JS in the same run_script block (or write a helper for each beat). Unlocking an achievement:

$ renpy.emscripten.run_script("""
    if (window.Wavedash) {
        window.Wavedash.setAchievement('first_chapter_complete', true);
    }
""")

Reading the current player's username (sync round-trip via run_script_string):

$ raw = renpy.emscripten.run_script_string("JSON.stringify(window.Wavedash?.getUsername() ?? null)")
$ import json
$ username = json.loads(raw) or "Player"

Any other JS-SDK method (setStat, toggleFullscreen, toggleOverlay, getUserAvatarUrl, etc.) is reachable the same way — they're all on window.Wavedash. See the JS SDK reference for the full list.

Fullscreen

Ren'Py's built-in Preference("display", "fullscreen") doesn't work on Wavedash web — the iframe doesn't own the real fullscreen target. Use the Wavedash helper instead, from a preferences screen or button:

screen wavedash_fullscreen_button():
    textbutton "Fullscreen":
        action Function(renpy.emscripten.run_script, "window.Wavedash?.toggleFullscreen()")

wavedash.toml

game_id = "YOUR_GAME_ID_HERE"
upload_dir = "./build"

[renpy]
version = "8.6.0"
executable = "game.zip"

The [renpy] section tells the Wavedash CLI to treat the build as a Ren'Py 8.x web export.

Notes

  • main_menu label vs screen: Ren'Py checks for a main_menu label before using the main_menu screen. If you only define a screen, add an explicit label main_menu: call screen main_menu so Ren'Py actually mounts it.
  • Template screens required: Real Ren'Py games include game/screens.rpy, game/gui.rpy, and game/gui/ images from the SDK template. If you started from a bare script.rpy, the ESC menu (Save / Load / Preferences) will be missing.
  • Web build size: Ren'Py web builds can be 50MB+ with audio/image assets. Compress audio to OGG and resize images for web before building.