multiAI Summary Pending

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).

3,556 stars

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/afrexai-web-performance-engine/SKILL.md --create-dirs "https://raw.githubusercontent.com/openclaw/skills/main/skills/1kalin/afrexai-web-performance-engine/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/afrexai-web-performance-engine/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How Web Performance Engine Compares

Feature / AgentWeb Performance EngineStandard Approach
Platform SupportmultiLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Complete web performance optimization system. Audit, diagnose, fix, and monitor — no external tools required (but integrates with Lighthouse, WebPageTest, Chrome DevTools when available).

Which AI agents support this skill?

This skill is compatible with multi.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# 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 resources
- [ ] Largest Contentful Paint (LCP) > 2.5s → hero element problem
- [ ] Total Blocking Time (TBT) > 200ms → JavaScript problem
- [ ] Cumulative Layout Shift (CLS) > 0.1 → layout instability
- [ ] Interaction to Next Paint (INP) > 200ms → event handler problem

**Tier 2 — Important (affects experience):**
- [ ] Page weight > 2MB
- [ ] Requests > 80
- [ ] JavaScript > 500KB (compressed)
- [ ] Images > 1MB total
- [ ] No compression (gzip/brotli)
- [ ] No caching headers

**Tier 3 — Polish (competitive edge):**
- [ ] Speed Index > 3.4s
- [ ] Time to Interactive > 3.8s
- [ ] Font loading causes flash
- [ ] Third-party scripts > 30% of JS

### Audit Brief Template

```yaml
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
```

### Getting Metrics Without Tools

If no Lighthouse/DevTools available, use web-based tools:
1. `web_fetch "https://pagespeed.web.dev/analysis?url={encoded_url}"` — Google's free tool
2. `web_search "webpagetest {url}"` — find cached results
3. `web_search "site:{domain} core web vitals"` — find CrUX data
4. Check `<head>` for obvious issues: render-blocking CSS/JS, missing preloads, no meta viewport

## Phase 2: Diagnosis — The Performance Waterfall

### Critical Rendering Path Analysis

```
DNS → 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!
```

### Resource Impact Scoring

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.**

## Phase 3: Fix Playbooks

### 3A: Server Optimization (TTFB)

**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:**
- [ ] CDN in front (Cloudflare, Fastly, CloudFront)
- [ ] Brotli compression enabled (20-30% smaller than gzip)
- [ ] HTTP/2 minimum, HTTP/3 if possible
- [ ] Server-side caching (Redis, Varnish)
- [ ] Database query optimization (<50ms per query)
- [ ] Connection pooling enabled
- [ ] Edge computing for dynamic content (Workers, Lambda@Edge)

**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
```

### 3B: Render-Blocking Resources (FCP)

**CSS optimization:**
```html
<!-- 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:**
- Inline critical CSS (above-fold styles, < 14KB)
- Defer non-critical CSS
- Remove unused CSS (typical savings: 60-90%)
- Combine media queries
- Avoid `@import` (creates sequential loading)

**JavaScript optimization:**
```html
<!-- 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)
- Never put `<script>` in `<head>` without defer/async
- Inline small scripts (< 1KB)

### 3C: Hero Element Optimization (LCP)

**LCP 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:**
```html
<!-- 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 |

### 3D: JavaScript Optimization (TBT)

**Bundle analysis approach:**
1. Check total JS size: `web_fetch` the page, count `<script>` tags
2. Identify large libraries (React, Lodash, Moment.js)
3. Check for duplicate code across bundles
4. Identify unused exports

**Common 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:**
- Route-based splitting (each page loads its own JS)
- Component-level splitting for heavy components (modals, editors, charts)
- Dynamic import for below-fold features: `const Chart = lazy(() => import('./Chart'))`
- Vendor chunk for stable dependencies (changes rarely = long cache)

**Long task breaking:**
```javascript
// 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();
    }
  }
}
```

### 3E: Layout Stability (CLS)

**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:**
```css
/* 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;
}
```

### 3F: Interaction Optimization (INP)

**Event handler rules:**
- Keep handlers < 50ms
- Debounce scroll/resize (100-150ms)
- Use `requestAnimationFrame` for visual updates
- Offload heavy computation to Web Workers
- Use `content-visibility: auto` for off-screen content

**Input responsiveness:**
```javascript
// 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);
});
```

## Phase 4: Resource Loading Strategy

### Preload / Prefetch / Preconnect Decision

```html
<!-- 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:**
- Max 3-5 preloads per page (more = competing priorities)
- Always preload: LCP image, critical font, above-fold CSS
- Preconnect to known third-party origins (max 4-6)
- Prefetch only on fast connections

### Lazy Loading Strategy

```
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
```

### Font Loading Optimization

```css
/* 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:**
- [ ] WOFF2 format only (best compression)
- [ ] Subset fonts (Latin, extended only if needed)
- [ ] Max 2-3 font families
- [ ] Max 4 font files total (regular, bold, italic, bold-italic)
- [ ] Preload critical font files
- [ ] Consider system font stack for body text

**System font stacks:**
```css
/* 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;
```

## Phase 5: Third-Party Script Management

### Impact Assessment

```yaml
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:**
```javascript
// 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:**
- Audit ALL third-party scripts quarterly
- Every script needs a business justification
- If a script loads >100KB, it needs a loading strategy
- Self-host what you can (fonts, analytics alternatives)
- Use `rel="noopener"` on all external links

## Phase 6: Mobile Performance

### Mobile-Specific Optimization

**Targets (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:**
- [ ] Viewport meta tag present
- [ ] Touch targets ≥ 48×48px
- [ ] No horizontal scroll
- [ ] Images responsive (srcset + sizes)
- [ ] JS budget < 300KB (compressed) on mobile
- [ ] Critical CSS < 14KB (fits in first TCP round trip)
- [ ] Avoid complex CSS (heavy animations, large box-shadows)

## Phase 7: Performance Budget

### Setting Budgets

```yaml
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:**
- Any PR that increases JS by >10KB needs justification
- LCP regression > 200ms blocks deploy
- Monthly Lighthouse audit — track trend
- Per-route budgets for SPAs (homepage stricter than admin)

### Budget Monitoring Template

```yaml
# 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: []
```

## Phase 8: Performance Scoring Rubric

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:**
- 90-100: Elite. Maintain and iterate.
- 70-89: Good. Fix the weakest dimension.
- 50-69: Needs work. Follow Phase 3 playbooks.
- <50: Critical. Start with server + render-blocking fixes.

## Phase 9: Common Architectures — Quick Wins

### Next.js / React
- Use `next/image` (auto WebP, lazy, blur placeholder)
- Enable ISR or SSG for static pages
- Use `dynamic()` for heavy components
- Check bundle with `@next/bundle-analyzer`
- Middleware for edge caching

### WordPress
- Page cache plugin (WP Super Cache, W3 Total Cache)
- Image optimization (ShortPixel, Imagify)
- Disable unused plugins (each adds JS+CSS)
- Use a CDN plugin
- Consider static generation (Simply Static)

### SPA (React/Vue/Svelte)
- Route-based code splitting (mandatory)
- SSR or SSG for SEO pages
- Service worker for repeat visits
- Skeleton screens (not spinners)
- Virtual scrolling for long lists

### Static Sites
- Already fast — focus on image optimization
- Deploy to CDN edge (Cloudflare Pages, Netlify, Vercel)
- Inline all critical CSS
- Minimal JS (< 50KB)

## Phase 10: Advanced Techniques

### Service Worker Caching

```javascript
// 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))
    );
  }
});
```

### Resource Hints for Navigation

```javascript
// 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 });
});
```

### Performance Monitoring in Production

```javascript
// 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 });
```

### Edge Cases

**Infinite scroll / pagination:**
- Virtual scrolling for >100 items
- Intersection Observer to load batches
- `content-visibility: auto` for off-screen items
- Memory management: remove far-off-screen DOM nodes

**SPAs with client-side routing:**
- Measure soft navigations (not just initial load)
- Report per-route metrics
- Prefetch likely next routes
- Keep route JS < 100KB each

**E-commerce product pages:**
- Preload first product image
- Lazy load review section, related products
- Defer recommendation engine JS
- Cache product data with stale-while-revalidate

**Media-heavy sites:**
- Lazy load everything below fold
- Use `<video>` not GIF (90% smaller)
- Adaptive quality based on connection (Network Information API)
- Progressive JPEG for large photos

## Natural Language Commands

- "Audit {url}" → Run full Phase 1 audit
- "Fix LCP on {url}" → Phase 3C playbook
- "What's slowing down {url}?" → Phase 2 diagnosis tree
- "Set performance budget for {project}" → Phase 7 template
- "Score {url}" → Phase 8 rubric
- "Optimize images on {url}" → Phase 3C image checklist
- "Reduce JavaScript on {url}" → Phase 3D JS optimization
- "Fix layout shifts on {url}" → Phase 3E CLS playbook
- "Mobile performance audit for {url}" → Phase 6
- "Third-party script audit for {url}" → Phase 5
- "Weekly performance check for {url}" → Phase 7 monitoring template
- "Compare {url1} vs {url2}" → Side-by-side audit