skills/perf-landing/SKILL.md
Method to diagnose and raise the Lighthouse performance score of a public page (landing, marketing, home). Use when asked to improve Lighthouse/PageSpeed scores, when auditing the first uncached paint of a public page, or when a landing embedded in a SPA must reach a top score. Do NOT use for in-app screen performance (data loading, rendering). For a brand-new landing, the first recommendation is static HTML with no framework runtime — most of this skill exists for when that is not an option.
npx skillsauth add nicolas-codemate/claudecodeconfig perf-landingInstall 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.
Method distilled from a real case (Vue SPA landing, mobile 83 → 99, desktop 100). The score is won on the simulated critical path, which can differ wildly from real paint speed.
A landing served as plain static HTML (hand-written, Astro, SSG) with inline critical CSS scores 100 with none of the machinery below. Everything in the "SPA-hosted landing" section exists to make a SPA route look static to Lighthouse. If you are designing a new page and static is an option, take it and stop reading.
Lighthouse mobile does not measure your machine; it replays the request graph through the "lantern" simulation (RTT 150 ms, 1.6 Mbit/s, CPU x4). Consequences:
<head> (scripts — even type="module"/deferred —, stylesheets,
preloads) enter the simulated pre-LCP graph and compete for the simulated 1.6 Mbit/s. A large
entry bundle in the head degrades simulated LCP even when the real paint never waits for it.load).Always compare observed vs simulated in the report JSON
(.audits.metrics.details.items[0].observedFirstContentfulPaint vs .firstContentfulPaint).
Observed good + simulated bad = hunt the request graph (High-priority pre-LCP requests), not the
rendering. Identify the actual LCP element (.audits["largest-contentful-paint-element"]) before
optimizing anything — it is not always the one you think, and it can move (e.g. to a text node
that repaints on font swap) after you fix the current one.
npx lighthouse <url> --chrome-flags="--headless=new" --output=json --output-path=r.json --quietnpx serve -l <port> <dir>),
editing the HTML directly — seconds per iteration. Wire the winning variant into the build after.media="print" onload="this.media='all'" + <noscript> fallback). Only valid if the inline CSS really covers
everything above the fold.<link rel="preload" as="image" fetchpriority="high">
and correctly sized files. Inlining it as a data URI removes the request entirely (LCP collapses
to FCP) but adds ~33% to its bytes, on every HTML fetch, uncacheable separately — reserve it for
small images (≲ 25 KB) on HTML that is itself cached (service worker, CDN).@font-face rules
reachable at first paint (inline them if the main stylesheet is async — preload without
applicable @font-face = downloaded but unapplied). Caution: in the observed case, removing
font preloads worsened simulated LCP because the LCP anchor moved to text repainted on font
swap. Font tuning shifts LCP anchors; re-check the LCP element after every font change.width/height everywhere (CLS 0), loading="lazy" below the fold.These reproduce what static hosting gives for free:
<script type="module"> with a small
inline loader that injects it dynamically after window.load (plus a short delay, ~150 ms, to
let the load-complete frame paint before the download competes for bandwidth). Validity
condition — do not skip: nothing interactive above the fold may depend on the deferred
bundle. CTAs must be plain <a href> links that work as full navigations before the SPA
boots; verify this by blocking the bundle and clicking them. Branch the loader: boot
immediately for known/authed visitors (localStorage hint) and for every non-landing URL
(those visitors are waiting for the app, not the landing). If the site has several marketing
pages, the "is landing" test must cover all of them, not a hardcoded /.var() references transitively from the landing CSS
and drop the rest. Smaller HTML = faster download and smaller style-parse tasks.If the site is already SSR/SSG (Nuxt, Next, Astro): 1 is already done and 2 delays hydration — on a page with above-the-fold interactivity that means dead buttons on slow mobile. Do not apply it blindly; measure what the framework already ships.
Before writing any of this tooling, check whether the repo already has a prerender/landing build plugin and reuse it.
load.--only-categories).tools
Audits a project's Claude Code setup against real usage — mines the project's conversations (worktrees included), confronts the project's skills/agents/CLAUDE.md with best practices, and proposes adjustments or new skills/agents/rules. Use when the user asks to audit the project config, analyze project conversations, or find automation opportunities for the current project. Do NOT use for the global ~/.claude configuration (use /audit-config instead).
development
Coaching workflow orchestrator. Guides the developer through implementation without writing code.
development
Disciplined methodology for code architecture refactoring. Use when the user asks to refactor architecture, decouple code, restructure a family of classes, redesign an interface, or rename/reorganize a set of related components. Forces a big-picture analysis before any code is written. Do NOT use for simple bug fixes, feature additions, or single-file refactoring.
development
Analyse-Explore-Plan methodology for thorough analysis and planning before development. Use when starting a new feature, investigating a problem, or needing to understand a codebase before making changes. Provides structured workflow with parallel exploration agents and clarification questions. Integrates with Architect skill for high-quality implementation plans. Do NOT use for ticket-based planning (use /resolve <ticket> --plan-only instead) or when a saved plan is needed (use /create-plan instead).