I wanted a real Rust-to-WASM module doing per-pixel work off the main thread, not a toy that ships 4MB of glue and blocks the UI on load. Most prompts gave me code that assumed a specific bundler and fell apart under Vite.
The prompt below pins the toolchain, forces a narrow FFI boundary (pass a buffer, get a buffer, no fancy structs across the line), and makes the wasm run in a worker with a typed message protocol. It built and ran at interactive speed on a 12MP image.
Anyone got a good way to make the model keep the wasm binary small without me hand-tuning opt-level?
Generate a Rust + WebAssembly module for browser image processing plus the TypeScript glue to use it, targeting a Vite app. Keep the boundary tiny and the main thread free.
RUST SIDE (wasm-bindgen):
- Expose one function: `process(input: &[u8], width: u32, height: u32, op: u8) -> Vec<u8>` operating on RGBA. No structs across the FFI boundary, just buffers and primitives.
- Implement ops: 0 grayscale, 1 gaussian blur, 2 sobel edges. No external image crates; write the kernels.
- No panics across the boundary: validate lengths and return the input unchanged on bad input rather than unwrapping.
BUILD: give exact commands using wasm-pack with --target web, and a Cargo.toml with `opt-level = 's'` and `lto = true` for a small binary. State the expected .wasm size ballpark.
WEB SIDE:
- Run the wasm inside a Web Worker. Define a typed message protocol: `{ id, op, width, height, buffer }` in, `{ id, buffer }` out. Transfer the ArrayBuffer, don't copy it.
- A `useImageFilter` hook that posts work and resolves a Promise keyed by id.
- Strict TS, no any.
CONSTRAINT: must build with `wasm-pack build` and the app must import it without a custom bundler plugin. List every file and its path.