Every part of this window is a directory

  1. chrome/ · ui/the window itselfTabs, toolbar, menus. Not the web platform: Chrome draws its own chrome, with ui/views.
  2. components/the omniboxFeatures too shared for chrome/, too big for content/ — autofill, and the address bar.
  3. content/the tab is a rendererEverything under the toolbar is another process: RenderFrameHost on this side, RenderFrame on that one.
  4. v8/the script behind the buttonShipped inside the renderer, driven through Blink’s bindings — its own repo, its own pace.
  5. net/ · services/the bytes arriveSockets, DNS, TLS, QUIC and the HTTP cache, now reached through the network service.
  6. mojo/across the process lineThe dashed line is a real boundary. Every call over it is a typed .mojom message.
  7. third_party/blink/HTML into boxesDOM, CSS, layout and paint. A fork of WebKit — which is why it sits under third_party.
  8. cc/ · gpu/and finally, pixelsLayers rastered into tiles and handed to the GPU process — why scrolling stays smooth even when the tab is busy.

01 · The page

A page is a document the browser throws away

Before any of this is a framework problem it is a browser problem. Every page you have ever opened went through the same five steps — and then got discarded.

  1. Request

    You click a link. The browser sends one HTTP request and gets one HTML document back.

    GET /cart HTTP/1.1
  2. Parse

    The bytes become the DOM — a tree of objects, one per tag, that scripts can reach.

    <ul> → HTMLUListElement
  3. Style

    Stylesheets are parsed too, and every node in the tree gets a full set of computed values.

    color: #1d1e1c
  4. Layout & paint

    Those values become boxes with real positions, and the boxes become pixels on a screen.

    x, y, w, h → pixels
  5. Discard

    Click the next link and all of it is thrown away. The browser starts again at step one.

    location.href = '/checkout'

02 · The old way

Two decades of making that pipeline sit still

Nobody set out to build a framework. Each era solved the problem the last one left behind, and handed down a new one.

1993 →

The document

the server renders, the browser displays

Every page is built on the server and sent whole. A click is a new request, a form post is a new request, and the browser discards the current page each time. There is exactly one copy of the truth, in the database, and the page is a photograph of it.

<form method="post" action="/cart">
  <button>Add to cart</button>
</form>
2006 →

The sprinkle

jQuery, and the DOM patched by hand

Reloading the world to tick a checkbox is absurd, so scripts start editing the page in place. You select a node and set its text, its class, its style. The document stops being a photograph and becomes the live copy — the only copy — of what the user is looking at.

$('#count').text(n)
$('#row-3').addClass('done')
2010 →

The AJAX app

data over the wire, markup by hand

Then the data arrives without a reload either. Now the server holds a record, the browser holds a JavaScript object, and the DOM holds a rendering of it — and keeping three copies of one fact in step, by hand, forever, is your job.

fetch('/api/cart')
  .then(r => r.json())
  .then(render)   // 40 lines of innerHTML

03 · Where it broke

Four problems, and one cause underneath them

None of this is jQuery being bad at its job. It is what happens when the page is both the interface and the place the state is kept.

01

Three copies of the truth

state has no home

The server knows, a variable knows, and the DOM knows, and nothing keeps the three agreeing. Half of every bug report is two of them disagreeing, and reproducing it means retracing the exact click order that pulled them apart.

if ($('#row-3').hasClass('done')) …
// asking the page what it thinks it knows
02

You write the steps, not the result

every transition by hand

The code says how to get from this state to that one, so every pair of states needs its own patch. Add a fourth field to a form and you are not writing one branch — you are writing it against every state the form was already in.

if (n === 0) el.classList.add('empty')
else el.classList.remove('empty')
03

Nothing is a unit

there is no component to reuse

A widget is markup in one file, a rule in a stylesheet and a handler in a script, joined only by an id string. Put two on a page and the ids collide, the styles leak into each other, and neither one moves without finding all three pieces.

<div id="cart-count">   <!-- html -->
#cart-count { … }       /* css  */
$('#cart-count')        // js
04

The page or the app

you get one of the two

Full reloads are simple and lose everything — scroll, focus, half-typed input. Not reloading keeps them, but then routing, history, the back button and the title bar all become code you write, and get subtly wrong.

location.href = '/cart'
// simple, and the scroll position is gone

04 · The answer

Every framework makes the same four moves

Same four problems, in the same order. Everything in the catalog below is one project answering them in its own words — which is why reading two of them is easier than reading one.

01

One source of state

the DOM stops being the truth

State is declared in one place and the DOM is derived from it. Nothing reads the page to find out what is true, because the page is an output. Vue calls it a ref, React calls it useState, Solid calls it a signal — the same move, three names.

const n = ref(0)
const [n, setN] = useState(0)
02

Describe the result

the framework works out the steps

You write what the screen should look like for the state you have, and the framework finds the difference from what is on it now — by diffing a virtual tree, or by holding a dependency graph that already knows which text node depends on which value.

<p class={n === 0 ? 'empty' : ''}>{n}</p>
03

The component is the unit

markup, style and behaviour in one thing

One thing owns its own markup, its own scoped styles, its own state and its own lifetime, and two of them can sit on a page without ever meeting. Reuse stops being a copy of three files and becomes calling it twice.

<Cart count={n} />
<Cart count={saved} />
04

The app keeps the page

routing, then the server on new terms

A client router swaps a view without discarding the document, so scroll and focus and in-flight state survive it. Then the server comes back — rendered HTML for the first paint, hydration or streamed components to hand over. The reload was never the enemy; the loss was.

<Route path="/cart" element={<Cart />} />

Frameworks

The tools you already build with

Each one is a different answer to the same question: how does the screen stay in sync with the state? Read the answer, then read the repo that implements it.

3 atlases

Vue

Five core concepts, the eleven packages in vuejs/core, and the reactivity system taken apart down to track and trigger.

Open →
3 atlases

React

Fibers, reconciliation, and why hooks have rules. The scheduler that decides what renders and what waits.

Open →
soon

Solid

Signals without a virtual DOM. Components run once, and the reactive graph updates the exact nodes that changed.

The browser

What is actually running your code

Under every framework sits a browser, and under the browser sit a few enormous C++ projects. They are readable too.

5 atlases

Chromium

The multi-process architecture: browser, renderer, GPU. Why a tab crashing does not take the window with it.

Open →
4 atlases

V8

How JavaScript becomes machine code — Ignition, TurboFan, hidden classes, and what makes a function get optimised or thrown out.

Open →
soon

Blink

From bytes to pixels: parsing, style, layout, paint, composite. The pipeline every DOM change is priced against.

Graphics

Down where the pixels are

The last stop of every render pipeline, and the one place where the maths stops being an analogy and becomes the program.

soon

GPU

Thousands of small cores that only pay off when the work is identical. Warps, memory bandwidth, and why branching hurts.

soon

Shaders

Small programs run once per vertex and once per fragment. Vertex, fragment, compute — and the whole screen as one function.

Foundations

The maths the code is made of

Not a detour. A shader is a function evaluated a million times, a transform is a matrix, and an animation curve is a derivative.

soon

Linear Algebra

Vectors, matrices, and transformations as the language every renderer speaks. A 4×4 matrix is a camera.

soon

Calculus

Rates of change and accumulation — the shape of every easing curve, physics step, and gradient descent.

Why one site

These are not separate subjects

A reactive framework is a dependency graph. A dependency graph is a matrix. A shader is a function evaluated a million times in parallel, and the easing curve on a dropdown is a derivative. Split across four courses they look like four fields; read together they are one conversation that keeps handing the same idea to the next layer down.