MIT licensed · no build step · no framework
Kagaz is deliberately boring to work on. There is no toolchain, no bundler, no
node_modules to install before you can see a change.
Clone it, open a file in your browser, and you are developing.
git clone https://github.com/namastevis/kagaz.git
cd kagaz
python3 -m http.server 8000
# open http://localhost:8000
The small web server is only needed because pdf.js loads its worker as a separate file,
which browsers block on file://. Any static server will do.
index.html the landing page
merge-pdf/index.html one tool, one self-contained file
split-pdf/index.html
compress-pdf/index.html
pdf-to-jpg/index.html
certificate/index.html
shared/kagaz.css every page shares this stylesheet
shared/kagaz.js browser helpers: drop zones, downloads, canvas, messages
shared/ops.js the PDF logic — deliberately DOM-free
vendor/ pdf-lib, pdf.js, JSZip, fontkit — vendored, never a CDN
tests/stress.mjs throws deliberately broken PDFs at shared/ops.js
Three rules keep it that way, and they are the only ones:
shared/ops.js, not in the page. That file has no DOM references, so it runs in Node and can be tested. Anything needing a canvas is passed in as an argument.merge-pdf/index.html to your-tool/index.html. It is the simplest of the four.rotate-pdf, not rotator.shared/ops.js as a function that takes bytes and returns bytes.tests/stress.mjs.Roughly in order of how useful they would be, with the easiest first.
pdf-lib's embedJpg does the hard part. Needs page-size options and ordering.shared/kagaz.css, so this is mostly a prefers-color-scheme block.CompressionStream, which browsers now have.node tests/stress.mjs
This throws deliberately awful PDFs at shared/ops.js — zero-byte files, truncated
files, a JPEG renamed to .pdf, encrypted documents, a two-thousand-page monster,
pages of impossible sizes — and checks that each one fails cleanly with a message a human
could act on, rather than crashing or producing a broken file.
There is also an in-browser test page that runs the same battery against the real browser code, including the image compression that Node cannot exercise. Open it after any change.
Kagaz has no server, so it costs me almost nothing to run — a domain renewal and the evenings that go into it. It is free, unlimited and ad-free, and it will stay that way whether or not anyone sends me anything.
If it saved you an evening of fighting with a website that wanted your bank statement uploaded to it, a chai is a nice thing to do.
That Razorpay link is the only outbound link on this site that leads anywhere commercial, and nothing loads from it unless you click. No payment script runs on these pages.
I'm Amit Jena — mathematics and computer science by training, design by accident. I build things that turn data and documents into something a person can use. Kagaz is the documents half; the rest lives next door.