This skill has two modes. Use explicit invocation to select a mode, or let it auto-detect.
Invocation:
/frontend-design saas— B2B SaaS mode (explicit)/frontend-design marketing— Public/Marketing mode (explicit)/frontend-design— auto-detects from context, defaults to B2B SaaS
Auto-detection: Default to B2B SaaS unless the user mentions landing pages, homepages, brochure sites, marketing sites, or public-facing websites.
Mode 1: B2B SaaS (Default)
Build application interfaces using shadcn/ui primitives exclusively. Do not write custom components when a shadcn primitive exists. The goal is composable, consistent, production-grade UI with zero unnecessary custom code.
Standardized Stack
These decisions are already made. Do not re-evaluate, substitute, or propose alternatives:
| Concern | Library | Notes |
|---|---|---|
| UI primitives | shadcn/ui | Always. Every component. No exceptions. |
| Styling | Tailwind CSS | Utility classes only. No custom CSS files. Use shadcn CSS variables for theming. |
| Icons | Lucide | shadcn default. Already throughout the codebase. |
| Charts | Recharts via shadcn | Use shadcn's chart components, which wrap Recharts. |
| Data tables | TanStack Table | Via shadcn Data Table. All tabular data goes through this. |
| Data fetching | TanStack Query | Caching, invalidation, optimistic updates. Pairs naturally with TanStack Table. Use for all server state. |
| Forms | react-hook-form + zod | Via shadcn Form. All forms are validated with zod schemas. |
| Dates | date-fns | Tree-shakeable. Use for all date formatting, parsing, relative times. |
| Drag & drop | dnd-kit | For sortable lists, custom dashboard layouts, reorderable items. |
| Auth | Clerk | Owns all auth UI. Login/signup patterns come from Clerk components. Do not build custom auth screens. |
| State management | Context API + Reducers | Current standard. Do not introduce zustand/jotai/redux. |
Layout Architecture
Every B2B SaaS app uses this foundation:
- Sidebar (shadcn) — Always. Primary navigation lives here. User avatar, account switcher, and settings go in the sidebar footer. Use collapsible sidebar groups for organizing nav items.
- Resizable Panels (react-resizable-panels) — Use for any split-view layout: list/detail, editor/preview, main/sidebar content. Prefer this over custom flex layouts when content areas should be user-adjustable.
- Main content area — Compose with shadcn Cards, Tables, Forms, and Tabs as needed.
Core Rules
- shadcn/ui first: Before writing ANY component, check if shadcn has it. If it does, use it. No exceptions.
- No custom CSS files: Tailwind utility classes only. Use shadcn's CSS variables (
--primary,--secondary,--muted, etc.) for theming. - Composition over creation: Complex UI = more primitives composed together. A settings page is Cards + Form + Tabs + Separator. A dashboard is Cards + Data Table + Charts. Never build from scratch what you can compose.
- No custom buttons, inputs, selects, dialogs, or any form element: These always come from shadcn.
shadcn Component Reference
Always reach for these before writing custom code:
Layout & Navigation:
- Sidebar — app-level navigation, always present
- Tabs — content sections within a page
- Breadcrumb — location context
- Separator — visual dividers
- ScrollArea — scrollable containers
- Collapsible — expandable sections
Data Display:
- Data Table (TanStack Table) — any list of records, always
- Card — content containers, stats, summaries
- Badge — status indicators, tags, counts
- Avatar — user/entity representation
- Skeleton — loading states
- Alert — contextual messages
- Chart (Recharts) — all data visualization
Forms & Input:
- Form (react-hook-form + zod) — all forms, always validated
- Input, Textarea, Select, Checkbox, Switch, Label — form primitives
- Calendar, Date Picker — date selection (format with date-fns)
- Combobox — searchable select
Overlays & Feedback:
- Dialog — confirmations, focused tasks
- Sheet — slide-out panels for detail views or forms
- Command (cmdk) — command palette, searchable menus
- Dropdown Menu — context menus, action menus
- Popover — contextual info, mini-forms
- Tooltip — helper text on hover
- Toast / Sonner — notifications, success/error feedback
Actions:
- Button — all clickable actions
- Toggle / Toggle Group — binary or grouped selections
Interactive:
- dnd-kit — sortable lists, drag-and-drop layouts, reorderable items
Patterns
- List/Detail view: Resizable panels. Left panel = Data Table with search/filter. Right panel = detail Sheet or Card layout.
- Settings page: Sidebar nav (or Tabs) + Form sections in Cards.
- Dashboard: Grid of Cards with stats + Data Table for recent activity + Recharts via shadcn Chart for visualizations.
- Empty states: Card with centered content, Lucide icon, description, and primary action Button.
- Loading: Skeleton components matching the shape of the content they replace. TanStack Query handles loading/error states.
- Modals for creation: Dialog for simple forms. Sheet for complex multi-step forms.
- Sortable/reorderable UI: dnd-kit with shadcn Card or Table rows as drag targets.
- Date display: date-fns
formatDistanceToNowfor relative times,formatfor absolute dates. Be consistent within a view. - Data fetching: TanStack Query hooks for all server state.
useQueryfor reads,useMutationfor writes with optimistic updates where appropriate.
Mode 2: Public / Marketing
Activated when building public-facing websites, landing pages, marketing sites, brochure sites, or homepages. Invoke explicitly with /frontend-design marketing.
This mode prioritizes distinctive, memorable design. Implement real working code with exceptional craft using modern CSS and animation techniques.
Design Thinking
Before coding, commit to a BOLD aesthetic direction:
- Purpose: What problem does this interface solve? Who uses it?
- Tone: Pick an extreme — brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, editorial/magazine, brutalist/raw, art deco/geometric, industrial/utilitarian. Commit fully.
- Differentiation: What's the one thing someone will remember?
Execute the chosen direction with precision. Bold maximalism and refined minimalism both work — the key is intentionality, not intensity.
Library Stack
| Concern | Library | Notes |
|---|---|---|
| Smooth scroll | Lenis (3KB) | Industry standard. Preserves sticky & IntersectionObserver. |
| Animation (React) | Motion (8KB) | Spring physics, layout animations, gestures. |
| Complex timelines | GSAP | ScrollTrigger, SplitText (free since 2025), MorphSVG, Flip, Physics2D. |
| Text splitting | GSAP SplitText | Lines/words/chars with masking. Use for hero text reveals. |
| 3D (React) | React Three Fiber + Drei | WebGPU support. Use for hero scenes, product showcases. |
| Cursor effects | Cuberto Mouse Follower | Custom cursor with magnetic/morphing effects. Requires GSAP. |
| CSS animation | TailwindCSS Motion | Zero-JS animation utilities for Tailwind projects. |
Modern CSS (Use These — They're Supported Now)
Scroll-Driven Animations (no JS needed for 85% of scroll effects):
.element {
animation: reveal linear;
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
View Transitions API (page transitions without JS):
@view-transition { navigation: auto; }
.card { view-transition-name: card-element; }
:has() selector for parent-aware styling:
.card:has(img) { grid-template-columns: 200px 1fr; }
body:has(.modal[open]) { overflow: hidden; }
@starting-style for entry animations without JS:
.toast { opacity: 1; transform: translateY(0); transition: all 200ms ease; }
@starting-style { .toast { opacity: 0; transform: translateY(12px); } }
Container queries for truly responsive components:
.card-container { container-type: inline-size; }
@container (min-width: 400px) { .card { grid-template-columns: 200px 1fr; } }
OKLCH color space for perceptually uniform colors:
:root {
--brand: oklch(0.62 0.16 35);
--brand-soft: color-mix(in oklch, var(--brand), white 65%);
}
/* Richer gradients via oklch interpolation */
background: linear-gradient(to right in oklch, var(--brand), var(--accent));
CSS-only staggered animations with sibling-index():
.item { transition-delay: calc((sibling-index() - 1) * 40ms); }
Typography
Font pairings (never reuse the same pairing twice across generations):
Display fonts: Clash Display, Cabinet Grotesk, Fraunces (variable, expressive), Space Grotesk (techy) Body fonts: Satoshi, General Sans, Geist Sans, DM Sans, Outfit, Manrope Serif: Playfair Display (editorial), Fraunces (wonky axes)
AVOID: Inter, Roboto, Arial, system fonts — these are for SaaS mode, not marketing.
Fluid typography (always use clamp(), never fixed sizes):
--text-hero: clamp(2.5rem, 1.5rem + 5vw, 6rem);
--text-xl: clamp(1.75rem, 1.2rem + 2.5vw, 3rem);
--text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
Text effects: gradient text with OKLCH, image-masked text, variable font axis animation on hover.
Animation Patterns
Hero text reveal (GSAP SplitText + ScrollTrigger):
SplitText.create(heading, { type: "lines, words, chars", mask: "lines" });
gsap.fromTo(heading.querySelectorAll('.line'),
{ yPercent: 110 },
{ yPercent: 0, duration: 0.8, stagger: 0.08, ease: "power3.out" }
);
Magnetic buttons (spring physics on hover — GSAP or Motion):
// Element follows cursor within its bounds, snaps back with spring easing
const xTo = gsap.quickTo(el, "x", { duration: 1, ease: "elastic.out(1, 0.3)" });
const yTo = gsap.quickTo(el, "y", { duration: 1, ease: "elastic.out(1, 0.3)" });
Multi-layer parallax (pure CSS scroll-driven):
.bg-layer { animation: parallax linear; animation-timeline: scroll(); }
@keyframes parallax { to { transform: translateY(-10%); } }
Timing standards: micro-interactions 200-500ms, page transitions 300-600ms, stagger delays 30-80ms between elements.
Layout Patterns
Bento grid — asymmetric card grids with hero (2x2), wide (2x1), and tall (1x2) variants. Collapse to single column on mobile.
Sticky scroll sections — stacked position: sticky; height: 100vh sections where each "replaces" the previous on scroll. Perfect for feature showcases.
Horizontal scroll sections — scroll-snap-type: x mandatory with flex: 0 0 80vw children.
Overlapping elements — use CSS Grid with overlapping grid-column/grid-row ranges and z-index. Subgrid for inherited tracks.
Visual Effects
Glassmorphism (dark mode focused in 2026):
.glass {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(20px) saturate(180%);
border: 1px solid rgba(255, 255, 255, 0.08);
}
Grain/noise overlay — SVG feTurbulence filter at 3-4% opacity with mix-blend-mode: overlay. Apply as a fixed full-screen layer.
Aurora/mesh gradients — multiple radial-gradient layers in OKLCH with slow position animation (15s+ cycle).
3D card transforms — perspective(800px) with CSS custom properties (--rx, --ry) set by mousemove JS for tilt effect.
Anti-Patterns (NEVER Do These)
AI Slop Tells — these immediately signal "AI-generated, not designed":
- Chartreuse/purple/indigo gradient palettes (the default AI color story)
- Emoji as icons or decorative elements — use Lucide, custom SVGs, or nothing
- Oversized rounded corners on everything (the bubbly/toy look)
- Pastel cards with drop shadows floating on white backgrounds
- Generic hero illustrations (abstract blobs, floating 3D shapes)
- "Friendly" sans-serif + pastel palette + rounded buttons = the Lovable/v0 starter kit aesthetic
- Feature grids with emoji headers (the "rocket ship for speed, shield for security" cliche)
Design Anti-Patterns:
- Generic fonts (Inter, Roboto, Arial, system defaults)
- Cookie-cutter hero → features → testimonials → CTA layouts without spatial creativity
- Static, lifeless pages with no scroll interaction
- Reusing the same aesthetic across generations — every design must feel unique
- Over-animating: one orchestrated hero reveal > scattered micro-interactions everywhere
The standard: if a designer at a top agency would look at the output and say "that's clearly AI," it's wrong. The work should be indistinguishable from a senior designer's Figma-to-code handoff.