Aller au contenu

BRI-304 — Table de correspondance tokens Figma ↔ code (V0)

Livrable V0 : comparaison manuelle des tokens couleur + typo (Figma vs Tailwind/Uniwind). Critère de succès : les drifts identifiés sont réels et actionnables. Côté Figma : extrait le 2026-06-11 via MCP search_design_system sur la lib 🎨 Uimmo (yEPrXyd3donmRXv4K7kHtN). Côté code : à remplir avec le lead dev front au kick-off.

Légende statut : ✅ aligné · ⚠️ nom différent (même valeur) · 🎯 valeur différente · ❌ absent d'un côté · ❓ à vérifier

⚠️ À lire avant la réunion — 2 constats d'extraction

1. search_design_system donne les noms + clés + scopes, PAS les valeurs hex résolues. Pour extraire la valeur d'un token, il faut get_variable_defs(fileKey, nodeId) sur un nœud qui l'utilise → l'extracteur Figma du cron devra passer par là (ou l'API REST /variables). À acter comme contrainte technique. La colonne « valeur Figma » ci-dessous n'est remplie que là où on la connaît déjà (BRI-299) ; le reste = → get_variable_defs.

2. La clé (key) est l'identifiant stable, le nom dérive. Chaque variable a une key immuable. Le matching le plus robuste côté Figma se fait par key, pas par nom (le nom peut être renommé → c'est justement un drift). Le code n'a pas ces clés → pour le pont Figma↔code, le matching restera par convention de nommage, d'où l'importance d'une convention partagée.


🔴 Drifts DÉJÀ repérés côté Figma (avant même de regarder le code)

Trouvés pendant l'extraction. Ce sont des incohérences internes à Uimmo — donc des faux-négatifs garantis pour un matching naïf par nom. À montrer au lead dev : ça illustre concrètement pourquoi le sujet existe.

# Drift Détail Impact matching
D1 Casse incohérente Bricks specific/brandborder500 (b minuscule) vs brandBorder300 / brandBorder400 (B majuscule) Un match exact sur nom rate brandborder500
D2 Structure d'état incohérente Info state a infoBorder600 et infoBorder950 (bordures numérotées) alors que Success/Alert/Pending ont un seul xxxBorder non numéroté Le moteur doit gérer des schémas par état différents
D3 Doublon / orphelin infoBackground950 existe 2 fois : Info state/infoBackground950 (dans le groupe) et infoBackground950 tout court (hors groupe, Colors/color/infoBackground950) Doublon réel à nettoyer dans Figma
D4 Même nom, 2 collections Core/white existe dans la collection Colors (ea000bcf…) et dans Primitives (ed47f31a…) Lequel est la source ? Ambiguïté de matching
D5 Pollution legacy WebApp Les recherches remontent aussi la lib 🖥️ WebApp (colors/white, Text/md/md - Medium, gray-secondary…) L'extracteur doit filtrer sur libraryKey Uimmo sinon faux drifts massifs
D6 Surcharge sémantique Disabled state/disabledBackground sert à la fois border-non-cliquable et background (cf. description) ; disabledText a un scope quasi ALL Un token = plusieurs rôles → matching 1:1 code difficile

👉 Ces 6 points sont des drifts réels et actionnables = on a déjà à moitié rempli le critère de succès V0, sans même avoir ouvert le code.


1. Couleurs (collection « Colors », lib Uimmo)

Valeurs hex : seules celles connues via BRI-299 sont indiquées ; les autres → get_variable_defs.

Marque (Bricks specific)

Nom Figma key Figma Valeur Figma Nom code Valeur code Statut
Bricks specific/brandText 795b15c9… #ec5223
Bricks specific/brandBackground50 75faca62… → get_variable_defs
Bricks specific/brandBackground100 2ab7fe8c… #fde6d7
Bricks specific/brandBackground200 3419dbc4…
Bricks specific/brandBackground300 601c1c2d…
Bricks specific/brandBackground400 56cd619e… #f07141
Bricks specific/brandBackground500 afb4cc24…
Bricks specific/brandBorder300 b06e1d09…
Bricks specific/brandBorder400 f2c6435e…
Bricks specific/brandborder500 ⚠️D1 ac5bb2b4… ⚠️

Typographie (couleurs de texte)

Nom Figma key Figma Valeur Figma Nom code Valeur code Statut
Typography/defaultHeading 111c24f5… #13273e
Typography/defaultText 3ed5eb32… #76818b

Core

Nom Figma key Figma Valeur Figma Nom code Valeur code Statut
Core/white (Colors) ⚠️D4 ea000bcf… #ffffff ⚠️
Core/white (Primitives) ⚠️D4 ed47f31a… #ffffff ? ⚠️
Core/appBackground bb89c9d8…

Bordures & fonds neutres

Nom Figma key Figma Valeur Figma Nom code Valeur code Statut
Borders/nonInteractiveBorder 334f7ab4… #eceae8
Borders/interactiveBorder (à requêter) #dbd9d7
Backgrounds/neutralBackground50 be36abfc… #faf9f8
Backgrounds/neutralBackground100 c8e43ebb…
Backgrounds/neutralBackground200 51369555…
Backgrounds/neutralBackground300 dbade9ff…
Backgrounds/neutralBackground400 79f7aa66… #c7c7c7

État Success (rampe complète : Text · Border · Background 50→950)

Nom Figma key Figma Nom code Statut
Success state/successText 8e687ab4…
Success state/successBorder a16efae3…
Success state/successBackground50 ca473beb…
Success state/successBackground100 e32e2a87…
Success state/successBackground200 25587891…
Success state/successBackground300 fe116d30…
Success state/successBackground400 63bf111d…
Success state/successBackground500 4c9c130f…
Success state/successBackground600 13db70a5…
Success state/successBackground700 d2b8f258…
Success state/successBackground800 4c16c89b…
Success state/successBackground900 f59cf3e1…
Success state/successBackground950 b46d2a22…

Valeur de base connue : successText ≈ #16b374.

État Alert (rampe complète)

Nom Figma key Figma Nom code Statut
Alert state/alertText cf24c5dd…
Alert state/alertBorder 2e34d06d…
Alert state/alertBackground50 9cd9b85c…
Alert state/alertBackground100 841c92b0…
Alert state/alertBackground200 21751c1a…
Alert state/alertBackground300 ff7e64e4…
Alert state/alertBackground400 22512f24…
Alert state/alertBackground500 1dc9817a…
Alert state/alertBackground600 d72a5e58…
Alert state/alertBackground700 a05d0678…
Alert state/alertBackground800 9d66e935…
Alert state/alertBackground900 3bd3a0a7…
Alert state/alertBackground950 f0ef9177…

Valeur de base connue : alertText ≈ #d72746.

État Info (⚠️ structure différente — D2/D3)

Nom Figma key Figma Nom code Statut
Info state/infoText 3e667244…
Info state/infoBorder600 ⚠️D2 c5674a4e… ⚠️
Info state/infoBorder950 ⚠️D2 06ed436b… ⚠️
Info state/infoBackground50 246d2852…
Info state/infoBackground100 d9264243…
Info state/infoBackground300 3ac5fb50…
Info state/infoBackground400 4ceb35ab…
Info state/infoBackground500 d231bc94…
Info state/infoBackground600 15d98900…
Info state/infoBackground700 b644c0c0…
Info state/infoBackground800 6c374857…
Info state/infoBackground900 085150ae…
Info state/infoBackground950 ⚠️D3 9ae0b98e… ⚠️
infoBackground950 (orphelin) ⚠️D3 ad1d9eb8… 🔴

Valeur de base connue : infoText ≈ #3280c2. Pas de palier 200 visible (à confirmer).

État Pending (rampe complète)

Nom Figma key Figma Nom code Statut
Pending state/pendingText 71d1d1f4…
Pending state/pendingBorder 27f593bf…
Pending state/pendingBackground50 74d9ed24…
Pending state/pendingBackground100 79680472…
Pending state/pendingBackground200 13678d78…
Pending state/pendingBackground300 4539a7c9…
Pending state/pendingBackground400 7ba56520…
Pending state/pendingBackground500 996f6cbd…
Pending state/pendingBackground600 7ddb3981…
Pending state/pendingBackground700 36e960d3…
Pending state/pendingBackground800 5f04bdf5…
Pending state/pendingBackground900 12a83007…
Pending state/pendingBackground950 f527bd0b…

Valeur de base connue : pendingText ≈ #a66be1.

État Disabled (⚠️ surcharge sémantique — D6)

Nom Figma key Figma Nom code Statut
Disabled state/disabledText ⚠️D6 6da4d482… ⚠️
Disabled state/disabledBackground ⚠️D6 20e41808… ⚠️
Disabled state/disabledBorder ecf6c0a2…

Shiny (⚠️ rampe incomplète — un seul background)

Nom Figma key Figma Nom code Statut
Shiny/shinyText 0e68accc…
Shiny/shinyBorder 0d2e51a4…
Shiny/shinyBackground400 5669bd96…

Transparency (ghosts)

Nom Figma key Figma Nom code Statut
Transparency/ghost0 6d7f71ee…
Transparency/ghost1 b81fe7eb…
Transparency/ghost2 235b3727…
Transparency/ghost3 68f773ab…

⚠️ Figma annonce ~85 variables Colors ; cette table couvre les groupes principaux. Compléter les paliers manquants (ex. Info palier 200, interactiveBorder) avant de figer le périmètre.


2. Typographie (styles de texte, lib Uimmo)

Police Inter. Heading = Semi Bold, Text = Medium. La couleur est portée séparément (cf. tokens couleur). Tailles : seules les connues sont indiquées.

Heading (9 styles)

Style Figma key Figma Taille connue Nom code Statut
Heading/3xs 0114a842…
Heading/2xs 98805acf… 14
Heading/xs fae73ab8… 16
Heading/sm 5a85d6c1… 18
Heading/md 2411331a…
Heading/lg 314a507c…
Heading/xl 371900ab…
Heading/2xl 733bf7df…
Heading/3xl 99096772…

Text (4 styles)

Style Figma key Figma Taille connue Nom code Statut
Text/xs 02c3dcdf…
Text/sm 70aa1d8f… 12 / w500 / lh~1.5
Text/md 0815efb8… 14 / w500 / lh~1.5
Text/lg 995a2b1e…

⚠️ La lib legacy 🖥️ WebApp expose des styles homonymes mais nommés différemment (Text/md/md - Medium, … - Semibold) → à exclure du périmètre (cf. drift D5).


3. Synthèse drift — état au 2026-06-11 (après publish Uimmo de Rémy)

# Catégorie Drift Action Statut
D1 Couleur Casse brandborder500 renommé → brandBorder500 ✅ corrigé
D3 Couleur infoBackground950 en double orphelin supprimé ✅ corrigé
D6 Couleur Tokens disabled multi-rôles scopes disabledText resserrés → [SHAPE_FILL, TEXT_FILL] + descriptions clarifiées ✅ traité (non scindé, documenté)
D4 Couleur Core/white dans Colors + Primitives confirmé par Rémy : Colors/Core/white est un alias de la primitive ✅ non-drift (architecture saine)
D2 Couleur Info : bordures numérotées (infoBorder600/950) vs single ailleurs décision Rémy : laissé tel quel (choix assumé) ✅ clôturé (intentionnel)
D5 Process Lib WebApp legacy polluante WebApp n'est plus du tout utilisée — pur legacy. Exclure côté extracteur ; candidate à l'archivage/dépublication ➡️ hors Figma (cron)

Bonus : Info state/infoBackground200 désormais présent (palier auparavant ❓).

Conclusion drifts internes Figma : tous traités. D1/D3/D6 corrigés ; D4 = alias légitime (non-drift) ; D2 = choix design assumé. Aucun drift interne Uimmo ouvert.

Score de sync V0 (indicatif, code) : ___ tokens alignés / ___ comparés = ___ % (à remplir avec le lead dev)


4. Côté code — extraction du 2026-08-18

Source : ~/Dev/monorepo/projects/common/front/theme/src/tailwind/uniwind-theme.css, auto-généré (« DO NOT EDIT ») depuis les fichiers TS du paquet @bricks-common-front/theme (colors/palette.ts, spacing.ts, border-radius.ts, fonts.ts). Contenu : 89 tokens couleur, 16 espacements (+6 conteneurs), 9 rayons, 5 ombres, 13 utilitaires de texte. Monorepo : brickssas/monorepo, branche develop, commit 20a9cce.

4.1 La règle de correspondance est systématique

On supprime le groupe et on passe en kebab-case, avec le préfixe de famille :

Figma Code
Bricks specific/brandBackground100 --color-brand-background-100
Typography/defaultHeading --color-default-heading
Info state/infoBorder600 --color-info-border-600
Borders/nonInteractiveBorder --color-non-interactive-border
Transparency/ghost0 --color-ghost-0
Spaces/lg --spacing-lg
Radius/sm --radius-sm

Conséquence pour le cron : le matching n'a pas besoin d'une table écrite à la main — une transformation de nom suffit, et tout ce qui ne matche pas par cette règle est un candidat drift. C'est le vrai livrable V0.

4.2 Drifts réels (code ↔ Figma)

# Drift Figma Code Action
D7 Poids de police, sur les 13 styles Heading = Semi Bold · Text = Medium Inter-Bold pour tous les Heading · Inter-Regular pour tous les Text Le plus impactant visuellement. Trancher qui fait foi, puis corriger d'un côté
D8 Palier Shiny incohérent Shiny/shinyBackground400 --color-shiny-background-500: #F9C25D Un des deux se trompe de palier
D9 Palier absent côté code Backgrounds/neutralBackground300 rampe = 50 / 100 / 200 / 400 Ajouter le 300 côté code, ou le retirer de Figma s'il ne sert pas
D10 Valeur différente d'un point Borders/interactiveBorder = #dbd9d7 --color-interactive-border: #d8d9d7 Re-vérifier la valeur Figma (get_variable_defs) avant conclusion
D11 Tokens code sans équivalent Figma relevé --color-black (#13273e, doublon de defaultHeading), --color-black-deep, --color-modal-overlay, --color-none/transparent/current Vérifier : absents de Figma, ou hors périmètre design ?

4.3 ⚠️ Correction de notre propre colonne Figma

Trois « valeurs de base connues » notées en juin sont en fait les background-500, pas les tokens texte :

Token Valeur notée ici Valeur réelle côté code Lecture
successText #16b374 #08744d #16b374 = successBackground500
infoText #3280c2 #1d5187 #3280c2 = infoBackground500
pendingText #a66be1 #7b3ab6 #a66be1 = pendingBackground500
alertText #d72746 #d72746 ✅ aligné

Probable erreur de relevé de notre côté, pas un drift : à re-vérifier dans Figma avant de le remonter comme tel.

4.4 Alignés (nom + valeur vérifiés)

Espacements sm/lg/xl/3xl/4xl/8xl (8/12/16/24/32/64) · rayons sm/lg/full (8/16/9999) · defaultHeading #13273e · defaultText #76818b · appBackground #f9f5f1 · nonInteractiveBorder #eceae8 · white · ghost0→3 · les 3 disabled · les 10 tokens brand (dont brandBorder500, le renommage D1 est bien répercuté) · les rampes complètes success / alert / pending / info 50→950 · infoBorder600 et infoBorder950 (le code reproduit la structure atypique D2) · les 13 tailles de typo (Heading 3xs→3xl = 12→56 px, Text xs→lg = 10→16 px).

4.5 Score de sync V0

~85 tokens comparables · 5 drifts ouverts (D7→D11) · 1 erreur de relevé côté brain à corriger. D7 est structurel (poids de police sur tous les styles) ; D8/D9/D10 sont unitaires et actionnables ; D11 demande une vérification de périmètre.


5. D7 tranché — vérifié le 2026-08-18 (code + Storybook local)

Verdict : drift réel, mais uniquement sur le web. Le mobile est aligné.

Trois fichiers expliquent tout :

  1. projects/common/front/theme/src/fonts.ts — les variables s'appellent bien semibold et medium (l'intention est donc celle de Figma), mais elles pointent vers des alias de police trompeurs : const semibold = 'Inter-Bold' et const medium = 'Inter-Regular'. Aucun vrai Bold n'est utilisé nulle part.
  2. projects/common/uimmo/src/helpers/useThemeFonts.tsx — c'est là que l'alias est résolu, et il dépend de la plateforme :
Alias Mobile (native) Web
Inter-Bold (titres) Inter_600SemiBold Inter_500Medium 🎯
Inter-Regular (textes) Inter_500Medium Inter_400Regular 🎯
  1. projects/storybook/.storybook/global.css — les @font-face du web confirment : Inter-Bold = font-weight: 500, Inter-Regular = font-weight: 400, chargés depuis fonts.gstatic.com.

Mesure sur une story réelle (Accordion, Storybook local) : titre en famille Inter-Bold à 14 px / interligne 18,9 px / #13273e — conforme à heading/2xs sauf le poids, rendu en Medium 500 au lieu du SemiBold 600 de Figma. Le texte suit en Regular 400 au lieu de Medium 500.

Conclusion

  • Mobile : conforme à Figma. Rien à faire.
  • Web (Storybook, front-app, app-pdp-financement) : tout le texte est rendu un cran plus léger que la maquette. Écart systémique, visible à l'œil sur les titres.
  • Question au lead dev avant de corriger : est-ce un choix assumé (rendu web souvent perçu plus gras à poids égal) ou un héritage non intentionnel ? La réponse détermine si on corrige le code ou si on documente la règle « web = un cran plus léger » côté design.

Deux pièges à retenir pour l'outillage

  • Les alias de police mentent : Inter-Bold ne charge jamais de Bold. Un extracteur qui lit le nom de famille conclura faux.
  • font-weight calculé est inutilisable comme critère : il vaut 400 partout côté web, puisque le poids est porté par la famille (@font-face), pas par la propriété CSS. C'est exactement ce qui a produit le faux écart « fontWeight 400 vs 600 » du design QA de juin (BRI-301). La bonne clé de comparaison est le @font-face → poids réel, pas le computed style.