Most of a page load happens before a single byte of HTML arrives, and almost nobody can say how much. Page Load Anatomy is a dissectible model of that gap: pull out a layer — DNS, TCP, TLS, HTTP, the render path — see it working on its own, then change one thing and watch what moves downstream.
A simulator, not an animation
There is no shortage of pretty “how the internet works” diagrams. They animate a packet flying across a wire and teach nothing actionable, because the numbers are decorative.
This is a deterministic model built on real protocol arithmetic, with tests asserting the model matches the specs. When it says a cold HTTP/1.1 connection over TLS 1.2 spends seven round trips before the first byte of HTML, that comes from counting actual flights: four for a cold DNS walk from root to TLD to authoritative, one for the TCP handshake, two for the TLS 1.2 handshake.
Switch to HTTP/3 with 0-RTT resumption and a warm DNS cache and the same page spends zero. On a 100ms link that is 380ms of pure setup you either pay or you do not — and no amount of shrinking your JavaScript touches it.
Things the model makes obvious
Each of these is an assertion in the test suite, not a claim in a README.
- The first 14.6KB is special. TCP’s initial congestion window is ten segments at a 1460-byte MSS. Anything inside it arrives in one round trip; one byte over costs a second.
- A CDN beats halving your HTML. Cutting a document from 12KB to 6KB changes nothing when both fit the first window. Shortening every round trip changes everything.
- Bandwidth barely matters for small pages. Dropping from 1000Mbps to 5Mbps on an 8KB page costs under 20ms. Tripling the round-trip time more than doubles the load.
- HTTP/1.1 queues. Thirteen assets across six connections stack up. The same page over HTTP/2 does not queue at all.
- HTTP/3 saves exactly one round trip over HTTP/2, because QUIC folds the transport and crypto handshakes together.
The two rows worth staring at are bandwidth and latency next to each other. Most engineers optimize the one that barely moves.
Predict and observe
The model predicts. The browser reports. Both matter, and they are different halves.
It turns out the browser already dissects every request for you — PerformanceResourceTiming exposes DNS, connect, TLS, request, response and download timings for everything a page loads. Almost nobody reads it. The observer turns those entries into the same span shape the simulator produces, so a measured request and a predicted one can be drawn by the same code and compared directly.
That also surfaces something naive implementations get wrong. A cross-origin response without a Timing-Allow-Origin header has every phase timing zeroed by the browser. Drawing those as zero-length bars tells the viewer the request was instant, which is the exact opposite of what a withheld timing means. Those entries are flagged as opaque, and no phase spans are fabricated for them.
One instrument, many specimens
The panel ships as a custom element rather than a framework component, so it drops into Next.js, Astro, Vite, or a plain script tag unchanged, with Shadow DOM keeping the host page’s CSS out. The standalone build is 6.6KB, 3KB gzipped, and registers itself on load.
Its first home is the Rental Property Analyzer, where it does something better than measure performance: it proves a privacy claim. That app says your data never leaves the device, and the panel shows you the empty request log that makes the claim checkable.
Why build the fundamentals first
The obvious next step is pushing an LLM request through the same bench — time-to-first-token instead of TTFB, a response streaming for seconds, and a request payload that grows every turn because the whole conversation is resent.
Those properties are genuinely unusual, but they are only visible against a baseline of how ordinary requests behave. Bolting AI onto a black box teaches nothing. Putting it into a model you can already read shows exactly why it behaves unlike anything else on the wire. That is why the pipe came first.