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.
The demo on the front page of this site is built with exactly these components — what you install is what you see.