Skip to content

Browser support

This page lists what a browser needs to run alpha2 and what your server must send. After reading it you can check a browser and configure your hosting.

  • Browsers: Chrome 96, Firefox 89 or Safari 26, or later. The WebAssembly modules need WebAssembly SIMD and reference types; without them neither the engine, the audio worklet nor the extension modules load.
  • .wasm served as application/wasm. Otherwise the loader falls back to a slower way of compiling the modules and warns.
  • Audio preview needs a cross-origin isolated page. Editing, video preview and export do not.

The panel below probes the browser you are reading this in and starts the engine on a small canvas.

In your own app, detectBrowserCapabilities() from alpha2/robustness answers the same questions: whether there is a hardware WebGPU adapter, WebGL2, WebCodecs, OffscreenCanvas and the WebAssembly features, and which renderer "auto" would get (renderer: "gpu" or "cpu"). Its answers hold for the calling thread only; a worker host asks WorkerRenderBackend.detectCapabilities().

WebEffectRegistry.createForHtmlCanvas(canvas) (or createForCanvas with an OffscreenCanvas in a worker) renders with WebGPU, or with WebGL2 when the browser has no WebGPU. The WebGPU device is opened before the canvas is bound, so a failure leaves the canvas free for another context.

When neither is available (Chrome with hardware acceleration off, a blocklisted GPU), WebEffectRegistry.createCpu(canvas) makes the engine’s CPU renderer. It takes the same calls, draws in WebAssembly on one thread and puts the preview on the canvas’s 2D context. It draws exactly what the native CPU renderer draws, refuses runtime WGSL effects with EFFECT_ERROR, and needs no canvas to export.

import init, { WebEffectRegistry } from "alpha2/wasm";
await init();
let engine;
try {
engine = await WebEffectRegistry.createForHtmlCanvas(canvas, { softwareAdapter: "refuse" });
} catch {
engine = WebEffectRegistry.createCpu(canvas);
}

{ softwareAdapter: "refuse" } refuses software adapters (SwiftShader, llvmpipe, WARP, a WebGPU fallback adapter) and rejects with GPU_INIT_FAILED when the browser offers nothing else. createRenderer(binding, canvas, mode) in alpha2/renderer-choice does this choice for you: "auto" draws on a hardware GPU, else on the CPU renderer, and it tells you which it made.

Audio preview moves mixed audio to an AudioWorklet through a ring buffer in shared memory, which needs SharedArrayBuffer, and so a cross-origin isolated page. Send these two headers with the page:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

canShareAudioMemory() from alpha2/audio-timeline tells you whether the current page qualifies.

Send Content-Type: application/wasm for .wasm files. The package’s modules are alpha2/wasm/alpha2_wasm_bg.wasm (the engine), alpha2/wasm/alpha2_audio_worklet.wasm (the audio worklet) and alpha2/wasm/alpha2_extensions_bg.wasm (SVG, animated images, Lottie, OpenEXR and image sequences, loaded only for such a source).

init() loads the engine module from beside its JavaScript. If your bundler moves it, pass its URL, a Response, its bytes or a compiled WebAssembly.Module:

await init({ module_or_path: wasmUrl });

This site is served with serve, and its serve.json sends both the isolation headers and the .wasm type:

{
"headers": [
{
"source": "**",
"headers": [
{ "key": "Cross-Origin-Opener-Policy", "value": "same-origin" },
{ "key": "Cross-Origin-Embedder-Policy", "value": "require-corp" }
]
},
{
"source": "**/*.wasm",
"headers": [{ "key": "Content-Type", "value": "application/wasm" }]
}
]
}

The optional dependency mediabunny installs @types/dom-webcodecs 0.1.13, whose declarations clash with TypeScript 5.9’s DOM library. Either compile with skipLibCheck, or add "overrides": { "@types/dom-webcodecs": "0.1.19" } to your package.json. An app that imports alpha2/mediabunny also needs "ESNext.Disposable" in its lib.