DEV Community

Sébastien Belzile
Sébastien Belzile

Posted on • Updated on

Making Games in Rust - Deploying a Bevy App to the Web

This article was first written for Bevy 0.5. The release of Bevy 0.6, on the actual day I wrote this article, made it obsolete. Those b******** keep making their product better...

Bevy 0.6 added out of the box support for running their application for the web.

The first part of the article will describe how to deploy an application to the web with Bevy 0.6, the second part is what I originally wrote for Bevy 0.5.

Bevy 0.6

Originally, this article was part 14 of my Bevy Platformer tutorial. This time, I will use a simple Tic-Tac-Toe game example that can be found here. With a working web deployment here.

Prerequesites

First, you need to be able to compile to web assembly:

rustup target add wasm32-unknown-unknown
Enter fullscreen mode Exit fullscreen mode

Second, you will need the wasm-bindgen-cli:

cargo install -f wasm-bindgen-cli
Enter fullscreen mode Exit fullscreen mode

Building the code

cargo build --release --target wasm32-unknown-unknown
wasm-bindgen --out-dir ./out/ --target web ./target/wasm32-unknown-unknown/release/tic-tac-toe.wasm
Enter fullscreen mode Exit fullscreen mode

Running on the Web

First you will need an index.html file:

<html>
  <head>
    <meta charset="UTF-8" />
    <style>
      body {
        margin: 0;
        background: linear-gradient(-45deg, #a6a6a6, #5ac05a, #262626, #a6a6a6);
        background-size: 400% 400%;
        animation: gradient 15s ease infinite;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
      }
      canvas {
        background-color: white;
      }

      @keyframes gradient {
        0% {
          background-position: 0% 50%;
        }
        50% {
          background-position: 100% 50%;
        }
        100% {
          background-position: 0% 50%;
        }
      }
    </style>
  </head>
  <script type="module">
    import init from './out/tic-tac-toe.js'
    init()
  </script>
</html>
Enter fullscreen mode Exit fullscreen mode

Finally, you need to serve this HTML file:

npx serve .
Enter fullscreen mode Exit fullscreen mode

And then visit http://localhost:3000 to confirm everything works fine.

Note that npx serve . requires to have Node JS installed on your machine.

Original Content (with Bevy 0.5)

If you did not read the previous articles, you can start here.

This article will show how to deploy our project as a web application.

Most of the things covered here are explained in greater details in Bevy's Unofficial Cheat Book.

Prerequesites

First, you need to be able to compile to web assembly:

rustup target add wasm32-unknown-unknown
Enter fullscreen mode Exit fullscreen mode

Second, you need to install wasm-pack:

cargo install wasm-pack
Enter fullscreen mode Exit fullscreen mode

Cargo Configuration

[package]
name = "platformer"
version = "0.1.0"
edition = "2021"
resolver = "2"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
wasm-bindgen = "0.2"
bevy_rapier2d = { version = "0.11.0", features = [ "wasm-bindgen" ] }
rand = "0.8.4"
getrandom = { version = "0.2", features = ["js"] }

# Dependencies for native only.
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
bevy = {version = "0.5", default-features = false, features = ["bevy_wgpu", "bevy_winit", "render", "x11"]}

# Dependencies for WASM only.
[target.'cfg(target_arch = "wasm32")'.dependencies]
bevy = {version = "0.5", default-features = false, features = ["bevy_winit", "render"]}
bevy_webgl2 = "0.5"
Enter fullscreen mode Exit fullscreen mode

What was done here:

  1. Set the cargo resolver to version 2.
  2. Added [lib] tag with the cdylib and rlib types.
  3. Added wasm-bindgen as a dependency. This is the crate responsible for the interoperability between JS and Rust.
  4. Added the wasm-bindgen feature flag to rapier.
  5. Splitted the bevy dependency in 2. One for the web, the other for native development. In both cases, the required feature flags are set.
  6. Added bevy_webgl2 to the wasm dependencies. This crate provides webgl2 rendering support to Bevy.

Code Changes

Add a src/lib.rs file that contains the following:

use bevy::prelude::*;
use wasm_bindgen::prelude::*;

mod game;
use game::GamePlugin;

mod main_menu;
use main_menu::MainMenuPlugin;

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum AppState {
    MainMenu,
    InGame,
}

#[wasm_bindgen]
pub fn run() {
    let mut app = App::build();

    app.add_plugins(DefaultPlugins);

    #[cfg(target_arch = "wasm32")]
    app.add_plugin(bevy_webgl2::WebGL2Plugin);

    app.insert_resource(WindowDescriptor {
        title: "Platformer!".to_string(),
        width: 640.0,
        height: 400.0,
        vsync: true,
        ..Default::default()
    })
    .insert_resource(ClearColor(Color::rgb(0.04, 0.04, 0.04)))
    .add_state(AppState::MainMenu)
    .add_plugin(MainMenuPlugin)
    .add_plugin(GamePlugin)
    .run();
}
Enter fullscreen mode Exit fullscreen mode

This is the same code we had in our main.rs, except that the main function was renamed to run and adapted for the web.

Next step is to replace the content of src/main.rs to:

use platformer::run;

fn main() {
    run();
}
Enter fullscreen mode Exit fullscreen mode

The code should now compile and run. To run locally on your machine, run:

cargo run
Enter fullscreen mode Exit fullscreen mode

as usual, and to run for the web:

wasm-pack build --target web --release
npx serve .
Enter fullscreen mode Exit fullscreen mode

And then visit http://localhost:3000 to confirm everything works fine.

Note that npx serve . requires to have Node JS installed on your machine.

Possible Issues

You may encounter the following error:

the trait `__tracing_subscriber_Layer<Layered<EnvFilter, Registry>>` is not implemented for `WASMLayer`
Enter fullscreen mode Exit fullscreen mode

To fix it, run the following command:

cargo update -p tracing-wasm --precise 0.2.0
Enter fullscreen mode Exit fullscreen mode

The final code is available here. The most recent version of the game can be played here.

Discussion (0)