PDF Editor: The One Where No-Uploads Mattered Most
Merging, annotating, and stamping PDFs entirely client-side, and why undo had to work before this tool could be trusted with anything real.
Out of everything I've shipped as a web tool so far, this is the one where "no uploads" mattered the most before I'd written a single line of code. PDFs are disproportionately likely to be something someone actively doesn't want passing through a third-party server — contracts, IDs, tax documents, financial statements. A PDF editor that requires uploading the file first is asking for exactly the kind of trust that a browser-side tool doesn't need to ask for at all, and that difference was the entire reason to build this rather than just pointing people at one of the many upload-based PDF sites that already exist.
Two different jobs sharing one toolbar
This tool actually does two fairly different things: page-level operations (merge, split, extract, duplicate, watermark, page numbers) and direct annotation on a page's surface (freehand drawing, text boxes, rectangles, highlights, placed images). Page operations restructure the document itself — reordering, combining, or removing whole pages. Annotations draw on top of a page without touching its underlying content. I split these into two separate toolbars rather than one combined one specifically so it's always visually obvious which kind of action you're about to take. Merging a PDF and highlighting a paragraph are operationally nothing alike, and burying both behind the same button row would make it easy to reach for the wrong tool by accident on a document you can't afford to mess up.
Undo had to exist before this tool could be trusted
I didn't consider this tool done until Undo actually worked reliably across both page operations and annotations, even though it would've been a genuinely simpler build without it. Splitting out a page or applying a watermark are the kind of actions people want to try experimentally — "let me see what this looks like" — and a tool that can't back out of an accidental change on a document you might not have a backup of isn't trustworthy enough to use on something that actually matters. Since nothing here touches a server, there's no server-side version history to fall back on either; the entire safety net has to live in the browser's own undo stack, which made it a harder feature to get right than it would be in a tool that could just diff against a saved copy somewhere else.
Watermarks and page numbers needed real positioning controls
A watermark or page number stamp sounds like a small feature, but doing it well means giving someone real control over position, size, color, and opacity, not just slapping fixed text in a corner. A watermark that's too opaque ruins the readability of the page underneath it; one that's too faint might as well not exist. Rather than pick one "good enough" default and move on, both the watermark and page-number tools got their own modal with actual sliders for these values, because the right settings genuinely depend on what the document underneath looks like — a dense text page and a mostly-white scanned form need different watermark opacity to both stay legible and still be visible.
Merging PDFs means respecting the order you actually chose
Merge sounds like the simplest feature in the toolbar — combine two or more PDFs into one — but the part that actually took care was the page thumbnail sidebar letting you see and reorder pages before committing to a final document. Nobody merges files in the exact order they happened to select them in a file browser dialog often enough for that to be an acceptable default. Being able to see every incoming page as a thumbnail and drag it into the position you actually want, before the merge is final, turns this from "combine these files, hope for the best" into something closer to actually building the document you meant to build.
What I'm still not fully happy with
Rendering and editing a large, image-heavy PDF entirely client-side is genuinely more resource-intensive than a text-light one, and performance on a large document is the thing I'd most like to improve next. It works, but "works" and "feels instant" are different bars, and a fifty-page scanned document with embedded images doesn't feel as snappy as a five-page text contract does when you're switching between pages or applying an annotation. Server-side processing would sidestep this entirely by throwing more raw compute at the problem, which is exactly the trade-off I chose not to make. I'd rather keep optimizing the client-side path than give up the privacy guarantee that's the whole reason this tool exists.
The annotation tools also needed a decision I went back and forth on: should a placed annotation be part of the actual page content once applied, or should it stay as an editable, movable object indefinitely? I landed on the former — once you move on from an annotation, it commits to the page — mostly because keeping every annotation as a perpetually editable object across an entire multi-page document would mean tracking and rendering a growing list of live, adjustable elements for the whole session, which gets expensive and fragile fast on a longer document. Undo covers the case where you committed something you didn't mean to. That felt like a more honest trade-off than pretending every mark on the page should stay infinitely reversible forever.
I keep coming back to how different the design pressure is on this tool compared to something like the Image Editor. A slider that's slightly off just means a photo looks a little different than intended — mildly annoying, easily corrected. A PDF editor that mishandles a merge order or loses a page silently is a much worse failure, because the document people bring to this tool is often the only copy they have handy. That asymmetry is why undo, clear error states, and a visible page order mattered more here than raw feature count. Getting the safety net right felt like a bigger part of the actual job than adding one more toolbar button, even though nobody will ever specifically thank a tool for the mistake it quietly let them undo.