Docker,
in the browser.
Real OCI/Docker containers on unmodified Alpine Linux, booted by a from-scratch RISC-V emulator — entirely client-side in WebAssembly. No server, no daemon, no install. Just a URL.
Not a toy. A whole machine.
Every layer of a real computer, re-implemented and verified — then compiled to run in the one runtime everyone already has.
Unmodified Linux
Boots the stock Alpine riscv64 kernel + userland to a login shell — OpenRC, busybox, apk, the works.
// boot-to-loginPersistent disk
A copy-on-write overlay in IndexedDB survives tab reloads, with crash-consistent virtio-blk flush semantics.
// IndexedDB overlayReal networking
A user-mode TCP/IP stack (slirp) with DHCP + DNS, plus a Tailscale transport — the guest gets a real IP.
// slirp + tailscaleOCI containers
Pull and run real Docker Hub images as isolated containers with wvrun — pid/mount/uts namespaces.
Snapshot & resume
Freeze the whole machine — CPU, RAM, devices — to a coherent blob and resume instruction-exact, fsck-clean.
// save_resumeProvably correct
Differentially tested byte-for-byte against Spike, with a native≡wasm determinism gate on every build.
// diff vs spikeBuilt the long way. On purpose.
What the Node surface actually costs.
One portable script measures verified file reads/writes, streaming, server startup, and local HTTP request/response behavior across native Node, wasm-vm, WebContainers, almostnode, and WebVM.
Same fixture, every environment.
The complete row set is the current source of truth. Unsupported cells remain visible and explained; they are never replaced with a different benchmark or an inferred value.
| Environment | File read | File write | Stream read | Stream copy | Server lifecycle | HTTP round trip |
|---|---|---|---|---|---|---|
| Loading raw workload evidence… | ||||||
Each cell shows median time, p95, and throughput where bytes were transferred. The fixture is deterministic, every measured sample checks its output digest, and the raw JSON keeps the individual timings, runtime identity, script digest, sampling policy, and verification results. This is a workload measurement, not a claim that the environments provide identical storage or network isolation. Runner · Raw comparison →
Where a JIT can actually amortize.
This is a separate campaign from filesystem, stream, and HTTP boundaries. It keeps one process alive and times only deterministic arithmetic, branching, and typed-array loops.
| Environment | Integer mix | Branch mix | Memory mix |
|---|---|---|---|
| Loading steady-state compute evidence… | |||
Each measured cell shows median time, p95, and verified work rate. The fixture uses fixed checksums; process startup and memory preparation are excluded from timing. Measured browser rows come from the deployed Node guest; any remaining unmeasured row includes its reason. Runner · Raw compute comparison →
Hot blocks win; boundary blocks barely do.
| Workload | Interpreter | JIT | JIT / interpreter |
|---|---|---|---|
| Loading JIT diagnostic… | |||
This release-only handoff diagnostic is not substituted into the comparable browser table: six-op measures dispatch-bound behavior, while 64-op measures hot-block amortization.
Fetch → decode → execute, a few hundred million times.
An interpreter core in Rust, compiled to WebAssembly, driving a full virt platform — CLINT, PLIC, UART, virtio-blk/net/rng — off a deterministic clock. The whole stack, top to bottom:
# booting unmodified Alpine riscv64 in WebAssembly… [ 0.000000] Linux version 6.6.63 (riscv64) — in your browser [ 2.664] Run /init as init process wasm-vm:~# uname -m riscv64 wasm-vm:~# cat /proc/cpuinfo | grep isa isa : rv64imafdc wasm-vm:~# wvrun run busybox echo "hello from a container" hello from a container wasm-vm:~# _
A real machine — not a clever illusion.
Plenty of things look like a computer in a browser. This one actually is one.
Every instruction runs for real, retiring one at a time — not a pre-baked screencast or a canned transcript.
There's no server doing the work. The CPU, RAM, disk, and network stack all live in the page — offline-capable after first load.
Unmodified riscv64 binaries execute against a spec-correct core — differentially checked byte-for-byte against Spike.
Boot a Linux box. Right now.
It runs entirely on your machine — nothing you do here leaves the tab.