Skip to content
Development
Skill

/wasm-emscripten

WebAssembly with Emscripten skill for C/C++ to WASM compilation. Use when compiling C/C++ to WebAssembly with emcc, configuring EXPORTED_FUNCTIONS, understanding the WASM memory model, using Asyncify for async C code, debugging .wasm with browser devtools or wasm-opt, or

From plugin
low-level-dev-skills
159142 skills
Install
$ npx -y skills add mohitmishra786/low-level-dev-skills --skill wasm-emscripten --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/wasm-emscripten

Context preview

The summary Claude sees to decide when to auto-load this skill.

WebAssembly with Emscripten skill for C/C++ to WASM compilation. Use when compiling C/C++ to WebAssembly with emcc, configuring EXPORTED_FUNCTIONS, understanding the WASM memory model, using Asyncify for async C code, debugging .wasm with browser devtools or wasm-opt, or

SKILL.md

wasm-emscripten.SKILL.md
name: wasm-emscripten
description: WebAssembly with Emscripten skill for C/C++ to WASM compilation. Use when compiling C/C++ to WebAssembly with emcc, configuring EXPORTED_FUNCTIONS, understanding the WASM memory model, using Asyncify for async C code, debugging .wasm with browser devtools or wasm-opt, or targeting WASI vs browser environments. Activates on queries about Emscripten, emcc, WebAssembly from C/C++, WASM memory model, Asyncify, EXPORTED_FUNCTIONS, WASI, or wasm-opt.

WebAssembly with Emscripten

Purpose

Guide agents through compiling C/C++ to WebAssembly using Emscripten: emcc flag selection, function exports, memory model configuration, Asyncify for asynchronous C code, debugging WASM binaries, and targeting WASI vs browser.

Triggers

  • "How do I compile C to WebAssembly with Emscripten?"
  • "How do I export a C function to JavaScript?"
  • "How does WebAssembly memory work with Emscripten?"
  • "How do I debug a .wasm file?"
  • "How do I use Asyncify to make synchronous C code async?"
  • "What's the difference between WASI and Emscripten browser target?"

Workflow

1. Setup and first build

# Install Emscripten SDK
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh    # add emcc to PATH

# Verify
emcc --version

# Compile C to WASM (browser target)
emcc hello.c -o hello.html          # generates hello.html + hello.js + hello.wasm
emcc hello.c -o hello.js            # just JS + WASM (no HTML shell)

# Serve locally (WASM requires HTTP, not file://)
python3 -m http.server 8080
# Open: http://localhost:8080/hello.html

2. Exporting functions to JavaScript

// math.c
#include <emscripten.h>

// EMSCRIPTEN_KEEPALIVE prevents dead-code elimination
EMSCRIPTEN_KEEPALIVE
int add(int a, int b) {
    return a + b;
}

EMSCRIPTEN_KEEPALIVE
double sqrt_approx(double x) {
    return x * 0.5 + 1.0;
}
# Export specific functions
emcc math.c -o math.js \
  -s EXPORTED_FUNCTIONS='["_add","_sqrt_approx"]' \
  -s EXPORTED_RUNTIME_METHODS='["ccall","cwrap"]' \
  -s MODULARIZE=1 \
  -s EXPORT_NAME=MathModule

# The leading underscore is required for C functions
// Using exported functions in JS
const Module = await MathModule();

// Direct call
const result = Module._add(3, 4);

// Via ccall (type-safe)
const result2 = Module.ccall('add', 'number', ['number', 'number'], [3, 4]);

// Via cwrap (creates a callable JS function)
const add = Module.cwrap('add', 'number', ['number', 'number']);
console.log(add(3, 4));  // 7

3. Memory model

Emscripten provides a linear memory heap accessible from both C and JS:

# Configure initial and maximum heap
emcc prog.c -o prog.js \
  -s INITIAL_MEMORY=16MB \
  -s MAXIMUM_MEMORY=256MB \
  -s ALLOW_MEMORY_GROWTH=1    # allow dynamic growth

# Stack size (default 64KB)
emcc prog.c -o prog.js -s STACK_SIZE=1MB

# Shared memory (for SharedArrayBuffer / threads)
emcc prog.c -o prog.js -s SHARED_MEMORY=1 -s USE_PTHREADS=1
// Accessing C memory from JS
const ptr = Module._malloc(1024);     // allocate
Module.HEAPU8.set([1, 2, 3], ptr);   // write bytes
Module._free(ptr);                     // free

// Read a C string
const strPtr = Module.ccall('get_message', 'number', [], []);
const str = Module.UTF8ToString(strPtr);

// Write a string to C
const jsStr = "hello";
const cStr = Module.stringToNewUTF8(jsStr);  // malloc + copy
Module._process_string(cStr);
Module._free(cStr);

4. Asyncify — synchronous C in async environments

Asyncify lets synchronous C code suspend and resume for async operations (like `fetch()`, sleep, etc.):

// async.c
#include <emscripten.h>

// Synchronous sleep in C (blocks C, but yields to JS event loop)
EM_JS(void, do_fetch, (const char *url), {
    // Emscripten generates wrappers to suspend C while JS runs
    Asyncify.handleAsync(async () => {
        const resp = await fetch(UTF8ToString(url));
        const text = await resp.text();
        console.log(text);
    });
});

void process_url(const char *url) {
    do_fetch(url);     // looks synchronous in C
    printf("fetch complete\n");
}
# Enable Asyncify
emcc async.c -o async.js \
  -s ASYNCIFY \
  -s ASYNCIFY_STACK_SIZE=16384 \
  -O2   # Asyncify works better with optimization

5. Optimization and wasm-opt

# Optimization levels
emcc prog.c -O0 -o prog.js    # no optimization (fastest build)
emcc prog.c -O2 -o prog.js    # balanced
emcc prog.c -O3 -o prog.js    # aggressive
emcc prog.c -Os -o prog.js    # optimize for size
emcc prog.c -Oz -o prog.js    # aggressive size (Emscripten's smallest)

# Post-process with wasm-opt (Binaryen)
wasm-opt -Oz -o prog.opt.wasm prog.wasm    # optimize for size
wasm-opt -O4 -o prog.opt.wasm prog.wasm    # optimize for speed

# Compare sizes
ls -lh prog.wasm prog.opt.wasm

6. Debugging WASM

# Build with debug info
emcc prog.c -g -O0 -o prog.html \
  -s ASSERTIONS=1 \
  -s SAFE_HEAP=1      # catch misaligned accesses

# In Chrome DevTools:
# Sources → prog.wasm → line-by-line C source debugging
# (requires -g and browser with WASM debugging support)

# LLDB with WASM (wasmtime)
# See skills/runtimes/wasm-wasmtime for CLI WASM debugging
# Emscripten debug helpers
emcc prog.c -o prog.js \
  -s ASSERTIONS=2       # extensive runtime checks
  -s SAFE_HEAP=1        # sanitize heap accesses
  -s STACK_OVERFLOW_CHECK=1

# Print generated JS
emcc prog.c -o prog.js && cat prog.js | head -100

7. WASI vs browser target

| Feature | Browser (Emscripten) | WASI | |---------|---------------------|------| | Host APIs | Web APIs (fetch, WebGL, etc.) | POSIX subset (files, stdin/stdout) | | Runtime | Browser JS engine | wasmtime, wasmer, WAMR, Node.js | | Threads | SharedArrayBuffer + pthreads | wasi-threads (limited) | | Networking | fetch(), WebSocket | wasi-http (preview2) | | Use case | Web applicati

Read more
Ships withlow-level-dev-skills

A curated suite of AI agent skills for systems and low-level programming — C/C++, Rust, Zig, GPU, bare-metal firmware, Linux kernel/driver development, computer architecture, compiler internals, HPC, and more.

Get the whole plugin
Stats
172
Stars
24
Forks
Maintained
Maintenance
JavaScript
Language
MIT
License
1mo ago
Last commit
5mo ago
Created

Repo: mohitmishra786/low-level-dev-skills

Other skills on low-level-dev-skills.