La cible d'export par défaut de figmascope est Jetpack Compose. Mais le bundle est agnostique aux agents — les types de nœuds IR, le format des tokens et les refs de chaînes se mappent tout aussi proprement sur React + Tailwind. Il suffit de dire à l'agent de cibler JSX plutôt que Kotlin.

Ce guide couvre le mapping IR vers JSX, comment étendre tailwind.config.js avec les tokens depuis tokens.json, et les patterns de prompt qui produisent le moins de dérive côté React.

Une mise en garde importante d'emblée

Compose est ce que figmascope teste le plus. L'IR, le format des tokens et les contraintes CONTEXT.md ont été conçus avec Compose à l'esprit. React + Tailwind fonctionne — l'IR se mappe proprement — mais vous verrez légèrement plus de dérive, surtout autour de la typographie et des mises en page overlay. Signalez tout ce qui semble décalé et faites une vérification des tokens après le premier passage.

Étape 1 : Générer et décompresser le bundle

unzip ~/Downloads/context-bundle.zip -d ./design/

ls design/
# CONTEXT.md  _meta.json  components/  screens/  strings.json  tokens.json

Étape 2 : Étendre la config Tailwind avec les tokens de design

Avant de faire des prompts, mappez tokens.json dans votre tailwind.config.js. C'est l'étape clé qui rend Tailwind conscient des tokens — au lieu de valeurs hex codées en dur dans les chaînes className, vous obtenez des noms sémantiques traçables jusqu'au design.

// tailwind.config.js
const tokens = require('./design/tokens.json')

// Construire la map de couleurs : { 'brand-7f5cfe': '#7F5CFE', ... }
const colors = Object.fromEntries(
  Object.entries(tokens.color).map(([key, val]) => [
    `brand-${key}`, val
  ])
)

// Construire la map d'espacement : { 'ds-4': '4px', 'ds-8': '8px', ... }
const spacing = Object.fromEntries(
  Object.entries(tokens.spacing).map(([key, val]) => [
    `ds-${key}`, `${val}px`
  ])
)

// Construire la map de 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,
    }
  }
}

Cela produit des classes Tailwind comme bg-brand-7f5cfe, p-ds-16, rounded-ds-12. Pas les plus beaux noms de classes, mais ils sont traçables — chaque classe se mappe sur une clé de token.

Si vous préférez des alias sémantiques, ajoutez une couche d'alias :

// dans theme.extend.colors :
primary: tokens.color['7f5cfe'],
background: tokens.color['f6f2ea'],
surface: tokens.color['ffffff'],

Donnez les deux à l'agent — la config de token brute et les alias sémantiques — pour qu'il puisse choisir le bon nom en contexte.

Étape 3 : Prompter l'agent pour cibler React + Tailwind

CONTEXT.md indique que la cible par défaut est Compose. Remplacez-le explicitement dans votre prompt :

Implémente ./design/screens/home.json comme un composant fonctionnel React utilisant Tailwind CSS.

Override de framework : ignore les instructions Compose dans CONTEXT.md. Cible React + Tailwind.

Règles :
- Lis ./design/tokens.json. Les tokens sont étendus dans la config Tailwind —
  utilise des classes Tailwind correspondant aux clés de tokens (ex. bg-brand-7f5cfe, p-ds-16).
- Les chaînes UI viennent de ./design/strings.json. Importe-les et référence-les par clé.
- Mapping des types de nœuds 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"> avec enfants positionnés en absolu
    absolute                → <div className="absolute" style={{"{{"}}top, left, width, height{{"}}"}}>
    leaf (text)             → <span> ou <p> avec classes text Tailwind
    leaf (rectangle)        → <div> avec classes bg et rounded
- Ne code pas en dur des valeurs hex. Toutes les couleurs doivent utiliser des classes Tailwind de la config token.
- Ne code pas en dur des chaînes. Utilise les clés strings.json.

Sortie vers : src/screens/HomeScreen.tsx

Le mapping IR vers JSX

Voici le tableau de mapping complet pour React + Tailwind :

Type IRPropriétésPattern JSX
stackaxis: "vertical"<div className="flex flex-col gap-ds-{n}">
stackaxis: "horizontal"<div className="flex flex-row gap-ds-{n}">
overlayenfants superposés<div className="relative"> avec enfants 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}">

Valeurs de gap et padding : utilisez les classes d'espacement ds-{n} depuis l'extension de config Tailwind. Si la valeur de gap n'est pas une clé de token propre, utilisez la syntaxe de valeur arbitraire de Tailwind : gap-[20px].

Un exemple réel : IR d'écran d'accueil vers JSX

En utilisant le même IR que dans le tutoriel 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>
  )
}

Chaque className est traçable. gap-ds-24spacing.24 → 24px. text-brand-7f5cfecolor.7f5cfe#7F5CFE. Si une valeur dérive (ex. l'agent écrit gap-6 au lieu de gap-ds-24), c'est visible immédiatement dans une revue de code.

Pourquoi tokens.json + config Tailwind fonctionne

Les deux systèmes sont token-first. Tailwind étend une config de base avec des valeurs personnalisées ; tokens.json est déjà structuré comme une map de valeurs personnalisées. L'étape d'extension (Étape 2 ci-dessus) est une configuration unique — après ça, l'agent utilise des noms de classes Tailwind qui sont sémantiquement liés au système de design plutôt que des classes utilitaires arbitraires.

Le résultat : quand le token de design change (disons que la couleur primaire passe de #7F5CFE à #6B4EE6), vous mettez à jour une valeur dans tokens.json, relancez l'import de config, et Tailwind régénère. Le code du composant ne change pas.

Vérification de dérive des tokens

Après l'implémentation, demandez à l'agent d'auditer les dérives :

Audite src/screens/HomeScreen.tsx pour la dérive des tokens.

Vérifications :
1. Toute valeur de couleur hex non référencée via une classe Tailwind de la config token.
2. Toutes les valeurs d'espacement px ou rem codées en dur qui devraient être des classes ds-{n}.
3. Toutes les chaînes UI non issues de design/strings.json.

Liste les violations. Produis un diff qui les corrige.

Overlay et absolute — les cas délicats

Les nœuds overlay ont besoin d'un parent relative et d'enfants positionnés en absolute. L'IR liste les enfants dans l'ordre z (premier = couche inférieure). Dites à l'agent de préserver cet ordre dans le JSX — React rend dans l'ordre DOM et CSS position: absolute s'empile en conséquence.

Les nœuds absolute utilisent des coordonnées en pixels bruts depuis Figma. Ceux-ci viennent presque toujours de designs qui n'ont pas été construits avec l'auto-layout. Si vous voyez beaucoup de nœuds absolute, cela signifie généralement que le fichier Figma a du positionnement manuel — le code généré sera fragile à différentes tailles de viewport. Envisagez de signaler cela et de refactoriser en mises en page flex.

Gestion des chaînes dans React

Contrairement à Android (où les clés strings.json se mappent sur les IDs de ressources R.string.*), dans React vous importez le JSON directement :

import strings from '../../design/strings.json'

// utilisation
{strings['home.title'].value}
// ou avec fallback
{strings['home.title']?.value ?? strings['home.title']?.fallback ?? 'Sans titre'}

Si vous utilisez des bibliothèques i18n (react-i18next, next-intl), les clés en notation pointée dans strings.json se mappent directement sur les namespaces de clés de traduction. Dites à l'agent quelle bibliothèque i18n vous utilisez pour qu'il génère le bon pattern d'appel.

Lacunes honnêtes côté React

Utilitaires de typographie. Les utilitaires text de Tailwind (text-xs, text-2xl) ne se mappent pas 1:1 sur les tokens typography dans tokens.json. Tailwind a une échelle de types fixe ; le fichier token a des tailles arbitraires. Vous devrez soit étendre la config fontSize de Tailwind avec les valeurs de tokens, soit utiliser des valeurs arbitraires (text-[24px]). Les deux fonctionnent ; étendre la config est plus propre.

Hauteur de ligne. Même problème — les utilitaires leading de Tailwind ne correspondent pas aux valeurs lineHeight arbitraires. Utilisez leading-[{value}] ou étendez la config.

Dégradés. Non supportés dans l'IR. Tout fill dégradé apparaît comme un avertissement dans _meta.json et est omis de la propriété fill du nœud. À gérer manuellement.

Aucune de ces lacunes n'est bloquante — ce sont des lacunes connues. La fondation consciente des tokens est solide ; les bords ont juste besoin d'un traitement manuel.

Commencez avec figmascope pour exporter votre bundle, puis utilisez ce guide avec le workflow Cursor ou le workflow Claude Code pour piloter l'implémentation.