How this is builtGroundworkHow this is built
1 / 26 written chapters

B1 · Part 1 · Foundations

What this site is

One decision shaped everything else: the site is a build artifact, and the heavy work runs in your browser.

5 min read2 diagrams7 sections
07On this page
  1. The one-sentence version
  2. The decision underneath
  3. The three layers, and where work happens
  4. What the 1,803 routes are
  5. The four tools, and where each one runs
  6. What the server still does
  7. What this chapter set covers

The one-sentence version

A reading site with four tools attached — a code playground, a set of runnable problems, a mock interview and a whiteboard — rendered to files at build time, served by a CDN, and doing its heavy lifting inside the reader's browser. There is no database, no login, no session, and nothing kept alive between deploys. Three small server functions exist. Everything else was either written before you arrived or runs on your own machine.

The decision underneath

Almost every choice in these chapters follows from one call made early: the content lives in the repository as TypeScript, and the whole site is rendered ahead of time. That is not the obvious choice for a site whose latest production build wrote out 1,803 routes, and it has a real cost: fixing a typo means a deploy, and adding a problem means a build.

What it buys is that the interesting parts of this system are the parts that do not run. A page that was written at build time cannot time out, cannot exhaust a connection pool, and cannot return a 500 because something upstream is slow. The failure modes that dominate most web architectures were removed rather than handled.

The second decision followed from the first. Once there was no server to lean on, anything that looks like computation had to move to the reader. When you run Python on a problem, the Python interpreter is WebAssembly running in a Web Worker in your tab. When you compile C++, the compiler is clang, compiled to WebAssembly, downloaded once and cached by your browser. When you save a whiteboard, it goes to localStorage. The server never receives your code, your boards or your interview answers, because it has nowhere to put them.

Measured today
Prerendered routes1,803 in a local production build of this branch, counted from .next/prerender-manifest.json
Server functions3, all under /api/
Databases0
Topics32 — 5 written, 25 outlined, 2 standalone
Written chapters253, plus 358 outlines
Exercises with tests955
Interview questions420 across 27 rounds
Editor languages17, of which 11 run in the browser
Application code274 TypeScript files in app/, components/ and lib/, 26,684 lines

The route count comes from .next/prerender-manifest.json. The content counts come from the data through lib/content.ts. The code count is wc -l over the tracked files at commit d6b12d7.

The three layers, and where work happens

THE READER'S BROWSER HTML, one JS bundle per route localStorage: progress, code, boards, mock sessions Web Workers WASM runtimes iframes VERCEL EDGE CDN cache + firewall 1,803 prerendered routes 3 functions THIRD-PARTY CDN jsDelivr Pyodide, sql.js, Ruby, PHP, Lua and clang runtimes answers every request on first use deployed into the edge BUILT AHEAD OF TIME TypeScript content → HTML, JSON, images, sitemap
Only the top two rows exist at request time. The green band happened before the reader arrived, and the right-hand box is only touched when a reader picks a language that needs it.

What the 1,803 routes are

A static site with that many routes sounds like a site with that many pages of prose. It is not. About a third are reading pages. Most of the rest exist because every problem gets two routes: its own page, and a JSON file of test cases recorded from the JavaScript solution at build time.

1,803 PRERENDERED ROUTES, TO SCALE 594 chapter pages 538 problem pages 538 test-case JSON files 133 the other 133: 31 topic covers · 21 search indexes · 30 level pages · 12 path pages · 12 mock question banks · the placement page 9 share images · 17 single pages, icons and metadata files
The 594 chapter pages include the outlines: an unwritten chapter still gets a page, marked noindex and left out of the sitemap. Counted from .next/prerender-manifest.json.

The four tools, and where each one runs

ToolURLWhere the work happensWhere its state lives
Reader/<topic>/<chapter>HTML from the build; search JSON fetched on the first keystrokejsnotes:progress
Playground and problems/practice?id=free, /problems/<id>Web Workers, WebAssembly runtimes and sandboxed iframesgroundwork:playground:project, jsnotes:code:…
Mock interview/mockA client-side session engine over 12 prerendered question banksgroundwork:mock:…
Whiteboard/whiteboardA canvas that never renders on the server at allgroundwork:boards

The storage keys are the real ones. The older features write under jsnotes: and the newer ones under groundwork:. Renaming the old keys would orphan every reader's saved progress, so both prefixes stay.

What the server still does

Three route handlers under app/api/ run as functions on request. /api/tts turns chapter text into speech for the Listen button. /api/joke fetches one programming joke for the progress page. /api/client-error writes browser errors to the function log when Sentry is not configured. Each one has a per-IP rate limit, held in memory in the function instance, and none of them is on the path of reading a chapter or running code. If all three went down, the site would lose a voice and a joke.

What this chapter set covers

The beginner tier is orientation: this overview, the stack, the repository, the content model, what is written and what is not, and every route. After that come the chapters on how it runs: the request path, the build, rendering, state, the playground, the endpoints and search, plus the in-browser runtimes, how a solution in another language is graded, the step-through debugger, the whiteboard, the mock interview engine, the design system and how a change reaches production. The last tier is how it holds up: performance, security, the tests, the health of the project, what breaks first, and what is deliberately missing.

Every number here was measured, and a test keeps it honest

Nothing on these pages is an estimate. Counts come from the data itself, the route count from the build's own manifest, and line counts from the tracked files. Several of the numbers in these chapters are also checked by tests/claims.test.ts, which recomputes them from lib/content.ts and fails if the prose has drifted, so adding a chapter without updating the claims here breaks npm test. Where a number is unflattering it is still the number.