Making Games in Rust - Deploying a Bevy App to the Web
Tags: bevy, rust, programming, tutorial
Published: 2022-01-13 19:42:47

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](https://dev.to/sbelzile/rust-platformer-part-1-bevy-and-ecs-2pci). This time, I will use a simple Tic-Tac-Toe game example that can be found [here](https://github.com/belzile/tic-tac-toe). With a working web deployment [here](https://belzile.github.io/tic-tac-toe/).

## Prerequesites

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

```sh
rustup target add wasm32-unknown-unknown
```

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

```sh
cargo install -f wasm-bindgen-cli
```

## Building the code

```sh
cargo build --release --target wasm32-unknown-unknown
wasm-bindgen --out-dir ./out/ --target web ./target/wasm32-unknown-unknown/release/tic-tac-toe.wasm
```

## Running on the Web

First you will need an `index.html` file:

```html
<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>
```

Finally, you need to serve this HTML file:

```sh
npx serve .
```

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

Note that `npx serve .` requires to have [Node JS](https://nodejs.org/en/) installed on your machine.

# Original Content (with Bevy 0.5)

If you did not read the previous articles, you can start [here](https://dev.to/sbelzile/rust-platformer-part-1-bevy-and-ecs-2pci).

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](https://bevy-cheatbook.github.io/platforms/wasm.html).

## Prerequesites

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

```rs
rustup target add wasm32-unknown-unknown
```

Second, you need to install `wasm-pack`:

```rs
cargo install wasm-pack
```

## Cargo Configuration

```rs
[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"
```

What was done here:

1. Set the cargo resolver to version 2.
2. Added `[lib]` tag with the [`cdylib` and `rlib` types](https://doc.rust-lang.org/reference/linkage.html).
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:

```rs
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();
}
```

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:

```rs
use platformer::run;

fn main() {
    run();
}
```

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

```sh
cargo run
```

as usual, and to run for the web:

```sh
wasm-pack build --target web --release
npx serve .
```

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

Note that `npx serve .` requires to have [Node JS](https://nodejs.org/en/) installed on your machine.

## Possible Issues

You may encounter the following error:

```sh
the trait `__tracing_subscriber_Layer<Layered<EnvFilter, Registry>>` is not implemented for `WASMLayer`
```

To fix it, run the following command:

```sh
cargo update -p tracing-wasm --precise 0.2.0
```

The final code is available [here](https://github.com/belzile/platformer/tree/part-14). The most recent version of the game can be played [here](https://belzile.github.io/platformer/).