[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6AEG9R8R7Q8BKBACHRR4DVQ":3,"skill-same:01M6AEG9R8R7Q8BKBACHRR4DVQ":75},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":37,"linkOnly":38,"markdownContent":39,"markdownBody":40,"frontMatter":41,"refName":45,"commitSha":46,"skillDirectory":47,"forksCount":48,"repositoryHtmlUrl":49,"repositoryHomepageUrl":50,"ownerHtmlUrl":51,"ownerBlogUrl":52,"ownerDescription":53,"updatedAt":54,"install":55,"resources":68},"01M6AEG9R8R7Q8BKBACHRR4DVQ","core-web-vitals",null,"Optimize Core Web Vitals (LCP, INP, CLS) for better page experience and search ranking. Use when asked to \"improve Core Web Vitals\", \"fix LCP\", \"reduce CLS\", \"optimize INP\", \"page experience optimization\", or \"fix layout shifts\".","davila7\u002Fclaude-code-templates","davila7","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6216945?v=4","01M6ADEWWFPS191NFM0Y1EX1JH","Daniel Avila","01M6ADJHGM78PHQRD3XZTFDVKK",33481,"MIT","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fdevelopment\u002Fcore-web-vitals\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36],"core","web","vitals","core web vitals","web vitals","when","reduce","for","ranking","layout","optimize","use","fix","quality","page","improve","Optimization","search","2026-11-10 10:12:30",false,"---\nname: core-web-vitals\ndescription: Optimize Core Web Vitals (LCP, INP, CLS) for better page experience and search ranking. Use when asked to \"improve Core Web Vitals\", \"fix LCP\", \"reduce CLS\", \"optimize INP\", \"page experience optimization\", or \"fix layout shifts\".\nlicense: MIT\nmetadata:\n  author: web-quality-skills\n  version: \"1.0\"\n---\n\n# Core Web Vitals optimization\n\nTargeted optimization for the three Core Web Vitals metrics that affect Google Search ranking and user experience.\n\n## The three metrics\n\n| Metric | Measures | Good | Needs work | Poor |\n|--------|----------|------|------------|------|\n| **LCP** | Loading | ≤ 2.5s | 2.5s – 4s | > 4s |\n| **INP** | Interactivity | ≤ 200ms | 200ms – 500ms | > 500ms |\n| **CLS** | Visual Stability | ≤ 0.1 | 0.1 – 0.25 | > 0.25 |\n\nGoogle measures at the **75th percentile** — 75% of page visits must meet \"Good\" thresholds.\n\n---\n\n## LCP: Largest Contentful Paint\n\nLCP measures when the largest visible content element renders. Usually this is:\n- Hero image or video\n- Large text block\n- Background image\n- `\u003Csvg>` element\n\n### Common LCP issues\n\n**1. Slow server response (TTFB > 800ms)**\n```\nFix: CDN, caching, optimized backend, edge rendering\n```\n\n**2. Render-blocking resources**\n```html\n\u003C!-- ❌ Blocks rendering -->\n\u003Clink rel=\"stylesheet\" href=\"\u002Fall-styles.css\">\n\n\u003C!-- ✅ Critical CSS inlined, rest deferred -->\n\u003Cstyle>\u002F* Critical above-fold CSS *\u002F\u003C\u002Fstyle>\n\u003Clink rel=\"preload\" href=\"\u002Fstyles.css\" as=\"style\" \n      onload=\"this.onload=null;this.rel='stylesheet'\">\n```\n\n**3. Slow resource load times**\n```html\n\u003C!-- ❌ No hints, discovered late -->\n\u003Cimg src=\"\u002Fhero.jpg\" alt=\"Hero\">\n\n\u003C!-- ✅ Preloaded with high priority -->\n\u003Clink rel=\"preload\" href=\"\u002Fhero.webp\" as=\"image\" fetchpriority=\"high\">\n\u003Cimg src=\"\u002Fhero.webp\" alt=\"Hero\" fetchpriority=\"high\">\n```\n\n**4. Client-side rendering delays**\n```javascript\n\u002F\u002F ❌ Content loads after JavaScript\nuseEffect(() => {\n  fetch('\u002Fapi\u002Fhero-text').then(r => r.json()).then(setHeroText);\n}, []);\n\n\u002F\u002F ✅ Server-side or static rendering\n\u002F\u002F Use SSR, SSG, or streaming to send HTML with content\nexport async function getServerSideProps() {\n  const heroText = await fetchHeroText();\n  return { props: { heroText } };\n}\n```\n\n### LCP optimization checklist\n\n```markdown\n- [ ] TTFB \u003C 800ms (use CDN, edge caching)\n- [ ] LCP image preloaded with fetchpriority=\"high\"\n- [ ] LCP image optimized (WebP\u002FAVIF, correct size)\n- [ ] Critical CSS inlined (\u003C 14KB)\n- [ ] No render-blocking JavaScript in \u003Chead>\n- [ ] Fonts don't block text rendering (font-display: swap)\n- [ ] LCP element in initial HTML (not JS-rendered)\n```\n\n### LCP element identification\n```javascript\n\u002F\u002F Find your LCP element\nnew PerformanceObserver((list) => {\n  const entries = list.getEntries();\n  const lastEntry = entries[entries.length - 1];\n  console.log('LCP element:', lastEntry.element);\n  console.log('LCP time:', lastEntry.startTime);\n}).observe({ type: 'largest-contentful-paint', buffered: true });\n```\n\n---\n\n## INP: Interaction to Next Paint\n\nINP measures responsiveness across ALL interactions (clicks, taps, key presses) during a page visit. It reports the worst interaction (at 98th percentile for high-traffic pages).\n\n### INP breakdown\n\nTotal INP = **Input Delay** + **Processing Time** + **Presentation Delay**\n\n| Phase | Target | Optimization |\n|-------|--------|--------------|\n| Input Delay | \u003C 50ms | Reduce main thread blocking |\n| Processing | \u003C 100ms | Optimize event handlers |\n| Presentation | \u003C 50ms | Minimize rendering work |\n\n### Common INP issues\n\n**1. Long tasks blocking main thread**\n```javascript\n\u002F\u002F ❌ Long synchronous task\nfunction processLargeArray(items) {\n  items.forEach(item => expensiveOperation(item));\n}\n\n\u002F\u002F ✅ Break into chunks with yielding\nasync function processLargeArray(items) {\n  const CHUNK_SIZE = 100;\n  for (let i = 0; i \u003C items.length; i += CHUNK_SIZE) {\n    const chunk = items.slice(i, i + CHUNK_SIZE);\n    chunk.forEach(item => expensiveOperation(item));\n    \n    \u002F\u002F Yield to main thread\n    await new Promise(r => setTimeout(r, 0));\n    \u002F\u002F Or use scheduler.yield() when available\n  }\n}\n```\n\n**2. Heavy event handlers**\n```javascript\n\u002F\u002F ❌ All work in handler\nbutton.addEventListener('click', () => {\n  \u002F\u002F Heavy computation\n  const result = calculateComplexThing();\n  \u002F\u002F DOM updates\n  updateUI(result);\n  \u002F\u002F Analytics\n  trackEvent('click');\n});\n\n\u002F\u002F ✅ Prioritize visual feedback\nbutton.addEventListener('click', () => {\n  \u002F\u002F Immediate visual feedback\n  button.classList.add('loading');\n  \n  \u002F\u002F Defer non-critical work\n  requestAnimationFrame(() => {\n    const result = calculateComplexThing();\n    updateUI(result);\n  });\n  \n  \u002F\u002F Use requestIdleCallback for analytics\n  requestIdleCallback(() => trackEvent('click'));\n});\n```\n\n**3. Third-party scripts**\n```javascript\n\u002F\u002F ❌ Eagerly loaded, blocks interactions\n\u003Cscript src=\"https:\u002F\u002Fheavy-widget.com\u002Fwidget.js\">\u003C\u002Fscript>\n\n\u002F\u002F ✅ Lazy loaded on interaction or visibility\nconst loadWidget = () => {\n  import('https:\u002F\u002Fheavy-widget.com\u002Fwidget.js')\n    .then(widget => widget.init());\n};\nbutton.addEventListener('click', loadWidget, { once: true });\n```\n\n**4. Excessive re-renders (React\u002FVue)**\n```javascript\n\u002F\u002F ❌ Re-renders entire tree\nfunction App() {\n  const [count, setCount] = useState(0);\n  return (\n    \u003Cdiv>\n      \u003CCounter count={count} \u002F>\n      \u003CExpensiveComponent \u002F> {\u002F* Re-renders on every count change *\u002F}\n    \u003C\u002Fdiv>\n  );\n}\n\n\u002F\u002F ✅ Memoized expensive components\nconst MemoizedExpensive = React.memo(ExpensiveComponent);\n\nfunction App() {\n  const [count, setCount] = useState(0);\n  return (\n    \u003Cdiv>\n      \u003CCounter count={count} \u002F>\n      \u003CMemoizedExpensive \u002F>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n### INP optimization checklist\n\n```markdown\n- [ ] No tasks > 50ms on main thread\n- [ ] Event handlers complete quickly (\u003C 100ms)\n- [ ] Visual feedback provided immediately\n- [ ] Heavy work deferred with requestIdleCallback\n- [ ] Third-party scripts don't block interactions\n- [ ] Debounced input handlers where appropriate\n- [ ] Web Workers for CPU-intensive operations\n```\n\n### INP debugging\n```javascript\n\u002F\u002F Identify slow interactions\nnew PerformanceObserver((list) => {\n  for (const entry of list.getEntries()) {\n    if (entry.duration > 200) {\n      console.warn('Slow interaction:', {\n        type: entry.name,\n        duration: entry.duration,\n        processingStart: entry.processingStart,\n        processingEnd: entry.processingEnd,\n        target: entry.target\n      });\n    }\n  }\n}).observe({ type: 'event', buffered: true, durationThreshold: 16 });\n```\n\n---\n\n## CLS: Cumulative Layout Shift\n\nCLS measures unexpected layout shifts. A shift occurs when a visible element changes position between frames without user interaction.\n\n**CLS Formula:** `impact fraction × distance fraction`\n\n### Common CLS causes\n\n**1. Images without dimensions**\n```html\n\u003C!-- ❌ Causes layout shift when loaded -->\n\u003Cimg src=\"photo.jpg\" alt=\"Photo\">\n\n\u003C!-- ✅ Space reserved -->\n\u003Cimg src=\"photo.jpg\" alt=\"Photo\" width=\"800\" height=\"600\">\n\n\u003C!-- ✅ Or use aspect-ratio -->\n\u003Cimg src=\"photo.jpg\" alt=\"Photo\" style=\"aspect-ratio: 4\u002F3; width: 100%;\">\n```\n\n**2. Ads, embeds, and iframes**\n```html\n\u003C!-- ❌ Unknown size until loaded -->\n\u003Ciframe src=\"https:\u002F\u002Fad-network.com\u002Fad\">\u003C\u002Fiframe>\n\n\u003C!-- ✅ Reserve space with min-height -->\n\u003Cdiv style=\"min-height: 250px;\">\n  \u003Ciframe src=\"https:\u002F\u002Fad-network.com\u002Fad\" height=\"250\">\u003C\u002Fiframe>\n\u003C\u002Fdiv>\n\n\u003C!-- ✅ Or use aspect-ratio container -->\n\u003Cdiv style=\"aspect-ratio: 16\u002F9;\">\n  \u003Ciframe src=\"https:\u002F\u002Fyoutube.com\u002Fembed\u002F...\" \n          style=\"width: 100%; height: 100%;\">\u003C\u002Fiframe>\n\u003C\u002Fdiv>\n```\n\n**3. Dynamically injected content**\n```javascript\n\u002F\u002F ❌ Inserts content above viewport\nnotifications.prepend(newNotification);\n\n\u002F\u002F ✅ Insert below viewport or use transform\nconst insertBelow = viewport.bottom \u003C newNotification.top;\nif (insertBelow) {\n  notifications.prepend(newNotification);\n} else {\n  \u002F\u002F Animate in without shifting\n  newNotification.style.transform = 'translateY(-100%)';\n  notifications.prepend(newNotification);\n  requestAnimationFrame(() => {\n    newNotification.style.transform = '';\n  });\n}\n```\n\n**4. Web fonts causing FOUT**\n```css\n\u002F* ❌ Font swap shifts text *\u002F\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n}\n\n\u002F* ✅ Optional font (no shift if slow) *\u002F\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n  font-display: optional;\n}\n\n\u002F* ✅ Or match fallback metrics *\u002F\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n  font-display: swap;\n  size-adjust: 105%; \u002F* Match fallback size *\u002F\n  ascent-override: 95%;\n  descent-override: 20%;\n}\n```\n\n**5. Animations triggering layout**\n```css\n\u002F* ❌ Animates layout properties *\u002F\n.animate {\n  transition: height 0.3s, width 0.3s;\n}\n\n\u002F* ✅ Use transform instead *\u002F\n.animate {\n  transition: transform 0.3s;\n}\n.animate.expanded {\n  transform: scale(1.2);\n}\n```\n\n### CLS optimization checklist\n\n```markdown\n- [ ] All images have width\u002Fheight or aspect-ratio\n- [ ] All videos\u002Fembeds have reserved space\n- [ ] Ads have min-height containers\n- [ ] Fonts use font-display: optional or matched metrics\n- [ ] Dynamic content inserted below viewport\n- [ ] Animations use transform\u002Fopacity only\n- [ ] No content injected above existing content\n```\n\n### CLS debugging\n```javascript\n\u002F\u002F Track layout shifts\nnew PerformanceObserver((list) => {\n  for (const entry of list.getEntries()) {\n    if (!entry.hadRecentInput) {\n      console.log('Layout shift:', entry.value);\n      entry.sources?.forEach(source => {\n        console.log('  Shifted element:', source.node);\n        console.log('  Previous rect:', source.previousRect);\n        console.log('  Current rect:', source.currentRect);\n      });\n    }\n  }\n}).observe({ type: 'layout-shift', buffered: true });\n```\n\n---\n\n## Measurement tools\n\n### Lab testing\n- **Chrome DevTools** → Performance panel, Lighthouse\n- **WebPageTest** → Detailed waterfall, filmstrip\n- **Lighthouse CLI** → `npx lighthouse \u003Curl>`\n\n### Field data (real users)\n- **Chrome User Experience Report (CrUX)** → BigQuery or API\n- **Search Console** → Core Web Vitals report\n- **web-vitals library** → Send to your analytics\n\n```javascript\nimport {onLCP, onINP, onCLS} from 'web-vitals';\n\nfunction sendToAnalytics({name, value, rating}) {\n  gtag('event', name, {\n    event_category: 'Web Vitals',\n    value: Math.round(name === 'CLS' ? value * 1000 : value),\n    event_label: rating\n  });\n}\n\nonLCP(sendToAnalytics);\nonINP(sendToAnalytics);\nonCLS(sendToAnalytics);\n```\n\n---\n\n## Framework quick fixes\n\n### Next.js\n```jsx\n\u002F\u002F LCP: Use next\u002Fimage with priority\nimport Image from 'next\u002Fimage';\n\u003CImage src=\"\u002Fhero.jpg\" priority fill alt=\"Hero\" \u002F>\n\n\u002F\u002F INP: Use dynamic imports\nconst HeavyComponent = dynamic(() => import('.\u002FHeavy'), { ssr: false });\n\n\u002F\u002F CLS: Image component handles dimensions automatically\n```\n\n### React\n```jsx\n\u002F\u002F LCP: Preload in head\n\u003Clink rel=\"preload\" href=\"\u002Fhero.jpg\" as=\"image\" fetchpriority=\"high\" \u002F>\n\n\u002F\u002F INP: Memoize and useTransition\nconst [isPending, startTransition] = useTransition();\nstartTransition(() => setExpensiveState(newValue));\n\n\u002F\u002F CLS: Always specify dimensions in img tags\n```\n\n### Vue\u002FNuxt\n```vue\n\u003C!-- LCP: Use nuxt\u002Fimage with preload -->\n\u003CNuxtImg src=\"\u002Fhero.jpg\" preload loading=\"eager\" \u002F>\n\n\u003C!-- INP: Use async components -->\n\u003Ccomponent :is=\"() => import('.\u002FHeavy.vue')\" \u002F>\n\n\u003C!-- CLS: Use aspect-ratio CSS -->\n\u003Cimg :style=\"{ aspectRatio: '16\u002F9' }\" \u002F>\n```\n\n## References\n\n- [web.dev LCP](https:\u002F\u002Fweb.dev\u002Farticles\u002Flcp)\n- [web.dev INP](https:\u002F\u002Fweb.dev\u002Farticles\u002Finp)\n- [web.dev CLS](https:\u002F\u002Fweb.dev\u002Farticles\u002Fcls)\n- [Performance skill](..\u002Fperformance\u002FSKILL.md)\n","# Core Web Vitals optimization\n\nTargeted optimization for the three Core Web Vitals metrics that affect Google Search ranking and user experience.\n\n## The three metrics\n\n| Metric | Measures | Good | Needs work | Poor |\n|--------|----------|------|------------|------|\n| **LCP** | Loading | ≤ 2.5s | 2.5s – 4s | > 4s |\n| **INP** | Interactivity | ≤ 200ms | 200ms – 500ms | > 500ms |\n| **CLS** | Visual Stability | ≤ 0.1 | 0.1 – 0.25 | > 0.25 |\n\nGoogle measures at the **75th percentile** — 75% of page visits must meet \"Good\" thresholds.\n\n---\n\n## LCP: Largest Contentful Paint\n\nLCP measures when the largest visible content element renders. Usually this is:\n- Hero image or video\n- Large text block\n- Background image\n- `\u003Csvg>` element\n\n### Common LCP issues\n\n**1. Slow server response (TTFB > 800ms)**\n```\nFix: CDN, caching, optimized backend, edge rendering\n```\n\n**2. Render-blocking resources**\n```html\n\u003C!-- ❌ Blocks rendering -->\n\u003Clink rel=\"stylesheet\" href=\"\u002Fall-styles.css\">\n\n\u003C!-- ✅ Critical CSS inlined, rest deferred -->\n\u003Cstyle>\u002F* Critical above-fold CSS *\u002F\u003C\u002Fstyle>\n\u003Clink rel=\"preload\" href=\"\u002Fstyles.css\" as=\"style\" \n      onload=\"this.onload=null;this.rel='stylesheet'\">\n```\n\n**3. Slow resource load times**\n```html\n\u003C!-- ❌ No hints, discovered late -->\n\u003Cimg src=\"\u002Fhero.jpg\" alt=\"Hero\">\n\n\u003C!-- ✅ Preloaded with high priority -->\n\u003Clink rel=\"preload\" href=\"\u002Fhero.webp\" as=\"image\" fetchpriority=\"high\">\n\u003Cimg src=\"\u002Fhero.webp\" alt=\"Hero\" fetchpriority=\"high\">\n```\n\n**4. Client-side rendering delays**\n```javascript\n\u002F\u002F ❌ Content loads after JavaScript\nuseEffect(() => {\n  fetch('\u002Fapi\u002Fhero-text').then(r => r.json()).then(setHeroText);\n}, []);\n\n\u002F\u002F ✅ Server-side or static rendering\n\u002F\u002F Use SSR, SSG, or streaming to send HTML with content\nexport async function getServerSideProps() {\n  const heroText = await fetchHeroText();\n  return { props: { heroText } };\n}\n```\n\n### LCP optimization checklist\n\n```markdown\n- [ ] TTFB \u003C 800ms (use CDN, edge caching)\n- [ ] LCP image preloaded with fetchpriority=\"high\"\n- [ ] LCP image optimized (WebP\u002FAVIF, correct size)\n- [ ] Critical CSS inlined (\u003C 14KB)\n- [ ] No render-blocking JavaScript in \u003Chead>\n- [ ] Fonts don't block text rendering (font-display: swap)\n- [ ] LCP element in initial HTML (not JS-rendered)\n```\n\n### LCP element identification\n```javascript\n\u002F\u002F Find your LCP element\nnew PerformanceObserver((list) => {\n  const entries = list.getEntries();\n  const lastEntry = entries[entries.length - 1];\n  console.log('LCP element:', lastEntry.element);\n  console.log('LCP time:', lastEntry.startTime);\n}).observe({ type: 'largest-contentful-paint', buffered: true });\n```\n\n---\n\n## INP: Interaction to Next Paint\n\nINP measures responsiveness across ALL interactions (clicks, taps, key presses) during a page visit. It reports the worst interaction (at 98th percentile for high-traffic pages).\n\n### INP breakdown\n\nTotal INP = **Input Delay** + **Processing Time** + **Presentation Delay**\n\n| Phase | Target | Optimization |\n|-------|--------|--------------|\n| Input Delay | \u003C 50ms | Reduce main thread blocking |\n| Processing | \u003C 100ms | Optimize event handlers |\n| Presentation | \u003C 50ms | Minimize rendering work |\n\n### Common INP issues\n\n**1. Long tasks blocking main thread**\n```javascript\n\u002F\u002F ❌ Long synchronous task\nfunction processLargeArray(items) {\n  items.forEach(item => expensiveOperation(item));\n}\n\n\u002F\u002F ✅ Break into chunks with yielding\nasync function processLargeArray(items) {\n  const CHUNK_SIZE = 100;\n  for (let i = 0; i \u003C items.length; i += CHUNK_SIZE) {\n    const chunk = items.slice(i, i + CHUNK_SIZE);\n    chunk.forEach(item => expensiveOperation(item));\n    \n    \u002F\u002F Yield to main thread\n    await new Promise(r => setTimeout(r, 0));\n    \u002F\u002F Or use scheduler.yield() when available\n  }\n}\n```\n\n**2. Heavy event handlers**\n```javascript\n\u002F\u002F ❌ All work in handler\nbutton.addEventListener('click', () => {\n  \u002F\u002F Heavy computation\n  const result = calculateComplexThing();\n  \u002F\u002F DOM updates\n  updateUI(result);\n  \u002F\u002F Analytics\n  trackEvent('click');\n});\n\n\u002F\u002F ✅ Prioritize visual feedback\nbutton.addEventListener('click', () => {\n  \u002F\u002F Immediate visual feedback\n  button.classList.add('loading');\n  \n  \u002F\u002F Defer non-critical work\n  requestAnimationFrame(() => {\n    const result = calculateComplexThing();\n    updateUI(result);\n  });\n  \n  \u002F\u002F Use requestIdleCallback for analytics\n  requestIdleCallback(() => trackEvent('click'));\n});\n```\n\n**3. Third-party scripts**\n```javascript\n\u002F\u002F ❌ Eagerly loaded, blocks interactions\n\u003Cscript src=\"https:\u002F\u002Fheavy-widget.com\u002Fwidget.js\">\u003C\u002Fscript>\n\n\u002F\u002F ✅ Lazy loaded on interaction or visibility\nconst loadWidget = () => {\n  import('https:\u002F\u002Fheavy-widget.com\u002Fwidget.js')\n    .then(widget => widget.init());\n};\nbutton.addEventListener('click', loadWidget, { once: true });\n```\n\n**4. Excessive re-renders (React\u002FVue)**\n```javascript\n\u002F\u002F ❌ Re-renders entire tree\nfunction App() {\n  const [count, setCount] = useState(0);\n  return (\n    \u003Cdiv>\n      \u003CCounter count={count} \u002F>\n      \u003CExpensiveComponent \u002F> {\u002F* Re-renders on every count change *\u002F}\n    \u003C\u002Fdiv>\n  );\n}\n\n\u002F\u002F ✅ Memoized expensive components\nconst MemoizedExpensive = React.memo(ExpensiveComponent);\n\nfunction App() {\n  const [count, setCount] = useState(0);\n  return (\n    \u003Cdiv>\n      \u003CCounter count={count} \u002F>\n      \u003CMemoizedExpensive \u002F>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n### INP optimization checklist\n\n```markdown\n- [ ] No tasks > 50ms on main thread\n- [ ] Event handlers complete quickly (\u003C 100ms)\n- [ ] Visual feedback provided immediately\n- [ ] Heavy work deferred with requestIdleCallback\n- [ ] Third-party scripts don't block interactions\n- [ ] Debounced input handlers where appropriate\n- [ ] Web Workers for CPU-intensive operations\n```\n\n### INP debugging\n```javascript\n\u002F\u002F Identify slow interactions\nnew PerformanceObserver((list) => {\n  for (const entry of list.getEntries()) {\n    if (entry.duration > 200) {\n      console.warn('Slow interaction:', {\n        type: entry.name,\n        duration: entry.duration,\n        processingStart: entry.processingStart,\n        processingEnd: entry.processingEnd,\n        target: entry.target\n      });\n    }\n  }\n}).observe({ type: 'event', buffered: true, durationThreshold: 16 });\n```\n\n---\n\n## CLS: Cumulative Layout Shift\n\nCLS measures unexpected layout shifts. A shift occurs when a visible element changes position between frames without user interaction.\n\n**CLS Formula:** `impact fraction × distance fraction`\n\n### Common CLS causes\n\n**1. Images without dimensions**\n```html\n\u003C!-- ❌ Causes layout shift when loaded -->\n\u003Cimg src=\"photo.jpg\" alt=\"Photo\">\n\n\u003C!-- ✅ Space reserved -->\n\u003Cimg src=\"photo.jpg\" alt=\"Photo\" width=\"800\" height=\"600\">\n\n\u003C!-- ✅ Or use aspect-ratio -->\n\u003Cimg src=\"photo.jpg\" alt=\"Photo\" style=\"aspect-ratio: 4\u002F3; width: 100%;\">\n```\n\n**2. Ads, embeds, and iframes**\n```html\n\u003C!-- ❌ Unknown size until loaded -->\n\u003Ciframe src=\"https:\u002F\u002Fad-network.com\u002Fad\">\u003C\u002Fiframe>\n\n\u003C!-- ✅ Reserve space with min-height -->\n\u003Cdiv style=\"min-height: 250px;\">\n  \u003Ciframe src=\"https:\u002F\u002Fad-network.com\u002Fad\" height=\"250\">\u003C\u002Fiframe>\n\u003C\u002Fdiv>\n\n\u003C!-- ✅ Or use aspect-ratio container -->\n\u003Cdiv style=\"aspect-ratio: 16\u002F9;\">\n  \u003Ciframe src=\"https:\u002F\u002Fyoutube.com\u002Fembed\u002F...\" \n          style=\"width: 100%; height: 100%;\">\u003C\u002Fiframe>\n\u003C\u002Fdiv>\n```\n\n**3. Dynamically injected content**\n```javascript\n\u002F\u002F ❌ Inserts content above viewport\nnotifications.prepend(newNotification);\n\n\u002F\u002F ✅ Insert below viewport or use transform\nconst insertBelow = viewport.bottom \u003C newNotification.top;\nif (insertBelow) {\n  notifications.prepend(newNotification);\n} else {\n  \u002F\u002F Animate in without shifting\n  newNotification.style.transform = 'translateY(-100%)';\n  notifications.prepend(newNotification);\n  requestAnimationFrame(() => {\n    newNotification.style.transform = '';\n  });\n}\n```\n\n**4. Web fonts causing FOUT**\n```css\n\u002F* ❌ Font swap shifts text *\u002F\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n}\n\n\u002F* ✅ Optional font (no shift if slow) *\u002F\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n  font-display: optional;\n}\n\n\u002F* ✅ Or match fallback metrics *\u002F\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n  font-display: swap;\n  size-adjust: 105%; \u002F* Match fallback size *\u002F\n  ascent-override: 95%;\n  descent-override: 20%;\n}\n```\n\n**5. Animations triggering layout**\n```css\n\u002F* ❌ Animates layout properties *\u002F\n.animate {\n  transition: height 0.3s, width 0.3s;\n}\n\n\u002F* ✅ Use transform instead *\u002F\n.animate {\n  transition: transform 0.3s;\n}\n.animate.expanded {\n  transform: scale(1.2);\n}\n```\n\n### CLS optimization checklist\n\n```markdown\n- [ ] All images have width\u002Fheight or aspect-ratio\n- [ ] All videos\u002Fembeds have reserved space\n- [ ] Ads have min-height containers\n- [ ] Fonts use font-display: optional or matched metrics\n- [ ] Dynamic content inserted below viewport\n- [ ] Animations use transform\u002Fopacity only\n- [ ] No content injected above existing content\n```\n\n### CLS debugging\n```javascript\n\u002F\u002F Track layout shifts\nnew PerformanceObserver((list) => {\n  for (const entry of list.getEntries()) {\n    if (!entry.hadRecentInput) {\n      console.log('Layout shift:', entry.value);\n      entry.sources?.forEach(source => {\n        console.log('  Shifted element:', source.node);\n        console.log('  Previous rect:', source.previousRect);\n        console.log('  Current rect:', source.currentRect);\n      });\n    }\n  }\n}).observe({ type: 'layout-shift', buffered: true });\n```\n\n---\n\n## Measurement tools\n\n### Lab testing\n- **Chrome DevTools** → Performance panel, Lighthouse\n- **WebPageTest** → Detailed waterfall, filmstrip\n- **Lighthouse CLI** → `npx lighthouse \u003Curl>`\n\n### Field data (real users)\n- **Chrome User Experience Report (CrUX)** → BigQuery or API\n- **Search Console** → Core Web Vitals report\n- **web-vitals library** → Send to your analytics\n\n```javascript\nimport {onLCP, onINP, onCLS} from 'web-vitals';\n\nfunction sendToAnalytics({name, value, rating}) {\n  gtag('event', name, {\n    event_category: 'Web Vitals',\n    value: Math.round(name === 'CLS' ? value * 1000 : value),\n    event_label: rating\n  });\n}\n\nonLCP(sendToAnalytics);\nonINP(sendToAnalytics);\nonCLS(sendToAnalytics);\n```\n\n---\n\n## Framework quick fixes\n\n### Next.js\n```jsx\n\u002F\u002F LCP: Use next\u002Fimage with priority\nimport Image from 'next\u002Fimage';\n\u003CImage src=\"\u002Fhero.jpg\" priority fill alt=\"Hero\" \u002F>\n\n\u002F\u002F INP: Use dynamic imports\nconst HeavyComponent = dynamic(() => import('.\u002FHeavy'), { ssr: false });\n\n\u002F\u002F CLS: Image component handles dimensions automatically\n```\n\n### React\n```jsx\n\u002F\u002F LCP: Preload in head\n\u003Clink rel=\"preload\" href=\"\u002Fhero.jpg\" as=\"image\" fetchpriority=\"high\" \u002F>\n\n\u002F\u002F INP: Memoize and useTransition\nconst [isPending, startTransition] = useTransition();\nstartTransition(() => setExpensiveState(newValue));\n\n\u002F\u002F CLS: Always specify dimensions in img tags\n```\n\n### Vue\u002FNuxt\n```vue\n\u003C!-- LCP: Use nuxt\u002Fimage with preload -->\n\u003CNuxtImg src=\"\u002Fhero.jpg\" preload loading=\"eager\" \u002F>\n\n\u003C!-- INP: Use async components -->\n\u003Ccomponent :is=\"() => import('.\u002FHeavy.vue')\" \u002F>\n\n\u003C!-- CLS: Use aspect-ratio CSS -->\n\u003Cimg :style=\"{ aspectRatio: '16\u002F9' }\" \u002F>\n```\n\n## References\n\n- [web.dev LCP](https:\u002F\u002Fweb.dev\u002Farticles\u002Flcp)\n- [web.dev INP](https:\u002F\u002Fweb.dev\u002Farticles\u002Finp)\n- [web.dev CLS](https:\u002F\u002Fweb.dev\u002Farticles\u002Fcls)\n- [Performance skill](..\u002Fperformance\u002FSKILL.md)\n",{"name":5,"license":15,"metadata":42,"description":7},{"author":43,"version":44},"web-quality-skills","1.0","main","2b749c82b5d11fac39d9a6e021ce3f5b8a541bd1","cli-tool\u002Fcomponents\u002Fskills\u002Fdevelopment\u002Fcore-web-vitals",3931,"https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates","https:\u002F\u002Faitmpl.com","https:\u002F\u002Fgithub.com\u002Fdavila7","https:\u002F\u002Fdanielavila.me","Building AI dev tools with LLMs","2026-11-14 06:14:46",{"source":8,"skillName":5,"commands":56,"prompt":66,"zipAvailable":67},[57,60,63],{"tool":58,"command":59},"npx","npx skills add davila7\u002Fclaude-code-templates --skill core-web-vitals",{"tool":61,"command":62},"bunx","bunx skills add davila7\u002Fclaude-code-templates --skill core-web-vitals",{"tool":64,"command":65},"pnpm","pnpm dlx skills add davila7\u002Fclaude-code-templates --skill core-web-vitals","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fdevelopment\u002Fcore-web-vitals\u002FSKILL.md",true,[69],{"path":70,"resourceType":71,"resourceTypeDesc":72,"sizeBytes":73,"sourceHtmlUrl":74},"references\u002FLCP.md","REFERENCE","参考文档",4431,"https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fdevelopment\u002Fcore-web-vitals\u002Freferences\u002FLCP.md",[76,104,131,164,198,222],{"skillNo":77,"name":78,"nameZh":6,"description":79,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":80,"categories":81,"keywords":87,"publishedAt":37},"01M70NHBTQ8BV0A2SCAZXEPHCX","wealthville-pool-scoring","Score DeFi liquidity pools before providing liquidity. Returns a 0-100 pool score and an Enter\u002FHold\u002FExit\u002FReduce\u002FAvoid verdict with calibrated confidence for ~68,800 Solana pools and 575 EVM pools, plus a public miss-inclusive track record. Use when asked whether a pool is worth LPing into, which pools look best right now, or how accurate the scores have actually been.","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fweb-data\u002Fwealthville-pool-scoring\u002FSKILL.md",[82],{"categoryNo":83,"categoryName":84,"taxonomyType":85,"taxonomyTypeDesc":86},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[88,89,90,91,92,26,93,94,30,24,25,95,96,97,98,99,100,101,102,103],"scoring","pool","wealthville pool scoring","liquidity","which","exit","now","with","record","track","verdict","evm","solana","how","public","look",{"skillNo":105,"name":106,"nameZh":6,"description":107,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":108,"categories":109,"keywords":111,"publishedAt":37},"01M70MB6VR8ERJ4EM8D5KHBMEV","technical-debt-auditor","Scans a codebase and produces a quantified technical debt report with a prioritized remediation plan. Analyzes dead code, TODO\u002FFIXME\u002FHACK markers, dependency staleness, complexity hotspots, code duplication signals, test coverage gaps, unused exports, and outdated patterns. Use this skill when the user asks to audit their codebase for tech debt, wants a health check of their code quality, says things like \"where should I focus refactoring\", \"find code smells\", \"audit my codebase\", \"what technical debt do we have\", \"prioritize cleanup work\", or asks about code quality metrics. Also trigger when the user mentions \"code rot\", \"legacy cleanup\", \"refactoring priorities\", or wants to understand the overall health of a project before a major effort. Trigger even if the user doesn't say \"technical debt\" explicitly — any request to systematically assess code quality and identify improvement priorities belongs here.","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fdevelopment\u002Ftechnical-debt-auditor\u002FSKILL.md",[110],{"categoryNo":83,"categoryName":84,"taxonomyType":85,"taxonomyTypeDesc":86},[112,113,114,115,116,117,118,119,120,121,122,24,123,124,125,126,127,128,129,130],"technical debt","debt","technical","technical debt auditor","auditor","coverage","complexity","markers","project","cleanup","unused","code","todo","work","plan","focus","signals","audit","dependency",{"skillNo":132,"name":133,"nameZh":6,"description":134,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":135,"categories":136,"keywords":146,"publishedAt":37},"01M70KPYH9QNHCNME5GJQGE22K","readonly-sql-guard","Make an agent's database access provably read-only. Use when an agent runs caller-supplied SQL against a production\u002FERP\u002Fanalytics database (a \"query\" MCP tool, text-to-SQL, an admin console), or when reviewing DB-access code for write\u002FDDL\u002Fside-effect\u002Ftransaction-escape risks. Checks what a statement CALLS, not just its shape.","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fdatabase\u002Freadonly-sql-guard\u002FSKILL.md",[137,140,141],{"categoryNo":138,"categoryName":139,"taxonomyType":85,"taxonomyTypeDesc":86},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":83,"categoryName":84,"taxonomyType":85,"taxonomyTypeDesc":86},{"categoryNo":142,"categoryName":143,"taxonomyType":144,"taxonomyTypeDesc":145},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[147,148,149,150,151,152,153,26,154,155,156,157,158,159,160,30,161,162,24,163],"readonly","guard","sql guard","sql","readonly sql guard","erp","effect","read-only","db","just","tool","calls","only","MCP","access","database","query",{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":168,"licenseFileUrl":169,"sourceHtmlUrl":170,"categories":171,"keywords":175,"publishedAt":37},"01M6AFY6F7CC2BBZP1QD6VTNVC","web-artifacts-builder","Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn\u002Fui). Use for complex artifacts requiring state management, routing, or shadcn\u002Fui components - not for simple single-file HTML\u002FJSX artifacts.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Futilities\u002Fweb-artifacts-builder\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Futilities\u002Fweb-artifacts-builder\u002FSKILL.md",[172],{"categoryNo":173,"categoryName":174,"taxonomyType":85,"taxonomyTypeDesc":86},"01JBSEEDCAT000000000000009","前端开发",[176,20,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,26,197],"artifacts builder","web artifacts builder","artifacts","builder","state","routing","state management","component","css","frontend","ui","Tools","file","components","shadcn","react","Tailwind","suite","jsx","html","single-file","ui components",{"skillNo":199,"name":200,"nameZh":6,"description":201,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":168,"licenseFileUrl":202,"sourceHtmlUrl":203,"categories":204,"keywords":209,"publishedAt":37},"01M6AFWF33SFV9Z3SF4PEEE4BF","webapp-testing","Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fsecurity\u002Fwebapp-testing\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fsecurity\u002Fwebapp-testing\u002FSKILL.md",[205,208],{"categoryNo":206,"categoryName":207,"taxonomyType":85,"taxonomyTypeDesc":86},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":173,"categoryName":174,"taxonomyType":85,"taxonomyTypeDesc":86},[210,211,212,213,214,20,215,185,186,216,217,218,219,26,220,95,221],"webapp testing","testing","webapp","browser","playwright","applications","debugging","toolkit","logs","screenshots","local","behavior",{"skillNo":223,"name":224,"nameZh":6,"description":225,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":168,"licenseFileUrl":226,"sourceHtmlUrl":227,"categories":228,"keywords":236,"publishedAt":37},"01M6AF67Q67JJJ5V51JR2P52KA","discernment-nudge","After you give a substantive answer or draft that the user may act on — advice or recommendations, drafted artifacts such as goals, plans, pitches, proposals, or emails, estimates or projections, analysis or interpretation of data, factual claims they may rely on, or a multi-step argument — invoke this skill BEFORE finalizing your reply and then, if it applies, append 2-3 short follow-up questions, each tied to something specific in what you just produced, that help the user check key facts, probe the reasoning or assumptions, and notice missing context. Do this at most once per conversation. Skip it when the user asked a trivial how-to or simple lookup, wants a purely educational explanation, asked you only to format, convert, or assemble a file from content they provided, is writing code they will run, is doing creative writing or casual chat, or already asked you to double-check, cite, or review — the skill file explains these boundaries and the exact output format.","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fdiscernment-nudge\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fdiscernment-nudge\u002FSKILL.md",[229,232,233],{"categoryNo":230,"categoryName":231,"taxonomyType":85,"taxonomyTypeDesc":86},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":83,"categoryName":84,"taxonomyType":85,"taxonomyTypeDesc":86},{"categoryNo":234,"categoryName":235,"taxonomyType":144,"taxonomyTypeDesc":145},"01JBSEEDCAT000000000000036","内容创作者",[237,238,239,240,241,242,243,244,178,245,188,123,246,247,248,249,250,159,251,24,252,253,254,255,256,101,257],"discernment nudge","nudge","interpretation","help","run","reasoning","data","writing","lookup","content","review","conversation","short","up","invoke","you","analysis","claims","argument","assemble","recommendations"]