Skip to content

Commit 4f7c0fb

Browse files
nucliwebtunetheweb
andauthored
Apply suggestions from code review
Co-authored-by: Barry Pollard <barrypollard@google.com>
1 parent 74b5155 commit 4f7c0fb

7 files changed

Lines changed: 40 additions & 50 deletions

File tree

skills/webperf-core-web-vitals/SKILL.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ Scripts fall into two execution patterns:
2828

2929
Run via `evaluate_script` and return structured JSON immediately from buffered performance data. The page must have already loaded.
3030

31-
### Tracking (INP)
31+
### Measuring (INP)
3232

3333
INP requires real user interactions to measure. The workflow is:
3434

35-
1. Run `INP.js` via `evaluate_script` → returns `{ status: "tracking", getDataFn: "getINP" }`
36-
2. **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."
35+
1. Run `INP.js` via `evaluate_script` → returns `{ status: "measuring", getDataFn: "getINP" }`
36+
2. **Tell the user:** "INP measuring is now active. Please interact with the page — click buttons, open menus, fill form fields — then let me know when you're done."
3737
3. Wait for the user to confirm they've interacted.
3838
4. Call `evaluate_script("getINP()")` to collect results.
3939
5. If `getINP()` returns `status: "error"` → the user has not interacted yet. Remind them and wait.
@@ -50,15 +50,15 @@ When the user asks for a comprehensive Core Web Vitals analysis or "audit CWV":
5050
1. **LCP.js** - Measure Largest Contentful Paint
5151
2. **CLS.js** - Measure Cumulative Layout Shift
5252
3. **INP.js** - Measure Interaction to Next Paint
53-
4. **LCP-Sub-Parts.js** - Break down LCP timing phases
53+
4. **LCP-Subparts.js** - Break down LCP timing phases
5454
5. **LCP-Trail.js** - Track LCP candidate evolution
5555

5656
### LCP Deep Dive
5757

5858
When LCP is slow or the user asks "debug LCP" or "why is LCP slow":
5959

6060
1. **LCP.js** - Establish baseline LCP value
61-
2. **LCP-Sub-Parts.js** - Break down into TTFB, resource load, render delay
61+
2. **LCP-Subparts.js** - Break down into TTFB, resource load, render delay
6262
3. **LCP-Trail.js** - Identify all LCP candidates and changes
6363
4. **LCP-Image-Entropy.js** - Check if LCP image has visual complexity issues
6464
5. **LCP-Video-Candidate.js** - Detect if LCP is a video (poster or video element)
@@ -77,7 +77,7 @@ When layout shifts are detected or the user asks "debug CLS" or "layout shift is
7777

7878
When interactions feel slow or the user asks "debug INP" or "slow interactions":
7979

80-
1. **INP.js** - Start tracking. Tell the user to interact with the page and confirm when done.
80+
1. **INP.js** - Start measuring. Tell the user to interact with the page and confirm when done.
8181
2. Call `getINP()` to collect results once the user confirms.
8282
3. Call `getINPDetails()` to see all interactions ranked by duration.
8383
4. **Interactions.js** (from `webperf-interaction` skill) - List all interactions with timing
@@ -91,7 +91,7 @@ When LCP is a video element (detected by LCP-Video-Candidate.js):
9191

9292
1. **LCP-Video-Candidate.js** - Identify video as LCP candidate
9393
2. **Video-Element-Audit.js** (from Media skill) - Audit video loading strategy
94-
3. **LCP-Sub-Parts.js** - Analyze video loading phases
94+
3. **LCP-Subparts.js** - Analyze video loading phases
9595
4. Cross-reference with **webperf-loading** skill:
9696
- Resource-Hints-Validation.js (check for video preload)
9797
- Priority-Hints-Audit.js (check for fetchpriority on video)
@@ -101,7 +101,7 @@ When LCP is a video element (detected by LCP-Video-Candidate.js):
101101
When LCP is an image (most common case):
102102

103103
1. **LCP.js** - Measure LCP timing
104-
2. **LCP-Sub-Parts.js** - Break down timing phases
104+
2. **LCP-Subparts.js** - Break down timing phases
105105
3. **LCP-Image-Entropy.js** - Analyze image complexity
106106
4. Cross-reference with **webperf-media** skill:
107107
- Image-Element-Audit.js (check format, dimensions, lazy loading)
@@ -122,7 +122,7 @@ Use this decision tree to automatically run follow-up snippets based on results:
122122
- **If LCP candidate is a video** → Run **LCP-Video-Candidate.js** and **webperf-media:Video-Element-Audit.js**
123123
- **Always run****LCP-Trail.js** to understand candidate evolution
124124

125-
### After LCP-Sub-Parts.js
125+
### After LCP-Subparts.js
126126

127127
- **If TTFB phase > 600ms** → Switch to **webperf-loading** skill and run TTFB-Sub-Parts.js
128128
- **If Resource Load Time > 1500ms** → Run:

skills/webperf-core-web-vitals/references/schema.md

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# Script Return Value Schema
22

3-
All scripts return a structured JSON object as the IIFE return value. This allows agents using `evaluate_script` to read structured data directly from the return value, rather than parsing human-readable console output.
3+
All scripts return a structured JSON object as the return value. This allows agents using `evaluate_script` to read structured data directly from the return value, rather than parsing human-readable console output.
44

55
## Base Shape
66

77
```typescript
88
{
99
script: string; // Script name, e.g. "LCP", "CLS", "INP"
1010
status: "ok" // Script ran, has data
11-
| "tracking" // Observer active, data accumulates over time
11+
| "monitoring" // Observer active, data accumulates over time
1212
| "error" // Failed or no data available
1313
| "unsupported"; // Browser API not supported
1414

@@ -25,7 +25,7 @@ All scripts return a structured JSON object as the IIFE return value. This allow
2525
details?: object;
2626
issues?: Array<{ severity: "error" | "warning" | "info"; message: string }>;
2727

28-
// Tracking scripts
28+
// Measurement scripts
2929
message?: string;
3030
getDataFn?: string; // window function name: evaluate_script(`${getDataFn}()`)
3131

@@ -37,18 +37,18 @@ All scripts return a structured JSON object as the IIFE return value. This allow
3737
## Agent Workflow
3838

3939
```
40-
// Synchronous scripts (LCP, CLS, LCP-Sub-Parts, LCP-Trail, LCP-Image-Entropy, LCP-Video-Candidate)
40+
// Synchronous scripts (LCP, CLS, LCP-Subparts, LCP-Trail, LCP-Image-Entropy, LCP-Video-Candidate)
4141
result = evaluate_script(scriptCode)
4242
// → { status: "ok", value: 1240, rating: "good", ... }
4343
44-
// Tracking scripts (INP)
44+
// Measurement scripts (INP)
4545
result = evaluate_script(INP_js)
46-
// → { status: "tracking", getDataFn: "getINP" }
46+
// → { status: "measuring", getDataFn: "getINP" }
4747
// (user interacts with the page)
4848
data = evaluate_script("getINP()")
4949
// → { status: "ok", value: 350, rating: "needs-improvement", ... }
5050
51-
// CLS (hybrid: returns current value immediately, keeps tracking)
51+
// CLS (hybrid: returns current value immediately, keeps measuring)
5252
result = evaluate_script(CLS_js)
5353
// → { status: "ok", value: 0.05, rating: "good", message: "Call getCLS() for updated value" }
5454
// (after more page interactions)
@@ -58,11 +58,11 @@ data = evaluate_script("getCLS()")
5858

5959
## Making Decisions from Return Values
6060

61-
- `rating === "good"`no action needed for this metric
61+
- `rating === "good"`metric meets recommended thresholds
6262
- `rating === "needs-improvement"` → investigate, check `details` and `issues`
6363
- `rating === "poor"` → high priority fix, check `issues` for specific problems
6464
- `status === "error"` → page may not have loaded yet, or metric has no data
65-
- `status === "tracking"` → call `evaluate_script(result.getDataFn + "()")` after interaction
65+
- `status === "measuring"` → call `evaluate_script(result.getDataFn + "()")` after interaction
6666

6767
## Script-Specific Schemas
6868

@@ -82,13 +82,11 @@ data = evaluate_script("getCLS()")
8282
"script": "CLS", "status": "ok", "metric": "CLS",
8383
"value": 0.05, "unit": "score", "rating": "good",
8484
"thresholds": { "good": 0.1, "needsImprovement": 0.25 },
85-
"message": "CLS tracking active. Call getCLS() for updated value after page interactions."
85+
"message": "CLS measurement active. Call getCLS() for updated value after page interactions."
8686
}
8787
```
8888

89-
### INP (initial — tracking)
90-
```json
91-
{ "script": "INP", "status": "tracking", "message": "INP tracking active. Interact with the page then call getINP() for results.", "getDataFn": "getINP" }
89+
### INP (initial — measuring)
9290
```
9391
`getINP()` returns (after interactions):
9492
```json
@@ -111,15 +109,7 @@ data = evaluate_script("getCLS()")
111109
]
112110
```
113111

114-
### LCP-Sub-Parts
115-
```json
116-
{
117-
"script": "LCP-Sub-Parts", "status": "ok", "metric": "LCP",
118-
"value": 2100, "unit": "ms", "rating": "needs-improvement",
119-
"thresholds": { "good": 2500, "needsImprovement": 4000 },
120-
"details": {
121-
"element": "img.hero", "url": "hero.jpg",
122-
"subParts": {
112+
### LCP-Subparts
123113
"ttfb": { "value": 450, "percent": 21, "overTarget": false },
124114
"resourceLoadDelay": { "value": 120, "percent": 6, "overTarget": false },
125115
"resourceLoadTime": { "value": 1200, "percent": 57, "overTarget": true },

skills/webperf-core-web-vitals/references/snippets.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Quick check for Largest Contentful Paint, a Core Web Vital that measures loading
1515
---
1616
## Cumulative Layout Shift (CLS)
1717

18-
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.
18+
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 worst batch impact of all unexpected layout shifts.
1919

2020
**Script:** `scripts/CLS.js`
2121

@@ -31,33 +31,33 @@ Quick check for Cumulative Layout Shift, a Core Web Vital that measures visual s
3131
---
3232
## Interaction to Next Paint (INP)
3333

34-
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.
34+
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.
3535

3636
**Script:** `scripts/INP.js`
3737

38-
**Usage:** Run `INP.js` once to start tracking. It returns `status: "tracking"` immediately. After the user interacts with the page, call `getINP()` to retrieve the current INP value.
38+
**Usage:** Run `INP.js` once to start measuring. It returns `status: "measuring"` immediately. After the user interacts with the page, call `getINP()` to retrieve the current INP value.
3939

4040
**Thresholds:**
4141

4242
| Rating | Time | Meaning |
4343
|--------|------|---------|
44-
| 🟢 Good | ≤ 200ms | Responsive, feels instant |
44+
| 🟢 Good | ≤ 200ms | Responsive, feels responsive |
4545
| 🟡 Needs Improvement | ≤ 500ms | Noticeable delay |
4646
| 🔴 Poor | > 500ms | Slow, frustrating experience |
4747
---
48-
## LCP Sub-Parts
48+
## LCP Subparts
4949

5050
Breaks down Largest Contentful Paint into its four phases to identify optimization opportunities. Understanding which phase is slowest helps focus optimization efforts where they'll have the most impact.
5151

52-
**Script:** `scripts/LCP-Sub-Parts.js`
52+
**Script:** `scripts/LCP-Subparts.js`
5353

54-
**Sub-parts:**
54+
**Subparts:**
5555

5656
| Phase | Target | Description |
5757
|-------|--------|-------------|
5858
| Time to First Byte (TTFB) | ≤ 800ms | Navigation start → first HTML byte |
5959
| Resource Load Delay | < 10% of LCP | TTFB → browser starts loading LCP resource |
60-
| Resource Load Time | ~40% of LCP | Time to download the LCP resource |
60+
| Resource Load Duration | ~40% of LCP | Time spent waiting for the downloading of the LCP resource |
6161
| Element Render Delay | < 10% of LCP | Resource downloaded → LCP element rendered |
6262
---
6363
## LCP Trail

skills/webperf-core-web-vitals/scripts/CLS.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,6 @@
3939
unit: "score",
4040
rating: valueToRating(clsSync),
4141
thresholds: { good: 0.1, needsImprovement: 0.25 },
42-
message: "CLS tracking active. Call getCLS() for updated value after page interactions.",
42+
message: "CLS measurement active. Call getCLS() for updated value after page interactions.",
4343
};
4444
})();

skills/webperf-core-web-vitals/scripts/INP.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
const phases = { inputDelay: 0, processingTime: 0, presentationDelay: 0 };
3030
if (entry.processingStart && entry.processingEnd) {
3131
phases.inputDelay = entry.processingStart - entry.startTime;
32-
phases.processingTime = entry.processingEnd - entry.processingStart;
32+
phases.processingDuration = entry.processingEnd - entry.processingStart;
3333
phases.presentationDelay = entry.duration - phases.inputDelay - phases.processingTime;
3434
}
3535
return phases;
@@ -71,7 +71,7 @@
7171
details.worstEvent = inpEntry.formattedName;
7272
details.phases = {
7373
inputDelay: Math.round(inpEntry.phases.inputDelay),
74-
processingTime: Math.round(inpEntry.phases.processingTime),
74+
processingDuration: Math.round(inpEntry.phases.processingDuration),
7575
presentationDelay: Math.round(inpEntry.phases.presentationDelay),
7676
};
7777
}
@@ -116,8 +116,8 @@
116116

117117
return {
118118
script: "INP",
119-
status: "tracking",
120-
message: "INP tracking active. Interact with the page then call getINP() for results.",
119+
status: "measuring",
120+
message: "INP measurement active. Interact with the page then call getINP() for results.",
121121
getDataFn: "getINP",
122122
};
123123
})();

skills/webperf-core-web-vitals/scripts/LCP-Image-Entropy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
if (lowEntropyCount > 0) {
4040
issues.push({
4141
severity: "warning",
42-
message: `${lowEntropyCount} image(s) have low entropy and are LCP-ineligible in Chrome 112+`,
42+
message: `${lowEntropyCount} image(s) have low entropy and are not considered for LCP`,
4343
});
4444
}
4545
if (lcpImage?.isLowEntropy) {

skills/webperf-core-web-vitals/scripts/LCP-Sub-Parts.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
const SUB_PARTS = [
88
{ name: "Time to First Byte", key: "ttfb", target: 800 },
99
{ name: "Resource Load Delay", key: "loadDelay", targetPercent: 10 },
10-
{ name: "Resource Load Time", key: "loadTime", targetPercent: 40 },
10+
{ name: "Resource Load Duration", key: "loadduration", targetPercent: 40 },
1111
{ name: "Element Render Delay", key: "renderDelay", targetPercent: 10 },
1212
];
1313

@@ -56,7 +56,7 @@
5656
const values = {
5757
ttfb,
5858
loadDelay: lcpRequestStart - ttfb,
59-
loadTime: lcpResponseEnd - lcpRequestStart,
59+
loadDuration: lcpResponseEnd - lcpRequestStart,
6060
renderDelay: total - lcpResponseEnd,
6161
};
6262
SUB_PARTS.forEach((part) => {
@@ -83,13 +83,13 @@
8383
const totalMs = Math.round(total);
8484
const ttfbVal = Math.round(ttfb);
8585
const loadDelayVal = Math.round(lcpRequestStart - ttfb);
86-
const loadTimeVal = Math.round(lcpResponseEnd - lcpRequestStart);
86+
const loadDurationVal = Math.round(lcpResponseEnd - lcpRequestStart);
8787
const renderDelayVal = Math.round(total - lcpResponseEnd);
8888

8989
const slowestPhase = [
9090
{ key: "ttfb", value: ttfbVal },
9191
{ key: "resourceLoadDelay", value: loadDelayVal },
92-
{ key: "resourceLoadTime", value: loadTimeVal },
92+
{ key: "resourceLoadDuration", value: loadDurationVal },
9393
{ key: "elementRenderDelay", value: renderDelayVal },
9494
].reduce((a, b) => (a.value > b.value ? a : b)).key;
9595

@@ -118,7 +118,7 @@
118118
subParts: {
119119
ttfb: { value: ttfbVal, percent: Math.round((ttfbVal / totalMs) * 100), overTarget: ttfbVal > 800 },
120120
resourceLoadDelay: { value: loadDelayVal, percent: Math.round((loadDelayVal / totalMs) * 100), overTarget: (loadDelayVal / totalMs) * 100 > 10 },
121-
resourceLoadTime: { value: loadTimeVal, percent: Math.round((loadTimeVal / totalMs) * 100), overTarget: (loadTimeVal / totalMs) * 100 > 40 },
121+
resourceLoadDuration: { value: loadDurationVal, percent: Math.round((loadDurationVal / totalMs) * 100), overTarget: (loadDurationVal / totalMs) * 100 > 40 },
122122
elementRenderDelay: { value: renderDelayVal, percent: Math.round((renderDelayVal / totalMs) * 100), overTarget: (renderDelayVal / totalMs) * 100 > 10 },
123123
},
124124
slowestPhase,

0 commit comments

Comments
 (0)