React + Rust + Wasm: Render a 3D Scene

Nikhil Gupta
2 min readNov 20, 2022

--

In this article, we will use Bevy game engine in our React application from our Rust WASM library to render a 3D scene. We will build on the previous tutorial available here.

Run a Bevy App using Rust

Last time, we used a setup function with our Bevy app to draw a 2D image. Now, let's modify our lib.rs to create another setup function that will render a 3D scene.

Update the setup function

#[wasm_bindgen]
pub fn run_bevy_app() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(setup_3d) # Defined below
.run();
}

Define setup_3d

fn setup_3d(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
# ...
}

Add a plane

fn setup_3d(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Plane { size: 5.0 })),
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
..default()
});
}

Add a cube

fn setup_3d(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
# ...
commands.spawn(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
transform: Transform::from_xyz(0.0, 0.5, 0.0),
..default()
});
}

Add some light

fn setup_3d(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
# ...
commands.spawn(PointLightBundle {
point_light: PointLight {
intensity: 1500.0,
shadows_enabled: true,
..default()
},
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default()
});
}

Position the camera

fn setup_3d(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
# ...
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
});
}

Build the new wasm library

Let’s run wasm-pack again to build the updated library

wasm-pack build --target web

Call the function from the demo app

Finally, let’s add a button to load the wasm and call run_bevy_app function from our App.ts file like so:

// App.ts

import init, { run_bevy_app } from "rust-wasm-lib";
import './App.css';

function App() {
const runBevyApp = async () => {
await init();
run_bevy_app();
};

return (
<div className="App">
<button onClick={runBevyApp}>Run Bevy App</button>
</div>
);
}

export default App;

Now, if you run the updated app and click on Run Bevy App, you should see a 3d scene :)

If you liked this article, subscribe here to get the complete code and updates for the entire collection:

--

--

Responses (1)