Inspiration

I have re-read the same paragraph three times and still not known what the author was trying to say. Not because the words were hard — because the structure was missing from my head.

That is the problem I wanted to fix. Summarizers compress: they hand you the gist and throw away the shape. But the shape is what makes an idea click. A summary of backpropagation is not the same as the moment you realize it is just the chain rule applied backwards. I wanted a tool that keeps the structure and only changes the framing, so the same source can land for a student, an executive, and an engineer without becoming three different documents.

What Clarity does

Paste text, drop a PDF, or extract a URL. Choose an audience. Clarity streams back four sections — a TL;DR, an analogy drawn from the audience's own world, a jargon buster, and one takeaway — plus an interactive concept graph. Every claim can carry a paragraph citation like [p3]. Click it and the source panel opens, scrolls to that paragraph, and highlights it. Verification instead of trust.

The audience is a contract, not a tone slider. It changes what the model is allowed to assume, which analogies it can reach for, and what the output is meant to do:

  • Student — no domain background, warm analogies from daily life, explains what and why.
  • Executive — business literacy, outcome over mechanism, explains so what and what to do.
  • Developer (Non-ML) — software fluency, not ML fluency, analogies from systems and data structures, explains how it works.

All three axes move at once. That is what makes the output feel tailored rather than adjusted.

One diagram

[ Dense Source (Paste / PDF / URL) ]
              |
              v
     [ Pick Audience ]
  (Student, Exec, Developer)
              |
              v
 [ Streamed Decode (via AI SDK) ]
              |
              +--- TL;DR -----------+
              +--- Analogy ---------+
              +--- Jargon Buster ---+--> [ [pN] Citations ]
              +--- Takeaway --------+    (Click to jump to source)
              +--- Concept Graph ---+
              |
              v
[ Local-First Storage (IndexedDB) ]
              |
              v
       [ Share Option ]
              |
              +--- NO  --> [ Stays on Device ]
              |
              +--- YES --> [ Public Link (Neon DB) ]

How I built it

Stack. Next.js 16 with the App Router and Turbopack, React 19, TypeScript in strict mode, Tailwind v4 with CSS variables for theming, Zustand for state, Dexie for IndexedDB, the Vercel AI SDK with Google Generative AI, React Flow with Dagre for the concept graph, Mozilla Readability and JSDOM for URL extraction, Neon Postgres for optional sharing, and Zod for validation at every boundary.

Prompt design. Each section is assembled from four blocks: role, audience guidance, a paragraph-numbered source marked as untrusted input, and a task instruction paired with a hard format ceiling. The TL;DR is capped at twenty-five words. The takeaway at twenty. The jargon buster uses a fixed arrow grammar with no prose at all. Those ceilings are what stop the model from drifting into essay mode, and they shipped before any UI code.

Citation pipeline. The source is split on blank lines and prefixed with [P1], [P2], and so on. The model is instructed to cite with lowercase [pN] when a clause traces to a specific paragraph. The frontend parses those markers into buttons that scroll and highlight the source. It turns "trust me" into "check me."

Streaming. SSE over a ReadableStream, one section at a time, tokens flushed on animation frame. Sections render progressively with skeletons that collapse as text arrives. The interface feels live instead of frozen, and partial results survive a dropped connection.

Safety. The URL extraction route resolves DNS, rejects private and link-local ranges, follows redirects manually, caps responses at 5 MB, times out at 10 seconds, and only accepts HTML content types. This is the part of the app most likely to be abused, so it was written defensively on day one.

Challenges

Hallucination. The first version produced confident nonsense. The fix was not a bigger model — it was a stricter contract. Ground every claim in the source block, mark the source as untrusted input, require a paragraph citation whenever a clause traces to one, and let the UI prove it. The result is that the output is checkable, not just plausible.

The audience contract. Early on, "Executive" and "Student" produced the same essay with different adjectives. I rewrote the audience guidance as three distinct operating instructions — what to assume, which analogies to reach for, what the output is for — and the sections started diverging within an hour of that change.

Privacy without giving up sharing. I wanted the whole app to work offline-first, but sharing needs a server. The compromise: everything lives in IndexedDB, the session identity lives in localStorage, and only when the user presses Share does a single decode payload go to Neon. The delete token is hashed with SHA-256 before storage. Revoking removes the row. The default state is private, and the user has to opt in to exposure.

Rate limits without a backend. The rate budget is enforced client-side in localStorage, twenty decodes per hour. Not bulletproof against a determined user, but enough to protect a free model tier from accidental abuse, and it never requires an account.

What I learned

Plan before you build. The Devpost Learn Skill Pack forced scope.md, prd.md, and spec.md before any code. That planning step is the whole game. AI agents drift toward disconnected features when you do not pin the boundaries first, and my scope.md explicitly listed what I would not build. That list saved the project more than once.

Design constraints before features. The citation requirement, the untrusted-input wrapper, and the word ceilings on each section all shipped before the UI. Those constraints are what make the output usable. Adding them later would have meant rewriting the prompts and every component that touched them.

Small product details do the heavy lifting. The rate budget bar in the status toolbar, the "Results out of date" badge when the source changes after a decode, the two-step delete confirmation — none of these are in the spec, and all of them make the app feel finished rather than demo-ready.

Local-first is a design decision, not a fallback. Starting from IndexedDB meant I never had a backend to lock myself into, and the privacy story wrote itself.

Try it

Clarity runs on your own Gemini key, so there is no hosted demo. The video shows the full flow end to end. The repo has everything you need to run it in two commands.

Built With

Share this project:

Updates

Submission history