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
- Put your compiled
.swffile in your upload directory (e.g.build/game.swf). - 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"- Run
wavedash devto 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.