1kalin/afrexai-web-performance-engine/SKILL.md
# Web Performance Engine Complete web performance optimization system. Audit, diagnose, fix, and monitor — no external tools required (but integrates with Lighthouse, WebPageTest, Chrome DevTools when available). ## Phase 1: Performance Audit ### Quick Health Check Run these checks in order. Stop when you find the bottleneck tier. **Tier 1 — Critical (blocks rendering):** - [ ] Time to First Byte (TTFB) > 800ms → server problem - [ ] First Contentful Paint (FCP) > 1.8s → render-blocking res
npx skillsauth add openclaw/skills 1kalin/afrexai-web-performance-engineInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Complete web performance optimization system. Audit, diagnose, fix, and monitor — no external tools required (but integrates with Lighthouse, WebPageTest, Chrome DevTools when available).
Run these checks in order. Stop when you find the bottleneck tier.
Tier 1 — Critical (blocks rendering):
Tier 2 — Important (affects experience):
Tier 3 — Polish (competitive edge):
audit:
url: ""
device: "mobile" # mobile | desktop | both
connection: "4G" # 3G | 4G | fiber
region: "" # closest to target users
scores:
performance: null # 0-100
fcp_ms: null
lcp_ms: null
tbt_ms: null
cls: null
inp_ms: null
ttfb_ms: null
page_weight:
total_kb: null
html_kb: null
css_kb: null
js_kb: null
images_kb: null
fonts_kb: null
other_kb: null
requests:
total: null
by_type: {}
third_party_count: null
third_party_kb: null
If no Lighthouse/DevTools available, use web-based tools:
web_fetch "https://pagespeed.web.dev/analysis?url={encoded_url}" — Google's free toolweb_search "webpagetest {url}" — find cached resultsweb_search "site:{domain} core web vitals" — find CrUX data<head> for obvious issues: render-blocking CSS/JS, missing preloads, no meta viewportDNS → TCP → TLS → TTFB → HTML Parse → CSSOM → Render Tree → FCP → LCP
↓
JS Download → Parse → Execute → INP
Bottleneck Decision Tree:
High TTFB (>800ms)?
├─ YES → Phase 3A: Server optimization
└─ NO → High FCP (>1.8s)?
├─ YES → Phase 3B: Render-blocking resources
└─ NO → High LCP (>2.5s)?
├─ YES → Phase 3C: Hero element optimization
└─ NO → High TBT (>200ms)?
├─ YES → Phase 3D: JavaScript optimization
└─ NO → High CLS (>0.1)?
├─ YES → Phase 3E: Layout stability
└─ NO → High INP (>200ms)?
├─ YES → Phase 3F: Interaction optimization
└─ NO → ✅ Performance is good!
Rate each resource by impact:
| Factor | Weight | Score 1 | Score 3 | Score 5 | |--------|--------|---------|---------|---------| | Size (KB) | 3x | <10 | 10-100 | >100 | | Render-blocking | 5x | No | Partial | Full | | Above-fold impact | 4x | None | Indirect | Direct | | Cacheable | 2x | Long cache | Short cache | No cache | | Compressible | 2x | Already done | Possible | Not compressed |
Priority = Sum(Factor × Weight). Fix highest scores first.
Quick wins:
# CDN: If no CDN, this is #1 priority
# Check: curl -sI {url} | grep -i 'x-cache\|cf-cache\|x-cdn'
# Compression: Must have brotli or gzip
# Check: curl -sI -H "Accept-Encoding: br,gzip" {url} | grep -i content-encoding
# HTTP/2 or HTTP/3
# Check: curl -sI --http2 {url} | head -1
Server-side checklist:
Cache headers template:
# Static assets (CSS, JS, images, fonts)
Cache-Control: public, max-age=31536000, immutable
# HTML pages
Cache-Control: public, max-age=0, must-revalidate
# API responses
Cache-Control: private, max-age=60, stale-while-revalidate=300
CSS optimization:
<!-- BEFORE: Render-blocking -->
<link rel="stylesheet" href="styles.css">
<!-- AFTER: Critical CSS inline + async load -->
<style>/* Critical above-fold CSS here (< 14KB) */</style>
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>
Rules:
@import (creates sequential loading)JavaScript optimization:
<!-- BEFORE: Render-blocking -->
<script src="app.js"></script>
<!-- AFTER: Non-blocking -->
<script src="app.js" defer></script>
<!-- OR: Independent scripts -->
<script src="analytics.js" async></script>
Rules:
defer for app scripts (maintains order, runs after parse)async for independent scripts (analytics, ads)<script> in <head> without defer/asyncLCP element types and fixes:
| LCP Element | Fix |
|------------|-----|
| <img> | Preload + responsive + modern format |
| <video> poster | Preload poster image |
| CSS background-image | Preload + inline critical CSS |
| Text block | Preload font + font-display: optional |
Image optimization checklist:
<!-- Optimal hero image -->
<link rel="preload" as="image" href="hero.webp"
imagesrcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
imagesizes="100vw">
<img src="hero.webp"
srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
sizes="100vw"
width="1200" height="600"
alt="Hero description"
fetchpriority="high"
decoding="async">
Image format decision:
Photo/complex image? → WebP (25-35% smaller than JPEG)
→ AVIF (50% smaller, but slower encode)
Simple graphic/logo? → SVG (scalable, tiny)
→ PNG only if transparency needed
Animation? → WebM/MP4 video (not GIF — 90% smaller)
Image size targets: | Viewport | Max width | Target KB | |----------|-----------|-----------| | Mobile | 400px | < 50KB | | Tablet | 800px | < 100KB | | Desktop | 1200px | < 150KB | | Hero/banner | 1600px | < 200KB |
Bundle analysis approach:
web_fetch the page, count <script> tagsCommon JS bloat and replacements:
| Library | Size | Alternative | Size | |---------|------|-------------|------| | moment.js | 67KB | date-fns | 2-10KB | | lodash (full) | 71KB | lodash-es (tree-shake) | 2-5KB | | jQuery | 87KB | vanilla JS | 0KB | | animate.css | 80KB | CSS animations | 1-2KB | | chart.js | 60KB | lightweight-charts | 40KB |
Code splitting rules:
const Chart = lazy(() => import('./Chart'))Long task breaking:
// BEFORE: Blocks main thread 200ms+
function processLargeList(items) {
items.forEach(item => heavyComputation(item));
}
// AFTER: Yields to main thread
async function processLargeList(items) {
for (const item of items) {
heavyComputation(item);
// Yield every 50ms
if (performance.now() - start > 50) {
await scheduler.yield(); // or setTimeout(0)
start = performance.now();
}
}
}
Top CLS causes and fixes:
| Cause | Fix |
|-------|-----|
| Images without dimensions | Always set width + height |
| Ads/embeds without space | Reserve space with aspect-ratio or min-height |
| Dynamic content injection | Use CSS contain or reserved space |
| Web fonts causing reflow | font-display: optional or swap with size-adjust |
| Late-loading CSS | Inline critical CSS |
Anti-CLS patterns:
/* Reserve space for dynamic content */
.ad-slot { min-height: 250px; }
.embed-container { aspect-ratio: 16/9; }
/* Prevent font swap reflow */
@font-face {
font-family: 'Brand';
src: url('brand.woff2') format('woff2');
font-display: optional; /* No swap = no shift */
size-adjust: 105%; /* Match fallback metrics */
}
/* Contain layout shifts */
.dynamic-widget {
contain: layout;
min-height: 200px;
}
Event handler rules:
requestAnimationFrame for visual updatescontent-visibility: auto for off-screen contentInput responsiveness:
// BEFORE: Blocks during type
input.addEventListener('input', (e) => {
expensiveFilter(e.target.value); // 100ms+
});
// AFTER: Debounced + visual feedback
input.addEventListener('input', (e) => {
showSpinner(); // Instant visual feedback
debounce(() => expensiveFilter(e.target.value), 150);
});
<!-- Preconnect: Third-party origins you'll need soon -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
<!-- DNS-prefetch: Third-party origins you might need -->
<link rel="dns-prefetch" href="https://analytics.example.com">
<!-- Preload: Critical resources for THIS page -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="hero.webp" as="image">
<link rel="preload" href="brand.woff2" as="font" type="font/woff2" crossorigin>
<!-- Prefetch: Resources for NEXT page (low priority) -->
<link rel="prefetch" href="/next-page.js">
<!-- Modulepreload: ES modules -->
<link rel="modulepreload" href="app.mjs">
Rules:
Above fold (viewport): fetchpriority="high", no lazy
Below fold (1-2 screens): loading="lazy", decoding="async"
Way below fold: Intersection Observer, load on demand
Off-screen widgets: content-visibility: auto
/* Optimal font loading */
@font-face {
font-family: 'Brand';
src: url('brand.woff2') format('woff2');
font-display: swap;
unicode-range: U+0000-00FF; /* Latin only if applicable */
}
Font checklist:
System font stacks:
/* Modern system fonts — zero network cost */
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
/* Monospace */
font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, monospace;
third_party_audit:
- script: "Google Analytics 4"
size_kb: 45
blocks_render: false
loads_more_scripts: true
total_impact_kb: 90
essential: true
mitigation: "gtag async, delay until interaction"
- script: "Intercom chat widget"
size_kb: 200
blocks_render: false
loads_more_scripts: true
total_impact_kb: 450
essential: false
mitigation: "Load on scroll/click, not page load"
Third-party loading strategies:
// Strategy 1: Load on interaction
document.addEventListener('scroll', () => {
loadThirdParty('chat-widget.js');
}, { once: true });
// Strategy 2: Load after page is idle
requestIdleCallback(() => {
loadThirdParty('analytics.js');
});
// Strategy 3: Facade pattern (show placeholder until needed)
chatButton.addEventListener('click', () => {
loadThirdParty('intercom.js').then(() => Intercom('show'));
});
Rules:
rel="noopener" on all external linksTargets (mobile on 4G): | Metric | Good | Needs Work | Poor | |--------|------|------------|------| | FCP | < 1.8s | 1.8-3.0s | > 3.0s | | LCP | < 2.5s | 2.5-4.0s | > 4.0s | | TBT | < 200ms | 200-600ms | > 600ms | | CLS | < 0.1 | 0.1-0.25 | > 0.25 | | INP | < 200ms | 200-500ms | > 500ms |
Mobile-specific checklist:
performance_budget:
metrics:
lcp_ms: 2500
fcp_ms: 1800
tbt_ms: 200
cls: 0.1
inp_ms: 200
resources:
total_kb: 1500
js_kb: 350
css_kb: 80
images_kb: 800
fonts_kb: 100
requests:
total: 60
third_party: 15
lighthouse:
performance: 90
accessibility: 90
best_practices: 90
seo: 90
Budget enforcement rules:
# Weekly performance check
date: "YYYY-MM-DD"
url: ""
device: "mobile"
scores:
lighthouse: null
lcp: null
fcp: null
tbt: null
cls: null
trend: "improving | stable | degrading"
regressions: []
actions: []
Rate the site 0-100:
| Dimension | Weight | 0-2 | 3-4 | 5 | |-----------|--------|-----|-----|---| | Core Web Vitals | 25% | All red | Mixed | All green | | Page weight | 15% | >5MB | 2-5MB | <2MB | | Caching strategy | 15% | None | Partial | Full with immutable | | Render path | 15% | Multiple blockers | Some optimized | Clean critical path | | Image optimization | 10% | Unoptimized | Partially | WebP/AVIF + responsive | | JavaScript health | 10% | >1MB, no splitting | Some splitting | <350KB, code-split | | Third-party control | 5% | Unmanaged | Some deferred | All managed + budgeted | | Mobile experience | 5% | Desktop-only | Responsive | Mobile-first optimized |
Score interpretation:
next/image (auto WebP, lazy, blur placeholder)dynamic() for heavy components@next/bundle-analyzer// Cache-first for static assets
self.addEventListener('fetch', (event) => {
if (event.request.url.match(/\.(css|js|woff2|webp|avif)$/)) {
event.respondWith(
caches.match(event.request).then(cached => cached || fetch(event.request))
);
}
});
// Predictive prefetch on hover
document.querySelectorAll('a').forEach(link => {
link.addEventListener('mouseenter', () => {
const prefetch = document.createElement('link');
prefetch.rel = 'prefetch';
prefetch.href = link.href;
document.head.appendChild(prefetch);
}, { once: true });
});
// Report Core Web Vitals
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Send to analytics
sendToAnalytics({
metric: entry.name,
value: entry.value,
rating: entry.rating, // "good" | "needs-improvement" | "poor"
});
}
}).observe({ type: 'largest-contentful-paint', buffered: true });
Infinite scroll / pagination:
content-visibility: auto for off-screen itemsSPAs with client-side routing:
E-commerce product pages:
Media-heavy sites:
<video> not GIF (90% smaller)tools
Use when the user wants to connect to, test, or use the McDonalds service at mcp.mcd.cn, including checking authentication, probing MCP endpoints, listing tools, or calling McDonalds MCP tools through a reusable local CLI.
development
Web scraping platform — Twitter/X data, Vinted marketplace, and general web scraping API
development
SlowMist AI Agent Security Review — comprehensive security framework for skills, repositories, URLs, on-chain addresses, and products (Claude Code version)
data-ai
去除中文文本中的 AI 写作痕迹,使其读起来自然。基于维基百科 AI 写作特征指南,检测 24 种 AI 模式。触发词:humanizer-cn、去除 AI 痕迹、去除 AI 写作痕迹、中文文本人性化。