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

Что такое библиотека промптов для дизайн-системы?

Библиотека промптов для дизайн-системы — это структурированный набор машиночитаемых спецификаций: design tokens в JSON, глобальные правила консистентности и компонентные промпты, которые обеспечивают LLM однозначным визуальным контрактом, чтобы каждый сгенерированный UI-компонент использовал только утверждённые цвета, отступы, типографику и паттерны взаимодействия независимо от сессии.

TL;DR

  • -Большая часть UI, сгенерированного через LLM, не проходит визуальный QA с первого раза; причина не в качестве модели, а в отсутствии формализованных правил — которые и предоставляет библиотека промптов.
  • -Каждый компонентный промпт содержит пять обязательных секций: identity, визуальная спецификация (только значения токенов), правила поведения, layout constraints и формат вывода кода — пропуск любой открывает пространство для импровизации модели.
  • -Токены должны включаться явно в каждый промпт — модель не помнит их между запросами и без них подставит значения по умолчанию.
  • -Программная сборка (токены + consistency rules + компонентный промпт) делает библиотеку поддерживаемой: изменение одного JSON-файла автоматически отражается во всех промптах.
  • -На модельном примере внедрение библиотеки поднимает first-pass acceptance rate в 2–3 раза (например, с 27% до 81%) и снижает среднее количество итераций перегенерации примерно вдвое (с 3.2 до 1.4 на компонент).

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):

{
  "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.

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

Компонентный промпт описывает один 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:

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 не дублируются. А промпт формируется под конкретную задачу, не расходуя контекстное окно на нерелевантные компоненты.

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

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

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

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

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

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

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.

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» предотвращает расхождения в описании одних и тех же концепций в разных компонентах.