Search documentation

Find pages, sections, and content across all docs.

WavedashDocs

Ruffle

Ship Flash (SWF) games to Wavedash — the platform wraps them in Ruffle and handles the SDK load lifecycle.

View example project on GitHub Playtest the example project

Ruffle is an open-source Flash Player emulator written in Rust. Wavedash has first-class support for Ruffle: upload your .swf, point wavedash.toml at it, and the platform wraps the SWF in Ruffle automatically. You don't need to bundle the Ruffle runtime or write any SDK code in your Flash game.

Upload your SWF

  1. Put your compiled .swf file in your upload directory (e.g. build/game.swf).
  2. In wavedash.toml, add a [ruffle] section pointing at the file:
game_id = "YOUR_GAME_ID_HERE"
upload_dir = "./build"

[ruffle]
version = "0.2.0-nightly.2026.2.24"
executable = "game.swf"
  1. Run wavedash dev to test locally. When ready to ship, upload your build and publish it from the Developer Portal.

Ruffle version

version must be a Ruffle nightly dated 2026-02-24 or later, written the way the @ruffle-rs/ruffle npm package names them (0.2.0-nightly.YYYY.M.D). It doesn't select the runtime: the platform currently loads 0.2.0-nightly.2026.2.24 for every 0.2.0-* version.

SDK integration

None required in your SWF. The platform reports load progress while the Ruffle runtime downloads and your SWF loads, then calls Wavedash.loadComplete() once the SWF is ready to play.

It does not call Wavedash.init(). Without it, no SDK events are ever delivered (lobby, P2P, backend, stats, fullscreen, entitlements), P2P runs on its default settings because init() is where the p2p config is applied, and readyForEvents() and the getP2P* getters throw. Everything else on window.Wavedash works. If your game needs events, call init() from a loader script once the SWF is ready — init() calls loadComplete() for you:

// build/loader.js
window.rufflePlayer.addEventListener("loadeddata", () => Wavedash.init());

If you want to call the SDK from ActionScript, expose plain functions from your loader script and call them with ExternalInterface.call(...). Don't call a dotted name like "Wavedash.setAchievement" directly — the SDK methods need Wavedash as this, which ExternalInterface.call doesn't provide:

// build/loader.js
window.wavedashSetAchievement = (id) => Wavedash.setAchievement(id, true);
import flash.external.ExternalInterface;

if (ExternalInterface.available) {
    ExternalInterface.call("wavedashSetAchievement", "first_win");
}

Custom loader script

If you need to run JavaScript before your SWF starts — for example, to set up save-data bridges, attach Ruffle player event listeners, or register ExternalInterface hooks — add a loader_url:

[ruffle]
version = "0.2.0-nightly.2026.2.24"
executable = "game.swf"
loader_url = "loader.js"

Place loader.js in your upload directory alongside the SWF. It runs after the Ruffle runtime is ready and the player element exists, but before player.load() is called for your SWF. At that point both window.Wavedash and window.rufflePlayer (the RufflePlayer Web Component) are available, so the loader is the right place to attach event listeners, register ExternalInterface bridges, or hook save-data persistence:

// build/loader.js
window.rufflePlayer.addEventListener("loadeddata", () => {
    console.log("SWF ready");
});

The platform owns the Ruffle load config (autoplay, letterbox, allowScriptAccess, etc.) and you can't override those defaults from the loader.

The Ruffle runtime is loaded from jsDelivr — the platform doesn't host its own copy. First-time loads fetch from the CDN, then the browser caches the wasm for subsequent plays.