B3 · Part 1 · Foundations
Where everything lives
Ten directories, the rule each one follows, and the places the rules bend.
06On this page
The map
The repository holds 552 tracked files. Nearly all of them sit in four directories, and the split
between those four is the most useful thing to know before opening anything. The counts are from
git ls-files at commit d6b12d7.
| Directory | Files | What is in it | The rule |
|---|---|---|---|
app/ | 158 | Routes: one folder per topic, the tools, the three API routes, and the metadata files | A route's page.tsx is a server component; the interactive part sits next to it as a client view |
components/ | 56 | UI shared by more than one route: the page frames, the reader, the playground | A component marked "use client" must earn it |
lib/ | 91 | Logic with no markup: content access, storage, runners and workers, and the engines | The engines are pure functions, so they can be tested without a browser |
content/ | 212 | Every word on the site, and every exercise, as typed TypeScript: 5.4 MB of it | Read through lib/, not by pages |
public/ | 0 | The TypeScript lib files and the React sandbox bundle | Generated by scripts before every build and ignored by git |
scripts/ | 4 | The two prebuild steps, the comment checker, and a Vercel clean-up tool | Plain Node, run by npm lifecycle hooks, git hooks or by hand |
tests/ | 15 | Vitest | Tests data and pure logic, not components |
e2e/ | 1 | Playwright: one smoke spec | A real browser against a production build |
docs/ | 3 | The roadmap and an audit | Not shipped to readers |
.github/ | 2 | A Vercel clean-up workflow, and Dependabot | No CI: the checks run locally |
Which way the imports point
content/ imports code, and pages ask lib/
for chapters rather than reaching into the files themselves.
The rule has three exceptions, and they are worth knowing because each one is a small cost someone
accepted. app/git/ imports content/git-body.ts directly, because the Git
guide is one pre-written HTML string rather than chapters, so there is nothing for lib/ to
do. app/mock/Room.tsx dynamically imports content/practice in the browser the
first time a coding question appears, so it can hand the full exercise to the editor; that is the
whole exercise set, downloaded once, on the one screen that needs it. And
lib/practiceLinks.ts imports a type from app/practice/, the only place
lib/ looks upward.
Inside app/
Thirty-one of the route folders are topics. Twenty of them have the same four things: page.tsx for
the cover, [chapter]/page.tsx, [chapter]/loading.tsx for the skeleton, and
search-index.json/route.ts. The other eleven, Python, Java, C++, Rust, Ruby, Go, MongoDB, DBMS,
Networks, Operating Systems and Claude and AI tools, have no chapters yet and hold only
page.tsx. Each of those files is a few lines that call into
components/reader/topicPages.tsx, so the folders are copies of one shape rather than
thirty-one implementations. The architecture folder is the one without a loading.tsx.
The tools are different. app/mock/ has 14 files besides its page: the lobby, the loop
wizard, the room, the scorecard, the readiness dashboard, a timer ring, a small design whiteboard, and
the hook that fetches question banks. app/whiteboard/ has 11, led by
Board.tsx at 1,851 lines, the largest component in the repository. They live with their
routes because nothing else uses them. The routes chapter walks
the whole tree.
Inside components/ and lib/
| Where | What |
|---|---|
components/frame/PageFrame.tsx, components/frame/FrameHeader.tsx, components/topic/TopicFrame.tsx | The frame every page but the whiteboard uses, and its header (a back pill, a menu button, the brand), which the playground and the problem pages reuse around their full-height shell |
components/SiteDrawer.tsx, AppHeader.tsx | The slide-in menu every frame opens, and the header of the full-screen tools |
components/Modal.tsx, AppearancePicker.tsx | Dialogs on the native <dialog> element, and the theme and handwriting picker shared by the playground and the whiteboard |
components/reader/ | 11 files: the helpers a chapter page leans on, such as search indexing, narration, the reader's DOM enhancements and the practice strip |
components/practice/ | 11 files, led by PracticeWorkspace.tsx at about 1,800 lines and CodeEditor.tsx at about 1,100, with workbench.module.css holding the page shell |
lib/polyglot/ | Records test cases from JavaScript solutions and grades other languages against them |
lib/mock/ | 12 files: loops, pacing, scoring, readiness and the session reducer of the mock interview |
lib/whiteboard/ | The board's element model, geometry, export and storage |
lib/debug/, lib/editor/ | The step-through debugger's instrumentation, and the editor's lint and format worker |
lib/*Worker.ts, lib/*Runner.ts | One runner per language family on the page side, and the three execution workers behind them |
There are two whiteboards. lib/whiteboard/ is the full board at /whiteboard,
with freehand, fifteen element kinds and arrows that stay attached. lib/mock/board.ts is a
much smaller one inside the mock interview's design round: boxes, databases, queues and arrows,
serialised into the interview session so the scorecard can draw it again. The cost of keeping them
apart is two drawings of boxes and arrows. The benefit is that the interview's board model is 84
lines and cannot break when the 1,851-line board changes.
The content directory in detail
content/
types.ts ← every content type
topics.ts ← the shelf: topics, levels, syllabus
notes.ts ← barrel for JavaScript (served at /notes)
js/ ← 41 chapter files
react-notes.ts, react/ ← 57
dsa-notes.ts, dsa/ ← 34 written, 8 outlined
system-design-notes.ts, system-design/ ← 24
architecture-notes.ts, architecture/ ← this topic
html-notes.ts ... kubernetes-notes.ts ← outlines only
interview-data.ts ← the interview book, its own record shape
git-body.ts ← the Git guide, one HTML string
practice.ts ← barrel over the exercise groups
practice/
js-fundamentals.ts, js-applied.ts
dsa.ts + dsa-1.ts ... dsa-8.ts
react.ts, react-components.ts
It did not start that way. Four files had grown past the point where an editor is comfortable: the exercises were 840 KB in one file, the DSA notes 626 KB, system design 577 KB and the JavaScript notes 306 KB. They were split by walking the TypeScript AST and moving each chapter's source text into its own file, so the formatting survived and the assembled data came out byte-for-byte identical to what it had been.
The obvious way to split a data file is to import it, then write each piece back out as JSON. That would have turned hundreds of kilobytes of readable HTML bodies, written as template literals with real newlines, into one escaped line each: making the files worse rather than better, while fixing the size. Moving the source text instead keeps every line where the author put it.
The files that are still large
content/interview-data.ts is 430,468 bytes, the largest tracked file after package-lock.json. It has
its own record shape, one object per round with questions, answers, traps and follow-ups, and it is
written one field per line on purpose, which is why .prettierignore lists it:
formatting it would explode it into thousands of lines without changing what a reader sees. The
exercise files are next. content/practice/react-components.ts is 387,720 bytes, and the
whole content/practice/ folder is also in .prettierignore.
content/topics.ts, at 181,034 bytes, used to be ignored too; it is now formatted like
everything else.
Finished reading?
0 of 26 chapters read in this series