From 3e9be9e08e5a18c851b96ff6249e2d2c10284c58 Mon Sep 17 00:00:00 2001 From: Amy Lam Date: Thu, 23 Jul 2026 22:49:10 -0600 Subject: [PATCH 1/4] Note current Lighthouse score in README Records the live site's mobile Lighthouse results (100 across the board) in the Testing section so the score has a documented reference point. Co-Authored-By: Claude Sonnet 5 --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index f4da86a..fb10ad3 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,10 @@ Key files: every sun altitude and fails if any ink/background pairing drops below WCAG AAA — see [the sky section](#the-sky) above. +A mobile Lighthouse run against the live site currently scores a +perfect 100 across Performance, Accessibility, Best Practices, and +SEO — a snapshot, not a gate, since nothing in CI enforces it yet. + The same Playwright run also feeds [Chromatic](https://www.chromatic.com) visual regression testing via [`@chromatic-com/playwright`](https://www.chromatic.com/docs/playwright/) — From 642d4098fbf95bd8746570aab58b939968255d03 Mon Sep 17 00:00:00 2001 From: Amy Lam Date: Thu, 23 Jul 2026 23:09:42 -0600 Subject: [PATCH 2/4] Enforce Lighthouse score thresholds in CI, add badges to README Adds a Lighthouse CI job that builds the site and fails the PR if any page's score drops below set floors (Performance 90, Best Practices 95, Accessibility/SEO 100), so a regression gets caught before merge instead of relying on someone noticing later. Adds shields.io badges showing the live production score to the top of the README. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/ci.yml | 33 +++++++++++++++++++++++++++++++++ .gitignore | 2 ++ README.md | 22 +++++++++++++++++----- lighthouserc.json | 18 ++++++++++++++++++ 4 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 lighthouserc.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e03d4a5..ac1f7a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,6 +77,39 @@ jobs: env: CHROMATIC_ARCHIVE_LOCATION: ./test-results + lighthouse: + name: Lighthouse CI + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up pnpm + uses: pnpm/action-setup@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm build + + # Tests the static dist/ output directly, so /api/geo and the Vercel + # Analytics script (both Vercel-runtime-only) 404 here even though + # they work in production — accounted for in lighthouserc.json's + # best-practices threshold. + - name: Run Lighthouse CI + uses: treosh/lighthouse-ci-action@v11 + with: + configPath: ./lighthouserc.json + uploadArtifacts: true + temporaryPublicStorage: true + lint: name: Lint + format runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 43a37a6..ed49f68 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ dist/ # playwright output test-results/ playwright-report/ +# lighthouse ci output +.lighthouseci/ # generated types .astro/ diff --git a/README.md b/README.md index fb10ad3..4a08657 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # youthphase.dev +![Lighthouse Performance](https://img.shields.io/badge/Lighthouse%20Performance-100-brightgreen) +![Lighthouse Accessibility](https://img.shields.io/badge/Lighthouse%20Accessibility-100-brightgreen) +![Lighthouse Best Practices](https://img.shields.io/badge/Lighthouse%20Best%20Practices-100-brightgreen) +![Lighthouse SEO](https://img.shields.io/badge/Lighthouse%20SEO-100-brightgreen) + Personal site of Amy Lam. Built with [Astro](https://astro.build) and [Tailwind CSS](https://tailwindcss.com), package-managed with [pnpm](https://pnpm.io), linted with Prettier/ESLint/Stylelint. This @@ -117,9 +122,16 @@ Key files: every sun altitude and fails if any ink/background pairing drops below WCAG AAA — see [the sky section](#the-sky) above. -A mobile Lighthouse run against the live site currently scores a -perfect 100 across Performance, Accessibility, Best Practices, and -SEO — a snapshot, not a gate, since nothing in CI enforces it yet. +[Lighthouse CI](https://github.com/GoogleChrome/lighthouse-ci) runs +against every page in the built `dist/` output and fails the build if +Performance drops below 90, Best Practices drops below 95, or +Accessibility or SEO drop below 100 — thresholds set in +[lighthouserc.json](lighthouserc.json). Performance gets a lower floor +because build-to-build timing variance on CI runners is real; Best +Practices gets one because testing the static `dist/` directly (rather +than a deployed Vercel environment) makes `/api/geo` and the Vercel +Analytics script 404, which they don't in production. The badges above +reflect an actual production run, which hits neither issue. The same Playwright run also feeds [Chromatic](https://www.chromatic.com) visual regression testing via @@ -152,8 +164,8 @@ to actually publish. [GitHub Actions](https://github.com/features/actions) (`.github/workflows/ci.yml`) runs the build, `check:contrast`, the full -Playwright suite, and all three linters on every push to `main` and on -every pull request. +Playwright suite, Lighthouse CI, and all three linters on every push to +`main` and on every pull request. ## Deploying (Vercel) diff --git a/lighthouserc.json b/lighthouserc.json new file mode 100644 index 0000000..6653cf2 --- /dev/null +++ b/lighthouserc.json @@ -0,0 +1,18 @@ +{ + "ci": { + "collect": { + "staticDistDir": "./dist" + }, + "assert": { + "assertions": { + "categories:performance": ["error", { "minScore": 0.9 }], + "categories:accessibility": ["error", { "minScore": 1 }], + "categories:best-practices": ["error", { "minScore": 0.95 }], + "categories:seo": ["error", { "minScore": 1 }] + } + }, + "upload": { + "target": "temporary-public-storage" + } + } +} From e5746ae7df7de94872d5771eeaf311382b8235bc Mon Sep 17 00:00:00 2001 From: Amy Lam Date: Thu, 23 Jul 2026 23:13:40 -0600 Subject: [PATCH 3/4] Take median of 3 Lighthouse runs to reduce CI flakiness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A single run on the shared GitHub Actions runner scored the 404 page's Performance at 0.87, below the 0.9 floor, on what's otherwise a stable page — runner CPU contention, not a real regression. Matches the numberOfRuns used when validating this config locally. Co-Authored-By: Claude Sonnet 5 --- lighthouserc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lighthouserc.json b/lighthouserc.json index 6653cf2..e70c96a 100644 --- a/lighthouserc.json +++ b/lighthouserc.json @@ -1,7 +1,8 @@ { "ci": { "collect": { - "staticDistDir": "./dist" + "staticDistDir": "./dist", + "numberOfRuns": 3 }, "assert": { "assertions": { From d0edab519d0951fee1358ed4154dd539bb3c95cc Mon Sep 17 00:00:00 2001 From: Amy Lam Date: Thu, 23 Jul 2026 23:38:16 -0600 Subject: [PATCH 4/4] Exclude decorative sky overlays from Chromatic diffing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The moon/star/rainbow/glow/scrim layers are live CSS-animated overlays whose pixel state at capture time depends on elapsed time since page load, not just the pinned sky time — a source of visual noise separate from (and not fixed by) the sky-pin race fix in db8dc55. Marking them data-chromatic="ignore" excludes that noise while leaving real page content (nav, forms, cards, the sky gradient/ink on itself) diffed as before. Co-Authored-By: Claude Sonnet 5 --- src/layouts/Layout.astro | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index 25f8a29..71e32bc 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -43,6 +43,7 @@ const ogImage = new URL('/og.png', Astro.site); @@ -59,6 +60,7 @@ const ogImage = new URL('/og.png', Astro.site); @@ -73,7 +75,12 @@ const ogImage = new URL('/og.png', Astro.site); sliding off another circle. sky.ts positions it with the moon and rewrites the shadow path each tick; visibility and the bloom transition live in global.css under html.moon-cycle. --> -