vemu.

Getting Started

vemu runs real firmware in the browser through WebAssembly. Two npm packages get you there:

  • @swedishembedded/vemu — the emulator runtime (freeware wasm build)
  • @swedishembedded/vemu-react — React components and hooks for embedding it

Install

npm install @swedishembedded/vemu @swedishembedded/vemu-react

@swedishembedded/vemu-react declares react >= 18 and @swedishembedded/vemu as peer dependencies.

Initialize the runtime

The wasm module loads lazily. Call initVemu() once before constructing an emulator:

import { initVemu, Emulator, list_boards } from "@swedishembedded/vemu";

await initVemu();

const boards = JSON.parse(list_boards());
// → [{ id: "nordic,nrf5340-dk-cpuapp", name: "nRF5340 DK (App core)", arch: "..." }, ...]

Boot a board

Construct an Emulator with a board id, firmware bytes, and the image kind ("elf" for ELF binaries, "bin" for raw flash images, "hex" for Intel HEX images). An empty byte array builds a firmware-less machine — useful for inspecting peripherals before loading code.

const elf = new Uint8Array(await (await fetch("/firmware/zephyr.elf")).arrayBuffer());
const emu = new Emulator("nordic,nrf5340-dk-cpuapp", elf, "elf");

emu.onEvent((events) => {
  for (const { kind, payload } of events) {
    if (kind === "uart.tx") {
      // payload.bytes is a Uint8Array of console output
    }
  }
});

function frame() {
  const running = emu.step_frame();
  if (running) requestAnimationFrame(frame);
}
requestAnimationFrame(frame);

Console input goes the other way through dispatch:

emu.dispatch("uart.rx", JSON.stringify({ bytes: [...new TextEncoder().encode("help\n")] }));

Every event kind the runtime accepts and emits is documented in the event vocabulary and on the per-peripheral pages of the runtime reference — generated from the exact build you install.

Use the React components

@swedishembedded/vemu-react wraps the loop, the canvas, and an xterm.js terminal so you don't write any of the above by hand:

import { useVemu, VemuCanvas, VemuTerminal, PeripheralPanel } from "@swedishembedded/vemu-react";

function EmbeddedVemu() {
  const vemu = useVemu();

  return (
    <div>
      <VemuCanvas hasVideo={vemu.hasVideo} setDraw={vemu.setDraw} />
      <VemuTerminal setUartSink={vemu.setUartSink} sendUart={vemu.sendUart} />
      <PeripheralPanel
        peripherals={vemu.peripheralList}
        events={vemu.peripheralEvents}
        refreshKey={vemu.snapshotVersion}
        getSnapshot={vemu.getPeripheralSnapshot}
        sendCommand={vemu.sendPeripheralCommand}
      />
    </div>
  );
}

See the React API reference for every component, hook, and prop.

Note:

The demo on the front page of this site is built with exactly these components — what you install is what you see.

Next steps