Browser Setup
Install the ESM package in the browser application's dependency set:
Load the module asynchronously before creating documents. This lets the package load its WebAssembly binary in a page or module Worker.
import { createMuhammaraWasm } from "@muhammara/wasm";
var muhammara = await createMuhammaraWasm();
var writer = muhammara.createWriter();
The package is ESM-only. Browser applications should serve the bundled module
and its .wasm asset over HTTP through their bundler or static server. Do not
use synchronous CommonJS loading.
TypeScript
The package ships its own declarations and requires TypeScript 5.7 or later.
PDF bytes returned by the package, such as endPDF(), end(), and
createBlankPdf(), are typed as Uint8Array<ArrayBuffer>, so they can be passed
to new Blob([bytes]) or new Response(bytes) without a cast.
Load The WebAssembly Binary
By default the package loads muhammara-wasm.wasm from next to its own
module, and bundlers emit the file automatically. To serve it from a CDN or
supply bytes the application retrieved itself, use the locateFile or
wasmBinary options described in Load the WebAssembly Binary From a CDN or
Your Own Bytes.
Load bidi-js Without a Bundler
Reordering right-to-left text, with the direction option, uses the
bidi-js package, which installs with
@muhammara/wasm. The package loads it with import("bidi-js") when it
starts, so bundlers such as Vite and webpack keep it as a chunk. A page that
loads the package's modules without a bundler maps the bare specifier itself:
<script type="importmap">
{
"imports": {
"@muhammara/wasm": "/node_modules/@muhammara/wasm/index.js",
"bidi-js": "/node_modules/bidi-js/dist/bidi.mjs"
}
}
</script>
bidi-js is loaded once for the page, Worker or process, and every instance
shares it. Pass bidi: false to createMuhammaraWasm() or createRecipe()
to skip loading it when the page never sets direction; once another call
or loadBidi() has loaded it, instances made with bidi: false reorder text
too. Without bidi-js, whether skipped or unresolved, everything else works,
and every call that has to order text by direction throws an error that
names bidi-js instead of drawing the text in the wrong order: text with
right-to-left characters and an "auto", "ltr" or "rtl" direction,
"rtl" text, and a flowed line with right-to-left characters once one of
its runs asks for a direction. Such a call throws before it draws anything,
a table before its first row, or before the row a cell renderer returns
such a direction for; a flow throws when it is laid out, at
flow: false, the next text() with coordinates, table() or endPage(),
and draws none of its runs. Text drawn as given, with the default
"none", needs no bidi-js, right-to-left characters included.
Module Workers do not read the page's import map in every browser; bundle the Worker, or load bidi-js there yourself.
Call loadBidi() to load bidi-js later, for example once a document first
needs right-to-left text after a factory ran with bidi: false. Instances
already created reorder text as soon as it resolves. Without an argument it
imports "bidi-js"; where that specifier does not resolve, pass the module
you imported yourself:
import { createRecipe, loadBidi } from "@muhammara/wasm";
var Recipe = await createRecipe({ bidi: false });
// Later, when right-to-left text is needed:
await loadBidi(await import("/node_modules/bidi-js/dist/bidi.mjs"));
Work With Bytes
Keep source PDFs, fonts, and images as bytes in application code. Inputs are
Uint8Array or ArrayBuffer; output remains owned JavaScript bytes after an
operation completes.
Continue with Byte Assets and Blob Input, then run the interactive browser examples. To display or transfer generated output, see Preview, Download, or Upload a PDF.