Figma → Landing Page
Génère une page d'atterrissage promotionnelle statique et déployable à partir d'une maquette Figma : index.html + css/main.css + js/{tool,pm_main,main}.js + images/*.webp.
Commande : /figma-landing-page <lien Figma> [nom de la campagne] [répertoire de sortie]
Contrat fixe (à ne pas déroger en aucun cas) :
- Espaces réservés du modèle : exactement 3 :
__PAGE_TITLE__,__FUNCTION_NAME__(tous deux dans main.js, le titre apparaît également dans index.html),__PC_BASE__(dans tool.js ; 375 = uniquement image mobile ; 1920 = images mobile et PC). - Les éléments CTA doivent obligatoirement avoir la classe supplémentaire
.join-btn(contrat de sélecteur pour le JS fixe), en plus des classes BEM. - Point de rupture 576px unifié à trois endroits : branche JS rem, CSS
@media (min-width: 576px), détermination de la plateforme. - Normalisation px : mobile
px × 375 ÷ largeur image mobile ÷ 100 = rem; PCpx × 1920 ÷ largeur image PC ÷ 100 = rem. - Les trois fichiers JS du modèle (
tool.jspour l'adaptation rem,pm_main.jspour le pont postMessage,main.jspour la couche métier de la campagne, chargés dans cet ordre) ne doivent pas être modifiés d'un seul mot ; les interactions de la page ne doivent être insérées que sous le commentaire// === Page-specific interactions ===dansmain.js(à l'intérieur de l'IIFE, vous pouvez utiliser directement$p/pm/track/Date.prototype.format). - Règles détaillées (limites de découpe d'images, noms de classes, table d'inférence des interactions) dans
references/patterns.md, critères de livraison dansreferences/checklist.md— à lire avant la génération.
Étape 1 — Analyse de l'entrée et vérification de l'environnement
- Extraire la clé de fichier et l'ID de nœud du lien. Convertir les traits d'union en deux-points dans l'ID de nœud (
123-456→123:456) avant d'appeler toute API Figma ; si l'appel API renvoie une erreur 404 ou un résultat vide, vérifier d'abord cette étape. - Trois vérifications de l'environnement (si elles échouent, les corriger d'abord avant de continuer) :
- Figma MCP est connecté (sinon, guider l'utilisateur pour l'authentification, celle-ci ne compte pas comme l'interruption unique de la porte de confirmation). Appeler d'abord
whoami(exempté du quota) pour confirmer le siège : les sièges Viewer/Collaborator ou Starter n'ont que 6 appels MCP par mois — en cas de budget serré, ignorer MCP et passer directement à la route REST des étapes 2/4 (PAT stocké dans~/.figma_token, demander à l'utilisateur d'en générer un dans Figma Settings → Security, et de l'écrire dans un fichier sur son terminal pour éviter d'être conservé dans l'historique de discussion). which cwebp— si absent, informer l'utilisateur avecbrew install webp; si l'utilisateur refuse l'installation, toute la page utilise des images PNG en repli, et le mentionner dans le rapport de livraison.node -e "require('playwright-core')"— si absent, installer dans le répertoire scratchpad avecnpm i playwright-core; réutiliser le Chrome du système (channel: 'chrome'), ne pas télécharger le binaire du navigateur.
- Figma MCP est connecté (sinon, guider l'utilisateur pour l'authentification, celle-ci ne compte pas comme l'interruption unique de la porte de confirmation). Appeler d'abord
- Répertoire de sortie par défaut :
./output/<slug-nom-campagne>/(tous les artefacts de la compétence sont placés sousoutput/; si le nom de la campagne n'est pas fourni, l'inférer à partir du nom de la page/image Figma, et le vérifier à la porte de confirmation). Si le répertoire existe et n'est pas vide, ne pas interrompre maintenant — la confirmation d'écrasement fait partie du contenu de la porte de confirmation.
Étape 2 — Inventaire de la conception
- Utiliser un outil de métadonnées clairsemées (type get_metadata) pour lire l'arborescence des nœuds ; ne pas récupérer l'intégralité du contexte de conception de l'image racine en une seule fois.
- Lorsque MCP est indisponible/le budget est épuisé : REST
GET /v1/files/<key>/nodes?ids=<node>(sans profondeur = JSON complet de l'arborescence, comprenant le texte intégral, les polices, les valeurs originales des dégradés de remplissage, le bbox précis — plus d'informations que get_metadata). Stocker localement pour une analyse répétée, un seul appel suffit pour l'ensemble du processus ; les valeurs CSS (couleurs, dégradés, textes) sont directement extraites de ce JSON, sans utiliser get_code. - Identification des images : largeur ≤ 480 → image mobile ; ≥ 1200 → image PC ; les images non déterminables sont listées dans la porte de confirmation. Une seule image mobile →
__PC_BASE__ = 375; images mobile et PC →__PC_BASE__ = 1920. - Produire une liste d'actifs : liste des sections (hero, bannière, étapes, conditions…); chaque nœud est annoté comme image découpée / texte véritable / composant interactif (règles de détermination dans
references/patterns.md). - Marquer tous les CTA (boutons "Rejoindre maintenant" / "S'inscrire" / "Sign Up") — ils doivent recevoir la classe
.join-btn.
Étape 3 — Porte de confirmation (unique interruption avant la génération dans le flux normal)
Lister tout le contenu suivant dans un seul message pour obtenir la confirmation de l'utilisateur en une fois ; ne plus interrompre jusqu'à la livraison :
- Nom de la campagne, valeur de
__PAGE_TITLE__, valeur de__FUNCTION_NAME__(par exempleWinsdayBillionDropLandingPage) - Répertoire de sortie (confirmer l'écrasement si le répertoire n'est pas vide)
- Liste des images découpées (nœud →
images/<nom>.webp) - Liste des nœuds CTA
- Liste des interactions : chaque élément avec sa base d'inférence et les paramètres requis (compte à rebours → heure limite/comportement à l'expiration ; carrousel → lecture automatique/intervalle ; popup → moment de déclenchement ; voir
references/patterns.md). Si la maquette ne permet pas de déduire les paramètres, demander à l'utilisateur de les remplir ici ; les nœuds non classifiables sont marqués comme "statiques". - Éléments douteux concernant l'identification des images
Étape 4 — Exportation des images découpées (chaîne de repli à quatre niveaux, dégradation en fonction de la disponibilité)
- MCP
download_assets(lorsque le budget du siège est suffisant) : maximum 20 nœuds par lot, échelle 2x, format png ; télécharger les URL temporaires avec curl. - Rendu REST
GET /v1/images/<key>?ids=…&format=png&scale=2: ids en lots séparés par des virgules mais maximum 4 grands nœuds par lot (au-delà, signalement "Render timeout") ; 429 = budget de rendu du siège épuisé (les sièges Viewer déclenchent environ 12 images, fenêtre horaire), passer au niveau suivant, ne pas attendre inutilement. - Point de terminaison REST des images originales
GET /v1/files/<key>/images: renvoie la correspondance imageRef → URL de l'image originale pour tout le fichier, utilise le budget du fichier, presque jamais limité. Idéal pour tous les nœuds de remplissage d'image (photos/autocollants/icônes — lefills[].imageRefdans le JSON du nœud correspond à l'URL, obtenant une résolution originale souvent bien supérieure à 2x, à recadrer selon le mode d'échelle du remplissage/alpha, puis à redimensionner). Ne convient pas aux nœuds composites vectoriels (panneaux/bandeaux). - Exportation manuelle par l'utilisateur (zéro quota) : demander à l'utilisateur de sélectionner le nœud dans Figma et d'exporter. Privilégier le format SVG — les parties vectorielles sont infiniment nettes, les bitmaps sont intégrés en base64 à leur résolution originale (on peut extraire l'image
<image>par regex, ce qui est la meilleure source pour les éléments transparents). Pipeline de rastérisation SVG → bitmap 2x : copier le SVG dans un répertoire temporaire (nom de fichier kebab sécurisé, les noms originaux contiennent souvent&/espaces), écrire une enveloppe HTML<img src="./x.svg">dans le même répertoire (ouvrir directement un SVG avec file:// ou une référence file:// cross-directory sera refusée par Chrome), prendre une capture d'écran avec playwright endeviceScaleFactor:2+omitBackground:truepour obtenir un PNG transparent.
- Général : convertir en webp avec
cwebp -q 80; nommer en kebab-case sémantique, sans hash ; pour les nœuds purement dégradés/couleur unie, écrire directement le CSS à partir du JSON, sans générer d'image. - Attention : le viewBox d'un SVG exporté par Figma peut contenir des ombres portées/débordement (plus grand que le cadre du nœud) ; lors du positionnement du conteneur basé sur le cadre du nœud, laisser l'image déborder proportionnellement, ne pas l'écraser.
- Échec de l'exportation d'une image unique : réessayer 2 fois → passer au niveau inférieur de la chaîne ; sauter uniquement en cas d'échec de toute la chaîne, et l'enregistrer dans le rapport de livraison.
Étape 5 — Génération du code
- Démarrer à partir de
assets/template/: le contenu debase.csssert de squelette initial pourcss/main.css(le seul fichier CSS produit, pas de base.css séparé). index.html: remplacer<title>; changer le lien de police pour la police de la maquette (si Google Fonts ne trouve pas de correspondance exacte, choisir la plus proche et l'enregistrer dans le rapport) ; générer une structure sémantique par section dans#app, avec des classes BEM (.hero__bg,.banner__headline), et les éléments CTA avec la classe supplémentairejoin-btn.css/main.css: valeurs extraites des tailles/couleurs/dégradés précis de Figma (la sortie HTML+CSS simple de get_code peut aider à obtenir les valeurs), normaliser d'abord les px en rem ; arrière-plan avecbackground-image, images de contenu avec<img>. Pour les pages à double image : règles mobiles d'abord, couverture PC dans@media (min-width: 576px).js/: copier les trois fichiers du modèle (tool.js / pm_main.js / main.js), remplacer les 3 espaces réservés (__PC_BASE__dans tool.js, les deux autres dans main.js) ; insérer le code d'interaction confirmé sous le marqueur dans main.js.- Les éléments dont le débordement dépasse le bord de l'image (bbox dépasse la largeur de l'image) doivent avoir un conteneur avec
overflow: hiddenpour reproduire le recadrage de l'image, sinon la page déborde horizontalement. - Auto-contrôle :
node --check js/*.jsdoit réussir pour les trois fichiers.
Étape 6 — Itération de comparaison par captures d'écran (par sections, maximum 3 cycles)
- Démarrer un serveur local dans le répertoire de sortie :
python3 -m http.server <port>. - Écrire le script de capture suivant dans le scratchpad et l'utiliser pour capturer par sections (coordonnées de découpage obtenues depuis le DOM :
page.evaluatepour chaque élément de section avecgetBoundingClientRect) :
// shot.mjs <url> <out.png> <width> <dsf> [clipY clipH]
import { chromium } from 'playwright-core';
const [url, out, width, dsf, clipY, clipH] = process.argv.slice(2);
const browser = await chromium.launch({ channel: 'chrome' });
const page = await browser.newPage({
viewport: { width: +width, height: 800 },
deviceScaleFactor: +dsf,
});
await page.goto(url, { waitUntil: 'networkidle' });
await page.screenshot(clipY === undefined
? { path: out, fullPage: true }
: { path: out, clip: { x: 0, y: +clipY, width: +width, height: +clipH } });
await browser.close();
- Comparaison mobile : local width 375, dsf 2 ; côté Figma, utiliser
download_assetspour exporter par section en 2x png comme image de comparaison (les images de comparaison sont mises dans le scratchpad, pas dansimages/). - Comparer côte à côte section par section, corriger chaque différence ; maximum 3 cycles, si des différences persistent, les enregistrer dans le rapport de livraison.
- Une fois la convergence atteinte, faire une rapide régression sur l'ensemble de la page à width 414 (dsf 2) pour confirmer l'absence de décalage/débordement (le checklist exige les deux tailles 375/414).
- Les captures d'écran de l'image entière ne sont utilisées que pour l'apparence du rapport de livraison, en aucun cas comme base de décision de différence (une longue page entière serait sous-échantillonnée, rendant les tailles de police/différences de couleur invisibles).
- Pour les pages à double image : répéter la comparaison par sections ci-dessus avec width 1920, dsf 1 pour la mise en page PC (sur l'image exportée en 1x pour l'image PC) ; faire une rapide régression sur l'ensemble de la page à width 1280 (le checklist pour double image exige 1280/1920).
- Vérifier au passage : aucune erreur dans la console du navigateur (
page.on('console')ou les outils de développement).
Étape 7 — Livraison
Le rapport de livraison contient :
- L'arborescence du répertoire de sortie
- Les résultats du
references/checklist.md, point par point - Les différences connues restantes (non résolues en 3 cycles)
- Les chemins des captures d'écran de comparaison par sections
- Les replis utilisés (png au lieu de webp, polices approximatives, images découpées ignorées)
Aide-mémoire pour la gestion des erreurs
| Scénario | Traitement |
|---|---|
| Figma MCP non connecté / authentification invalide | Guider l'utilisateur pour l'authentification, puis reprendre à l'étape interrompue (ne compte pas comme interruption de la porte de confirmation) |
| node-id appel API 404 / vide | Vérifier la conversion trait d'union → deux-points |
| Échec d'exportation d'image / limitation 429 | Réessayer 2 fois → passer au niveau inférieur de la chaîne (voir Étape 4) → si toujours en échec, sauter + enregistrer dans le rapport |
| cwebp manquant et utilisateur refuse l'installation | Repli vers les artefacts images/*.png + enregistrer dans le rapport |
| Structure d'image non identifiable | Inclure dans la porte de confirmation et demander à l'utilisateur (ID de nœud spécifique requis) |
| Répertoire de sortie non vide | Confirmer l'écrasement lors de la porte de confirmation |