plugins/frontend-toolkit/skills/rendering-performance/SKILL.md
Diagnose and fix Core Web Vitals (LCP ≤ 2.5s, INP ≤ 200ms, CLS ≤ 0.1) with measurement-first methodology. Use when Lighthouse drops, CWV field data fails, users report slowness, or before shipping. Not for when JS payload is the bottleneck (use bundle-optimization) or moving work to the server (use render-strategy-decision).
npx skillsauth add jaykim88/claude-ai-engineering rendering-performanceInstall 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.
Achieve and sustain Core Web Vitals targets through measure-then-fix discipline. Never guess at optimization — measure first, fix specifically, verify the metric moved.
Universal — Core Web Vitals (LCP / INP / CLS) are browser-level metrics, identical for every framework. The diagnose-then-fix order and fix categories (image priority, font display, JS payload reduction, virtualization) apply everywhere; only tool names differ.
Measure first — never optimize blind
web-vitals library and report LCP / INP / CLS to analyticsLCP fixes (target ≤ 2.5s)
display: swap/optional), inline above-fold CSS, server-render the element (not client-only).render-strategy-decision / api-caching-optimization.unload (use pagehide), no Cache-Control: no-store on the document. Verify in DevTools → Application → Back/forward cache.prerender.INP fixes (target ≤ 200ms)
web-vitals/attribution + LoAF (Long Animation Frames) pinpoint the exact script/phase; React DevTools Profiler → find Long Tasks (50ms+).startTransition / useDeferredValue), break long tasks (scheduler.yield()), push work to idle (requestIdleCallback) / a Web Worker / the server (Server Components), and cut initial JS (see bundle-optimization).useDeferredValue); oversized Client Components hydrating (shrink the 'use client' boundary).CLS fixes (target ≤ 0.1) — reserve space for anything that loads late: explicit width/height (or aspect-ratio) on media, skeletons sized to the final content, font-display: optional, slots for ads/embeds. Rule: never let late content push layout.
Lists with 1000+ items → virtualize
react-window or TanStack VirtualCut unnecessary work per update (cause first, memoize last)
state-management-decisions)Verify after each fix (validation loop)
| Tier | Examples | Action SLA | |---|---|---| | Critical | LCP > 4s, INP > 500ms, CLS > 0.25 (p75 field data) | Block release; fix immediately | | Major | LCP 2.5-4s, INP 200-500ms, CLS 0.1-0.25 | Fix this sprint | | Minor | All CWV targets met; room to improve (e.g., 2.0s LCP could be 1.5s) | Schedule within 2 sprints |
docs/perf-audit-YYYY-MM-DD.md with sections:
## Summary — LCP / INP / CLS before & after (lab + field)## Critical/Major/Minor findings per severity tier## Fixes applied — per fix: metric affected, change, before/after measurementperf(<metric>): <description> (e.g., perf(LCP): add fetchpriority to hero image)docs/lighthouse-YYYY-MM-DD-{before,after}.jsonnext/image with priority + fetchpriority="high" for LCP elementnext/font with display: 'swap' or 'optional'startTransition / useDeferredValue; scheduler.yield() for long tasks; requestIdleCallback for analytics; Web WorkersReact.memo / useCallback / useMemo — only after Profiler proves costreact-window or TanStack Virtual<NuxtImg> (with format="webp" and priority); useFetch for server work; defineAsyncComponent for code splitting; virtualization via vue-virtual-scrollerenhanced:img Vite plugin (Vite 5+); +server.ts for server work; Svelte 5 fine-grained reactivity reduces unnecessary updates; virtualization via svelte-virtual-list<NgOptimizedImage> with priority; signal() and effect() instead of RxJS for fine-grained updates; CDK Virtual Scrollweb-vitals library is framework-agnostic; Lighthouse / PageSpeed Insights audits any URL; LoAF API works in any browserbundle-optimization — when JS payload is the LCP/INP bottleneckrender-strategy-decision — when the fix is moving work to the serveranimation-quality — when animation jank is causing INP regressionweb-vitals library in the field before optimizing, then apply LCP / INP / CLS fixes as separate playbooks. Field data > lab data: lab Lighthouse can mislead on real-user variability, especially INP which depends on actual interaction patterns.development
Audit and optimize third-party scripts — analytics, tag managers, chat widgets, embeds — with the right loading strategy, performance budget, facades, and CSP/consent controls. Use when adding a script, when TBT/INP regress, when a GDPR/CCPA consent requirement arises, or before shipping. Not for first-party bundle size (use bundle-optimization) or broad Core Web Vitals diagnosis (use rendering-performance).
development
Apply the Testing Trophy (mostly integration tests with RTL + MSW, sparing E2E with Playwright) and set coverage thresholds. Use before new feature work, after bug fixes, when CI coverage falls below target, or when tests are flaky or break on every refactor. Not for wiring coverage gates + Playwright into the GitHub Actions matrix (use cicd-pipeline) or auditing WCAG a11y compliance (use accessibility-audit).
development
Inventory and prioritize technical debt — TODO/FIXME/HACK, any usage, deprecated APIs, untested logic — with impact × effort matrix. Use at quarter start, before a refactoring sprint, when a new teammate joins, or when feature velocity slows. Not for actually paying down debt (use code-refactoring) or recording a migration approach (use decision-records) — this only inventories and prioritizes.
development
Decision framework for choosing the right state location — URL, server cache, local component, or shared/global store. Use when state-sync bugs appear, prop drilling gets deep (3+ levels), filters/tabs lose state on reload, or quarterly review. Not for form state specifically (use form-ux) or when the state is actually server data (use api-caching-optimization).