Целевой платформой по умолчанию для figmascope является Jetpack Compose. Но бандл агентонезависим — виды IR-узлов, формат токенов и ссылки на строки отображаются так же чисто на React + Tailwind. Просто скажите агенту нацеливаться на JSX вместо Kotlin.
В этом руководстве рассматривается маппинг IR → JSX, как расширить tailwind.config.js токенами из tokens.json, и паттерны промптинга, дающие наименьшее отклонение на стороне React.
Одна важная оговорка с самого начала
Compose — это то, что figmascope тестирует больше всего. IR, формат токенов и ограничения CONTEXT.md проектировались с учётом Compose. React + Tailwind работает — IR отображается чисто, — но вы увидите немного больше дрейфа, особенно с типографикой и overlay-вёрстками. Фиксируйте всё, что выглядит странно, и после первого прохода запускайте проверку токенов.
Шаг 1: Сгенерируйте и разархивируйте бандл
unzip ~/Downloads/context-bundle.zip -d ./design/
ls design/
# CONTEXT.md _meta.json components/ screens/ strings.json tokens.json
Шаг 2: Расширьте конфигурацию Tailwind дизайн-токенами
Прежде чем промптить, отобразите tokens.json в ваш tailwind.config.js. Это ключевой шаг, делающий Tailwind осведомлённым о токенах — вместо захардкоженных hex-значений в строках className вы получаете семантические имена, восходящие к дизайну.
// tailwind.config.js
const tokens = require('./design/tokens.json')
// Создать карту цветов: { 'brand-7f5cfe': '#7F5CFE', ... }
const colors = Object.fromEntries(
Object.entries(tokens.color).map(([key, val]) => [
`brand-${key}`, val
])
)
// Создать карту отступов: { 'ds-4': '4px', 'ds-8': '8px', ... }
const spacing = Object.fromEntries(
Object.entries(tokens.spacing).map(([key, val]) => [
`ds-${key}`, `${val}px`
])
)
// Создать карту border-radius
const borderRadius = Object.fromEntries(
Object.entries(tokens.radius).map(([key, val]) => [
`ds-${key}`, val === 9999 ? '9999px' : `${val}px`
])
)
module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
colors,
spacing,
borderRadius,
}
}
}
Это производит Tailwind-классы типа bg-brand-7f5cfe, p-ds-16, rounded-ds-12. Не самые красивые имена классов, но они трассируемые — каждый класс восходит к ключу токена.
Если предпочитаете семантические псевдонимы, добавьте слой алиасинга:
// в theme.extend.colors:
primary: tokens.color['7f5cfe'],
background: tokens.color['f6f2ea'],
surface: tokens.color['ffffff'],
Дайте агенту оба — сырую конфигурацию токенов и семантические псевдонимы — чтобы он мог выбрать правильное имя в контексте.
Шаг 3: Промптите агента нацелиться на React + Tailwind
CONTEXT.md говорит, что цель по умолчанию — Compose. Явно переопределите это в промпте:
Реализуй ./design/screens/home.json как функциональный компонент React с использованием Tailwind CSS.
Переопределение фреймворка: игнорировать инструкции Compose в CONTEXT.md. Целевая платформа — React + Tailwind.
Правила:
- Читать ./design/tokens.json. Токены расширены в конфигурацию Tailwind —
использовать Tailwind-классы, соответствующие ключам токенов (например, bg-brand-7f5cfe, p-ds-16).
- UI-строки берутся из ./design/strings.json. Импортировать и ссылаться по ключу.
- Маппинг видов IR-узлов:
stack (axis:vertical) → <div className="flex flex-col gap-[Xpx]">
stack (axis:horizontal) → <div className="flex flex-row gap-[Xpx]">
overlay → <div className="relative"> с абсолютно-позиционированными дочерними
absolute → <div className="absolute" style={{"{{"}}top, left, width, height{{"}}"}}>
leaf (text) → <span> или <p> с Tailwind text-классами
leaf (rectangle) → <div> с bg и rounded классами
- Не захардкоживать hex-значения. Все цвета должны использовать Tailwind-классы из конфигурации токенов.
- Не захардкоживать строки. Использовать ключи из strings.json.
Вывод в: src/screens/HomeScreen.tsx
Маппинг IR → JSX
Полная таблица маппинга для React + Tailwind:
| Вид IR | Свойства | Паттерн JSX |
|---|---|---|
stack | axis: "vertical" | <div className="flex flex-col gap-ds-{n}"> |
stack | axis: "horizontal" | <div className="flex flex-row gap-ds-{n}"> |
overlay | слоистые дочерние | <div className="relative"> с className="absolute ..." дочерними |
absolute | x, y, w, h | <div className="absolute" style={{"{{"}}top: y, left: x, width: w, height: h{{"}}"}}> |
leaf | type: "text" | <span className="text-{size} font-{weight} leading-{lh} text-brand-{color}"> |
leaf | type: "rectangle" | <div className="bg-brand-{color} rounded-ds-{r}"> |
Значения gap и padding: используйте классы отступов ds-{n} из расширения конфигурации Tailwind. Если значение gap не является чистым ключом токена, используйте синтаксис произвольных значений Tailwind: gap-[20px].
Реальный пример: IR домашнего экрана → JSX
Используя тот же IR из руководства по Compose:
import strings from '../../design/strings.json'
export function HomeScreen() {
return (
<div className="flex flex-col gap-ds-24 p-ds-16 bg-brand-f6f2ea min-h-screen">
<h1 className="text-2xl font-bold leading-tight text-brand-1a1a2e">
{strings['home.title'].value}
</h1>
<div className="flex flex-col gap-ds-12">
<div className="bg-white rounded-ds-12 p-ds-16">
<span className="text-xs font-medium text-brand-7f5cfe">
{strings['home.card.label'].value}
</span>
</div>
</div>
</div>
)
}
Каждый className трассируемый. gap-ds-24 → spacing.24 → 24px. text-brand-7f5cfe → color.7f5cfe → #7F5CFE. Если значение дрейфует (например, агент пишет gap-6 вместо gap-ds-24), это видно сразу в код-ревью.
Почему tokens.json + конфигурация Tailwind работает
Обе системы построены на токенах. Tailwind расширяет базовую конфигурацию кастомными значениями; tokens.json уже структурирован как карта кастомных значений. Шаг расширения (Шаг 2 выше) — это разовая настройка — после этого агент использует Tailwind-классы, семантически привязанные к дизайн-системе, а не произвольные utility-классы.
Результат: когда дизайн-токен меняется (скажем, основной цвет переходит с #7F5CFE на #6B4EE6), вы обновляете одно значение в tokens.json, перезапускаете импорт конфигурации, и Tailwind пересоздаёт. Код компонента не меняется.
Проверка дрейфа токенов
После реализации попросите агента проверить дрейф:
Проверь src/screens/HomeScreen.tsx на дрейф токенов.
Проверь:
1. Любые hex-значения цветов, не ссылающиеся через Tailwind-класс из конфигурации токенов.
2. Любые захардкоженные значения px или rem, которые должны быть классами ds-{n}.
3. Любые UI-строки, не взятые из design/strings.json.
Список нарушений. Создай diff, исправляющий их.
Overlay и absolute — сложные случаи
Узлы overlay нуждаются в родителе с relative и дочерних элементах с absolute-позиционированием. IR перечисляет дочерние элементы в z-порядке (первый = нижний слой). Скажите агенту сохранять этот порядок в JSX — React рендерит в порядке DOM, и CSS position: absolute укладывается соответственно.
Absolute-узлы используют сырые пиксельные координаты из Figma. Они почти всегда приходят из дизайнов, не построенных с auto-layout. Если вы видите много absolute-узлов, это обычно означает, что файл Figma имеет ручное позиционирование — сгенерированный код будет хрупким при разных размерах вьюпорта. Рассмотрите возможность его пометки и рефакторинга во flex-вёрстку.
Обработка строк в React
В отличие от Android (где ключи strings.json отображаются на ID ресурсов R.string.*), в React вы напрямую импортируете JSON:
import strings from '../../design/strings.json'
// использование
{strings['home.title'].value}
// или с запасным вариантом
{strings['home.title']?.value ?? strings['home.title']?.fallback ?? 'Untitled'}
Если вы используете i18n-библиотеки (react-i18next, next-intl), ключи в точечной нотации из strings.json напрямую отображаются на пространства имён ключей переводов. Скажите агенту, какую i18n-библиотеку вы используете, чтобы он генерировал правильный паттерн вызова.
Честные ограничения на стороне React
Утилиты типографики. Текстовые утилиты Tailwind (text-xs, text-2xl) не отображаются 1:1 на токены typography в tokens.json. У Tailwind фиксированная шкала типов; в файле токенов произвольные размеры. Вам нужно либо расширить конфигурацию fontSize Tailwind значениями токенов, либо использовать произвольные значения (text-[24px]). Оба работают; расширение конфигурации чище.
Высота строки. Та же проблема — утилиты leading Tailwind не соответствуют произвольным значениям lineHeight. Используйте leading-[{value}] или расширьте конфигурацию.
Градиенты. Не поддерживаются в IR. Любая градиентная заливка появляется как предупреждение в _meta.json и опускается из свойства заливки узла. Обработайте вручную.
Ни одно из них не является блокером — это известные ограничения. Основа с осведомлённостью о токенах надёжна; края просто требуют ручной обработки.
Начните с figmascope для экспорта бандла, затем используйте это руководство вместе с рабочим процессом Cursor или рабочим процессом Claude Code для управления реализацией.