Целевой платформой по умолчанию для 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
stackaxis: "vertical"<div className="flex flex-col gap-ds-{n}">
stackaxis: "horizontal"<div className="flex flex-row gap-ds-{n}">
overlayслоистые дочерние<div className="relative"> с className="absolute ..." дочерними
absolutex, y, w, h<div className="absolute" style={{"{{"}}top: y, left: x, width: w, height: h{{"}}"}}>
leaftype: "text"<span className="text-{size} font-{weight} leading-{lh} text-brand-{color}">
leaftype: "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-24spacing.24 → 24px. text-brand-7f5cfecolor.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 для управления реализацией.