SMRTR
Inspiration
Most of what I study comes as a PDF of lecture slides. All the definitions are there, but they come first, and the reason anyone should care comes last, if it shows up at all. A queue appears as "a FIFO abstract data type" long before anyone mentions that you already stand in one every morning at the café.
I wanted a tool where you drop in your notes, or just type a topic, press Make it click, and get a lesson that starts from something you already understand, lets you play with a working model of the idea, and then checks whether it stuck. I didn't want a summary. I wanted the same material in a better order.
What it does
- Takes a question, a topic, or up to three files (PDF, Word, plain text) and builds a visual lesson on an open canvas.
- Each lesson follows one continuing scenario: the problem first, then intuition, then the mechanism, then why it works and where it breaks, and finally a transfer example on new data.
- The interactive parts actually run. The breadth-first search lesson turns a graph into delivery addresses and one-way roads, with parcels waiting on a conveyor belt (the queue). You can edit the map, predict the next stop, and step through the search.
- Before generating, you pick how confident you feel (four levels, optionally per topic). A beginner and an experienced student get different routes and different explanations. "Start more simply" can always be undone.
- A wrong practice answer links back to the exact step that explains it. Optional extras include YouTube resources attached to each stop and a study-time budget that trims the route to fit. Each page is estimated at $\max\left(8,\ \lceil w/150 \rceil + 6\right)$ minutes for $w$ words.
How I built it
The stack is Next.js 16 with React 19 and TypeScript. The canvas uses React Flow and dagre, every data contract is a Zod schema, and uploads are read with unpdf and mammoth. Lessons are generated through OpenRouter (with a direct OpenAI fallback), and the interactive visuals are generated with Claude.
Generation runs as a pipeline instead of one big prompt:
- Preview. A small, fast call picks out the subject and 6–8 key terms, so the loading screen teaches you something while you wait. If it fails, it fails quietly and the lesson still arrives.
- Plan. One call designs the lesson: the concepts, a teaching sequence, a page hierarchy and a concept graph. Those are three different structures, and each is validated separately.
- Modules. Each concept is written on its own, with at most three requests running at once, and streamed to the browser as NDJSON. A module only appears after it passes validation, so you can start reading while the rest is still being written.
The rule I kept coming back to was the model writes the story, and code computes the answers. The BFS engine is ordinary tested code with fixed rules (neighbors in alphabetical order, a node counts as discovered when it's added to the queue). That guarantees
$$d(v) = d(u) + 1 \quad \text{where } u \text{ is the node that first discovered } v,$$
and the whole trace runs in $O(V + E)$. When a question asks which addresses can't be reached, the server works out the answer from the graph instead of trusting the model's answer key.
The generated visuals work the same way. The model streams one JSON line at a time (a shape, a slider, a variable, a readout), and each line is validated as it arrives. Numbers come from a tiny expression language with functions like sqrt and sin, so no code written by the model ever runs in the browser. Standard algorithms (sorting, searching, BFS, DFS, Dijkstra) are computed by trusted engines, and the model only chooses the scenario and the layout. For example, the car-suspension visual defines
$$\zeta = \frac{c}{2\sqrt{km}}$$
and asks you to turn up the shock absorber until the car settles without bouncing. That point is $\zeta = 1$, called critical damping.
There is also a path that needs no API key. The website creates a local lesson request, any MCP-compatible chat can fulfill it through SMRTR's MCP tools, and the result is imported only if it matches the exact request revision.
What I learned
- Valid isn't the same as good. A schema can prove a lesson has the right shape. It can't prove the teaching makes sense. So I added meaning checks on top: every link has to point to a real page, every connection has to explain why two ideas are related, and the beginner and experienced routes have to actually differ. Wherever I could, answers are computed instead of written by the model.
- Teaching order isn't prerequisite order. At first I taught concepts in dependency order, which put the definitions first, exactly what I was trying to avoid. Separating "what you need to know" from "the best order to discover it" fixed the lessons.
- Waiting time is a design problem. I timed models for the visuals. Claude Haiku spent about 30 s thinking before drawing its first line, while Claude Sonnet started in about 8 s and finished in about 20 s, so Sonnet won. A full live map (outline, four units and five visuals) finished in about 48 s, with the first visual on screen at around 7 s.
- Tone matters more than layout. Early lessons read like a textbook. Switching to "start from a real-life scene, then name the term in brackets" ("the café line (a queue)") changed how the lessons felt more than any visual redesign did.
Challenges
- The canvas moved too much. Opening a branch rearranged the graph, paused, then zoomed to fit, and on phones it also jumped to the first child. That was three movements for one click. The fix was to keep the clicked card fixed in place, let its neighbors settle with a critically damped motion (the same $\zeta = 1$ as the suspension lesson), and never move the camera just because a branch opened.
- Untrusted input everywhere. Uploaded notes, model output and filenames are all treated as data, never as instructions. The prompts say so explicitly, uploads are capped at 10 MB per file and 40,000 characters in total, and nothing is ever rendered as HTML.
- Old responses overwriting new ones. With streaming, cancelling and retrying, an old response can arrive after a newer one. Every request carries a revision number, and anything out of date is dropped.
- Building in parallel. I worked with several AI coding agents at once, each on its own branch and git worktree (learning stations, practice exams, videos, visuals). Combining them meant agreeing on shared contracts and keeping concept and question IDs stable, so a saved wrong answer still jumps to the right review step after the layout changes. The combined build passes 195 app tests and 7 MCP tests.
- Being honest about limits. Scanned PDFs need selectable text. Confidence is self-reported, and practice never claims you've mastered anything. Generated visuals can still overlap their own labels. Demo content is labeled as demo content, and if generation fails, the app never swaps in a preset lesson.
Built With
- dagre
- lucide-react
- mammoth
- model-context-protocol
- next.js
- node.js
- openai
- openrouter
- react
- react-flow
- typescript
- unpdf
- zod
Log in or sign up for Devpost to join the conversation.