figma-spec

Par figma · mcp-server-guide

Cette compétence est requise pour créer, lire, modifier, réviser ou commenter des specs Figma. Vous devez la lire lorsque vous travaillez sur un PRD, un brief, un RFC ou tout type de document, que ce soit dans une spec Figma autonome ou une spec Figma intégrée dans un fichier Figma Design ou Figjam.

npx skills add https://github.com/figma/mcp-server-guide --skill figma-spec

Travailler avec une spec Figma

Vous DEVEZ toujours appeler whoami avant d'utiliser une API figma.spec.* et confirmer que le plan du fichier cible (ou le plan de destination pour un nouveau fichier) a specs_enabled: true. whoami n'identifie pas quel plan possède un fichier. Si le plan n'est pas clair, vous DEVEZ demander à l'utilisateur ; ne l'inférez jamais à partir de la clé du fichier ou du plan d'un autre. Si specs_enabled est false ou absent pour ce plan, expliquez que Specs n'est pas disponible et arrêtez le workflow.

Une spec Figma native est du Markdown saveur GitHub (GFM) sous un nœud SPEC_BLOCK. Une spec Figma autonome ne contient qu'une spec ; un fichier FigJam ou Design peut en contenir plusieurs intégrées.

Découvrir et choisir la spec Figma

Résolvez une URL node-id fournie si elle est présente avec figma.getNodeByIdAsync et exigez type === "SPEC_BLOCK" plus specBlockType === "DOCUMENT". Sinon, cherchez sur la page courante avec findAllWithCriteria({ types: ['SPEC_BLOCK'] }), en filtrant sur specBlockType === "DOCUMENT" (et en examinant le contenu avec figma.spec.getContent si nécessaire) jusqu'à trouver votre cible. Si elle n'est pas sur la page courante, chargez d'autres pages une à une avec page.loadAsync() et répétez votre requête, en vous arrêtant une fois la cible résolue.

Passez l'ID racine résolu à chaque appel de contenu. Omettez specNodeId uniquement si le fichier est connu pour contenir exactement une spec Figma ; l'omission lève une erreur sinon. Ne modifiez jamais les nœuds de texte ordinaires du canvas en secours.

Créer une spec Figma sur un canvas

// Crée une spec Figma intégrée sur un canvas Design ou FigJam (pas un fichier spec Figma autonome).
const { specNodeId } = await figma.spec.createOnCanvasAsync({
  title: 'Untitled spec',
  content: '# Title\n\nA paragraph.\n',
})

const specNode = await figma.getNodeByIdAsync(specNodeId)
if (!specNode) throw new Error('The created Figma spec could not be resolved')

const after = await figma.spec.getContent({ specNodeId })
if (!after.markdown.includes('A paragraph.')) {
  throw new Error('The new Figma spec content was not applied')
}

Passez toujours un title non vide et une chaîne content ('' est autorisé). title nomme la racine ; incluez tout # H1 désiré dans content.

Méthodes de contenu

// LECTURE — retourne specNodeId, markdown, title, etc.
// Le corps est `markdown`, pas `content`.
const before = await figma.spec.getContent({ specNodeId: chosenSpec.id })
const page = await figma.spec.getContent({
  specNodeId: before.specNodeId,
  offset: 100,
  maxLines: 50,
})

// REMPLACER — efface + recrée le document ; utiliser seulement pour un premier brouillon vide.
await figma.spec.setContent({
  specNodeId: before.specNodeId,
  content: '# Title\n\nA paragraph.\n',
})

// ÉDITER — chercher/remplacer ; chaque oldText doit correspondre exactement une fois.
await figma.spec.editContent({
  specNodeId: before.specNodeId,
  edits: [{ oldText: 'First paragraph.', newText: 'Edited first paragraph.' }],
})

const after = await figma.spec.getContent({ specNodeId: before.specNodeId })
if (!after.markdown.includes('Edited first paragraph.')) {
  throw new Error('The targeted Figma spec edit was not applied')
}
  • Utilisez getContent avec le même specNodeId avant les éditions et pour vérifier les écritures ; ne vous fiez PAS aux captures d'écran.
  • Optez par défaut pour editContent sûr en contexte collaboratif et chirurgical.
  • Utilisez setContent destructeur seulement pour un premier brouillon vide ou un remplacement de document complet explicite.

Règles critiques

  1. editContent exige exactement une correspondance. Zéro ou plusieurs correspondances oldText échouent sans modification. Ajoutez du contexte environnant pour le rendre unique.
  2. Passez le Markdown comme chaînes simples. Ne l'encodez jamais avec Buffer/base64 ni ne le décodez avec atob(). Base64 est réservé aux données d'images dans les URLs de données intégrées en Markdown.
  3. Gardez Markdown et traversée séparés. figma.spec.* gère le contenu ; la traversée de nœuds expose seulement les racines de document et les branches de canvas intégré.
  4. Préservez les marqueurs de commentaire. Gardez les paires [comment:<uuid>]…[/comment:<uuid>] qui se chevauchent inchangées autour du même texte, sinon le thread peut se détacher ou disparaître. En cas de doute, copiez l'intervalle marqué exactement et modifiez autour.
  5. Utilisez des références portables. Les specs Figma partagées doivent utiliser des liens comme les permaliens GitHub, jamais les chemins locaux à la machine ou les URLs localhost.

Style

  • Gardez le bloc de titre en premier et formaté comme H1, même si son texte est vide. Ne le supprimez jamais ni n'insérez de blocs avant lui.
  • Préférez le texte gras dans la ligne d'en-tête du tableau.
  • Utilisez <ins> pour le soulignement, y compris le formatage combiné : <ins>**gras et souligné**</ins>. N'utilisez pas <u>, qui ne fonctionne que dans les imports HTML.

Images

Les images utilisent la syntaxe GFM pour les images à l'intérieur de setContent ou editContent :

  • ![alt](data:image/png;base64,...) intègre les octets qui sont décodés et uploadés.
  • ![alt](https://host/img.png) est récupéré côté serveur ; les hôtes non autorisés sont rejetés.

getContent émet les URLs d'images comme https://<host>/spec/<fileKey>/image/<sha>?w=<width>&h=<height>.

Commentaires

Utilisez figma.spec.comments.* pour les threads ancrés. Préférez les commentaires plutôt que de laisser des éditions silencieuses si vous avez un doute sur une modification.

const comment = await figma.spec.comments.create({
  specNodeId: before.specNodeId,
  anchorText: 'le texte rendu exact auquel l\'ancrer', // DOIT apparaître exactement une fois
  contextText: 'une sous-chaîne unique plus longue contenant anchorText', // optionnel ; désambiguïse les répétitions
  message: 'Corps du commentaire (markdown).',
})

const { root, replies, hasMore } = await figma.spec.comments.getThread({ uuid: comment.uuid })
await figma.spec.comments.reply({ uuid: comment.uuid, message: 'Une réponse.' })
  • anchorText doit correspondre exactement une fois dans la spec Figma rendue. Utilisez un contextText plus long le contenant pour désambiguïser le texte répété.
  • getThread et reply exigent l'UUID du commentaire racine exposé par un marqueur [comment:<uuid>] ; ne passez jamais l'UUID d'une réponse à reply.

Skills similaires