# Design System Prompt Library: как добиться консистентного UI от AI

> Библиотека промптов для дизайн-системы: design tokens, компонентные промпты и consistency rules для предсказуемой генерации UI через LLM.
> Author: Roman Belov · Published: 2026-07-13 · Source: https://futurecraft.pro/ru/blog/design-system-prompts/

UI, сгенерированный через LLM, чаще всего не проходит визуальный QA с первого раза. Основная причина не в качестве модели — а в отсутствии формализованных правил, которые модель может интерпретировать без двусмысленности.

Дизайн-система в Figma решает задачу консистентности для людей. Библиотека промптов решает ту же задачу для AI. Статья описывает структуру такой библиотеки: от design tokens до полноценных компонентных промптов с валидацией.

## Design tokens как фундамент промптов

Design tokens в контексте AI-генерации выполняют две функции. Первая: единый источник правды для визуальных параметров. Вторая: машиночитаемый контракт, который исключает интерпретацию "на глаз".

Стандартный JSON-формат design tokens — Design Tokens Format Module от DTCG (Design Tokens Community Group при W3C):

```json
{
  "color": {
    "primary": { "$value": "#1a1a2e", "$type": "color" },
    "accent": { "$value": "#e2a832", "$type": "color" },
    "surface": { "$value": "#16213e", "$type": "color" },
    "text-primary": { "$value": "#eaeaea", "$type": "color" },
    "text-secondary": { "$value": "#a0a0b0", "$type": "color" },
    "error": { "$value": "#e74c3c", "$type": "color" },
    "success": { "$value": "#2ecc71", "$type": "color" }
  },
  "spacing": {
    "xs": { "$value": "4px", "$type": "dimension" },
    "sm": { "$value": "8px", "$type": "dimension" },
    "md": { "$value": "16px", "$type": "dimension" },
    "lg": { "$value": "24px", "$type": "dimension" },
    "xl": { "$value": "32px", "$type": "dimension" },
    "2xl": { "$value": "48px", "$type": "dimension" }
  },
  "typography": {
    "heading-1": {
      "fontFamily": { "$value": "Inter", "$type": "fontFamily" },
      "fontSize": { "$value": "32px", "$type": "dimension" },
      "fontWeight": { "$value": 700, "$type": "number" },
      "lineHeight": { "$value": 1.2, "$type": "number" }
    },
    "body": {
      "fontFamily": { "$value": "Inter", "$type": "fontFamily" },
      "fontSize": { "$value": "16px", "$type": "dimension" },
      "fontWeight": { "$value": 400, "$type": "number" },
      "lineHeight": { "$value": 1.5, "$type": "number" }
    }
  },
  "radius": {
    "sm": { "$value": "4px", "$type": "dimension" },
    "md": { "$value": "8px", "$type": "dimension" },
    "lg": { "$value": "16px", "$type": "dimension" },
    "full": { "$value": "9999px", "$type": "dimension" }
  }
}
```

Цвет `accent` (#e2a832) в примере — не абстракция: это реальный акцентный цвет дизайн-системы этого блога, futurecraft.pro. Остальные токены в примере иллюстративные и нужны для демонстрации структуры.

Токены передаются в промпт целиком или фрагментами, в зависимости от задачи. Полный набор нужен для генерации страницы. Подмножество `color` + `typography` достаточно для текстового компонента.

Критически важный момент: AI-модель не "запоминает" токены между запросами. Каждый промпт содержит все необходимые токены явно. Без этого модель подставляет значения по умолчанию и ломает консистентность. Подробнее о работе с контекстом в [руководстве по context engineering](/ru/blog/context-engineering-guide/).

## Структура компонентного промпта

Компонентный промпт описывает один UI-элемент: кнопку, карточку, навигацию, форму. Структура состоит из пяти секций.

### Секция 1: Identity

Название компонента, его роль в интерфейсе, варианты (variants).

```
Component: Button
Role: Primary user action trigger
Variants: primary, secondary, ghost, danger
States: default, hover, active, disabled, loading
```

### Секция 2: Visual specification

Точные значения из design tokens. Никаких относительных описаний вроде "крупный шрифт" или "яркий цвет".

```
[variant: primary]
background: {color.accent}
text-color: {color.primary}
font: {typography.body}, fontWeight: 600
padding: {spacing.sm} {spacing.lg}
border-radius: {radius.md}
min-height: 44px

[variant: secondary]
background: transparent
border: 1px solid {color.accent}
text-color: {color.accent}
font: {typography.body}, fontWeight: 600
padding: {spacing.sm} {spacing.lg}
border-radius: {radius.md}
```

### Секция 3: Behavior rules

Интерактивные состояния и переходы. Модель должна знать, что происходит при наведении, клике, фокусе.

```
Hover: background opacity 0.9, cursor: pointer
Active: scale(0.98), transition 100ms
Disabled: opacity 0.5, pointer-events: none
Loading: replace text with spinner (16x16), maintain button dimensions
Focus: outline 2px solid {color.accent}, offset 2px
```

### Секция 4: Layout constraints

Минимальные и максимальные размеры, правила размещения, отступы от соседних элементов.

```
Min-width: 120px
Max-width: 100% of parent container
Margin between adjacent buttons: {spacing.sm}
Icon + text: icon 20x20, gap {spacing.xs}, icon left of text
Full-width on viewport < 640px
```

### Секция 5: Code output format

Формат ожидаемого результата. Без этой секции модель выбирает формат произвольно.

```
Output: React component with TypeScript
Styling: Tailwind CSS classes only
Props interface: { variant, size, disabled, loading, onClick, children }
No inline styles. No CSS modules. No styled-components.
Export: named export, not default
```

Пять секций покрывают полный жизненный цикл компонента. Пропуск любой из них открывает пространство для "творчества" модели, что в контексте дизайн-системы равно поломке.

## Consistency rules: глобальные ограничения

Компонентные промпты описывают отдельные элементы. Consistency rules описывают отношения между ними. Это правила, которые действуют на уровне всего интерфейса.

### Правила типографики

```
TYPOGRAPHY RULES:
- Heading hierarchy: h1 > h2 > h3. Never skip levels.
- Maximum 2 font families per page: {typography.heading.fontFamily} for headings,
  {typography.body.fontFamily} for body text.
- Line length: 45-75 characters for body text. Enforce max-width on text containers.
- No font sizes outside the token scale. If a size is not in tokens, it does not exist.
```

### Правила пространства

```
SPACING RULES:
- Vertical rhythm: all vertical spacing is a multiple of {spacing.sm} (8px).
- Section spacing: {spacing.2xl} between major sections.
- Component internal spacing: {spacing.md} as default padding.
- Related elements: {spacing.sm} gap. Unrelated elements: {spacing.lg} minimum.
- Never use arbitrary values (5px, 13px, 22px). Only token values.
```

### Правила цвета

```
COLOR RULES:
- Background/text contrast ratio: minimum 4.5:1 (WCAG AA).
- Accent color ({color.accent}) used for: CTAs, active states, links. Not for backgrounds.
- Maximum 1 accent color per viewport. No competing visual anchors.
- Error states: {color.error} for borders and icons, not for text.
- Dark surfaces: {color.primary} or {color.surface}. No other dark values.
```

### Правила иконок и медиа

```
ICON RULES:
- Icon sizes: 16px (inline), 20px (button), 24px (standalone), 32px (feature).
- Stroke width: 1.5px for all icons. Consistent across the system.
- Icon color inherits text color of parent. No hardcoded icon colors.
- Decorative icons: aria-hidden="true". Functional icons: aria-label required.

IMAGE RULES:
- Aspect ratios: 16:9 (hero), 4:3 (card), 1:1 (avatar).
- Always include width, height, alt attributes.
- Lazy loading for images below the fold.
```

Consistency rules включаются в каждый промпт как преамбула. Компонентный промпт без consistency rules даёт правильный компонент в неправильном контексте.

## Промпт для композиции: страницы и секции

Отдельные компоненты собираются в секции, секции в страницы. Композиционный промпт описывает структуру более высокого уровня.

```
PAGE: Pricing Page
LAYOUT: single column, max-width 1200px, centered
SECTIONS (top to bottom):
  1. Hero: heading (h1) + subheading (body) + CTA (Button:primary)
     - Heading: max 8 words
     - Subheading: max 2 lines
     - Vertical spacing: {spacing.xl} between elements
  2. Pricing Cards: 3-column grid, gap {spacing.lg}
     - Each card: Card component
     - Highlighted card: border 2px solid {color.accent}
     - Cards equal height (flexbox align-stretch)
  3. FAQ: Accordion component, max 6 items
     - Section heading: h2
     - Spacing from pricing cards: {spacing.2xl}
  4. CTA Footer: centered text + Button:primary
     - Background: {color.surface}
     - Padding: {spacing.2xl} vertical

RESPONSIVE:
  - < 1024px: pricing cards → 2 columns
  - < 640px: pricing cards → 1 column, full-width buttons
```

Композиционный промпт ссылается на компонентные промпты по имени (`Card component`, `Button:primary`, `Accordion component`). Модель получает определения компонентов отдельно или в том же контексте.

## Организация библиотеки промптов

Библиотека промптов требует файловой структуры. Хаотичный набор промптов в одном документе теряет управляемость после 10-15 компонентов.

```
prompt-library/
├── tokens/
│   ├── colors.json
│   ├── typography.json
│   ├── spacing.json
│   └── radius.json
├── rules/
│   ├── consistency.md
│   ├── accessibility.md
│   └── responsive.md
├── components/
│   ├── button.md
│   ├── card.md
│   ├── input.md
│   ├── modal.md
│   ├── navigation.md
│   ├── table.md
│   └── accordion.md
├── compositions/
│   ├── pricing-page.md
│   ├── dashboard-layout.md
│   ├── auth-flow.md
│   └── settings-page.md
└── templates/
    ├── component-template.md
    └── composition-template.md
```

Каждый файл автономен, но ссылается на tokens и rules. Сборка финального промпта происходит программно: скрипт берёт `consistency.md` + нужные tokens + конкретный компонентный промпт и формирует один запрос к API.

Пример сборки на Python:

```python
def build_component_prompt(component_name: str, tokens: list[str]) -> str:
    rules = read_file("rules/consistency.md")
    a11y = read_file("rules/accessibility.md")

    token_data = {}
    for token_file in tokens:
        token_data.update(load_json(f"tokens/{token_file}.json"))

    component = read_file(f"components/{component_name}.md")

    return f"""You are a UI component generator.

## Design Tokens
{json.dumps(token_data, indent=2)}

## Consistency Rules
{rules}

## Accessibility Rules
{a11y}

## Component Specification
{component}

Generate the component following ALL rules above. Output ONLY code, no explanations."""


# Использование
prompt = build_component_prompt("button", ["colors", "typography", "spacing", "radius"])
```

Программная сборка решает сразу три проблемы. Tokens обновляются в одном месте и автоматически попадают во все промпты. Rules не дублируются. А промпт формируется под конкретную задачу, не расходуя контекстное окно на нерелевантные компоненты.

## Валидация результатов: автоматические проверки

Генерация без валидации бессмысленна. Набор автоматических проверок закрывает типичные ошибки модели.

### Проверка токенов

```python
ALLOWED_COLORS = {"#1a1a2e", "#e2a832", "#16213e", "#eaeaea", "#a0a0b0", "#e74c3c", "#2ecc71"}
ALLOWED_SPACING = {"4px", "8px", "16px", "24px", "32px", "48px"}

def validate_tokens(generated_code: str) -> list[str]:
    violations = []
    hex_colors = re.findall(r'#[0-9a-fA-F]{6}', generated_code)
    for color in hex_colors:
        if color.lower() not in ALLOWED_COLORS:
            violations.append(f"Unauthorized color: {color}")

    px_values = re.findall(r'(\d+)px', generated_code)
    for val in px_values:
        px = f"{val}px"
        if px not in ALLOWED_SPACING and int(val) not in [0, 1, 2, 16, 20, 24, 32, 44]:
            violations.append(f"Non-standard spacing: {px}")

    return violations
```

### Проверка accessibility

```python
def validate_a11y(generated_code: str) -> list[str]:
    violations = []
    img_tags = re.findall(r'<img[^>]*>', generated_code)
    for img in img_tags:
        if 'alt=' not in img:
            violations.append(f"Image missing alt attribute: {img[:50]}")

    button_tags = re.findall(r'<button[^>]*>.*?</button>', generated_code, re.DOTALL)
    for btn in button_tags:
        if 'aria-label' not in btn and '>' not in btn.split('</')[0].split('>')[1]:
            violations.append("Button without accessible label")

    return violations
```

### Проверка структуры

```python
def validate_heading_hierarchy(generated_code: str) -> list[str]:
    violations = []
    headings = re.findall(r'<h(\d)', generated_code)
    levels = [int(h) for h in headings]

    for i in range(1, len(levels)):
        if levels[i] > levels[i-1] + 1:
            violations.append(
                f"Heading hierarchy skip: h{levels[i-1]} → h{levels[i]}"
            )
    return violations
```

Все три проверки работают как post-processing pipeline. Если нарушений больше порога, пайплайн отклоняет результат и отправляет промпт повторно с дополнением: «Previous output contained these violations: [list]. Fix them.»

## Промпт-шаблоны для типовых задач

Библиотека содержит готовые шаблоны для частых сценариев. Шаблон формализует задачу так, чтобы модель выдавала предсказуемый результат.

### Шаблон: новый компонент

```
TASK: Create a new UI component
COMPONENT: [name]
DESIGN TOKENS: [attached]
CONSISTENCY RULES: [attached]

REQUIREMENTS:
- Follow the 5-section component spec format (identity, visual, behavior, layout, output)
- Use ONLY provided design tokens for all visual values
- Include all interactive states
- TypeScript + Tailwind CSS
- WCAG AA compliance

OUTPUT:
1. Component code (.tsx)
2. Props interface
3. Usage example (3 variants)
```

### Шаблон: адаптация существующего компонента

```
TASK: Adapt existing component to design system
CURRENT CODE: [attached]
DESIGN TOKENS: [attached]
CONSISTENCY RULES: [attached]

INSTRUCTIONS:
- Replace all hardcoded color values with design token equivalents
- Replace all hardcoded spacing with token values
- Preserve existing functionality and props API
- Add missing interactive states (hover, focus, disabled)
- Fix accessibility violations

OUTPUT:
1. Updated component code
2. List of changes made (before → after)
```

### Шаблон: аудит страницы

```
TASK: Audit page against design system
PAGE CODE: [attached]
DESIGN TOKENS: [attached]
CONSISTENCY RULES: [attached]

CHECK:
- Token compliance (unauthorized colors, spacing, fonts)
- Heading hierarchy
- Contrast ratios
- Responsive breakpoints
- Component consistency (same component, same styling everywhere)

OUTPUT FORMAT:
| Issue | Location | Severity | Fix |
|-------|----------|----------|-----|
```

## Версионирование и эволюция

Библиотека промптов живёт в git. Изменение токена `color.accent` с `#e2a832` на `#f0b429` порождает коммит, который автоматически обновляет все промпты, ссылающиеся на этот токен (через JSON-файл).

Semantic versioning для промптов:

- **Patch** (1.0.x): исправление формулировок без изменения поведения
- **Minor** (1.x.0): новый компонент или новый вариант существующего
- **Major** (x.0.0): изменение tokens, breaking change в consistency rules

Каждую версию тестируют: прогоняют набор из 10-15 эталонных генераций через валидацию. Если процент нарушений вырос после изменения промпта, версию откатывают.

## Метрики эффективности

Четыре метрики показывают, работает ли библиотека.

**Token compliance rate.** Процент сгенерированных значений, соответствующих design tokens. Целевой показатель: 95%+.

**First-pass acceptance.** Процент результатов, прошедших валидацию с первой попытки. Модельный пример: около 27% до внедрения библиотеки, около 81% после — порядок величины эффекта, а не измеренный бенчмарк.

**Regeneration rate.** Сколько раз приходится перегенерировать компонент до приемлемого результата. Модельный пример: с библиотекой среднее значение падает с 3.2 до 1.4 итерации.

**Cross-component consistency.** Визуальная однородность между компонентами, сгенерированными в разных сессиях. Измеряется автоматически через сравнение извлечённых CSS-свойств с эталонным набором.

## Ограничения и компромиссы

Библиотека промптов не решает все проблемы генерации UI.

Контекстное окно ограничено. Полный набор tokens + rules + компонентный промпт + композиция занимает 3000-5000 токенов. Для сложной страницы с 8-10 компонентами это 15000-20000 токенов только на инструкции. Решение: иерархическая генерация. Сначала layout и секции, затем каждый компонент отдельным запросом.

Модели интерпретируют Tailwind-классы лучше, чем raw CSS. Если дизайн-система использует CSS-in-JS или CSS Modules, промпты требуют дополнительных примеров для каждого паттерна.

Анимации и микроинтеракции описываются промптами хуже, чем статичные компоненты. Для сложных переходов эффективнее предоставить референсный код, чем описывать поведение текстом.

## Минимальная рабочая библиотека

Пять артефактов, два-три часа:

1. **Design tokens в JSON** — colors, spacing, typography. Три файла, 50–100 строк.
2. **Consistency rules** — типографика, цвет, пространство в одном документе. 30–40 строк.
3. **Три компонентных промпта** — Button, Card, Input покрывают 60% типичного интерфейса.
4. **Скрипт сборки** — 20 строк, собирающих tokens + rules + component в один промпт.
5. **Базовая валидация** — проверка hex-цветов и spacing на соответствие tokens. 15 строк.

После этого каждый компонент генерируется по стандарту. Библиотека растёт добавлением одного файла на компонент в `components/` — больше ничего менять не нужно.

---

*Нужна помощь с дизайн-системой? Я помогаю стартапам внедрять AI-решения и строить продукты — [belov.works](https://belov.works).*

## FAQ

**Как обрабатывать варианты компонентов, требующие токенов, которых ещё нет в дизайн-системе?**

Правильный путь — заблокировать генерацию и сначала добавить токен, а не разрешать модели изобретать ad-hoc значение. Когда промпт возвращает компонент с захардкоженным значением без соответствия в токенах — это сигнал о пробеле в библиотеке, а не исключение, которое можно допустить. Добавьте отсутствующий токен в соответствующий JSON-файл (например, `color.warning` или `spacing.compact`), закоммитьте, затем перезапустите промпт компонента. Это сохраняет библиотеку как единственный источник истины и предотвращает накопление token debt.

**Как наиболее надёжно специфицировать интерактивные состояния, если модель склонна их пропускать?**

Самый эффективный приём — перечислять состояния явно в секции identity компонента, а не полагаться на общую инструкцию «включи все интерактивные состояния». Указывайте каждое состояние по имени с ожидаемым визуальным изменением: `focus: outline 2px solid {color.accent}, outline-offset 2px`. Модели генерируют более полную и консистентную обработку состояний, когда промпт перечисляет их как отдельные deliverables. Для Tailwind-компонентов дополнительно укажите формат модификатора — `hover:bg-[{color.primary.hover}]` — иначе модель может использовать произвольные значения для hover.

**Как поддерживать консистентность библиотеки промптов, когда несколько членов команды вносят спецификации компонентов?**

Храните шаблон компонента в `templates/component-template.md` и проверяйте его использование через чеклист PR-ревью, подтверждающий наличие всех пяти секций. Запускайте скрипты валидации на сгенерированных результатах в CI — несоответствие токенам или нарушения accessibility блокируют мёрдж. Более глубокая проблема консистентности — семантическая: два разных человека могут по-разному специфицировать «состояние ошибки» для кнопки и для поля ввода. Общий глоссарий в `rules/` с определениями терминов «error», «disabled», «loading» предотвращает расхождения в описании одних и тех же концепций в разных компонентах.
