Dev Log: Turning PDF into Markdown — All in the Browser
2026-06-24
dev-logpdfbuilding-in-publicjavascript
This is the first post in the LocalPapa Notes dev-log series. We promised to build in public, so let's start at the very beginning — the first tool recorded in our development log: PDF to Markdown.
Why this one first
The starting point was practical. People constantly need to pull text out of a PDF — to paste into notes, drop into an AI chat window, or convert into something editable. The usual approach is to throw the file at some online converter. But that means uploading your document to a stranger's server.
For a contract, a medical record, or an unpublished report, that's too high a price.
So we asked the question that runs through all of LocalPapa: can this be done entirely in the browser?
It can.
The core problem: a PDF doesn't know what a "line" is
Here's the thing most people don't realise: PDFs have no concept of paragraphs or lines.
Under the hood, a PDF is a pile of drawing instructions: "paint this character at coordinate (x, y)." To a machine it isn't prose — it's text fragments scattered across a canvas, each carrying its own position. Extract them naively and you get a jumbled, structureless blob.
Turning that into decent Markdown means the real work is reconstructing visual structure from coordinates.
How we solved it
We use pdf.js (which parses the PDF locally in the browser, honouring the no-upload rule) to get each text block's X, Y coordinates and width, then do three things:
- Group fragments into lines by Y coordinate. Cluster text at similar vertical positions into the same line — but with a 5px tolerance. Why the tolerance? Because text on the same line rarely sits at exactly the same Y: superscripts, mixed font sizes, and baseline differences nudge things slightly. Splitting strictly on "equal Y" would shatter a single line into pieces.
- Sort within each line by X coordinate. So text reads left-to-right in visual order, not in the PDF's internal draw order.
- Detect X-coordinate gaps to recover structure. This is the key to making the output feel structured: when two blocks on the same line are separated by a large horizontal gap (>50px), we insert spaces. That small heuristic preserves column alignment and simple tables — without it, tables collapse into mush.
Finally we assemble the cleaned text into Markdown, paired with a live preview and one-click copy, ready to paste straight into an AI chat.
What we learned
- "Extract the text" sounds simple, but it's really a structure-reconstruction problem. The hard part isn't reading the characters — it's guessing their original layout intent.
- Be honest about heuristics. The 5px line tolerance and the 50px gap threshold are pragmatic trade-offs, not universal truths. They work well on clean, text-based PDFs; they can't help with scanned image-only PDFs that have no text layer at all — that needs OCR, and that's another story.
- Privacy doesn't have to cost performance or quality. The whole pipeline runs inside your browser tab; not a single byte of the file leaves your device.
The start of a principle
Looking back, this first tool set the tone for everything that followed: use clever client-side engineering to do things people assume "must" require a server.
Since then, that same idea grew into the PDF suite, the image tools, the developer utilities, even the divination services — 39+ tools today. But all of them answer the same question we asked back then:
Can this be done entirely in the browser?
Usually, the answer is yes.
In the next dev log, we'll pick another tool and unpack the trade-offs behind it. Want to be first to read it? Bookmark LocalPapa Notes.