Inspiration

What it does

Elucidate is a Chrome extension that helps students understand why a problem works, not just how to solve it. A student opens a homework question, opens the Elucidate side panel, and captures the question from the page, either from selected text or by picking one of the questions on the page.

Elucidate then breaks the problem into the principles it tests, the assumptions behind the reasoning, and the constraints that limit valid methods and answers. The side panel shows these as layered bands, from the surface of the problem down to its limiting conditions, followed by a short explanation of why the concepts apply.

Once the student has read the analysis, they choose how to challenge themselves: change a condition, push the problem to an edge case, find a counterexample by negating an assumption, or work backward from a result. Elucidate generates new questions that test the same underlying concepts in a different situation, rather than just swapping the numbers. Each variation arrives without its answer, so the student attempts it first and reveals the answer and explanation only when they're ready.

How we built it

Elucidate has three parts:

  • Chrome extension: a Manifest V3 side panel built with React, TypeScript, and Vite. A content script reads the question from the page and converts rendered KaTeX back to clean LaTeX. The side panel handles the flow and renders math with KaTeX.
  • Backend: a FastAPI service with three endpoints (analyze, variations, explain). The AI key stays on the server, prompts are built there, and every model response is validated against strict Pydantic schemas, with one automatic repair attempt when the output is invalid.
  • Demo page: a static problem set, built with React, TypeScript, Vite, and KaTeX, that serves as a realistic test target for the extension.

We started with the API contract rather than the interface. We defined the request and response schemas first, then built mock endpoints that returned hardcoded data for the sample questions, and built the extension against those. That let us finish and test the whole loop before any AI was involved, then swap in the real model behind the same endpoints. A USE_MOCK switch keeps the mock path available for UI work and offline demos.

The backend is stateless. The extension sends the original question and its analysis back with each request, so there's no database and no accounts. The model is Google Gemini, called through the google-genai SDK on the free tier from Google AI Studio.

Challenges we ran into

  • Making the AI output reliable. A response that parses as valid JSON can still be wrong, and a variation question can be badly posed. We used strict schemas, count checks on the number of variations per category, and a repair retry, but these only guarantee the shape of a response. Checking that the math is actually correct is still an open problem.
  • Switching AI providers mid-build. We designed the backend around one model provider, then had to move to Gemini's free tier. Because the AI call lives in one small client module, the prompts, schemas, routes, and extension didn't change. The structured-output feature, though, rejected our strict schemas (they forbid extra fields, which Gemini's schema format didn't accept), so we moved the schema into the prompt and kept validating the result ourselves.
  • A moving target of model names. The model we first chose was retired for new users partway through, and fixing it taught us to treat the model name as configuration rather than code.
  • Reading math off a webpage. KaTeX renders each formula twice, once visually and once as hidden MathML, so naively reading the page text duplicated every equation. We solved it by reading the original LaTeX from KaTeX's annotation element instead.
  • Extension build and reload friction. A Manifest V3 extension needs separate entry points for the side panel, background worker, and content script, with predictable filenames. Several times a failed build or a missing extension reload left an old version running, which made it look like our changes weren't taking effect.
  • Free-tier limits. Rate limits meant we had to keep a mock mode available so a demo wouldn't depend on the API being available.

What we learned

  • Define the contract first. Settling the schemas and mock endpoints before touching the AI or the UI made every later step easier to debug, and it kept the extension simple.
  • Schema validation is not correctness. The hardest part of this project isn't the interface or the plumbing. It's getting an AI to generate conceptually meaningful questions with answers that are actually right.
  • Keep the AI behind a thin layer. Isolating the model call in one module made a provider switch and a model rename small changes instead of rewrites.
  • Design for stateless first. Sending state back with each request removed the need for a database and kept the prototype small.
  • Treat web content as untrusted. Captured page text goes to the model wrapped as data, not instructions, since a page could contain text that tries to steer the model.
  • Small details carry the experience. Rendering math properly, showing clear loading and error states, and splitting question from answer shaped how the tool feels as much as the AI did.

What's next for Elucidate

  • Testing with real students to find out which parts of the analysis and variations actually help them learn, and which are confusing.
  • Wider support: working on more websites beyond the demo page, and accepting images and handwritten work through OCR.
  • Persistence: saved sessions, accounts, and progress tracking so students can see which concepts they've mastered and which keep tripping them up.
  • Deployment: hosting the backend with request limits, so Elucidate can be shared without everyone running it locally.
  • A richer learning loop: letting students submit their own attempt and getting feedback on their reasoning, not only the final answer.

Built With

Share this project:

Updates

Submission history