implement-design
Implement an updated design handoff in this repo - study what changed in design/ (DESIGN.md + mockups), commit the handoff, build the new or changed pages with the tailwind-design-system and vercel-re
SKILL.md.claude/skills/implement-design/SKILL.md
GitHubImplement a design update
The design handoff in design/ is the source of truth (.claude/rules/styling.md). A design drop usually
changes design/DESIGN.md, adds design/mockups/<page>/{light,dark}/*.dc.html and touches the shared
header/footer links in every existing mockup. Work through the phases in order and keep the user posted.
1. Study the change
git status --short design/andgit diff design/DESIGN.md: the new sections (## N. <Page> (/route)) are the spec. Read related older sections too (tokens §2, dark mapping §10) when the new one refers to them.git diff --stat design/mockupsthen a sample diff of an existing mockup: often only nav links changed (e.g. a live-site URL became an internal route) and need the same change insrc/content/site.tslinks.- Render the mockups:
python3 scripts/render-mockups.py(writes.design-preview/). If a new page needs fixed values for time-dependent holes, extend the script like thehomecase. - Read each new mockup at all three sizes (
awk '/<main/,/<\/main>/' <file>keeps it short, andgrep -v '<path\|<svg'drops icon noise) plus itsclass Componentscript: it holds the logic (filters, live status) and the sample data. Diff light vs dark to get the dark colours, then map every hex to an existing token insrc/styles/globals.css(white cards in light →raisedin dark, etc.). - Before coding, list for yourself: routes, data model changes (
src/content/types/<group>.ts), pure logic forsrc/lib/<group>/(with tests), server vs client components (client only for "now", state or browser APIs), and anything the spec leaves open. Ask the user only about choices that change what you build.
2. Commit the design handoff
Commit the design changes on their own, before touching any code, with the commit skill. That keeps the
handoff separate from the implementation in the history.
- Stage only
design/(git add design/); leave everything else unstaged. - Use a
docs(design)message naming the new or changed pages, e.g.docs(design): add the Pořad bohoslužeb and Kontakty handoff. - This commit is docs-only, so the
commitskill's build check does not apply to it.
3. Implement
Load the tailwind-design-system and vercel-react-best-practices skills (Skill tool) before
writing components, and follow the project rules (.claude/rules/*.md, loaded per path):
- Content stays in
src/content/, behindsrc/content/types/; one data source per concept (e.g. the regular schedule feeds both the homepage and Pořad bohoslužeb). Update.claude/rules/content-and-time.mdwhen the data model changes. - Pure date/logic in
src/lib/<group>/*.tswith Vitest tests (.claude/rules/structure.md) (Prague time,pragueWeekday,useNow/useTodayfor anything depending on "now"; client components getrenderedAt={BUILD_TIME}). - Components in
src/components/<group>/, one per block, one markup for all breakpoints (contents,order-*, grid,max-*), tokens only (no hex, no arbitrary values; add a token in both themes if needed),cvafor variants,clsxto join classes, no duplicate utilities for one property. - Pages in
src/app/<route>/page.tsxwithmetadata,<SiteHeader currentHref=…>,<main id="obsah" className="container-page …">,PageHeading. Rememberoutput: "export": nothing that needs a server. - JS-only controls get
data-js-onlyplus<noscript><style>[data-js-only]{display:none}</style></noscript>. - Update README.md (project layout),
.claude/rules/structure.mdif a new group appears, and.claude/rules/design-check.md(page list).
Known traps from earlier drops:
- Mockup links/buttons are
content-box:min-height: 52px+padding: 8px 0is 68px tall, + a 2px border is 56px. Tailwind isborder-box, so add padding/border to the min-height. - The mockup renders use a fallback font when Google Fonts doesn't load, so their text runs wider; compare layout and spacing, not where lines wrap.
- Rules beat the mockup: never white text on green or orange (use
on-orange/on-green), coloured text uses*-ink, arrows areArrowRightIcon(Oxygen has no→) and a text link with one isArrowLink, placeholders like[foto]/[mapa]become designed placeholders,href="#"needs a real URL.
4. Verify
pnpm format && pnpm test && pnpm lint && pnpm exec tsc --noEmit && pnpm build.- Serve both:
python3 -m http.server -d out 4173andpython3 -m http.server -d .design-preview 4174(background). Use the Playwright MCP tools (load them with ToolSearch) or Claude in Chrome. - Screenshot mockup and build per page at viewport widths 405, 849, 1455 (mockup width + ~15px),
light and dark (
emulateMedia({ colorScheme: 'dark' })), into the scratchpad, e.g. withbrowser_run_code_unsafe:
Paste each pair side by side with PIL (mockup | build, scaled to ≤ 1800px tall) and Read the result; one composite per size is far cheaper than separate images.async (page) => { const dir = "<scratchpad>/shots", pages = [["<page>", "/<route>/"]]; for (const [name, route] of pages) for (const [file, w] of [ ["mobile-390", 405], ["tablet-834", 849], ["desktop-1440", 1455], ]) { await page.setViewportSize({ width: w, height: 900 }); await page.goto(`http://localhost:4174/mockups/${name}/light/${file}.html`); await page.screenshot({ path: `${dir}/${name}-${file}-mock.png`, fullPage: true }); await page.goto(`http://localhost:4173${route}`); await page.waitForTimeout(400); await page.screenshot({ path: `${dir}/${name}-${file}-build.png`, fullPage: true }); } }; - Also check: no horizontal scroll (
document.documentElement.scrollWidthequals the viewport width), the interactions (filters, copy buttons, live status), the page with JavaScript disabled (new browser context withjavaScriptEnabled: false), and that pages sharing changed data (e.g. the homepage) still render. - Fix differences, rebuild and check again until the build matches.
5. Commit the implementation
Once everything in step 4 passes, commit the implementation with the commit skill. That skill runs the
full check again and validates the message with commitlint.
- Stage the code, tests and docs explicitly. Never stage
out/,.design-preview/,.playwright-mcp/or screenshots. - If the work has independent parts (e.g. a data-model change, each new page, docs or tooling), make one
Conventional Commit per part, in an order where every commit still builds. Otherwise make a single
feat(<scope>)commit.
Then report to the user: what was built, the data model changes, deliberate deviations from the mockup and why, open questions for the parish (copy, URLs, photos), and the commits made.