MantisPDF is a free, open-source PDF toolkit that runs entirely in your browser. Split, merge, compress, rotate, encrypt, and watermark PDFs using WebAssembly β no uploads, no servers, no tracking.
Your files never leave your browser. All PDF processing runs locally via Rust-compiled WebAssembly.
Most online PDF tools (ilovepdf, smallpdf, etc.) upload your files to their servers. MantisPDF is different:
- No uploads. Your PDFs stay on your machine β always.
- No server, no tracking. There's nothing to breach and nothing to log.
- Rust performance in the browser. PDF operations run in a Web Worker via
wasm-pack-compiled Rust, so the UI stays responsive even on large files. - Open source. MIT β audit it, fork it, self-host it.
- Split PDF β Select exactly where to split and download the parts as a ZIP
- Merge PDF β Combine multiple PDFs into one, with drag-and-drop reordering
- Edit PDF β Delete or reorder pages, download result as
_edited.pdf - Compress PDF β Reduce PDF file size entirely client-side
- Rotate PDF β Rotate individual pages (90Β°, 180Β°, or 270Β°)
- PDF to Images β Export each page as a PNG or JPEG image
- Watermark PDF β Stamp custom text on every page (size, opacity, angle, color)
- Encrypt PDF β Password-protect a PDF so only authorized readers can open it
| Layer | Technology |
|---|---|
| Frontend | React 19, TypeScript (strict), Tailwind CSS |
| Bundler | Vite 6 with WASM + top-level-await plugins |
| PDF engine | Rust + lopdf, compiled to WASM via wasm-pack |
| Preview | react-pdf for page thumbnails |
| Packaging | JSZip for multi-file downloads |
- Node.js >= 18
- Rust toolchain (
rustup) - wasm-pack β install with
cargo install wasm-pack
# Clone the repo
git clone https://github.com/BryanBradfo/mantispdf.git
cd mantispdf
# Build the WASM module (required before first run)
npm run build:wasm
# Install JS dependencies
npm install
# Start dev server
npm run devThe app opens at http://localhost:5173.
mantispdf/
βββ crates/mantis-wasm/ # Rust crate β PDF ops compiled to WASM via wasm-pack
βββ src/
β βββ pages/ # Route-level page components (one per tool)
β βββ components/ # UI components grouped by tool + shared common/
β βββ hooks/ # usePdfWorker, useSplitState, useMergeState, β¦
β βββ workers/ # pdf.worker.ts β WASM init + PDF processing off main thread
β βββ lib/ # workerProtocol.ts, fileHelpers.ts, downloadZip.ts
βββ vite.config.ts # WASM plugin config (worker.plugins + optimizeDeps exclude)
βββ package.json
Contributions are welcome! For ideas or bug reports, open a Discussion or Issue.
To contribute code:
# Fork the repo, then:
git clone https://github.com/<your-fork>/mantispdf.git
cd mantispdf
npm run build:wasm # build WASM first
npm install
npm run dev # start dev server at localhost:5173Run Rust tests with:
cd crates/mantis-wasm && cargo testThen open a PR against main. Please keep PRs focused β one feature or fix per PR.
- Upload β Drop a PDF onto the DropZone. The file is validated (type + 100 MB limit) and read into an
ArrayBuffer. - Configure β Choose tool-specific options (split points, passwords, watermark text, β¦).
- Process β The main thread transfers the PDF bytes to a Web Worker via
postMessage. The worker calls the relevant Rust/WASM function (extract_pages,merge_pdfs,encrypt_pdf, β¦) off the main thread. - Download β The result is transferred back and saved: single files via a Blob URL, multi-part results via JSZip.
UI Thread Web Worker
ββββββββββββ ββββββββββ
DropZone β validate & read
Configure tool options
β
βββ postMessage(pdfBytes, options) βββ
β init WASM (once)
β call WASM fn (lopdf)
β βββ postMessage(result)
β
downloadBlob / downloadZip β browser saves file