Tokeny projektowania to wspólny słownik między projektantami a programistami. Istnieją w różnych formach od ery Salesforce Lightning — Style Dictionary, Theo, projekt specyfikacji W3C Design Token Community Group. Co ostatnio się zmieniło, to że są teraz również wspólnym słownikiem między bazą kodu a agentami AI do kodowania.

Agent, który wie, że color.accent = #d96a3a, użyje tej wartości. Agent, który dostaje zrzut ekranu, zgadnie „ciepła pomarańcza" i wyprodukuje coś zbliżonego, ale niepoprawnego. Różnica kumuluje się przez dziesiątki komponentów.

figmascope eksportuje tokens.json jako część każdego pakietu kontekstu. Ten artykuł szczegółowo wyjaśnia format, jak figmascope pobiera tokeny z Figmy, fallback wnioskowania z częstotliwości dla plików bez zmiennych Figmy i jak podłączyć wynik do popularnych frameworków. Aby zobaczyć, jak tokeny pasują do pełnego przepływu eksportu, odwiedź aplikację figmascope lub przeczytaj Figma do Cursor i Figma do Claude Code.

Format tokens.json

figmascope używa formatu inspirowanego W3C Design Token Community Group. Każdy token to obiekt z polami $value i $type, zagnieżdżonymi pod kluczami kategorii semantycznych:

{
  "color": {
    "surface":      { "$value": "#f6f2ea", "$type": "color" },
    "surface-2":    { "$value": "#efe9dc", "$type": "color" },
    "ink":          { "$value": "#1f1d1a", "$type": "color" },
    "ink-muted":    { "$value": "#4a4641", "$type": "color" },
    "accent":       { "$value": "#d96a3a", "$type": "color" },
    "accent-soft":  { "$value": "#f2c7a8", "$type": "color" },
    "good":         { "$value": "#6a8f5a", "$type": "color" },
    "warn":         { "$value": "#c89a3a", "$type": "color" },
    "bad":          { "$value": "#b8553a", "$type": "color" }
  },
  "spacing": {
    "1":  { "$value": "4px",   "$type": "dimension" },
    "2":  { "$value": "8px",   "$type": "dimension" },
    "3":  { "$value": "12px",  "$type": "dimension" },
    "4":  { "$value": "16px",  "$type": "dimension" },
    "6":  { "$value": "24px",  "$type": "dimension" },
    "8":  { "$value": "32px",  "$type": "dimension" },
    "12": { "$value": "48px",  "$type": "dimension" },
    "16": { "$value": "64px",  "$type": "dimension" }
  },
  "radius": {
    "sm":   { "$value": "4px",  "$type": "dimension" },
    "md":   { "$value": "8px",  "$type": "dimension" },
    "lg":   { "$value": "16px", "$type": "dimension" },
    "full": { "$value": "9999px", "$type": "dimension" }
  },
  "typography": {
    "body": {
      "fontFamily": { "$value": "Inter",  "$type": "fontFamily" },
      "fontSize":   { "$value": "14px",   "$type": "dimension" },
      "fontWeight": { "$value": 400,       "$type": "number" },
      "lineHeight": { "$value": 1.45,     "$type": "number" }
    },
    "heading": {
      "sm": {
        "fontFamily": { "$value": "Inter",  "$type": "fontFamily" },
        "fontSize":   { "$value": "18px",   "$type": "dimension" },
        "fontWeight": { "$value": 600,       "$type": "number" },
        "lineHeight": { "$value": 1.25,     "$type": "number" }
      }
    },
    "mono": {
      "fontFamily": { "$value": "JetBrains Mono", "$type": "fontFamily" },
      "fontSize":   { "$value": "13px",   "$type": "dimension" },
      "fontWeight": { "$value": 400,       "$type": "number" }
    }
  }
}

Dlaczego „w stylu W3C", a nie dokładnie zgodnie ze specyfikacją?

Specyfikacja W3C Design Token Community Group jest nadal projektem. figmascope przestrzega podstawowych konwencji ($value, $type, zagnieżdżone grupy), ale nie implementuje wszystkich przypadków krawędziowych, takich jak typy złożone i łańcuchy rozwiązywania aliasów. Wynik jest wystarczająco stabilny, aby był konsumowany przez Style Dictionary, bezpośrednie przechodzenie JSON lub model językowy — który jest głównym konsumentem.

Typy tokenów w użyciu

$type Kategoria Format $value Przykład
color kolor ciąg hex "#d96a3a"
dimension odstępy, promień ciąg CSS z jednostką "16px"
fontFamily typografia ciąg nazwy czcionki "Inter"
number typografia liczba bez jednostki 400, 1.45

Kolory są zawsze wyświetlane jako ciągi hex. Jeśli źródło Figmy używa RGBA z niepełną przezroczystością, kanał alfa jest zachowany w 8-cyfrowym hex (#d96a3a80).

Jak figmascope pobiera tokeny

figmascope używa dwupoziomowej strategii pozyskiwania. Zmienne Figmy są preferowanym źródłem; wnioskowanie z częstotliwości jest fallbackiem.

Poziom 1: Zmienne Figmy

Jeśli plik Figmy ma zdefiniowane zmienne (natywny system tokenów Figmy, dostępny w planach Professional i Organization), figmascope odczytuje je przez endpoint /v1/files/:key/variables/local REST API. Nazwy zmiennych są używane jako klucze tokenów, sanityzowane do kebab-case. Tryby są zwijane do domyślnego trybu, chyba że plik ma jeden tryb, w którym to przypadku wartości tego trybu są używane bezpośrednio.

Kolekcje zmiennych mapują do kluczy kategorii najwyższego poziomu w tokens.json. Kolekcja o nazwie „Color" produkuje tokens.color.*; „Spacing" produkuje tokens.spacing.*. Jeśli twój plik Figmy używa niestandardowych nazw kolekcji, figmascope próbuje wywnioskować kategorię z rozwiązanego typu zmiennej.

Poziom 2: Wnioskowanie z częstotliwości

Wiele plików Figmy — szczególnie starszych lub plików od klientów, którzy nie przyjęli zmiennych — nie ma definicji zmiennych. figmascope obsługuje to, przechodząc przez całe drzewo węzłów i budując histogramy częstotliwości kolorów wypełnień, wartości odstępów, promieni rogów i właściwości typografii.

Wartości pojawiające się powyżej progu częstotliwości stają się kandydatami na tokeny. Są nazwane przez kategorię i kolejny indeks (color.0, color.1...), chyba że można wywnioskować nazwę czytelną dla człowieka na podstawie sposobu użycia wartości (np. kolor używany tylko na tłach w wielu ramkach staje się color.surface).

Manifest _meta.json zapisuje tokensSource jako "variables" lub "inferred", więc twój prompt agenta może odnotować, kiedy użyto wnioskowania:

// _meta.json — inferred fallback
{
  "tokensSource": "inferred",
  "warnings": [
    {
      "code": "tokens-inferred",
      "message": "No Figma Variables found. Tokens were inferred from usage frequency."
    }
  ]
}

Tokeny wywnioskowane są przydatne, ale nie autorytatywne. Traktuj je jako punkt wyjścia, nie specyfikację systemu projektowania.

Odwołania do tokenów w IR układu

Pliki IR per-ekran (screens/*.json) odwołują się do tokenów przez ścieżkę używając ciągów $ref zamiast osadzania surowych wartości. Dzięki temu IR jest kompaktowy i zapewnia, że agent zawsze rozwiązuje wartości z jednego źródła prawdy:

{
  "kind": "stack",
  "name": "PrimaryButton",
  "direction": "horizontal",
  "gap": { "$ref": "spacing.2" },
  "padding": {
    "top": 10, "right": 16, "bottom": 10, "left": 16
  },
  "background": { "$ref": "color.accent" },
  "radius": { "$ref": "radius.sm" },
  "children": [
    {
      "kind": "leaf",
      "name": "ButtonLabel",
      "type": "text",
      "style": { "$ref": "typography.body" },
      "color": { "$ref": "color.surface" }
    }
  ]
}

Agent przetwarzający ten węzeł rozwiązuje color.accent do #d96a3a i spacing.2 do 8px z równoległego pliku tokens.json. Brak niejednoznaczności, brak halucynacji wartości.

Zobacz wyjaśnienie IR per-ekran po pełną dokumentację schematu węzłów.

Używanie tokens.json ze Style Dictionary

Wynik figmascope jest kompatybilny z Style Dictionary przy minimalnej konfiguracji. Ponieważ już używa konwencji $value / $type, możesz wskazać Style Dictionary bezpośrednio na tokens.json:

// style-dictionary.config.js
module.exports = {
  source: ['design/tokens.json'],
  platforms: {
    css: {
      transformGroup: 'css',
      prefix: 'fs',
      buildPath: 'src/styles/',
      files: [{ destination: 'tokens.css', format: 'css/variables' }]
    },
    js: {
      transformGroup: 'js',
      buildPath: 'src/',
      files: [{ destination: 'tokens.js', format: 'javascript/es6' }]
    }
  }
};

Uruchomienie style-dictionary build wyprodukuje właściwości niestandardowe CSS i eksporty modułów ES z tego samego pliku źródłowego, którego używa agent.

Używanie tokens.json z Tailwind

Mały skrypt konwertuje tokens.json na rozszerzenie motywu Tailwind. Struktura jest wystarczająco płaska, aby przechodzić bez rekursji dla typowych przypadków:

// scripts/tokens-to-tailwind.js
const fs = require('fs');
const tokens = JSON.parse(fs.readFileSync('design/tokens.json', 'utf8'));

function flattenGroup(group) {
  return Object.fromEntries(
    Object.entries(group).map(([k, v]) => [k, v.$value])
  );
}

const extend = {
  colors:      flattenGroup(tokens.color),
  spacing:     flattenGroup(tokens.spacing),
  borderRadius: flattenGroup(tokens.radius),
};

console.log(JSON.stringify(extend, null, 2));
node scripts/tokens-to-tailwind.js > design/tailwind-extend.json

Następnie w tailwind.config.ts:

import extend from './design/tailwind-extend.json';

export default {
  content: ['./src/**/*.{ts,tsx}'],
  theme: { extend },
};

Używanie tokens.json z Jetpack Compose

Dla projektów Android struktura tokenów mapuje czysto do Kotlin object. Możesz generować to programistycznie lub poprosić Claude Code, aby to zrobił. Dla tokenów kolorów:

// Generated from design/tokens.json
object DesignTokens {
  object Color {
    val surface    = Color(0xFFF6F2EA)
    val ink        = Color(0xFF1F1D1A)
    val accent     = Color(0xFFD96A3A)
    val accentSoft = Color(0xFFF2C7A8)
  }
  object Spacing {
    val s1 = 4.dp
    val s2 = 8.dp
    val s4 = 16.dp
    val s8 = 32.dp
  }
}

Zobacz Jetpack Compose z Figmy po kompletny przewodnik obejmujący integrację MaterialTheme.

Czego tokens.json nie zawiera

Znajomość ograniczeń zakresu pomaga ustawić właściwe oczekiwania:

Tablica warnings w _meta.json odnotuje wszelkie wartości, których nie można było wyeksportować czysto. Przejrzyj ją przed przekazaniem pakietu agentowi.

Jak wyprowadzane są nazwy tokenów

Gdy figmascope odczytuje zmienne Figmy, nazwa zmiennej w Figmie staje się kluczem tokenu. Zmienna o nazwie Colors/Surface/Primary w kolekcji o nazwie Color staje się tokens.color.surface.primary w tokens.json — separator ścieżki to / w Figmie, . w zagnieżdżonych kluczach JSON.

Figma pozwala na nazwy zmiennych ze spacjami, wielkimi literami i znakami specjalnymi. figmascope je normalizuje:

Krok transliteracji ma znaczenie dla międzynarodowych zespołów. Ukraiński zespół projektowy używający cyrylickich nazw zmiennych, takich jak Фон (tło), otrzymuje stabilny klucz ASCII (fon) w wynikach, który jest użyteczny w nazwach klas CSS i JSON bez problemów z kodowaniem. Oryginalna nazwa jest zachowana jako pole $description, jeśli jest obecna w metadanych zmiennej Figmy.

Sprawdzanie pokrycia tokenów przed codegen

Przed przekazaniem pakietu agentowi warto sprawdzić, czy pokrycie tokenów wygląda rozsądnie. Szybki skrypt Node sprawdzający, czy wszystkie wartości kolorów przywoływane w IR ekranów rozwiązują do wpisów w tokens.json:

// scripts/check-token-coverage.js
const fs = require('fs');
const glob = require('glob');

const tokens = JSON.parse(fs.readFileSync('design/tokens.json', 'utf8'));
const screenFiles = glob.sync('design/screens/*.json');

function getRef(obj) {
  const refs = [];
  if (obj && typeof obj === 'object') {
    if (obj.$ref) refs.push(obj.$ref);
    for (const v of Object.values(obj)) refs.push(...getRef(v));
  }
  return refs;
}

function resolveRef(ref, tokens) {
  return ref.split('.').reduce((o, k) => o?.[k], tokens);
}

let missing = 0;
for (const file of screenFiles) {
  const screen = JSON.parse(fs.readFileSync(file, 'utf8'));
  for (const ref of getRef(screen)) {
    if (!resolveRef(ref, tokens)) {
      console.error(`Missing token: ${ref} (in ${file})`);
      missing++;
    }
  }
}
if (missing === 0) console.log('All token refs resolve.');
else console.error(`${missing} unresolved token refs.`);

Zero brakujących odwołań oznacza, że agent będzie mógł rozwiązać każde $ref w IR układu bez wymyślania wartości. Jeśli są brakujące odwołania, zazwyczaj oznacza to, że plik Figmy zmienił się po wyeksportowaniu pakietu — uruchom ponownie figmascope, aby uzyskać świeży eksport. Możesz też sprawdzić blog figmascope po więcej wskazówek dotyczących utrzymania pokrycia tokenów w iteracjach projektowych.