Les tokens de design sont le vocabulaire partagé entre les designers et les développeurs. Ils existent sous diverses formes depuis l'ère Salesforce Lightning — Style Dictionary, Theo, le projet de spécification du W3C Design Token Community Group. Ce qui a changé récemment, c'est qu'ils constituent désormais également le vocabulaire partagé entre votre base de code et les agents de codage IA.

Un agent qui sait que color.accent = #d96a3a utilisera cette valeur. Un agent qui reçoit une capture d'écran devinera « orange chaud » et produira quelque chose de proche, mais faux. L'écart se cumule sur des dizaines de composants.

figmascope exporte un tokens.json dans le cadre de chaque bundle de contexte. Cet article explique le format en détail, comment figmascope source les tokens depuis Figma, le mécanisme d'inférence par fréquence pour les fichiers sans Variables Figma, et comment connecter la sortie aux frameworks courants. Pour voir comment les tokens s'intègrent dans le flux d'export complet, visitez l'application figmascope ou lisez Figma vers Cursor et Figma vers Claude Code.

Le format tokens.json

figmascope utilise un format inspiré du W3C Design Token Community Group. Chaque token est un objet avec des champs $value et $type, imbriqué sous des clés de catégorie sémantique :

{
  "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" }
    }
  }
}

Pourquoi « inspiré du W3C » et pas la spec exacte ?

La spécification du W3C Design Token Community Group est encore un projet. figmascope suit les conventions de base ($value, $type, groupes imbriqués) mais n'implémente pas tous les cas limites comme les types composites et les chaînes de résolution d'alias. La sortie est suffisamment stable pour être consommée par Style Dictionary, un parcours JSON direct, ou un modèle de langage — qui est le principal consommateur.

Types de tokens utilisés

$type Catégorie Format $value Exemple
color couleur chaîne hexadécimale "#d96a3a"
dimension espacement, rayon chaîne CSS avec unité "16px"
fontFamily typographie nom de police "Inter"
number typographie nombre sans unité 400, 1.45

Les couleurs sont toujours produites sous forme de chaînes hexadécimales. Si la source Figma utilise RGBA avec une opacité non totale, le canal alpha est préservé en hex à 8 chiffres (#d96a3a80).

Comment figmascope source les tokens

figmascope utilise une stratégie de sourcing à deux niveaux. Les Variables Figma sont la source préférée ; l'inférence par fréquence est le mécanisme de secours.

Niveau 1 : Variables Figma

Si le fichier Figma dispose de Variables définies (le système de tokens natif de Figma, disponible sur les plans Professional et Organization), figmascope les lit via le point de terminaison REST /v1/files/:key/variables/local. Les noms de variables sont utilisés comme clés de tokens, normalisés en kebab-case. Les modes sont fusionnés vers le mode par défaut, sauf si le fichier n'en possède qu'un, auquel cas les valeurs de ce mode sont utilisées directement.

Les collections de variables se mappent vers les clés de catégorie de premier niveau dans tokens.json. Une collection nommée « Color » produit tokens.color.* ; « Spacing » produit tokens.spacing.*. Si votre fichier Figma utilise des noms de collection non standard, figmascope tente d'inférer la catégorie à partir du type résolu de la variable.

Niveau 2 : Inférence par fréquence

De nombreux fichiers Figma — notamment les plus anciens ou les fichiers de clients n'ayant pas adopté les Variables — n'ont pas de définitions de variables. figmascope gère ce cas en parcourant l'intégralité de l'arbre de nœuds et en construisant des histogrammes de fréquence des couleurs de remplissage, des valeurs d'espacement, des rayons d'angle et des propriétés typographiques.

Les valeurs apparaissant au-dessus d'un seuil de fréquence deviennent des tokens candidats. Ils sont nommés par leur catégorie et un index séquentiel (color.0, color.1…) sauf si un nom lisible peut être inféré de leur utilisation (par ex., une couleur utilisée uniquement sur des fonds sur plusieurs frames devient color.surface).

Le manifeste _meta.json enregistre tokensSource comme "variables" ou "inferred", de sorte que votre prompt agent peut noter quand l'inférence a été utilisée :

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

Les tokens inférés sont utiles mais non autoritaires. Traitez-les comme un point de départ, pas comme une spécification de système de design.

Références de tokens dans l'IR de mise en page

Les fichiers IR par écran (screens/*.json) référencent les tokens par chemin via des chaînes $ref plutôt que d'intégrer des valeurs brutes. Cela maintient l'IR compact et garantit que l'agent résout toujours les valeurs depuis une source de vérité unique :

{
  "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" }
    }
  ]
}

Un agent traitant ce nœud résout color.accent vers #d96a3a et spacing.2 vers 8px depuis le fichier tokens.json parallèle. Aucune ambiguïté, aucune hallucination de valeurs.

Consultez l'IR par écran expliqué pour la documentation complète du schéma de nœuds.

Utiliser tokens.json avec Style Dictionary

La sortie de figmascope est compatible avec Style Dictionary avec une configuration minimale. Puisqu'il utilise déjà la convention $value / $type, vous pouvez pointer Style Dictionary directement vers 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' }]
    }
  }
};

L'exécution de style-dictionary build produira des propriétés CSS personnalisées et des exports de modules ES depuis le même fichier source que celui qu'utilise l'agent.

Utiliser tokens.json avec Tailwind

Un petit script convertit tokens.json en extension de thème Tailwind. La structure est suffisamment plate pour être parcourue sans récursion dans les cas courants :

// 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

Puis dans tailwind.config.ts :

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

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

Utiliser tokens.json avec Jetpack Compose

Pour les projets Android, la structure des tokens se mappe bien vers un object Kotlin. Vous pouvez le générer programmatiquement ou demander à Claude Code de le faire. Pour les tokens de couleur :

// 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
  }
}

Consultez Jetpack Compose depuis Figma pour un guide complet incluant l'intégration avec MaterialTheme.

Ce que tokens.json ne contient pas

Connaître les limites du périmètre permet de calibrer les attentes :

Le tableau warnings dans _meta.json signalera toute valeur qui n'a pas pu être exportée proprement. Vérifiez-le avant de remettre le bundle à un agent.

Comment les noms de tokens sont dérivés

Lorsque figmascope lit les Variables Figma, le nom de la variable dans Figma devient la clé du token. Une variable nommée Colors/Surface/Primary dans une collection nommée Color devient tokens.color.surface.primary dans tokens.json — le séparateur de chemin est / dans Figma, . dans les clés imbriquées JSON.

Figma autorise les noms de variables avec des espaces, des majuscules et des caractères spéciaux. figmascope les normalise :

L'étape de translittération est importante pour les équipes internationales. Une équipe de design ukrainienne utilisant des noms de variables cyrilliques comme Фон (arrière-plan) obtient une clé ASCII stable (fon) dans la sortie, utilisable dans les noms de classes CSS et en JSON sans problèmes d'encodage. Le nom original est préservé dans un champ $description s'il est présent dans les métadonnées de la Variable Figma.

Vérifier la couverture des tokens avant la génération de code

Avant de confier le bundle à un agent, il vaut la peine de vérifier que la couverture des tokens semble raisonnable. Un script Node rapide qui vérifie si toutes les valeurs de couleur référencées dans les IR d'écrans se résolvent vers des entrées dans 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.`);

Zéro référence manquante signifie que l'agent pourra résoudre chaque $ref dans l'IR de mise en page sans inventer de valeurs. En cas de références manquantes, cela signifie généralement que le fichier Figma a changé après l'export du bundle — relancez figmascope pour obtenir un export frais. Vous pouvez aussi consulter le blog figmascope pour plus de conseils sur le maintien de la couverture des tokens à travers les itérations de design.