page-efficiency-score
Compute a composite 0-100 efficiency score using JS/CSS coverage, render-blocking resources, transfer size, and navigation timing via CDP.
What this skill does
# Page Efficiency Score
Calculate a weighted composite score (0-100) that measures how efficiently a page uses its resources. Combines JavaScript coverage, CSS coverage, render-blocking resource count, total transfer size, TTFB, and DOMContentLoaded timing into a single actionable metric.
## When to Use
- Quick health check of page load efficiency during development or QA
- Comparing efficiency across pages, routes, or deployments
- Identifying the primary bottleneck category (JS bloat, CSS bloat, render-blocking, network)
- Tracking efficiency improvements over time with a single comparable number
- Prioritizing optimization efforts based on weighted category scores
## Prerequisites
- Playwright MCP server connected with a **Chromium** browser session (CDP required for JS/CSS coverage)
- Target page must be accessible in the browser session
- Page should be tested in a clean state (clear cache for accurate transfer size measurement, or test with cache to measure real-world performance)
- Network conditions should be consistent between comparisons
## Scoring System
The composite score is the weighted sum of six category scores. Each category is scored 0, 5, or 10 based on thresholds.
### Scoring Table
| Category | Weight | Good (10 pts) | OK (5 pts) | Bad (0 pts) |
|---|---|---|---|---|
| JS Unused % | 25% | < 30% unused | 30-60% unused | > 60% unused |
| CSS Unused % | 15% | < 40% unused | 40-70% unused | > 70% unused |
| Render-blocking Resources | 20% | 0-2 resources | 3-5 resources | > 5 resources |
| Total Transfer Size | 20% | < 500 KB | 500 KB - 2 MB | > 2 MB |
| TTFB | 10% | < 200 ms | 200-600 ms | > 600 ms |
| DOMContentLoaded | 10% | < 1000 ms | 1000-3000 ms | > 3000 ms |
### Score Interpretation
| Score Range | Rating | Meaning |
|---|---|---|
| 85 - 100 | Excellent | Page is well-optimized; minor improvements possible |
| 70 - 84 | Good | Solid performance with some optimization opportunities |
| 50 - 69 | Needs Work | Significant inefficiencies; prioritize top weight categories |
| 30 - 49 | Poor | Major resource waste; likely impacts user experience |
| 0 - 29 | Critical | Severe inefficiency across multiple categories |
## Workflow
### Step 1: Start Coverage Tracking via CDP
Use `browser_run_code` to initialize both JavaScript and CSS coverage tracking. This must run **before** navigation.
```javascript
browser_run_code({
code: `async (page) => {
const client = await page.context().newCDPSession(page);
page.__cdpClient = client;
// Enable profiler for JS coverage
await client.send('Profiler.enable');
await client.send('Profiler.startPreciseCoverage', {
callCount: false,
detailed: true
});
// Enable CSS coverage
await client.send('CSS.enable');
await client.send('CSS.startRuleUsageTracking');
return 'JS and CSS coverage tracking started';
}`
})
```
### Step 2: Navigate to the Target Page
```
browser_navigate({ url: "https://example.com/page" })
```
Wait for the page to be fully loaded. Use `networkidle` state for the most accurate measurement:
```javascript
browser_run_code({
code: `async (page) => {
await page.waitForLoadState('networkidle');
return 'Page loaded (networkidle)';
}`
})
```
### Step 3: Collect JS and CSS Coverage Data
Use `browser_run_code` to stop coverage tracking and retrieve the raw data.
```javascript
browser_run_code({
code: `async (page) => {
const client = page.__cdpClient;
// Collect JS coverage
const jsCoverage = await client.send('Profiler.takePreciseCoverage');
await client.send('Profiler.stopPreciseCoverage');
await client.send('Profiler.disable');
// Collect CSS coverage
const cssCoverage = await client.send('CSS.stopRuleUsageTracking');
// Calculate JS usage
let totalJSBytes = 0;
let usedJSBytes = 0;
jsCoverage.result.forEach(script => {
const scriptLength = script.end || 0;
totalJSBytes += scriptLength;
script.functions.forEach(fn => {
fn.ranges.forEach(range => {
if (range.count > 0) {
usedJSBytes += (range.endOffset - range.startOffset);
}
});
});
});
const jsUnusedPercent = totalJSBytes > 0
? Math.round(((totalJSBytes - usedJSBytes) / totalJSBytes) * 1000) / 10
: 0;
// Calculate CSS usage
const totalCSSRules = cssCoverage.ruleUsage.length;
const usedCSSRules = cssCoverage.ruleUsage.filter(r => r.used).length;
const cssUnusedPercent = totalCSSRules > 0
? Math.round(((totalCSSRules - usedCSSRules) / totalCSSRules) * 1000) / 10
: 0;
// Store for later use
await page.evaluate((data) => {
window.__coverageData = data;
}, {
jsUnusedPercent,
cssUnusedPercent,
totalJSBytes,
usedJSBytes,
totalCSSRules,
usedCSSRules
});
return {
jsUnusedPercent,
cssUnusedPercent,
totalJSKB: Math.round(totalJSBytes / 1024),
usedJSKB: Math.round(usedJSBytes / 1024),
totalCSSRules,
usedCSSRules
};
}`
})
```
### Step 4: Collect Timing and Resource Data
Use `browser_evaluate` to extract Resource Timing, Navigation Timing, and render-blocking resource information.
```javascript
browser_evaluate({
function: `() => {
// Navigation Timing
const navEntry = performance.getEntriesByType('navigation')[0] || {};
const ttfb = Math.round(navEntry.responseStart - navEntry.requestStart) || 0;
const domContentLoaded = Math.round(navEntry.domContentLoadedEventEnd - navEntry.startTime) || 0;
const loadEventEnd = Math.round(navEntry.loadEventEnd - navEntry.startTime) || 0;
const domInteractive = Math.round(navEntry.domInteractive - navEntry.startTime) || 0;
// Resource Timing
const resources = performance.getEntriesByType('resource');
let totalTransferBytes = 0;
let renderBlockingCount = 0;
const renderBlockingResources = [];
resources.forEach(r => {
totalTransferBytes += (r.transferSize || 0);
// Check renderBlockingStatus (Chromium 105+)
if (r.renderBlockingStatus === 'blocking') {
renderBlockingCount++;
renderBlockingResources.push({
url: r.name.split('/').pop().split('?')[0].substring(0, 60),
type: r.initiatorType,
transferSizeKB: Math.round((r.transferSize || 0) / 1024 * 10) / 10,
durationMs: Math.round(r.duration)
});
}
});
const totalTransferKB = Math.round(totalTransferBytes / 1024 * 10) / 10;
return {
timing: {
ttfb: ttfb,
domContentLoaded: domContentLoaded,
domInteractive: domInteractive,
loadEventEnd: loadEventEnd
},
transfer: {
totalTransferKB: totalTransferKB,
totalTransferMB: Math.round(totalTransferKB / 1024 * 100) / 100,
resourceCount: resources.length
},
renderBlocking: {
count: renderBlockingCount,
resources: renderBlockingResources
}
};
}`
})
```
### Step 5: Collect Network Request Count
Use `browser_network_requests` to get the total number of HTTP requests.
```
browser_network_requests({ includeStatic: true })
```
### Step 6: Compute the Composite Score
Use `browser_evaluate` to calculate the weighted composite score using all collected data. Pass the coverage data and resource data as needed.
```javascript
browser_evaluate({
function: `() => {
const coverage = window.__coverageData || {};
// Navigation Timing
const navEntry = performance.getEntriesByType('navigation')[0] || {};
const ttfb = Math.round(navEntry.responseStart - navEntry.requestStart) || 0;
const domContentLoaded = Math.round(navEntry.domContentLoadedEventEnd - navEntry.startTime) || 0;
// Resources
const resources = performance.getEntriesByType('resource');
let totalTransferBytes = 0;
let renderBlockingCount = 0;
resources.forEach(r => {
totalTransferBytes += (r.transferSize |Related in Image & Video
watch
IncludedWatch a video (URL or local path). Downloads with yt-dlp, extracts auto-scaled frames with ffmpeg, pulls the transcript from captions (or Whisper API fallback), and hands the result to Claude so it can answer questions about what's in the video.
physical-ai-defect-image-generation
IncludedUse when the user wants to orchestrate defect image generation, run associated setup, or handle outputs on OSMO. The Day 0 path handles cold-start with USD-to-ROI, image-edit augmentation, and AnomalyGen to create initial PCBA datasets. The Day 1 path performs inference and labeling on real images. This skill helps with first-time asset setup, creation of finetuning checkpoints, and configuring deployment. Trigger keywords: defect image generation, dig workflow, dig pipeline, defect image detection workflow, aoi pipeline, aoi anomalygen, usd2roi anomalygen, day 0 pcba, day 1 pcba, day 1 real-photo alignment, day 1 manual roi, metal surface anomaly, glass defect, anomalygen finetune, setup_pcb, setup_metal, setup_glass, setup_pretrained, dig setup, dig datasets, dig pretrained checkpoint, dig image-edit endpoint.
accelint-react-best-practices
IncludedReact performance optimization and best practices. ALWAYS use this skill when working with any React code - writing components, hooks, JSX; refactoring; optimizing re-renders, memoization, state management; reviewing for performance; fixing hydration mismatches; debugging infinite re-renders, stale closures, input focus loss, animations restarting; preventing remounting; implementing transitions, lazy initialization, effect dependencies. Even simple React tasks benefit from these patterns. Covers React 19+ (useEffectEvent, Activity, ref props). Triggers - useEffect, useState, useMemo, useCallback, memo, inline components, nested components, components inside components, re-render, performance, hydration, SSR, Next.js, useDeferredValue, combined hooks.
elevenlabs-agents
IncludedBuild conversational AI voice agents with ElevenLabs Platform using React, JavaScript, React Native, or Swift SDKs. Configure agents, tools (client/server/MCP), RAG knowledge bases, multi-voice, and Scribe real-time STT. Use when: building voice chat interfaces, implementing AI phone agents with Twilio, configuring agent workflows or tools, adding RAG knowledge bases, testing with CLI "agents as code", or troubleshooting deprecated @11labs packages, Android audio cutoff, CSP violations, dynamic variables, or WebRTC config. Keywords: ElevenLabs Agents, ElevenLabs voice agents, AI voice agents, conversational AI, @elevenlabs/react, @elevenlabs/client, @elevenlabs/react-native, @elevenlabs/elevenlabs-js, @elevenlabs/agents-cli, elevenlabs SDK, voice AI, TTS, text-to-speech, ASR, speech recognition, turn-taking model, WebRTC voice, WebSocket voice, ElevenLabs conversation, agent system prompt, agent tools, agent knowledge base, RAG voice agents, multi-voice agents, pronunciation dictionary, voice speed control, elevenlabs scribe, @11labs deprecated, Android audio cutoff, CSP violation elevenlabs, dynamic variables elevenlabs, case-sensitive tool names, webhook authentication
humanizer
IncludedHumanize AI-generated text by detecting and removing patterns typical of LLM output. Rewrites text to sound natural, specific, and human. Uses 28 pattern detectors, 560+ AI vocabulary terms across 3 tiers, and statistical analysis (burstiness, type-token ratio, readability) for comprehensive detection. Use when asked to humanize text, de-AI writing, make content sound more natural/human, review writing for AI patterns, score text for AI detection, or improve AI-generated drafts. Covers content, language, style, communication, and filler categories.
generating-mermaid-diagrams
IncludedSalesforce architecture diagrams using Mermaid with ASCII fallback. Use this skill when generating text-based diagrams for Salesforce architecture, OAuth flows, ERDs, integration sequences, or Agentforce structure. TRIGGER when: user says "diagram", "visualize", "ERD", or asks for sequence diagrams, flowcharts, class diagrams, or architecture visualizations in Mermaid. DO NOT TRIGGER when: user wants PNG/SVG image output (use generating-visual-diagrams), or asks about non-Salesforce systems.