Figma Bridge
Figma ne dispose pas d'API publique d'écriture. Cette compétence utilise un pont local : des opérations nommées via HTTP, exécutées dans Figma par un plugin, via l'API Plugin Figma. Pas d'OAuth, pas de jetons.
Dépôt : https://github.com/iggypcnfsky/figma-bridge — AGENTS.md, docs/ops-reference.md.
Préconditions — à vérifier avant toute action
figma est dans le PATH, donc ne cherchez jamais le dépôt dans le système de fichiers :
figma doctor # dépôt, serveur, fenêtres connectées, img-forge + clé FAL en une commande
figma clients # id, fichier, page de chaque fenêtre Figma connectée
figma rules # contraintes du projet : type floor, grille, taille de cadre, nommage de version
Lisez figma rules avant de concevoir. Il contient les limites non évidentes — par ex. « Poppins 20/25 est le minimum » — qu'aucune lecture du canevas ne vous révélera. Considérez "confirmed": false comme une hypothèse à vérifier avec l'utilisateur, et {} comme « demandez, n'inventez pas ».
Si la commande est manquante, utilisez node "$(figma where)/server.mjs" seulement après avoir demandé ; ne faites pas de find du dépôt et ne devinez pas les chemins.
pluginConnected: false→ arrêtez. Demandez à l'utilisateur d'exécuterPlugins → Development → Figma Bridgedans la fenêtre du fichier qu'il souhaite modifier. Réessayer ne sert à rien.503de/runsignifie la même chose.504 PLUGIN_GONEsignifie qu'ils ont fermé la fenêtre du plugin.409signifie que plusieurs fenêtres Figma sont connectées et qu'aucune n'a été choisie. Sélectionnez le fichier nommé par l'utilisateur (--file <NOM>) ou un identifiant client (--client <ID>) ; ne réessayez jamais aveuglément, sinon vous risquez de modifier le mauvais fichier.
La boucle
- Orientez-vous.
./bin/figma status→ nom du fichier, page courante, sélection, toutes les pages. - Lisez.
selection 2,node <id> 2,find {"name":"Header","allPages":true}. Ne devinez jamais unnodeId— les identifiants Figma ressemblent à4022:2et ne sont pas dérivables. - Planifiez. Déterminez le parent, la taille, l'ordre. Les nouveaux nœuds vont sur la page courante sauf si
parentIdest fourni. - Écrivez.
./bin/figma run '[{...},{...}]'. - Vérifiez.
./bin/figma export <id> out/check.png PNG 2et regardez réellement l'image.
Commandes
./bin/figma op '{"op":"status"}'
./bin/figma run '[{"op":"createFrame","name":"Card","width":320,"height":200,"fill":"#0B0B0F",
"props":{"cornerRadius":16,"layoutMode":"VERTICAL","paddingTop":24,"paddingLeft":24,"itemSpacing":12}}]'
./bin/figma run '[{"op":"createText","parentId":"12:34","characters":"Title","fontSize":24,"color":"#FFFFFF"}]'
./bin/figma op '{"op":"varFill","nodeId":"12:34","variableName":"color/bg/surface"}'
./bin/figma export 12:34 out/card.png PNG 2
./bin/figma image 12:34 out/cover.png FILL # fichier image local → remplissage (pas de cloud)
Ops : ping status pages variables styles fonts inventory · selection node find · createFrame createRect createEllipse createText createPage createInstance · update clone reparent remove goto group ungroup select · grids setGrids align distribute effects · applyStyle varFill · export imageFill · exec.
Paramètres complets : docs/ops-reference.md.
Raccourcis utiles pour le travail de design :
- grid signifie GRILLE : quand l'utilisateur dit « mettre une grille », il veut la grille de mise en page carrée, pas des colonnes :
{"op":"setGrids","nodeId":"…","grid":true}(cellules de 40 px, 40 % par défaut) ou"grid":40. Utilisezcolumns/rowsseulement s'ils parlent de colonnes, d'une grille à 12 colonnes, ou donnent des valeurs de gouttière/marge. Ne simulez jamais une grille avec des rectangles ;applyStyleaveckind:"grid"applique un style de grille enregistré. - lignes d'éléments : construisez-les, puis
{"op":"align","nodeIds":[…],"mode":"TOP"}et{"op":"distribute","nodeIds":[…],"axis":"HORIZONTAL","gap":24}. - profondeur :
{"op":"effects","nodeId":"…","shadow":{"y":8,"blur":24,"color":"#00000033"}}ou{"op":"effects","nodeId":"…","blur":{"type":"BACKGROUND","radius":20}}. - dégradés :
{"op":"gradient","nodeId":"…","kind":"linear","angle":135,"stops":[[0,"#8B76FF"],[1,"#0E0E12"]]}— l'angle 0 est de gauche à droite, 90 de haut en bas. Ne simulez jamais un dégradé avec des rectangles empilés. - système de design :
createInstanceavec un idCOMPONENT, puisinstancePropspour les variantes (lisez d'abord les noms) etinstanceTextpour changer le texte sans détacher ;applyStylepour les styles. Ne redessinez pas ce que la bibliothèque fournit déjà et ne détachez pas une instance pour « corriger » son texte. - vérifications d'espacement :
{"op":"measure","a":"1:2","b":"1:3"}retourne les écarts par côté et la distance centrale ; utilisez-le plutôt que d'exporter une capture d'écran pour juger de l'alignement. - styles :
saveStylecrée ou met à jour un styletext/paint/effect/gridpar nom, etapplyStylel'applique. Créez le jeton une fois, appliquez-le partout. - responsive :
sizingdéfinitHUG/FILL/FIXEDpar axe plus min/max ;constraintscouvre les enfants non-auto-layout (STRETCH/MIN/MAX/CENTER/SCALE). Lisez les deux depuisnodeavant de les modifier —sizingretourneskippedavec la raison de Figma quand une propriété ne s'applique pas.
Images
Besoin d'illustrations ? Générez-les avec le CLI img-forge frère
(https://github.com/iggypcnfsky/img-forge), puis placez-les — la génération reste en dehors de Figma pour que la clé API n'entre jamais dans le code du plugin et qu'un rendu lent ne bloque pas le canevas :
cd ../img-forge
./img gen --prompt "fond dégradé abstrait, violet à noir" --preset 16:9@2k --out out/cover.png
./img edit --prompt "transforme-le en nuit avec accents néon" --ref out/cover.png # ou modifier un actif existant
cd ../figma-bridge
./bin/figma image 12:34 ../img-forge/out/cover.png FILL
FILL recadre sur le nœud, FIT ajoute des boîtes aux lettres, TILE répète, CROP respecte le recadrage existant.
Pour modifier ce que l'utilisateur a sélectionné, exportez-le d'abord (./bin/figma export <nodeId> out/sel.png PNG 2) et passez ce fichier comme --ref.
La fenêtre du plugin dispose également d'un panneau Générer / Modifier pour les humains (modèle, préréglages de taille, coût, insérer).
Ne pilotez pas le panneau par programmation — utilisez le CLI ; il expose plus (masque, variantes, simulation).
Les préréglages enregistrés dans ce panneau vivent dans figma-bridge/presets.json.
Construire sur une ébauche existante
Une ébauche qui « n'est pas finie » encode quand même des décisions : ce qui est à côté de quoi, ce qui est groupé, l'ordre des éléments, le rythme d'espacement. Lisez-la avant de concevoir, puis conservez-la.
{"op":"inventory"}— les cadres, leurs tailles et les statistiques typographiques.{"op":"structure","nodeId":"<cadre>"}— enfants regroupés en lignes avec espacements et unreadingOrder; c'est le groupement choisi par l'auteur.{"op":"node",…,"depth":2}donne le même arbre avec plus de profondeur.- Notez le motif (une marge gauche qui se répète, un titre qui se trouve toujours au-dessus de trois colonnes) et conservez-le. Modifiez ce que la demande nécessite, laissez le reste là où il est.
- Signalez les écarts que vous avez faits — « déplacé le pied de page vers le haut de 40 px », pas seulement « amélioré la mise en page ».
Ne normalisez jamais une ébauche silencieusement. Si la cohérence nécessite de déplacer des éléments que l'utilisateur a placés, dites-le et demandez ; une diapositive soignée qui a perdu leurs groupements est une régression, pas une amélioration.
Règles
- Lire avant d'écrire. Minimum deux appels : inspecter, puis modifier.
- Un lot = une pensée. Une opération ne peut pas référencer le résultat d'une opération précédente, donc si vous avez besoin de l'
iddu nouveau nœud, divisez en deux appels. - Respectez la disposition héritée : l'ordre des frères, la proximité et le groupement sont une intention. Ne réorganisez pas une ébauche pour la rendre plus nette sauf demande ; demandez d'abord quand la cohérence déplacerait leurs éléments.
- Ne touchez jamais aux calques existants de l'utilisateur (
update,remove,reparent) sans instruction explicite. Préfixez vos propres créations :Bridge / …. - Une refonte se place juste à côté de l'original, aussi proche que possible. Si on vous demande de refaire une diapositive/écran/section : dupliquez-la, appelez
{"op":"placeNear","nodeId":"<nouvel id>","move":true,"gap":80,"name":"Bridge / v2 — <nom>"}pour que la copie atterrisse sur le premier côté libre au lieu d'une coordonnée devinée, et laissez l'original intact. Si l'outil signalefree: false, demandez où elle doit aller. Remplacez les éléments sur place seulement quand l'utilisateur le demande explicitement. gotomodifie la vue de l'utilisateur — seulement sur demande.execest un dernier recours. Cela fonctionne (le bac à sable de Figma autorisenew Function) et contourne toute validation de paramètres. Retournez uniquement des valeurs sérialisables en JSON.- Nettoyez les artefacts de test, ou demandez s'il faut les conserver.
Pièges
- Utilisez
localhost, jamais127.0.0.1: le manifeste du plugin n'autorise quehttp://localhost:3847(devAllowedDomains) ; Figma rejette les IP. Le serveur écoute à la fois sur127.0.0.1et::1. figma.currentPageest la page ouverte dans cette fenêtre Figma — pas un pointeur sauvegardé. Changer d'onglet modifie ce que vous voyez à l'appel suivant.- Les positions sont relatives au parent, et un
parentIdomis signifie la page courante. - Les questions typographiques (polices, tailles, nombres) se font en un appel :
{"op":"fonts"}; ajoutez"allPages":truepour tout le fichier. Ne parcourez pas les cadres avec votre propre script. - Un aperçu du jeu de diapositives se fait aussi en un appel :
{"op":"inventory"}retourne chaque cadre avec sa géométrie,minFontSize, polices, nombre de grilles et remplissages — assez pour choisir « les cadres 11–19 » ou trouver un texte en dessous d'une taille minimale. - N'indexez jamais un champ que la référence ne liste pas.
summarycontientfont,fontSize,lineHeightetletterSpacingpour TEXT ; tout le reste vient deexecavec le nom réel de l'API. Les styles mixtes sont la chaîne"MIXED", donc protégez avec.get()et des valeurs de repli. - Un rectangle ne peut pas avoir d'enfants ; utilisez un cadre quand du texte ou des icônes doivent être à l'intérieur d'une forme.
- Pas de variables locales →
variablesretournecollections: []etvarFilléchoue. Vérifiez d'abord. - Le texte a besoin d'une police :
createTextla charge vialoadFontAsync; si la famille est manquante, utilisezInter. exportplafonne à 8 Mo — réduisezscaleau lieu de réessayer.- Lire les enfants d'une page non courante nécessite
loadAllPagesAsync; le pont réessaie une fois automatiquement, mais préférezfindavecallPages: true. - Après avoir modifié les fichiers du plugin (
code.js,ui.html), l'utilisateur doit relancer le plugin ; les modifications demanifest.jsonnécessitent une réimportation.