Project 43, Hardware and performance
WebAssembly Image Filters
Four photo filters written by hand in WebAssembly text format, compiled to 491 bytes. Run them on a photo and compare the time with the same filters in JavaScript.
- Main API
- WebAssembly
- Module size
- 491 bytes
- Files
- index.html, filters.wat
- Your browser
- Checking
Photo
Speed race
WASM
-
JavaScript
-
Modern JavaScript engines are fast for simple loops, so the gap is often small. WASM shines with steady timing and heavier math.
View filters.wat
How it works
- Copy pixels inThe photo's RGBA bytes are copied into the WebAssembly memory. Memory grows in 64 KB pages to fit.
- Run the filterThe exported function loops over every pixel in place, using only integer math.
- Copy pixels outThe page reads the bytes back from the same memory and paints them on the canvas.
const bytes = Uint8Array.from(atob(WASM_BASE64), (c) => c.charCodeAt(0));
const { instance } = await WebAssembly.instantiate(bytes);
const { memory, grayscale } = instance.exports;
const img = ctx.getImageData(0, 0, w, h);
const need = Math.ceil(img.data.length / 65536) - memory.buffer.byteLength / 65536;
if (need > 0) memory.grow(need); // 64 KB pages
new Uint8Array(memory.buffer).set(img.data); // copy in
grayscale(img.data.length); // run in place
img.data.set(new Uint8Array(memory.buffer, 0, img.data.length)); // copy out
ctx.putImageData(img, 0, 0);