Skip to main content

Command Palette

Search for a command to run...

Comment générer un écran web avec Cursor à partir d'une maquette Figma ?

Published
20 min read
Comment générer un écran web avec Cursor à partir d'une maquette Figma ?

Problématique

Créer des pages web (ou mobile) en respectant un design précis est un véritable challenge pour une IA.
Pour l'aider à réussir cette tâche, le développeur Front va devoir se poser les bonnes questions :

  • Faut-il découper la maquette composant par composant ou peut-on générer une page complète d'un coup ?

  • Peut-on utiliser un simple screenshot ?

  • Comment récupérer les infos précises de Figma (codes couleurs, polices, marges...) ?

  • Quel modèle LLM utiliser ? (GPT, Claude, Gemini...)

De plus, d'autres contraintes non-visibles sur la maquette entrent en jeu, comme le responsive, les interactions (clic, mouseover...), les animations, l'accessibilité, etc.

Il y a plusieurs approches possibles pour transcrire une maquette Figma en code, et chacune a ses avantages et ses inconvénients.

Spoiler : il n'y a pas de méthode miracle... ^^'

Le but de cet article n'est donc pas de fournir une méthode clef en main, mais plutôt dans un premier temps de comparer différentes approches (écran vs composant, screenshot vs Figma) avec différents modèles LLM.

TLDR;

Si vous n'avez pas le temps de lire, voici l'essentiel :

  • Ne pas générer une page complète : préférer une approche composant par composant.

  • L'IA ne sait pas faire du pixel-perfect (les couleurs, polices et marges seront approximatives).

  • Figma MCP permet d'obtenir les couleurs exactes, ainsi que les assets (pictos, images...), mais fournit un code HTML presque inutilisable (la fameuse "soupe de divs").

  • L'accessibilité et le responsive sont souvent oubliés par l'IA, il faut les demander explicitement et vérifier.

  • Demander aussi de mutualiser le code autant que possible (composants, styles...).

  • Ne pas se fier à ce que raconte l'IA : elle ne fait pas toujours ce qu'elle dit avoir fait → toujours vérifier ce qui a été généré (git diff).

  • Pour obtenir du pixel-perfect, il est souvent indispensable de finir le travail à la main (CSS...) ou au moins de donner un maximum d'éléments dans le prompt.

Pour plus de détails, lisez la suite... ;)

1ère approche : génération d'une page complète

Voici la maquette de l'écran que nous souhaiterions générer : il contient de nombreux composants plus ou moins complexes.

Ecran Figma de référence

Au premier abord, convertir le design d'une page web entière, voire d'un site complet peut paraître intéressant à plusieurs niveaux :

  1. Gain de temps : toute la page serait générée en 1 prompt.

  2. Vision globale : cela permet d'avoir une vue d'ensemble de ce qui est mutualisable ou non.

  3. Cohérence : le code produit en 1 passe a plus de chance de garder une certaine cohérence que si on crée chaque composant individuellement.

Cependant, cette piste a rapidement été éliminée pour diverses raisons :

  • Pour l'exemple ci-dessus, le screenshot de la page complète fait 5Mo (PNG en 1440x6000px) et contient énormément d'informations (textes, images, nombreux composants, etc.).

  • Les LLM ont une taille de contexte limitée : leur "mémoire" serait vite saturée et les détails se perdraient dans cette masse d'informations.

  • De plus, cette approche consomme énormément de tokens d'un coup (> 1 million pour analyser l'image et générer tout le code associé (qui sera en plus très approximatif)).

  • Si on voit que le LLM a fait des choix qui ne nous conviennent pas, ou n'a pas bien suivi les guidelines, on est obligé de TOUT regénérer ! (page complète → nombreux composants → contexte saturé → suit moins bien les guidelines des cursorrules).

  • Le découpage en sous-composants n'est pas forcément celui que l'on aurait souhaité (ou toute la page risquerait même d'être codée dans 1 seul énorme composant...).

  • Le résultat est souvent très approximatif car il y a trop d'infos : le contexte du LLM sature.

Il semble donc préférable de suivre une approche composant par composant. Concentrons nous donc sur 1 composant à la fois (ou une section de page).

Exemple d'un composant avec accordéon

Voici le screenshot du composant qui servira de test (au milieu de la page complète) : c'est un composant modérément complexe, avec principalement un accordéon à gauche et une image à droite.

Exemple de composant avec accordéon

Note : pour une IA, cela représente déjà une certaine difficulté car même si un œil humain verra assez facilement qu'il y a un accordéon à gauche, l'IA pourrait y voir juste un rectangle arrondi pour le 1er item, et 2 autres items séparés par un trait.

1ère stratégie : utiliser un simple screenshot du composant

Une première approche possible est de prendre une capture d'écran du composant à coder, et de demander à Cursor de la convertir en React par exemple.

Test avec GPT-5

Nous avons volontairement choisi de faire un prompt très succinct, en ne donnant aucune information visuelle dans le prompt.

Ainsi, le prompt utilisé dans le Chat (en mode "Agent") avec le modèle GPT-5 était simplement :

Crée ce composant et ajoute le dans la Home page.
Pose moi des questions si besoin.

Accompagné du screenshot du composant ci-dessus.

Comme il n'y avait aucune information visuelle dans le prompt à part le screenshot, l'ajout de la phrase "Pose moi des questions si besoin" invitait le LLM à demander les informations manquantes s'il avait un doute sur l'interprétation du screenshot.

Étonnamment, GPT-5 n'en a pas tenu compte et s'est lancé dans le codage directement.

Voici le résultat obtenu :

Rendu du composant généré avec GPT-5

A première vue, le résultat est plutôt correct, mais si on y regarde de plus près, il y a beaucoup d'approximations, un peu comme si on codait nous-mêmes le composant directement en HTML en essayant de deviner les différentes valeurs (→ marges inexactes, couleurs approximatives, polices incorrectes, etc.).

De plus, l'image de droite n'a pas pu être extraite à partir du screenshot, le LLM a donc intégré la première image qu'il a trouvée dans le projet (une icône...).

Même si le composant est fonctionnel, nous sommes loin du pixel-perfect...

Test avec Claude 4.5 Sonnet

En testant le même prompt avec Claude 4.5 Sonnet (sans thinking), celui-ci a été plus malin. En effet, comme suggéré dans le prompt, il a commencé par me poser des questions pertinentes :

User: Crée ce composant et ajoute-le dans la Home page. Pose-moi des questions si besoin.  Claude: Je vais analyser l'image pour créer ce composant. J'ai quelques questions pour bien comprendre vos besoins :  Comportement des accordéons : Les sections "Approvisionnements responsables", "Process vertueux" et "Engagement sociétal" doivent-elles fonctionner comme des accordéons interactifs (clic pour ouvrir/fermer) ?  Contenu des sections fermées : Quel contenu souhaitez-vous afficher quand on ouvre "Process vertueux" et "Engagement sociétal" ?  Liens des boutons : Où doivent pointer les boutons "Découvrez nos engagements RSE" et "Découvrez la démarche" ?  Image : Avez-vous l'image à utiliser ou dois-je utiliser une image placeholder ?  Responsive : Comment souhaitez-vous que ce composant s'affiche sur mobile (image en dessous du texte, stack vertical, etc.) ?  Couleurs et tokens : Voulez-vous que j'extraie les couleurs depuis Figma en utilisant le MCP Figma, ou puis-je utiliser des couleurs qui correspondent visuellement ?  En attendant vos réponses, je peux commencer par la structure de base si vous le souhaitez.

Il a ainsi repéré l'accordéon et m'a demandé des précisions sur le comportement souhaité, l'image à intégrer à droite, le comportement responsive et les couleurs à utiliser (même si je l'ai laissé les deviner).

Il a bien compris le fonctionnement et a réalisé une maquette assez proche, malgré quelques loupés sur l'icône chevron, l'alignement des boutons ou les couleurs trop claires.

Rendu du composant généré avec Claude 4.5 Sonnet

Test avec Gemini 3 Pro

Même test avec Gemini 3 Pro. Il a posé qqs questions mais a quand même commencé à coder avant d'en avoir les réponses ^^

User: Crée ce composant et ajoute-le dans la Home page. Pose-moi des questions si besoin.  Gemini: Thought for 16s  Bonjour! J'ai bien analysé votre demande et l'image fournie. Je vais commencer par créer une version statique de ce composant, en me basant sur ce que je vois.  Pour que le résultat soit parfait, j'aurai besoin de quelques éléments de votre part :  L'image de la femme tenant l'ardoise. Pouvez-vous me la fournir ? En attendant, j'utiliserai une image de substitution.  Les icônes "+" et "-". Avez-vous des fichiers SVG pour celles-ci ou dois-je en trouver qui ressemblent ?  L'interactivité : La section avec les "Approvisionnements responsables" ressemble à un accordéon. Souhaitez-vous qu'il soit fonctionnel (qu'on puisse ouvrir et fermer chaque section) ou est-ce juste une présentation statique pour le moment ?  Je commence dès maintenant à créer la structure du composant et à l'intégrer. Je vais d'abord lire le fichier src/app/globals.css pour comprendre la configuration de Tailwind CSS.

A noter qu'il a même poussé l'analyse assez loin en repérant qu'il y avait une femme tenant une ardoise dans l'image à intégrer !

Au final, le rendu est encore plus proche de la maquette (c'est même le meilleur de ce comparatif).

Rendu du composant généré avec Gemini 3 Pro

Synthèse des résultats pour la génération via screenshot

Les LLMs s'en sortent plutôt bien en analyse d'image : ils ont tous identifié l'accordéon et ont pu également récupérer tous les textes.

Sur ces tests en "one shot", Claude 4.5 Sonnet et Gemini 3 Pro sont les 2 vainqueurs, avec un léger avantage pour Claude sur la qualité du code, et à Gemini pour la qualité du rendu très proche de la maquette.

2ème stratégie : utiliser Figma MCP

Figma propose un serveur MCP permettant à un LLM de récupérer des métadonnées dans une maquette Figma.

A noter que ce serveur MCP est gratuit mais n'est disponible que si l'on active le "Dev Mode" de Figma (le Dev Mode n'étant, lui, pas gratuit).

Comment mettre en place le MCP Figma ?

Il y a 2 façons de mettre en place le MCP Figma : soit en local (en installant l'application Figma Desktop), soit en se connectant à Figma en remote.

Les 2 procédures sont décrites ici :

Comment utiliser Figma MCP ?

Une fois le MCP Figma configuré, aller sur la maquette Figma et faire un clic-droit sur le composant à reproduire, puis "Copy link to selection".

Récupération du lien vers le composant Figma

On obtient une URL du genre https://www.figma.com/design/xxxxxxxxxx/MCP-FIGMA---Tests?node-id=5420-15527&m=dev.

Ensuite, dans Cursor, on peut fournir cette URL dans un prompt :

Crée ce composant en React et ajoute-le dans la Home page : [lien_figma] Pose-moi des questions si besoin.

Le LLM fera alors appel au MCP et pourra ainsi récupérer :

  • Un screenshot du composant

  • Les variables Figma utilisées (par exemples pour les couleurs ou les polices)

  • Le code HTML/JSX généré par Figma

Nous devrions ainsi pouvoir améliorer la précision et la fidélité des composants générés en récupérant les valeurs exactes des couleurs, marges, etc.

Enfin, en théorie, car le code HTML généré par Figma est assez mauvais (une soupe de div ^^') et étonnamment, il est loin d'être pixel-perfect aussi (les couleurs sont exactes, mais le texte en haut déborde, les textes de l'accordéon sont centrés alors qu'ils devraient être calés à gauche, etc.).

Et en plus ce code est statique : il n'est ni responsive, ni interactif : c'est juste du dessin...

Rendu HTML généré par le MCP Figma

Le rendu peut être plus ou moins fidèle selon la complexité des écrans, mais il ne faut donc pas s'attendre à des miracles : le LLM va devoir faire un mix intelligent entre :

  1. le screenshot (propre mais difficile à "voir" correctement par les LLM),

  2. le code HTML Figma (moche et pas toujours fidèle, à part les codes couleurs)

  3. son expérience pour "deviner" les interactions, le responsive et les animations (ou au moins poser les bonnes questions)

  4. le framework JS que l'on souhaite avoir en sortie (React, Vue, Angular...)

  5. le styling (CSS, Tailwind, ShadCN...)

Test avec GPT-5

GPT-5 a récupéré le code Figma et les variables Figma

Variables Figma renvoyées par le MCP Figma

ainsi que le screenshot du composant :

Screenshot du composant renvoyé par le MCP Figma

Au final, les couleurs sont bonnes, mais le résultat pourrait être meilleur. Il a bien repéré l'accordéon et l'a mis en place correctement, mais les alignements verticaux des icônes ne sont pas conformes. Et la maquette n'est pas responsive.

Rendu de l'accordéon avec GPT-5

En lui demandant simplement "Gère le responsive" (volontairement sans plus d'infos), il a su ajouter du responsive, mais c'est perfectible (texte du bouton qui déborde...).

Responsive de l'accordéon avec GPT-5

Test avec Claude 4.5 Sonnet

Claude a également récupéré le screenshot, les variables et le code Figma. Il a généré quelque chose de proche de la maquette (bons codes couleurs, bons positionnements, icônes un peu approximatives).

Rendu de l'accordéon avec Claude 4.5 Sonnet

Il a bien repéré l'accordéon et même quelques effets d'animation précisés dans des annotations Figma ! (c'est le seul a avoir repéré ça ! Ça ne se voyait même pas dans le Dev Mode de Figma !)

Par contre la maquette produite n'était pas responsive : il s'est trop inspiré du code HTML fourni par Figma, qui n'est pas responsive.

Mais en lui demandant de gérer lui-même le responsive, sans plus d'indication, il a su l'ajouter proprement (mieux qu'avec GPT-5) et intelligemment (image positionnée avant l'accordéon).

Responsive de l'accordéon avec Claude 4.5 Sonnet

Test avec Gemini 3 Pro

Gemini 3 Pro s'en sort très bien aussi : il a généré un code très proche de la maquette et responsive, même si les animations sont un peu moins fluides que lors du test avec le screenshot uniquement (peut-être à cause du code plus volumineux inspiré par le code généré par Figma).

Rendu de l'accordéon avec Gemini 3 Pro

Synthèse des résultats pour la génération via le MCP Figma

L'utilisation du MCP Figma a, comme attendu, permis d'améliorer la précision des couleurs, cependant le code trop verbeux, statique et approximatif généré par Figma est plutôt un handicap car cela pousse le LLM à s'inspirer de ce code et cela remplit le contexte du LLM, qui suit donc moins bien les instructions (car il y a trop d'informations en même temps).

Par ailleurs, cela consomme pas mal de tokens.

Autre exemple : un formulaire

Faisons maintenant le même comparatif avec un formulaire assez complet.

Composant formulaire d'exemple

Note : pour économiser du temps et des tokens, nous éliminerons GPT-5 qui avait de moins bons résultats sur le composant précédent.

Génération à partir d'un screenshot

Comme précédemment, nous commençons par tester un simple screenshot pour la génération du formulaire.

Avec Claude 4.5 Sonnet

Il a tout de suite posé les bonnes questions (validation, captcha, contenu des listes, responsive...) :

User : Je vais analyser cette maquette de formulaire et vous poser quelques questions avant de créer le composant.  Claude :  Questions :  Validation et soumission : Que doit-il se passer lorsqu'on clique sur "Envoyer mon message" ? Faut-il une vraie soumission de formulaire ou juste une console.log pour l'instant ?  reCAPTCHA : Je vois le widget reCAPTCHA. Avez-vous une clé d'API Google reCAPTCHA à utiliser, ou dois-je créer une version mockée pour la démo ?  Validation des champs : Quelles sont les règles de validation exacte (ex: format email, longueur min/max des champs, format téléphone français, etc.) ? Le champ "Nom de mon entreprise" doit-il être désactivé/en lecture seule comme sur la maquette ?  Liste des secteurs professionnels : Quelles sont les options à mettre dans la dropdown "Secteur Professionnel" ?  Tokens Figma : Voulez-vous que j'extraie les variables de design depuis Figma (couleurs, espacements, typographie) pour créer un fichier de tokens CSS, ou puis-je utiliser des valeurs approximatives basées sur la maquette ?  Responsive : Le design doit-il être responsive (mobile/tablette) ou fluide/fixe (desktop) ?  En attendant vos réponses, je peux commencer par récupérer les informations de design depuis Figma si vous avez le fichier ouvert.

Après avoir répondu à ses questions, le résultat obtenu est correct, mais on ne voit pas les bordures sur les champs, et la couleur des erreurs n'est pas respectée non plus... Un peu décevant. Par contre le formulaire est responsive (tout sur 1 colonne en mobile).

Formulaire avec Claude 4.5 Sonnet (première tentative)

Déçu par le résultat précédent, je lui accorde un 2ème essai (oui car la magie des LLM fait qu'on n'a jamais le même résultat à une même question... ✨ ^^').

C'est mieux :

Formulaire avec Claude 4.5 Sonnet (deuxième tentative)

Cette fois-ci on voit les bordures des champs, mais les messages d'erreurs ne s'affichent pas (ils ont été remplacés par des contrôles natifs en popover). Mais la validation est proprement gérée avec l'utilisation de la lib Zod.

Par contre, il n'y a pas de mutualisation des styles des champs : chaque input à ses styles Tailwind copiés-collés, avec en prime quelques incohérences (les 2 dropdowns ne sont pas identiques (cf. chevrons), et certaines checkboxes non plus...).

En améliorant le prompt utilisé, on peut obtenir quelque chose de plus cohérent. Par exemple, en restant volontairement toujours assez vague, si on ajoute "Mutualise tout ce que tu peux", la qualité du code est bien meilleure.

Prompt :

Crée ce composant et ajoute-le dans la Home page. Mutualise tout ce que tu peux (classes Tailwind, sous-composants...) Prends bien en compte l'accessibilité et le responsive. Pose-moi des questions si besoin.

Ainsi, au lieu d'avoir plein de classes Tailwind dupliquées, les styles sont mutualisés dans des composants réutilisables (FormCheckbox, FormInput...).

Code du formulaire de contact mutualisé

Le résultat est beaucoup plus propre et maintenable :

Formulaire avec Claude 4.5 Sonnet avec mutualisation de code

Avec Gemini 3 Pro

Gemini m'a lui aussi posé des questions très pertinentes.

Questions de Gemini 3 Pro pour clarifier le fonctionnement du formulaire

Il m'a alors généré un formulaire encore plus proche de la maquette du premier coup, avec des composants mutualisés également.

Formulaire avec Gemini 3 Pro

Génération via Figma MCP

Comme vu précédemment, le code HTML généré par Figma n'est pas toujours optimal...

Voyons déjà le rendu du HTML renvoyé par le MCP Figma.

Rendu HTML du formulaire via Figma MCP

Visuellement, ce n'est pas trop mal (même si le champ en erreur devrait avoir une bordure rouge, pas noire), mais une fois de plus, c'est une vraie soupe de div : aucun input, ni select, ni button dans le code généré ! Le formulaire n'est pas du tout fonctionnel, il est juste dessiné.

Soupe de div renvoyée par le MCP Figma

Avec Claude 4.5 Sonnet

Après avoir appelé le MCP Figma, Claude m'a posé à peu près les mêmes questions qu'avec le screenshot, et a fini par générer un formulaire assez proche de la maquette (à part un chevron un peu gros sur la dropdown), mais surtout fonctionnel (input, select, button...) et responsive (tout sur 1 colonne en mobile):

Formulaire avec Claude 4.5 Sonnet et Figma MCP

Par contre, les labels ne sont pas associés aux inputs → le formulaire n'est pas accessible, alors que je l'avais demandé dans le prompt ("Prends bien en compte l'accessibilité et le responsive.").

Le pire, c'est que Claude m'affirmait le contraire dans son bilan ^^'

Claude a menti dans son bilan ! Les labels ne sont pas associés aux inputs.

Comme quoi, il est difficile d'avoir quelque chose de déterministe avec les LLM, et il ne faut pas les croire sur parole lorsqu'ils font un bilan de leurs actions : TOUJOURS VERIFIER LES MODIFICATIONS AVEC UN GIT DIFF !

Heureusement, si je lui demande explicitement de vérifier l'accessibilité, le résultat est bien meilleur :

Vérification du RGAA avec Claude 4.5 Sonnet

Claude a ainsi détecté les erreurs qu'il a lui-même faites, et les a bien corrigées cette fois.

Lorsqu'on demande trop de choses en même temps à un LLM, il a tendance a en oublier, ou à les faire partiellement. Le fait que je lui demande explicitement de se concentrer sur l'accessibilité dans un 2ème temps lui a permis de se focaliser sur cette tâche et se corriger lui-même proprement.

Avec Gemini 3 Pro

Gemini s'en est plutôt bien sorti également (à part le textarea qui était un peu trop arrondi...) et a bien généré un formulaire accessible et responsive avec les champs demandés.

Formulaire avec Gemini 3 Pro et Figma MCP

Conclusion

Les devs Front ont encore de beaux jours devant eux... Du moins pour l'instant... ^^'

Les IA ont bien progressé, mais elles ont encore beaucoup de mal à faire du pixel-perfect et à prendre en compte toutes les contraintes annexes liées au dev Front (responsive, accessibilité, interactivité, animations...).

Même en combinant l'utilisation d'un screenshot et des données Figma, ce n'est pas suffisant.

Et tous les modèles ne se valent pas : Claude 4.5 produit un code de qualité, et Gemini 3 semble légèrement meilleur sur la qualité de rendu, un cran au-dessus de GPT-5 (mais cela peut vite changer dans les prochains mois...).

Dans tous les cas, il est particulièrement important de bien vérifier ce que génèrent les LLM, non seulement pour la propreté/maintenabilité du code, mais aussi pour s'assurer que toutes les contraintes du projet sont bien respectées.

On ne peut pas se fier au petit résumé que font souvent les LLM à la fin de leurs actions.

Ce comparatif était volontairement basé sur des prompts minimalistes, avec juste un screenshot ou un lien Figma.

Pour améliorer la génération de composants, plusieurs pistes sont envisageables :

  1. Donner quelques précisions dans le prompt sur des comportements attendus, voire faire une mini-spec du composant, plutôt que de fournir uniquement un screenshot ou un lien Figma.

  2. Lister succinctement (pour ne pas surcharger le contexte) les principales règles dans des cursorrules (répertoires principaux, accessibilité, mutualisation, bonnes pratiques).

  3. Mettre en place des "commandes" pour vérifier régulièrement l'accessibilité ou d'autres critères (genre /check-accessibility, /security-audit... cf. https://cursor.com/fr/docs/context/skills).

  4. Mettre en place un Design System pour mutualiser les composants de base (titres, champs de formulaire...) et dire explicitement au LLM de les utiliser.

Même si l'humain reste indispensable pour respecter un design précis, l'IA va certainement progresser encore dans les prochains mois. Les choses sont encore loin d'être parfaites, mais l'IA peut déjà faire gagner beaucoup de temps en générant une bonne partie du code. Si nous ne voulons pas que les IA nous remplacent, il faut en faire des alliés : les IA sont avant tout des OUTILS qui peuvent nous permettre de gagner en efficacité, à condition de bien les guider en optimisant le contexte et les prompts utilisés.

Cela fera probablement l'objet d'un prochain article sur Niji.tech ! ;)