Skip to content
Beta Multi-model support (OpenAI, Gemini, and more) launching soon.

perf-asset-optimisation

Installable Ships in performance-auditor — or copy the raw skill below.
Open Claude.ai

Paste into Claude Code, Claude.ai, the desktop app, or the browser extension — ⌘/Ctrl+V.

ExperimentalNo security review

Asset Optimisation Review

Audit images, video, fonts, and static assets for format, compression, sizing, and delivery pipeline gaps. Every unoptimised asset on the LCP critical path can cost 0.5–2 s.

Usage

/perf-asset-optimisation <URL or project-root-path> [--platform sitecore|optimizely|umbraco|headless]

Phase 1 — Asset Inventory

URL mode

From the Lighthouse network-requests audit, filter assets by type:

images:  .jpg .jpeg .png .gif .webp .avif .svg
video:   .mp4 .webm .ogv
fonts:   .woff .woff2 .ttf .eot
scripts: .js .mjs
styles:  .css
other:   .json .xml data URIs

For each image: record URL, transferred size, decoded size, Content-Type, and cache headers.

Source mode

Scan project for image references:

grep -r "src=" --include="*.tsx" --include="*.jsx" --include="*.html" --include="*.cshtml" \
  --include="*.astro" . | grep -E "\.(jpg|jpeg|png|gif|webp|avif|svg)"

Phase 2 — Image Audit

2.1 Format selection

Current format Replace with Typical savings When NOT to convert
JPEG (photos) WebP 25–35% IE11 (if still supported — check requirements)
JPEG (photos, high quality) AVIF 40–50% Older iOS (< 16) — check analytics
PNG (transparency) WebP 20–35% Complex transparency on old browsers
PNG (opaque, photo) WebP or JPEG 30–50% Never — always prefer compressed format
GIF (animated) <video autoplay loop muted playsinline> 60–80% N/A
SVG Keep SVG N/A SVGs are already vector/optimised

2.2 Responsive images

Every image that renders at different sizes across breakpoints should use srcset + sizes:

<!-- Missing responsive variants — serves 1200 px image to a 375 px screen -->
<img src="/hero.webp" alt="Hero">

<!-- Correct: browser picks the best-fit variant -->
<img
  src="/hero-800.webp"
  srcset="/hero-400.webp 400w, /hero-800.webp 800w, /hero-1200.webp 1200w, /hero-1920.webp 1920w"
  sizes="(max-width: 768px) 100vw, (max-width: 1280px) 50vw, 1200px"
  alt="Hero"
  width="1200"
  height="600"
>

Flag images where Lighthouse uses-responsive-images shows potential savings > 50 KB.

2.3 Lazy loading

All images below the fold must have loading="lazy". All LCP candidate images must NOT have loading="lazy" (it delays the LCP resource discovery):

<!-- Hero / LCP candidate — eager load + high priority -->
<img src="/hero.webp" loading="eager" fetchpriority="high" width="1440" height="680" alt="Hero">

<!-- Below-fold images — lazy load -->
<img src="/card-thumb.webp" loading="lazy" width="400" height="300" alt="Article thumbnail">

2.4 CLS-safe sizing

Every <img> and <video> must have explicit width and height attributes OR aspect-ratio CSS. Missing dimensions = CLS risk.

<!-- Missing dimensions = CLS -->
<img src="/product.webp" alt="Product">

<!-- Explicit dimensions = browser reserves space before image loads -->
<img src="/product.webp" alt="Product" width="600" height="400">

<!-- Or CSS aspect-ratio (useful for fluid/responsive images) -->
<style>
.product-img { aspect-ratio: 3 / 2; width: 100%; }
</style>
<img class="product-img" src="/product.webp" alt="Product">

2.5 Platform-specific image delivery

Sitecore XM Cloud / Media Library

  • Is the Media Library CDN URL configured? (/~/media/ should resolve to a CDN edge URL, not origin.)
  • Check if Sitecore JSS is using next/image with sitecorecloud.io in remotePatterns.
  • For media items: are Width and Height fields populated? Affects CLS and correct srcset generation.
  • SXA Media Handler: confirm WebP output is configured on the media handler pipeline.

Optimizely Content Cloud / DXP

  • Is the ImageResizer / EPiServer.ImageSharpGlobal package installed?
  • Are image URLs including format query params (?format=webp&width=800)?
  • DXP CDN: are /globalassets/ and /contentassets/ paths cached at the edge?

Umbraco

  • Is Umbraco.Cms.Imaging.ImageSharp configured with WebP output enabled?
    // appsettings.json
    "Umbraco": {
      "CMS": {
        "Imaging": {
          "Cache": { "BrowserMaxAge": "7.00:00:00" },
          "Resize": { "MaxWidth": 5000, "MaxHeight": 5000 }
        }
      }
    }
    
  • Are ImageSharp crop presets defined for common breakpoints?
  • Is the /media/ path covered by Azure CDN / Front Door caching rules?

Next.js (headless)

  • Are all images going through next/image? Bypassed images miss WebP negotiation and lazy load.
  • Is images.formats set to ['image/avif', 'image/webp'] in next.config.js?
  • Are remotePatterns limited to known CMS domains (not hostname: '*')?

Phase 3 — Video Audit

3.1 Replace GIFs with video

<!-- Before: 2.4 MB GIF, blocking, no pause control -->
<img src="/animation.gif" alt="Animation">

<!-- After: 420 KB WebM + 560 KB MP4 fallback, hardware-decoded, no autoplay jank -->
<video autoplay loop muted playsinline width="800" height="450">
  <source src="/animation.webm" type="video/webm">
  <source src="/animation.mp4" type="video/mp4">
</video>

3.2 Video loading strategy

  • Background/hero videos: use preload="none" + poster image to prevent bandwidth waste on mobile.
  • LCP video: use preload="metadata" and poster to avoid CLS.
  • Never autoplay with sound (triggers browser blocking in Chrome/Firefox).
<video
  preload="metadata"
  poster="/hero-poster.webp"
  autoplay loop muted playsinline
  width="1440" height="810"
>
  <source src="/hero.webm" type="video/webm">
  <source src="/hero.mp4" type="video/mp4">
</video>

Phase 4 — Font Asset Audit

4.1 Font file inventory

List all font files loaded. For each:

  • Format: woff2 preferred; woff acceptable; ttf/eot = outdated (flag)
  • Weights/variants loaded vs. weights/variants used — excess variants waste bandwidth
  • Subset needed: if only Latin characters are used, a Latin subset saves 40–60% vs. full Unicode

4.2 System font fallback stack

For each custom font, check that the font-family stack includes a system fallback:

/* Without fallback — FOUT leaves unstyled text until font loads */
font-family: 'Inter', sans-serif;

/* With size-adjusted fallback — reduces CLS from FOUT reflow */
@font-face {
  font-family: 'Inter-Fallback';
  src: local('Arial');
  size-adjust: 96%;  /* tune to match your custom font's metrics */
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}
font-family: 'Inter', 'Inter-Fallback', sans-serif;

Phase 5 — Static Asset Delivery Check

For scripts and stylesheets, verify:

  1. Compression: Are responses served with Content-Encoding: br (Brotli) or gzip?

    • Brotli gives ~15–20% better compression than gzip for text assets.
    • Flag if large assets (> 50 KB) lack compression.
  2. Cache headers: Are static assets served with long TTLs + fingerprinted filenames? See perf-caching-review for the full cache audit.

  3. HTTP/2 or HTTP/3: Is the origin serving over HTTP/2+ for multiplexed requests? HTTP/1.1 with many assets = connection queue bottleneck.


Phase 6 — Report

## Asset Optimisation Report

**URL / Path:** [target]
**Platform:** [detected/specified]

### Asset Summary
| Type | Count | Total transferred | Potential savings |
|---|---|---|---|
| Images | N | XX KB | XX KB |
| Video | N | XX KB | XX KB |
| Fonts | N | XX KB | XX KB |
| Scripts | N | XX KB | XX KB |
| Styles | N | XX KB | XX KB |

### Findings (ranked by impact)
[findings]

### Quick Wins
[list]

Quality Checklist

  • LCP image identified; fetchpriority="high" and loading="eager" checked
  • All below-fold images have loading="lazy"
  • All images have width + height or aspect-ratio (CLS safety)
  • GIFs identified and flagged for video replacement
  • Font format: all woff2; no ttf/eot in production
  • Platform media delivery pipeline configuration checked
  • Brotli/gzip compression verified on at least the top 5 assets by size
Technical details
Plugin
performance-auditor
Author
Dakota Smith
Skill name
perf-asset-optimisation
Maturity
experimental
Security review
No security review
Owners
  • engineering
Argument hint
<URL or project-root-path> [--platform sitecore|optimizely|umbraco|headless]
Allowed tools
  • Read
  • Write
  • Glob
  • Grep
  • Bash(npx lighthouse *)
  • Bash(node *)
  • Bash(cat *)
  • Bash(ls *)
  • WebFetch(domain:localhost)
  • WebFetch(domain:web.dev)
Source
plugins/performance-auditor/skills/perf-asset-optimisation/SKILL.md

Edit this skill on GitHub — opens GitHub's web editor. No git knowledge needed.