| name | webperf-core-web-vitals |
|---|---|
| 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. |
| context | fork |
JavaScript snippets for measuring web performance in Chrome DevTools. Execute with evaluate_script, capture output with get_console_message.
scripts/CLS.js— Cumulative Layout Shift (CLS)scripts/INP.js— Interaction to Next Paint (INP)scripts/LCP-Image-Entropy.js— LCP Image Entropyscripts/LCP-Sub-Parts.js— LCP Sub-Partsscripts/LCP-Trail.js— LCP Trailscripts/LCP-Video-Candidate.js— LCP Video Candidatescripts/LCP.js— Largest Contentful Paint (LCP)
Descriptions, thresholds, and return schemas: references/snippets.md, references/schema.md
Scripts fall into two execution patterns:
Run via evaluate_script and return structured JSON immediately from buffered performance data. The page must have already loaded.
INP requires real user interactions to measure. The workflow is:
- Run
INP.jsviaevaluate_script→ returns{ status: "tracking", getDataFn: "getINP" } - Tell the user: "INP tracking is now active. Please interact with the page — click buttons, open menus, fill form fields — then let me know when you're done."
- Wait for the user to confirm they've interacted.
- Call
evaluate_script("getINP()")to collect results. - If
getINP()returnsstatus: "error"→ the user has not interacted yet. Remind them and wait. - For a full breakdown of all interactions, call
evaluate_script("getINPDetails()")— returns all recorded interactions sorted by duration.
The agent cannot interact with the page on behalf of the user for INP measurement. Real user interactions are required.
When the user asks for a comprehensive Core Web Vitals analysis or "audit CWV":
- LCP.js - Measure Largest Contentful Paint
- CLS.js - Measure Cumulative Layout Shift
- INP.js - Measure Interaction to Next Paint
- LCP-Sub-Parts.js - Break down LCP timing phases
- LCP-Trail.js - Track LCP candidate evolution
When LCP is slow or the user asks "debug LCP" or "why is LCP slow":
- LCP.js - Establish baseline LCP value
- LCP-Sub-Parts.js - Break down into TTFB, resource load, render delay
- LCP-Trail.js - Identify all LCP candidates and changes
- LCP-Image-Entropy.js - Check if LCP image has visual complexity issues
- LCP-Video-Candidate.js - Detect if LCP is a video (poster or video element)
When layout shifts are detected or the user asks "debug CLS" or "layout shift issues":
- CLS.js - Measure overall CLS score
- Layout-Shift-Loading-and-Interaction.js (from
webperf-interactionskill) - Separate loading vs interaction shifts - Cross-reference with webperf-loading skill:
- Find-Above-The-Fold-Lazy-Loaded-Images.js (lazy images causing shifts)
- Fonts-Preloaded-Loaded-and-used-above-the-fold.js (font swap causing shifts)
When interactions feel slow or the user asks "debug INP" or "slow interactions":
- INP.js - Start tracking. Tell the user to interact with the page and confirm when done.
- Call
getINP()to collect results once the user confirms. - Call
getINPDetails()to see all interactions ranked by duration. - Interactions.js (from
webperf-interactionskill) - List all interactions with timing - Input-Latency-Breakdown.js (from
webperf-interactionskill) - Break down input delay, processing, presentation - Long-Animation-Frames.js (from
webperf-interactionskill) - Identify blocking animation frames - Long-Animation-Frames-Script-Attribution.js (from
webperf-interactionskill) - Find scripts causing delays
When LCP is a video element (detected by LCP-Video-Candidate.js):
- LCP-Video-Candidate.js - Identify video as LCP candidate
- Video-Element-Audit.js (from Media skill) - Audit video loading strategy
- LCP-Sub-Parts.js - Analyze video loading phases
- Cross-reference with webperf-loading skill:
- Resource-Hints-Validation.js (check for video preload)
- Priority-Hints-Audit.js (check for fetchpriority on video)
When LCP is an image (most common case):
- LCP.js - Measure LCP timing
- LCP-Sub-Parts.js - Break down timing phases
- LCP-Image-Entropy.js - Analyze image complexity
- Cross-reference with webperf-media skill:
- Image-Element-Audit.js (check format, dimensions, lazy loading)
- Cross-reference with webperf-loading skill:
- Find-Above-The-Fold-Lazy-Loaded-Images.js (check if incorrectly lazy)
- Priority-Hints-Audit.js (check for fetchpriority="high")
- Resource-Hints-Validation.js (check for preload)
Use this decision tree to automatically run follow-up snippets based on results:
- If LCP > 2.5s → Run LCP-Sub-Parts.js to diagnose which phase is slow
- If LCP > 4.0s (poor) → Run full LCP deep dive workflow (5 snippets)
- If LCP candidate is an image → Run LCP-Image-Entropy.js and webperf-media:Image-Element-Audit.js
- If LCP candidate is a video → Run LCP-Video-Candidate.js and webperf-media:Video-Element-Audit.js
- Always run → LCP-Trail.js to understand candidate evolution
- If TTFB phase > 600ms → Switch to webperf-loading skill and run TTFB-Sub-Parts.js
- If Resource Load Time > 1500ms → Run:
- webperf-loading:Resource-Hints-Validation.js (check for preload/preconnect)
- webperf-loading:Priority-Hints-Audit.js (check fetchpriority)
- webperf-loading:Find-render-blocking-resources.js (competing resources)
- If Render Delay > 200ms → Run:
- webperf-loading:Find-render-blocking-resources.js (blocking CSS/JS)
- webperf-loading:Script-Loading.js (parser-blocking scripts)
- webperf-interaction:Long-Animation-Frames.js (main thread blocking)
- If many LCP candidate changes (>3) → This causes visual instability, investigate:
- webperf-loading:Find-Above-The-Fold-Lazy-Loaded-Images.js (late-loading images)
- webperf-loading:Fonts-Preloaded-Loaded-and-used-above-the-fold.js (font swaps)
- CLS.js (layout shifts contributing to LCP changes)
- If final LCP candidate appears late → Run webperf-loading:Resource-Hints-Validation.js
- If early candidate was replaced → Understand why initial content was pushed down (likely CLS issue)
- If entropy is very high → Image is visually complex, recommend:
- Modern formats (WebP, AVIF)
- Appropriate compression
- Potentially a placeholder strategy
- If entropy is low → Image may be over-optimized or placeholder-like
- If large file size detected → Run webperf-media:Image-Element-Audit.js for format/sizing analysis
- If video is LCP → Run:
- webperf-media:Video-Element-Audit.js (check poster, preload, formats)
- webperf-loading:Priority-Hints-Audit.js (check fetchpriority on poster)
- LCP-Sub-Parts.js (analyze video loading phases)
- If poster image is LCP → Treat as image LCP (run image workflows)
- If CLS > 0.1 → Run webperf-interaction:Layout-Shift-Loading-and-Interaction.js to separate causes
- If CLS > 0.25 (poor) → Run comprehensive shift investigation:
- webperf-loading:Find-Above-The-Fold-Lazy-Loaded-Images.js (images without dimensions)
- webperf-loading:Fonts-Preloaded-Loaded-and-used-above-the-fold.js (font loading strategy)
- webperf-loading:Critical-CSS-Detection.js (late-loading styles)
- webperf-media:Image-Element-Audit.js (missing width/height)
- If CLS = 0 → Confirm with multiple page loads (might be timing-dependent)
- If INP > 200ms → Run webperf-interaction:Interactions.js to identify slow interactions
- If INP > 500ms (poor) → Run full INP debugging workflow:
- webperf-interaction:Interactions.js (list all interactions)
- webperf-interaction:Input-Latency-Breakdown.js (phase breakdown)
- webperf-interaction:Long-Animation-Frames.js (blocking frames)
- webperf-interaction:Long-Animation-Frames-Script-Attribution.js (culprit scripts)
- If specific interaction type is slow (e.g., keyboard) → Focus analysis on that interaction type
These triggers recommend using snippets from other skills:
-
If LCP > 2.5s and TTFB phase is dominant → Use webperf-loading skill:
- TTFB.js, TTFB-Sub-Parts.js, Service-Worker-Analysis.js
-
If LCP image is lazy-loaded → Use webperf-loading skill:
- Find-Above-The-Fold-Lazy-Loaded-Images.js
-
If LCP has no fetchpriority → Use webperf-loading skill:
- Priority-Hints-Audit.js
-
If CLS caused by fonts → Use webperf-loading skill:
- Fonts-Preloaded-Loaded-and-used-above-the-fold.js
- Resource-Hints-Validation.js (for font preload)
-
If CLS caused by images → Use webperf-media skill:
- Image-Element-Audit.js (check for width/height attributes)
- If INP > 200ms → Use webperf-interaction skill for full debugging:
- Interactions.js, Input-Latency-Breakdown.js
- Long-Animation-Frames.js, Long-Animation-Frames-Script-Attribution.js
- LongTask.js (if pre-interaction blocking suspected)
- If render delay or interaction delay is high → Use webperf-interaction skill:
- Long-Animation-Frames.js (main thread blocking)
Note on cross-skill references: This skill runs in an isolated subagent (
context: fork). When a decision tree recommends scripts from another skill (e.g.,webperf-loading,webperf-interaction,webperf-media), report the recommendation to the user as a next step — do not attempt to execute those scripts directly. The user or the main agent can activate the appropriate skill to continue the investigation.
When a script returns status: "error":
- LCP/CLS/LCP-Sub-Parts/LCP-Trail → The page may not have finished loading. Ask the user to wait for full load or reload, then re-run the script.
- INP (
getINP()returns error) → No interactions have been recorded yet. Remind the user to interact with the page, then callgetINP()again. - LCP-Image-Entropy → No images with measurable BPP found. This is normal for text-only pages or pages where all images are data URIs.
- LCP-Video-Candidate → No LCP entries found; see LCP error recovery above.
By default, scripts highlight the LCP element(s) with colored dashed outlines — useful when the user is watching the browser while the agent runs. To disable:
window.__cwvHighlight = false;
// then run any LCP scriptScripts that support this flag: LCP.js, LCP-Sub-Parts.js, LCP-Trail.js.