|
| 1 | +--- |
| 2 | +name: webperf-core-web-vitals |
| 3 | +description: Intelligent Core Web Vitals analysis with automated workflows and decision trees. Measures LCP, CLS, INP with guided debugging that automatically determines follow-up analysis based on results. Includes workflows for LCP deep dive (5 phases), CLS investigation (loading vs interaction), INP debugging (latency breakdown + attribution), and cross-skill integration with loading, interaction, and media skills. Use when the user asks about Core Web Vitals, LCP optimization, layout shifts, or interaction responsiveness. Compatible with Chrome DevTools MCP. |
| 4 | +--- |
| 5 | + |
| 6 | +# WebPerf: Core Web Vitals |
| 7 | + |
| 8 | +JavaScript snippets for measuring web performance in Chrome DevTools. Execute with `mcp__chrome-devtools__evaluate_script`, capture output with `mcp__chrome-devtools__get_console_message`. |
| 9 | + |
| 10 | +## Available Snippets |
| 11 | + |
| 12 | +| Snippet | Description | File | |
| 13 | +|---------|-------------|------| |
| 14 | +| Cumulative Layout Shift (CLS) | Quick check for Cumulative Layout Shift, a Core Web Vital that measures visual stability | scripts/CLS.js | |
| 15 | +| Interaction to Next Paint (INP) | Tracks Interaction to Next Paint, a Core Web Vital that measures responsiveness | scripts/INP.js | |
| 16 | +| LCP Image Entropy | Checks if images qualify as LCP candidates based on their entropy (bits per pixel) | scripts/LCP-Image-Entropy.js | |
| 17 | +| LCP Sub-Parts | Breaks down Largest Contentful Paint into its four phases to identify optimization opportunities | scripts/LCP-Sub-Parts.js | |
| 18 | +| LCP Trail | Tracks every LCP candidate element during page load and highlights each one with a distinct pastel-c | scripts/LCP-Trail.js | |
| 19 | +| LCP Video Candidate | Detects whether the LCP element is a <video> and audits the poster image configuration — the most co | scripts/LCP-Video-Candidate.js | |
| 20 | +| Largest Contentful Paint (LCP) | Quick check for Largest Contentful Paint, a Core Web Vital that measures loading performance | scripts/LCP.js | |
| 21 | + |
| 22 | +## Execution with Chrome DevTools MCP |
| 23 | + |
| 24 | +``` |
| 25 | +1. mcp__chrome-devtools__navigate_page → navigate to target URL |
| 26 | +2. mcp__chrome-devtools__evaluate_script → run snippet code (read from scripts/ file) |
| 27 | +3. mcp__chrome-devtools__get_console_message → capture console output |
| 28 | +4. Interpret results using thresholds below, provide recommendations |
| 29 | +``` |
| 30 | + |
| 31 | +## Common Workflows |
| 32 | + |
| 33 | +### Complete Core Web Vitals Audit |
| 34 | + |
| 35 | +When the user asks for a comprehensive Core Web Vitals analysis or "audit CWV": |
| 36 | + |
| 37 | +1. **LCP.js** - Measure Largest Contentful Paint |
| 38 | +2. **CLS.js** - Measure Cumulative Layout Shift |
| 39 | +3. **INP.js** - Measure Interaction to Next Paint |
| 40 | +4. **LCP-Sub-Parts.js** - Break down LCP timing phases |
| 41 | +5. **LCP-Trail.js** - Track LCP candidate evolution |
| 42 | + |
| 43 | +### LCP Deep Dive |
| 44 | + |
| 45 | +When LCP is slow or the user asks "debug LCP" or "why is LCP slow": |
| 46 | + |
| 47 | +1. **LCP.js** - Establish baseline LCP value |
| 48 | +2. **LCP-Sub-Parts.js** - Break down into TTFB, resource load, render delay |
| 49 | +3. **LCP-Trail.js** - Identify all LCP candidates and changes |
| 50 | +4. **LCP-Image-Entropy.js** - Check if LCP image has visual complexity issues |
| 51 | +5. **LCP-Video-Candidate.js** - Detect if LCP is a video (poster or video element) |
| 52 | + |
| 53 | +### CLS Investigation |
| 54 | + |
| 55 | +When layout shifts are detected or the user asks "debug CLS" or "layout shift issues": |
| 56 | + |
| 57 | +1. **CLS.js** - Measure overall CLS score |
| 58 | +2. **Layout-Shift-Loading-and-Interaction.js** (from Interaction skill) - Separate loading vs interaction shifts |
| 59 | +3. Cross-reference with **webperf-loading** skill: |
| 60 | + - Find-Above-The-Fold-Lazy-Loaded-Images.js (lazy images causing shifts) |
| 61 | + - Fonts-Preloaded-Loaded-and-used-above-the-fold.js (font swap causing shifts) |
| 62 | + |
| 63 | +### INP Debugging |
| 64 | + |
| 65 | +When interactions feel slow or the user asks "debug INP" or "slow interactions": |
| 66 | + |
| 67 | +1. **INP.js** - Measure overall INP value |
| 68 | +2. **Interactions.js** (from Interaction skill) - List all interactions with timing |
| 69 | +3. **Input-Latency-Breakdown.js** (from Interaction skill) - Break down input delay, processing, presentation |
| 70 | +4. **Long-Animation-Frames.js** (from Interaction skill) - Identify blocking animation frames |
| 71 | +5. **Long-Animation-Frames-Script-Attribution.js** (from Interaction skill) - Find scripts causing delays |
| 72 | + |
| 73 | +### Video as LCP Investigation |
| 74 | + |
| 75 | +When LCP is a video element (detected by LCP-Video-Candidate.js): |
| 76 | + |
| 77 | +1. **LCP-Video-Candidate.js** - Identify video as LCP candidate |
| 78 | +2. **Video-Element-Audit.js** (from Media skill) - Audit video loading strategy |
| 79 | +3. **LCP-Sub-Parts.js** - Analyze video loading phases |
| 80 | +4. Cross-reference with **webperf-loading** skill: |
| 81 | + - Resource-Hints-Validation.js (check for video preload) |
| 82 | + - Priority-Hints-Audit.js (check for fetchpriority on video) |
| 83 | + |
| 84 | +### Image as LCP Investigation |
| 85 | + |
| 86 | +When LCP is an image (most common case): |
| 87 | + |
| 88 | +1. **LCP.js** - Measure LCP timing |
| 89 | +2. **LCP-Sub-Parts.js** - Break down timing phases |
| 90 | +3. **LCP-Image-Entropy.js** - Analyze image complexity |
| 91 | +4. Cross-reference with **webperf-media** skill: |
| 92 | + - Image-Element-Audit.js (check format, dimensions, lazy loading) |
| 93 | +5. Cross-reference with **webperf-loading** skill: |
| 94 | + - Find-Above-The-Fold-Lazy-Loaded-Images.js (check if incorrectly lazy) |
| 95 | + - Priority-Hints-Audit.js (check for fetchpriority="high") |
| 96 | + - Resource-Hints-Validation.js (check for preload) |
| 97 | + |
| 98 | +## Decision Tree |
| 99 | + |
| 100 | +Use this decision tree to automatically run follow-up snippets based on results: |
| 101 | + |
| 102 | +### After LCP.js |
| 103 | + |
| 104 | +- **If LCP > 2.5s** → Run **LCP-Sub-Parts.js** to diagnose which phase is slow |
| 105 | +- **If LCP > 4.0s (poor)** → Run full LCP deep dive workflow (5 snippets) |
| 106 | +- **If LCP candidate is an image** → Run **LCP-Image-Entropy.js** and **webperf-media:Image-Element-Audit.js** |
| 107 | +- **If LCP candidate is a video** → Run **LCP-Video-Candidate.js** and **webperf-media:Video-Element-Audit.js** |
| 108 | +- **Always run** → **LCP-Trail.js** to understand candidate evolution |
| 109 | + |
| 110 | +### After LCP-Sub-Parts.js |
| 111 | + |
| 112 | +- **If TTFB phase > 600ms** → Switch to **webperf-loading** skill and run TTFB-Sub-Parts.js |
| 113 | +- **If Resource Load Time > 1500ms** → Run: |
| 114 | + 1. **webperf-loading:Resource-Hints-Validation.js** (check for preload/preconnect) |
| 115 | + 2. **webperf-loading:Priority-Hints-Audit.js** (check fetchpriority) |
| 116 | + 3. **webperf-loading:Find-render-blocking-resources.js** (competing resources) |
| 117 | +- **If Render Delay > 200ms** → Run: |
| 118 | + 1. **webperf-loading:Find-render-blocking-resources.js** (blocking CSS/JS) |
| 119 | + 2. **webperf-loading:Script-Loading.js** (parser-blocking scripts) |
| 120 | + 3. **webperf-interaction:Long-Animation-Frames.js** (main thread blocking) |
| 121 | + |
| 122 | +### After LCP-Trail.js |
| 123 | + |
| 124 | +- **If many LCP candidate changes (>3)** → This causes visual instability, investigate: |
| 125 | + 1. **webperf-loading:Find-Above-The-Fold-Lazy-Loaded-Images.js** (late-loading images) |
| 126 | + 2. **webperf-loading:Fonts-Preloaded-Loaded-and-used-above-the-fold.js** (font swaps) |
| 127 | + 3. **CLS.js** (layout shifts contributing to LCP changes) |
| 128 | +- **If final LCP candidate appears late** → Run **webperf-loading:Resource-Hints-Validation.js** |
| 129 | +- **If early candidate was replaced** → Understand why initial content was pushed down (likely CLS issue) |
| 130 | + |
| 131 | +### After LCP-Image-Entropy.js |
| 132 | + |
| 133 | +- **If entropy is very high** → Image is visually complex, recommend: |
| 134 | + - Modern formats (WebP, AVIF) |
| 135 | + - Appropriate compression |
| 136 | + - Potentially a placeholder strategy |
| 137 | +- **If entropy is low** → Image may be over-optimized or placeholder-like |
| 138 | +- **If large file size detected** → Run **webperf-media:Image-Element-Audit.js** for format/sizing analysis |
| 139 | + |
| 140 | +### After LCP-Video-Candidate.js |
| 141 | + |
| 142 | +- **If video is LCP** → Run: |
| 143 | + 1. **webperf-media:Video-Element-Audit.js** (check poster, preload, formats) |
| 144 | + 2. **webperf-loading:Priority-Hints-Audit.js** (check fetchpriority on poster) |
| 145 | + 3. **LCP-Sub-Parts.js** (analyze video loading phases) |
| 146 | +- **If poster image is LCP** → Treat as image LCP (run image workflows) |
| 147 | + |
| 148 | +### After CLS.js |
| 149 | + |
| 150 | +- **If CLS > 0.1** → Run **webperf-interaction:Layout-Shift-Loading-and-Interaction.js** to separate causes |
| 151 | +- **If CLS > 0.25 (poor)** → Run comprehensive shift investigation: |
| 152 | + 1. **webperf-loading:Find-Above-The-Fold-Lazy-Loaded-Images.js** (images without dimensions) |
| 153 | + 2. **webperf-loading:Fonts-Preloaded-Loaded-and-used-above-the-fold.js** (font loading strategy) |
| 154 | + 3. **webperf-loading:Critical-CSS-Detection.js** (late-loading styles) |
| 155 | + 4. **webperf-media:Image-Element-Audit.js** (missing width/height) |
| 156 | +- **If CLS = 0** → Confirm with multiple page loads (might be timing-dependent) |
| 157 | + |
| 158 | +### After INP.js |
| 159 | + |
| 160 | +- **If INP > 200ms** → Run **webperf-interaction:Interactions.js** to identify slow interactions |
| 161 | +- **If INP > 500ms (poor)** → Run full INP debugging workflow: |
| 162 | + 1. **webperf-interaction:Interactions.js** (list all interactions) |
| 163 | + 2. **webperf-interaction:Input-Latency-Breakdown.js** (phase breakdown) |
| 164 | + 3. **webperf-interaction:Long-Animation-Frames.js** (blocking frames) |
| 165 | + 4. **webperf-interaction:Long-Animation-Frames-Script-Attribution.js** (culprit scripts) |
| 166 | +- **If specific interaction type is slow (e.g., keyboard)** → Focus analysis on that interaction type |
| 167 | + |
| 168 | +### Cross-Skill Triggers |
| 169 | + |
| 170 | +These triggers recommend using snippets from other skills: |
| 171 | + |
| 172 | +#### From LCP to Loading Skill |
| 173 | + |
| 174 | +- **If LCP > 2.5s and TTFB phase is dominant** → Use **webperf-loading** skill: |
| 175 | + - TTFB.js, TTFB-Sub-Parts.js, Service-Worker-Analysis.js |
| 176 | + |
| 177 | +- **If LCP image is lazy-loaded** → Use **webperf-loading** skill: |
| 178 | + - Find-Above-The-Fold-Lazy-Loaded-Images.js |
| 179 | + |
| 180 | +- **If LCP has no fetchpriority** → Use **webperf-loading** skill: |
| 181 | + - Priority-Hints-Audit.js |
| 182 | + |
| 183 | +#### From CLS to Loading Skill |
| 184 | + |
| 185 | +- **If CLS caused by fonts** → Use **webperf-loading** skill: |
| 186 | + - Fonts-Preloaded-Loaded-and-used-above-the-fold.js |
| 187 | + - Resource-Hints-Validation.js (for font preload) |
| 188 | + |
| 189 | +- **If CLS caused by images** → Use **webperf-media** skill: |
| 190 | + - Image-Element-Audit.js (check for width/height attributes) |
| 191 | + |
| 192 | +#### From INP to Interaction Skill |
| 193 | + |
| 194 | +- **If INP > 200ms** → Use **webperf-interaction** skill for full debugging: |
| 195 | + - Interactions.js, Input-Latency-Breakdown.js |
| 196 | + - Long-Animation-Frames.js, Long-Animation-Frames-Script-Attribution.js |
| 197 | + - LongTask.js (if pre-interaction blocking suspected) |
| 198 | + |
| 199 | +#### From LCP/INP to Interaction Skill |
| 200 | + |
| 201 | +- **If render delay or interaction delay is high** → Use **webperf-interaction** skill: |
| 202 | + - Long-Animation-Frames.js (main thread blocking) |
| 203 | + - LongTask.js (long tasks delaying rendering) |
| 204 | + |
| 205 | +### Multi-Metric Correlation |
| 206 | + |
| 207 | +When multiple CWV metrics are poor, prioritize investigation: |
| 208 | + |
| 209 | +- **If LCP > 2.5s AND CLS > 0.1** → Likely shared root cause: |
| 210 | + 1. Check for late-loading content pushing LCP element |
| 211 | + 2. Run LCP-Trail.js to see LCP candidate changes |
| 212 | + 3. Run Layout-Shift-Loading-and-Interaction.js to correlate timing |
| 213 | + |
| 214 | +- **If LCP > 2.5s AND INP > 200ms** → Main thread congestion: |
| 215 | + 1. Run Long-Animation-Frames.js |
| 216 | + 2. Run webperf-loading:Script-Loading.js |
| 217 | + 3. Run webperf-loading:JS-Execution-Time-Breakdown.js |
| 218 | + |
| 219 | +- **If CLS > 0.1 AND INP > 200ms** → Layout thrashing or interaction-triggered shifts: |
| 220 | + 1. Run Layout-Shift-Loading-and-Interaction.js |
| 221 | + 2. Run Interactions.js |
| 222 | + 3. Check if shifts occur during/after interactions |
| 223 | + |
| 224 | +--- |
| 225 | + |
| 226 | +--- |
| 227 | + |
| 228 | +## Cumulative Layout Shift (CLS) |
| 229 | + |
| 230 | +Quick check for Cumulative Layout Shift, a Core Web Vital that measures visual stability. CLS tracks how much the page layout shifts unexpectedly during its lifetime, providing a single score that represents the cumulative impact of all unexpected layout shifts. |
| 231 | + |
| 232 | +**Script:** `scripts/CLS.js` |
| 233 | + |
| 234 | +**Thresholds:** |
| 235 | + |
| 236 | +| Rating | Score | Meaning | |
| 237 | +|--------|-------|---------| |
| 238 | +| 🟢 Good | ≤ 0.1 | Stable, minimal shifting | |
| 239 | +| 🟡 Needs Improvement | ≤ 0.25 | Noticeable shifting | |
| 240 | +| 🔴 Poor | > 0.25 | Significant layout instability | |
| 241 | + |
| 242 | +--- |
| 243 | + |
| 244 | +## Interaction to Next Paint (INP) |
| 245 | + |
| 246 | +Tracks Interaction to Next Paint, a Core Web Vital that measures responsiveness. INP evaluates how quickly a page responds to user interactions throughout the entire page visit, replacing First Input Delay (FID) as a Core Web Vital in March 2024. |
| 247 | + |
| 248 | +**Script:** `scripts/INP.js` |
| 249 | + |
| 250 | +**Thresholds:** |
| 251 | + |
| 252 | +| Rating | Time | Meaning | |
| 253 | +|--------|------|---------| |
| 254 | +| 🟢 Good | ≤ 200ms | Responsive, feels instant | |
| 255 | +| 🟡 Needs Improvement | ≤ 500ms | Noticeable delay | |
| 256 | +| 🔴 Poor | > 500ms | Slow, frustrating experience | |
| 257 | + |
| 258 | +--- |
| 259 | + |
| 260 | +## LCP Image Entropy |
| 261 | + |
| 262 | +Checks if images qualify as LCP candidates based on their entropy (bits per pixel). Since Chrome 112, low-entropy images are ignored for LCP measurement. |
| 263 | + |
| 264 | +**Script:** `scripts/LCP-Image-Entropy.js` |
| 265 | + |
| 266 | +**Thresholds:** |
| 267 | + |
| 268 | +| BPP | Entropy | LCP Eligible | Example | |
| 269 | +|-----|---------|--------------|---------| |
| 270 | +| < 0.05 | 🔴 Low | ❌ No | Solid colors, simple gradients, placeholders | |
| 271 | +| ≥ 0.05 | 🟢 Normal | ✅ Yes | Photos, complex graphics | |
| 272 | + |
| 273 | +--- |
| 274 | + |
| 275 | +## LCP Sub-Parts |
| 276 | + |
| 277 | +Breaks down Largest Contentful Paint into its four phases to identify optimization opportunities. Understanding which phase is slowest helps you focus your optimization efforts where they'll have the most impact. Based on the Web Vitals Chrome Extension. |
| 278 | + |
| 279 | +**Script:** `scripts/LCP-Sub-Parts.js` |
| 280 | + |
| 281 | +--- |
| 282 | + |
| 283 | +## LCP Trail |
| 284 | + |
| 285 | +Tracks every LCP candidate element during page load and highlights each one with a distinct pastel-colored dashed outline — so you can see the full trail from first candidate to final LCP. |
| 286 | + |
| 287 | +**Script:** `scripts/LCP-Trail.js` |
| 288 | + |
| 289 | +--- |
| 290 | + |
| 291 | +## LCP Video Candidate |
| 292 | + |
| 293 | +Detects whether the LCP element is a <video> and audits the poster image configuration — the most common source of avoidable LCP delay when video is the hero element. |
| 294 | + |
| 295 | +**Script:** `scripts/LCP-Video-Candidate.js` |
| 296 | + |
| 297 | +--- |
| 298 | + |
| 299 | +## Largest Contentful Paint (LCP) |
| 300 | + |
| 301 | +Quick check for Largest Contentful Paint, a Core Web Vital that measures loading performance. LCP marks when the largest content element becomes visible in the viewport. |
| 302 | + |
| 303 | +**Script:** `scripts/LCP.js` |
| 304 | + |
| 305 | +**Thresholds:** |
| 306 | + |
| 307 | +| Rating | Time | Meaning | |
| 308 | +|--------|------|---------| |
| 309 | +| 🟢 Good | ≤ 2.5s | Fast, content appears quickly | |
| 310 | +| 🟡 Needs Improvement | ≤ 4s | Moderate delay | |
| 311 | +| 🔴 Poor | > 4s | Slow, users may abandon | |
0 commit comments