In-browser renderer
The studio editor on this site runs the puml renderer entirely in your browser. There is no server, no remote service, no PlantUML JAR — the same Rust code that powers the puml CLI is compiled to WebAssembly and loaded by the page.
How it works
The crates/puml-wasm/ crate exposes the lib API (render_source_to_svg, render_source_to_svgs, detect_diagram_family) to JavaScript via wasm-bindgen. The Pages CI job builds it with wasm-pack build --release --target web and drops the artifact in site/static/wasm/. The editor dynamically imports puml_wasm.js, initializes the .wasm module, and calls into it on every keystroke (debounced 400 ms). Browser callers can pass a frontend hint (auto, plantuml, picouml, or mermaid) so Markdown fences render through the same dialect adapter selected by the CLI.
// Simplified view of the JS surface the editor uses.
;
;
;
;
;
;
render_svgs_json and render_svgs_json_with_frontend return a JSON string of { ok: string[] } | { error: Diagnostic }, which is convenient because diagnostics survive the WASM boundary as one round-trip.
What’s different from the CLI
- No filesystem or URL fetching.
!include,!include_many,!includesub,!import, and!include <stdlib/...>all return deterministic include diagnostics in WASM. This differs from the native CLI, which enables URL includes by default for PlantUML compatibility. Everything else — parser, normaliser, layout, SVG render — is identical to the native build. - No PNG output. The browser already has a DOM, so the page consumes the SVG directly. The
resvg/tiny-skia/imagedeps that the CLI uses for PNG rasterization are feature-gated to theclifeature and never enter the WASM binary. - One single-page renderer per call. Multi-page diagrams come back as an array of SVG strings; the studio currently concatenates them vertically.
Binary size
The release-mode WASM file is around 1.3 MB. It’s served once, browser-cached, and decodes quickly. If size becomes a problem, wasm-opt -Oz (run automatically by wasm-pack) is the first lever; trimming winnow’s monomorphizations is the second.
Local development
# One-time
|
# Rebuild after touching Rust code
# Then run Zola
&&
The CI job in .github/workflows/pages.yml runs the same commands.