Vanilla JavaScript Projects

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.

WA
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

  1. Copy pixels inThe photo's RGBA bytes are copied into the WebAssembly memory. Memory grows in 64 KB pages to fit.
  2. Run the filterThe exported function loops over every pixel in place, using only integer math.
  3. 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);