---
# System prepended metadata

title: 'Project 1: crystal visualizer in WASM'

---

# Project 1: crystal visualizer in WASM

[back to index](https://hackmd.io/hz9-b8TdTNSY4sLyKBuVCQ)

- project repo: https://github.com/rs4rse/vizcrystal

note: 

The content below was generated from chatgpt-5 by just providing the goal (crystal visualizer) and tech-stacks (bevy, cif, wasm), we do vibe coding from scratch.
The proposal may need to be adapted along the vibe coding. (like `cifparser` which not existed but David has some prototype crate where we can use the modules here. Otherwise see project3 and go with xyz files.)

## Core Goal

Build a web-based crystal structure visualizer in **Rust** using **Bevy** compiled to **WebAssembly (WASM)**.
The app should load a valid **CIF (Crystallographic Information File)** and render the 3D crystal structure, supporting mouse-based interaction (zoom, rotate, pan).
Publish to npm.

## tech stacks

- wasm
- rust
- use typescript where if possible since in rust we deal with types anyway.
- wasm-bindgen https://wasm-bindgen.github.io/
- wasmbuild deno glue code https://github.com/denoland/wasmbuild

---

## **Phase 1: Setup**

* Set up a **Bevy project** targeting WASM.

  * Use `wasm-bindgen` or `wasm-pack` to compile.
  * Serve via `trunk` or `wasm-server-runner`.
* Confirm that a simple rotating cube renders correctly in browser.

---

## **Phase 2: CIF Parsing**

* Add a Rust crate or implement a small parser for CIF files.

  * Option A: Use [cifparser](https://crates.io/crates/cifparser).
  * Option B: Write a minimal parser for atomic positions, cell dimensions, and symmetry.
* Extract:

  * **Lattice vectors**
  * **Atom positions** and **species**
* Store data in a struct, e.g.:

  ```rust
  struct Crystal {
      lattice: [[f32; 3]; 3],
      atoms: Vec<Atom>,
  }

  struct Atom {
      element: String,
      position: [f32; 3],
  }
  ```

---

## **Phase 3: Visualization in Bevy**

* Render atoms as spheres (or colored meshes).
* Render bonds as cylinders (optional at first).
* Color atoms by element type (basic mapping: H=white, C=black, O=red, etc.).
* Add unit cell edges (wireframe cube).

---

## **Phase 4: Camera & Interaction**

* Add **mouse controls**:

  * **Rotate**: Click & drag.
  * **Zoom**: Scroll wheel.
  * **Pan**: Right-click drag or middle button.
* Use `bevy_mod_picking` or implement a custom orbital camera system.

---

## **Phase 5: Web Integration**

* Create an **HTML file** with a file upload button (`<input type="file">`).
* Use **JavaScript + wasm-bindgen** to pass uploaded CIF file content to Rust.
* When a file is loaded:

  * Parse CIF → Render in scene.
* Ensure browser app works offline (bundle with Trunk).

---

## **Phase 6: Extensions (Optional / Bonus)**

* **Multiple CIFs**: Dropdown to switch between different crystals.
* **Supercell builder**: Duplicate unit cell `n x n x n`.
* **Labels**: Show element symbols next to atoms.
* **Bond detection**: Compute bonds dynamically using distance cutoff.

---

## **Deliverables**

1. WASM + Bevy app running in browser.
2. Working CIF file parser.
3. Interactive crystal visualization (zoom/rotate).
4. Extended functionality (optional):

   * Bonds, labels, supercell.

---

## **Tech Hints**

* Bevy WASM:

  ```bash
  cargo install trunk
  trunk serve --open
  ```
* For parsing files from HTML:

  * Use `web-sys` or `gloo-file` to read uploaded files.
* For interactivity:

  * Bevy’s `Transform` + mouse input events.
* For bonds:

  * Distance cutoff \~1.2 × (r1 + r2) where r = covalent radii.
