Shots in this scene
The Rendering Pipeline in Depth
In one line
A frame is style, layout, paint and composite. Some of that runs on the busy main thread and some on the compositor thread, which is why a transform animation can keep moving while a left animation freezes.
Think of it like this
A restaurant. The waiter (the main thread) takes orders, decides where every table goes and fills the plates. A conveyor belt (the compositor) carries finished plates to the tables. If the waiter is stuck in a long argument in the kitchen, plates already on the belt keep riding. But a change that needs the waiter, such as moving a table, waits until the waiter is free.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- main thread
- The one thread that runs your JavaScript, style, layout and paint. A long task on it blocks everything else on it.
- compositor thread
- A second thread that stacks painted layers and can move, scale and fade them without the main thread.
- layout
- Working out the size and position of every box on the page. One change can move many boxes, so it can cost the most.
- paint and raster
- Paint records what to draw; raster turns that into pixels. Together they draw an element's look again.
- composite
- Stacking painted layers (with their transforms and opacity) into the final picture.
- jank
- Visible stutter: a frame that arrives late or not at all.
Step by step
01Follow one frame
On a 60 Hz screen the browser gets 16.7 ms per frame. Each frame it runs your timers and requestAnimationFrame callbacks, then style, layout and paint on the main thread, then composite on the compositor thread. If the main-thread part runs past the deadline, that frame is late.
02Start with the widget
Choose transform, then left in the widget below, and switch on main thread busy: the left lane misses frames and the transform lane does not.
03Prove it in the page
In "A busy main thread" the left track is red and the transform track is green. Press the button at 1× (not paused).
04Check who drives the animation
In "Who runs it?" CSS, the Web Animations API and a requestAnimationFrame loop all move transform. Only the loop box stops.
Try it yourself
- 1
Freeze one box, not the other
In "A busy main thread" press the block button while the boxes move. In a screen recording in headless Chromium, the blue
transformbox showed 29 frames of movement during the block and the orangeleftbox none. - 2
Count the animations the browser knows
In "Who runs it?" the console says
animations the browser knows about: 2. Press the button: the CSS and WAAPI boxes kept moving (29 frames each) and therequestAnimationFramebox showed none.
Code & diagrams
Try it: interactive
The frame, step by step
Pick transform, then left, then switch on the busy main thread. Watch which lane misses frames. (Its stage times are illustrative, not measured.)
Press the button at 1×: the orange box (left) freezes for 600 ms, the blue one (transform) keeps moving. The busy loop stops itself after 3 million turns, so a paused timeline cannot hang it.
Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.
Console
Nothing logged yet.Expected console output
animations: 2CSS and the Web Animations API show up on the timeline as tracks (2 animations). The requestAnimationFrame loop does not: the browser does not know it is an animation, and it stops when the thread is busy.
Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.
Console
Nothing logged yet.Expected console output
animations the browser knows about: 2Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Drive the transform from JavaScript
In "A busy main thread", replace the CSS via-transform keyframes with a requestAnimationFrame loop that sets style.transform (as the green box in "Who runs it?" does).
Myth vs fact
Myth
Anything animated with transform is always smooth.
Fact
Only when the browser drives it. A transform set from a requestAnimationFrame loop stops when the main thread is busy.
Remember this
- 1
The problem this solves: an animation that is smooth on your laptop can stutter on a phone, and your own page code can freeze one animation but not another. Until you know the steps of a frame and who does them, this looks random. With the steps, it is predictable.
- 2
The steps of a frame. (1) Style: the browser works out which CSS rules apply to each element and what the values are right now. (2) Layout: it works out the size and position of every box. (3) Paint: it records what to draw (text, borders, backgrounds, shadows) for each layer. (4) Raster: it turns those drawing instructions into pixels, tile by tile, usually on the GPU. (5) Composite: it stacks the layers, moving, fading or transforming them, and sends the picture to the screen. (Recall from Topic 1.4: you met these steps in plain words. Here we open each one.)
- 3
Two threads that matter. The main thread runs your JavaScript, style, layout and paint. It does one thing at a time, so a long task blocks everything else on it. The compositor thread only stacks layers that are already painted. It can move, rotate, scale and fade a layer without asking the main thread, and it also drives scrolling.
- 4
Which animations run on the compositor. A CSS animation, a CSS transition or a Web Animations API animation of
transformoropacitycan. Hectal's measured table in Topic 6.2 adds a few more in current Chromium. An animation written in JavaScript (arequestAnimationFrameloop that setsstyle.transform) cannot, because the main thread must run that code every frame. Who drives the animation matters as much as the property.
Explain it without notes
Name the steps of a frame and say which run on the main thread.
Why can a CSS transform animation keep moving while a 600 ms task runs, but an identical left animation stops?
Practice
In "Who runs it?" add a fourth box animated with the translate property (translate: 150px 0) by CSS, and a button that blocks the thread. Does it keep moving?
Write a busy(ms) function and describe how you would use it to test whether a given animation survives a busy main thread.
Done when you can
You can name the five steps of a frame
You can say which thread runs each step
You know which kinds of animation can run on the compositor
You can show with a busy-loop test whether an animation survives a busy page