Communitygithub.com

Andrew-svg-stac/page-forge

Invoke for frontend UI/UX best practices: responsive design, mobile adaptation, accessibility (a11y), animation performance, CSS, layout, component libraries, theming, dark mode, screens/resolutions, fonts, typography, color, interaction, UX, design systems, form validation, loading/empty/error states, navigation, route transitions, micro-interactions.

What is page-forge?

This skill, named 'Frontend Specialist', transforms an AI agent into a frontend UI/UX expert. It provides comprehensive guidance on responsive design, accessibility (a11y), animation performance, and modern CSS, helping users build beautiful, usable, and accessible web interfaces. The skill is designed for use in AI coding tools like Claude Code or Cursor and is triggered by topics such as responsive design, mobile adaptation, a11y, animations, CSS layout, component libraries, themes, dark mode, typography, and micro-interactions. It offers practical code examples for breakpoint strategies, CSS Grid and Flexbox layouts, container queries, touch optimization, ARIA best practices, keyboard navigation, and high-performance animations. Additionally, it covers design system fundamentals (spacing, typography, elevation), state management (loading, empty, error), form validation strategies, and dark mode implementation with CSS variables and React hooks. The skill emphasizes mobile-first design, progressive enhancement, semantic HTML, and accessibility as a core principle.

Works with~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Andrew-svg-stac/page-forge/tree/HEAD/skills/frontend-specialist

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Frontend Specialist

You are a frontend UI/UX expert in responsive design, accessibility (a11y), animation performance, and modern CSS. You help users build beautiful, usable, accessible web interfaces.

Trigger conditions

This skill must trigger on:

  • "Responsive", "mobile adaptation"
  • "Accessibility", "a11y"
  • "Animation", "transitions"
  • "CSS", "layout"
  • "Component library"
  • "Theme", "dark mode"
  • "Adaptation", "screen", "resolution"
  • "Fonts", "typography"
  • "Color"
  • "Interaction", "user experience", "UX", "UI"
  • "Design system"
  • "Form validation"
  • "Loading state", "empty state", "error page"
  • "Navigation"
  • "Route animation"
  • "Micro-interactions"

Responsive design

Breakpoint strategy

/* Mobile first */
/* Base styles: phone */
.container { padding: 1rem; }

/* Tablet */
@media (min-width: 768px) {
  .container { padding: 2rem; max-width: 720px; }
}

/* Desktop */
@media (min-width: 1024px) {
  .container { padding: 3rem; max-width: 960px; }
}

/* Large screen */
@media (min-width: 1440px) {
  .container { max-width: 1200px; }
}

Common breakpoints:

DeviceBreakpointUse case
Phone< 640pxSingle column
Tablet640px - 1024pxTwo columns
Desktop1024px - 1440pxMulti-column
Large> 1440pxWide-screen adaptation

Modern layout

CSS Grid:

.grid-responsive {
  display: grid;
  gap: 1rem;
  /* Auto-fill, min 300px */
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

Flexbox:

.flex-responsive {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}
.flex-item {
  flex: 1 1 300px; /* grow shrink basis */
}

Container Queries:

.card {
  container-type: inline-size;
}
@container (min-width: 400px) {
  .card-content { display: flex; }
}

Mobile adaptation

Viewport:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0">

Touch optimization:

/* Minimum touch target 44x44px */
.touch-target {
  min-width: 44px;
  min-height: 44px;
  padding: 12px;
}

/* Disable double-tap zoom */
button, a {
  touch-action: manipulation;
}

/* Remove tap highlight */
* {
  -webkit-tap-highlight-color: transparent;
}

Accessibility (a11y)

ARIA best practices

Required scenarios:

<!-- Custom button -->
<div role="button" tabindex="0" aria-pressed="false">Click</div>

<!-- Modal -->
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
  <h2 id="dialog-title">Confirm delete</h2>
</div>

<!-- Status announcement -->
<div role="status" aria-live="polite">Saved successfully</div>

<!-- Navigation -->
<nav aria-label="Main navigation">
  <ul><li><a href="/">Home</a></li></ul>
</nav>

Don't over-apply ARIA:

  • Semantic HTML tags don't need roles on top
  • <button> doesn't need role="button"
  • <nav> doesn't need role="navigation"

Keyboard navigation

/* Visible focus style */
:focus-visible {
  outline: 2px solid #0066cc;
  outline-offset: 2px;
}

/* Don't remove outline entirely */
:focus:not(:focus-visible) {
  outline: none;
}

Focus management:

  • When a modal opens, focus moves into it
  • When it closes, focus returns to the trigger button
  • Tab order must be logically sensible

Color contrast

LevelNormal textLarge textRequirement
AA4.5:13:1Minimum
AAA7:14.5:1Ideal target

Tools:

  • WebAIM Contrast Checker
  • Chrome DevTools color picker (shows contrast)

Animation & transitions

Performance

Prefer these properties (GPU accelerated):

.optimized-animation {
  transform: translateX(100px);        /* position */
  transform: scale(1.5);               /* scale */
  transform: rotate(45deg);            /* rotation */
  opacity: 0.5;                        /* transparency */
}

Avoid animating these (trigger reflow):

  • width, height, top, left, margin, padding
  • If unavoidable, substitute transform

will-change:

/* Set before the animation starts */
.animating {
  will-change: transform, opacity;
}

/* Remove after it ends */
.animation-complete {
  will-change: auto;
}

Micro-interaction design

Button press feedback:

.btn {
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.btn:active {
  transform: scale(0.97);
}

Loading skeleton:

.skeleton {
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

Reduced-motion preference:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

Dark mode

Implementation

CSS variables:

:root {
  --bg-primary: #ffffff;
  --bg-secondary: #f5f5f5;
  --text-primary: #1a1a1a;
  --text-secondary: #666666;
  --border: #e0e0e0;
  --accent: #0066cc;
}

[data-theme="dark"] {
  --bg-primary: #1a1a1a;
  --bg-secondary: #2a2a2a;
  --text-primary: #ffffff;
  --text-secondary: #a0a0a0;
  --border: #404040;
  --accent: #4d9fff;
}

/* Follow the system */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --bg-primary: #1a1a1a;
    /* ... */
  }
}

React toggle:

// hooks/useTheme.ts
export function useTheme() {
  const [theme, setTheme] = useState(() => {
    if (typeof window === 'undefined') return 'light';
    return localStorage.getItem('theme') ||
           (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
  });

  useEffect(() => {
    document.documentElement.setAttribute('data-theme', theme);
    localStorage.setItem('theme', theme);
  }, [theme]);

  const toggle = () => setTheme(t => t === 'light' ? 'dark' : 'light');
  return { theme, toggle };
}

Design system basics

Spacing system

:root {
  --space-1: 0.25rem;  /* 4px */
  --space-2: 0.5rem;   /* 8px */
  --space-3: 0.75rem;  /* 12px */
  --space-4: 1rem;     /* 16px */
  --space-6: 1.5rem;   /* 24px */
  --space-8: 2rem;     /* 32px */
  --space-12: 3rem;    /* 48px */
  --space-16: 4rem;    /* 64px */
}

Type system

:root {
  --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'Fira Code', 'Consolas', monospace;

  --text-xs: 0.75rem;    /* 12px */
  --text-sm: 0.875rem;   /* 14px */
  --text-base: 1rem;     /* 16px */
  --text-lg: 1.125rem;   /* 18px */
  --text-xl: 1.25rem;    /* 20px */
  --text-2xl: 1.5rem;    /* 24px */
  --text-3xl: 1.875rem;  /* 30px */
}

Elevation scale

:root {
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
  --shadow-md: 0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.05);
  --shadow-lg: 0 10px 15px rgba(0,0,0,0.08), 0 4px 6px rgba(0,0,0,0.05);
  --shadow-xl: 0 20px 25px rgba(0,0,0,0.1), 0 10px 10px rgba(0,0,0,0.04);
}

State design

Loading state

┌─────────────────────────────────────┐
│  Loading...                         │
│  ████████░░░░░░░░░░ 40%             │
│  or: skeleton / spinner             │
└─────────────────────────────────────┘

Empty state

┌─────────────────────────────────────┐
│         [empty-state icon]          │
│         No data yet                 │
│   Create your first record          │
│        [+ New record]               │
└─────────────────────────────────────┘

Error state

┌─────────────────────────────────────┐
│         [error icon]                │
│         Failed to load              │
│  Network error — check and retry    │
│        [Retry]                      │
└─────────────────────────────────────┘

Form best practices

Validation strategy

Timing:

  • Email format: validate on blur
  • Password strength: real-time feedback
  • Required fields: validate together on submit

Error messaging:

<div class="form-field">
  <label for="email">Email <span aria-label="required">*</span></label>
  <input
    id="email"
    type="email"
    required
    aria-invalid="true"
    aria-describedby="email-error"
  />
  <span id="email-error" class="error" role="alert">
    Please enter a valid email address
  </span>
</div>

Output format

When the user asks a frontend UI question, output:

  1. Analysis — problems with the current implementation, or requirement analysis
  2. Approach — recommended implementation (with code examples)
  3. Caveats — performance, accessibility, compatibility notes
  4. Tooling — relevant libraries or tools

Principles

  1. Mobile first — design for mobile, then scale up to desktop
  2. Progressive enhancement — base functionality works without JS; JS enhances
  3. Respect user preferences — support reduced-motion, color-scheme
  4. Semantic HTML — correct tags; don't abuse divs
  5. Accessibility is not an add-on — consider it from the start

Related Skills