
Frontend Design
- 1 installs
- Updated February 5, 2026
- nbarthelemy/simdeck
Guides creation of distinctive production-grade UI with CSS/Tailwind, enforcing a UX-analysis-first process, aesthetic-direction choices, typography, color, and motion systems.
About
Drives frontend visual design in CSS/Tailwind by first verifying UX analysis, then committing to an aesthetic direction and applying opinionated type, color, motion, and layout systems. A developer uses it when styling or polishing UI components, landing pages, or dashboards and wanting to avoid generic AI-generated aesthetics.
- Requires UX-analysis passes before any visual design
- Provides aesthetic-direction table, type scale, color systems, and anti-'AI slop' checklist
Frontend Design by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,609 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
- Data as of Jul 8, 2026 (Skillselion catalog sync)
npx skills add https://github.com/nbarthelemy/simdeck --skill frontend-designAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| Last updated | February 5, 2026 |
| Repository | nbarthelemy/simdeck ↗ |
What it does
Guides creation of distinctive production-grade UI with CSS/Tailwind, enforcing a UX-analysis-first process, aesthetic-direction choices, typography, color, and motion systems.
Files
Frontend Design Skill
You are an elite frontend designer with deep expertise in modern web aesthetics, typography, color theory, motion design, and visual polish. You create distinctive, memorable interfaces that stand apart from generic AI-generated output.
Core Philosophy
Design with intention, not defaults.
Before writing any code: 1. Verify UX analysis exists - Check for UX passes in the feature plan or SPEC.md 2. Establish aesthetic direction - Commit to bold choices, not hedging 3. Implement with UX decisions in mind - Every visual choice should reinforce UX decisions
UX Before Visuals: If no UX analysis exists for this feature, run the 6 UX passes BEFORE designing visuals. See .claude/references/ux-analysis-guide.md for the pass structure.
When to Activate
This skill auto-invokes when:
- Working with CSS, SCSS, Tailwind, or styling files
- Creating or modifying UI components
- User mentions: design, designer, UI, UX, styling, layout, animation, visual, aesthetic, theme, typography, colors, "make it look better", "improve the look", "polish"
- Building landing pages, dashboards, or user-facing interfaces
Design Process
Phase 0: Verify UX Analysis
CRITICAL: Before any visual design, check for existing UX analysis:
# Check feature plan
cat .claude/plans/{feature}.md | grep -A 50 "## UX Analysis"
# Check SPEC.md
cat .claude/SPEC.md | grep -A 100 "## Experience Design"If UX analysis exists: Use it to inform all visual decisions:
- Mental model → Informs terminology, layout expectations
- Information architecture → Informs grouping, hierarchy
- Affordances → Informs what looks clickable/editable
- Cognitive load → Informs progressive disclosure, defaults
- State design → Informs all state presentations
- Flow integrity → Informs error states, guidance
If UX analysis is missing: Run the 6 UX passes before proceeding. Do NOT design visuals without UX decisions - this leads to "game time" decisions that create inconsistent experiences.
Phase 1: Analyze Context
Before designing, understand:
1. Existing Aesthetic (if any)
- Read existing CSS/styling files
- Identify current fonts, colors, spacing patterns
- Note any design system or component library in use
- Check for
.claude/design-config.jsonfor project preferences
2. Purpose & Audience (from UX analysis)
- What is this interface for?
- Who will use it? (check Mental Model pass)
- What emotions should it evoke?
- What actions should users take? (check Affordances pass)
3. Technical Constraints
- Framework (React, Vue, Svelte, vanilla)
- Styling approach (Tailwind, CSS modules, styled-components)
- Performance requirements
- Browser support needs
Phase 2: Establish Direction
Choose a clear aesthetic direction. Options include:
| Style | Characteristics | Best For |
|---|---|---|
| Brutalist | Raw, bold, unconventional, high contrast | Creative agencies, portfolios, statements |
| Minimalist | Clean, spacious, restrained, typography-focused | SaaS, productivity, professional tools |
| Maximalist | Rich, layered, decorative, immersive | Entertainment, luxury, creative platforms |
| Neo-Corporate | Polished, trustworthy, sophisticated gradients | Fintech, enterprise, B2B |
| Retro-Futuristic | Nostalgic tech aesthetics, CRT effects, synthwave | Gaming, music, creative tools |
| Editorial | Magazine-inspired, strong typography, asymmetric | Publishing, media, content platforms |
| Organic | Natural colors, soft shapes, hand-drawn elements | Wellness, sustainability, lifestyle |
| Dark Mode Native | Deep backgrounds, glowing accents, depth layers | Dev tools, creative software, night apps |
Commit fully. Mixed aesthetics create confusion. If brutalist, be brutalist everywhere.
Phase 3: Execute with Excellence
Typography
Never use generic fonts. Avoid Arial, Inter, Roboto, Open Sans for primary typography.
Distinctive alternatives by category:
| Category | Options |
|---|---|
| Display/Headlines | Clash Display, Cabinet Grotesk, Satoshi, Space Grotesk, Syne |
| Serif/Editorial | Playfair Display, Fraunces, Newsreader, Lora, Merriweather |
| Mono/Technical | JetBrains Mono, Berkeley Mono, Fira Code, IBM Plex Mono |
| Humanist/Warm | Nunito, Quicksand, Poppins (sparingly), DM Sans |
Typography rules:
- Establish clear hierarchy (3-4 distinct levels max)
- Use generous line-height (1.5-1.7 for body)
- Letter-spacing adjustments for large text (-0.02em to -0.05em)
- Responsive sizing with clamp()
/* Example type scale */
--font-display: 'Clash Display', sans-serif;
--font-body: 'Satoshi', sans-serif;
--font-mono: 'JetBrains Mono', monospace;
--text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
--text-sm: clamp(0.875rem, 0.8rem + 0.375vw, 1rem);
--text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--text-lg: clamp(1.25rem, 1.1rem + 0.75vw, 1.5rem);
--text-xl: clamp(1.5rem, 1.2rem + 1.5vw, 2.25rem);
--text-2xl: clamp(2rem, 1.5rem + 2.5vw, 3.5rem);
--text-3xl: clamp(2.5rem, 1.75rem + 3.75vw, 5rem);Color
Dominant colors with sharp accents outperform timid, evenly-distributed palettes.
Color principles:
- Define a cohesive system using CSS custom properties
- One dominant background, one primary accent, limited secondary colors
- Ensure sufficient contrast (WCAG AA minimum)
- Dark mode should be designed separately, not just inverted
/* Example color system - Dark mode native */
:root {
--bg-primary: hsl(225 15% 8%);
--bg-secondary: hsl(225 15% 12%);
--bg-tertiary: hsl(225 15% 16%);
--text-primary: hsl(0 0% 98%);
--text-secondary: hsl(225 10% 65%);
--text-tertiary: hsl(225 10% 45%);
--accent-primary: hsl(265 90% 65%);
--accent-primary-hover: hsl(265 90% 72%);
--accent-secondary: hsl(180 70% 50%);
--border-subtle: hsl(225 15% 20%);
--border-strong: hsl(225 15% 30%);
--glow-primary: hsl(265 90% 65% / 0.3);
}Avoid clichés:
- Purple-to-blue gradients on white (overused)
- Rainbow gradients (unless intentional)
- Flat gray on white (boring)
- Neon on dark without purpose
Motion & Animation
One well-orchestrated page load with staggered reveals creates more delight than scattered micro-interactions.
Animation principles:
- Purpose over decoration
- Consistent timing functions across the interface
- Stagger related elements (50-100ms delays)
- Respect prefers-reduced-motion
/* Example animation system */
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
--ease-in-out-quart: cubic-bezier(0.76, 0, 0.24, 1);
--duration-fast: 150ms;
--duration-normal: 250ms;
--duration-slow: 400ms;
--duration-slower: 600ms;
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-in {
animation: fadeInUp var(--duration-slow) var(--ease-out-expo) forwards;
}
/* Stagger children */
.stagger-children > * {
opacity: 0;
animation: fadeInUp var(--duration-slow) var(--ease-out-expo) forwards;
}
.stagger-children > *:nth-child(1) { animation-delay: 0ms; }
.stagger-children > *:nth-child(2) { animation-delay: 75ms; }
.stagger-children > *:nth-child(3) { animation-delay: 150ms; }
.stagger-children > *:nth-child(4) { animation-delay: 225ms; }Backgrounds & Depth
Move beyond solid colors. Create atmosphere and depth:
- Layered gradients (subtle, not garish)
- Geometric patterns (SVG, CSS)
- Grain/noise textures for warmth
- Glassmorphism with restraint
- Mesh gradients for modern feel
/* Subtle gradient background */
.bg-gradient {
background:
radial-gradient(ellipse at top right, var(--accent-primary) / 0.1, transparent 50%),
radial-gradient(ellipse at bottom left, var(--accent-secondary) / 0.08, transparent 50%),
var(--bg-primary);
}
/* Noise texture overlay */
.bg-noise::before {
content: '';
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%' height='100%' filter='url(%23noise)'/%3E%3C/svg%3E");
opacity: 0.03;
pointer-events: none;
}Layout & Spacing
Unexpected compositions create memorability.
- Asymmetric layouts where appropriate
- Generous whitespace (don't fear emptiness)
- Consistent spacing scale
- Break the grid intentionally, not accidentally
/* Spacing scale */
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-5: 1.5rem;
--space-6: 2rem;
--space-8: 3rem;
--space-10: 4rem;
--space-12: 6rem;
--space-16: 8rem;
--space-20: 10rem;Anti-Patterns: What to Avoid
"AI Slop" Indicators
These scream "generated by AI" — avoid them:
1. Generic Typography
- Inter as the only font
- Roboto for everything
- No hierarchy differentiation
2. Clichéd Colors
- Purple-blue gradients on white backgrounds
- The exact same "startup blue" (#3B82F6)
- Desaturated pastels without purpose
3. Cookie-Cutter Layouts
- Identical card grids
- Predictable hero → features → CTA
- No spatial tension or interest
4. Meaningless Decoration
- Gradients on everything
- Shadows without purpose
- Animations that don't aid comprehension
5. Lack of Character
- No personality in copy or visuals
- Generic stock photo aesthetic
- Safe, forgettable choices
Adapting to Existing Designs
When joining an existing project:
Step 1: Audit Current State
# Find styling files
find . -name "*.css" -o -name "*.scss" -o -name "*.tailwind.config.*" | head -20
# Check for design tokens
grep -r "var(--" src/ --include="*.css" | head -10
# Find component library
grep -E "shadcn|radix|chakra|mui|antd" package.jsonStep 2: Document Existing Patterns
Create mental map of:
- Primary/secondary colors in use
- Font families and sizes
- Spacing patterns
- Component styles
- Animation approaches
Step 3: Enhance, Don't Replace
- Strengthen existing aesthetic direction
- Fill gaps in the design system
- Add polish to rough edges
- Maintain consistency with improvements
Step 4: Polish Techniques
Quick wins for improving existing designs:
/* Better focus states */
:focus-visible {
outline: 2px solid var(--accent-primary);
outline-offset: 2px;
}
/* Smoother transitions */
* {
transition-property: color, background-color, border-color, opacity, transform;
transition-duration: 150ms;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
/* Better shadows */
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--shadow-glow: 0 0 20px var(--glow-primary);Project Configuration
Check for .claude/design-config.json to understand project-specific preferences:
{
"aesthetic": "minimalist",
"primaryFont": "Satoshi",
"accentColor": "#6366f1",
"darkMode": true,
"animationLevel": "subtle",
"designReferences": [
"linear.app",
"vercel.com"
],
"avoidPatterns": [
"gradients",
"rounded corners > 8px"
]
}Output Standards
All frontend code must:
1. Be production-ready — No placeholders or TODOs 2. Be accessible — WCAG AA compliance minimum 3. Be responsive — Mobile-first approach 4. Be performant — No layout shifts, optimized animations 5. Be distinctive — Identifiable aesthetic direction 6. Respect preferences — Honor prefers-reduced-motion, prefers-color-scheme
Documentation References
- @.claude/skills/claudenv/frontend-design/references/design-principles.md
- @.claude/skills/claudenv/frontend-design/references/tailwind-patterns.md
- @.claude/skills/claudenv/frontend-design/references/animation-library.md
Delegation
Hand off to other skills when:
- Backend logic needed → appropriate backend skill
- Complex state management → framework-specific skill
- Accessibility audit → if accessibility skill exists
Animation Library
Production-ready animation patterns for modern interfaces.
Core Principles
1. Purpose over decoration — Every animation should aid comprehension or provide feedback 2. Consistent timing — Use the same easing and duration patterns throughout 3. Performance first — Only animate transform and opacity (GPU accelerated) 4. Respect preferences — Honor prefers-reduced-motion
---
Timing Functions
Easing Curves
/* Standard curves */
--ease-linear: linear;
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
/* Expressive curves */
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
--ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1);
--ease-in-out-quart: cubic-bezier(0.76, 0, 0.24, 1);
/* Spring-like */
--ease-spring: cubic-bezier(0.68, -0.55, 0.265, 1.55);
--ease-bounce: cubic-bezier(0.68, -0.6, 0.32, 1.6);Duration Scale
| Category | Duration | Use Case |
|---|---|---|
| Instant | 0ms | State changes (no animation) |
| Fast | 100-150ms | Micro-interactions, hovers, toggles |
| Normal | 200-300ms | Standard transitions, modals |
| Slow | 400-500ms | Page transitions, emphasis |
| Slower | 600-800ms | Complex sequences, hero animations |
--duration-instant: 0ms;
--duration-fast: 150ms;
--duration-normal: 250ms;
--duration-slow: 400ms;
--duration-slower: 600ms;---
Entrance Animations
Fade In
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.animate-fade-in {
animation: fadeIn var(--duration-normal) var(--ease-out) forwards;
}Fade In Up
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fade-in-up {
animation: fadeInUp var(--duration-slow) var(--ease-out-expo) forwards;
}Fade In Down
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fade-in-down {
animation: fadeInDown var(--duration-slow) var(--ease-out-expo) forwards;
}Slide In (Directional)
@keyframes slideInLeft {
from {
opacity: 0;
transform: translateX(-30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideInRight {
from {
opacity: 0;
transform: translateX(30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.animate-slide-in-left {
animation: slideInLeft var(--duration-slow) var(--ease-out-expo) forwards;
}
.animate-slide-in-right {
animation: slideInRight var(--duration-slow) var(--ease-out-expo) forwards;
}Scale In
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
.animate-scale-in {
animation: scaleIn var(--duration-normal) var(--ease-out-back) forwards;
}Bounce In
@keyframes bounceIn {
0% {
opacity: 0;
transform: scale(0.3);
}
50% {
transform: scale(1.05);
}
70% {
transform: scale(0.9);
}
100% {
opacity: 1;
transform: scale(1);
}
}
.animate-bounce-in {
animation: bounceIn var(--duration-slower) var(--ease-spring) forwards;
}---
Exit Animations
Fade Out
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
.animate-fade-out {
animation: fadeOut var(--duration-fast) var(--ease-in) forwards;
}Fade Out Down
@keyframes fadeOutDown {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(20px);
}
}
.animate-fade-out-down {
animation: fadeOutDown var(--duration-normal) var(--ease-in) forwards;
}Scale Out
@keyframes scaleOut {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.9);
}
}
.animate-scale-out {
animation: scaleOut var(--duration-fast) var(--ease-in) forwards;
}---
Stagger System
CSS Stagger Pattern
/* Parent applies stagger to children */
.stagger-children > * {
opacity: 0;
animation: fadeInUp var(--duration-slow) var(--ease-out-expo) forwards;
}
.stagger-children > *:nth-child(1) { animation-delay: 0ms; }
.stagger-children > *:nth-child(2) { animation-delay: 75ms; }
.stagger-children > *:nth-child(3) { animation-delay: 150ms; }
.stagger-children > *:nth-child(4) { animation-delay: 225ms; }
.stagger-children > *:nth-child(5) { animation-delay: 300ms; }
.stagger-children > *:nth-child(6) { animation-delay: 375ms; }
.stagger-children > *:nth-child(7) { animation-delay: 450ms; }
.stagger-children > *:nth-child(8) { animation-delay: 525ms; }
/* Utility classes for manual control */
.delay-0 { animation-delay: 0ms; }
.delay-75 { animation-delay: 75ms; }
.delay-150 { animation-delay: 150ms; }
.delay-225 { animation-delay: 225ms; }
.delay-300 { animation-delay: 300ms; }
.delay-400 { animation-delay: 400ms; }
.delay-500 { animation-delay: 500ms; }Tailwind Stagger
<div class="space-y-4">
<div class="animate-fade-in-up">Item 1</div>
<div class="animate-fade-in-up opacity-0 [animation-delay:75ms]">Item 2</div>
<div class="animate-fade-in-up opacity-0 [animation-delay:150ms]">Item 3</div>
<div class="animate-fade-in-up opacity-0 [animation-delay:225ms]">Item 4</div>
</div>---
Continuous Animations
Pulse
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.animate-pulse {
animation: pulse 2s var(--ease-in-out) infinite;
}Pulse Glow
@keyframes pulseGlow {
0%, 100% {
box-shadow: 0 0 20px var(--glow-primary);
}
50% {
box-shadow: 0 0 40px var(--glow-primary), 0 0 60px var(--glow-primary);
}
}
.animate-pulse-glow {
animation: pulseGlow 2s var(--ease-in-out) infinite;
}Float
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
.animate-float {
animation: float 3s var(--ease-in-out) infinite;
}Spin
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.animate-spin {
animation: spin 1s linear infinite;
}
.animate-spin-slow {
animation: spin 3s linear infinite;
}Shimmer (Loading)
@keyframes shimmer {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
.animate-shimmer {
background: linear-gradient(
90deg,
var(--bg-secondary) 25%,
var(--bg-tertiary) 50%,
var(--bg-secondary) 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}---
Interactive Animations
Hover Lift
.hover-lift {
transition: transform var(--duration-fast) var(--ease-out);
}
.hover-lift:hover {
transform: translateY(-4px);
}Hover Scale
.hover-scale {
transition: transform var(--duration-fast) var(--ease-out);
}
.hover-scale:hover {
transform: scale(1.02);
}Hover Glow
.hover-glow {
transition: box-shadow var(--duration-normal) var(--ease-out);
}
.hover-glow:hover {
box-shadow: 0 0 30px var(--glow-primary);
}Press Effect
.press-effect {
transition: transform var(--duration-fast) var(--ease-out);
}
.press-effect:hover {
transform: translateY(-2px);
}
.press-effect:active {
transform: translateY(0);
}Magnetic Hover (Advanced)
/* Requires JavaScript for full effect */
.magnetic {
transition: transform var(--duration-fast) var(--ease-out);
}
/* JS applies transform based on cursor position */---
Page Transitions
Fade Transition
.page-enter {
opacity: 0;
}
.page-enter-active {
opacity: 1;
transition: opacity var(--duration-slow) var(--ease-out);
}
.page-exit {
opacity: 1;
}
.page-exit-active {
opacity: 0;
transition: opacity var(--duration-fast) var(--ease-in);
}Slide Transition
.page-enter {
opacity: 0;
transform: translateX(20px);
}
.page-enter-active {
opacity: 1;
transform: translateX(0);
transition: all var(--duration-slow) var(--ease-out-expo);
}
.page-exit {
opacity: 1;
transform: translateX(0);
}
.page-exit-active {
opacity: 0;
transform: translateX(-20px);
transition: all var(--duration-normal) var(--ease-in);
}---
Scroll Animations
Reveal on Scroll
.scroll-reveal {
opacity: 0;
transform: translateY(40px);
transition: all var(--duration-slower) var(--ease-out-expo);
}
.scroll-reveal.is-visible {
opacity: 1;
transform: translateY(0);
}Parallax Layer
.parallax-slow {
transform: translateY(calc(var(--scroll-y) * 0.3));
}
.parallax-medium {
transform: translateY(calc(var(--scroll-y) * 0.5));
}
.parallax-fast {
transform: translateY(calc(var(--scroll-y) * 0.7));
}---
Accessibility
Reduced Motion
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}Safe Animations (Alternative)
/* Provide simpler alternatives for reduced motion */
@media (prefers-reduced-motion: reduce) {
.animate-fade-in-up,
.animate-slide-in-left,
.animate-bounce-in {
animation: fadeIn var(--duration-fast) var(--ease-out) forwards;
}
}---
Framework Integration
Tailwind Config
// tailwind.config.js
module.exports = {
theme: {
extend: {
animation: {
'fade-in': 'fadeIn 0.5s ease-out forwards',
'fade-in-up': 'fadeInUp 0.5s ease-out forwards',
'fade-in-down': 'fadeInDown 0.5s ease-out forwards',
'slide-in-left': 'slideInLeft 0.4s ease-out forwards',
'slide-in-right': 'slideInRight 0.4s ease-out forwards',
'scale-in': 'scaleIn 0.3s ease-out forwards',
'bounce-in': 'bounceIn 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards',
'pulse-glow': 'pulseGlow 2s ease-in-out infinite',
'float': 'float 3s ease-in-out infinite',
'shimmer': 'shimmer 1.5s infinite',
},
keyframes: {
fadeIn: { /* ... */ },
fadeInUp: { /* ... */ },
// ... all keyframes
},
},
},
}React/Framer Motion
// Common animation variants
export const fadeInUp = {
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -10 },
transition: { duration: 0.4, ease: [0.16, 1, 0.3, 1] }
};
export const staggerContainer = {
animate: {
transition: {
staggerChildren: 0.075
}
}
};
export const scaleIn = {
initial: { opacity: 0, scale: 0.9 },
animate: { opacity: 1, scale: 1 },
transition: { duration: 0.3, ease: [0.34, 1.56, 0.64, 1] }
};Vue Transitions
<template>
<Transition name="fade-up">
<div v-if="show">Content</div>
</Transition>
</template>
<style>
.fade-up-enter-active {
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.fade-up-leave-active {
transition: all 0.2s ease-in;
}
.fade-up-enter-from {
opacity: 0;
transform: translateY(20px);
}
.fade-up-leave-to {
opacity: 0;
transform: translateY(-10px);
}
</style>Design Principles Reference
Deep knowledge base for the frontend-design skill.
The Hierarchy of Design Decisions
1. Concept (Most Important)
What story is this interface telling? What emotion should users feel?
2. Layout
How is space organized? Where does the eye travel?
3. Typography
How does text communicate hierarchy and personality?
4. Color
How do colors reinforce the concept and guide attention?
5. Details (Least Important, But Memorable)
Shadows, borders, animations, micro-interactions
Work top-down. A beautiful button cannot save a confused layout.
---
Typography Deep Dive
Font Pairing Strategies
Contrast Pairing (Most common, safest)
- Serif headlines + Sans body
- Display font + Neutral body
- Example: Playfair Display + Source Sans Pro
Superfamily Pairing
- Same family, different weights/styles
- Example: Inter Display + Inter
- Guarantees harmony
Mood Pairing
- Match emotional register
- Both fonts feel technical, or both feel warm
- Example: Space Grotesk + JetBrains Mono (technical)
Typography Scale Systems
Modular Scale (1.25 ratio)
12px → 15px → 19px → 24px → 30px → 37px → 47px → 59pxFluid Typography
/* Base: 16px at 320px, 20px at 1200px */
font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);Line Height Guide
| Text Size | Line Height |
|---|---|
| < 16px | 1.6 - 1.7 |
| 16-20px | 1.5 - 1.6 |
| 20-32px | 1.3 - 1.5 |
| 32-48px | 1.2 - 1.3 |
| > 48px | 1.0 - 1.2 |
---
Color Theory in Practice
Building a Palette
60-30-10 Rule
- 60% Dominant (backgrounds, large areas)
- 30% Secondary (cards, sections)
- 10% Accent (CTAs, highlights)
Semantic Colors
/* Success/Error/Warning/Info */
--success: hsl(142 70% 45%);
--error: hsl(0 84% 60%);
--warning: hsl(38 92% 50%);
--info: hsl(200 98% 48%);Dark Mode Principles
1. Don't invert — Design fresh for dark 2. Reduce contrast — Pure white (#fff) on pure black (#000) strains eyes 3. Desaturate slightly — Bright colors feel harsh on dark 4. Add depth with subtle gradients — Prevents flat feeling 5. Glow effects work — Neon/glow is appropriate in dark mode
/* Dark mode color adjustments */
.dark {
--text-primary: hsl(0 0% 93%); /* Not pure white */
--bg-primary: hsl(225 20% 8%); /* Not pure black */
--accent-primary: hsl(265 80% 68%); /* Slightly desaturated */
}Color Accessibility
| Contrast Ratio | Use Case |
|---|---|
| 4.5:1 | Normal text (WCAG AA) |
| 3:1 | Large text, UI components |
| 7:1 | Normal text (WCAG AAA) |
---
Layout Patterns
The Bento Grid
Asymmetric grid with varied cell sizes. Modern, interesting.
.bento {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 200px);
gap: 1rem;
}
.bento-large { grid-column: span 2; grid-row: span 2; }
.bento-wide { grid-column: span 2; }
.bento-tall { grid-row: span 2; }Broken Grid
Elements that break the grid create visual tension.
.break-grid {
margin-left: -2rem;
width: calc(100% + 4rem);
}Overlap Compositions
Layered elements create depth.
.overlap-container {
display: grid;
grid-template-columns: 1fr;
}
.overlap-container > * {
grid-column: 1;
grid-row: 1;
}---
Animation Principles
The 12 Principles (Adapted for UI)
1. Timing — Fast for UI (150-300ms), slower for emphasis 2. Easing — Never linear; ease-out for entrances, ease-in for exits 3. Anticipation — Slight pull-back before forward motion 4. Staging — Guide the eye to what matters 5. Follow-through — Elements settle, don't just stop
Animation Categories
Micro-interactions (100-200ms)
- Button hover states
- Toggle switches
- Icon morphs
Transitions (200-400ms)
- Page transitions
- Modal open/close
- Drawer slides
Emphasis (400-800ms)
- Hero animations
- Success celebrations
- Onboarding sequences
Performance Rules
1. Only animate transform and opacity — GPU accelerated 2. Use will-change sparingly — Only on elements about to animate 3. Respect prefers-reduced-motion
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}---
Component Design Patterns
Cards
The Perfect Card:
.card {
background: var(--bg-secondary);
border: 1px solid var(--border-subtle);
border-radius: 12px;
padding: 1.5rem;
transition: all 200ms ease;
}
.card:hover {
border-color: var(--border-strong);
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}Buttons
Button Hierarchy: 1. Primary — Main action, filled 2. Secondary — Alternative action, outlined 3. Ghost — Tertiary, minimal styling 4. Destructive — Dangerous actions, red
.btn-primary {
background: var(--accent-primary);
color: white;
padding: 0.75rem 1.5rem;
border-radius: 8px;
font-weight: 500;
transition: all 150ms ease;
}
.btn-primary:hover {
background: var(--accent-primary-hover);
transform: translateY(-1px);
}
.btn-primary:active {
transform: translateY(0);
}Forms
Input Excellence:
.input {
width: 100%;
padding: 0.75rem 1rem;
background: var(--bg-tertiary);
border: 1px solid var(--border-subtle);
border-radius: 8px;
color: var(--text-primary);
transition: all 150ms ease;
}
.input:hover {
border-color: var(--border-strong);
}
.input:focus {
outline: none;
border-color: var(--accent-primary);
box-shadow: 0 0 0 3px var(--glow-primary);
}
.input::placeholder {
color: var(--text-tertiary);
}---
Responsive Design
Breakpoint Strategy
/* Mobile-first breakpoints */
--bp-sm: 640px; /* Large phones */
--bp-md: 768px; /* Tablets */
--bp-lg: 1024px; /* Laptops */
--bp-xl: 1280px; /* Desktops */
--bp-2xl: 1536px; /* Large monitors */Container Queries (Modern)
.card-container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
flex-direction: row;
}
}---
Design System Tokens
Complete Token Set
:root {
/* Colors */
--color-gray-50: hsl(220 20% 98%);
--color-gray-100: hsl(220 17% 93%);
--color-gray-200: hsl(220 15% 85%);
--color-gray-300: hsl(220 13% 70%);
--color-gray-400: hsl(220 11% 55%);
--color-gray-500: hsl(220 9% 45%);
--color-gray-600: hsl(220 11% 35%);
--color-gray-700: hsl(220 13% 25%);
--color-gray-800: hsl(220 15% 16%);
--color-gray-900: hsl(220 17% 10%);
--color-gray-950: hsl(220 20% 6%);
/* Spacing */
--space-px: 1px;
--space-0: 0;
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-5: 1.25rem;
--space-6: 1.5rem;
--space-8: 2rem;
--space-10: 2.5rem;
--space-12: 3rem;
--space-16: 4rem;
--space-20: 5rem;
--space-24: 6rem;
/* Border Radius */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
--radius-2xl: 24px;
--radius-full: 9999px;
/* Shadows */
--shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
/* Transitions */
--transition-fast: 150ms ease;
--transition-normal: 250ms ease;
--transition-slow: 400ms ease;
/* Z-index */
--z-dropdown: 100;
--z-sticky: 200;
--z-modal: 300;
--z-popover: 400;
--z-toast: 500;
}Tailwind CSS Patterns
Modern, distinctive patterns for Tailwind CSS projects.
Custom Configuration
Extend, Don't Override
// tailwind.config.js
module.exports = {
theme: {
extend: {
// Custom fonts
fontFamily: {
display: ['Clash Display', 'sans-serif'],
body: ['Satoshi', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
},
// Custom colors (HSL for flexibility)
colors: {
brand: {
50: 'hsl(265 100% 98%)',
100: 'hsl(265 95% 94%)',
200: 'hsl(265 90% 85%)',
300: 'hsl(265 85% 74%)',
400: 'hsl(265 80% 64%)',
500: 'hsl(265 75% 54%)',
600: 'hsl(265 70% 45%)',
700: 'hsl(265 65% 36%)',
800: 'hsl(265 60% 28%)',
900: 'hsl(265 55% 20%)',
950: 'hsl(265 50% 12%)',
},
},
// Custom animations
animation: {
'fade-in': 'fadeIn 0.5s ease-out forwards',
'fade-in-up': 'fadeInUp 0.5s ease-out forwards',
'fade-in-down': 'fadeInDown 0.5s ease-out forwards',
'scale-in': 'scaleIn 0.3s ease-out forwards',
'slide-in-right': 'slideInRight 0.4s ease-out forwards',
'slide-in-left': 'slideInLeft 0.4s ease-out forwards',
'bounce-in': 'bounceIn 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards',
'spin-slow': 'spin 3s linear infinite',
'pulse-glow': 'pulseGlow 2s ease-in-out infinite',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
fadeInUp: {
'0%': { opacity: '0', transform: 'translateY(20px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
fadeInDown: {
'0%': { opacity: '0', transform: 'translateY(-20px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
scaleIn: {
'0%': { opacity: '0', transform: 'scale(0.9)' },
'100%': { opacity: '1', transform: 'scale(1)' },
},
slideInRight: {
'0%': { opacity: '0', transform: 'translateX(20px)' },
'100%': { opacity: '1', transform: 'translateX(0)' },
},
slideInLeft: {
'0%': { opacity: '0', transform: 'translateX(-20px)' },
'100%': { opacity: '1', transform: 'translateX(0)' },
},
bounceIn: {
'0%': { opacity: '0', transform: 'scale(0.3)' },
'50%': { transform: 'scale(1.05)' },
'70%': { transform: 'scale(0.9)' },
'100%': { opacity: '1', transform: 'scale(1)' },
},
pulseGlow: {
'0%, 100%': { boxShadow: '0 0 20px hsl(265 75% 54% / 0.3)' },
'50%': { boxShadow: '0 0 40px hsl(265 75% 54% / 0.6)' },
},
},
// Custom spacing
spacing: {
'18': '4.5rem',
'22': '5.5rem',
'128': '32rem',
'144': '36rem',
},
// Custom backdrop blur
backdropBlur: {
xs: '2px',
},
// Animation delays
transitionDelay: {
'0': '0ms',
'75': '75ms',
'100': '100ms',
'150': '150ms',
'200': '200ms',
'300': '300ms',
'400': '400ms',
'500': '500ms',
},
},
},
plugins: [],
}---
Component Patterns
Distinctive Buttons
<!-- Primary with glow -->
<button class="
px-6 py-3
bg-brand-500 hover:bg-brand-400
text-white font-medium
rounded-lg
shadow-lg shadow-brand-500/25
hover:shadow-xl hover:shadow-brand-500/30
transform hover:-translate-y-0.5
transition-all duration-200
focus:outline-none focus:ring-2 focus:ring-brand-400 focus:ring-offset-2
">
Get Started
</button>
<!-- Ghost button -->
<button class="
px-6 py-3
bg-transparent
text-gray-300 hover:text-white
border border-gray-700 hover:border-gray-500
rounded-lg
transition-all duration-200
focus:outline-none focus:ring-2 focus:ring-gray-500
">
Learn More
</button>
<!-- Gradient button -->
<button class="
px-6 py-3
bg-gradient-to-r from-brand-500 to-purple-500
hover:from-brand-400 hover:to-purple-400
text-white font-medium
rounded-lg
shadow-lg
transform hover:scale-[1.02]
transition-all duration-200
">
Try Now
</button>Modern Cards
<!-- Glass card -->
<div class="
p-6
bg-white/5 backdrop-blur-xl
border border-white/10
rounded-2xl
hover:bg-white/10 hover:border-white/20
transition-all duration-300
">
<h3 class="text-xl font-semibold text-white">Card Title</h3>
<p class="mt-2 text-gray-400">Card description goes here.</p>
</div>
<!-- Elevated card with hover -->
<div class="
p-6
bg-gray-900
border border-gray-800
rounded-xl
shadow-lg
hover:shadow-2xl hover:shadow-brand-500/10
hover:border-gray-700
transform hover:-translate-y-1
transition-all duration-300
">
<h3 class="text-xl font-semibold text-white">Card Title</h3>
<p class="mt-2 text-gray-400">Card description goes here.</p>
</div>
<!-- Bento card -->
<div class="
relative overflow-hidden
p-8
bg-gradient-to-br from-gray-900 to-gray-800
border border-gray-700
rounded-3xl
group
">
<!-- Gradient orb -->
<div class="
absolute -top-24 -right-24
w-48 h-48
bg-brand-500/30
rounded-full
blur-3xl
group-hover:bg-brand-500/40
transition-colors duration-500
"></div>
<div class="relative z-10">
<h3 class="text-2xl font-bold text-white">Feature</h3>
<p class="mt-4 text-gray-400">Description text.</p>
</div>
</div>Inputs & Forms
<!-- Modern input -->
<div class="relative">
<input
type="text"
placeholder="Enter your email"
class="
w-full
px-4 py-3
bg-gray-900
border border-gray-700
rounded-lg
text-white placeholder:text-gray-500
focus:outline-none focus:border-brand-500 focus:ring-2 focus:ring-brand-500/20
transition-all duration-200
"
/>
</div>
<!-- Floating label input -->
<div class="relative">
<input
type="text"
id="email"
placeholder=" "
class="
peer
w-full
px-4 pt-6 pb-2
bg-gray-900
border border-gray-700
rounded-lg
text-white
focus:outline-none focus:border-brand-500
transition-all duration-200
"
/>
<label
for="email"
class="
absolute left-4 top-4
text-gray-500
transition-all duration-200
peer-placeholder-shown:top-4 peer-placeholder-shown:text-base
peer-focus:top-2 peer-focus:text-xs peer-focus:text-brand-400
peer-[:not(:placeholder-shown)]:top-2 peer-[:not(:placeholder-shown)]:text-xs
"
>
Email address
</label>
</div>Navigation
<!-- Glassmorphism navbar -->
<nav class="
fixed top-0 inset-x-0
px-6 py-4
bg-gray-950/80 backdrop-blur-xl
border-b border-white/5
z-50
">
<div class="max-w-7xl mx-auto flex items-center justify-between">
<a href="/" class="text-xl font-bold text-white">Logo</a>
<div class="flex items-center gap-8">
<a href="#" class="text-gray-400 hover:text-white transition-colors">Features</a>
<a href="#" class="text-gray-400 hover:text-white transition-colors">Pricing</a>
<a href="#" class="text-gray-400 hover:text-white transition-colors">Docs</a>
</div>
<button class="
px-4 py-2
bg-brand-500 hover:bg-brand-400
text-white text-sm font-medium
rounded-lg
transition-colors
">
Sign In
</button>
</div>
</nav>---
Layout Patterns
Hero Section
<section class="relative min-h-screen flex items-center overflow-hidden">
<!-- Background gradient -->
<div class="absolute inset-0 bg-gray-950">
<div class="absolute top-0 left-1/4 w-96 h-96 bg-brand-500/20 rounded-full blur-3xl"></div>
<div class="absolute bottom-0 right-1/4 w-96 h-96 bg-purple-500/20 rounded-full blur-3xl"></div>
</div>
<!-- Grid pattern overlay -->
<div class="absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.02)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.02)_1px,transparent_1px)] bg-[size:64px_64px]"></div>
<div class="relative z-10 max-w-7xl mx-auto px-6 py-24 text-center">
<h1 class="text-5xl md:text-7xl font-bold text-white tracking-tight">
Build something
<span class="text-transparent bg-clip-text bg-gradient-to-r from-brand-400 to-purple-400">
remarkable
</span>
</h1>
<p class="mt-6 text-xl text-gray-400 max-w-2xl mx-auto">
Description text that explains the value proposition clearly and concisely.
</p>
<div class="mt-10 flex flex-col sm:flex-row gap-4 justify-center">
<button class="px-8 py-4 bg-brand-500 hover:bg-brand-400 text-white font-medium rounded-lg transition-colors">
Get Started Free
</button>
<button class="px-8 py-4 bg-white/5 hover:bg-white/10 text-white font-medium rounded-lg border border-white/10 transition-colors">
View Demo
</button>
</div>
</div>
</section>Bento Grid
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 p-4">
<!-- Large feature -->
<div class="col-span-2 row-span-2 p-8 bg-gray-900 rounded-3xl border border-gray-800">
<h3 class="text-2xl font-bold text-white">Main Feature</h3>
</div>
<!-- Small cards -->
<div class="p-6 bg-gray-900 rounded-2xl border border-gray-800">
<h4 class="font-semibold text-white">Feature 1</h4>
</div>
<div class="p-6 bg-gray-900 rounded-2xl border border-gray-800">
<h4 class="font-semibold text-white">Feature 2</h4>
</div>
<!-- Wide card -->
<div class="col-span-2 p-6 bg-gray-900 rounded-2xl border border-gray-800">
<h4 class="font-semibold text-white">Wide Feature</h4>
</div>
</div>---
Animation Utilities
Staggered Children
<div class="space-y-4">
<div class="animate-fade-in-up [animation-delay:0ms]">Item 1</div>
<div class="animate-fade-in-up [animation-delay:100ms] opacity-0">Item 2</div>
<div class="animate-fade-in-up [animation-delay:200ms] opacity-0">Item 3</div>
<div class="animate-fade-in-up [animation-delay:300ms] opacity-0">Item 4</div>
</div>Hover Reveals
<div class="group relative overflow-hidden rounded-xl">
<img src="..." class="w-full transition-transform duration-500 group-hover:scale-110" />
<div class="
absolute inset-0
bg-gradient-to-t from-black/80 to-transparent
opacity-0 group-hover:opacity-100
transition-opacity duration-300
flex items-end p-6
">
<h3 class="text-white font-bold translate-y-4 group-hover:translate-y-0 transition-transform duration-300">
Title
</h3>
</div>
</div>---
Utility Classes to Add
@layer utilities {
/* Text gradient */
.text-gradient {
@apply text-transparent bg-clip-text bg-gradient-to-r from-brand-400 to-purple-400;
}
/* Glow effect */
.glow {
box-shadow: 0 0 20px theme('colors.brand.500 / 0.3');
}
.glow-lg {
box-shadow: 0 0 40px theme('colors.brand.500 / 0.4');
}
/* Hide scrollbar */
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
/* Noise texture */
.bg-noise {
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%' height='100%' filter='url(%23noise)'/%3E%3C/svg%3E");
}
}