Frontend Performance/Foundations — From URL to Pixels
Lesson 1 of 20 · Episode 1

Introduction

What makes a site feel fast, the two battles (network + the single main thread), and the journey from URL to pixels.

Why performanceNetworkSingle thread14 KB rule
Watch on YouTube ↗

This series is about one question: what makes a website feel fast? Not “fast” in a benchmark, but fast to the human staring at the screen — the page shows up quickly, and it responds the instant they touch it. Everything we'll do for the next 20 lessons is in service of those two feelings.

The goal

What “fast” actually means

Strip away the jargon and a fast site is two things to a user. Fast load — when I open the page, the important stuff appears quickly. And smoothness — when I click, type, or scroll, the page reacts right away instead of stuttering. Almost every technique in this course is aimed at one or both of these.

InteractiveTwo halves of fast
Fast load — biggest content paints1,800 ms · perceived speed
Smoothness — response to a tap90 ms · responsiveness
A janky site — main thread blocked3,200 ms · feels broken
Loading speed and interaction smoothness are measured separately — and a site can ace one while failing the other.
Why it's hard

The two battles

If a site is slow, the cause almost always traces back to one of two fundamental constraints — and naming them upfront makes every later lesson click into place.

The network. Bytes have to travel from a server to the user over a connection with limited bandwidth and real latency. The more you send, and the more round trips you need, the longer they wait. A huge slice of performance work is simply sending less, sooner.

The browser's single main thread. The browser runs your JavaScript, and lays out and paints the page, on one thread. It pulls tasks off a queue one at a time and can't switch away mid-task — not even for an urgent click. One fat task and the whole UI locks up. So the second half of the work is keeping that thread free.

The whole course in one sentence
Send fewer bytes over fewer round trips, and never hog the main thread. Everything else — Core Web Vitals, bundle splitting, virtual scrolling — is a specific tactic for one of those two.
Mechanics

The journey from URL to pixels

Before we optimize anything, you need the map. Here's everything that happens between hitting enter on a URL and seeing the first pixel. Step through it — each stage is a place we'll later find time to save.

InteractiveFrom hitting enter to first paint
From hitting enter to first paint
ahemdan.com
Translate the domain name into a server IP address:
ahemdan.com🔍 lookup93.184.216.34
💾 The browser caches this — the next visit skips the lookup entirely.
1/6 · DNS
DNS Lookup. The browser maps ahemdan.com to a server IP. Cached after the first visit.
DNS → TCP → TLS → request → parse → render. Every later lesson optimizes one of these stages.
A number worth memorizing

The 14 KB rule

Here's a detail that surprises people. When the server starts sending your HTML, it doesn't blast it all at once. TCP slow start cautiously probes the connection: the first round trip carries only about 14 KB (≈ 10 segments × 1500 bytes). If the data arrives safely, the window doubles each round trip; if packets drop, it halves.

The practical upshot: if the critical HTML and CSS the browser needs to paint a meaningful first screen fit inside that first ~14 KB, rendering can begin after a single round trip. Drag the slider and watch how the cost grows once you blow past it.

InteractiveHow many round trips does your HTML cost?
60 KB
Round trips to deliver
3
Est. delay before full HTML
~150 ms
First round trip
14 KB
Congestion window doubles every round trip — each bar is one round:
14KB
RT1
28KB
RT2
18KB
RT3
At 60 KB the browser needs 3 round trips before it has the full HTML. Inline only the critical HTML + CSS so a meaningful first paint fits in that first 14 KB.
The congestion window doubles every round trip. Keeping critical content under ~14 KB means the browser can start rendering after the first one.
Tip
This is why frameworks inline critical CSS and ship a small HTML shell first. You're not just shrinking the file for its own sake — you're trying to land a useful first paint inside that opening 14 KB.
Feel it for yourself

The single main thread

Reading that the main thread is single-threaded is one thing. Feeling it is another. Below is a live spinner and a clickable button. Run a chunk of heavy work as one big task and the page genuinely freezes — the spinner stops, your clicks queue up and only fire when the task finally ends. Switch to chunked + yield and the same total work stays buttery, because it hands control back to the browser between slices.

InteractiveBlock the thread, then unblock it
0/24 done

Start the work, then mash this button and watch the spinner. In one big task mode the spinner freezes and your clicks only register after the task ends — the single thread was busy.

One long task freezes everything (this really blocks your browser for ~1.6 s). Breaking work into slices that yield keeps the UI alive.
Watch out
That frozen feeling is the single biggest cause of “this site is laggy.” A task over ~50 ms is called a long task, and chasing them down is most of what we do in the responsiveness lessons (INP, Chrome DevTools).
Q1Sort each scenario
Each problem below is really about one of the two fundamental constraints. Sort them.
A 4 MB hero image takes seconds to download
A giant synchronous script freezes clicks for 2 s
A cross-origin API needs DNS + TCP + TLS before its first byte
Sorting 100k rows on the click handler stutters the page
Q2Multiple choice
Why does keeping critical HTML/CSS under ~14 KB matter for first paint?
Q3Multiple choice
In the demo, why did the spinner freeze during the “one big task” run?
Q4Multiple choice
Which pair best summarizes the two things a user means by a “fast” site?
Key takeaways
  • “Fast” means two things to a user: fast load and smoothness.
  • Slowness traces back to two constraints — the network (bytes + round trips) and the browser's single main thread.
  • Getting to first paint runs a fixed gauntlet: DNS → TCP → TLS → request → parse (DOM/CSSOM) → render.
  • TCP slow start delivers ~14 KB in the first round trip — fit a meaningful first paint inside it.
  • A single long task freezes the whole UI. Keep tasks small and yield often.
Next →
2. Critical Rendering Path