guide

Start with a function you already have.

Wrap it in a jz template and it comes back as a WebAssembly module with that function exported. No annotations, no second language.

import jz from 'jz'

const { exports } = jz`
  export const dist = (x, y) =>
    (x*x + y*y) ** 0.5
`

console.log(exports.dist(3, 4)) // 5

The tag compiles and instantiates once, so keep the module around: every call to exports.dist from here runs WebAssembly. Notice what the source never said – that x and y are numbers. JZ read that off the arithmetic.

npm install jz

Or open the playground first, with nothing to install.

Give it a whole loop

A two-line function shows the shape of it. Loops are where it earns its keep: crossing into WASM costs something each time, so hand it a whole array rather than one number.

import jz from 'jz'

const { exports, memory } = jz`
  export const sum = a => {
    let total = 0
    for (const x of a) total += x
    return total
  }
`

const values = new Float64Array([1, 2, 3])
console.log(exports.sum(values)) // 6
memory.reset()

Arrays, strings and objects cross the boundary for you. What they allocate stays on the heap until you say otherwise, so finish the batch, then call memory.reset(): it invalidates every pointer and view handed out before it. If state has to survive between calls, read the memory contract first.

Your fallback is the same file

Already have a numeric kernel? Leave it where it is. Export its functions and compile the file in your build:

npx jz kernel.js -o kernel.wasm

Ship the .wasm and load it with instantiate from jz/interop; the compiler stays in your build. The .js you compiled from is still there, still running as JavaScript. API and CLI reference →

Start with one kernel and run your existing tests against both versions. JZ is experimental and covers a subset of JavaScript, so measure the whole call, transfer included, before you trust a speedup.

Find an example to adapt · See the measurements