8 min read

i rebuilt the PDF three times on paper before i ever touched code

three PRDs planned an extract-and-rebuild architecture for lecture PDFs. I never built any of them. Here's the story of how I talked myself into that plan twice, walked away from it twice, and only started coding once I'd finally let the PDF be a PDF.

lectureliftarchitectureproduct
Four PRD documents stacked, representing LectureLift's architecture pivot
lectureliftarchitectureproduct

Before I wrote a single line of code for LectureLift, I planned it out four separate times. Three of those plans never left the page, each one scrapped for a different reason before I built anything from it. Let me walk you through all four, because the story of how I got to the fourth one is more useful than the fourth one itself.

The problem I kept coming back to

Lecture PDFs are written for people who already understand the subject. Slides skip steps, assume prior knowledge, and introduce terms without defining them. I know this one personally, not just as a builder. You hit a wall in your own lecture notes, open ChatGPT in another tab, copy-paste the confusing paragraph, and by the time you get an answer you've lost your place in the original document. Then you do it again ten minutes later.

I wanted to build something that caught that confusion before I had to go looking for help. Flag the parts of a document likely to trip me up, teach the missing prerequisite right there, quiz me on the actual material once I'd been through a section.

That part of the idea never changed, not once, across four rewrites of the plan. What kept changing was how I imagined the document itself would look on screen. And it turns out that one decision was carrying the entire project.

v1: a plan built for a stage, not a semester

The idea to build LectureLift started as a hackathon PRD. I scoped it for exactly what a four-minute demo needed: confusion detection, a "translate lecturer language" toggle, PDF-aware chat, a prerequisite-teaching flow, quizzes, an audio tutor if there was time left over.

I even planned a whole section on demo reliability into that PRD. Pre-cache the AI responses before judging starts. Keep a fallback video ready in case the live pipeline breaks on stage. Looking back, that's exactly the right way to plan something that has to work once, in front of judges, for four minutes.

It is not a plan for something you're going to lean on every week for a semester. I knew that even then. I just didn't act on it yet.

v2: I planned myself into a company I couldn't build alone

After the hackathon I sat down and rewrote the whole thing under a new name, Omzig, and somewhere in that rewrite the scope stopped being about a PDF at all. The vision line changed from "highlight confusing sections" to becoming the first AI-native textbook platform, and the feature list grew to match that ambition.

I planned a pipeline that would extract concepts instead of text, then build a dependency graph between them. Picture something like Arrays leading to Linked Lists, leading to Stacks, leading to Trees, leading to Binary Search Trees, with the system recommending what to study next based on where you sat in that graph. I planned seven separate explanation modes, Simple, Technical, Exam Focused, Real World, Visual, Programming, Step-by-Step, each one generated fresh for the same concept. On top of that, an adaptive learning layer tracking time spent, repeated reads, explanation requests, quiz performance, chat interactions, all feeding into a mastery estimate.

I also planned ingestion beyond PDF. PowerPoint and DOCX for v1, YouTube transcripts and EPUB and web articles queued up as "future."

None of it was a bad idea on its own. A concept-dependency graph is genuinely useful. Seven explanation modes are genuinely useful. Mastery estimation from behavior is genuinely useful. But laid out together, I'd sketched a small ed-tech company's roadmap, not something one person builds solo while still in school.

I never opened a code editor for this version either. I just kept adding pages to a document until it stopped describing anything I could actually finish. Although the vision isn't dead yet, I'd still come back to it later.

v3: I finally had the right scope and the wrong idea about rendering

v3 is where I pulled the ambition back down to something one developer could realistically ship: confusion detection, "Teach Me the Missing Piece," grounded chat, quizzes with source-linked feedback. I cut the concept graph, the seven modes, the mastery layer. That cut was the right call, and it's the one part of this story that held all the way through to what I eventually built.

But I carried one idea over from the Omzig detour without questioning it hard enough: extract the PDF into structured content with a JS-native parser, then render a custom interactive workspace from that structure. JSON in, UI out. The student would never actually see their own PDF again, only my rebuild of it.

I didn't get far into testing that idea before I saw why it wouldn't hold up.

I ran extraction against a real, dense lecture PDF, and the structure that came back wasn't clean. Diagrams, tables, equations, code blocks, none of it maps neatly onto extractable text, and I couldn't get anywhere near the accuracy this approach actually needed.

Then I did the cost math in my head, and it didn't sit right either. Rebuilding a document's layout and content well enough to look intentional means running real generation against every page, not just the parts a student gets confused by. I didn't have exact numbers to run, but I could see the shape of it clearly enough: a cost that scales with every document someone uploads, on a free tool with no revenue, is the wrong shape from day one.

And the third thing, honestly, is the one I already carried a scar from. I'd used other ed-tech tools that strip a lecturer's diagrams and tables down into a flattened summary, and I knew exactly how much that degrades the material, because I'd felt it as a student. A rebuilt page that turns a professor's diagram into a caption isn't a study tool. It's a worse copy of something I already had.

v4: the version where I stopped fighting the PDF

The fix, once I actually saw it, felt almost too simple. Stop extracting and rebuilding entirely. Render the original PDF exactly as it is, using pdf.js, and let that be the reading surface, full stop. Everything LectureLift adds on top — confusion highlights, missing-piece explanations, quiz prompts — gets layered on as an overlay, positioned using bounding-box data that gets pulled separately and used only for AI analysis, never shown to the student.

Diagram showing the original PDF rendered by pdf.js on one path, and bounding-box extraction plus AI analysis on another path, converging into an overlay drawn on top of the unmodified PDF
The hybrid path: the source PDF never gets rebuilt, only annotated.

That one change solved the content-loss problem and the cost problem at the same time, which is part of why it felt so obvious in hindsight. Nothing about the source document ever gets regenerated, so there's no content to lose and no per-page rendering cost sitting on top of every upload. The only AI spend left is analysis: finding the friction points, writing the explanations, generating the quiz questions, all scoped to the sections that actually need it.

This is also where the real building started. Writing v4 is the first time I opened an editor for this project.

The switch brought a dependency I hadn't planned for. The tool doing the bounding-box extraction needed Java, so the backend moved to a Docker-based setup on Render, with a separate keep-warm cron ping to dodge cold starts on the free tier.

v4 also gave me something the earlier plans never had: section-boundary pacing with configurable strictness, soft, medium, or hard. Once I stopped trying to control the experience by rebuilding the document's structure, pacing became the actual lever for controlling how someone moves through it.

Where it still isn't perfect

I want to be straight about this part. Bounding-box positioning from PDF extraction isn't pixel-perfect on every layout, dense equation-heavy slides especially, and running a Java-based extraction step made hosting heavier than a pure Node backend would have been.

Neither of those broke anything I'd built. But they're the two things I'd end up circling back to next.

What I'd tell myself before any of this

The jump from v1 to v2 was ambition running ahead of scope. The jump from v2 to v3 was scope discipline finally catching up, though it took a whole detour into a textbook-platform fantasy to figure out what actually needed cutting. But the real insight, the one that mattered, was that extraction-and-rebuild was fighting the format instead of using it, only showed up once I sat with v3's plan long enough to test it against a real PDF and watch it fail on parsing, on cost, and on the exact content loss I already knew to be afraid of.

That's the architecture running now, and the first one I actually sat down and built. Next up: the parsing swap that got extraction off Java entirely.

Background Image

thoughtsandnotes

here i share ideas, document experiments, and talk about things i'm learning or building along the way. it's more of a quiet corner for insights, progress, and everything in between.

YOU MADE IT THIS FAR

Let’s build something exceptional together.

Tell me about your project and I’ll help you shape it into a polished, high-performing experience.