Elm, Rust, and WebGL in one interface
While we wait for the Elm lang 1.0 release, I dusted off an old Elm project I did a couple of years ago!
I was messing around with Rust, targeting WebAssembly and using WebGL to display some fancy 3D graphics on a canvas element. Once I had some 3D objects showing, I also wanted some regular input elements to control the scene, such as sliders and color pickers.
Thankfully, modern browsers ship with a bunch of these useful input elements already implemented.
Being very familiar with Elm, I was looking for a way to combine my Rust code and Elm in the same frontend. I came across elm_rs as a bridge between Elm and Rust.
This allows me to define a Msg type in Rust:
#[derive(Debug, Serialize, Deserialize, Elm, ElmEncode, ElmDecode)]
pub enum Msg {
Focus,
Unfocus,
ChangeFOV { angle: f32 },
ChangeEnvLight { color: Color },
// ...
}
And a matching type is auto-generated for my Elm code, with encoder and decoder functions included.
With the Rust canvas existing as a custom element, it sends messages to Elm-land with JavaScript events, and Elm can dispatch messages to Rust with an Elm port. Elm owns the page's DOM and layout. Rust owns the canvas and the state of the 3D scene. If Elm wants to view the scene state that is defined in Rust — like the current fps — a simple decoder can retrieve it. This is convenient because it completely separates the fast canvas loop from slow DOM events.
Interop between Rust and Elm is type-safe and statically validated.
Try it out here
WebGL shader.
The original purpose of this project was to play around with shader code. Right now, it shows an approximation of subsurface scattering. It uses an AO map of the 3D model's interior to estimate depth for the subsurface scattering. You can see the effect below.
It is a fun coincidence that I ended up doing something very similar for my master's thesis this summer.
Alternatively, you could reach for something like egui and render input elements directly in the canvas.