Detail 09 · Transitions
Sketching the page before it arrives
The page sinking away, then the next one measured and sketched in pencil before it builds inside the sketch. 9 minutes, 3 demos.

01 · The idea
Draw it before you build it
On most sites, a click swaps one page for the next. Here the next page arrives the way a designer first sees it: as a pencil wireframe, with every box and line of text roughed in, and then the real page builds inside the sketch.
It’s the site’s whole idea, sketch first and interface second, played out on every page change. And it’s not a picture of a wireframe: each sketch is measured from the real page, at the size you’re seeing it, every time.
02 · Watch it
Four beats
Below is a small page, marked up the way the site’s pages are, and measured and sketched by the site’s own code. Pick another page to play the whole change; slow it down, and show the marks to see what the sketch is built from.

1.Sink away
The page you're on scales back and blurs, fading only at the very end, toward the middle of the screen.
1.4s2.Measure
Unseen, the new page goes in. Once its layout settles, every marked block and line of text is measured where it really is.
measureWireframe()3.Sketch
The measurements become a pencil wireframe: paper, hatched boxes, tags, a scribble for each line of text.
2s4.Build
After a short pause, each block blurs in where its box was drawn, in reading order, and its sketch fades away under it.
revealDelay(index)
03 · The exit
Sinking, not cutting
The page you’re leaving doesn’t vanish. It sinks back, scaling down a little and blurring the whole way, and only fades out in the last few tenths of a second. That way you watch it go, rather than seeing it blink out.
const LEAVE_DURATION = 1.4; // s for the current page to sink away (slow, cinematic)
// Within that: it sinks and blurs the whole way, and only fades out at the very end
const LEAVE_TRANSITION = {
scale: { duration: LEAVE_DURATION, ease: [0.4, 0, 0.2, 1] },
// Blur builds slowly, then deepens
filter: { duration: LEAVE_DURATION, ease: [0.5, 0, 0.75, 0] },
opacity: { delay: LEAVE_DURATION * 0.72, duration: LEAVE_DURATION * 0.28, ease: "easeIn" },
};It sinks toward the middle of what’s on screen, not the middle of the page. Halfway down a long page, the middle of the page is somewhere far below you, and the page would drift away sideways instead of falling back.
04 · Measuring
The page describes itself
There’s no wireframe drawn for each page. Each page marks its own parts instead: the area the sketch sits on, each block that reveals as one piece with its place in the order, and the kind of text inside it.
<Reveal
as="p"
index={0}
data-wf="block"
data-wf-index={0}
data-wf-label="copy 01"
data-wf-text="meta"The page is measured after it has loaded but before it’s shown, so every box is where it really is, at this screen size, with this text. Two things make that harder than it sounds. The blocks are waiting to reveal, zoomed in and blurred, and the portrait is tilted; measured as they are, the boxes would come out too big. So each block’s size is read from the layout, and only its centre from the screen.
// Measure the block untransformed: a reveal may start zoomed in, and the
// portrait is tilted. Zooming and tilting keep the center, so take that from
// the box on screen and the size from the layout.
const box = toRect(el.getBoundingClientRect());
const cx = box.left + box.width / 2;
const cy = box.top + box.height / 2;
const width = el.offsetWidth || box.width;
const height = el.offsetHeight || box.height;
const rect = {
left: cx - width / 2,
top: cy - height / 2,
right: cx + width / 2,
bottom: cy + height / 2,
width,
height,
};
const rotate = Number(el.dataset.wfRotate) || 0;And text is drawn as one scribble per rendered line, so a paragraph’s sketch has as many lines as the paragraph has on your screen. The browser already knows where each line breaks; it just has to be asked.
The page
Each line of text becomes one scribble. The browser already knows where every line breaks: a range over the text gives one box per piece of a line, and the pieces that share a line are joined into one.
Its sketch
/** One entry per rendered line of `el`'s text: { left, right, mid, height } */
function textLines(el, toRect) {
const range = document.createRange();
range.selectNodeContents(el);
const fragments = [...range.getClientRects()]
.map(toRect)
.filter((r) => r.width > 1 && r.height > 1);
// Spans and wrapped text give several fragments per line: merge those that share a line
const lines = [];
for (const r of fragments) {
const mid = r.top + r.height / 2;
const line = lines.find((l) => Math.abs(l.mid - mid) < Math.min(l.height, r.height) * 0.5);
if (line) {
line.left = Math.min(line.left, r.left);
line.right = Math.max(line.right, r.right);
line.height = Math.max(line.height, r.height);
} else {
lines.push({ left: r.left, right: r.right, mid, height: r.height });
}
}
return lines;
}Only what’s on screen is sketched, plus a sliver past the bottom edge so the cut is never seen. A long page would otherwise spend its two seconds drawing boxes nobody sees.
05 · The sketch
Graphite, never bright
The sketch is drawn the way a quick wireframe is: the paper first, with a faint grid and its width marked; then each block as a box traced twice and lightly hatched, with a handwritten tag; titles as heavy scribbles, body text lighter, labels lighter still; images as a box crossed corner to corner. On the home page the navbar is roughed in too, with guides around the logo, the islands and the music, and the music staff ruled where it plays.
Every sketch takes the same two seconds, however many blocks the page has (one second between details, as the next section shows): the time is divided between them. Then a quarter-second pause to take it in, and the build starts. Each box fades as its block blurs in, and the paper goes last.
06 · Again and again
Quicker the fifth time
The full change takes about six seconds: a second and a half to sink, two to sketch, a pause, then the build. Opening the home page or a case study, that’s the point; it’s the site saying what it is. But moving from detail to detail in this case studook, you make the same change again and again, and by the fifth time it was a wait, not a welcome.
So between two details it runs quicker, and its beats overlap instead of queueing. The route changes the moment you click. The old content can’t sink away while the new content takes its place, so a frozen copy of it does the sinking. It dips back at once, so the click is felt, and waits there. The moment the new content is in and measured, the copy sinks away and the sketch draws over it, together, however long the new page took to arrive. The sketch takes one second instead of two, and the build starts the moment it’s done, at the brisk pace the résumé’s flight uses. The list of details beside it stays put the whole time, its box gliding to the new row.

// Within a shell (detail → detail), a change made again and again: the same
// idea, quicker. The route changes at the click; a frozen copy of the old
// content sinks away as the new content's sketch draws, together, and the new
// content builds in as soon as the sketch is done, at the brisk pace.
const QUICK_SKETCH = 1; // s
const QUICK_LEAVE = {
scale: { duration: 0.45, ease: [0.4, 0, 0.2, 1] },
filter: { duration: 0.45, ease: [0.5, 0, 0.75, 0] },
opacity: { duration: 0.45, ease: "easeIn" },
};It’s the same idea at a different pace: still a sketch, still built in reading order, just not making you wait for it. The full version stays where it’s rare and it matters, between the sections of the site.
07 · Decisions
Why it’s built this way
Measured, not drawn
No page has a wireframe to keep up to date. Change the page, and its sketch changes with it, at every screen size.
The same two seconds
A page with three blocks and a page with twenty both sketch in two seconds. The rhythm of the site doesn’t depend on the page.
Only what you'll see
The sketch stops at the bottom of the screen. Drawing what’s below the fold would only make you wait.
Quiet pencil
Every stroke is faint white. The sketch is a promise of the page, never louder than the page itself.
Overlap, don't queue
For a change made again and again, the old page leaves while the new one is sketched. Same idea, less than half the wait.
08 · Takeaways
What to keep
- Let the page describe itself with a few marks, and measure it live: a sketch made from the real layout can’t go stale.
- Measure what the layout is, not what’s on screen mid-animation: take sizes from the layout and centres from the screen.
- Give every transition the same rhythm, whatever the page, and only draw what will be seen.
- Match the pace to how often it’s seen: a transition that welcomes you once shouldn’t make you wait the tenth time.
Back to the case study: watch its title, book and intro sketched in pencil before they build in.