mugon.net docs
SDKs

Bevy

A Bevy game compiled to wasm, with the mugon-sdk-bevy crate.

Bevy is the main SDK. Start a project with mugon init and pick the bevy template (see what you need installed). It gives you a Bevy app, a small Vite entry and build commands. Two pieces have to work together:

The entry (src/index.js) imports the SDK first and starts the wasm from inside Mugon.start, which publishes the context as window.mugon. Vite bundles it, the SDK and the wasm into your distribution folder; you don't ship any SDK file yourself:

import { Mugon } from "@mugon/sdk";
import init from "../pkg/game.js";

Mugon.start(async () => {
  try {
    await init(); // downloads game_bg.wasm through the file proxy and runs main
  } catch (error) {
    // Bevy's web event loop unwinds `main` with this exception on purpose.
    if (!String(error).includes("control flow")) throw error;
  }
  // Keep the callback pending, see below.
  await new Promise(() => {});
});

The crate mugon-sdk-bevy reads that context:

use bevy::prelude::*;
use mugon_sdk_bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins((DefaultPlugins, MugonPlugin))
        .add_systems(Startup, setup)
        .run();
}

fn setup(bridge: NonSend<Bridge>) {
    info!("{:?} {}", bridge.network_mode(), bridge.own_id());
    bridge.loaded(); // the game is playable: close the loading overlay
}

MugonPlugin panics with a clear message if window.mugon is missing, i.e. if the wasm isn't started from inside the Mugon.start callback.

Loading progress

The entry keeps the Mugon.start callback pending because App::run returns immediately on the web, and a returning callback closes the overlay before your assets are loaded. Close it from Rust instead:

  • Bridge::loaded() when the game is ready, and optionally Bridge::set_progress(fraction, label) while loading; or
  • enable the loading feature, add MugonLoadingPlugin and track assets: the overlay shows loaded/total and closes when they are all loaded.
fn setup(asset_server: Res<AssetServer>, mut loading: ResMut<MugonLoading>) {
    loading.track(asset_server.load::<Image>("sprite.png"));
}

Track everything the game needs before it's playable in one go; assets tracked after the overlay closed are not waited for.

The bridge

Bridge is a NonSend resource with network_mode(), own_id(), server_id(), pop_connect(), pop_disconnect(), pop_recv(), send(peer, bytes, channel), disconnect(peer), show_invite() and toggle_fullscreen(). On a server the connect queue starts with the peers that were connected already. For Lightyear games, the lightyear_mugon crate builds on this.

Building

The template has two build commands. Both run cargo build --target wasm32-unknown-unknown, wasm-bindgen --target web into pkg/, and npm run build (Vite):

  • mugon dev uses the plain --release profile, which compiles quickly on every save.
  • mugon publish uses the release-lto profile (full LTO, one codegen unit): a much slower compile for a smaller and faster wasm.

Install the wasm-bindgen CLI in the same version as the wasm-bindgen crate in your Cargo.lock. Debug builds of Bevy are very large (hundreds of megabytes), so the template never uses them.

On this page