Repository navigation
Improve Lighthouse performance score to 100 #25
Description
Activity
- addedenhancementNew feature or requestNew feature or requestclaude-grill-meLet claude grill you for this issueLet claude grill you for this issue
on May 6, 2026 Clarifying Questions
I looked through the codebase before drafting these. Check the boxes that apply — no need to write anything unless an "Other" option fits better.
Fonts
app/assets/css/main.cssdeclaresPublic SansandInstrument Serifvia Tailwind theme variables, but there are no@font-facerules, no<link rel="preload">, and no font files inpublic/. It's unclear where these fonts actually come from.- Where are Public Sans and Instrument Serif loaded from?
- Google Fonts CDN (added somewhere not visible in the checked-in code, e.g. a
.envor host config) -
@nuxt/ui/ Tailwind bundles or downloads them automatically - They are not loaded — the site falls back to system fonts silently
- Other (please comment below)
- Google Fonts CDN (added somewhere not visible in the checked-in code, e.g. a
Deployment & hosting
-
Where is the production site hosted?
- GitHub Pages
- Netlify
- Vercel
- Cloudflare Pages
- Other (please comment below)
-
Does the host already serve Brotli/Gzip compression and long-lived
Cache-Controlheaders for hashed static assets?- Yes — handled automatically by the host
- No / not sure — needs investigation
Current failing metrics
A score below 80 can have many causes. Knowing which Core Web Vitals are failing avoids optimising the wrong thing.
-
Which metrics are currently dragging performance below 80? (check all that apply)
- LCP (Largest Contentful Paint) — the hero image or text is slow to appear
- CLS (Cumulative Layout Shift) — elements shift after load
- TBT (Total Blocking Time) — long JS tasks blocking the main thread
- INP (Interaction to Next Paint) — slow response to user input
- FCP (First Contentful Paint) — slow initial paint
- Haven't run a detailed audit yet — unknown
-
Which device profile matters most?
- Mobile (throttled CPU + network — hardest to pass)
- Desktop
- Both equally
Images
Hero.vueuses<NuxtImg>withloading="eager"for the profile photo but nofetchpriority="high". The hero background images (/hero/random-*.avif) are rendered via a plain<img>tag with no preload hint. Lab/talk card images lack explicitwidth/height.-
Should
fetchpriority="high"be added to the profile photo inHero.vue?- Yes
- No — it's small (72 × 72 px) and unlikely to be the LCP element
-
Should a
<link rel="preload">be added for the hero background AVIF that is rendered on load?- Yes — preload the first/default hero image
- No — the hero background is decorative and not the LCP element
- Not sure — depends on what Lighthouse flags as the LCP element
-
Should the JPEG profile photo (
fabian-meyer-portrait.jpg) be converted to AVIF/WebP?- Yes, convert it
- No —
@nuxt/imagehandles format negotiation at serve time, so it's fine as JPEG on disk - Only if Lighthouse flags it explicitly
-
Are there any lab or talk content images in
public/that are large or unoptimised?- Yes, some images need attention
- No, all are already well-optimised
- Not sure
Animations (motion-v)
motion-vis used in all five landing components. Hero animations run immediately on load (blur/scale, staggered 0.1 s–0.5 s delays). Below-fold components usewhile-in-viewwithonce: true.-
How important are the Hero entrance animations (blur + scale on initial load) to the design?
- Critical — keep them exactly as they are, even if they cost a few points
- Important — reduce/defer where possible, but don't remove them
- Flexible — can simplify or remove them if they're measurably hurting TBT/INP
-
Are the below-fold
while-in-viewanimations (Focus, WorkExperience, LabsTeaser, SpeakingTeaser) worth keeping?- Yes, keep all of them
- Keep them but defer/lazy-load the motion-v runtime until after hydration if possible
- Fine to remove if they're contributing to bundle weight
Scope & workflow
-
What should the first step be?
- Run a full Lighthouse audit (mobile + desktop) first and report findings before any code changes
- Skip straight to the obvious quick wins (fetchpriority, width/height attrs, font-display) and audit after
- Run the audit and implement fixes together in one PR
-
For inner pages (
/labs,/speaking,/labs/[slug],/speaking/[slug]): is 95+ acceptable if 100 isn't feasible on those routes?- Yes, 95+ is fine for non-homepage routes
- No — must hit 100 everywhere
- Only the homepage (
/) matters for this issue; inner pages are out of scope for now
Generated by Claude Code
- Where are Public Sans and Instrument Serif loaded from?
- removedclaude-grill-meLet claude grill you for this issueLet claude grill you for this issue
on May 7, 2026
Problem
The Lighthouse performance score for fmeyer.dev is currently sitting just below 80, while Accessibility, Best Practices, and SEO all score 100. The goal is to bring Performance up to 100 as well, so the site has a perfect Lighthouse profile across all four categories.
Current state
Goal
Performance: 100 (alongside the other three already at 100).
Areas to investigate
Run a fresh Lighthouse audit (mobile + desktop) against the production site and the local
pnpm generate+pnpm previewoutput, then address whichever of the following metrics are dragging the score down:public/hero/random-*.avif— verify dimensions, preload the image actually rendered, and ensure<NuxtImg>/<NuxtPicture>is used with explicitwidth/heightandloading="eager"+fetchpriority="high"for the hero.public/profile/— same treatment if it appears above the fold.font-display: swapand preload critical fonts.motion-vusage inapp/components/landing/*— defer non-critical animations until after hydration / useIntersectionObserverso off-screen sections don't run on load.@nuxt/uicomponents and confirm tree-shaking is effective.nuxt.config.tsexperimental.payloadExtractionand route rules for static pages.@nuxt/imageis generating responsivesrcsets and that the served image isn't oversized for the viewport.Acceptance criteria
/)./labs,/labs/[slug],/speaking, and/speaking/[slug].Out of scope