Skip to main content
Aurora OS uses WebAssembly (WASM) to run compiled kernel modules in the browser, bridging native C code with browser JavaScript APIs. This enables code reuse between native and browser targets while maintaining performance and security.

Design decision

Aurora OS chose Option B: WASM-based virtual OS runtime over compiling the entire kernel to WASM.

Options evaluated

Approach: Use Emscripten to compile the entire native kernel to WebAssemblyPros:
  • Maximum code reuse (single codebase)
  • Automatic C → WASM translation
  • Familiar development workflow
Cons:
  • Hardware-dependent code can’t compile to WASM (inline assembly, direct I/O)
  • Complex build system (multiple toolchains)
  • Large WASM binary size (~10+ MB)
  • Poor integration with browser APIs (requires JS shims)
Reference: Emscripten — Porting Guide

Rationale

Option B provides cleaner architecture:
  1. Pure computation (scheduler logic, policy engines, agent decision code) compiles to WASM
  2. Hardware-dependent code (interrupt handlers, page table manipulation) stays native-only
  3. Browser APIs (DOM, IndexedDB, WebSocket) used directly via JavaScript
This approach eliminates the impedance mismatch of forcing hardware-dependent C code through WASM. Documentation: docs/wasm-runtime.md in source repository

Architecture

The WASM runtime consists of three layers:
┌──────────────────────────────────────────────────┐
│         Desktop UI (os.js, enhanced-apps.js)      │
│         DOM, CSS animations, event handlers       │
├──────────────────────────────────────────────────┤
│         BPE/U Engine (bpe/*.js)                   │
│         Syscalls, scheduler, memory, VFS, auth    │
├──────────────────────────────────────────────────┤
│         WASM Modules (kernel-wasm.c → .wasm)      │
│         Compiled pure computation functions       │
├──────────────────────────────────────────────────┤
│         Browser APIs (OPFS, WebCrypto, WS)        │
└──────────────────────────────────────────────────┘

WASM compilation

Aurora OS uses Emscripten to compile C kernel modules to WebAssembly:

Build process

# From Makefile:112
make wasm:
    emcc wasm-runtime/bridge/kernel-wasm.c \
        -o wasm-runtime/pwa/kernel.js \
        -s EXPORTED_RUNTIME_METHODS='["ccall","cwrap","UTF8ToString"]' \
        -s ALLOW_MEMORY_GROWTH=1 \
        -s INITIAL_MEMORY=16777216 \
        -s MODULARIZE=1 \
        -s EXPORT_NAME='AuroraKernel' \
        -s ENVIRONMENT='web' \
        -s NO_EXIT_RUNTIME=1 \
        -s FILESYSTEM=0 \
        -O2
Compiler flags:
  • EXPORTED_RUNTIME_METHODS: Expose ccall, cwrap for JS ↔ WASM calls
  • ALLOW_MEMORY_GROWTH: Enable dynamic memory expansion
  • INITIAL_MEMORY=16777216: Start with 16 MB (grows as needed)
  • MODULARIZE=1: Export as ES module
  • EXPORT_NAME='AuroraKernel': Module name for import
  • ENVIRONMENT='web': Target browser environment
  • NO_EXIT_RUNTIME=1: Keep WASM module alive
  • FILESYSTEM=0: Disable Emscripten’s virtual FS (use BPE/U VFS instead)
  • -O2: Optimize for size and speed
Output:
  • kernel.js — JavaScript loader and glue code (~50 KB)
  • kernel.wasm — Compiled WebAssembly binary (~200 KB)
Implementation: Makefile:112-120, wasm-runtime/bridge/kernel-wasm.c

WASM module interface

// wasm-runtime/bridge/kernel-wasm.c:15
#include <emscripten.h>

// Exported functions (callable from JavaScript)
EMSCRIPTEN_KEEPALIVE
int wasm_schedule(int pid, int priority) {
    // Scheduler decision logic (pure computation)
    // No hardware access, no syscalls
    return next_pid;
}

EMSCRIPTEN_KEEPALIVE
void wasm_policy_eval(const char *rule, int *result) {
    // Security policy evaluation
    // Capability token validation
    *result = evaluate_rule(rule);
}

EMSCRIPTEN_KEEPALIVE
int wasm_agent_exec(const char *code, int sandbox_level) {
    // Agent runtime execution
    // Sandboxed environment, no I/O
    return exec_sandboxed(code, sandbox_level);
}
Usage from JavaScript:
// Load WASM module
import AuroraKernel from './kernel.js';

const kernel = await AuroraKernel();

// Call WASM functions
const nextPID = kernel.ccall(
    'wasm_schedule',      // Function name
    'number',             // Return type
    ['number', 'number'], // Argument types
    [currentPID, priority] // Arguments
);

// Or use cwrap for repeated calls
const schedule = kernel.cwrap('wasm_schedule', 'number', ['number', 'number']);
const nextPID = schedule(currentPID, priority);
Implementation: wasm-runtime/bridge/kernel-wasm.c

Browser API integration

The WASM runtime bridges browser APIs to OS subsystems:
Purpose: Persistent file storage that survives cache clear
// wasm-runtime/pwa/bpe/bpe-vfs.js:30
class BPEVFS {
    async init() {
        // Get OPFS root directory
        this.opfsRoot = await navigator.storage.getDirectory();
        
        // Request persistent storage
        if (navigator.storage.persist) {
            const granted = await navigator.storage.persist();
            if (granted) console.log('OPFS persistence granted');
        }
    }

    async readFile(path) {
        const parts = path.split('/').filter(p => p);
        let dir = this.opfsRoot;
        
        // Navigate to parent directory
        for (let i = 0; i < parts.length - 1; i++) {
            dir = await dir.getDirectoryHandle(parts[i]);
        }
        
        // Get file handle
        const fileHandle = await dir.getFileHandle(parts[parts.length - 1]);
        const file = await fileHandle.getFile();
        return await file.arrayBuffer();
    }

    async writeFile(path, data) {
        const parts = path.split('/').filter(p => p);
        let dir = this.opfsRoot;
        
        // Create parent directories
        for (let i = 0; i < parts.length - 1; i++) {
            dir = await dir.getDirectoryHandle(parts[i], { create: true });
        }
        
        // Create or open file
        const fileHandle = await dir.getFileHandle(
            parts[parts.length - 1], 
            { create: true }
        );
        
        const writable = await fileHandle.createWritable();
        await writable.write(data);
        await writable.close();
    }
}
Benefits:
  • Not cleared by “Clear browsing data” (only “All data”)
  • Async I/O (non-blocking)
  • Full POSIX-like API (read, write, mkdir, unlink)
Implementation: wasm-runtime/pwa/bpe/bpe-vfs.js, persistent-fs.js
Purpose: Password hashing, encryption, secure random numbers
// wasm-runtime/pwa/bpe/bpe-auth.js:40
async hashPassword(password, salt) {
    const enc = new TextEncoder();
    
    // Import password as key material
    const keyMaterial = await crypto.subtle.importKey(
        'raw',
        enc.encode(password),
        'PBKDF2',
        false,
        ['deriveBits']
    );
    
    // Derive key with PBKDF2
    const bits = await crypto.subtle.deriveBits(
        {
            name: 'PBKDF2',
            salt: salt,
            iterations: 600000,  // OWASP 2023 recommendation
            hash: 'SHA-256'
        },
        keyMaterial,
        256  // 256-bit output
    );
    
    return new Uint8Array(bits);
}

async encryptData(data, key) {
    const iv = crypto.getRandomValues(new Uint8Array(12));
    
    const encrypted = await crypto.subtle.encrypt(
        { name: 'AES-GCM', iv },
        key,
        new TextEncoder().encode(data)
    );
    
    return { encrypted, iv };
}
Algorithms used:
  • PBKDF2-SHA256 (600k iterations) for password hashing
  • AES-GCM for credential encryption
  • Secure random number generation for salts, IVs, tokens
Implementation: wasm-runtime/pwa/bpe/bpe-auth.js
Purpose: TCP-like socket communication
// wasm-runtime/pwa/bpe/bpe-network.js:20
class BPENetwork {
    async connect(host, port) {
        return new Promise((resolve, reject) => {
            this.ws = new WebSocket(`wss://${host}:${port}`);
            
            this.ws.onopen = () => {
                this.connected = true;
                resolve(0);  // Success
            };
            
            this.ws.onerror = (err) => {
                reject(-1);  // Connection failed
            };
            
            this.ws.onmessage = (event) => {
                this.receiveQueue.push(event.data);
            };
        });
    }

    async send(data) {
        if (!this.connected) return -1;
        this.ws.send(data);
        return data.byteLength;
    }

    async recv(maxLen) {
        while (this.receiveQueue.length === 0) {
            await new Promise(r => setTimeout(r, 10));  // Poll
        }
        return this.receiveQueue.shift();
    }
}
Limitations:
  • WebSocket only (no raw TCP/UDP)
  • Requires proxy server for non-WebSocket protocols
  • HTTPS/WSS required (no HTTP/WS in production)
Implementation: wasm-runtime/pwa/bpe/bpe-network.js
Purpose: Fallback storage for large structured data
// wasm-runtime/pwa/persistent-fs.js:80
class IndexedDBStorage {
    async init() {
        return new Promise((resolve, reject) => {
            const req = indexedDB.open('AuroraOS', 1);
            
            req.onupgradeneeded = (e) => {
                const db = e.target.result;
                if (!db.objectStoreNames.contains('files')) {
                    db.createObjectStore('files', { keyPath: 'path' });
                }
            };
            
            req.onsuccess = (e) => {
                this.db = e.target.result;
                resolve();
            };
            
            req.onerror = reject;
        });
    }

    async writeFile(path, data) {
        const tx = this.db.transaction(['files'], 'readwrite');
        const store = tx.objectStore('files');
        await store.put({ path, data, timestamp: Date.now() });
    }

    async readFile(path) {
        const tx = this.db.transaction(['files'], 'readonly');
        const store = tx.objectStore('files');
        const result = await store.get(path);
        return result ? result.data : null;
    }
}
Use cases:
  • Large file storage (OPFS has size limits in some browsers)
  • Database-like queries (key-value, indexes)
  • Fallback when OPFS unavailable
Implementation: wasm-runtime/pwa/persistent-fs.js

Progressive Web App

Aurora OS is a PWA (Progressive Web App) with offline support:

Service worker

// wasm-runtime/pwa/sw.js:10
const CACHE_NAME = 'aurora-os-v1';
const urlsToCache = [
    '/',
    '/index.html',
    '/os.css',
    '/os.js',
    '/kernel.js',
    '/kernel.wasm',
    // ... all assets
];

self.addEventListener('install', (event) => {
    event.waitUntil(
        caches.open(CACHE_NAME).then((cache) => {
            return cache.addAll(urlsToCache);
        })
    );
});

self.addEventListener('fetch', (event) => {
    event.respondWith(
        caches.match(event.request).then((response) => {
            // Return cached version or fetch from network
            return response || fetch(event.request);
        })
    );
});

Manifest

// wasm-runtime/pwa/manifest.json
{
    "name": "Aurora OS",
    "short_name": "Aurora",
    "description": "A reactive, agentic OS with modern polish",
    "start_url": "/index.html",
    "display": "fullscreen",
    "theme_color": "#0066ff",
    "background_color": "#0b0f14",
    "icons": [
        {
            "src": "/icon-192.svg",
            "sizes": "192x192",
            "type": "image/svg+xml"
        },
        {
            "src": "/icon-512.svg",
            "sizes": "512x512",
            "type": "image/svg+xml"
        }
    ]
}
PWA features:
  • Offline mode (service worker caches all assets)
  • Install to desktop/home screen
  • Fullscreen mode (no browser UI)
  • App-like experience
Implementation: wasm-runtime/pwa/sw.js, manifest.json

Performance optimization

WASM compilation flags

Emscripten optimization levels:
FlagSizeSpeedNotes
-O0800 KB1.0×Debug (no optimization)
-O1500 KB1.5×Basic optimizations
-O2200 KB2.5×Default (size + speed)
-O3180 KB3.0×Aggressive (slower compile)
-Os150 KB2.0×Size-focused
-Oz120 KB1.8×Extreme size (slower)
Aurora OS uses -O2 for balanced size and performance.

Memory growth strategy

// Emscripten memory management
-s INITIAL_MEMORY=16777216   // Start with 16 MB
-s ALLOW_MEMORY_GROWTH=1     // Grow dynamically
-s MAXIMUM_MEMORY=536870912  // Cap at 512 MB
Growth pattern:
  • Initial: 16 MB (sufficient for boot)
  • Typical: 32-64 MB (desktop with apps)
  • Maximum: 512 MB (prevents runaway allocation)

Async I/O

All browser APIs use async I/O to prevent blocking:
// Synchronous API (blocks UI thread) ❌
const data = fs.readFileSync('/path/to/file');

// Asynchronous API (non-blocking) ✅
const data = await fs.readFile('/path/to/file');
BPE/U wraps all I/O in async functions to maintain 60 fps UI.

Limitations

The browser runtime has limitations compared to native:
FeatureNativeBrowserNotes
Direct hardware accessNo raw I/O, DMA, interrupts
Syscall performance~100 ns~50 μsJS function call overhead
Memory accessDirectVirtualizedWASM linear memory only
NetworkingRaw TCP/UDPWebSocketRequires proxy for raw sockets
File systemExt2/FAT32OPFS/IDBBrowser-specific APIs
Process isolationHardware MMUWASM sandboxWeaker isolation
Real-timePossibleNoJavaScript event loop unpredictable
See docs/browser-limitations.md for details.

Next steps

BPE/U engine

Explore the browser processing engine

Hybrid design

Learn how native and browser code share logic

Quick start

Run Aurora OS in your browser

Building

Build WASM modules from source