Armeet Singh Jatyani

Founder · AI Researcher & Engineer

Back to blog
#rust#tech#web

Web MRI Volume Renderer in Rust

Over the weekend, I made a GPU-accelerated 3D MRI volume renderer written in Rust that compiles to WASM and runs directly in web.

Demo GIF

Here’s my repo: github. I’m open to PR’s! You should go checkout the demo application website and video (15s).

Back when I was a researcher working on AI models for 3D medical imaging, one of the problems I faced frequently was visualizing extremely dense (512³) MRI volumes (I was working with knee and brain MRI primarily) directly in 3D. Matplotlib doesn’t have interactive 3D support and plotly didn’t work for my use case. Raw MRI samples from the SKM-TEA 3D dataset can be ~8GB per sample. The best I could do was visualize 2D cross-sections.

So this weekend, I wrote my own interactive 3D volume renderer. The client is written in Rust, using egui/ eframe and compiles to WASM with trunk. The core volume renderer uses glow and targets WebGL in the browser, implementing a ray marching approach. The server is written in axum and serves volumes stored on disk. I specifically chose a client-server architecture to allow for future expansion (e.g., loading volumes from a database, more advanced chunking and rendering of massive volumes, etc).

Here’s what I used and why.

  • Rust: I didn’t want to write C++. I wrote a compiler in OCaml for a class in college once and people tell me Rust was inspired by some of the style choices in OCaml. This gives me an excuse to try out the language everyone seems to love. I am extremely impressed at how easy it was to build a GUI, server, and compile everything to wasm with trunk. I’ve worked with Emscripten in the past with C, which was a pain.
  • Amp Code: I’ve been meaning to use amp in a real project to check it out. My initial impression is that it has a far better UX than claude code, doesn’t seem to have any of the stuttering terminal spam bugs, and even has a free tier which is great. I’ll have to continue using it on our larger main codebase to get a better idea of where it stands in terms of performance/quality.
  • OpenGL: Honestly, I’m no graphics programmer. As Garry says, “zap the rocks!” and that’s primarily what I did here. At first, I tried implementing everything using WebGPU since this is the modern successor but had some compatibility issues. Moving to OpenGL shaders seemed to do the trick. This part of the project was straightforward.
  • HDF5 files: samples in MRI are usually provided in the .h5 format. I used bindings to the hdf5 library to quickly load samples from disk.
  • Fly.io: I read a dev blog post a while back about how Fly uses Gleam (not sure if they still do) for parts of their stack and thought that was cool. Have been meaning to try them out so I did. Easy deployment.
  • egui: was a breeze to work with and the obvious choice for making a quick UI that easily compiles to web.
  • axum: If my client is in Rust, why not kill 2 birds with 1 stone and just setup simple axum routes as well? A project like this would’ve taken me days. Now it takes just a couple of hours.

Features

  • volume rendering in browser (WebGL ray marching)
  • trackball rotation (quaternion-based, no gimbal lock)
  • quality slider (adjust step size for performance/quality tradeoff)
  • opacity control
  • hover info card (voxel coordinates, value, intensity)
  • occupancy grid optimization (skip empty regions)
  • XYZ axes visualization
  • naive server serves entire HDF5 volume