Стандартна ціль експорту 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 токен-aware — замість захардкоджених 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: використовуйте spacing-класи 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 працює

Обидві системи є токен-first. 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.

Перелічи порушення. Створи диф, що виправляє їх.

Overlay і absolute — складні випадки

Вузли overlay потребують батьківського relative і absolute-позиціонованих дочірніх. IR перераховує дочірні у z-порядку (перший = нижній шар). Скажіть агенту зберігати цей порядок у JSX — React рендерить у DOM-порядку, і CSS position: absolute відповідно стекується.

Вузли absolute використовують сирі пікселі координат із Figma. Вони майже завжди походять із дизайнів, побудованих без auto-layout. Якщо ви бачите багато absolute-вузлів — зазвичай це означає, що файл Figma має ручне позиціонування, і згенерований код буде крихким при різних розмірах вікна. Розгляньте позначення цього і рефакторинг до flex-розкладок.

Обробка рядків у React

На відміну від Android (де ключі strings.json відображаються на ідентифікатори ресурсів 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 має фіксовану шкалу типів; файл токенів має довільні розміри. Вам потрібно або розширити конфіг Tailwind fontSize значеннями токенів, або використовувати довільні значення (text-[24px]). Обидва варіанти працюють; розширення конфігу — чистіше.

Висота рядка. Та сама проблема — утиліти leading Tailwind не відповідають довільним значенням lineHeight. Використовуйте leading-[{value}] або розширте конфіг.

Градієнти. Не підтримуються в IR. Будь-яка градієнтна заливка з'являється як попередження у _meta.json і опускається з властивості fill вузла. Обробляйте вручну.

Жодна з цих проблем не є блокером — це відомі прогалини. Токен-aware основа міцна; краї просто потребують ручної обробки.

Починайте з figmascope для експорту бандлу, потім використовуйте цей посібник разом із воркфлоу Cursor або воркфлоу Claude Code для реалізації.