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.
Au premier abord, convertir le design d'une page web entière, voire d'un site complet peut paraître intéressant à plusieurs niveaux :
Gain de temps : toute la page serait générée en 1 prompt.
Vision globale : cela permet d'avoir une vue d'ensemble de ce qui est mutualisable ou non.
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.
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 :
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 :
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.
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 ^^
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).
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 :
En local : https://developers.figma.com/docs/figma-mcp-server/local-server-installation/
En remote : https://developers.figma.com/docs/figma-mcp-server/remote-server-installation/
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".
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...
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 :
le screenshot (propre mais difficile à "voir" correctement par les LLM),
le code HTML Figma (moche et pas toujours fidèle, à part les codes couleurs)
son expérience pour "deviner" les interactions, le responsive et les animations (ou au moins poser les bonnes questions)
le framework JS que l'on souhaite avoir en sortie (React, Vue, Angular...)
le styling (CSS, Tailwind, ShadCN...)
Test avec GPT-5
GPT-5 a récupéré le code Figma et les variables Figma
ainsi que le screenshot du composant :
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.
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...).
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).
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).
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).
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.
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...) :
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).
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 :
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...).
Le résultat est beaucoup plus propre et maintenable :
Avec Gemini 3 Pro
Gemini m'a lui aussi posé des questions très pertinentes.
Il m'a alors généré un formulaire encore plus proche de la maquette du premier coup, avec des composants mutualisés également.
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.
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é.
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):
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 ^^'
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 :
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.
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 :
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.
Lister succinctement (pour ne pas surcharger le contexte) les principales règles dans des cursorrules (répertoires principaux, accessibilité, mutualisation, bonnes pratiques).
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).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 ! ;)





