§Oxide — The Binary-First WebAssembly Browser
https://docs.oxide.foundation
Oxide is a binary-first browser that fetches and executes .wasm
(WebAssembly) modules instead of HTML/JavaScript. Guest applications run
in a secure sandbox with zero access to the host filesystem, environment
variables, or raw network sockets. The browser exposes a rich set of
capability APIs that guest modules import to interact with the host.
§Crate Map
| Crate | Purpose | Audience |
oxide_sdk | Guest SDK — safe Rust wrappers for the "oxide" host imports | App developers |
oxide_browser | Host runtime — Wasmtime engine, sandbox, egui UI | Browser contributors |
§Quick Start — Building a Guest App
# Cargo.toml
[package]
name = "my-oxide-app"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
oxide-sdk = "0.2"
ⓘuse oxide_sdk::*;
#[no_mangle]
pub extern "C" fn start_app() {
log("Hello from Oxide!");
canvas_clear(30, 30, 46, 255);
canvas_text(20.0, 40.0, 28.0, 255, 255, 255, "Welcome to Oxide");
}
Build and run:
cargo build --target wasm32-unknown-unknown --release
# Open Oxide browser → navigate to your .wasm file
§Architecture Overview
┌─────────────────────────────────────────────────────┐
│ Oxide Browser │
│ │
│ ┌──────────┐ ┌────────────┐ ┌──────────────────┐ │
│ │ URL Bar │ │ Canvas │ │ Console │ │
│ └────┬─────┘ └──────┬─────┘ └──────┬───────────┘ │
│ │ │ │ │
│ ┌────▼───────────────▼───────────────▼──────────┐ │
│ │ Host Runtime (oxide-browser) │ │
│ │ Wasmtime engine · sandbox policy │ │
│ │ fuel: 500M instructions · memory: 16 MB │ │
│ └────────────────────┬──────────────────────────┘ │
│ │ │
│ ┌────────────────────▼──────────────────────────┐ │
│ │ Capability Provider │ │
│ │ "oxide" wasm import module │ │
│ │ canvas · console · storage · clipboard │ │
│ │ fetch · audio · timers · crypto · navigation │ │
│ │ widgets · input · hyperlinks · protobuf │ │
│ └────────────────────┬──────────────────────────┘ │
│ │ │
│ ┌────────────────────▼──────────────────────────┐ │
│ │ Guest .wasm Module (oxide-sdk) │ │
│ │ exports: start_app(), on_frame(dt_ms) │ │
│ │ imports: oxide::* │ │
│ └───────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
§Guest SDK API Reference
The oxide_sdk crate provides the full guest-side API. All functions
are available via use oxide_sdk::*;.
§Canvas Drawing
The canvas is the main rendering surface. Coordinates start at (0, 0)
in the top-left corner.
ⓘuse oxide_sdk::*;
canvas_clear(30, 30, 46, 255);
canvas_rect(10.0, 10.0, 200.0, 100.0, 80, 120, 200, 255);
canvas_circle(300.0, 200.0, 50.0, 200, 100, 150, 255);
canvas_text(20.0, 30.0, 24.0, 255, 255, 255, "Hello!");
canvas_line(0.0, 0.0, 400.0, 300.0, 255, 200, 0, 2.0);
let (w, h) = canvas_dimensions();
log(&format!("Canvas: {}x{}", w, h));
§Console Logging
§HTTP Networking
All network access is mediated by the host — the guest never opens raw
sockets. Protocol Buffers is the native wire format.
ⓘuse oxide_sdk::*;
let resp = fetch_get("https://api.example.com/data").unwrap();
log(&format!("Status: {}, Body: {}", resp.status, resp.text()));
The oxide_sdk::proto module provides a zero-dependency protobuf
encoder/decoder compatible with the Protocol Buffers wire format.
ⓘuse oxide_sdk::proto::{ProtoEncoder, ProtoDecoder};
let msg = ProtoEncoder::new()
.string(1, "alice")
.uint64(2, 42)
.bool(3, true)
.finish();
let mut decoder = ProtoDecoder::new(&msg);
while let Some(field) = decoder.next() {
match field.number {
1 => log(&format!("name = {}", field.as_str())),
2 => log(&format!("age = {}", field.as_u64())),
_ => {}
}
}
§Storage
§Audio
§Timers
Timer callbacks fire via the guest-exported on_timer(callback_id) function.
§Navigation & History
Widgets are rendered during the on_frame() loop:
§Crypto & Encoding
§Other APIs
§Browser Internals
The oxide_browser crate contains the host-side implementation.
Key modules for contributors:
oxide_browser::engine — Wasmtime engine setup, oxide_browser::engine::SandboxPolicy,
fuel metering, bounded linear memory
oxide_browser::runtime — oxide_browser::runtime::BrowserHost orchestrates module
fetching, compilation, and execution. oxide_browser::runtime::LiveModule keeps interactive
apps alive across frames.
oxide_browser::capabilities — The "oxide" import module: every host function the
guest can call is registered here via register_host_functions(). Also contains shared state
types (oxide_browser::capabilities::HostState, oxide_browser::capabilities::CanvasState,
oxide_browser::capabilities::InputState, etc.).
oxide_browser::navigation — oxide_browser::navigation::NavigationStack implements
browser-style back/forward history with opaque state.
oxide_browser::bookmarks — oxide_browser::bookmarks::BookmarkStore provides
persistent bookmark storage backed by sled.
oxide_browser::url — oxide_browser::url::OxideUrl wraps WHATWG URL parsing with
support for http, https, file, and oxide:// schemes.
oxide_browser::ui — oxide_browser::ui::OxideApp is the egui/eframe application
with tabbed browsing, toolbar, canvas rendering, console panel, and bookmarks sidebar.
§Guest Module Contract
Every .wasm module loaded by Oxide must:
- Export
start_app — extern "C" fn() entry point called on load
- Optionally export
on_frame — extern "C" fn(dt_ms: u32) for
interactive apps with a render loop
- Optionally export
on_timer — extern "C" fn(callback_id: u32)
to receive timer callbacks
- Import from
"oxide" — all host APIs live under this namespace
- Compile as
cdylib — crate-type = ["cdylib"] in Cargo.toml
- Target
wasm32-unknown-unknown — no WASI, pure capability-based
§Security Model
| Constraint | Value | Purpose |
| Filesystem access | None | Guest cannot read/write host files |
| Environment variables | None | Guest cannot inspect host env |
| Raw network sockets | None | All networking is mediated via fetch |
| Memory limit | 16 MB (256 pages) | Prevents memory exhaustion |
| Fuel limit | 500M instructions | Prevents infinite loops / DoS |
| No WASI | — | Zero implicit system access |