Skip to content

Real-Fruit-Snacks/Shallows

Shallows

Important

Browser-native Linux terminals powered by x86 emulation. Full Alpine Linux virtual machines running entirely in your browser via WebAssembly. No servers, no installs, no accounts. Inter-VM networking, file transfer, state snapshots, and offline support. Just open and type.

Shallow water is where the bottom is still in reach. Felt fitting for a tab that loads a real Linux kernel without leaving your browser.


§1 / Premise

Each terminal is a complete Alpine Linux x86 virtual machine running in WebAssembly via v86. Not a shell emulator — a real kernel, real filesystem, real processes. BusyBox utilities and the APK package manager are included.

All terminals share a virtual ethernet switch on 10.0.0.0/24 with auto-assigned MACs and IPs, so VMs can ping, nc, and run server/client pairs against each other. Drag-and-drop drops files into /tmp/<filename>; sendfile pulls files back to your browser. After the first ISO boot (~30s), full VM state (memory + CPU) is snapshot-cached in IndexedDB for near-instant restore.

Live demo


§2 / Specs

KEY VALUE
GUEST OS Alpine Linux 3.20 virt (x86 32-bit) · BusyBox · APK
EMULATOR v86 0.5.319 · x86-to-WASM
VMs Up to 6 concurrent · 128 MB RAM each · ID pool recycling
NETWORK Virtual ethernet switch · 10.0.0.0/24 · auto-assigned MACs and IPs
TRANSFER Drag-drop upload (max 2 MB) · sendfile for download · serial port (ttyS0)
SNAPSHOTS Full memory + CPU · IndexedDB · near-instant restore
OFFLINE Service worker · cache-first · COOP/COEP injection
THEME Catppuccin Mocha
STACK Vanilla HTML/CSS/JS · no Node, no bundler, no package manager · MIT

Architecture in §5 below.


§3 / Quickstart

git clone https://github.com/Real-Fruit-Snacks/Shallows.git
cd Shallows
python3 -m http.server 8000     # any static server works

Open http://localhost:8000 in Chrome, Firefox, or Edge. Click New Terminal to boot an Alpine Linux VM.

If SharedArrayBuffer is unavailable, VMs still work but run slower. The included service worker injects the required COOP/COEP headers automatically.

Inside the VM:

apk add curl
uname -a
cat /etc/os-release

Between two VMs:

# Terminal 1 (10.0.0.1)
nc -l -p 8080

# Terminal 2 (10.0.0.2)
echo "hello" | nc 10.0.0.1 8080
ping 10.0.0.2

§4 / Reference

CLIPBOARD

  Ctrl+Shift+C            Copy screen text
  Ctrl+Shift+V            Paste into VM
  Copy / Paste buttons    Topbar equivalents

FILE TRANSFER

  Drag-drop onto terminal Upload — written to /tmp/<filename> (max 2 MB)
  sendfile <path>         Download file from VM to browser

NETWORKING

  10.0.0.0/24             Auto-assigned VM addresses
  ip a                    Inspect interface inside VM
  nc -l -p <port>         Listen
  nc <ip> <port>          Connect
  ping <ip>               ICMP between VMs

LIFECYCLE

  New Terminal            Spawn a fresh VM (boots from ISO first time, then snapshot)
  Tab / Grid view         Focused vs side-by-side layouts
  Snapshot                Persisted in IndexedDB after first successful boot

PRIVACY

  No servers              All computation happens locally in your browser
  No accounts             No authentication, no tracking, no analytics
  No network calls        After initial load, fully offline
  Local-only state        VM state in IndexedDB on your machine

PLATFORM

  Chrome / Firefox / Edge   Full support — VM boot, snapshots, networking, clipboard
  Safari                    Limited — partial SharedArrayBuffer + clipboard

§5 / Architecture

Shallows/
  index.html                       Entry — topbar, tabs, viewport
  sw.js                            Service worker — offline + COOP/COEP
  css/style.css                    Catppuccin Mocha theme
  js/
    app.js                         Event wiring, clipboard, shortcuts
    ui.js                          Tab/grid management, drag-and-drop
    terminal-manager.js            VM lifecycle, IndexedDB snapshots
    virtual-network.js             VirtualSwitch + FakeWebSocket
    file-transfer.js               Serial-based upload/download
    libv86.js                      v86 x86 emulator (WASM loader)
    v86.wasm                       v86 emulator core
  assets/
    bios/seabios.bin               SeaBIOS firmware
    bios/vgabios.bin               VGA BIOS firmware
    images/alpine-virt-3.20.3-x86.iso   Alpine 3.20 (~47 MB)
Layer Implementation
Emulator v86 0.5.319 · emulates x86 CPU in WebAssembly
Display VGA canvas per VM · PS/2 keyboard for input
Network In-memory VirtualSwitch broadcasts ethernet frames between FakeWebSocket adapters
Transfer Serial port (ttyS0) with base64 marker protocol
Cache IndexedDB snapshot of full VM memory + CPU
Offline Service worker · cache-first strategy · injects COOP/COEP
Build None — vanilla HTML/CSS/JS · static-host friendly

Key patterns: All assets are self-contained — BIOS, WASM engine, Alpine ISO ship with the repo. No external scripts, no CDN dependencies at runtime. The included GitHub Actions workflow deploys on every push to main; enable Pages with Source: GitHub Actions.


§6 / Troubleshooting

Problem Solution
VM won't boot Check console for WASM errors. Ensure js/v86.wasm and assets/ are accessible
Slow VM performance SharedArrayBuffer may be unavailable — confirm sw.js is registered for COOP/COEP
Terminals can't ping VMs auto-assigned unique MACs — check console for ip link set
File upload not working Wait for VM to fully boot (loading overlay disappears)
sendfile not found Command installed during auto-login; reinstall manually if boot was interrupted
Clipboard buttons fail Browser requires HTTPS or localhost for clipboard API

License: MIT · Part of Real-Fruit-Snacks — building offensive security tools, one wave at a time.

About

Browser-native Linux terminals powered by x86 emulation — no servers, no installs, no accounts. Just open and type.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Contributors