| name | Frontend Development |
| description | Expert skill for Next.js 16 frontend development with React, TypeScript, and TailwindCSS. Use when building UI components, implementing hooks, or debugging frontend issues. |
Frontend Development Skill
Overview
This skill provides expertise in developing the Chimera frontend using Next.js 16, React, TypeScript, and TailwindCSS with a focus on avant-garde, premium UI design.
When to Use This Skill
- Building or modifying React components
- Implementing custom hooks (useAuth, useAegisTelemetry, etc.)
- Debugging WebSocket connections
- Styling with TailwindCSS and custom CSS
- Fixing TypeScript type errors
- Troubleshooting build or dev server issues
Technology Stack
Core Framework
- Next.js 16: React framework with App Router
- React 19: Latest React with Server Components
- TypeScript 5.7+: Strict type checking
- TailwindCSS 3: Utility-first CSS framework
Key Dependencies
{
"next": "^16.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"typescript": "^5.7.0",
"tailwindcss": "^3.4.0",
"zustand": "^4.5.0",
"axios": "^1.6.0",
"zod": "^3.22.0"
}
Project Structure
frontend/
├── src/
│ ├── app/ # Next.js App Router pages
│ │ ├── (auth)/ # Authentication layouts
│ │ │ ├── login/
│ │ │ └── register/
│ │ ├── dashboard/ # Main dashboard
│ │ └── layout.tsx # Root layout
│ ├── components/ # Reusable components
│ │ ├── aegis/ # Aegis-specific components
│ │ │ ├── AegisCampaignDashboard.tsx
│ │ │ ├── CampaignMetrics.tsx
│ │ │ └── PersonaVisualization.tsx
│ │ ├── ui/ # Radix UI primitives
│ │ └── layout/ # Layout components
│ ├── hooks/ # Custom React hooks
│ │ ├── useAuth.ts
│ │ ├── useAegisTelemetry.ts
│ │ └── useWebSocket.ts
│ ├── contexts/ # React Context providers
│ │ ├── AuthContext.tsx
│ │ └── WebSocketProvider.tsx
│ ├── lib/ # Utility functions
│ │ ├── api.ts # API client
│ │ └── utils.ts # Helper functions
│ ├── styles/ # Global and custom CSS
│ │ └── globals.css
│ └── types/ # TypeScript type definitions
├── public/ # Static assets
├── tailwind.config.ts # TailwindCSS configuration
└── next.config.ts # Next.js configuration
Design Philosophy: "Avant-Garde Minimalism"
Core Principles
- Anti-Generic: Reject bootstrap templates, create bespoke layouts
- Intentional Placement: Every element must have a calculated purpose
- Premium Aesthetics: Use vibrant colors, dark modes, glassmorphism, dynamic animations
- Micro-Interactions: Smooth hover effects, subtle animations for engagement
Color Palette Guidelines
--color-bad-red: #ff0000;
--color-bad-blue: #0000ff;
--color-primary: hsl(260, 85%, 60%);
--color-accent: hsl(180, 100%, 50%);
--color-success: hsl(142, 76%, 36%);
--color-danger: hsl(0, 84%, 60%);
Typography
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
.heading {
font-family: 'Inter', 'Google Sans Flex', sans-serif;
font-weight: 600;
letter-spacing: -0.02em;
}
Glassmorphism Example
<div className="
backdrop-blur-md bg-white/10
border border-white/20
rounded-2xl shadow-2xl
p-6
hover:bg-white/15
transition-all duration-300
">
{}
</div>
Common Commands
Development Server
npm run dev:frontend
cd frontend
npm run dev
Build and Production
cd frontend
npm run build
npm start
npm run type-check
Linting and Formatting
npm run lint
npm run lint:fix
npm run format
Common Issues and Solutions
1. Login Page Not Redirecting After Success
Symptom: Login succeeds but page stays on login screen
Root Cause: isAuthStateReady flag not properly managed or redirect logic missing
Fix:
"use client";
import { useAuth } from "@/hooks/useAuth";
import { useRouter } from "next/navigation";
import { useEffect } from "react";
export default function LoginPage() {
const { user, isAuthStateReady } = useAuth();
const router = useRouter();
useEffect(() => {
if (isAuthStateReady && user) {
router.push("/dashboard");
}
}, [isAuthStateReady, user, router]);
}
2. WebSocket Connection Failures
Symptom: useAegisTelemetry hook fails to connect or disconnects immediately
Root Cause: Incorrect WebSocket URL or missing authentication
Fix:
import { useEffect, useState } from "react";
export function useAegisTelemetry(campaignId: string) {
const [socket, setSocket] = useState<WebSocket | null>(null);
const [data, setData] = useState(null);
useEffect(() => {
const ws = new WebSocket(
`ws://localhost:8001/api/v1/ws/aegis/telemetry/${campaignId}`
);
ws.onopen = () => console.log("WebSocket connected");
ws.onmessage = (event) => setData(JSON.parse(event.data));
ws.onerror = (error) => console.error("WebSocket error:", error);
ws.onclose = () => console.log("WebSocket closed");
setSocket(ws);
return () => {
ws.();
};
}, [campaignId]);
{ socket, data };
}
3. TypeScript Type Errors
Symptom: Type 'X' is not assignable to type 'Y' errors
Common Fixes:
const [data, setData] = useState(null);
const [data, setData] = useState<CampaignData | null>(null);
const handleSubmit = (e) => { ... }
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { ... }
const name = user.profile.name;
const name = user?.profile?.name ?? "Guest";
4. TailwindCSS Styles Not Applying
Symptom: Classes not generating styles
Checklist:
- Verify
tailwind.config.ts has correct content paths:
export default {
content: [
"./src/app/**/*.{js,ts,jsx,tsx}",
"./src/components/**/*.{js,ts,jsx,tsx}",
],
}
- Ensure
globals.css imports Tailwind directives:
@tailwind base;
@tailwind components;
@tailwind utilities;
- Restart dev server after config changes
5. API Proxy 404 Errors
Symptom: Frontend requests to /api/* return 404
Root Cause: Next.js not configured to proxy to backend
Fix in next.config.ts:
const nextConfig = {
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'http://localhost:8001/api/:path*',
},
];
},
};
Component Development Best Practices
1. Use Radix UI Primitives (If Available)
import { Button } from "@/components/ui/button";
import { Dialog } from "@/components/ui/dialog";
<Button className="bg-gradient-to-r from-purple-600 to-pink-600">
Launch Campaign
</Button>
2. Server vs Client Components
export default function CampaignList({ campaigns }) {
return <div>{campaigns.map(c => <CampaignCard key={c.id} {...c} />)}</div>;
}
"use client";
export default function CampaignForm() {
const [name, setName] = useState("");
const handleSubmit = () => { };
return <form onSubmit={handleSubmit}>...</form>;
}
3. Semantic HTML and Accessibility
<nav aria-label="Main navigation">
<ul>
<li><a href="/dashboard">Dashboard</a></li>
<li><a href="/campaigns">Campaigns</a></li>
</ul>
</nav>
<div className="nav">
<div className="link">Dashboard</div>
</div>
4. Loading States and Error Boundaries
import { Suspense } from "react";
import Loading from "./loading";
import ErrorBoundary from "./error";
export default function CampaignPage() {
return (
<ErrorBoundary fallback={<Error />}>
<Suspense fallback={<Loading />}>
<CampaignDashboard />
</Suspense>
</ErrorBoundary>
);
}
Custom Hooks Patterns
useAuth Hook
import { useContext } from "react";
import { AuthContext } from "@/contexts/AuthContext";
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within AuthProvider");
}
return context;
}
useWebSocket Hook
export function useWebSocket(url: string) {
const [status, setStatus] = useState<"connecting" | "open" | "closed">("connecting");
useEffect(() => {
const ws = new WebSocket(url);
ws.onopen = () => setStatus("open");
ws.onclose = () => setStatus("closed");
return () => ws.close();
}, [url]);
return { status };
}
Performance Optimization
1. Code Splitting
import dynamic from "next/dynamic";
const HeavyChart = dynamic(() => import("@/components/HeavyChart"), {
ssr: false,
loading: () => <Skeleton />,
});
2. Image Optimization
import Image from "next/image";
<Image
src="/campaign-bg.jpg"
alt="Campaign background"
width={1200}
height={630}
priority // For above-the-fold images
/>
3. Memoization
import { useMemo, useCallback } from "react";
const expensiveValue = useMemo(() => {
return computeExpensiveValue(data);
}, [data]);
const handleClick = useCallback(() => {
}, [dependency]);
Animation Examples
Micro-Interactions
<button className="
px-6 py-3
bg-gradient-to-r from-purple-600 to-pink-600
rounded-lg
transform transition-all duration-200
hover:scale-105 hover:shadow-2xl
active:scale-95
focus:outline-none focus:ring-2 focus:ring-purple-500
">
Start Campaign
</button>
Loading Spinner
<div className="
w-12 h-12
border-4 border-purple-200
border-t-purple-600
rounded-full
animate-spin
" />
Testing
Unit Tests (Vitest)
import { render, screen } from "@testing-library/react";
import { describe, it, expect } from "vitest";
describe("Button", () => {
it("renders with text", () => {
render(<Button>Click me</Button>);
expect(screen.getByText("Click me")).toBeInTheDocument();
});
});
E2E Tests (Playwright)
import { test, expect } from "@playwright/test";
test("login flow", async ({ page }) => {
await page.goto("http://localhost:3001/login");
await page.fill('input[name="email"]', "test@example.com");
await page.fill('input[name="password"]', "password");
await page.click('button[type="submit"]');
await expect(page).toHaveURL(/.*dashboard/);
});
References