Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .omo/evidence/design-system-fidelity-v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Design System Fidelity v2 Evidence

## Scope

- Branch: `code-yeongyu/lazycodex-design-system-fidelity`
- Base: `origin/main` at `4a15494c5bff789a45047c753d167dac60512579`
- Worktree: `/Users/yeongyu/local-workspaces/lazycodex-wt/design-system-fidelity-v2`
- Control baseline: clean `origin/main` production build

## Design System Work

- Extracted the existing Tailwind theme, root CSS tokens, base layer, and shared card-gradient utilities from `packages/web/app/globals.css` into `packages/web/app/styles/design-system.css`.
- Kept `globals.css` as the import hub for Tailwind, shared design-system CSS, and page composition CSS.
- Updated `packages/web/DESIGN.md` so the documented token values and component families match the current rendered green identity.
- Preserved current visual output, behavior, and page experience; no redesign was introduced.

## Visual QA

- Browser harness: `.omo/scripts/design-system-fidelity/capture-and-drive.mjs`
- Evidence directory: `.omo/ulw-loop/evidence/design-system-fidelity-v2/`
- Routes compared: `/`, `/docs`
- Viewports compared: `390x844`, `768x1024`, `1280x800`
- Pixel-diff summary: all 6 comparisons passed with `diffPixels: 0`, `diffRatio: 0`, `similarityScore: 100`, `dimensionsMatch: true`, and `alphaChannelIntact: true`.
- Interaction checks passed: copy install command, landing docs navigation, docs mobile menu, Command-K search focus, docs search filtering, and docs hash navigation.
- Console/page health: no console warnings/errors and no page errors recorded during the capture run.

## Automated Verification

- `pnpm install --frozen-lockfile` passed in `packages/web`.
- `pnpm run build` passed in `packages/web`.
- `pnpm run lint` passed in `packages/web`.
- `pnpm run type-check` passed in `packages/web`.
- `pnpm run test:e2e` passed in `packages/web` after refreshing a stale docs-copy assertion that also failed on clean `origin/main`.
- Lighthouse in the e2e suite reached 100/100/100/100 on both mobile and desktop using real Chrome.

## Notes

- The stale docs-copy assertion was updated from old rendered copy to the current `content/docs/skills.md` wording.
- The old closed draft PR #70 is superseded by this fresh branch from current `origin/main`.
181 changes: 181 additions & 0 deletions .omo/scripts/design-system-fidelity/capture-and-drive.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import { mkdirSync, writeFileSync } from "node:fs"
import { createRequire } from "node:module"
import { join } from "node:path"

const require = createRequire(new URL("../../../packages/web/package.json", import.meta.url))
const { chromium } = require("@playwright/test")

const [, , controlUrl, currentUrl, outDir] = process.argv

if (!controlUrl || !currentUrl || !outDir) {
throw new Error("usage: capture-and-drive.mjs <control-url> <current-url> <out-dir>")
}

const viewports = [
{ id: "mobile", width: 390, height: 844 },
{ id: "tablet", width: 768, height: 1024 },
{ id: "desktop", width: 1280, height: 800 },
]

const routes = [
{ id: "landing", path: "/" },
{ id: "docs", path: "/docs" },
]

const starsPayload = {
stars: 12345,
formatted: "12.3k",
source: "github",
}

function ensureDir(path) {
mkdirSync(path, { recursive: true })
}

async function withPage(context, events, callback) {
const page = await context.newPage()
page.on("console", (message) => {
if (["error", "warning"].includes(message.type())) {
events.console.push({ type: message.type(), text: message.text() })
}
})
page.on("pageerror", (error) => {
events.pageErrors.push(error.message)
})
try {
await callback(page)
} finally {
await page.close()
}
}

async function routeStableStars(context) {
await context.route("**/api/github-stars", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify(starsPayload),
})
})
}

async function captureSurface(browser, label, baseUrl) {
const surfaceDir = join(outDir, "screenshots", label)
ensureDir(surfaceDir)
const context = await browser.newContext()
await routeStableStars(context)
const events = { console: [], pageErrors: [] }
const captures = []

for (const viewport of viewports) {
for (const routeSpec of routes) {
await withPage(context, events, async (page) => {
await page.setViewportSize({ width: viewport.width, height: viewport.height })
const target = new URL(routeSpec.path, baseUrl).toString()
await page.goto(target, { waitUntil: "networkidle" })
await page.waitForTimeout(950)
const overflow = await page.evaluate(() => ({
scrollWidth: document.documentElement.scrollWidth,
clientWidth: document.documentElement.clientWidth,
overflowX: document.documentElement.scrollWidth - document.documentElement.clientWidth,
}))
const fileName = `${routeSpec.id}-${viewport.id}-${viewport.width}x${viewport.height}.png`
const screenshotPath = join(surfaceDir, fileName)
await page.screenshot({ path: screenshotPath, fullPage: true })
captures.push({
route: routeSpec.path,
viewport,
screenshotPath,
overflow,
})
})
}
}

await context.close()
return { label, baseUrl, captures, events }
}

async function driveCurrent(browser) {
const interactionDir = join(outDir, "screenshots", "interactions")
ensureDir(interactionDir)
const context = await browser.newContext({ viewport: { width: 390, height: 844 } })
await routeStableStars(context)
const events = { console: [], pageErrors: [] }
const checks = []

await withPage(context, events, async (page) => {
await page.goto(new URL("/", currentUrl).toString(), { waitUntil: "networkidle" })
await page.waitForTimeout(950)
await page.getByRole("button", { name: "Copy install command" }).click()
const copied = await page.getByText("Copied", { exact: true }).isVisible()
checks.push({ id: "copy-install-command", passed: copied })
await page.getByRole("link", { name: /docs/i }).first().click()
await page.waitForURL("**/docs")
checks.push({ id: "landing-docs-navigation", passed: page.url().endsWith("/docs") })
})

await withPage(context, events, async (page) => {
await page.goto(new URL("/docs", currentUrl).toString(), { waitUntil: "networkidle" })
await page.getByRole("button", { name: "Menu" }).click()
const expanded = await page.getByRole("button", { name: "Close Menu" }).getAttribute("aria-expanded")
checks.push({ id: "docs-mobile-menu-opens", passed: expanded === "true" })
await page.screenshot({
path: join(interactionDir, "docs-mobile-menu-open-390x844.png"),
fullPage: true,
})
})

await withPage(context, events, async (page) => {
await page.setViewportSize({ width: 1280, height: 800 })
await page.goto(new URL("/docs", currentUrl).toString(), { waitUntil: "networkidle" })
await page.keyboard.press("Meta+K")
const focused = await page.locator("#docs-search-input").evaluate((node) => document.activeElement === node)
checks.push({ id: "docs-command-k-focuses-search", passed: focused })
await page.locator("#docs-search-input").fill("feature")
const skillsVisible = await page
.getByLabel("Documentation", { exact: true })
.getByRole("link", { name: "Feature coverage" })
.isVisible()
const noMatchesHidden = (await page.getByText("No matches.").count()) === 0
checks.push({ id: "docs-search-filters-skills", passed: skillsVisible && noMatchesHidden })
await page.locator("#docs-search-input").fill("")
await page.getByLabel("Documentation", { exact: true }).getByRole("link", { name: "$ulw-loop" }).click()
await page.waitForURL(/#ulw-loop$/)
const inViewport = await page.locator("#ulw-loop").evaluate((node) => {
const rect = node.getBoundingClientRect()
return rect.top < window.innerHeight && rect.bottom > 0
})
checks.push({ id: "docs-hash-navigation", passed: inViewport })
await page.screenshot({
path: join(interactionDir, "docs-desktop-search-hash-1280x800.png"),
fullPage: true,
})
})

await context.close()
return { checks, events }
}

const browser = await chromium.launch({ channel: "chrome", headless: true })
try {
ensureDir(outDir)
const control = await captureSurface(browser, "control", controlUrl)
const current = await captureSurface(browser, "current", currentUrl)
const interactions = await driveCurrent(browser)
const allChecksPassed = interactions.checks.every((check) => check.passed)
const report = {
generatedAt: new Date().toISOString(),
control,
current,
interactions,
allChecksPassed,
cleanup: "closed Playwright Chrome contexts and browser",
}
writeFileSync(join(outDir, "capture-report.json"), `${JSON.stringify(report, null, 2)}\n`)
if (!allChecksPassed) {
throw new Error("one or more interaction checks failed")
}
} finally {
await browser.close()
}
Loading
Loading