What is Crow Docs?
Crow Docs is a free, open-source, browser-based document toolkit. Merge, split, compress, sign, translate, OCR, compare, booklet, metadata editing, Markdown-to-slides, image-to-PDF, PDF-to-audio, PDF-to-PPTX — it does a lot.
The key detail: everything runs 100% client-side. No file uploads. No server processing. Your documents never leave your device. It's a PWA, so it works offline too.
The email that started everything
A user wrote in with two issues: "the PPTX export doesn't open in PowerPoint" and "GIFs in my PDF don't animate."
Fair feedback. But instead of patching just those two things, I decided to audit every tool in the app. What I found was humbling — 12 bugs across the entire toolkit, some hiding in plain sight for months.
The 12 bugs (and why they existed)
PDF to PPTX wouldn't open in PowerPoint — Google Slides is forgiving about missing OOXML structure. PowerPoint is not. Added proper theme, clrMap, txStyles, grpSpPr transforms, and docProps.
QR codes wouldn't scan — Custom inline QR encoder had subtle bugs. Replaced with the battle-tested qrcode-generator library.
Compare PDFs showed NaN — ImageData dimensions mismatch when PDFs had different page sizes. Fixed by normalizing to same-size canvas.
Booklet page ordering was wrong — Saddle-stitch imposition algorithm had incorrect formula for inner sheets. Corrected: outerLeft = total-1-s*2, outerRight = s*2, innerLeft = s*2+1, innerRight = total-2-s*2.
Markdown to Slides splitting failed — Regex didn't handle whitespace around --- or Windows \r\n line endings.
Translate PDF lost paragraphs — join(' ') instead of join('\n'). One character, all paragraphs gone.
PDF metadata keywords stored incorrectly — Saved as single-element array instead of splitting by comma.
Sign PDF crash — No null check on canvas element before drawing.
Organize PDF used generic filename — Now preserves the original filename.
GIF in PDF — no warning — PDFs don't support animation. Added toast notification explaining the limitation.
OCR errors showed "undefined" — Six catch blocks used e.message without fallback. Fixed with e?.message || String(e).
Header/footer regex typo — /^Página?/ matched "Págin" instead of "Página". Fixed to /^P[aá]gina/i.
Lessons learned
PowerPoint doesn't forgive. Google Slides will render a half-valid PPTX. PowerPoint will reject it. Test against the strictest consumer.
Users find what tests don't. A real person trying to open your file in their specific environment — that's where edge cases live.
Self-hosting dependencies pays off. Every library lives in /libs/. No CDN calls. The offline story is bulletproof because there are zero external runtime requests.
Tech stack
Vanilla JS. No frameworks, no build step. The heavy lifting comes from: pdf-lib, jsPDF, PDF.js, Tesseract.js, JSZip, mammoth, docx, and qrcode-generator.
Try it, break it, tell me
Top comments (0)