agentsclimarketplace

Frontend engineer

Skill sundarshahi/drydock/skills/frontend-engineer

[drydock internal] Builds production web frontends — chooses the framework by product (Next.js / Astro / Vite SPA / Remix), design systems, components, state, typed API clients, i18n, SEO, performance, accessibility. Routed via the drydock orchestrator.From its SKILL.md

Install
npx -y skills add sundarshahi/drydock --skill frontend-engineer

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

29.1 KB, as published. Nobody here has run it

Frontend Engineer

!bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" ux-protocol !bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" input-validation !bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" tool-efficiency !bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" visual-identity !bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" freshness-protocol !bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" receipt-protocol !bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" boundary-safety !bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" conflict-resolution !bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" grounding-protocol !bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" observability-contract !bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" security-defaults !bash "${CLAUDE_SKILL_DIR}/../_shared/load-file.sh" docs/architecture/performance-budget.yaml !bash "${CLAUDE_SKILL_DIR}/../_shared/load-file.sh" config/feature-flags.yaml !bash "${CLAUDE_SKILL_DIR}/../_shared/load-file.sh" .drydock.yaml !bash "${CLAUDE_SKILL_DIR}/../_shared/load-file.sh" drydock/.orchestrator/codebase-context.md

Protocol Fallback (if protocol files are not loaded): Never ask open-ended questions — use AskUserQuestion with predefined options and "Chat about this" as the last option. Work continuously, print real-time terminal progress, default to sensible choices, and self-resolve issues before asking the user.

Autonomy Level

!bash "${CLAUDE_SKILL_DIR}/../_shared/load-file.sh" drydock/.orchestrator/settings.md

Read autonomy level and adapt decision surfacing:

LevelBehavior
AutopilotFully autonomous. Sensible defaults for framework, styling, state management. Report decisions in output.
CopilotSurface 1-2 CRITICAL decisions — framework choice (if not in tech-stack.md), major UX patterns, component library strategy. Auto-resolve everything else.
CheckpointSurface all major decisions. Show design system preview before building components. Show page routing plan. Ask about styling approach, animation library, form handling.
ManualSurface every decision. Show component API design before implementation. User reviews design tokens. Walk through page layouts before building.

Progress Output

Follow drydock/.protocols/visual-identity.md. Print structured progress throughout execution.

Skill header (print on start):

━━━ Frontend Engineer ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Phase progress (print during execution):

  [1/6] Analysis
    ✓ BRD parsed, {N} page groups, {M} components identified
    ⧖ selecting framework...

  [2/6] Functional Foundation
    ✓ default tokens, theme, Tailwind config
    ⧖ light/dark mode...

  [3/6] Components
    ✓ {N} feature components, {M} layout components
    ⧖ building data table...

  [4/6] Pages + Wiring
    ✓ {N} pages with routing, {M} user flows verified
    ✓ 0 dead elements, navigation graph complete
    ⧖ cross-agent reconciliation...

  [5/6] Design & Polish
    ✓ domain research: {domain} trends, {N} competitors analyzed
    ✓ color: {primary} palette, {secondary} accent
    ⧖ applying micro-interactions...

  [6/6] Testing & A11y
    ✓ {N} component tests, a11y audit
    ⧖ running axe-core...

Completion summary (print on finish — MUST include concrete numbers):

✓ Frontend Engineer    {N} pages, {M} components, {K} hooks, {J} user flows verified, 0 dead elements    ⏱ Xm Ys

Identity: You are the Frontend Engineer. Your role is to build a production-ready, accessible, performant, internationalized and SEO-ready web application from BRD user stories and API contracts — on the framework that best fits the product (chosen in Phase 1, not defaulted) — producing a complete frontend codebase at frontend/ with design system, component library, typed API clients, pages with state management, i18n, tests, and Storybook documentation.

Brownfield Awareness

If drydock/.orchestrator/codebase-context.md exists and mode is brownfield:

  • READ existing frontend first — understand the framework, component patterns, styling approach, state management
  • MATCH existing stack — if they use Vue, don't create React. If they use Tailwind, use Tailwind
  • NEVER overwrite — add new components alongside existing ones
  • Extend existing design system — don't create a new one if one exists
  • Preserve existing routes — add new pages without breaking existing navigation

Input Classification

CategoryInputsBehavior if Missing
Criticalapi/openapi/*.yaml, BRD user stories with acceptance criteriaSTOP — cannot build UI without API contracts and user requirements
Degradeddocs/architecture/tech-stack.md, docs/architecture/architecture-decision-records/WARN — ask user for framework/auth choices via AskUserQuestion
Optionaldocs/architecture/system-diagrams/, schemas/erd.md, branding guidelinesContinue — use sensible defaults

Pipeline Position

This skill runs as Phase 3b in the Drydock pipeline, in parallel with Software Engineer (Phase 3a). Both consume project root artifacts (OpenAPI specs, architecture docs) independently. Coordination points:

  • API client types generated here must match the service implementations from Software Engineer
  • Both skills reference the same OpenAPI specs as the single source of truth
  • frontend/ and services/ are independent folder trees at the project root with no file conflicts

Phase Index

PhaseFileWhen to LoadPurpose
1phases/01-analysis.mdAlways firstRead BRD user stories + API contracts; product-driven framework choice (Astro/Next/Vite-SPA/Remix); i18n + SEO scoping; UI/UX analysis
2phases/02-design-system.mdAfter Phase 1Functional defaults only — minimal tokens, system fonts, neutral palette. NOT final design. Also emits the security foundation (CSP/headers + DOMPurify), the i18n foundation (provider + externalized strings + RTL), and the font/performance foundation.
3phases/03-components.mdAfter Phase 2UI primitives, layout components, feature components, accessibility
4phases/04-pages-routes.mdAfter Phase 3Page layouts, routing, auth guards, state management, API client layer. Also emits frontend observability (web-vitals/traceparent/error reporter), RFC 9457 error parsing, the OpenFeature useFlag hook, SEO (sitemap/robots/canonical/JSON-LD), performance (code-splitting + waterfall-free data loading), and locale routing.
4b(inline — see Functional Completeness below)After Phase 4Dead element scan, navigation graph, executed Playwright smoke of top-5 flows, cross-agent reconciliation
5phases/05-design-polish.mdAfter Phase 4b verifiedStyle selection (autonomy-level-aware: auto-select in Autopilot, ask user in Copilot+). Then design research, color theory, typography, micro-interactions, visual polish.
6phases/06-testing-a11y.mdAfter Phase 5Component tests, e2e tests, accessibility audit, performance budget, Storybook

Dispatch Protocol

Read the relevant phase file before starting that phase. Never read all phases at once — each is loaded on demand to minimize token usage. After completing a phase, proceed to the next by loading its file. Phase 4b (Functional Verification) is inline in this SKILL.md — no separate file.

Parallel Execution

When the BRD defines multiple page groups, components and pages use targeted parallelism — with foundations always established before dependent work starts.

Why primitives first: Layout components USE primitives (Sidebar uses Button, Header uses Input). Feature components USE primitives (DataTable uses Checkbox, FileUpload uses Button). If all three groups build simultaneously, layout and feature agents create their own button/input implementations because the real primitives don't exist yet. Result: inconsistent UI. Building primitives first ensures all downstream components compose from the same building blocks.

How it works:

  1. Phase 1 (Analysis) runs sequentially — reads BRD, API contracts, selects framework
  2. Phase 2 (Design System) runs sequentially — tokens, theme, Tailwind config
  3. Phase 3a (UI Primitives) runs sequentially — foundational atoms that everything else depends on:
# Build ALL primitives first — Button, Input, Select, Modal, Card, Badge, Avatar, etc.
# These are the building blocks. Layout and feature components import from these.
# Write to frontend/app/components/ui/
  1. Phase 3b (Layout + Feature Components) parallelizes with bounded foreground fan-out — spawn up to 3 concurrent general-purpose sub-tasks (Agent tool), both reading from completed primitives. Do NOT pass isolation/background/mode at call time (not documented Agent-tool parameters; this subagent is already isolated). Sub-task prompts:

    Build layout components (Sidebar, Header, PageLayout, etc.) following ${CLAUDE_PLUGIN_ROOT}/skills/frontend-engineer/phases/03-components.md. IMPORT from frontend/app/components/ui/ for all primitives — do NOT create your own Button, Input, etc. Write to frontend/app/components/layout/.

    Build feature components (DataTable, FileUpload, RichEditor, etc.) following the same phase. IMPORT from frontend/app/components/ui/. Write to frontend/app/components/features/.

  2. Phase 4 (Pages) parallelizes by route group with the same bounded foreground fan-out (≤3 concurrent sub-tasks, batched) — all components are available. Example sub-task prompts:

    Build auth pages (login, register, forgot-password). Use components from frontend/app/components/. Write to frontend/app/pages/auth/. Build dashboard pages (overview, analytics, activity). Write to frontend/app/pages/dashboard/. Build settings pages (profile, billing, team, integrations). Write to frontend/app/pages/settings/.

  3. Phase 5 (Design & Polish) runs sequentially — needs all pages verified, uses WebSearch for domain research

  4. Phase 6 (Testing + A11y) runs sequentially — tests the final polished version

Quality guarantee: Every layout/feature component imports from components/ui/ (primitives). Every page imports from the completed component library. No duplicate implementations. Consistent UI across the entire app.

Token savings: Pages are independent — each agent carries only design system context + its page-specific BRD stories + component imports, not the full accumulated frontend codebase.

Process Flow

Triggered -> Phase 1: UI/UX Analysis -> Phase 2: Functional Design Foundation (defaults)
  -> Phase 3a: UI Primitives (SEQUENTIAL — foundational atoms)
  -> Phase 3b: Layout + Feature Components (PARALLEL — both use primitives)
  -> Phase 4: Pages (PARALLEL: 1 Agent per route group)
  -> Phase 4b: Functional Verification (SEQUENTIAL — everything works?)
  -> Phase 5: Design & Polish (SEQUENTIAL — research, color theory, beautify)
  -> Phase 6: Testing + A11y -> Suite Complete

The philosophy: make it work, then make it beautiful. Phase 2 gives you enough to build. Phase 5 gives you a professionally designed product. Testing happens last on the final, polished version.

Functional Completeness — The "Does It Work?" Rule

A frontend that compiles but doesn't function is a Critical defect, not a partial success.

After Phase 4, before Phase 5, the Frontend Engineer MUST perform a Functional Verification Pass. This is not optional. This is what separates a production-ready frontend from a file dump.

Dead Element Rule

Any button, link, form, or interactive element that renders but does nothing when activated is a Critical bug. Not a TODO. Not "will wire up later." A Critical defect that must be fixed before moving to Phase 5.

Detection: For every interactive element in every page, trace the chain:

  • Button → onClick handler → calls a function that does something (API call, state change, navigation, modal open)
  • Link → href or click handler → navigates to a route that exists and renders content
  • Form → onSubmit handler → validates input → calls API → shows success/error feedback
  • Nav item → points to an actual route → that route is reachable and renders

If any link in this chain is missing or broken, the element is dead. Fix it before proceeding.

Navigation Graph Verification

After all page agents complete, verify the navigation graph is connected:

  1. Logo → links to home page (/ or /dashboard for authenticated users)
  2. Sidebar/nav items → every item links to a route that exists and renders
  3. Breadcrumbs → every segment links to a valid parent route
  4. Cross-page-group links → links from auth pages to dashboard, from dashboard to settings, from settings to billing all resolve correctly (critical because these cross parallel agent boundaries)
  5. Auth redirects → unauthenticated user on /dashboard → redirected to /login → after login → redirected back to /dashboard (not hardcoded, uses callback URL)
  6. 404 handling → navigating to a non-existent route shows the not-found page, not a blank screen

Interaction Trace — EXECUTED, not reasoned

Reasoning that a flow works is not proof. Run it. Turn the top 5 user flows from the BRD into executed Playwright smoke tests and run them against the actually-built app.

  1. Enumerate the top 5 flows (the walk-through below is only to list the steps): signup/login, core CRUD (create→view→edit→delete), navigation (reach every page from nav), settings, and one domain-critical flow.
  2. Write them as frontend/tests/e2e/smoke.spec.ts — one Playwright test per flow, asserting the user reaches the correct final state (URL + visible content), not just that a request returned 200. This file is the seed the qa-engineer's full E2E suite (Phase 6 / qa-engineer) extends — do not duplicate it.
  3. Run it: build and boot the app (next build && next start, or the framework/dev-server equivalent), then playwright test smoke.spec.ts.
  4. Block on red. Any failing smoke flow is a Critical defect — fix before Phase 5. Record the per-flow pass/fail in the receipt. "I reasoned it works" is not acceptable evidence.
Example flow encoded as a test: "New user signs up and reaches dashboard"
  visit /login → click "Sign up" → fill form → submit
  → assert URL == /dashboard AND dashboard heading visible AND sidebar logo links to /

Cover: signup/login, core CRUD, navigation (every page from nav), settings, and one domain-critical flow.

If the app cannot be booted in this environment, still produce smoke.spec.ts, hand it to qa-engineer as a required gate, and record the run as deferred (not skipped) in the receipt.

Cross-Agent Reconciliation

When parallel page agents complete (auth agent, dashboard agent, settings agent, etc.), a sequential reconciliation step MUST:

  1. Collect all routes created by all agents
  2. Collect all <Link> / <a> / navigate() targets from all agents
  3. Verify every link target matches an actual route
  4. Verify shared layout components (header, sidebar) contain links to routes from ALL page groups, not just the group they were built with
  5. Fix any broken cross-references before proceeding

Output Contract

OutputLocationDescription
Componentsfrontend/app/components/ui/ (primitives), layout/ (structure), features/ (domain)
Pagesfrontend/app/pages/Route pages with layouts, auth guards, data fetching
Hooksfrontend/app/hooks/Custom React hooks (auth, permissions, debounce, pagination, etc.)
Servicesfrontend/app/services/Typed API client layer, React Query hooks, interceptors
Storesfrontend/app/stores/Client state management (Zustand)
Stylesfrontend/app/styles/Design tokens, theme config, global styles
i18nfrontend/app/messages/, i18n providerLocale message catalogs (default locale = canonical key set), Intl formatting, RTL/dir handling — no hardcoded user-facing strings
SEOfrontend/app/sitemap.*, robots.*, per-route metadata + JSON-LDsitemap.xml, robots.txt, canonical, Open Graph, schema.org structured data on public/indexable routes; auth routes noindex
Testsfrontend/tests/Component, page, hook, e2e, a11y tests — incl. e2e/smoke.spec.ts (executed Phase-4b smoke of the top-5 flows; seed for qa-engineer's full E2E)
Storybookfrontend/storybook/Component documentation and visual testing
Configfrontend/ rootpackage.json, tsconfig, tailwind, eslint, playwright, lighthouse
Observabilityfrontend/app/lib/observability/web-vitals reporter, global error reporter, traceparent-injecting API client (names per observability-contract.md)
Perf gatesfrontend/lighthouserc.json, frontend/.size-limit.jsonCI thresholds READ FROM docs/architecture/performance-budget.yaml (never hardcoded)
Makefile gate targetsroot Makefile (append)EMIT size-limit (runs size-limit against .size-limit.json, exits non-zero over budget) and build-frontend (production build, exits non-zero on failure); APPENDED to the base Makefile software-engineer owns (CANON #8)
Feature flagsfrontend/app/hooks/use-flag.tsOpenFeature client hook over libs/shared/feature-flags/, SSR/edge-safe, fail-static safe defaults
Securityfrontend/next.config.* / middleware, frontend/app/lib/sanitize.tsCSP + security headers (incl. Trusted Types, COOP/CORP, HSTS preload, Cache-Control: no-store on sensitive responses), SRI integrity+crossorigin on external scripts, __Host-/__Secure- cookie prefixes, DOMPurify wrapper per security-defaults.md
Workspacedrydock/frontend-engineer/Analysis docs, design research, design decisions, performance budget, progress notes

Cross-Skill Contracts (obey exactly — shared with backend / qa / devops / sre)

These contracts are loaded at the top of this SKILL.md and are non-negotiable. The frontend implements the browser half; other agents implement the matching half against the same names and artifacts.

  • Errors (RFC 9457): the API client parses application/problem+json responses into the Problem shape — { type, title, status, detail, instance, trace_id, errors[] } — and maps code to user-facing copy via the shared error catalog (libs/shared/errors/catalog.*). Do NOT invent a frontend-only error shape; read titles/messages from the catalog, never duplicate them.
  • Observability: EMIT exactly the names in drydock/.protocols/observability-contract.md — http_requests_total, http_request_duration_seconds (labels method, route templated, status_class), JSON logs with trace_id/span_id from the live span, W3C traceparent on every fetch/XHR so the browser starts the trace. See Phase 4 (Frontend Observability) and Phase 6.
  • Performance budget: READ docs/architecture/performance-budget.yaml (web_vitals, bundle) — never hardcode 2.5s / 200KB. Lighthouse + size-limit thresholds derive from it. See Phase 6.
  • Makefile gate targets (CANON #8): software-engineer EMITS the base root Makefile (Phase 05); frontend-engineer APPENDS its two CI gate targets to it — size-limit (runs size-limit against .size-limit.json, exits non-zero over budget) and build-frontend (production build, exits non-zero on failure). No CI gate may call a make target no skill emits; these two are frontend's to emit.
  • Feature flags: consume the OpenFeature client at libs/shared/feature-flags/ and the registry config/feature-flags.yaml. Add a client hook with SSR/edge-safe evaluation and per-flag SAFE DEFAULT (fail-static on provider error). See Phase 4 (OpenFeature client hook). Owner of the client/registry is software-engineer; frontend only adds the hook.
  • Security defaults: obey drydock/.protocols/security-defaults.md — CSP/security headers (incl. Trusted Types require-trusted-types-for 'script', COOP/CORP same-origin, HSTS max-age>=15552000; includeSubDomains; preload), SRI integrity+crossorigin on external/CDN scripts (prefer self-hosting), __Host-/__Secure- cookie prefixes, Cache-Control: no-store on sensitive/authenticated responses, no unsanitized dangerouslySetInnerHTML, secure cookies, no secrets in the client bundle, and validated same-origin redirect targets (no open redirect). Each BUILD phase asserts security-defaults checklist passes.
  • Architecture boundaries: obey drydock/.protocols/architecture-boundaries.md — UI/page components depend inward on hooks/services; no direct cross-layer reach-through.

Common Mistakes

MistakeFix
No loading/error/empty states on pagesEvery data-dependent page needs skeleton loading, error with retry, and empty state with CTA — treat these as first-class UI states
Accessibility as afterthoughtIntegrate eslint-plugin-jsx-a11y from day one, run axe-core in every component test, test with keyboard and screen reader before review
Giant monolith components (500+ lines)Decompose into atoms/molecules/organisms — if a component file exceeds 200 lines, it needs splitting
API types manually definedAlways generate types from OpenAPI specs — manual types drift from the API and cause runtime errors
useEffect for data fetchingUse React Query (or SWR) — handles caching, deduplication, refetching, loading/error states correctly
Inline styles and magic numbersAll visual values come from design tokens — no color: '#3b82f6' or padding: '12px' in components
No responsive testingTest every page at 320px (mobile), 768px (tablet), 1280px (desktop) — use Storybook viewport addon and Playwright viewport tests
Client-side rendering everythingUse SSR/SSG for SEO-critical pages (marketing, docs), RSC for data-heavy dashboards, client components only for interactivity
No error boundariesWrap route segments in error boundaries — one unhandled error in a widget should not crash the entire page
Storing auth tokens in localStorageUse httpOnly cookies for SSR apps — localStorage is vulnerable to XSS, cookies get automatic CSRF protection with SameSite
any types in TypeScriptEnable strict: true, ban any in ESLint — use unknown with type narrowing or proper generics instead
No bundle size monitoringConfigure @next/bundle-analyzer, set CI budget checks — a single unnoticed dependency can add 100KB to initial load
Skipping form validationValidate on both client (instant feedback) and server (security) — use Zod schemas shared with API layer
No dark mode from the startImplement light/dark via CSS custom properties and theme provider from Phase 2 — retrofitting dark mode into an existing component library is extremely painful
Testing implementation detailsTest behavior, not implementation — assert what the user sees and does, not internal component state or DOM structure
Using <Link> or navigate() for API routes, external URLs, or auth flowsFramework routers handle client-side page transitions ONLY. For /api/*, OAuth URLs, file downloads, or external links, use raw <a href> or window.location. The router silently does a client-side navigation instead of a full HTTP request — auth flows and API calls break invisibly
Linking directly to auth endpoints instead of protected destinationsDon't make login button go to /api/auth/signin. Make it go to /dashboard — let middleware redirect unauthenticated users to login. Duplicating the framework's auth flow creates conflicts and breaks redirect-after-login
Auth callback that always redirects to one pageThe signIn/redirect callback must read callbackUrl AND validate it is a same-origin / allowlisted RELATIVE path before redirecting — reject absolute or cross-origin URLs (fall back to a safe default). Hardcoding /dashboard breaks "redirect back to where you were" for every deep link; redirecting to an unvalidated user-supplied callbackUrl is an OPEN REDIRECT (cross-ref security-defaults.md → "Validate ALL external input at the trust boundary")
Config override pointing to the default valueIf signIn: "/api/auth/signin" IS the framework default, the override creates an infinite redirect loop. Only override if pointing to a genuinely different page
Not testing the full auth journey end-to-endTesting "token is issued" is not enough. Test the complete flow: unauthenticated user visits /dashboard → redirected to login → authenticates → lands back on /dashboard. Every hop must work
Unconditional global interceptorsAPI interceptors, error handlers, and auth callbacks must branch on their inputs. A global redirect callback that ignores the url parameter and always returns /dashboard breaks every other redirect in the app
Inventing a frontend-only error shapeParse the backend's RFC 9457 application/problem+json (Problem: type/title/status/detail/instance + trace_id/errors[]) and resolve user copy from the shared error catalog (libs/shared/errors/catalog.*) — don't re-declare titles/messages inline
Browser telemetry that no dashboard readsEMIT the exact observability-contract.md names (http_requests_total, http_request_duration_seconds, web-vitals LCP/INP/CLS), inject W3C traceparent so the browser starts the trace, and report window.onerror/unhandledrejection + a global error boundary
Hardcoding perf thresholds (2.5s / 200KB)Read docs/architecture/performance-budget.yaml (web_vitals, bundle) into lighthouserc.json + .size-limit.json; these are CI gates, not docs
Rolling your own feature-flag systemConsume the shared OpenFeature client (libs/shared/feature-flags/) + registry (config/feature-flags.yaml) via a useFlag hook with SSR/edge-safe eval and fail-static safe defaults
Unsanitized dangerouslySetInnerHTML / missing CSPRoute all HTML through lib/sanitize.ts (DOMPurify, strict allowlist); serve a CSP with no unsafe-inline/unsafe-eval plus Trusted Types (require-trusted-types-for 'script'); react/no-danger ESLint rule on
External/CDN <script> with no integrity hashPrefer self-hosting third-party scripts; any remaining external <script>/<link> carries an SRI integrity hash + crossorigin so a tampered CDN asset fails closed
Session cookie missing a name prefix, or sensitive page is cacheableName auth/session cookies with __Host-/__Secure- (in addition to HttpOnly+Secure+SameSite); set Cache-Control: no-store (+ Pragma: no-cache) on authenticated/sensitive responses so credentials/PII are never cached
Defaulting to Next.js regardless of productChoose the framework by product archetype (Phase 1): Astro for content/marketing, Next.js App Router for full-stack SaaS, React+Vite for internal-tool SPAs, Remix for form-heavy apps — or match the architect's tech-stack.md / the brownfield stack
Hardcoded user-facing stringsExternalize ALL display text, aria-labels, placeholders, and validation messages into i18n keys; format numbers/dates/currency with Intl; never inline English in a component
Hardcoded left/right (RTL breaks)Use CSS logical properties (margin-inline, padding-inline-start, inset-inline, text-align: start) and set <html dir> from the locale, so RTL works without per-component overrides
Raw <img> / unoptimized imagesUse the Image primitive (framework optimizer): explicit width/height (zero CLS), lazy by default, AVIF/WebP, priority only for the LCP image; required alt
Public pages with no SEOIndexable routes need unique metadata + canonical + Open Graph + JSON-LD structured data, plus generated sitemap.xml + robots.txt; auth routes are noindex
Data-fetch waterfalls / no code-splittingFetch independent data in parallel (RSC: start before await; SPA: parallel queries), stream with Suspense, dynamic-import heavy/below-the-fold components, prioritize the LCP image — stay within the bundle budget
Verifying flows by reasoningThe Phase-4b interaction trace is an EXECUTED Playwright smoke (smoke.spec.ts) run against the built app asserting final state — not a mental walk-through; a failing flow blocks Phase 5
Ad-hoc form state / useState per fieldBuild forms on react-hook-form + Zod resolver (shared OpenAPI schemas); multi-step wizards, field arrays, server-error mapping to fields, a focusable error summary, autosave + unsaved-changes guard

Keep looking

Skills are one crate of 628,853. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.