A local, offline assembler / disassembler in the browser — a self-hosted take on disasm.pro. Both panels are live and edit both ways: change the assembly and the machine-code bytes update; change the bytes and the assembly re-disassembles. Nothing is sent anywhere.
Powered by Keystone (assembler) and Capstone (disassembler), compiled to WebAssembly.
WebAssembly can't load from a file:// page, so serve the folder over HTTP.
A zero-dependency launcher is included:
python3 serve.py # LAN: binds all interfaces, port 8000
python3 serve.py 9000 # different port
python3 serve.py --local # this computer only (127.0.0.1)It prints a http://<your-lan-ip>:8000/ URL to open on other devices. Any static
server works too (python3 -m http.server, npx serve ., nginx, Caddy).
- Both panels are editable at the same time — no mode switch, no swap button.
- Type in Assembly → it assembles and rewrites the Machine code panel.
- Type in Machine code → it parses + disassembles and rewrites Assembly.
- Whichever panel you edited last is the source of truth; the other is regenerated from it. Changing arch/mode/endian/syntax/base recomputes from that same side.
- A shared listing and byte map below both panels always reflect the current bytes.
Architectures
- x86 — 16 / 32 / 64-bit, Intel and AT&T syntax
- ARM — ARM and Thumb modes
- ARM64 (AArch64)
- MIPS — MIPS32 / MIPS64
- Little- and big-endian for ARM, ARM64, MIPS (x86 is LE-only)
Machine-code formats (the byte panel's dropdown)
- hex raw string · hex spaced ·
\xescaped ·0x,comma · C array · Pythonbytes· base64 - The dropdown controls how generated bytes are shown and how typed input is
read: pick base64 to type/parse base64; any hex-ish form is parsed liberally
(you can paste a whole C array or
b"..."— surrounding identifiers are ignored). Switching the format also normalizes whatever is currently in the panel.
Listing + byte map
- Per-instruction listing: address · bytes · mnemonic · operands
- A colored byte map: each byte is tinted by the instruction it belongs to. Hover an instruction to light up its bytes, or hover a byte to find its instruction. Undecoded trailing bytes are shown dashed.
- A base address field sets the addresses in the listing.
serve.py binds 0.0.0.0 by default and prints the LAN URL. To let other
devices connect, open the port in your firewall, e.g.:
sudo ufw allow 8000/tcp # Ubuntu/Debian
sudo firewall-cmd --add-port=8000/tcp # Fedora/RHELNote: over plain http://<ip> the browser treats the page as a non-secure
context, so the async clipboard API is unavailable — the copy button falls back
to the legacy method automatically. For real HTTPS on the LAN, front it with
Caddy or nginx. To keep it always-on, wrap serve.py in a systemd service or
serve the static folder from an nginx/Caddy container.
index.html UI + styles
app.js all logic (arch config, encoders, parser, two-way recompute)
serve.py local HTTP launcher (LAN-capable)
vendor/ keystone.js/.wasm, capstone.js/.wasm, upstream licenses
Keystone is GPLv2 (with a commercial option); Capstone is BSD. See the
*.LICENSE files in vendor/. WASM builds are the @alexaltea Keystone.js /
Capstone.js ports. Everything runs in your tab — no network calls, no telemetry.