frontend-scaffold
frontend-scaffold
Convert designs and specs into production-ready React/Next.js component scaffolds with typed API hooks.
Context Files
$JAAN_CONTEXT_DIR/tech.md- Tech stack context (CRITICAL — determines framework, styling, versions)- Uses sections:
#current-stack,#frameworks,#constraints
- Uses sections:
$JAAN_CONTEXT_DIR/design.md- Design system guidelines (optional)$JAAN_CONTEXT_DIR/brand.md- Brand guidelines (optional)$JAAN_TEMPLATES_DIR/jaan-to-frontend-scaffold.template.md- Output template$JAAN_LEARN_DIR/jaan-to-frontend-scaffold.learn.md- Past lessons (loaded in Pre-Execution)${CLAUDE_PLUGIN_ROOT}/docs/extending/language-protocol.md- Language resolution protocol${CLAUDE_PLUGIN_ROOT}/docs/extending/frontend-ui-workflow-reference.md- Shared UI workflow reference (CSF3 format)
Input
Upstream Artifacts: $ARGUMENTS
Accepts 1-3 file paths or descriptions:
- frontend-design — Path to HTML preview or component description (from
/jaan-to:frontend-designoutput) - frontend-task-breakdown — Path to FE task breakdown (from
/jaan-to:frontend-task-breakdownoutput) - backend-api-contract — Path to OpenAPI YAML (from
/jaan-to:backend-api-contractoutput) - Empty — Interactive wizard
- Cross-role: optionally consumes
/jaan-to:ux-microcopy-writeoutput
Pre-Execution Protocol
MANDATORY — Read and execute ALL steps in: ${CLAUDE_PLUGIN_ROOT}/docs/extending/pre-execution-protocol.md
Skill name: frontend-scaffold
Execute: Step 0 (Init Guard) → A (Load Lessons) → B (Resolve Template) → C (Offer Template Seeding)
Also read context files if available:
$JAAN_CONTEXT_DIR/tech.md— Know the tech stack for framework-specific code generation$JAAN_CONTEXT_DIR/design.md— Know the design system patterns$JAAN_CONTEXT_DIR/brand.md— Know brand colors, fonts, tone
Language Settings
Read and apply language protocol: ${CLAUDE_PLUGIN_ROOT}/docs/extending/language-protocol.md
Override field for this skill: language_frontend-scaffold
Language exception: Generated code output (variable names, code blocks, schemas, SQL, API specs) is NOT affected by this setting and remains in the project's programming language.
PHASE 1: Analysis (Read-Only)
Thinking Mode
ultrathink
Use extended reasoning for:
- Analyzing design artifacts to derive component architecture
- Mapping API contract schemas to TypeScript interfaces and hooks
- Planning Server Component vs Client Component boundaries
- Identifying accessibility requirements per component
Step 1: Validate & Parse Inputs
For each provided path:
- frontend-design: Read HTML preview or component description, extract component list, layout, interactions
- frontend-task-breakdown: Read markdown, extract component inventory, state matrices, estimates, dependencies
- backend-api-contract: Read OpenAPI YAML, extract schemas for TypeScript interfaces, endpoints for API hooks
- Report which inputs found vs missing; suggest fallback for missing
Present input summary:
INPUT SUMMARY
─────────────
Sources Found: {list}
Sources Missing: {list with fallback suggestions}
Components: {extracted component names with atomic level}
API Endpoints: {count from API contract}
TypeScript Types: {count derivable from schemas}
Step 2: Detect Tech Stack
Read $JAAN_CONTEXT_DIR/tech.md:
- Extract frontend framework from
#current-stack(default: React v19 + Next.js v15) - Extract styling approach (default: TailwindCSS v4)
- Extract state management, testing tools
- If tech.md missing: ask framework/styling via AskUserQuestion
Storybook detection (check alongside tech stack):
Glob: .storybook/main.*— Storybook installed?Grep: "storybook" package.json— Storybook in devDependencies?Glob: src/**/*.stories.tsx— Existing stories pattern?- If detected: set
storybook_available = true(used in Steps 5, Phase 2 Output, Step 8)
Step 3: Design System Check
Read $JAAN_CONTEXT_DIR/design.md and $JAAN_CONTEXT_DIR/brand.md if available:
- Extract color tokens, typography, spacing scale
- Identify existing component patterns to extend
- Note brand guidelines affecting component appearance
Step 4: Clarify Architecture
AskUserQuestion for items not in tech.md or design.md:
- State management (TanStack Query only / + Zustand / + URL state via nuqs)
- Routing (App Router / Pages Router / custom)
- Testing (Vitest + Testing Library / Playwright / both)
- Responsive strategy (mobile-first / desktop-first / adaptive)
Step 5: Plan Component Tree
Present component tree with atomic design levels:
COMPONENT TREE
══════════════
STACK: {framework} + {styling} + {state_management}
COMPONENTS ({count} total)
──────────────────────────
Atoms: {list with estimates}
Molecules: {list with estimates}
Organisms: {list with estimates}
Templates: {list}
Pages: {list}
API HOOKS ({count})
───────────────────
{list of TanStack Query hooks with endpoints}
TYPES ({count})
───────────────
{list of TypeScript interfaces from API schemas}
STORIES ({count} — if Storybook detected)
──────────────────────────────────────────
{list of CSF3 story files to generate, one per component}
HARD STOP — Review Scaffold Plan
Use AskUserQuestion:
- Question: "Proceed with generating the frontend scaffold?"
- Header: "Generate"
- Options:
- "Yes" — Generate the scaffold code
- "No" — Cancel
- "Edit" — Let me revise the component tree or architecture first
Do NOT proceed to Phase 2 without explicit approval.
PHASE 2: Generation (Write Phase)
Phase 2 Output — Flat folder
All files in $JAAN_OUTPUTS_DIR/frontend/scaffold/{id}-{slug}/:
{id}-{slug}/
├── {id}-{slug}.md # Main doc (architecture + component map)
├── {id}-{slug}-components.tsx # React components
├── {id}-{slug}-hooks.ts # Typed API client hooks
├── {id}-{slug}-types.ts # TypeScript interfaces from API schemas
├── {id}-{slug}-pages.tsx # Page layouts / routes
├── {id}-{slug}-config.ts # Package.json + tsconfig + tailwind config
├── {id}-{slug}-stories.tsx # CSF3 Storybook stories (if Storybook detected)
├── {id}-{slug}-orval-config.ts # → project root: orval.config.ts
├── {id}-{slug}-msw-handlers.ts # → src/mocks/handlers.ts
├── {id}-{slug}-msw-browser.ts # → src/mocks/browser.ts
├── {id}-{slug}-msw-server.ts # → src/mocks/server.ts
└── {id}-{slug}-readme.md # Setup + run instructions
Include Source → Destination mapping table in {id}-{slug}-readme.md for dev-output-integrate to consume.
Step 6.5: Generate API Integration Layer (if backend-api-contract provided)
When an API contract (OpenAPI spec) is available from inputs:
-
Generate
{id}-{slug}-orval-config.ts— Orval configuration:input.target: relative path to the spec fileoutput.client:'react-query'(TanStack Query v5)output.target:'./src/lib/api/generated'output.schemas:'./src/lib/api/schemas'output.mock:true(generates MSW handlers)output.mode:'tags-split'
-
Generate
{id}-{slug}-msw-handlers.ts— MSW request handlers from spec:- For each endpoint: success handler (200/201), error handler (4xx/5xx with RFC 9457 shape)
- Import pattern:
import { http, HttpResponse } from 'msw'
-
Generate
{id}-{slug}-msw-browser.ts— MSW browser setup:import { setupWorker } from 'msw/browser'; import { handlers } from './handlers'; export const worker = setupWorker(...handlers); -
Generate
{id}-{slug}-msw-server.ts— MSW Node.js server setup:import { setupServer } from 'msw/node'; import { handlers } from './handlers'; export const server = setupServer(...handlers); -
Update
{id}-{slug}-config.ts: add to devDependencies:orval,msw,msw-storybook-addon. Add script:"generate:api": "orval --config ./orval.config.ts".
Reference: See
${CLAUDE_PLUGIN_ROOT}/docs/extending/openapi-integration-reference.mdfor Orval config patterns, MSW handler patterns, and flat output conventions.
Step 7: Generate Content
Read $JAAN_TEMPLATES_DIR/jaan-to-frontend-scaffold.template.md and populate all sections based on Phase 1 analysis.
If tech stack needed, extract sections from tech.md:
- Current Stack:
#current-stack - Frameworks:
#frameworks - Constraints:
#constraints
Step 8: Quality Check
Validate generated output against checklist:
- All components from task breakdown inventory generated
- Server Components default;
'use client'only where needed - TypeScript interfaces match API contract schemas
- TanStack Query hooks for client-side data fetching
- Loading/error/empty/success states on all data components
- Accessibility: ARIA, semantic HTML, keyboard nav
- No anti-patterns present in generated code
- Framework-implied build dependencies included (e.g.,
babel-plugin-react-compilerwhenreactCompiler: true) - CSF3 stories generated for each component (if
storybook_available) — see${CLAUDE_PLUGIN_ROOT}/docs/extending/frontend-ui-workflow-reference.mdsection "CSF3 Story Format Spec"
If any check fails, fix before preview.
Step 9: Preview & Approval
Present generated output summary. Use AskUserQuestion:
- Question: "Write scaffold files to output?"
- Header: "Write Files"
- Options:
- "Yes" — Write the files
- "No" — Cancel
- "Refine" — Make adjustments first
Step 10: Generate ID and Folder Structure
source "${CLAUDE_PLUGIN_ROOT}/scripts/lib/id-generator.sh"
SUBDOMAIN_DIR="$JAAN_OUTPUTS_DIR/frontend/scaffold"
mkdir -p "$SUBDOMAIN_DIR"
NEXT_ID=$(generate_next_id "$SUBDOMAIN_DIR")
slug="{project-name-slug}"
OUTPUT_FOLDER="${SUBDOMAIN_DIR}/${NEXT_ID}-${slug}"
Preview output configuration:
Output Configuration
- ID: {NEXT_ID}
- Folder:
$JAAN_OUTPUTS_DIR/frontend/scaffold/{NEXT_ID}-{slug}/- Main file:
{NEXT_ID}-{slug}.md
Step 11: Write Output
- Create output folder:
mkdir -p "$OUTPUT_FOLDER" - Write all scaffold files to
$OUTPUT_FOLDER - Update subdomain index:
source "${CLAUDE_PLUGIN_ROOT}/scripts/lib/index-updater.sh"
add_to_index \
"$SUBDOMAIN_DIR/README.md" \
"$NEXT_ID" \
"${NEXT_ID}-${slug}" \
"{Project Title}" \
"{Executive summary — 1-2 sentences}"
- Confirm completion:
Scaffold written to:
$JAAN_OUTPUTS_DIR/frontend/scaffold/{NEXT_ID}-{slug}/Index updated:$JAAN_OUTPUTS_DIR/frontend/scaffold/README.md
Step 12: Suggest Next Actions
Scaffold generated successfully!
Next Steps:
- Copy scaffold files to your project directory
- Run
npm installto install dependencies- Run
/jaan-to:frontend-story-generateto generate additional Storybook stories- Run
/jaan-to:frontend-visual-verifyto visually verify components (requires Playwright MCP)- Run
/jaan-to:dev-output-integrateto integrate scaffold into project- Run
/jaan-to:qa-test-casesto generate test cases
Step 13: Capture Feedback
Use AskUserQuestion:
- Question: "How did the scaffold turn out?"
- Header: "Feedback"
- Options:
- "Perfect!" — Done
- "Needs fixes" — What should I improve?
- "Learn from this" — Capture a lesson for future runs
If "Learn from this": Run /jaan-to:learn-add frontend-scaffold "{feedback}"
Key Generation Rules (Research-Informed)
React 19 Patterns (CRITICAL — differs from React 18):
- Server Components are default — only add
'use client'when needed async/awaitin Server Components, NOTuseEffect+useStateuse(promise)with Suspense, NOTuseEffect; never create promises during render (infinite loops)refis a regular prop, NOTforwardRef- React Compiler (stable v1.0, October 2025) handles memoization — no
useMemo/useCallback/React.memo; enable innext.config.tswith{ reactCompiler: true }; requiresbabel-plugin-react-compilerin devDependencies; up to 12% faster initial loads useActionState+useFormStatus(must be in child component of<form>) for forms- Server Actions for mutations, ES6 default parameters (NOT
defaultProps) <Context.Provider>deprecated — use<Context>directlyrefcallbacks support cleanup functions
TailwindCSS v4 Patterns:
- CSS-first config:
@import "tailwindcss"+@theme { }— NOtailwind.config.js - Dark mode:
@custom-variant dark (&:where(.dark, .dark *))+next-themes cn()helper (clsx + tailwind-merge), OKLCH colors- v3→v4 breaking syntax:
!bg-red-500→bg-red-500!(suffix),@layer utilities→@utility,bg-[--my-var]→bg-(--my-var); requires Safari 16.4+, Chrome 111+, Firefox 128+ - PostCSS uses
@tailwindcss/postcssas single plugin — autoprefixer is built-in - Content detection is automatic (no
contentarray)
Component Generation:
- 4 states per data component: loading, error, empty, success
- Atomic Design: Atoms -> Molecules -> Organisms -> Templates
- Feature-based organization,
aria-*on all interactive elements - Minimum 24x24px touch targets (WCAG 2.2 AA); 44x44px recommended (AAA / mobile guideline)
- Use semantic HTML (
<button>,<nav>,<main>) before ARIA; enforce witheslint-plugin-jsx-a11y
API Integration:
- Orval v7 for TypeScript types + TanStack Query hooks from OpenAPI (ready-to-use
useQuery/useMutationwith auto-generated keys) - Alternative:
openapi-typescript(~1.68M weekly downloads) generates only TypeScript types with zero runtime; companionopenapi-fetchprovides type-safecreateClient<paths>()wrapper; requires manually writing TanStack Query hooks but offers more control - TanStack Query v5 for client-side fetching;
HydrationBoundaryfor RSC → client data handoff (prefetch withqueryClient.prefetchQuery(), dehydrate cache, wrap in<HydrationBoundary state={dehydrate(queryClient)}>) - Use
queryOptions()factories for type-safe, reusable query definitions with hierarchical key factories - Separate generated API code into
src/lib/api/generated/— treated as dependency, never hand-edited - Add
"generate:api": "orval --config ./orval.config.ts"to package.json
State Management:
- Server/API data → TanStack Query v5
- Local state →
useState/useReducer - Global client state → Zustand v5 (no Provider needed, ~1KB gzip); use targeted selectors to minimize re-renders
- URL state →
nuqsv2.5+ (used by Sentry, Supabase, Vercel); type-safe parsers, server-side viacreateLoader() - Form state →
useActionState+useFormStatus - Optimistic UI →
useOptimistic(React 19); instant UI feedback, auto-reconcile or rollback
Next.js 15 Caching:
fetch()defaults tono-store(wasforce-cachein v14); opt into caching withcache: 'force-cache'ornext: { revalidate: 3600 }unstable_cachedeprecated — use'use cache'directive withcacheTag()andcacheLife()- Server Actions for internal mutations; Route Handlers (
route.ts) for external consumers - ESLint 9 flat config (
eslint.config.mjs) replaces.eslintrc.json
CSF3 Story Patterns (when storybook_available):
Reference: See
${CLAUDE_PLUGIN_ROOT}/docs/extending/frontend-ui-workflow-reference.mdfor CSF3 format spec, CVA variant detection, argTypes controls, and state coverage matrix.
- Generate one
{ComponentName}.stories.tsxper component - Use
Meta<typeof Component>+StoryObj<typeof meta>pattern - Cover: Default, Loading, Error, Empty, each CVA variant
- Declarative
argsobjects only (no render functions) - Match existing story conventions from project's
*.stories.tsxfiles
Anti-Patterns to NEVER Generate
React 19: useEffect for data fetching, forwardRef, manual memoization (useMemo/useCallback/React.memo), defaultProps, PropTypes, <Context.Provider>
Next.js 15: 'use client' everywhere, API routes for internal mutations, unstable_cache (deprecated — use 'use cache' directive with cacheTag()/cacheLife()), next lint (removed in Next.js 16 — use ESLint CLI with eslint.config.mjs flat config)
TailwindCSS v4: tailwind.config.js, dynamic class construction, @tailwind directives, v3 bang syntax (!bg-red-500), @layer utilities
Accessibility: <div onClick>, missing alt, color-only indicators, missing form labels
Package Dependencies (Research-Validated)
Production: react ^19, react-dom ^19, next ^15, @tanstack/react-query ^5.60, zustand ^5, nuqs ^2.5, next-themes ^0.4, clsx ^2.1, tailwind-merge ^2.6, zod ^3.23, axios ^1.7
Dev: typescript ^5.7, @types/react ^19, @types/node ^22, @tailwindcss/postcss ^4, tailwindcss ^4, eslint ^9, prettier ^3.4, orval ^7, vitest ^2, @testing-library/react ^16, eslint-plugin-jsx-a11y, babel-plugin-react-compiler (when reactCompiler: true)
Skill Alignment
- Two-phase workflow with HARD STOP for human approval
- Framework-agnostic with
tech.mddetection - Template-driven output structure
- Output to standardized
$JAAN_OUTPUTS_DIRpath
Definition of Done
- All components from frontend-task-breakdown inventory generated
- Server Components default;
'use client'only where needed - TypeScript interfaces from API contract schemas
- TanStack Query hooks for client-side data fetching
- Loading/error/empty/success states on all data components
- Accessibility: ARIA, semantic HTML, keyboard nav
- TailwindCSS v4 CSS-first config
- Responsive mobile-first breakpoints
- CSF3 stories generated per component (if Storybook detected)
- Setup README complete
- Output follows v3.0.0 structure
- Index updated with executive summary
- User approved final result