Уявіть команду, де продукт живе на трьох платформах: веб на React, iOS на SwiftUI і Android на Compose. Основний акцентний колір — один. Але в коді він продубльований тричі: #A8FF57 у CSS-змінній, той самий hex у Swift-константі і ще раз в Android XML. Дизайнер оновлює бренд — і хтось має вручну знайти всі три місця. Одне забули — і на iOS кнопка вже трохи іншого відтінку, ніж на вебі.

Це і є проблема, яку вирішує Style Dictionary — інструмент від Amazon, що бере одне джерело правди (JSON з токенами) і генерує з нього платформенні файли: CSS, Swift, Kotlin, TypeScript, будь-що. Оновлюєте колір в одному місці — перезбираєте — і всі три платформи отримують нове значення. Розберемо, як це працює, на реальному прикладі.

Що таке Style Dictionary насправді

Це не плагін і не хмарний сервіс. Це build-інструмент — npm-пакет, який запускається командою в терміналі й перетворює токени у код. Ментальна модель проста, три кроки:

  1. Source — ваші токени у вигляді JSON-файлів (джерело правди).
  2. Transforms — правила перетворення: як записати колір, як перевести 16 у 16px для вебу і 16.0 для iOS, як назвати змінну.
  3. Formats — фінальні файли для кожної платформи: variables.css, Tokens.swift, tokens.xml.

Ви описуєте токени й конфіг один раз. Далі кожна збірка детермінована: той самий вхід завжди дає той самий вихід. Ніякого ручного копіювання hex-кодів між репозиторіями.

Крок 1: токени у JSON

Style Dictionary очікує токени як дерево. У версії 4 нативно підтримується формат W3C DTCG — з полями $value і $type. Починаємо з примітивів (сирі значення):

// tokens/primitive/color.json
{
  "color": {
    "green": {
      "500": { "$value": "#A8FF57", "$type": "color" }
    }
  }
}

А далі — семантичний шар, який посилається на примітив, а не дублює значення. Це та сама трирівнева ієрархія (primitive → semantic → component), про яку варто думати ще на етапі дизайну:

// tokens/semantic/color.json
{
  "color": {
    "action": {
      "primary": { "$value": "{color.green.500}", "$type": "color" }
    }
  }
}

Фігурні дужки {color.green.500} — це посилання (alias). Style Dictionary розв'яже його під час збірки. Зміните green.500 — оновляться всі токени, що на нього посилаються. Це і є суть: значення живе в одному місці.

Крок 2: конфіг збірки

Файл config.json описує, звідки брати токени і які платформи генерувати. Кожна платформа — це transformGroup (готовий набір перетворень) + buildPath + список файлів із форматом:

{
  "source": ["tokens/**/*.json"],
  "platforms": {
    "css": {
      "transformGroup": "css",
      "buildPath": "build/web/",
      "files": [{ "destination": "variables.css", "format": "css/variables" }]
    },
    "ios": {
      "transformGroup": "ios-swift",
      "buildPath": "build/ios/",
      "files": [{ "destination": "Tokens.swift", "format": "ios-swift/class.swift" }]
    },
    "android": {
      "transformGroup": "android",
      "buildPath": "build/android/",
      "files": [{ "destination": "colors.xml", "format": "android/resources" }]
    }
  }
}

Запускаєте npx style-dictionary build — і в теці build/ з'являються три файли. Той самий color.action.primary стане --color-action-primary у CSS, colorActionPrimary у Swift і <color name="color_action_primary"> в Android. Одне джерело, три ідіоматичні виходи.

Що на виході: три файли з одного токена

Найкраще суть видно на результаті. Один семантичний токен color.action.primary, який посилається на color.green.500, після збірки перетворюється на три ідіоматичні файли — кожен у стилі своєї платформи:

/* build/web/variables.css */
:root { --color-action-primary: #A8FF57; }

// build/ios/Tokens.swift
public static let colorActionPrimary = UIColor(...)

<!-- build/android/colors.xml -->
<color name="color_action_primary">#FFA8FF57</color>

Зверніть увагу: розробнику вебу не треба знати про Swift, а iOS-інженер не бачить XML. Кожен працює зі звичним для себе форматом, але значення гарантовано однакове — бо народилося з одного рядка JSON. Оце і є «single source of truth» не на словах, а в коді.

Transforms і formats: чому це не просто пошук-заміна

Різні платформи мають різні конвенції — і Style Dictionary це знає. Кілька прикладів, що робить transformGroup за вас:

  • Іменування. Web любить kebab-case, Swift — camelCase, Android — snake_case. Трансформ name/* робить це автоматично.
  • Розміри. 16 стане 1rem або 16px для вебу, 16.0 (CGFloat) для iOS, 16dp/16sp для Android.
  • Кольори. Один hex перетворюється на UIColor для iOS чи Android-ресурс з альфою у правильному порядку байтів.

Якщо стандартних трансформів мало — пишете власний у JavaScript. Наприклад, додати префікс до всіх CSS-змінних чи згенерувати Jetpack Compose-об'єкт замість XML. Саме тут дизайн-система перестає бути статичним артефактом і стає програмованим конвеєром — навичка, яку ми окремо розбираємо на YouTube-каналі UX Hero на живих прикладах.

Темна тема і мультибренд

Тут криється найпоширеніша помилка новачків: генерувати окремий набір токенів на кожну тему й дублювати примітиви. Правильний підхід — перевизначати лише семантичний шар. Тримаєте одну колекцію примітивів, а для теми підмінюєте семантичні посилання:

// світла: color.bg.primary → {color.white}
// темна: color.bg.primary → {color.gray.900}

На практиці роблять два прогони збірки з різними source-теками (base + theme-overrides) або використовують один конфіг із кількома вихідними файлами. Результат для вебу — два блоки CSS-змінних під :root і [data-theme="dark"]; для iOS — Swift-структура з light/dark значеннями. Логіка перемикання тем при цьому лишається однаковою на всіх платформах, бо джерело — одне.

Де тут Figma

Style Dictionary не читає Figma напряму — йому потрібен JSON. Міст будують плагіном Tokens Studio, який експортує Figma Variables у JSON і пушить у Git. Повний ланцюг виглядає так:

Figma Variables → Tokens Studio → JSON у Git →
Style Dictionary (CI) → CSS + Swift + Kotlin

Дизайнер міняє токен у Figma, пушить — CI-пайплайн (GitHub Actions) запускає збірку й відкриває PR з оновленими файлами для всіх трьох платформ. Дизайнер стає джерелом правди для коду, а не просто малює макет, який хтось потім вручну переносить. Якщо ви ще обираєте між нативними Figma Variables і Tokens Studio — це окрема розмова з нюансами.

Коли Style Dictionary виправданий, а коли ні: якщо у вас лише веб — рідних CSS-змінних вистачить, зайвий build-крок не потрібен. Style Dictionary окупається з другої платформи: щойно з'являються iOS чи Android, ручна синхронізація перетворюється на постійне джерело розбіжностей.

Три помилки, які коштують часу

  1. Плоский список токенів без ієрархії. Коли всі значення на одному рівні й без посилань — тему не зробити, а зміна кольору перетворюється на масову заміну. Починайте з примітивів і семантики від першого дня.
  2. Хардкод замість посилань. Якщо семантичні токени містять сирі hex замість {color.green.500} — ви втратили головну перевагу. Одне значення = одне місце.
  3. Ручний коміт згенерованих файлів. build/ має генеруватися в CI, а не редагуватися руками. Інакше хтось «швиденько підправить» вихід — і джерело з кодом розійдуться знову.

Від нуля до першої збірки за 30 хвилин

  1. Створіть проєкт: npm init -y і npm i -D style-dictionary.
  2. Додайте теку tokens/ з двома-трьома JSON (примітиви + семантика).
  3. Створіть config.json з однією платформою css — переконайтеся, що збірка працює.
  4. Запустіть npx style-dictionary build і подивіться на build/web/variables.css.
  5. Додайте платформу ios або android — і зберіть знову.
  6. Винесіть збірку в GitHub Action на кожен push у теку токенів.

Дизайн-система, що живе тільки у Figma, — це картинка. Дизайн-система, з якої одним прогоном народжуються CSS, Swift і Kotlin, — це інфраструктура. Style Dictionary — найкоротший шлях від першого до другого.