I incorporate WebGPU+Rust in the following way
(index.html)
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GreenMatterAI graphics preview</title>
<style>
canvas {
background-color: black;
}
</style>
</head>
<body id="wasm-example">
<script type="module">
import init from "./pkg/gmai_cad.js";
init().then(() => {
console.log("WASM Loaded");
});
</script>
</body>
</html>
(lib.rs)
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))]
pub async fn run() {
cfg_if::cfg_if! {
if #[cfg(target_arch = "wasm32")] {
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init_with_level(log::Level::Warn).expect("Couldn't initialize logger");
} else {
env_logger::init();
}
}
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
#[cfg(target_arch = "wasm32")]
{
use winit::dpi::PhysicalSize;
window.set_inner_size(PhysicalSize::new(450, 400));
use winit::platform::web::WindowExtWebSys;
web_sys::window()
.and_then(|win| win.document())
.and_then(|doc| {
let dst = doc.get_element_by_id("wasm-example")?;
let canvas = web_sys::Element::from(window.canvas());
dst.append_child(&canvas).ok()?;
Some(())
})
.expect("Couldn't append canvas to document body.");
}
let mut state = State::new(window).await;
event_loop.run(move |event, _, control_flow| match event {
Event::RedrawRequested(window_id) if window_id == state.window().id() => {
state.update();
state.render()
}
Event::MainEventsCleared => {
state.window().request_redraw();
}
Event::WindowEvent {
ref event,
window_id,
} => { state.event(event) },
_ => {}
});
}
The way this code is structured there is no way I could pass any data from Javascript to the render loop. I want to have some HTML inputs that user can modify and affect the rendering interactively. The only thing that comes to my mind is to have a global mutable variable and expose a few Rust functions that Javascript could use to modify those variables. Of course that's a clear Rust anti-pattern. What's the canonical way of going about this?
Instead of using a function marked #[wasm_bindgen(start)]
, use an ordinary #[wasm_bindgen]
exported function that can take parameters, and call it from JavaScript.
#[cfg(target_arch = "wasm32")
#[wasm_bindgen]
pub async fn run_in_browser(configuration: JsValue /* or whatever */) {
...
}
<script type="module">
import init, { run_in_browser } from "./pkg/gmai_cad.js";
init().then(() => {
console.log("WASM Loaded");
run_in_browser({ /* put configuration/callbacks here */ });
});
</script>