{"id":"1e76c986-97e1-457b-8f62-17bfd85acaac","entityType":"agent","slug":"clawhub-alirezarezvani-senior-frontend","name":"Senior Frontend","canonicalUrl":"https://www.xpersona.co/agent/clawhub-alirezarezvani-senior-frontend","canonicalPath":"/agent/clawhub-alirezarezvani-senior-frontend","generatedAt":"2026-10-09T14:59:25.755Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":null},"description":"Frontend development skill for React, Next.js, TypeScript, and Tailwind CSS applications. Use when building React components, optimizing Next.js performance, analyzing bundle sizes, scaffolding frontend projects, implementing accessibility, or reviewing frontend code quality. Skill: Senior Frontend Owner: alirezarezvani Summary: Frontend development skill for React, Next.js, TypeScript, and Tailwind CSS applications. Use when building React components, optimizing Next.js performance, analyzing bundle sizes, scaffolding frontend projects, implementing accessibility, or reviewing frontend code quality. Tags: latest:1.0.0 Version history: v1.0.0 | 2026-02-06T18:27:42.862Z | auto Initial rele","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.4K downloads reported by the source. Last updated 4/15/2026.","installCommand":"clawhub skill install kn7f2gr00xy51fj1nx2y64ckjs800mhn:senior-frontend","sourceUrl":"https://clawhub.ai/alirezarezvani/senior-frontend","homepage":"https://clawhub.ai/alirezarezvani/senior-frontend","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/alirezarezvani/senior-frontend","kind":"source"}],"safetyScore":84,"overallRank":62,"popularityScore":63,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Frontend development skill for React, Next.js, TypeScript, and Tailwind CSS applications. Use when building React components, optimizing Next.js performance, an"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":null},"stars":null,"forks":null,"downloads":1434,"packageName":null,"latestVersion":"1.0.0","tractionLabel":"1.4K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-02-28T22:09:01.129Z","emptyReason":null},"lastUpdatedAt":"2026-04-15T00:45:39.800Z","lastCrawledAt":"2026-02-28T22:09:01.129Z","lastIndexedAt":null,"nextCrawlAt":"2026-03-01T22:09:01.129Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.0","createdAt":"2026-02-06T18:27:42.862Z","changelog":"Initial release of the senior-frontend skill. - Provides workflows and tools for scaffolding React/Next.js projects with TypeScript and Tailwind CSS. - Supports automated generation of components, hooks, tests, and Storybook stories. - Includes bundle analysis scripts to detect heavy dependencies and recommend optimizations. - Documents advanced React patterns, including compound components, custom hooks, and render props. - Offers Next.js optimization guidance for server/client components, image usage, and data fetching. - Emphasizes code quality, accessibility, and best practices throughout.","fileCount":8,"zipByteSize":38342}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install kn7f2gr00xy51fj1nx2y64ckjs800mhn:senior-frontend","setupComplexity":"low","setupSteps":["Setup complexity is LOW. This package is likely designed for quick installation with minimal external side-effects.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alirezarezvani-senior-frontend/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alirezarezvani-senior-frontend/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alirezarezvani-senior-frontend/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-alirezarezvani-senior-frontend/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-alirezarezvani-senior-frontend/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-alirezarezvani-senior-frontend/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T14:59:25.754Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alirezarezvani-senior-frontend/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alirezarezvani-senior-frontend/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alirezarezvani-senior-frontend/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-alirezarezvani-senior-frontend/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":null},"readme":"Skill: Senior Frontend\n\nOwner: alirezarezvani\n\nSummary: Frontend development skill for React, Next.js, TypeScript, and Tailwind CSS applications. Use when building React components, optimizing Next.js performance, analyzing bundle sizes, scaffolding frontend projects, implementing accessibility, or reviewing frontend code quality.\n\nTags: latest:1.0.0\n\nVersion history:\n\nv1.0.0 | 2026-02-06T18:27:42.862Z | auto\n\nInitial release of the senior-frontend skill.\n\n- Provides workflows and tools for scaffolding React/Next.js projects with TypeScript and Tailwind CSS.\n- Supports automated generation of components, hooks, tests, and Storybook stories.\n- Includes bundle analysis scripts to detect heavy dependencies and recommend optimizations.\n- Documents advanced React patterns, including compound components, custom hooks, and render props.\n- Offers Next.js optimization guidance for server/client components, image usage, and data fetching.\n- Emphasizes code quality, accessibility, and best practices throughout.\n\nArchive index:\n\nArchive v1.0.0: 8 files, 38342 bytes\n\nFiles: references/frontend_best_practices.md (19783b), references/nextjs_optimization_guide.md (15123b), references/react_patterns.md (17341b), scripts/bundle_analyzer.py (13339b), scripts/component_generator.py (8684b), scripts/frontend_scaffolder.py (27981b), SKILL.md (10999b), _meta.json (134b)\n\nFile v1.0.0:SKILL.md\n\n---\nname: senior-frontend\ndescription: Frontend development skill for React, Next.js, TypeScript, and Tailwind CSS applications. Use when building React components, optimizing Next.js performance, analyzing bundle sizes, scaffolding frontend projects, implementing accessibility, or reviewing frontend code quality.\n---\n\n# Senior Frontend\n\nFrontend development patterns, performance optimization, and automation tools for React/Next.js applications.\n\n## Table of Contents\n\n- [Project Scaffolding](#project-scaffolding)\n- [Component Generation](#component-generation)\n- [Bundle Analysis](#bundle-analysis)\n- [React Patterns](#react-patterns)\n- [Next.js Optimization](#nextjs-optimization)\n- [Accessibility and Testing](#accessibility-and-testing)\n\n---\n\n## Project Scaffolding\n\nGenerate a new Next.js or React project with TypeScript, Tailwind CSS, and best practice configurations.\n\n### Workflow: Create New Frontend Project\n\n1. Run the scaffolder with your project name and template:\n   ```bash\n   python scripts/frontend_scaffolder.py my-app --template nextjs\n   ```\n\n2. Add optional features (auth, api, forms, testing, storybook):\n   ```bash\n   python scripts/frontend_scaffolder.py dashboard --template nextjs --features auth,api\n   ```\n\n3. Navigate to the project and install dependencies:\n   ```bash\n   cd my-app && npm install\n   ```\n\n4. Start the development server:\n   ```bash\n   npm run dev\n   ```\n\n### Scaffolder Options\n\n| Option | Description |\n|--------|-------------|\n| `--template nextjs` | Next.js 14+ with App Router and Server Components |\n| `--template react` | React + Vite with TypeScript |\n| `--features auth` | Add NextAuth.js authentication |\n| `--features api` | Add React Query + API client |\n| `--features forms` | Add React Hook Form + Zod validation |\n| `--features testing` | Add Vitest + Testing Library |\n| `--dry-run` | Preview files without creating them |\n\n### Generated Structure (Next.js)\n\n```\nmy-app/\n├── app/\n│   ├── layout.tsx        # Root layout with fonts\n│   ├── page.tsx          # Home page\n│   ├── globals.css       # Tailwind + CSS variables\n│   └── api/health/route.ts\n├── components/\n│   ├── ui/               # Button, Input, Card\n│   └── layout/           # Header, Footer, Sidebar\n├── hooks/                # useDebounce, useLocalStorage\n├── lib/                  # utils (cn), constants\n├── types/                # TypeScript interfaces\n├── tailwind.config.ts\n├── next.config.js\n└── package.json\n```\n\n---\n\n## Component Generation\n\nGenerate React components with TypeScript, tests, and Storybook stories.\n\n### Workflow: Create a New Component\n\n1. Generate a client component:\n   ```bash\n   python scripts/component_generator.py Button --dir src/components/ui\n   ```\n\n2. Generate a server component:\n   ```bash\n   python scripts/component_generator.py ProductCard --type server\n   ```\n\n3. Generate with test and story files:\n   ```bash\n   python scripts/component_generator.py UserProfile --with-test --with-story\n   ```\n\n4. Generate a custom hook:\n   ```bash\n   python scripts/component_generator.py FormValidation --type hook\n   ```\n\n### Generator Options\n\n| Option | Description |\n|--------|-------------|\n| `--type client` | Client component with 'use client' (default) |\n| `--type server` | Async server component |\n| `--type hook` | Custom React hook |\n| `--with-test` | Include test file |\n| `--with-story` | Include Storybook story |\n| `--flat` | Create in output dir without subdirectory |\n| `--dry-run` | Preview without creating files |\n\n### Generated Component Example\n\n```tsx\n'use client';\n\nimport { useState } from 'react';\nimport { cn } from '@/lib/utils';\n\ninterface ButtonProps {\n  className?: string;\n  children?: React.ReactNode;\n}\n\nexport function Button({ className, children }: ButtonProps) {\n  return (\n    <div className={cn('', className)}>\n      {children}\n    </div>\n  );\n}\n```\n\n---\n\n## Bundle Analysis\n\nAnalyze package.json and project structure for bundle optimization opportunities.\n\n### Workflow: Optimize Bundle Size\n\n1. Run the analyzer on your project:\n   ```bash\n   python scripts/bundle_analyzer.py /path/to/project\n   ```\n\n2. Review the health score and issues:\n   ```\n   Bundle Health Score: 75/100 (C)\n\n   HEAVY DEPENDENCIES:\n     moment (290KB)\n       Alternative: date-fns (12KB) or dayjs (2KB)\n\n     lodash (71KB)\n       Alternative: lodash-es with tree-shaking\n   ```\n\n3. Apply the recommended fixes by replacing heavy dependencies.\n\n4. Re-run with verbose mode to check import patterns:\n   ```bash\n   python scripts/bundle_analyzer.py . --verbose\n   ```\n\n### Bundle Score Interpretation\n\n| Score | Grade | Action |\n|-------|-------|--------|\n| 90-100 | A | Bundle is well-optimized |\n| 80-89 | B | Minor optimizations available |\n| 70-79 | C | Replace heavy dependencies |\n| 60-69 | D | Multiple issues need attention |\n| 0-59 | F | Critical bundle size problems |\n\n### Heavy Dependencies Detected\n\nThe analyzer identifies these common heavy packages:\n\n| Package | Size | Alternative |\n|---------|------|-------------|\n| moment | 290KB | date-fns (12KB) or dayjs (2KB) |\n| lodash | 71KB | lodash-es with tree-shaking |\n| axios | 14KB | Native fetch or ky (3KB) |\n| jquery | 87KB | Native DOM APIs |\n| @mui/material | Large | shadcn/ui or Radix UI |\n\n---\n\n## React Patterns\n\nReference: `references/react_patterns.md`\n\n### Compound Components\n\nShare state between related components:\n\n```tsx\nconst Tabs = ({ children }) => {\n  const [active, setActive] = useState(0);\n  return (\n    <TabsContext.Provider value={{ active, setActive }}>\n      {children}\n    </TabsContext.Provider>\n  );\n};\n\nTabs.List = TabList;\nTabs.Panel = TabPanel;\n\n// Usage\n<Tabs>\n  <Tabs.List>\n    <Tabs.Tab>One</Tabs.Tab>\n    <Tabs.Tab>Two</Tabs.Tab>\n  </Tabs.List>\n  <Tabs.Panel>Content 1</Tabs.Panel>\n  <Tabs.Panel>Content 2</Tabs.Panel>\n</Tabs>\n```\n\n### Custom Hooks\n\nExtract reusable logic:\n\n```tsx\nfunction useDebounce<T>(value: T, delay = 500): T {\n  const [debouncedValue, setDebouncedValue] = useState(value);\n\n  useEffect(() => {\n    const timer = setTimeout(() => setDebouncedValue(value), delay);\n    return () => clearTimeout(timer);\n  }, [value, delay]);\n\n  return debouncedValue;\n}\n\n// Usage\nconst debouncedSearch = useDebounce(searchTerm, 300);\n```\n\n### Render Props\n\nShare rendering logic:\n\n```tsx\nfunction DataFetcher({ url, render }) {\n  const [data, setData] = useState(null);\n  const [loading, setLoading] = useState(true);\n\n  useEffect(() => {\n    fetch(url).then(r => r.json()).then(setData).finally(() => setLoading(false));\n  }, [url]);\n\n  return render({ data, loading });\n}\n\n// Usage\n<DataFetcher\n  url=\"/api/users\"\n  render={({ data, loading }) =>\n    loading ? <Spinner /> : <UserList users={data} />\n  }\n/>\n```\n\n---\n\n## Next.js Optimization\n\nReference: `references/nextjs_optimization_guide.md`\n\n### Server vs Client Components\n\nUse Server Components by default. Add 'use client' only when you need:\n- Event handlers (onClick, onChange)\n- State (useState, useReducer)\n- Effects (useEffect)\n- Browser APIs\n\n```tsx\n// Server Component (default) - no 'use client'\nasync function ProductPage({ params }) {\n  const product = await getProduct(params.id);  // Server-side fetch\n\n  return (\n    <div>\n      <h1>{product.name}</h1>\n      <AddToCartButton productId={product.id} />  {/* Client component */}\n    </div>\n  );\n}\n\n// Client Component\n'use client';\nfunction AddToCartButton({ productId }) {\n  const [adding, setAdding] = useState(false);\n  return <button onClick={() => addToCart(productId)}>Add</button>;\n}\n```\n\n### Image Optimization\n\n```tsx\nimport Image from 'next/image';\n\n// Above the fold - load immediately\n<Image\n  src=\"/hero.jpg\"\n  alt=\"Hero\"\n  width={1200}\n  height={600}\n  priority\n/>\n\n// Responsive image with fill\n<div className=\"relative aspect-video\">\n  <Image\n    src=\"/product.jpg\"\n    alt=\"Product\"\n    fill\n    sizes=\"(max-width: 768px) 100vw, 50vw\"\n    className=\"object-cover\"\n  />\n</div>\n```\n\n### Data Fetching Patterns\n\n```tsx\n// Parallel fetching\nasync function Dashboard() {\n  const [user, stats] = await Promise.all([\n    getUser(),\n    getStats()\n  ]);\n  return <div>...</div>;\n}\n\n// Streaming with Suspense\nasync function ProductPage({ params }) {\n  return (\n    <div>\n      <ProductDetails id={params.id} />\n      <Suspense fallback={<ReviewsSkeleton />}>\n        <Reviews productId={params.id} />\n      </Suspense>\n    </div>\n  );\n}\n```\n\n---\n\n## Accessibility and Testing\n\nReference: `references/frontend_best_practices.md`\n\n### Accessibility Checklist\n\n1. **Semantic HTML**: Use proper elements (`<button>`, `<nav>`, `<main>`)\n2. **Keyboard Navigation**: All interactive elements focusable\n3. **ARIA Labels**: Provide labels for icons and complex widgets\n4. **Color Contrast**: Minimum 4.5:1 for normal text\n5. **Focus Indicators**: Visible focus states\n\n```tsx\n// Accessible button\n<button\n  type=\"button\"\n  aria-label=\"Close dialog\"\n  onClick={onClose}\n  className=\"focus-visible:ring-2 focus-visible:ring-blue-500\"\n>\n  <XIcon aria-hidden=\"true\" />\n</button>\n\n// Skip link for keyboard users\n<a href=\"#main-content\" className=\"sr-only focus:not-sr-only\">\n  Skip to main content\n</a>\n```\n\n### Testing Strategy\n\n```tsx\n// Component test with React Testing Library\nimport { render, screen } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\n\ntest('button triggers action on click', async () => {\n  const onClick = vi.fn();\n  render(<Button onClick={onClick}>Click me</Button>);\n\n  await userEvent.click(screen.getByRole('button'));\n  expect(onClick).toHaveBeenCalledTimes(1);\n});\n\n// Test accessibility\ntest('dialog is accessible', async () => {\n  render(<Dialog open={true} title=\"Confirm\" />);\n\n  expect(screen.getByRole('dialog')).toBeInTheDocument();\n  expect(screen.getByRole('dialog')).toHaveAttribute('aria-labelledby');\n});\n```\n\n---\n\n## Quick Reference\n\n### Common Next.js Config\n\n```js\n// next.config.js\nconst nextConfig = {\n  images: {\n    remotePatterns: [{ hostname: 'cdn.example.com' }],\n    formats: ['image/avif', 'image/webp'],\n  },\n  experimental: {\n    optimizePackageImports: ['lucide-react', '@heroicons/react'],\n  },\n};\n```\n\n### Tailwind CSS Utilities\n\n```tsx\n// Conditional classes with cn()\nimport { cn } from '@/lib/utils';\n\n<button className={cn(\n  'px-4 py-2 rounded',\n  variant === 'primary' && 'bg-blue-500 text-white',\n  disabled && 'opacity-50 cursor-not-allowed'\n)} />\n```\n\n### TypeScript Patterns\n\n```tsx\n// Props with children\ninterface CardProps {\n  className?: string;\n  children: React.ReactNode;\n}\n\n// Generic component\ninterface ListProps<T> {\n  items: T[];\n  renderItem: (item: T) => React.ReactNode;\n}\n\nfunction List<T>({ items, renderItem }: ListProps<T>) {\n  return <ul>{items.map(renderItem)}</ul>;\n}\n```\n\n---\n\n## Resources\n\n- React Patterns: `references/react_patterns.md`\n- Next.js Optimization: `references/nextjs_optimization_guide.md`\n- Best Practices: `references/frontend_best_practices.md`\n\nFile v1.0.0:_meta.json\n\n{\n  \"ownerId\": \"kn7f2gr00xy51fj1nx2y64ckjs800mhn\",\n  \"slug\": \"senior-frontend\",\n  \"version\": \"1.0.0\",\n  \"publishedAt\": 1770402462862\n}\n\nFile v1.0.0:references/frontend_best_practices.md\n\n# Frontend Best Practices\n\nModern frontend development standards for accessibility, testing, TypeScript, and Tailwind CSS.\n\n---\n\n## Table of Contents\n\n- [Accessibility (a11y)](#accessibility-a11y)\n- [Testing Strategies](#testing-strategies)\n- [TypeScript Patterns](#typescript-patterns)\n- [Tailwind CSS](#tailwind-css)\n- [Project Structure](#project-structure)\n- [Security](#security)\n\n---\n\n## Accessibility (a11y)\n\n### Semantic HTML\n\n```tsx\n// BAD - Divs for everything\n<div onClick={handleClick}>Click me</div>\n<div class=\"header\">...</div>\n<div class=\"nav\">...</div>\n\n// GOOD - Semantic elements\n<button onClick={handleClick}>Click me</button>\n<header>...</header>\n<nav>...</nav>\n<main>...</main>\n<article>...</article>\n<aside>...</aside>\n<footer>...</footer>\n```\n\n### Keyboard Navigation\n\n```tsx\n// Ensure all interactive elements are keyboard accessible\nfunction Modal({ isOpen, onClose, children }: ModalProps) {\n  const modalRef = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    if (isOpen) {\n      // Focus first focusable element\n      const focusable = modalRef.current?.querySelectorAll(\n        'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n      );\n      (focusable?.[0] as HTMLElement)?.focus();\n\n      // Trap focus within modal\n      const handleTab = (e: KeyboardEvent) => {\n        if (e.key === 'Tab' && focusable) {\n          const first = focusable[0] as HTMLElement;\n          const last = focusable[focusable.length - 1] as HTMLElement;\n\n          if (e.shiftKey && document.activeElement === first) {\n            e.preventDefault();\n            last.focus();\n          } else if (!e.shiftKey && document.activeElement === last) {\n            e.preventDefault();\n            first.focus();\n          }\n        }\n\n        if (e.key === 'Escape') {\n          onClose();\n        }\n      };\n\n      document.addEventListener('keydown', handleTab);\n      return () => document.removeEventListener('keydown', handleTab);\n    }\n  }, [isOpen, onClose]);\n\n  if (!isOpen) return null;\n\n  return (\n    <div\n      ref={modalRef}\n      role=\"dialog\"\n      aria-modal=\"true\"\n      aria-labelledby=\"modal-title\"\n    >\n      {children}\n    </div>\n  );\n}\n```\n\n### ARIA Attributes\n\n```tsx\n// Live regions for dynamic content\n<div aria-live=\"polite\" aria-atomic=\"true\">\n  {status && <p>{status}</p>}\n</div>\n\n// Loading states\n<button disabled={isLoading} aria-busy={isLoading}>\n  {isLoading ? 'Loading...' : 'Submit'}\n</button>\n\n// Form labels\n<label htmlFor=\"email\">Email address</label>\n<input\n  id=\"email\"\n  type=\"email\"\n  aria-required=\"true\"\n  aria-invalid={!!errors.email}\n  aria-describedby={errors.email ? 'email-error' : undefined}\n/>\n{errors.email && (\n  <p id=\"email-error\" role=\"alert\">\n    {errors.email}\n  </p>\n)}\n\n// Navigation\n<nav aria-label=\"Main navigation\">\n  <ul>\n    <li><a href=\"/\" aria-current={isHome ? 'page' : undefined}>Home</a></li>\n    <li><a href=\"/about\" aria-current={isAbout ? 'page' : undefined}>About</a></li>\n  </ul>\n</nav>\n\n// Toggle buttons\n<button\n  aria-pressed={isEnabled}\n  onClick={() => setIsEnabled(!isEnabled)}\n>\n  {isEnabled ? 'Enabled' : 'Disabled'}\n</button>\n\n// Expandable sections\n<button\n  aria-expanded={isOpen}\n  aria-controls=\"content-panel\"\n  onClick={() => setIsOpen(!isOpen)}\n>\n  Show details\n</button>\n<div id=\"content-panel\" hidden={!isOpen}>\n  Content here\n</div>\n```\n\n### Color Contrast\n\n```tsx\n// Ensure 4.5:1 contrast ratio for text (WCAG AA)\n// Use tools like @axe-core/react for testing\n\n// tailwind.config.js - Define accessible colors\nmodule.exports = {\n  theme: {\n    colors: {\n      // Primary with proper contrast\n      primary: {\n        DEFAULT: '#2563eb', // Blue 600\n        foreground: '#ffffff',\n      },\n      // Error state\n      error: {\n        DEFAULT: '#dc2626', // Red 600\n        foreground: '#ffffff',\n      },\n      // Text colors with proper contrast\n      foreground: '#0f172a', // Slate 900\n      muted: '#64748b', // Slate 500 - minimum 4.5:1 on white\n    },\n  },\n};\n\n// Never rely on color alone\n<span className=\"text-red-600\">\n  <ErrorIcon aria-hidden=\"true\" />\n  <span>Error: Invalid input</span>\n</span>\n```\n\n### Screen Reader Only Content\n\n```tsx\n// Visually hidden but accessible to screen readers\nconst srOnly = 'absolute w-px h-px p-0 -m-px overflow-hidden whitespace-nowrap border-0';\n\n// Skip link for keyboard users\n<a href=\"#main-content\" className={srOnly + ' focus:not-sr-only focus:absolute focus:top-0'}>\n  Skip to main content\n</a>\n\n// Icon buttons need labels\n<button aria-label=\"Close menu\">\n  <XIcon aria-hidden=\"true\" />\n</button>\n\n// Or use visually hidden text\n<button>\n  <XIcon aria-hidden=\"true\" />\n  <span className={srOnly}>Close menu</span>\n</button>\n```\n\n---\n\n## Testing Strategies\n\n### Component Testing with Testing Library\n\n```tsx\n// Button.test.tsx\nimport { render, screen, fireEvent } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { Button } from './Button';\n\ndescribe('Button', () => {\n  it('renders with correct text', () => {\n    render(<Button>Click me</Button>);\n    expect(screen.getByRole('button', { name: 'Click me' })).toBeInTheDocument();\n  });\n\n  it('calls onClick when clicked', async () => {\n    const user = userEvent.setup();\n    const handleClick = jest.fn();\n\n    render(<Button onClick={handleClick}>Click me</Button>);\n    await user.click(screen.getByRole('button'));\n\n    expect(handleClick).toHaveBeenCalledTimes(1);\n  });\n\n  it('is disabled when loading', () => {\n    render(<Button isLoading>Submit</Button>);\n    expect(screen.getByRole('button')).toBeDisabled();\n    expect(screen.getByRole('button')).toHaveAttribute('aria-busy', 'true');\n  });\n\n  it('shows loading text when loading', () => {\n    render(<Button isLoading loadingText=\"Submitting...\">Submit</Button>);\n    expect(screen.getByText('Submitting...')).toBeInTheDocument();\n  });\n});\n```\n\n### Hook Testing\n\n```tsx\n// useCounter.test.ts\nimport { renderHook, act } from '@testing-library/react';\nimport { useCounter } from './useCounter';\n\ndescribe('useCounter', () => {\n  it('initializes with default value', () => {\n    const { result } = renderHook(() => useCounter());\n    expect(result.current.count).toBe(0);\n  });\n\n  it('initializes with custom value', () => {\n    const { result } = renderHook(() => useCounter(10));\n    expect(result.current.count).toBe(10);\n  });\n\n  it('increments count', () => {\n    const { result } = renderHook(() => useCounter());\n\n    act(() => {\n      result.current.increment();\n    });\n\n    expect(result.current.count).toBe(1);\n  });\n\n  it('resets to initial value', () => {\n    const { result } = renderHook(() => useCounter(5));\n\n    act(() => {\n      result.current.increment();\n      result.current.increment();\n      result.current.reset();\n    });\n\n    expect(result.current.count).toBe(5);\n  });\n});\n```\n\n### Integration Testing\n\n```tsx\n// LoginForm.test.tsx\nimport { render, screen, waitFor } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { LoginForm } from './LoginForm';\nimport { AuthProvider } from '@/contexts/AuthContext';\n\nconst mockLogin = jest.fn();\n\njest.mock('@/lib/auth', () => ({\n  login: (...args: unknown[]) => mockLogin(...args),\n}));\n\ndescribe('LoginForm', () => {\n  beforeEach(() => {\n    mockLogin.mockReset();\n  });\n\n  it('submits form with valid credentials', async () => {\n    const user = userEvent.setup();\n    mockLogin.mockResolvedValueOnce({ user: { id: '1', name: 'Test' } });\n\n    render(\n      <AuthProvider>\n        <LoginForm />\n      </AuthProvider>\n    );\n\n    await user.type(screen.getByLabelText(/email/i), 'test@example.com');\n    await user.type(screen.getByLabelText(/password/i), 'password123');\n    await user.click(screen.getByRole('button', { name: /sign in/i }));\n\n    await waitFor(() => {\n      expect(mockLogin).toHaveBeenCalledWith('test@example.com', 'password123');\n    });\n  });\n\n  it('shows validation errors for empty fields', async () => {\n    const user = userEvent.setup();\n\n    render(\n      <AuthProvider>\n        <LoginForm />\n      </AuthProvider>\n    );\n\n    await user.click(screen.getByRole('button', { name: /sign in/i }));\n\n    expect(await screen.findByText(/email is required/i)).toBeInTheDocument();\n    expect(await screen.findByText(/password is required/i)).toBeInTheDocument();\n    expect(mockLogin).not.toHaveBeenCalled();\n  });\n});\n```\n\n### E2E Testing with Playwright\n\n```typescript\n// e2e/checkout.spec.ts\nimport { test, expect } from '@playwright/test';\n\ntest.describe('Checkout flow', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/');\n    await page.click('[data-testid=\"product-1\"] button');\n    await page.click('[data-testid=\"cart-button\"]');\n  });\n\n  test('completes checkout with valid payment', async ({ page }) => {\n    await page.click('text=Proceed to Checkout');\n\n    // Fill shipping info\n    await page.fill('[name=\"email\"]', 'test@example.com');\n    await page.fill('[name=\"address\"]', '123 Test St');\n    await page.fill('[name=\"city\"]', 'Test City');\n    await page.selectOption('[name=\"state\"]', 'CA');\n    await page.fill('[name=\"zip\"]', '90210');\n\n    await page.click('text=Continue to Payment');\n    await page.click('text=Place Order');\n\n    // Verify success\n    await expect(page).toHaveURL(/\\/order\\/confirmation/);\n    await expect(page.locator('h1')).toHaveText('Order Confirmed!');\n  });\n});\n```\n\n---\n\n## TypeScript Patterns\n\n### Component Props\n\n```tsx\n// Use interface for component props\ninterface ButtonProps {\n  variant?: 'primary' | 'secondary' | 'ghost';\n  size?: 'sm' | 'md' | 'lg';\n  isLoading?: boolean;\n  children: React.ReactNode;\n  onClick?: () => void;\n}\n\n// Extend HTML attributes\ninterface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n  variant?: 'primary' | 'secondary';\n  isLoading?: boolean;\n}\n\nfunction Button({ variant = 'primary', isLoading, children, ...props }: ButtonProps) {\n  return (\n    <button\n      {...props}\n      disabled={props.disabled || isLoading}\n      className={cn(variants[variant], props.className)}\n    >\n      {isLoading ? <Spinner /> : children}\n    </button>\n  );\n}\n\n// Polymorphic components\ntype PolymorphicProps<E extends React.ElementType> = {\n  as?: E;\n} & React.ComponentPropsWithoutRef<E>;\n\nfunction Box<E extends React.ElementType = 'div'>({\n  as,\n  children,\n  ...props\n}: PolymorphicProps<E>) {\n  const Component = as || 'div';\n  return <Component {...props}>{children}</Component>;\n}\n\n// Usage\n<Box as=\"section\" id=\"hero\">Content</Box>\n<Box as=\"article\">Article content</Box>\n```\n\n### Discriminated Unions\n\n```tsx\n// State machines with exhaustive type checking\ntype AsyncState<T> =\n  | { status: 'idle' }\n  | { status: 'loading' }\n  | { status: 'success'; data: T }\n  | { status: 'error'; error: Error };\n\nfunction DataDisplay<T>({ state, render }: {\n  state: AsyncState<T>;\n  render: (data: T) => React.ReactNode;\n}) {\n  switch (state.status) {\n    case 'idle':\n      return null;\n    case 'loading':\n      return <Spinner />;\n    case 'success':\n      return <>{render(state.data)}</>;\n    case 'error':\n      return <ErrorMessage error={state.error} />;\n    // TypeScript ensures all cases are handled\n  }\n}\n```\n\n### Generic Components\n\n```tsx\n// Generic list component\ninterface ListProps<T> {\n  items: T[];\n  renderItem: (item: T, index: number) => React.ReactNode;\n  keyExtractor: (item: T) => string;\n  emptyMessage?: string;\n}\n\nfunction List<T>({ items, renderItem, keyExtractor, emptyMessage }: ListProps<T>) {\n  if (items.length === 0) {\n    return <p className=\"text-muted\">{emptyMessage || 'No items'}</p>;\n  }\n\n  return (\n    <ul>\n      {items.map((item, index) => (\n        <li key={keyExtractor(item)}>{renderItem(item, index)}</li>\n      ))}\n    </ul>\n  );\n}\n\n// Usage\n<List\n  items={users}\n  keyExtractor={(user) => user.id}\n  renderItem={(user) => <UserCard user={user} />}\n/>\n```\n\n### Type Guards\n\n```tsx\n// User-defined type guards\ninterface User {\n  id: string;\n  name: string;\n  email: string;\n}\n\ninterface Admin extends User {\n  role: 'admin';\n  permissions: string[];\n}\n\nfunction isAdmin(user: User): user is Admin {\n  return 'role' in user && user.role === 'admin';\n}\n\nfunction UserBadge({ user }: { user: User }) {\n  if (isAdmin(user)) {\n    // TypeScript knows user is Admin here\n    return <Badge variant=\"admin\">Admin ({user.permissions.length} perms)</Badge>;\n  }\n\n  return <Badge>User</Badge>;\n}\n\n// API response type guards\ninterface ApiSuccess<T> {\n  success: true;\n  data: T;\n}\n\ninterface ApiError {\n  success: false;\n  error: string;\n}\n\ntype ApiResponse<T> = ApiSuccess<T> | ApiError;\n\nfunction isApiSuccess<T>(response: ApiResponse<T>): response is ApiSuccess<T> {\n  return response.success === true;\n}\n```\n\n---\n\n## Tailwind CSS\n\n### Component Variants with CVA\n\n```tsx\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '@/lib/utils';\n\nconst buttonVariants = cva(\n  // Base styles\n  'inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',\n  {\n    variants: {\n      variant: {\n        primary: 'bg-blue-600 text-white hover:bg-blue-700 focus-visible:ring-blue-500',\n        secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200 focus-visible:ring-gray-500',\n        ghost: 'hover:bg-gray-100 hover:text-gray-900',\n        destructive: 'bg-red-600 text-white hover:bg-red-700 focus-visible:ring-red-500',\n      },\n      size: {\n        sm: 'h-8 px-3 text-sm',\n        md: 'h-10 px-4 text-sm',\n        lg: 'h-12 px-6 text-base',\n        icon: 'h-10 w-10',\n      },\n    },\n    defaultVariants: {\n      variant: 'primary',\n      size: 'md',\n    },\n  }\n);\n\ninterface ButtonProps\n  extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n    VariantProps<typeof buttonVariants> {}\n\nfunction Button({ className, variant, size, ...props }: ButtonProps) {\n  return (\n    <button\n      className={cn(buttonVariants({ variant, size }), className)}\n      {...props}\n    />\n  );\n}\n\n// Usage\n<Button variant=\"primary\" size=\"lg\">Large Primary</Button>\n<Button variant=\"ghost\" size=\"icon\"><MenuIcon /></Button>\n```\n\n### Responsive Design\n\n```tsx\n// Mobile-first responsive design\n<div className=\"\n  grid\n  grid-cols-1          {/* Mobile: 1 column */}\n  sm:grid-cols-2       {/* 640px+: 2 columns */}\n  lg:grid-cols-3       {/* 1024px+: 3 columns */}\n  xl:grid-cols-4       {/* 1280px+: 4 columns */}\n  gap-4\n  sm:gap-6\n  lg:gap-8\n\">\n  {products.map(product => <ProductCard key={product.id} product={product} />)}\n</div>\n\n// Container with responsive padding\n<div className=\"container mx-auto px-4 sm:px-6 lg:px-8\">\n  Content\n</div>\n\n// Hide/show based on breakpoint\n<nav className=\"hidden md:flex\">Desktop nav</nav>\n<button className=\"md:hidden\">Mobile menu</button>\n```\n\n### Animation Utilities\n\n```tsx\n// Skeleton loading\n<div className=\"animate-pulse space-y-4\">\n  <div className=\"h-4 bg-gray-200 rounded w-3/4\" />\n  <div className=\"h-4 bg-gray-200 rounded w-1/2\" />\n</div>\n\n// Transitions\n<button className=\"\n  transition-all\n  duration-200\n  ease-in-out\n  hover:scale-105\n  active:scale-95\n\">\n  Hover me\n</button>\n\n// Custom animations in tailwind.config.js\nmodule.exports = {\n  theme: {\n    extend: {\n      animation: {\n        'fade-in': 'fadeIn 0.3s ease-out',\n        'slide-up': 'slideUp 0.3s ease-out',\n        'spin-slow': 'spin 3s linear infinite',\n      },\n      keyframes: {\n        fadeIn: {\n          '0%': { opacity: '0' },\n          '100%': { opacity: '1' },\n        },\n        slideUp: {\n          '0%': { transform: 'translateY(10px)', opacity: '0' },\n          '100%': { transform: 'translateY(0)', opacity: '1' },\n        },\n      },\n    },\n  },\n};\n\n// Usage\n<div className=\"animate-fade-in\">Fading in</div>\n```\n\n---\n\n## Project Structure\n\n### Feature-Based Structure\n\n```\nsrc/\n├── app/                    # Next.js App Router\n│   ├── (auth)/             # Auth route group\n│   │   ├── login/\n│   │   └── register/\n│   ├── dashboard/\n│   │   ├── page.tsx\n│   │   └── layout.tsx\n│   └── layout.tsx\n├── components/\n│   ├── ui/                 # Shared UI components\n│   │   ├── Button.tsx\n│   │   ├── Input.tsx\n│   │   └── index.ts\n│   └── features/           # Feature-specific components\n│       ├── auth/\n│       │   ├── LoginForm.tsx\n│       │   └── RegisterForm.tsx\n│       └── dashboard/\n│           ├── StatsCard.tsx\n│           └── RecentActivity.tsx\n├── hooks/                  # Custom React hooks\n│   ├── useAuth.ts\n│   ├── useDebounce.ts\n│   └── useLocalStorage.ts\n├── lib/                    # Utilities and configs\n│   ├── utils.ts\n│   ├── api.ts\n│   └── constants.ts\n├── types/                  # TypeScript types\n│   ├── user.ts\n│   └── api.ts\n└── styles/\n    └── globals.css\n```\n\n### Barrel Exports\n\n```tsx\n// components/ui/index.ts\nexport { Button } from './Button';\nexport { Input } from './Input';\nexport { Card, CardHeader, CardContent, CardFooter } from './Card';\nexport { Dialog, DialogTrigger, DialogContent } from './Dialog';\n\n// Usage\nimport { Button, Input, Card } from '@/components/ui';\n```\n\n---\n\n## Security\n\n### XSS Prevention\n\nReact escapes content by default, which prevents most XSS attacks. When you need to render HTML content:\n\n1. **Avoid rendering raw HTML** when possible\n2. **Sanitize with DOMPurify** for trusted content sources\n3. **Use allow-lists** for permitted tags and attributes\n\n```tsx\n// React escapes by default - this is safe\n<div>{userInput}</div>\n\n// When you must render HTML, sanitize first\nimport DOMPurify from 'dompurify';\n\nfunction SafeHTML({ html }: { html: string }) {\n  const sanitized = DOMPurify.sanitize(html, {\n    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p'],\n    ALLOWED_ATTR: ['href'],\n  });\n\n  return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;\n}\n```\n\n### Input Validation\n\n```tsx\nimport { z } from 'zod';\nimport { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\n\nconst schema = z.object({\n  email: z.string().email('Invalid email address'),\n  password: z.string()\n    .min(8, 'Password must be at least 8 characters')\n    .regex(/[A-Z]/, 'Password must contain uppercase letter')\n    .regex(/[0-9]/, 'Password must contain number'),\n  confirmPassword: z.string(),\n}).refine((data) => data.password === data.confirmPassword, {\n  message: 'Passwords do not match',\n  path: ['confirmPassword'],\n});\n\ntype FormData = z.infer<typeof schema>;\n\nfunction RegisterForm() {\n  const { register, handleSubmit, formState: { errors } } = useForm<FormData>({\n    resolver: zodResolver(schema),\n  });\n\n  return (\n    <form onSubmit={handleSubmit(onSubmit)}>\n      <Input {...register('email')} error={errors.email?.message} />\n      <Input type=\"password\" {...register('password')} error={errors.password?.message} />\n      <Input type=\"password\" {...register('confirmPassword')} error={errors.confirmPassword?.message} />\n      <Button type=\"submit\">Register</Button>\n    </form>\n  );\n}\n```\n\n### Secure API Calls\n\n```tsx\n// Use environment variables for API endpoints\nconst API_URL = process.env.NEXT_PUBLIC_API_URL;\n\n// Never include secrets in client code - use server-side API routes\n// app/api/data/route.ts\nexport async function GET() {\n  const response = await fetch('https://api.example.com/data', {\n    headers: {\n      'Authorization': `Bearer ${process.env.API_SECRET}`, // Server-side only\n    },\n  });\n\n  return Response.json(await response.json());\n}\n```\n\nFile v1.0.0:references/nextjs_optimization_guide.md\n\n# Next.js Optimization Guide\n\nPerformance optimization techniques for Next.js 14+ applications.\n\n---\n\n## Table of Contents\n\n- [Rendering Strategies](#rendering-strategies)\n- [Image Optimization](#image-optimization)\n- [Code Splitting](#code-splitting)\n- [Data Fetching](#data-fetching)\n- [Caching Strategies](#caching-strategies)\n- [Bundle Optimization](#bundle-optimization)\n- [Core Web Vitals](#core-web-vitals)\n\n---\n\n## Rendering Strategies\n\n### Server Components (Default)\n\nServer Components render on the server and send HTML to the client. Use for data-heavy, non-interactive content.\n\n```tsx\n// app/products/page.tsx - Server Component (default)\nasync function ProductsPage() {\n  // This runs on the server - no client bundle impact\n  const products = await db.products.findMany();\n\n  return (\n    <div className=\"grid grid-cols-3 gap-4\">\n      {products.map(product => (\n        <ProductCard key={product.id} product={product} />\n      ))}\n    </div>\n  );\n}\n```\n\n### Client Components\n\nUse `'use client'` only when you need:\n- Event handlers (onClick, onChange)\n- State (useState, useReducer)\n- Effects (useEffect)\n- Browser APIs (window, document)\n\n```tsx\n'use client';\n\nimport { useState } from 'react';\n\nfunction AddToCartButton({ productId }: { productId: string }) {\n  const [isAdding, setIsAdding] = useState(false);\n\n  async function handleClick() {\n    setIsAdding(true);\n    await addToCart(productId);\n    setIsAdding(false);\n  }\n\n  return (\n    <button onClick={handleClick} disabled={isAdding}>\n      {isAdding ? 'Adding...' : 'Add to Cart'}\n    </button>\n  );\n}\n```\n\n### Mixing Server and Client Components\n\n```tsx\n// app/products/[id]/page.tsx - Server Component\nasync function ProductPage({ params }: { params: { id: string } }) {\n  const product = await getProduct(params.id);\n\n  return (\n    <div>\n      {/* Server-rendered content */}\n      <h1>{product.name}</h1>\n      <p>{product.description}</p>\n\n      {/* Client component for interactivity */}\n      <AddToCartButton productId={product.id} />\n\n      {/* Server component for reviews */}\n      <ProductReviews productId={product.id} />\n    </div>\n  );\n}\n```\n\n### Static vs Dynamic Rendering\n\n```tsx\n// Force static generation at build time\nexport const dynamic = 'force-static';\n\n// Force dynamic rendering at request time\nexport const dynamic = 'force-dynamic';\n\n// Revalidate every 60 seconds (ISR)\nexport const revalidate = 60;\n\n// Revalidate on-demand\nimport { revalidatePath, revalidateTag } from 'next/cache';\n\nasync function updateProduct(id: string, data: ProductData) {\n  await db.products.update({ where: { id }, data });\n\n  // Revalidate specific path\n  revalidatePath(`/products/${id}`);\n\n  // Or revalidate by tag\n  revalidateTag('products');\n}\n```\n\n---\n\n## Image Optimization\n\n### Next.js Image Component\n\n```tsx\nimport Image from 'next/image';\n\n// Basic optimized image\n<Image\n  src=\"/hero.jpg\"\n  alt=\"Hero image\"\n  width={1200}\n  height={600}\n  priority // Load immediately for LCP\n/>\n\n// Responsive image\n<Image\n  src=\"/product.jpg\"\n  alt=\"Product\"\n  fill\n  sizes=\"(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw\"\n  className=\"object-cover\"\n/>\n\n// With placeholder blur\nimport productImage from '@/public/product.jpg';\n\n<Image\n  src={productImage}\n  alt=\"Product\"\n  placeholder=\"blur\" // Uses imported image data\n/>\n```\n\n### Remote Images Configuration\n\n```js\n// next.config.js\nmodule.exports = {\n  images: {\n    remotePatterns: [\n      {\n        protocol: 'https',\n        hostname: 'cdn.example.com',\n        pathname: '/images/**',\n      },\n      {\n        protocol: 'https',\n        hostname: '*.cloudinary.com',\n      },\n    ],\n    // Image formats (webp is default)\n    formats: ['image/avif', 'image/webp'],\n    // Device sizes for srcset\n    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],\n    // Image sizes for srcset\n    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],\n  },\n};\n```\n\n### Lazy Loading Patterns\n\n```tsx\n// Images below the fold - lazy load (default)\n<Image\n  src=\"/gallery/photo1.jpg\"\n  alt=\"Gallery photo\"\n  width={400}\n  height={300}\n  loading=\"lazy\" // Default behavior\n/>\n\n// Above the fold - load immediately\n<Image\n  src=\"/hero.jpg\"\n  alt=\"Hero\"\n  width={1200}\n  height={600}\n  priority\n  loading=\"eager\"\n/>\n```\n\n---\n\n## Code Splitting\n\n### Dynamic Imports\n\n```tsx\nimport dynamic from 'next/dynamic';\n\n// Basic dynamic import\nconst HeavyChart = dynamic(() => import('@/components/HeavyChart'), {\n  loading: () => <ChartSkeleton />,\n});\n\n// Disable SSR for client-only components\nconst MapComponent = dynamic(() => import('@/components/Map'), {\n  ssr: false,\n  loading: () => <div className=\"h-[400px] bg-gray-100\" />,\n});\n\n// Named exports\nconst Modal = dynamic(() =>\n  import('@/components/ui').then(mod => mod.Modal)\n);\n\n// With suspense\nconst DashboardCharts = dynamic(() => import('@/components/DashboardCharts'), {\n  loading: () => <Suspense fallback={<ChartsSkeleton />} />,\n});\n```\n\n### Route-Based Splitting\n\n```tsx\n// app/dashboard/analytics/page.tsx\n// This page only loads when /dashboard/analytics is visited\nimport { Suspense } from 'react';\nimport AnalyticsCharts from './AnalyticsCharts';\n\nexport default function AnalyticsPage() {\n  return (\n    <Suspense fallback={<AnalyticsSkeleton />}>\n      <AnalyticsCharts />\n    </Suspense>\n  );\n}\n```\n\n### Parallel Routes for Code Splitting\n\n```\napp/\n├── dashboard/\n│   ├── @analytics/\n│   │   └── page.tsx    # Loaded in parallel\n│   ├── @metrics/\n│   │   └── page.tsx    # Loaded in parallel\n│   ├── layout.tsx\n│   └── page.tsx\n```\n\n```tsx\n// app/dashboard/layout.tsx\nexport default function DashboardLayout({\n  children,\n  analytics,\n  metrics,\n}: {\n  children: React.ReactNode;\n  analytics: React.ReactNode;\n  metrics: React.ReactNode;\n}) {\n  return (\n    <div className=\"grid grid-cols-2 gap-4\">\n      {children}\n      <Suspense fallback={<AnalyticsSkeleton />}>{analytics}</Suspense>\n      <Suspense fallback={<MetricsSkeleton />}>{metrics}</Suspense>\n    </div>\n  );\n}\n```\n\n---\n\n## Data Fetching\n\n### Server-Side Data Fetching\n\n```tsx\n// Parallel data fetching\nasync function Dashboard() {\n  // Start both requests simultaneously\n  const [user, stats, notifications] = await Promise.all([\n    getUser(),\n    getStats(),\n    getNotifications(),\n  ]);\n\n  return (\n    <div>\n      <UserHeader user={user} />\n      <StatsPanel stats={stats} />\n      <NotificationList notifications={notifications} />\n    </div>\n  );\n}\n```\n\n### Streaming with Suspense\n\n```tsx\nimport { Suspense } from 'react';\n\nasync function ProductPage({ params }: { params: { id: string } }) {\n  const product = await getProduct(params.id);\n\n  return (\n    <div>\n      {/* Immediate content */}\n      <h1>{product.name}</h1>\n      <p>{product.description}</p>\n\n      {/* Stream reviews - don't block page */}\n      <Suspense fallback={<ReviewsSkeleton />}>\n        <Reviews productId={params.id} />\n      </Suspense>\n\n      {/* Stream recommendations */}\n      <Suspense fallback={<RecommendationsSkeleton />}>\n        <Recommendations productId={params.id} />\n      </Suspense>\n    </div>\n  );\n}\n\n// Slow data component\nasync function Reviews({ productId }: { productId: string }) {\n  const reviews = await getReviews(productId); // Slow query\n  return <ReviewList reviews={reviews} />;\n}\n```\n\n### Request Memoization\n\n```tsx\n// Next.js automatically dedupes identical requests\nasync function Layout({ children }) {\n  const user = await getUser(); // Request 1\n  return <div>{children}</div>;\n}\n\nasync function Header() {\n  const user = await getUser(); // Same request - cached!\n  return <div>Hello, {user.name}</div>;\n}\n\n// Both components call getUser() but only one request is made\n```\n\n---\n\n## Caching Strategies\n\n### Fetch Cache Options\n\n```tsx\n// Cache indefinitely (default for static)\nfetch('https://api.example.com/data');\n\n// No cache - always fresh\nfetch('https://api.example.com/data', { cache: 'no-store' });\n\n// Revalidate after time\nfetch('https://api.example.com/data', {\n  next: { revalidate: 3600 } // 1 hour\n});\n\n// Tag-based revalidation\nfetch('https://api.example.com/products', {\n  next: { tags: ['products'] }\n});\n\n// Later, revalidate by tag\nimport { revalidateTag } from 'next/cache';\nrevalidateTag('products');\n```\n\n### Route Segment Config\n\n```tsx\n// app/products/page.tsx\n\n// Revalidate every hour\nexport const revalidate = 3600;\n\n// Or force dynamic\nexport const dynamic = 'force-dynamic';\n\n// Generate static params at build\nexport async function generateStaticParams() {\n  const products = await getProducts();\n  return products.map(p => ({ id: p.id }));\n}\n```\n\n### unstable_cache for Custom Caching\n\n```tsx\nimport { unstable_cache } from 'next/cache';\n\nconst getCachedUser = unstable_cache(\n  async (userId: string) => {\n    const user = await db.users.findUnique({ where: { id: userId } });\n    return user;\n  },\n  ['user-cache'],\n  {\n    revalidate: 3600, // 1 hour\n    tags: ['users'],\n  }\n);\n\n// Usage\nconst user = await getCachedUser(userId);\n```\n\n---\n\n## Bundle Optimization\n\n### Analyze Bundle Size\n\n```bash\n# Install analyzer\nnpm install @next/bundle-analyzer\n\n# Update next.config.js\nconst withBundleAnalyzer = require('@next/bundle-analyzer')({\n  enabled: process.env.ANALYZE === 'true',\n});\n\nmodule.exports = withBundleAnalyzer({\n  // config\n});\n\n# Run analysis\nANALYZE=true npm run build\n```\n\n### Tree Shaking Imports\n\n```tsx\n// BAD - Imports entire library\nimport _ from 'lodash';\nconst result = _.debounce(fn, 300);\n\n// GOOD - Import only what you need\nimport debounce from 'lodash/debounce';\nconst result = debounce(fn, 300);\n\n// GOOD - Named imports (tree-shakeable)\nimport { debounce } from 'lodash-es';\n```\n\n### Optimize Dependencies\n\n```js\n// next.config.js\nmodule.exports = {\n  // Transpile specific packages\n  transpilePackages: ['ui-library', 'shared-utils'],\n\n  // Optimize package imports\n  experimental: {\n    optimizePackageImports: ['lucide-react', '@heroicons/react'],\n  },\n\n  // External packages for server\n  serverExternalPackages: ['sharp', 'bcrypt'],\n};\n```\n\n### Font Optimization\n\n```tsx\n// app/layout.tsx\nimport { Inter, Roboto_Mono } from 'next/font/google';\n\nconst inter = Inter({\n  subsets: ['latin'],\n  display: 'swap',\n  variable: '--font-inter',\n});\n\nconst robotoMono = Roboto_Mono({\n  subsets: ['latin'],\n  display: 'swap',\n  variable: '--font-roboto-mono',\n});\n\nexport default function RootLayout({ children }) {\n  return (\n    <html lang=\"en\" className={`${inter.variable} ${robotoMono.variable}`}>\n      <body className=\"font-sans\">{children}</body>\n    </html>\n  );\n}\n```\n\n---\n\n## Core Web Vitals\n\n### Largest Contentful Paint (LCP)\n\n```tsx\n// Optimize LCP hero image\nimport Image from 'next/image';\n\nexport default function Hero() {\n  return (\n    <section className=\"relative h-[600px]\">\n      <Image\n        src=\"/hero.jpg\"\n        alt=\"Hero\"\n        fill\n        priority // Preload for LCP\n        sizes=\"100vw\"\n        className=\"object-cover\"\n      />\n      <div className=\"relative z-10\">\n        <h1>Welcome</h1>\n      </div>\n    </section>\n  );\n}\n\n// Preload critical resources in layout\nexport default function RootLayout({ children }) {\n  return (\n    <html>\n      <head>\n        <link rel=\"preload\" href=\"/hero.jpg\" as=\"image\" />\n        <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n      </head>\n      <body>{children}</body>\n    </html>\n  );\n}\n```\n\n### Cumulative Layout Shift (CLS)\n\n```tsx\n// Prevent CLS with explicit dimensions\n<Image\n  src=\"/product.jpg\"\n  alt=\"Product\"\n  width={400}\n  height={300}\n/>\n\n// Or use aspect ratio\n<div className=\"aspect-video relative\">\n  <Image src=\"/video-thumb.jpg\" alt=\"Video\" fill />\n</div>\n\n// Skeleton placeholders\nfunction ProductCard({ product }: { product?: Product }) {\n  if (!product) {\n    return (\n      <div className=\"animate-pulse\">\n        <div className=\"h-48 bg-gray-200 rounded\" />\n        <div className=\"h-4 bg-gray-200 rounded mt-2 w-3/4\" />\n        <div className=\"h-4 bg-gray-200 rounded mt-1 w-1/2\" />\n      </div>\n    );\n  }\n\n  return (\n    <div>\n      <Image src={product.image} alt={product.name} width={300} height={200} />\n      <h3>{product.name}</h3>\n      <p>{product.price}</p>\n    </div>\n  );\n}\n```\n\n### First Input Delay (FID) / Interaction to Next Paint (INP)\n\n```tsx\n// Defer non-critical JavaScript\nimport Script from 'next/script';\n\nexport default function Layout({ children }) {\n  return (\n    <html>\n      <body>\n        {children}\n\n        {/* Load analytics after page is interactive */}\n        <Script\n          src=\"https://analytics.example.com/script.js\"\n          strategy=\"afterInteractive\"\n        />\n\n        {/* Load chat widget when idle */}\n        <Script\n          src=\"https://chat.example.com/widget.js\"\n          strategy=\"lazyOnload\"\n        />\n      </body>\n    </html>\n  );\n}\n\n// Use web workers for heavy computation\n// app/components/DataProcessor.tsx\n'use client';\n\nimport { useEffect, useState } from 'react';\n\nfunction DataProcessor({ data }: { data: number[] }) {\n  const [result, setResult] = useState<number | null>(null);\n\n  useEffect(() => {\n    const worker = new Worker(new URL('../workers/processor.js', import.meta.url));\n\n    worker.postMessage(data);\n    worker.onmessage = (e) => setResult(e.data);\n\n    return () => worker.terminate();\n  }, [data]);\n\n  return <div>Result: {result}</div>;\n}\n```\n\n### Measuring Performance\n\n```tsx\n// app/components/PerformanceMonitor.tsx\n'use client';\n\nimport { useReportWebVitals } from 'next/web-vitals';\n\nexport function PerformanceMonitor() {\n  useReportWebVitals((metric) => {\n    switch (metric.name) {\n      case 'LCP':\n        console.log('LCP:', metric.value);\n        break;\n      case 'FID':\n        console.log('FID:', metric.value);\n        break;\n      case 'CLS':\n        console.log('CLS:', metric.value);\n        break;\n      case 'TTFB':\n        console.log('TTFB:', metric.value);\n        break;\n    }\n\n    // Send to analytics\n    analytics.track('web-vital', {\n      name: metric.name,\n      value: metric.value,\n      id: metric.id,\n    });\n  });\n\n  return null;\n}\n```\n\n---\n\n## Quick Reference\n\n### Performance Checklist\n\n| Area | Optimization | Impact |\n|------|-------------|--------|\n| Images | Use next/image with priority for LCP | High |\n| Fonts | Use next/font with display: swap | Medium |\n| Code | Dynamic imports for heavy components | High |\n| Data | Parallel fetching with Promise.all | High |\n| Render | Server Components by default | High |\n| Cache | Configure revalidate appropriately | Medium |\n| Bundle | Tree-shake imports, analyze size | Medium |\n\n### Config Template\n\n```js\n// next.config.js\n/** @type {import('next').NextConfig} */\nconst nextConfig = {\n  images: {\n    remotePatterns: [{ hostname: 'cdn.example.com' }],\n    formats: ['image/avif', 'image/webp'],\n  },\n  experimental: {\n    optimizePackageImports: ['lucide-react'],\n  },\n  headers: async () => [\n    {\n      source: '/(.*)',\n      headers: [\n        { key: 'X-Content-Type-Options', value: 'nosniff' },\n        { key: 'X-Frame-Options', value: 'DENY' },\n      ],\n    },\n  ],\n};\n\nmodule.exports = nextConfig;\n```\n\nFile v1.0.0:references/react_patterns.md\n\n# React Patterns\n\nProduction-ready patterns for building scalable React applications with TypeScript.\n\n---\n\n## Table of Contents\n\n- [Component Composition](#component-composition)\n- [Custom Hooks](#custom-hooks)\n- [State Management](#state-management)\n- [Performance Patterns](#performance-patterns)\n- [Error Boundaries](#error-boundaries)\n- [Anti-Patterns](#anti-patterns)\n\n---\n\n## Component Composition\n\n### Compound Components\n\nUse compound components when building reusable UI components with multiple related parts.\n\n```tsx\n// Compound component pattern for a Select\ninterface SelectContextType {\n  value: string;\n  onChange: (value: string) => void;\n}\n\nconst SelectContext = createContext<SelectContextType | null>(null);\n\nfunction Select({ children, value, onChange }: {\n  children: React.ReactNode;\n  value: string;\n  onChange: (value: string) => void;\n}) {\n  return (\n    <SelectContext.Provider value={{ value, onChange }}>\n      <div className=\"relative\">{children}</div>\n    </SelectContext.Provider>\n  );\n}\n\nfunction SelectTrigger({ children }: { children: React.ReactNode }) {\n  const context = useContext(SelectContext);\n  if (!context) throw new Error('SelectTrigger must be used within Select');\n\n  return (\n    <button className=\"flex items-center gap-2 px-4 py-2 border rounded\">\n      {children}\n    </button>\n  );\n}\n\nfunction SelectOption({ value, children }: { value: string; children: React.ReactNode }) {\n  const context = useContext(SelectContext);\n  if (!context) throw new Error('SelectOption must be used within Select');\n\n  return (\n    <div\n      onClick={() => context.onChange(value)}\n      className={`px-4 py-2 cursor-pointer hover:bg-gray-100 ${\n        context.value === value ? 'bg-blue-50' : ''\n      }`}\n    >\n      {children}\n    </div>\n  );\n}\n\n// Attach sub-components\nSelect.Trigger = SelectTrigger;\nSelect.Option = SelectOption;\n\n// Usage\n<Select value={selected} onChange={setSelected}>\n  <Select.Trigger>Choose option</Select.Trigger>\n  <Select.Option value=\"a\">Option A</Select.Option>\n  <Select.Option value=\"b\">Option B</Select.Option>\n</Select>\n```\n\n### Render Props\n\nUse render props when you need to share behavior with flexible rendering.\n\n```tsx\ninterface MousePosition {\n  x: number;\n  y: number;\n}\n\nfunction MouseTracker({ render }: { render: (pos: MousePosition) => React.ReactNode }) {\n  const [position, setPosition] = useState<MousePosition>({ x: 0, y: 0 });\n\n  useEffect(() => {\n    const handleMouseMove = (e: MouseEvent) => {\n      setPosition({ x: e.clientX, y: e.clientY });\n    };\n    window.addEventListener('mousemove', handleMouseMove);\n    return () => window.removeEventListener('mousemove', handleMouseMove);\n  }, []);\n\n  return <>{render(position)}</>;\n}\n\n// Usage\n<MouseTracker\n  render={({ x, y }) => (\n    <div>Mouse position: {x}, {y}</div>\n  )}\n/>\n```\n\n### Higher-Order Components (HOC)\n\nUse HOCs for cross-cutting concerns like authentication or logging.\n\n```tsx\nfunction withAuth<P extends object>(WrappedComponent: React.ComponentType<P>) {\n  return function AuthenticatedComponent(props: P) {\n    const { user, isLoading } = useAuth();\n\n    if (isLoading) return <LoadingSpinner />;\n    if (!user) return <Navigate to=\"/login\" />;\n\n    return <WrappedComponent {...props} />;\n  };\n}\n\n// Usage\nconst ProtectedDashboard = withAuth(Dashboard);\n```\n\n---\n\n## Custom Hooks\n\n### useAsync - Handle async operations\n\n```tsx\ninterface AsyncState<T> {\n  data: T | null;\n  error: Error | null;\n  status: 'idle' | 'loading' | 'success' | 'error';\n}\n\nfunction useAsync<T>(asyncFn: () => Promise<T>, deps: any[] = []) {\n  const [state, setState] = useState<AsyncState<T>>({\n    data: null,\n    error: null,\n    status: 'idle',\n  });\n\n  const execute = useCallback(async () => {\n    setState({ data: null, error: null, status: 'loading' });\n    try {\n      const data = await asyncFn();\n      setState({ data, error: null, status: 'success' });\n    } catch (error) {\n      setState({ data: null, error: error as Error, status: 'error' });\n    }\n  }, deps);\n\n  useEffect(() => {\n    execute();\n  }, [execute]);\n\n  return { ...state, refetch: execute };\n}\n\n// Usage\nfunction UserProfile({ userId }: { userId: string }) {\n  const { data: user, status, error, refetch } = useAsync(\n    () => fetchUser(userId),\n    [userId]\n  );\n\n  if (status === 'loading') return <Spinner />;\n  if (status === 'error') return <Error message={error?.message} />;\n  if (!user) return null;\n\n  return <Profile user={user} />;\n}\n```\n\n### useDebounce - Debounce values\n\n```tsx\nfunction useDebounce<T>(value: T, delay: number): T {\n  const [debouncedValue, setDebouncedValue] = useState(value);\n\n  useEffect(() => {\n    const timer = setTimeout(() => setDebouncedValue(value), delay);\n    return () => clearTimeout(timer);\n  }, [value, delay]);\n\n  return debouncedValue;\n}\n\n// Usage\nfunction SearchInput() {\n  const [query, setQuery] = useState('');\n  const debouncedQuery = useDebounce(query, 300);\n\n  useEffect(() => {\n    if (debouncedQuery) {\n      searchAPI(debouncedQuery);\n    }\n  }, [debouncedQuery]);\n\n  return <input value={query} onChange={(e) => setQuery(e.target.value)} />;\n}\n```\n\n### useLocalStorage - Persist state\n\n```tsx\nfunction useLocalStorage<T>(key: string, initialValue: T) {\n  const [storedValue, setStoredValue] = useState<T>(() => {\n    if (typeof window === 'undefined') return initialValue;\n    try {\n      const item = window.localStorage.getItem(key);\n      return item ? JSON.parse(item) : initialValue;\n    } catch {\n      return initialValue;\n    }\n  });\n\n  const setValue = useCallback((value: T | ((val: T) => T)) => {\n    try {\n      const valueToStore = value instanceof Function ? value(storedValue) : value;\n      setStoredValue(valueToStore);\n      if (typeof window !== 'undefined') {\n        window.localStorage.setItem(key, JSON.stringify(valueToStore));\n      }\n    } catch (error) {\n      console.error('Error saving to localStorage:', error);\n    }\n  }, [key, storedValue]);\n\n  return [storedValue, setValue] as const;\n}\n\n// Usage\nconst [theme, setTheme] = useLocalStorage('theme', 'light');\n```\n\n### useMediaQuery - Responsive design\n\n```tsx\nfunction useMediaQuery(query: string): boolean {\n  const [matches, setMatches] = useState(false);\n\n  useEffect(() => {\n    const media = window.matchMedia(query);\n    setMatches(media.matches);\n\n    const listener = (e: MediaQueryListEvent) => setMatches(e.matches);\n    media.addEventListener('change', listener);\n    return () => media.removeEventListener('change', listener);\n  }, [query]);\n\n  return matches;\n}\n\n// Usage\nfunction ResponsiveNav() {\n  const isMobile = useMediaQuery('(max-width: 768px)');\n  return isMobile ? <MobileNav /> : <DesktopNav />;\n}\n```\n\n### usePrevious - Track previous values\n\n```tsx\nfunction usePrevious<T>(value: T): T | undefined {\n  const ref = useRef<T>();\n\n  useEffect(() => {\n    ref.current = value;\n  }, [value]);\n\n  return ref.current;\n}\n\n// Usage\nfunction Counter() {\n  const [count, setCount] = useState(0);\n  const prevCount = usePrevious(count);\n\n  return (\n    <div>\n      Current: {count}, Previous: {prevCount}\n    </div>\n  );\n}\n```\n\n---\n\n## State Management\n\n### Context with Reducer\n\nFor complex state that multiple components need to access.\n\n```tsx\n// types.ts\ninterface CartItem {\n  id: string;\n  name: string;\n  price: number;\n  quantity: number;\n}\n\ninterface CartState {\n  items: CartItem[];\n  total: number;\n}\n\ntype CartAction =\n  | { type: 'ADD_ITEM'; payload: CartItem }\n  | { type: 'REMOVE_ITEM'; payload: string }\n  | { type: 'UPDATE_QUANTITY'; payload: { id: string; quantity: number } }\n  | { type: 'CLEAR_CART' };\n\n// reducer.ts\nfunction cartReducer(state: CartState, action: CartAction): CartState {\n  switch (action.type) {\n    case 'ADD_ITEM': {\n      const existingItem = state.items.find(i => i.id === action.payload.id);\n      if (existingItem) {\n        return {\n          ...state,\n          items: state.items.map(item =>\n            item.id === action.payload.id\n              ? { ...item, quantity: item.quantity + 1 }\n              : item\n          ),\n        };\n      }\n      return {\n        ...state,\n        items: [...state.items, { ...action.payload, quantity: 1 }],\n      };\n    }\n    case 'REMOVE_ITEM':\n      return {\n        ...state,\n        items: state.items.filter(i => i.id !== action.payload),\n      };\n    case 'UPDATE_QUANTITY':\n      return {\n        ...state,\n        items: state.items.map(item =>\n          item.id === action.payload.id\n            ? { ...item, quantity: action.payload.quantity }\n            : item\n        ),\n      };\n    case 'CLEAR_CART':\n      return { items: [], total: 0 };\n    default:\n      return state;\n  }\n}\n\n// context.tsx\nconst CartContext = createContext<{\n  state: CartState;\n  dispatch: React.Dispatch<CartAction>;\n} | null>(null);\n\nfunction CartProvider({ children }: { children: React.ReactNode }) {\n  const [state, dispatch] = useReducer(cartReducer, { items: [], total: 0 });\n\n  // Compute total whenever items change\n  const stateWithTotal = useMemo(() => ({\n    ...state,\n    total: state.items.reduce((sum, item) => sum + item.price * item.quantity, 0),\n  }), [state.items]);\n\n  return (\n    <CartContext.Provider value={{ state: stateWithTotal, dispatch }}>\n      {children}\n    </CartContext.Provider>\n  );\n}\n\nfunction useCart() {\n  const context = useContext(CartContext);\n  if (!context) throw new Error('useCart must be used within CartProvider');\n  return context;\n}\n```\n\n### Zustand (Lightweight Alternative)\n\n```tsx\nimport { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\n\ninterface AuthStore {\n  user: User | null;\n  token: string | null;\n  login: (email: string, password: string) => Promise<void>;\n  logout: () => void;\n}\n\nconst useAuthStore = create<AuthStore>()(\n  persist(\n    (set) => ({\n      user: null,\n      token: null,\n      login: async (email, password) => {\n        const { user, token } = await authAPI.login(email, password);\n        set({ user, token });\n      },\n      logout: () => set({ user: null, token: null }),\n    }),\n    { name: 'auth-storage' }\n  )\n);\n\n// Usage\nfunction Profile() {\n  const { user, logout } = useAuthStore();\n  return user ? <div>{user.name} <button onClick={logout}>Logout</button></div> : null;\n}\n```\n\n---\n\n## Performance Patterns\n\n### React.memo with Custom Comparison\n\n```tsx\ninterface ListItemProps {\n  item: { id: string; name: string; count: number };\n  onSelect: (id: string) => void;\n}\n\nconst ListItem = React.memo(\n  function ListItem({ item, onSelect }: ListItemProps) {\n    return (\n      <div onClick={() => onSelect(item.id)}>\n        {item.name} ({item.count})\n      </div>\n    );\n  },\n  (prevProps, nextProps) => {\n    // Only re-render if item data changed\n    return (\n      prevProps.item.id === nextProps.item.id &&\n      prevProps.item.name === nextProps.item.name &&\n      prevProps.item.count === nextProps.item.count\n    );\n  }\n);\n```\n\n### useMemo for Expensive Calculations\n\n```tsx\nfunction DataTable({ data, sortColumn, filterText }: {\n  data: Item[];\n  sortColumn: string;\n  filterText: string;\n}) {\n  const processedData = useMemo(() => {\n    // Filter\n    let result = data.filter(item =>\n      item.name.toLowerCase().includes(filterText.toLowerCase())\n    );\n\n    // Sort\n    result = [...result].sort((a, b) => {\n      const aVal = a[sortColumn as keyof Item];\n      const bVal = b[sortColumn as keyof Item];\n      return aVal < bVal ? -1 : aVal > bVal ? 1 : 0;\n    });\n\n    return result;\n  }, [data, sortColumn, filterText]);\n\n  return (\n    <table>\n      {processedData.map(item => (\n        <tr key={item.id}>{/* ... */}</tr>\n      ))}\n    </table>\n  );\n}\n```\n\n### useCallback for Stable References\n\n```tsx\nfunction ParentComponent() {\n  const [items, setItems] = useState<Item[]>([]);\n\n  // Stable reference - won't cause child re-renders\n  const handleItemClick = useCallback((id: string) => {\n    setItems(prev => prev.map(item =>\n      item.id === id ? { ...item, selected: !item.selected } : item\n    ));\n  }, []);\n\n  const handleAddItem = useCallback((newItem: Item) => {\n    setItems(prev => [...prev, newItem]);\n  }, []);\n\n  return (\n    <>\n      <ItemList items={items} onItemClick={handleItemClick} />\n      <AddItemForm onAdd={handleAddItem} />\n    </>\n  );\n}\n```\n\n### Virtualization for Long Lists\n\n```tsx\nimport { useVirtualizer } from '@tanstack/react-virtual';\n\nfunction VirtualList({ items }: { items: Item[] }) {\n  const parentRef = useRef<HTMLDivElement>(null);\n\n  const virtualizer = useVirtualizer({\n    count: items.length,\n    getScrollElement: () => parentRef.current,\n    estimateSize: () => 50, // estimated row height\n    overscan: 5,\n  });\n\n  return (\n    <div ref={parentRef} className=\"h-[400px] overflow-auto\">\n      <div\n        style={{ height: `${virtualizer.getTotalSize()}px`, position: 'relative' }}\n      >\n        {virtualizer.getVirtualItems().map(virtualRow => (\n          <div\n            key={virtualRow.key}\n            style={{\n              position: 'absolute',\n              top: 0,\n              left: 0,\n              width: '100%',\n              height: `${virtualRow.size}px`,\n              transform: `translateY(${virtualRow.start}px)`,\n            }}\n          >\n            {items[virtualRow.index].name}\n          </div>\n        ))}\n      </div>\n    </div>\n  );\n}\n```\n\n---\n\n## Error Boundaries\n\n### Class-Based Error Boundary\n\n```tsx\ninterface ErrorBoundaryProps {\n  children: React.ReactNode;\n  fallback?: React.ReactNode;\n  onError?: (error: Error, errorInfo: React.ErrorInfo) => void;\n}\n\ninterface ErrorBoundaryState {\n  hasError: boolean;\n  error: Error | null;\n}\n\nclass ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n  state: ErrorBoundaryState = { hasError: false, error: null };\n\n  static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n    return { hasError: true, error };\n  }\n\n  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {\n    this.props.onError?.(error, errorInfo);\n    // Log to error reporting service\n    console.error('Error caught:', error, errorInfo);\n  }\n\n  render() {\n    if (this.state.hasError) {\n      return this.props.fallback || (\n        <div className=\"p-4 bg-red-50 border border-red-200 rounded\">\n          <h2 className=\"text-red-800 font-bold\">Something went wrong</h2>\n          <p className=\"text-red-600\">{this.state.error?.message}</p>\n          <button\n            onClick={() => this.setState({ hasError: false, error: null })}\n            className=\"mt-2 px-4 py-2 bg-red-600 text-white rounded\"\n          >\n            Try Again\n          </button>\n        </div>\n      );\n    }\n\n    return this.props.children;\n  }\n}\n\n// Usage\n<ErrorBoundary\n  fallback={<ErrorFallback />}\n  onError={(error) => trackError(error)}\n>\n  <MyComponent />\n</ErrorBoundary>\n```\n\n### Suspense with Error Boundary\n\n```tsx\nfunction DataComponent() {\n  return (\n    <ErrorBoundary fallback={<ErrorMessage />}>\n      <Suspense fallback={<LoadingSpinner />}>\n        <AsyncDataLoader />\n      </Suspense>\n    </ErrorBoundary>\n  );\n}\n```\n\n---\n\n## Anti-Patterns\n\n### Avoid: Inline Object/Array Creation in JSX\n\n```tsx\n// BAD - Creates new object every render, causes re-renders\n<Component style={{ color: 'red' }} items={[1, 2, 3]} />\n\n// GOOD - Define outside or use useMemo\nconst style = { color: 'red' };\nconst items = [1, 2, 3];\n<Component style={style} items={items} />\n\n// Or with useMemo for dynamic values\nconst style = useMemo(() => ({ color: theme.primary }), [theme.primary]);\n```\n\n### Avoid: Index as Key for Dynamic Lists\n\n```tsx\n// BAD - Index keys break with reordering/filtering\n{items.map((item, index) => (\n  <Item key={index} data={item} />\n))}\n\n// GOOD - Use stable unique ID\n{items.map(item => (\n  <Item key={item.id} data={item} />\n))}\n```\n\n### Avoid: Prop Drilling\n\n```tsx\n// BAD - Passing props through many levels\n<App user={user}>\n  <Layout user={user}>\n    <Sidebar user={user}>\n      <UserInfo user={user} />\n    </Sidebar>\n  </Layout>\n</App>\n\n// GOOD - Use Context\nconst UserContext = createContext<User | null>(null);\n\nfunction App() {\n  return (\n    <UserContext.Provider value={user}>\n      <Layout>\n        <Sidebar>\n          <UserInfo />\n        </Sidebar>\n      </Layout>\n    </UserContext.Provider>\n  );\n}\n\nfunction UserInfo() {\n  const user = useContext(UserContext);\n  return <div>{user?.name}</div>;\n}\n```\n\n### Avoid: Mutating State Directly\n\n```tsx\n// BAD - Mutates state directly\nconst addItem = (item: Item) => {\n  items.push(item); // WRONG\n  setItems(items);  // Won't trigger re-render\n};\n\n// GOOD - Create new array\nconst addItem = (item: Item) => {\n  setItems(prev => [...prev, item]);\n};\n\n// GOOD - For objects\nconst updateUser = (field: string, value: string) => {\n  setUser(prev => ({ ...prev, [field]: value }));\n};\n```\n\n### Avoid: useEffect for Derived State\n\n```tsx\n// BAD - Unnecessary effect and extra render\nconst [items, setItems] = useState<Item[]>([]);\nconst [total, setTotal] = useState(0);\n\nuseEffect(() => {\n  setTotal(items.reduce((sum, item) => sum + item.price, 0));\n}, [items]);\n\n// GOOD - Compute during render\nconst [items, setItems] = useState<Item[]>([]);\nconst total = items.reduce((sum, item) => sum + item.price, 0);\n\n// Or useMemo for expensive calculations\nconst total = useMemo(\n  () => items.reduce((sum, item) => sum + item.price, 0),\n  [items]\n);\n```","readmeExcerpt":"Skill: Senior Frontend Owner: alirezarezvani Summary: Frontend development skill for React, Next.js, TypeScript, and Tailwind CSS applications. Use when building React components, optimizing Next.js performance, analyzing bundle sizes, scaffolding frontend projects, implementing accessibility, or reviewing frontend code quality. Tags: latest:1.0.0 Version history: v1.0.0 | 2026-02-06T18:27:42.862Z | auto Initial rele","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"python scripts/frontend_scaffolder.py my-app --template nextjs"},{"language":"bash","snippet":"python scripts/frontend_scaffolder.py dashboard --template nextjs --features auth,api"},{"language":"bash","snippet":"cd my-app && npm install"},{"language":"bash","snippet":"npm run dev"},{"language":"text","snippet":"my-app/\n├── app/\n│   ├── layout.tsx        # Root layout with fonts\n│   ├── page.tsx          # Home page\n│   ├── globals.css       # Tailwind + CSS variables\n│   └── api/health/route.ts\n├── components/\n│   ├── ui/               # Button, Input, Card\n│   └── layout/           # Header, Footer, Sidebar\n├── hooks/                # useDebounce, useLocalStorage\n├── lib/                  # utils (cn), constants\n├── types/                # TypeScript interfaces\n├── tailwind.config.ts\n├── next.config.js\n└── package.json"},{"language":"bash","snippet":"python scripts/component_generator.py Button --dir src/components/ui"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: senior-frontend\ndescription: Frontend development skill for React, Next.js, TypeScript, and Tailwind CSS applications. Use when building React components, optimizing Next.js performance, analyzing bundle sizes, scaffolding frontend projects, implementing accessibility, or reviewing frontend code quality.\n---\n\n# Senior Frontend\n\nFrontend development patterns, performance optimization, and automation tools for React/Next.js applications.\n\n## Table of Contents\n\n- [Project Scaffolding](#project-scaffolding)\n- [Component Generation](#component-generation)\n- [Bundle Analysis](#bundle-analysis)\n- [React Patterns](#react-patterns)\n- [Next.js Optimization](#nextjs-optimization)\n- [Accessibility and Testing](#accessibility-and-testing)\n\n---\n\n## Project Scaffolding\n\nGenerate a new Next.js or React project with TypeScript, Tailwind CSS, and best practice configurations.\n\n### Workflow: Create New Frontend Project\n\n1. Run the scaffolder with your project name and template:\n   ```bash\n   python scripts/frontend_scaffolder.py my-app --template nextjs\n   ```\n\n2. Add optional features (auth, api, forms, testing, storybook):\n   ```bash\n   python scripts/frontend_scaffolder.py dashboard --template nextjs --features auth,api\n   ```\n\n3. Navigate to the project and install dependencies:\n   ```bash\n   cd my-app && npm install\n   ```\n\n4. Start the development server:\n   ```bash\n   npm run dev\n   ```\n\n### Scaffolder Options\n\n| Option | Description |\n|--------|-------------|\n| `--template nextjs` | Next.js 14+ with App Router and Server Components |\n| `--template react` | React + Vite with TypeScript |\n| `--features auth` | Add NextAuth.js authentication |\n| `--features api` | Add React Query + API client |\n| `--features forms` | Add React Hook Form + Zod validation |\n| `--features testing` | Add Vitest + Testing Library |\n| `--dry-run` | Preview files without creating them |\n\n### Generated Structure (Next.js)\n\n```\nmy-app/\n├── app/\n│   ├── layout.tsx        # Root layout with fonts\n│   ├── page.tsx          # Home page\n│   ├── globals.css       # Tailwind + CSS variables\n│   └── api/health/route.ts\n├── components/\n│   ├── ui/               # Button, Input, Card\n│   └── layout/           # Header, Footer, Sidebar\n├── hooks/                # useDebounce, useLocalStorage\n├── lib/                  # utils (cn), constants\n├── types/                # TypeScript interfaces\n├── tailwind.config.ts\n├── next.config.js\n└── package.json\n```\n\n---\n\n## Component Generation\n\nGenerate React components with TypeScript, tests, and Storybook stories.\n\n### Workflow: Create a New Component\n\n1. Generate a client component:\n   ```bash\n   python scripts/component_generator.py Button --dir src/components/ui\n   ```\n\n2. Generate a server component:\n   ```bash\n   python scripts/component_generator.py ProductCard --type server\n   ```\n\n3. Generate with test and story files:\n   ```bash\n   python scripts/component_generator.py UserProfile --with-test --with-story\n   ```\n\n4. Generate a custom hook"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7f2gr00xy51fj1nx2y64ckjs800mhn\",\n  \"slug\": \"senior-frontend\",\n  \"version\": \"1.0.0\",\n  \"publishedAt\": 1770402462862\n}"},{"path":"references/frontend_best_practices.md","content":"# Frontend Best Practices\n\nModern frontend development standards for accessibility, testing, TypeScript, and Tailwind CSS.\n\n---\n\n## Table of Contents\n\n- [Accessibility (a11y)](#accessibility-a11y)\n- [Testing Strategies](#testing-strategies)\n- [TypeScript Patterns](#typescript-patterns)\n- [Tailwind CSS](#tailwind-css)\n- [Project Structure](#project-structure)\n- [Security](#security)\n\n---\n\n## Accessibility (a11y)\n\n### Semantic HTML\n\n```tsx\n// BAD - Divs for everything\n<div onClick={handleClick}>Click me</div>\n<div class=\"header\">...</div>\n<div class=\"nav\">...</div>\n\n// GOOD - Semantic elements\n<button onClick={handleClick}>Click me</button>\n<header>...</header>\n<nav>...</nav>\n<main>...</main>\n<article>...</article>\n<aside>...</aside>\n<footer>...</footer>\n```\n\n### Keyboard Navigation\n\n```tsx\n// Ensure all interactive elements are keyboard accessible\nfunction Modal({ isOpen, onClose, children }: ModalProps) {\n  const modalRef = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    if (isOpen) {\n      // Focus first focusable element\n      const focusable = modalRef.current?.querySelectorAll(\n        'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n      );\n      (focusable?.[0] as HTMLElement)?.focus();\n\n      // Trap focus within modal\n      const handleTab = (e: KeyboardEvent) => {\n        if (e.key === 'Tab' && focusable) {\n          const first = focusable[0] as HTMLElement;\n          const last = focusable[focusable.length - 1] as HTMLElement;\n\n          if (e.shiftKey && document.activeElement === first) {\n            e.preventDefault();\n            last.focus();\n          } else if (!e.shiftKey && document.activeElement === last) {\n            e.preventDefault();\n            first.focus();\n          }\n        }\n\n        if (e.key === 'Escape') {\n          onClose();\n        }\n      };\n\n      document.addEventListener('keydown', handleTab);\n      return () => document.removeEventListener('keydown', handleTab);\n    }\n  }, [isOpen, onClose]);\n\n  if (!isOpen) return null;\n\n  return (\n    <div\n      ref={modalRef}\n      role=\"dialog\"\n      aria-modal=\"true\"\n      aria-labelledby=\"modal-title\"\n    >\n      {children}\n    </div>\n  );\n}\n```\n\n### ARIA Attributes\n\n```tsx\n// Live regions for dynamic content\n<div aria-live=\"polite\" aria-atomic=\"true\">\n  {status && <p>{status}</p>}\n</div>\n\n// Loading states\n<button disabled={isLoading} aria-busy={isLoading}>\n  {isLoading ? 'Loading...' : 'Submit'}\n</button>\n\n// Form labels\n<label htmlFor=\"email\">Email address</label>\n<input\n  id=\"email\"\n  type=\"email\"\n  aria-required=\"true\"\n  aria-invalid={!!errors.email}\n  aria-describedby={errors.email ? 'email-error' : undefined}\n/>\n{errors.email && (\n  <p id=\"email-error\" role=\"alert\">\n    {errors.email}\n  </p>\n)}\n\n// Navigation\n<nav aria-label=\"Main navigation\">\n  <ul>\n    <li><a href=\"/\" aria-current={isHome ? 'page' : undefined}>Home</a></li>\n    <li><a href=\"/about\" aria-current={isAbout ? 'page' : undefined}>About</a></li>\n  </ul>\n</nav>\n"},{"path":"references/nextjs_optimization_guide.md","content":"# Next.js Optimization Guide\n\nPerformance optimization techniques for Next.js 14+ applications.\n\n---\n\n## Table of Contents\n\n- [Rendering Strategies](#rendering-strategies)\n- [Image Optimization](#image-optimization)\n- [Code Splitting](#code-splitting)\n- [Data Fetching](#data-fetching)\n- [Caching Strategies](#caching-strategies)\n- [Bundle Optimization](#bundle-optimization)\n- [Core Web Vitals](#core-web-vitals)\n\n---\n\n## Rendering Strategies\n\n### Server Components (Default)\n\nServer Components render on the server and send HTML to the client. Use for data-heavy, non-interactive content.\n\n```tsx\n// app/products/page.tsx - Server Component (default)\nasync function ProductsPage() {\n  // This runs on the server - no client bundle impact\n  const products = await db.products.findMany();\n\n  return (\n    <div className=\"grid grid-cols-3 gap-4\">\n      {products.map(product => (\n        <ProductCard key={product.id} product={product} />\n      ))}\n    </div>\n  );\n}\n```\n\n### Client Components\n\nUse `'use client'` only when you need:\n- Event handlers (onClick, onChange)\n- State (useState, useReducer)\n- Effects (useEffect)\n- Browser APIs (window, document)\n\n```tsx\n'use client';\n\nimport { useState } from 'react';\n\nfunction AddToCartButton({ productId }: { productId: string }) {\n  const [isAdding, setIsAdding] = useState(false);\n\n  async function handleClick() {\n    setIsAdding(true);\n    await addToCart(productId);\n    setIsAdding(false);\n  }\n\n  return (\n    <button onClick={handleClick} disabled={isAdding}>\n      {isAdding ? 'Adding...' : 'Add to Cart'}\n    </button>\n  );\n}\n```\n\n### Mixing Server and Client Components\n\n```tsx\n// app/products/[id]/page.tsx - Server Component\nasync function ProductPage({ params }: { params: { id: string } }) {\n  const product = await getProduct(params.id);\n\n  return (\n    <div>\n      {/* Server-rendered content */}\n      <h1>{product.name}</h1>\n      <p>{product.description}</p>\n\n      {/* Client component for interactivity */}\n      <AddToCartButton productId={product.id} />\n\n      {/* Server component for reviews */}\n      <ProductReviews productId={product.id} />\n    </div>\n  );\n}\n```\n\n### Static vs Dynamic Rendering\n\n```tsx\n// Force static generation at build time\nexport const dynamic = 'force-static';\n\n// Force dynamic rendering at request time\nexport const dynamic = 'force-dynamic';\n\n// Revalidate every 60 seconds (ISR)\nexport const revalidate = 60;\n\n// Revalidate on-demand\nimport { revalidatePath, revalidateTag } from 'next/cache';\n\nasync function updateProduct(id: string, data: ProductData) {\n  await db.products.update({ where: { id }, data });\n\n  // Revalidate specific path\n  revalidatePath(`/products/${id}`);\n\n  // Or revalidate by tag\n  revalidateTag('products');\n}\n```\n\n---\n\n## Image Optimization\n\n### Next.js Image Component\n\n```tsx\nimport Image from 'next/image';\n\n// Basic optimized image\n<Image\n  src=\"/hero.jpg\"\n  alt=\"Hero image\"\n  width={1200}\n  height={600}\n  priority // Load immediately for LCP\n/>\n\n// Responsive ima"},{"path":"references/react_patterns.md","content":"# React Patterns\n\nProduction-ready patterns for building scalable React applications with TypeScript.\n\n---\n\n## Table of Contents\n\n- [Component Composition](#component-composition)\n- [Custom Hooks](#custom-hooks)\n- [State Management](#state-management)\n- [Performance Patterns](#performance-patterns)\n- [Error Boundaries](#error-boundaries)\n- [Anti-Patterns](#anti-patterns)\n\n---\n\n## Component Composition\n\n### Compound Components\n\nUse compound components when building reusable UI components with multiple related parts.\n\n```tsx\n// Compound component pattern for a Select\ninterface SelectContextType {\n  value: string;\n  onChange: (value: string) => void;\n}\n\nconst SelectContext = createContext<SelectContextType | null>(null);\n\nfunction Select({ children, value, onChange }: {\n  children: React.ReactNode;\n  value: string;\n  onChange: (value: string) => void;\n}) {\n  return (\n    <SelectContext.Provider value={{ value, onChange }}>\n      <div className=\"relative\">{children}</div>\n    </SelectContext.Provider>\n  );\n}\n\nfunction SelectTrigger({ children }: { children: React.ReactNode }) {\n  const context = useContext(SelectContext);\n  if (!context) throw new Error('SelectTrigger must be used within Select');\n\n  return (\n    <button className=\"flex items-center gap-2 px-4 py-2 border rounded\">\n      {children}\n    </button>\n  );\n}\n\nfunction SelectOption({ value, children }: { value: string; children: React.ReactNode }) {\n  const context = useContext(SelectContext);\n  if (!context) throw new Error('SelectOption must be used within Select');\n\n  return (\n    <div\n      onClick={() => context.onChange(value)}\n      className={`px-4 py-2 cursor-pointer hover:bg-gray-100 ${\n        context.value === value ? 'bg-blue-50' : ''\n      }`}\n    >\n      {children}\n    </div>\n  );\n}\n\n// Attach sub-components\nSelect.Trigger = SelectTrigger;\nSelect.Option = SelectOption;\n\n// Usage\n<Select value={selected} onChange={setSelected}>\n  <Select.Trigger>Choose option</Select.Trigger>\n  <Select.Option value=\"a\">Option A</Select.Option>\n  <Select.Option value=\"b\">Option B</Select.Option>\n</Select>\n```\n\n### Render Props\n\nUse render props when you need to share behavior with flexible rendering.\n\n```tsx\ninterface MousePosition {\n  x: number;\n  y: number;\n}\n\nfunction MouseTracker({ render }: { render: (pos: MousePosition) => React.ReactNode }) {\n  const [position, setPosition] = useState<MousePosition>({ x: 0, y: 0 });\n\n  useEffect(() => {\n    const handleMouseMove = (e: MouseEvent) => {\n      setPosition({ x: e.clientX, y: e.clientY });\n    };\n    window.addEventListener('mousemove', handleMouseMove);\n    return () => window.removeEventListener('mousemove', handleMouseMove);\n  }, []);\n\n  return <>{render(position)}</>;\n}\n\n// Usage\n<MouseTracker\n  render={({ x, y }) => (\n    <div>Mouse position: {x}, {y}</div>\n  )}\n/>\n```\n\n### Higher-Order Components (HOC)\n\nUse HOCs for cross-cutting concerns like authentication or logging.\n\n```tsx\nfunction withAuth<P extends object>(WrappedComponent: React"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Frontend development skill for React, Next.js, TypeScript, and Tailwind CSS applications. Use when building React components, optimizing Next.js performance, analyzing bundle sizes, scaffolding frontend projects, implementing accessibility, or reviewing frontend code quality. Skill: Senior Frontend Owner: alirezarezvani Summary: Frontend development skill for React, Next.js, TypeScript, and Tailwind CSS applications. Use when building React components, optimizing Next.js performance, analyzing bundle sizes, scaffolding frontend projects, implementing accessibility, or reviewing frontend code quality. Tags: latest:1.0.0 Version history: v1.0.0 | 2026-02-06T18:27:42.862Z | auto Initial rele","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1025,"uniquenessScore":51,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T14:59:25.755Z","emptyReason":null},"items":[{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-10T18:48:31.762Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}