# DOM web backend The web backend keeps the existing Pardes core and replaces the old Emscripten/SDL/WebGL shell. Zig produces a `wasm32-freestanding` module with no imports. Vanilla JavaScript owns `requestAnimationFrame`, browser input, window sizing, and effect/IO dispatch; HTML and CSS render selectable, accessible text. There is no canvas. The default web build links Tree-sitter's C runtime and the Zig grammar inside that same import-free module. A small freestanding compatibility layer supplies the C ABI locally, so source panes retain the core's Tree-sitter highlighting without Emscripten, WASI, or browser libc imports. Other grammar tiers remain selectable with `-Dtree-sitter=minimal` or `-Dtree-sitter=full`. `src/web.zig` is the narrow WASM ABI. Events enter through exported functions, and `pardes_frame` writes the canonical `Surface` into a packed 20-byte cell array. `src/web/app.mjs` reads that array in one linear pass and patches stable DOM nodes. Core effects become browser operations (links, downloads, clipboard) or `pardes-io` custom events for a process-capable embedding host. Build a replay from a dump: ```sh zig build web \ -Dplatform=web \ -Dtarget=wasm32-freestanding \ -Dtree-sitter=zig \ -Ddump=test/web-snapshots/source-list.dump.zon ``` The output is in `zig-out/web`. Serve that directory over HTTP; browsers do not allow a useful WASM module load from `file:` URLs. Two dependency-free test layers cover the boundary: ```sh # Real WASM in Node plus a small DOM double. zig build web-harness \ -Dplatform=web \ -Dtarget=wasm32-freestanding \ -Dtree-sitter=zig \ -Ddump=test/web-snapshots/source-list.dump.zon # Real headless Chrome, DOM rendering, and browser touch input. zig build web-e2e ``` Set `PARDES_CHROME` when Chrome/Chromium is not on `PATH` or in a normal Playwright/Puppeteer cache.