From dd8497e09d882adde50236706a58c97a9124fdc5 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sat, 25 Apr 2026 20:21:01 -0400 Subject: [PATCH 01/19] Add See and Do pattern Closes #8 Co-Authored-By: Claude Opus 4.7 (1M context) --- src/assets/see_and_do_thumbnail.svg | 39 +++++++++++++++ src/patterns/see_and_do.md | 76 +++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/assets/see_and_do_thumbnail.svg create mode 100644 src/patterns/see_and_do.md diff --git a/src/assets/see_and_do_thumbnail.svg b/src/assets/see_and_do_thumbnail.svg new file mode 100644 index 0000000..24682c8 --- /dev/null +++ b/src/assets/see_and_do_thumbnail.svg @@ -0,0 +1,39 @@ + + + Visible should mean usable + + + Page paint timeline + + + + + + paint + long task + paint + long task + idle + + + + + SEE + page is painted + + + + + + + + Click me + DO + page should respond + + + ! + but... + JS blocking + + diff --git a/src/patterns/see_and_do.md b/src/patterns/see_and_do.md new file mode 100644 index 0000000..65c21b6 --- /dev/null +++ b/src/patterns/see_and_do.md @@ -0,0 +1,76 @@ +--- +layout: article.njk +title: See and Do +tags: pattern +thumbnail: /assets/see_and_do_thumbnail.svg +og_image: /assets/speed_patterns_og_image.jpg +order: 10 +--- + +When a user can see a button, they assume they can press it. When they can read a form field, they assume they can type into it. The mental model is simple: visible means usable. The web routinely violates this assumption — JavaScript is still parsing, hydrating, or executing long tasks during the seconds after first paint, and the page sits there looking interactive while not actually responding to input. + + + +## The Problem + +Modern web apps frequently have a window — sometimes a few hundred milliseconds, sometimes several seconds — between when content becomes visible and when the page is actually ready to handle interaction. During that window: + +- Clicks may be silently dropped because no event listener is attached yet. +- Inputs may register keystrokes but not validate, autocomplete, or submit. +- Long tasks on the main thread (script evaluation, framework hydration, expensive layout) block the event loop, so even queued events sit waiting. + +The user's experience is "I tapped the button and nothing happened." From their perspective, the site is broken. From the dev tools' perspective, the page is "loaded" — the metric just doesn't match the experience. + +## Solution + +Treat _interactivity_ as part of the loading experience, not a separate concern. The goal is to close the gap between "the user can see it" and "the user can use it" — ideally to zero. + +### 1. Measure the right thing + +Time-to-paint metrics like First Contentful Paint and Largest Contentful Paint don't tell you whether the page is responsive. The metrics that do: + +- **Interaction to Next Paint (INP)** — measures the latency of real user interactions. A page with bad INP looks fast and feels broken. +- **Total Blocking Time (TBT)** — sums up the time the main thread is blocked by long tasks during load. +- **Long Tasks API** — surfaces individual tasks longer than 50ms that prevent the page from responding to input. ([Long Tasks spec](https://www.w3.org/TR/longtasks/)) +- **Time to Interactive (TTI)** — when the page has been visually ready and the main thread has stayed quiet long enough to handle input. + +Watch INP and TBT in real-user monitoring, not just lab tests — the lab can hide problems that real devices and real interaction patterns expose. + +### 2. Don't render UI you can't yet operate + +If a control isn't ready to do its job, don't show it as if it were. Options: + +- **Render the control disabled** until its handler is wired up. The user can see it but visibly cannot use it yet — that mismatch is honest. +- **Defer the entire feature** behind a placeholder, and swap it in only when its code is loaded. This is the [Convert on Arrival](/patterns/convert_on_arrival/) pattern. +- **Server-render the form action** so a submit during the gap still works — the page progressively enhances rather than depending on JS for basic function. + +### 3. Break up long tasks + +The main thread is a single lane. While it's busy compiling a 400KB framework bundle or hydrating a thousand components, every user input is queued behind that work. + +- **Split work into smaller chunks** using `requestIdleCallback`, `scheduler.postTask`, or simple `setTimeout(0)` yields. +- **Defer non-critical scripts** with `async`, `defer`, or dynamic imports gated by interaction. +- **Avoid re-hydrating already-rendered server HTML** when possible — emerging patterns like resumability, islands, and selective hydration target exactly this cost. +- **Audit third-party scripts.** Tag managers, analytics, A/B testing libraries and chat widgets are common sources of long tasks that block the page during the most visible part of load. + +### 4. Make critical input paths cheap + +Even when the rest of the page is busy, the path that handles "click the most important button on this view" should be reachable. If your hero CTA depends on a 200KB JS bundle that's still parsing, that's a design choice — usually the wrong one. + +## Why This Matters + +A site that scores well on paint metrics but fails on interactivity feels worse than one that paints a bit slower but is responsive from the moment things appear. Users don't measure performance in milliseconds — they measure it in trust. Every dropped click chips away at that trust. + +The "see and do" gap is also one of the easiest performance problems to overlook because most automated checks don't surface it. Watching INP, splitting long tasks, and resisting the urge to ship visually-finished but functionally-incomplete UI keeps the experience honest. + +## Related Patterns + +- [Acknowledge Actions](/patterns/acknowledge_actions/) — what to do once interaction is ready. +- [Convert on Arrival](/patterns/convert_on_arrival/) — staging interactivity progressively. +- [Skeletal Designs](/patterns/skeletal_designs/) — placeholders for content that isn't ready yet. + +## Resources + +- [Long Tasks API specification](https://www.w3.org/TR/longtasks/) +- [Interaction to Next Paint (INP) on web.dev](https://web.dev/articles/inp) +- [Total Blocking Time (TBT) on web.dev](https://web.dev/articles/tbt) From d2f6f262e4acd0baaafab4c92d456eed295e2bb9 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 12:26:00 -0400 Subject: [PATCH 02/19] Move technical implementation details to the end of the article --- src/patterns/see_and_do.md | 50 ++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/patterns/see_and_do.md b/src/patterns/see_and_do.md index 65c21b6..4065d69 100644 --- a/src/patterns/see_and_do.md +++ b/src/patterns/see_and_do.md @@ -25,43 +25,27 @@ The user's experience is "I tapped the button and nothing happened." From their Treat _interactivity_ as part of the loading experience, not a separate concern. The goal is to close the gap between "the user can see it" and "the user can use it" — ideally to zero. -### 1. Measure the right thing - -Time-to-paint metrics like First Contentful Paint and Largest Contentful Paint don't tell you whether the page is responsive. The metrics that do: - -- **Interaction to Next Paint (INP)** — measures the latency of real user interactions. A page with bad INP looks fast and feels broken. -- **Total Blocking Time (TBT)** — sums up the time the main thread is blocked by long tasks during load. -- **Long Tasks API** — surfaces individual tasks longer than 50ms that prevent the page from responding to input. ([Long Tasks spec](https://www.w3.org/TR/longtasks/)) -- **Time to Interactive (TTI)** — when the page has been visually ready and the main thread has stayed quiet long enough to handle input. - -Watch INP and TBT in real-user monitoring, not just lab tests — the lab can hide problems that real devices and real interaction patterns expose. - -### 2. Don't render UI you can't yet operate +### Don't render UI you can't yet operate If a control isn't ready to do its job, don't show it as if it were. Options: - **Render the control disabled** until its handler is wired up. The user can see it but visibly cannot use it yet — that mismatch is honest. - **Defer the entire feature** behind a placeholder, and swap it in only when its code is loaded. This is the [Convert on Arrival](/patterns/convert_on_arrival/) pattern. -- **Server-render the form action** so a submit during the gap still works — the page progressively enhances rather than depending on JS for basic function. - -### 3. Break up long tasks +- **Keep the form action working without JavaScript** so a submit during the gap still works — the page progressively enhances rather than depending on scripts for basic function. -The main thread is a single lane. While it's busy compiling a 400KB framework bundle or hydrating a thousand components, every user input is queued behind that work. +### Make critical input paths cheap -- **Split work into smaller chunks** using `requestIdleCallback`, `scheduler.postTask`, or simple `setTimeout(0)` yields. -- **Defer non-critical scripts** with `async`, `defer`, or dynamic imports gated by interaction. -- **Avoid re-hydrating already-rendered server HTML** when possible — emerging patterns like resumability, islands, and selective hydration target exactly this cost. -- **Audit third-party scripts.** Tag managers, analytics, A/B testing libraries and chat widgets are common sources of long tasks that block the page during the most visible part of load. +Even when the rest of the page is busy, the path that handles "click the most important button on this view" should be reachable. If your hero CTA depends on a 200KB bundle that's still parsing, that's a design choice — usually the wrong one. Treat the most important interactions on each page as a budget: their handlers must be ready by the time the user can see them. -### 4. Make critical input paths cheap +### Watch the right thing -Even when the rest of the page is busy, the path that handles "click the most important button on this view" should be reachable. If your hero CTA depends on a 200KB JS bundle that's still parsing, that's a design choice — usually the wrong one. +Time-to-paint metrics don't tell you whether the page is responsive. Decisions need to be informed by interactivity metrics, not just paint metrics. Real-user monitoring (RUM) on responsiveness exposes problems that lab tests on fast hardware will hide. ## Why This Matters A site that scores well on paint metrics but fails on interactivity feels worse than one that paints a bit slower but is responsive from the moment things appear. Users don't measure performance in milliseconds — they measure it in trust. Every dropped click chips away at that trust. -The "see and do" gap is also one of the easiest performance problems to overlook because most automated checks don't surface it. Watching INP, splitting long tasks, and resisting the urge to ship visually-finished but functionally-incomplete UI keeps the experience honest. +The "see and do" gap is also one of the easiest performance problems to overlook because most automated checks don't surface it. Closing the gap means resisting the urge to ship visually-finished but functionally-incomplete UI. ## Related Patterns @@ -69,6 +53,26 @@ The "see and do" gap is also one of the easiest performance problems to overlook - [Convert on Arrival](/patterns/convert_on_arrival/) — staging interactivity progressively. - [Skeletal Designs](/patterns/skeletal_designs/) — placeholders for content that isn't ready yet. +## Technical Implementation + +### Metrics to watch + +- **Interaction to Next Paint (INP)** — measures the latency of real user interactions. A page with bad INP looks fast and feels broken. +- **Total Blocking Time (TBT)** — sums up the time the main thread is blocked by long tasks during load. +- **Long Tasks API** — surfaces individual tasks longer than 50ms that prevent the page from responding to input. ([Long Tasks spec](https://www.w3.org/TR/longtasks/)) +- **Time to Interactive (TTI)** — when the page has been visually ready and the main thread has stayed quiet long enough to handle input. + +Watch INP and TBT in real-user monitoring, not just lab tests — the lab can hide problems that real devices and real interaction patterns expose. + +### Breaking up long tasks + +The main thread is a single lane. While it's busy compiling a 400KB framework bundle or hydrating a thousand components, every user input is queued behind that work. + +- **Split work into smaller chunks** using `requestIdleCallback`, `scheduler.postTask`, or simple `setTimeout(0)` yields. +- **Defer non-critical scripts** with `async`, `defer`, or dynamic imports gated by interaction. +- **Avoid re-hydrating already-rendered server HTML** when possible — emerging patterns like resumability, islands, and selective hydration target exactly this cost. +- **Audit third-party scripts.** Tag managers, analytics, A/B testing libraries and chat widgets are common sources of long tasks that block the page during the most visible part of load. + ## Resources - [Long Tasks API specification](https://www.w3.org/TR/longtasks/) From afaaeb6c36ae676676a381789f66904c7414b2ae Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 12:37:52 -0400 Subject: [PATCH 03/19] Drop trailing periods from list items --- src/patterns/see_and_do.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/patterns/see_and_do.md b/src/patterns/see_and_do.md index 4065d69..44d83fe 100644 --- a/src/patterns/see_and_do.md +++ b/src/patterns/see_and_do.md @@ -15,9 +15,9 @@ When a user can see a button, they assume they can press it. When they can read Modern web apps frequently have a window — sometimes a few hundred milliseconds, sometimes several seconds — between when content becomes visible and when the page is actually ready to handle interaction. During that window: -- Clicks may be silently dropped because no event listener is attached yet. -- Inputs may register keystrokes but not validate, autocomplete, or submit. -- Long tasks on the main thread (script evaluation, framework hydration, expensive layout) block the event loop, so even queued events sit waiting. +- Clicks may be silently dropped because no event listener is attached yet +- Inputs may register keystrokes but not validate, autocomplete, or submit +- Long tasks on the main thread (script evaluation, framework hydration, expensive layout) block the event loop, so even queued events sit waiting The user's experience is "I tapped the button and nothing happened." From their perspective, the site is broken. From the dev tools' perspective, the page is "loaded" — the metric just doesn't match the experience. @@ -29,9 +29,9 @@ Treat _interactivity_ as part of the loading experience, not a separate concern. If a control isn't ready to do its job, don't show it as if it were. Options: -- **Render the control disabled** until its handler is wired up. The user can see it but visibly cannot use it yet — that mismatch is honest. -- **Defer the entire feature** behind a placeholder, and swap it in only when its code is loaded. This is the [Convert on Arrival](/patterns/convert_on_arrival/) pattern. -- **Keep the form action working without JavaScript** so a submit during the gap still works — the page progressively enhances rather than depending on scripts for basic function. +- **Render the control disabled** until its handler is wired up. The user can see it but visibly cannot use it yet — that mismatch is honest +- **Defer the entire feature** behind a placeholder, and swap it in only when its code is loaded. This is the [Convert on Arrival](/patterns/convert_on_arrival/) pattern +- **Keep the form action working without JavaScript** so a submit during the gap still works — the page progressively enhances rather than depending on scripts for basic function ### Make critical input paths cheap @@ -49,18 +49,18 @@ The "see and do" gap is also one of the easiest performance problems to overlook ## Related Patterns -- [Acknowledge Actions](/patterns/acknowledge_actions/) — what to do once interaction is ready. -- [Convert on Arrival](/patterns/convert_on_arrival/) — staging interactivity progressively. -- [Skeletal Designs](/patterns/skeletal_designs/) — placeholders for content that isn't ready yet. +- [Acknowledge Actions](/patterns/acknowledge_actions/) — what to do once interaction is ready +- [Convert on Arrival](/patterns/convert_on_arrival/) — staging interactivity progressively +- [Skeletal Designs](/patterns/skeletal_designs/) — placeholders for content that isn't ready yet ## Technical Implementation ### Metrics to watch -- **Interaction to Next Paint (INP)** — measures the latency of real user interactions. A page with bad INP looks fast and feels broken. -- **Total Blocking Time (TBT)** — sums up the time the main thread is blocked by long tasks during load. +- **Interaction to Next Paint (INP)** — measures the latency of real user interactions. A page with bad INP looks fast and feels broken +- **Total Blocking Time (TBT)** — sums up the time the main thread is blocked by long tasks during load - **Long Tasks API** — surfaces individual tasks longer than 50ms that prevent the page from responding to input. ([Long Tasks spec](https://www.w3.org/TR/longtasks/)) -- **Time to Interactive (TTI)** — when the page has been visually ready and the main thread has stayed quiet long enough to handle input. +- **Time to Interactive (TTI)** — when the page has been visually ready and the main thread has stayed quiet long enough to handle input Watch INP and TBT in real-user monitoring, not just lab tests — the lab can hide problems that real devices and real interaction patterns expose. @@ -68,10 +68,10 @@ Watch INP and TBT in real-user monitoring, not just lab tests — the lab can hi The main thread is a single lane. While it's busy compiling a 400KB framework bundle or hydrating a thousand components, every user input is queued behind that work. -- **Split work into smaller chunks** using `requestIdleCallback`, `scheduler.postTask`, or simple `setTimeout(0)` yields. -- **Defer non-critical scripts** with `async`, `defer`, or dynamic imports gated by interaction. -- **Avoid re-hydrating already-rendered server HTML** when possible — emerging patterns like resumability, islands, and selective hydration target exactly this cost. -- **Audit third-party scripts.** Tag managers, analytics, A/B testing libraries and chat widgets are common sources of long tasks that block the page during the most visible part of load. +- **Split work into smaller chunks** using `requestIdleCallback`, `scheduler.postTask`, or simple `setTimeout(0)` yields +- **Defer non-critical scripts** with `async`, `defer`, or dynamic imports gated by interaction +- **Avoid re-hydrating already-rendered server HTML** when possible — emerging patterns like resumability, islands, and selective hydration target exactly this cost +- **Audit third-party scripts.** Tag managers, analytics, A/B testing libraries and chat widgets are common sources of long tasks that block the page during the most visible part of load ## Resources From e80e34875d2543650a87dfc4da18c04e0cff9f15 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 13:12:57 -0400 Subject: [PATCH 04/19] Redraw thumbnail to follow canonical diagram theme --- src/assets/see_and_do_thumbnail.svg | 62 ++++++++++++++--------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/assets/see_and_do_thumbnail.svg b/src/assets/see_and_do_thumbnail.svg index 24682c8..f6dc62b 100644 --- a/src/assets/see_and_do_thumbnail.svg +++ b/src/assets/see_and_do_thumbnail.svg @@ -1,39 +1,39 @@ - - Visible should mean usable - - - Page paint timeline - - - - - - paint - long task - paint - long task - idle + + Visible should mean usable + + + Page paint timeline + + + + + + paint + long task + paint + long task + idle - - - SEE - page is painted + + + SEE + page is painted - - - + + - - - Click me - DO - page should respond + + + + Click me + DO + page should respond - - ! - but... - JS blocking + + ! + but... + JS blocking From 74c06321838bec461db3cb2d1a91cae5ad15905c Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 13:15:48 -0400 Subject: [PATCH 05/19] Embed thumbnail illustration after the Problem section --- src/patterns/see_and_do.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/patterns/see_and_do.md b/src/patterns/see_and_do.md index 44d83fe..2c3d418 100644 --- a/src/patterns/see_and_do.md +++ b/src/patterns/see_and_do.md @@ -21,6 +21,11 @@ Modern web apps frequently have a window — sometimes a few hundred millisecond The user's experience is "I tapped the button and nothing happened." From their perspective, the site is broken. From the dev tools' perspective, the page is "loaded" — the metric just doesn't match the experience. +
+
The user can see the page and the button (SEE), but a long task on the main thread is still blocking input — the click goes nowhere (DO).
+A page paint timeline showing alternating paint and long-task blocks; below it a circle marked SEE next to a button marked DO connected by a blue arrow, with a red exclamation mark indicating that JavaScript is blocking the click +
+ ## Solution Treat _interactivity_ as part of the loading experience, not a separate concern. The goal is to close the gap between "the user can see it" and "the user can use it" — ideally to zero. From 4750b69f623841bbac5dc2f20234f988b31e1465 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 13:26:40 -0400 Subject: [PATCH 06/19] Move SVG title text to figcaption; description becomes paragraph --- src/assets/see_and_do_thumbnail.svg | 3 +-- src/patterns/see_and_do.md | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/assets/see_and_do_thumbnail.svg b/src/assets/see_and_do_thumbnail.svg index f6dc62b..0bf2738 100644 --- a/src/assets/see_and_do_thumbnail.svg +++ b/src/assets/see_and_do_thumbnail.svg @@ -1,6 +1,5 @@ - + - Visible should mean usable Page paint timeline diff --git a/src/patterns/see_and_do.md b/src/patterns/see_and_do.md index 2c3d418..01544c8 100644 --- a/src/patterns/see_and_do.md +++ b/src/patterns/see_and_do.md @@ -21,8 +21,10 @@ Modern web apps frequently have a window — sometimes a few hundred millisecond The user's experience is "I tapped the button and nothing happened." From their perspective, the site is broken. From the dev tools' perspective, the page is "loaded" — the metric just doesn't match the experience. +The user can see the page and the button (SEE), but a long task on the main thread is still blocking input — the click goes nowhere (DO). +
-
The user can see the page and the button (SEE), but a long task on the main thread is still blocking input — the click goes nowhere (DO).
+
Visible should mean usable
A page paint timeline showing alternating paint and long-task blocks; below it a circle marked SEE next to a button marked DO connected by a blue arrow, with a red exclamation mark indicating that JavaScript is blocking the click From 24bc903e78c90686baa00cf20f3ff8103d246cd5 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 13:37:06 -0400 Subject: [PATCH 07/19] Move figcaption below the image --- src/patterns/see_and_do.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/patterns/see_and_do.md b/src/patterns/see_and_do.md index 01544c8..41c54e1 100644 --- a/src/patterns/see_and_do.md +++ b/src/patterns/see_and_do.md @@ -24,8 +24,8 @@ The user's experience is "I tapped the button and nothing happened." From their The user can see the page and the button (SEE), but a long task on the main thread is still blocking input — the click goes nowhere (DO).
-
Visible should mean usable
A page paint timeline showing alternating paint and long-task blocks; below it a circle marked SEE next to a button marked DO connected by a blue arrow, with a red exclamation mark indicating that JavaScript is blocking the click +
Visible should mean usable
## Solution From 44657a9f8d3053e26f86b05ea116564ae803a5e3 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 13:41:23 -0400 Subject: [PATCH 08/19] Move page paint timeline to the bottom of the illustration --- src/assets/see_and_do_thumbnail.svg | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/assets/see_and_do_thumbnail.svg b/src/assets/see_and_do_thumbnail.svg index 0bf2738..2cb7a3d 100644 --- a/src/assets/see_and_do_thumbnail.svg +++ b/src/assets/see_and_do_thumbnail.svg @@ -1,38 +1,38 @@ - - Page paint timeline - - - - - - paint - long task - paint - long task - idle - - SEE page is painted - + - - + + Click me DO page should respond - + ! but... JS blocking + + + Page paint timeline + + + + + + paint + long task + paint + long task + idle + From 80da838c84a2d49bba76b3287d8c6b390b0674ad Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 14:02:36 -0400 Subject: [PATCH 09/19] Use white-with-border boxes; tint long-task blocks with low-opacity red --- src/assets/see_and_do_thumbnail.svg | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/assets/see_and_do_thumbnail.svg b/src/assets/see_and_do_thumbnail.svg index 2cb7a3d..8af14b4 100644 --- a/src/assets/see_and_do_thumbnail.svg +++ b/src/assets/see_and_do_thumbnail.svg @@ -1,7 +1,7 @@ - + SEE page is painted @@ -11,7 +11,7 @@ - + Click me DO page should respond @@ -24,11 +24,11 @@ Page paint timeline - - - - - + + + + + paint long task paint From 5e1ae2ff13f08a7e6c66b63d4f7955bc0cca0cac Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 14:05:23 -0400 Subject: [PATCH 10/19] Color timeline blocks like Chrome DevTools (purple paint, red long tasks) --- src/assets/see_and_do_thumbnail.svg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/assets/see_and_do_thumbnail.svg b/src/assets/see_and_do_thumbnail.svg index 8af14b4..08d28eb 100644 --- a/src/assets/see_and_do_thumbnail.svg +++ b/src/assets/see_and_do_thumbnail.svg @@ -24,10 +24,10 @@ Page paint timeline - - - - + + + + paint long task From 2791cfc4a111d1016236d3fcb4ec4bda01e4452a Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 14:09:54 -0400 Subject: [PATCH 11/19] Increase illustration size by 15% (400 -> 460) --- src/patterns/see_and_do.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/patterns/see_and_do.md b/src/patterns/see_and_do.md index 41c54e1..c4b7585 100644 --- a/src/patterns/see_and_do.md +++ b/src/patterns/see_and_do.md @@ -24,7 +24,7 @@ The user's experience is "I tapped the button and nothing happened." From their The user can see the page and the button (SEE), but a long task on the main thread is still blocking input — the click goes nowhere (DO).
-
A page paint timeline showing alternating paint and long-task blocks; below it a circle marked SEE next to a button marked DO connected by a blue arrow, with a red exclamation mark indicating that JavaScript is blocking the click +A page paint timeline showing alternating paint and long-task blocks; below it a circle marked SEE next to a button marked DO connected by a blue arrow, with a red exclamation mark indicating that JavaScript is blocking the click
Visible should mean usable
From b78127a0731dbfef07ce6d5eb5a778f841e08004 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 14:22:43 -0400 Subject: [PATCH 12/19] Split timeline into Paint and JS rows with visible/interactive markers --- src/assets/see_and_do_thumbnail.svg | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/assets/see_and_do_thumbnail.svg b/src/assets/see_and_do_thumbnail.svg index 08d28eb..5c9beb9 100644 --- a/src/assets/see_and_do_thumbnail.svg +++ b/src/assets/see_and_do_thumbnail.svg @@ -22,17 +22,20 @@ JS blocking - - Page paint timeline - - - - - - paint - long task - paint - long task - idle + + Page paint timeline + Paint + + + + JS + + JS loading + + long task + + visible + + interactive From 518112cd0020a662d5d61410c567c787b5aee007 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 14:24:06 -0400 Subject: [PATCH 13/19] Clarify JS-blocking label to 'JS is late/blocking' --- src/assets/see_and_do_thumbnail.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/see_and_do_thumbnail.svg b/src/assets/see_and_do_thumbnail.svg index 5c9beb9..830c2fa 100644 --- a/src/assets/see_and_do_thumbnail.svg +++ b/src/assets/see_and_do_thumbnail.svg @@ -19,7 +19,7 @@ ! but... - JS blocking + JS is late/blocking From b128d2bc7f99bacfe37f711d1d6fd2fa258360c5 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 14:29:16 -0400 Subject: [PATCH 14/19] Replace extra paint blocks with single paint preceded by green CSS box --- src/assets/see_and_do_thumbnail.svg | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/assets/see_and_do_thumbnail.svg b/src/assets/see_and_do_thumbnail.svg index 830c2fa..cea50ae 100644 --- a/src/assets/see_and_do_thumbnail.svg +++ b/src/assets/see_and_do_thumbnail.svg @@ -25,16 +25,16 @@ Page paint timeline Paint - - - + + CSS + JS - JS loading + JS loading long task - - visible + + visible interactive From 662227f1cd2971b9f1a2fc609a1667c916407933 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 14:34:27 -0400 Subject: [PATCH 15/19] Polish See and Do illustration: native button styling, vertical centering, full-width timeline --- src/assets/see_and_do_thumbnail.svg | 46 ++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/assets/see_and_do_thumbnail.svg b/src/assets/see_and_do_thumbnail.svg index cea50ae..b144576 100644 --- a/src/assets/see_and_do_thumbnail.svg +++ b/src/assets/see_and_do_thumbnail.svg @@ -10,32 +10,32 @@ - - - Click me - DO - page should respond + + + Click me + DO + page should respond - + ! - but... - JS is late/blocking + but... + JS is late/blocking - - + + Page paint timeline - Paint - - CSS - - JS - - JS loading - - long task - - visible - - interactive + Paint + + CSS + + JS + + JS loading + + long task + + visible + + interactive From d8981c5f402cd018c22c8355be91f1878f5a675e Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 14:40:08 -0400 Subject: [PATCH 16/19] Equalize top/bottom padding inside timeline box --- src/assets/see_and_do_thumbnail.svg | 73 +++++++++++++++++------------ 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/src/assets/see_and_do_thumbnail.svg b/src/assets/see_and_do_thumbnail.svg index b144576..21d1d43 100644 --- a/src/assets/see_and_do_thumbnail.svg +++ b/src/assets/see_and_do_thumbnail.svg @@ -1,41 +1,54 @@ - + - - - SEE - page is painted + + + SEE + page is + painted - + - + - - Click me - DO - page should respond + + Click me + DO + page should + respond - ! - but... - JS is late/blocking + ! + but... + JS is + late/blocking - - Page paint timeline - Paint - - CSS - - JS - - JS loading - - long task - - visible - - interactive + + Page paint + timeline + Paint + + CSS + + JS + + JS + loading + + long task + + visible + + interactive - + \ No newline at end of file From 345df18b6bdc98e8dbc777fe38ab034f6c51f65c Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 14:43:35 -0400 Subject: [PATCH 17/19] Shift top half left by 15px to balance margins with timeline box --- src/assets/see_and_do_thumbnail.svg | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/assets/see_and_do_thumbnail.svg b/src/assets/see_and_do_thumbnail.svg index 21d1d43..d03675f 100644 --- a/src/assets/see_and_do_thumbnail.svg +++ b/src/assets/see_and_do_thumbnail.svg @@ -1,6 +1,6 @@ - + - + - - + + Click me @@ -21,7 +21,7 @@ page should respond - + ! Date: Sun, 26 Apr 2026 20:30:26 -0400 Subject: [PATCH 18/19] Add authors and creation date to See and Do Primary author taken from the original issue (#8) creator (Joseph Gannon / vanux); Sergey Chernyshev added as secondary author. Date is the issue creation date. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/patterns/see_and_do.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/patterns/see_and_do.md b/src/patterns/see_and_do.md index c4b7585..216bfd7 100644 --- a/src/patterns/see_and_do.md +++ b/src/patterns/see_and_do.md @@ -5,6 +5,12 @@ tags: pattern thumbnail: /assets/see_and_do_thumbnail.svg og_image: /assets/speed_patterns_og_image.jpg order: 10 +date: 2017-12-27 +authors: + - name: Joseph Gannon + url: https://www.linkedin.com/in/environmentalux/ + - name: Sergey Chernyshev + url: https://www.sergeychernyshev.com/ --- When a user can see a button, they assume they can press it. When they can read a form field, they assume they can type into it. The mental model is simple: visible means usable. The web routinely violates this assumption — JavaScript is still parsing, hydrating, or executing long tasks during the seconds after first paint, and the page sits there looking interactive while not actually responding to input. From 1b9d6dfe2bed268bf2cdfc8480a14d1499a85b65 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Sun, 26 Apr 2026 20:39:49 -0400 Subject: [PATCH 19/19] Mark See and Do as AI-assisted Co-Authored-By: Claude Opus 4.7 (1M context) --- src/patterns/see_and_do.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/patterns/see_and_do.md b/src/patterns/see_and_do.md index 216bfd7..207d787 100644 --- a/src/patterns/see_and_do.md +++ b/src/patterns/see_and_do.md @@ -5,6 +5,7 @@ tags: pattern thumbnail: /assets/see_and_do_thumbnail.svg og_image: /assets/speed_patterns_og_image.jpg order: 10 +ai_assisted: true date: 2017-12-27 authors: - name: Joseph Gannon