# Rust + WebAssembly Demos

Interactive demos showcasing **Rust** compiled to **WebAssembly** running in the browser,
organized by category. Each demo is its own crate compiled to its own small `.wasm` (mostly 15–45 KB, 6–25 KB gzipped), so a page downloads only its own code.

## Quick Start

```bash
rustup target add wasm32-unknown-unknown   # One-time setup
cargo install wasm-pack                    # One-time setup

python3 scripts/build.py        # Build every demo → pkg/<demo>/  (or: build.py <demo> ...)
python3 scripts/serve.py 8080   # Dev server: no-cache + COOP/COEP headers
open http://localhost:8080/www/ # Open home page
```

Run tests with `cargo test --workspace -- --test-threads=1` (single-threaded: several crates use global state).

> Full setup guide and troubleshooting (in Chinese): [docs/INSTALL.md](docs/INSTALL.md).
> Behind a proxy, `wasm-pack build` can hang silently while downloading `wasm-bindgen` / `wasm-opt`.
> Pre-install both tools to avoid this (see the guide). `cargo run` is not supported: demo crates are `cdylib`s.
> The multithreaded path tracer build (`pathtracer-mt`) additionally needs nightly Rust with `rust-src`; without it `build.py` skips that one build and the page uses the single-threaded one.

## Demos

| Category | Demo | Crate | Render | Description |
|---|---|---|---|---|
| Graphics | 🌀 Mandelbrot | `mandelbrot` | Canvas2D | Real-time fractal, wheel / pinch zoom |
| | 🌐 3D Mandelbulb | `mandelbulb` | **WebGL** | Raymarching power-8 fractal |
| | 🏔️ Perlin Terrain | `terrain` | Canvas2D | Improved Perlin noise + fBm, infinite pannable map |
| | 🧊 Software Rasterizer | `rasterizer` | Canvas2D | Transform, back-face culling, top-left rule, z-buffer, Phong — all on the CPU |
| | 💡 Path Tracing | `pathtracer` | Canvas2D + Worker | Progressive Monte Carlo path tracer; optional rayon threads (`pathtracer-mt`) |
| | 🧩 Wave Function Collapse | `wfc` | Canvas2D | Entropy-ordered constraint propagation with backtracking; tiled and learnt-from-sample models |
| Simulation | 🌌 Particles | `particles` | Canvas2D | N-body gravity — 300 particles CPU |
| | ⚡ WebGPU N-body | `webgpu` | **WebGPU** | 5K–20K particles, WGSL compute shader |
| | 🌊 Stable Fluids | `fluid` | Canvas2D | Jos Stam's Navier-Stokes solver, drag to stir |
| | 🔲 Game of Life | `game-of-life` | Canvas2D | 46,800 cells Conway automaton |
| | 🧵 Cloth | `cloth` | Canvas2D | Verlet integration + distance constraints; drag, cut and tear |
| Algorithms | 📊 Data Table | `data-table` | DOM | 100K rows sorted & filtered in WASM |
| | 🗺️ A* Pathfinding | `pathfind` | Canvas2D | Recursive-backtracker maze, animated A* vs Dijkstra |
| | ⚖️ JS vs WASM | `benchmark` | DOM | Sieve, recursion, sort, matmul — same algorithm in both languages |
| | 🚀 SIMD | `simd` | DOM + Canvas2D | Scalar vs 128-bit SIMD: dot product, image add, Mandelbrot |
| | 🔺 Delaunay / Voronoi | `delaunay` | Canvas2D | Bowyer-Watson with a vertex at infinity; low-poly images |
| | 🔢 Sudoku | `sudoku` | DOM | Exact cover with Dancing Links vs naive backtracking |
| Media | 🎨 Image Filter | `image-filter` | Canvas2D | 5 pixel filters (blur, edge, emboss...) |
| | 📹 Video Filter | _(reuses `image-filter`)_ | Canvas2D + **WebRTC** | Live camera, WASM per-frame filter |
| | 🎵 Audio Spectrum | `spectrum` | Canvas2D + Web Audio | Hand-written radix-2 FFT, spectrogram, note detection |
| | 🎹 Synthesizer | `synth` | **AudioWorklet** | 8-voice subtractive synth; bare `.wasm` (no wasm-bindgen) on the audio thread |
| | ✂️ Seam Carving | `seam-carving` | Canvas2D | Content-aware resizing by dynamic programming; object removal |
| | 🖼️ JPEG Encoder | `jpeg` | Canvas2D | Baseline JFIF encoder (DCT, quantisation, Huffman) with an 8×8 block inspector |
| Tools | 🔐 SHA-256 | `sha256` | DOM | Streaming file hashing, cross-checked with Web Crypto |
| | 🔲 QR Code | `qrcode` | Canvas2D | QR encoder: Reed-Solomon, masking, penalty scores |
| | 🗜️ Compression | `compress` | DOM | DEFLATE (RFC 1951) compressor / decompressor, zlib-compatible |
| | 📝 Markdown | `markdown` | DOM | CommonMark subset + GFM tables to HTML, code highlighting, XSS-safe |
| | 🔌 MCP Console | `mcp` | DOM + **local bridge** | MCP client in WASM; a local bridge (`serve.py --mcp`) runs stdio / HTTP MCP servers and CLI tools. The only demo that needs a server |
| Games & AI | 🏖️ Falling Sand | `falling-sand` | Canvas2D | Cellular sandbox: sand, water, wood, fire, smoke |
| | ⚫ Gomoku | `gomoku` | Canvas2D | Five-in-a-row against an alpha-beta search AI |
| | ✍️ Digit Recognition | `digits` | Canvas2D | MNIST-trained int8 MLP (98.5% test accuracy), recognises what you draw |
| | 🕹️ CHIP-8 | `chip8` | Canvas2D + Web Audio | Interpreter with debugger, assembler and editable built-in programs |

## Architecture

```
Cargo.toml              ← workspace
crates/common/          ← helpers shared by several crates (xorshift RNG)
crates/<category>/<demo>/  ← one crate per demo: graphics, simulation, algorithms, media, tools, games
scripts/build.py        ← wasm-pack build for every crate; per-crate flags, raw builds and extra
                          variants (e.g. pathtracer-mt) via [package.metadata.webtt]
www/index.html          ← Navigation home (+ home.css)
www/style.css           ← Shared dark theme and components
www/explain.css         ← 原理说明 panel styles
www/nav.js              ← Top nav: Escape closes the 全部示例 panel
www/<demo>/index.html + index.js [+ style.css]  ← One directory per demo
pkg/<demo>/index.js     ← build output per demo (gitignored)
scripts/serve.py        ← Dev server (Cache-Control: no-cache, COOP/COEP for SharedArrayBuffer); --mcp enables the MCP bridge
ecosystem.config.cjs    ← pm2 config: keep serve.py --mcp running on this machine (docs/INSTALL.md §3.4)
scripts/mcp_bridge.py   ← MCP bridge: stdio / HTTP MCP servers and CLI tools for www/mcp/ (localhost only, token cookie)
scripts/mcp_shell.py    ← Restricted shell for the bridge: allowlisted programs, each command confirmed in the terminal
scripts/mcp_remote.py   ← Remote access to the bridge through a domain name: password login, sessions, lockout
scripts/mcp_demo_server.py ← Plain-Python stdio MCP server for trying out and testing the console
crates/tools/mcp/examples/demo_server.rs ← The same demo server in Rust (std + the crate's JSON module): cargo build --release -p mcp --example demo_server
examples/mcp-servers/{go,zig}/ ← …and in Go and Zig (standard library only), built into target/mcp-demo/ (docs/INSTALL.md §3.2)
scripts/gen_nav.py      ← Writes the shared top nav (current category + a 全部示例 panel of all demos) into every page
scripts/new_demo.py     ← Scaffolds a demo page, its nav entry and home card
scripts/gen_explain.py  ← Renders each page's 原理说明 panel from scripts/explain/*.json
docs/INSTALL.md         ← Setup, phone access, troubleshooting (Chinese)
HELP.md                 ← How to use each demo (Chinese)
```

**Two Rust patterns**:
- **Stateless**: `mandelbrot`, `mandelbulb`, `terrain`, `webgpu`, `benchmark`, `image-filter`, `spectrum`, `qrcode`, `compress`, `digits`, `markdown`, `jpeg`, `sudoku` — pure functions
- **Browser-side state** (`thread_local!` + `RefCell`, async exports): `mcp`
- **Stateful**: `data-table`, `game-of-life`, `particles`, `pathfind`, `fluid`, `sha256`, `falling-sand`, `gomoku`, `rasterizer`, `pathtracer`, `simd`, `synth`, `chip8`, `seam-carving`, `wfc`, `cloth`, `delaunay` — `static Mutex<Option<Struct>>` (or a small stats `Mutex`)

Frontend: vanilla JS + ES modules, no bundler. Canvas output via `ImageData`/WebGL/WebGPU.

## MCP console (needs a local server)

```bash
cp mcp.config.example.json mcp.config.json    # add your own MCP servers / CLI tools (gitignored)
python3 scripts/serve.py 8080 --mcp mcp.config.json
open http://localhost:8080/www/mcp/           # must be opened on this machine
```

The config lists stdio servers (`"command": [...]`), Streamable HTTP servers (`"url"`) and command-line tools (`"cli": [...]`, run without a shell, arguments filled into `{placeholders}`). See `mcp.config.example.json`.

## Requirements

- [Rust](https://rustup.rs) stable + `wasm32-unknown-unknown` target
- [wasm-pack](https://github.com/drager/wasm-pack) 0.12+ (verified with 0.15.0)
- `wasm-bindgen` CLI matching the version in `Cargo.lock` (currently 0.2.126). wasm-pack auto-downloads it if missing
- `wasm-opt` from [binaryen](https://github.com/WebAssembly/binaryen) (optional, shrinks the `.wasm`)
- Python 3 for `scripts/serve.py` (any static server works; set `Cache-Control: no-cache` to avoid stale `pkg/` modules, and COOP/COEP headers if you want the multithreaded path tracer)
- Optional, for `pathtracer-mt` only: nightly Rust with `rust-src` (`rustup component add rust-src --toolchain nightly`)
- Browsers: desktop Chrome / Edge / Firefox / Safari; mobile iOS 15+ Safari, Android Chrome 89+ (incl. WeChat's built-in browser). ES modules with top-level `await` set this floor
- WebGPU demo: desktop Chrome / Edge 113+, Android Chrome 121+, iOS / iPadOS Safari 26+
- SIMD demo: Chrome 91+, Firefox 89+, Safari 16.4+ (the page says so on older browsers)
- Synthesizer, camera and microphone: a secure context (`localhost` or HTTPS)

## License

MIT
