- install toolchain
- install
wasm-pack
- install cargo-generate,
cargo install cargo-generate
, generate a template project - install npm, front end stuff
- create a wasm-pack template project
cargo generate --git https://github.com/rustwasm/wasm-pack-template
- basic concept of directory layout
lib.rs
is the entry file we access from JS#[wasm-bindgen]
to interface with JS. Import from JS or export to it.
- how to build
wasm-pack build
- output to
pkg/
. we got a.wasm
binary,.js
and.ts
file for glue
- put into web page
- crate a JS project tempalte
npm init wasm-app www
- we got a www directory,
index.js
andindex.html
is our entry point - install dependencies, run
npm install
inside www directory - add our wasm as dependencies. modify
www/package.json
- import our package into js, index.js
npm install
again to install package
- crate a JS project tempalte
- run:
npm run start
- nodejs version: v16.11.1
Then each time your rust code is done, just wasm-pack build
- Memory management between JS and WASM. ABI problem
- JS is garbage collected lang. There is no direct access from wasm now. (2018)
- Js can access wasm but only as ArrayBuffer. For js wasm obj is a wrapped pointer
- JS to wasm interface design
- large, long-lived data are implement as Rust types and live in the wasm linear memory export to JS as opaque handle
rust code
- define cell
#[repr(u8)]
so that each cell is a single byte
- define universe
- a long array, width and height
- helper function to access cell and state change
- tick, compute next frame
js code
- add
<pre>
element and some style - import wasm code and use the object that exposed
- print the web page as a console
The whole state is store in the wasm obj. JS can make use of it.
- replace
<pre>
with<canvas>
- draw grid using canvas API. Just some criss-cross lines.
- access wasm linear memory via
memory
. It is define inyou_project_bg.js
seepkg/
- cell color for each cell
- Exercises
- create a space ship!
- create a random pattern: to run it in js. you should use
js-sys
crate - improve with bitmap
pause and resume
- add
<button>
- get
<button>
DOM and add event - resume event continue draw and tick
- pause event
cancelAnimationFrame(animationId)
draw by hand
- add toggle logic of cell in rust code
- compute row and col relative to canvas
- toggle
- export getter and setter
- more helper function
- write test:
tests/web.rs
- test generated wasm:
wasm-pack test [--chrome|--firefox|--node]
TODO: debug wasm in browser
- JS: Record timestamp for each frame so that we can calculate FPS
- Rust: measure how long
Universe::tick
takes- web-sys crate, enable console feature
- RAII timer per tick in rust so that it can print in the console of browser
found that change fillStyle is expensive. So we can draw Alive Cell first and then Dead Cell.
Rust bench
- Install cargo benchcmp tool
- Write micro-bench in
benches/bench.rs
path - Comment
#[wasm_bindgen]
to generate native code for bench - Run
cargo bench | tee before.txt
to tell where the binary is - Perf it
And we found that the %
operator is expensive in counting neighbors in our case
Optimizing Builds for Code Size
https://rustwasm.github.io/docs/book/game-of-life/testing.html
- improve with hashlife algo
- multi rule
- dragon curve
-
Add some random pattern: to run it in js. you should use
js-sys
crate -
Improve with bitmap
fixedbitset
crate- set:
cells.set(idx, bool)
, get:cells[idx]
- set:
-
ctrl + click
to generate glider andshift + click
to generate pular -
<input type="range">
to control how many ticks per frame -
<button>
to reset whole world or generate random world -
Double buffer for cells. Since free and reallocate is expensive
-
Implement delta based design: Rust return a list of cells that changed