Koobiq Icons Figma Audit

Valide qu'un composant d'icône Figma est organisé correctement avant de l'exporter depuis le fichier d'icônes Koobiq (figma:sync / figma-export). Vérifie le type de nœud, le format du nom, la taille, la disposition, la structure racine shape/shape-2, les contraintes d'échelle, le contrat de couleur de remplissage et les métadonnées de description — et vérifie que les variantes de taille de la même icône concordent entre elles. Utilisez-le chaque fois que l'utilisateur souhaite vérifier, examiner, valider ou « проверить » un composant d'icône nouvellement dessiné ou non publié par rapport aux conventions de la bibliothèque, ou demande si une icône est prête à être exportée — même s'il ne colle qu'un lien Figma ou un nom d'icône. Exécutez-le avant figma:sync lors de l'ajout ou de la modification d'icônes.

Qu'est-ce que Koobiq Icons Figma Audit ?

Cette compétence effectue un audit structuré des composants d'icônes dans le fichier Figma Koobiq icons pour garantir leur conformité avec les conventions de la bibliothèque avant l'exportation via la pipeline figma:sync / @figma-export. Elle vérifie systématiquement : le type de nœud et le format du nom (expression régulière, lettres minuscules, pas de traits d'union doubles, suffixe de taille valide), la géométrie et la disposition (pas de mise en page automatique, taille carrée fixe, clip content désactivé), la structure racine (un enfant shape pour les icônes monochromes, shape et shape-2 pour les bicolores, pas de nœuds superflus), les contraintes d'échelle (scale sur les deux axes), le contrat de couleur de remplissage (la variable Icon/Contrast liée pour la forme primaire, #E21D03 ou variable Icon/Error pour la forme secondaire), et la métadonnée de description. L'audit est en lecture seule par défaut, et nécessite le MCP Figma connecté avec les compétences get_metadata, use_figma et get_screenshot. Il utilise des identifiants de page prédéfinis pour les pages de taille (16, 24, 32, 48, 64) afin d'éviter les allers-retours de découverte de page. Les lectures parallèles sont autorisées uniquement avant toute modification Figma, et des gardes de changement de page sont utilisées pour éviter les interférences de contexte. Le résultat de l'audit est un tableau de bord réussite/échec avec des constats spécifiques et exploitables, et les corrections ne sont proposées que si l'utilisateur le demande explicitement.

Compatible avec~Claude Code~Codex CLI~Cursor
Part ofMobile
npx skills add https://github.com/rmnturov/koobiq-icons-figma-audit-skill/tree/HEAD

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Que fait Koobiq Icons Figma Audit ?

Cette compétence vérifie qu'un composant d'icône dans le fichier Figma des icônes Koobiq suit les conventions structurelles de la bibliothèque, afin que figma:sync (la pipeline @figma-export) produise un SVG propre et correct. Détecter les problèmes dans Figma est bien moins coûteux que de les découvrir après l'exportation, car l'exportation transforme silencieusement tout ce qu'il trouve — un nom de calque erroné, un nœud supplémentaire ou une coordonnée hors grille devient un SVG cassé sans erreur.

Il s'agit d'un audit en lecture seule par défaut : inspectez, puis rapportez une liste de contrôle claire réussite/échec avec des constatations spécifiques et exploitables. Ne modifiez le fichier Figma que si l'utilisateur vous demande explicitement de corriger quelque chose (voir « Proposer des corrections »).

Prérequis

  • Le MCP Figma doit être connecté. Cette compétence l'utilise via get_metadata (aperçu de la structure), use_figma (inspection précise via l'API du Plugin) et get_screenshot (vérification visuelle de cohérence).

  • Avant tout appel use_figma, chargez la compétence figma-use — elle documente les règles de l'API du Plugin et évite les échecs courants et difficiles à déboguer.

  • La clé du fichier et les pages de taille sont fixes (vérifiées par rapport au document en direct). Pour sauter un aller-retour de découverte de page, accédez directement à une page par son identifiant de nœud :

    tailleidentifiant du nœud de la page
    161320:17387
    2442149:860
    3242149:862
    4842149:861
    6442149:863

    Clé du fichier : WvUarBj8tO256vML4PkBLl. Chaque nom de page est le suffixe de taille ; une icône nommée foo_24 se trouve sur la page 24. Document : https://www.figma.com/design/WvUarBj8tO256vML4PkBLl/%F0%9F%9F%A5-koobiq-%C2%B7-icons?node-id=1320-17387

    • Cette clé de fichier est la source de vérité — elle correspond à config.mjs. Le lien « Draw an icon » dans packages/icons/README.md pointe vers un fichier différent et erroné — ignorez-le et faites confiance à la clé ci-dessus.
    • get_metadata sans nodeId liste uniquement la première page (ICONS, qui ne contient aucun composant d'icône) — elle n'énumère pas les pages de taille. Ne l'utilisez pas pour la découverte de pages ; utilisez les identifiants de nœud ci-dessus.

Si le fichier est inaccessible

Si un appel Figma échoue — erreur d'authentification/de permission, « le nœud n'existe pas », un fichier vide/inattendu, ou le MCP ne répond pas — arrêtez-vous et signalez-le à l'utilisateur au lieu de deviner. Dites-lui ce qui a échoué et demandez-lui de :

  • fournir un lien Figma différent / correct (la clé du fichier dans config.mjs peut être obsolète, ou il a collé un lien vers un autre fichier ou une branche), ou
  • revérifier le FIGMA_TOKEN dans le .env du dépôt (le jeton d'accès figma-export / MCP peut être manquant, expiré ou révoqué), ou
  • confirmer que son compte Figma a accès au fichier (il s'agit d'un fichier de conception privé — il peut avoir besoin d'être invité ou d'utiliser un jeton lié à un compte disposant des autorisations).

N'inventez pas un résultat d'audit à partir d'hypothèses ; une vérification n'a de sens que par rapport au fichier en direct.

Lectures parallèles et contexte de page

Les appels de lecture Figma peuvent être exécutés en parallèle, mais seulement avant la première modification Figma de la tâche. Après le début d'une modification, exécutez les appels Figma un par un.

Les lectures parallèles qui changent de page peuvent interférer les unes avec les autres. Lors d'une exécution observée, une lecture ciblant la page 24 a renvoyé les données de la page 16 (le même nombre de composants, des noms erronés), et l'audit a signalé les variantes 24px comme manquantes. Protégez chaque lecture qui change de page :

// À utiliser dans chaque lecture qui change de page. Renvoie les données uniquement pour les nœuds appartenant à PAGE_ID.
const PAGE_ID = "42149:860";   // identifiant du nœud de la page du tableau ci-dessus
const NAMES = ["foo_24"];       // noms des composants à rechercher
const page = await figma.getNodeByIdAsync(PAGE_ID);
await figma.setCurrentPageAsync(page);
if (figma.currentPage.id !== PAGE_ID) throw new Error("inadéquation du contexte de page avant la lecture");
const pageOf = (n) => { let p = n; while (p && p.type !== "PAGE") p = p.parent; return p; };
const hits = figma.currentPage
  .findAllWithCriteria({ types: ["COMPONENT", "COMPONENT_SET"] })
  .filter((n) => NAMES.includes(n.name) && pageOf(n) && pageOf(n).id === PAGE_ID)
  .map((n) => ({ name: n.name, id: n.id, w: n.width, h: n.height }));
if (figma.currentPage.id !== PAGE_ID) throw new Error("le contexte de la page a changé pendant la lecture");
return { pageId: PAGE_ID, hits };

Si une garde lève une exception, rejetez ce résultat et réexécutez la lecture. Une affirmation de « manquant » (par exemple, « aucune variante 24px ») doit reposer sur une lecture protégée de cette page, ou sur une recherche par identifiant de nœud. Ne signalez jamais l'absence à partir d'une lecture qui a levé une exception ou d'une page que vous n'avez pas vérifiée.

Étape 1 — Résoudre la cible

L'utilisateur peut vous donner l'un des éléments suivants :

  • Une URL ou un identifiant de nœud Figma (par exemple node-id=44731-6643) → inspectez exactement ce nœud, puis recherchez également ses variantes de taille sœurs par nom pour la vérification croisée des variantes.
  • Un nom d'icône (par exemple floating-window, ou floating-window_16) → trouvez chaque variante de taille sur les pages d'icônes et vérifiez-les toutes. Les nouvelles icônes sont souvent non publiées et peuvent même être sans nom, donc si une correspondance de nom échoue, listez les composants sur la ou les pages pertinentes et demandez à l'utilisateur de pointer le nœud, ou inspectez par identifiant de nœud.

Les noms de page sont égaux au suffixe de taille. Balayage des tailles : vérifiez les cinq pages (16 / 24 / 32 / 48 / 64) pour chaque nom demandé, car une icône peut exister dans des tailles que l'utilisateur n'a pas mentionnées. Utilisez les identifiants de nœud de page du tableau Prérequis, un appel use_figma par page, chacun avec la garde de « Lectures parallèles et contexte de page ». Exécutez-les en parallèle uniquement avant toute modification Figma. Signalez le résultat sous forme de tableau (nom × taille → identifiant de nœud ou manquant).

Étape 2 — Inspecter

Exécutez ce script en lecture seule (adaptez les cibles/l'identifiant de page). Il renvoie tout ce dont les règles ci-dessous ont besoin. Associez-le à une get_screenshot pour pouvoir confirmer que le glyphe s'affiche réellement.

// Collez dans use_figma (skillNames: "figma-use"). Définissez PAGE_ID et NAMES.
// Identifiants des nœuds de page : 16=1320:17387  24=42149:860  32=42149:862  48=42149:861  64=42149:863
const PAGE_ID = "1320:17387";      // page dont le nom est la taille, par ex. "16"
const NAMES = ["floating-window_16"]; // nom(s) de composant(s) à auditer sur cette page
figma.skipInvisibleInstanceChildren = false; // false : la règle G doit également voir les calques cachés
const page = await figma.getNodeByIdAsync(PAGE_ID);
await figma.setCurrentPageAsync(page);
if (figma.currentPage.id !== PAGE_ID) throw new Error("inadéquation du contexte de page avant la lecture");

const toHex = (c) => {
  const h = (n) => Math.round(n * 255).toString(16).padStart(2, "0").toUpperCase();
  return "#" + h(c.r) + h(c.g) + h(c.b);
};
const describeFill = (n) => {
  if (!n.fills || n.fills === figma.mixed) return n.fills === figma.mixed ? "MIXED" : null;
  return n.fills.filter((f) => f.visible !== false).map((f) => ({
    type: f.type,
    hex: f.type === "SOLID" ? toHex(f.color) : undefined,
    opacity: f.opacity,
    boundVar: f.boundVariables && f.boundVariables.color ? f.boundVariables.color.id : null,
  }));
};

const pageOf = (n) => { let p = n; while (p && p.type !== "PAGE") p = p.parent; return p; };
const all = page.findAllWithCriteria({ types: ["COMPONENT", "COMPONENT_SET"] })
  .filter((n) => pageOf(n) && pageOf(n).id === PAGE_ID);
const report = [];
for (const name of NAMES) {
  const c = all.find((x) => x.name === name);
  if (!c) { report.push({ name, found: false }); continue; }
  report.push({
    name: c.name, id: c.id, type: c.type,
    width: c.width, height: c.height, x: c.x, y: c.y,
    layoutMode: c.layoutMode,
    clipsContent: c.clipsContent,
    description: c.description,
    children: c.children.map((ch) => ({
      name: ch.name, type: ch.type,
      w: ch.width, h: ch.height, x: ch.x, y: ch.y,
      constraints: ch.constraints,
      fills: describeFill(ch),
      styles: { fill: ch.fillStyleId, stroke: ch.strokeStyleId, effect: ch.effectStyleId },
      boundVariableFields: ch.boundVariables ? Object.keys(ch.boundVariables) : [],
    })),
  });
}
if (figma.currentPage.id !== PAGE_ID) throw new Error("le contexte de la page a changé pendant la lecture");
return report;

Pour valider le contrat de couleur de manière fiable, lisez également une icône sœur de bonne qualité de la même taille (par exemple list_16) de la même manière et comparez la clé de la variable liée de la forme primaire (Règle D). La couleur hexadécimale nominale du contrat et la valeur réellement stockée dans le fichier diffèrent (voir Règle D), donc une comparaison avec un voisin réel est plus fiable que la correspondance avec un hexadécimal littéral.

Étape 3 — Vérifier par rapport aux règles

Signalez chaque élément comme ✅ réussi / ❌ échoué avec la valeur observée et, en cas d'échec, ce qu'elle devrait être.

A. Type de nœud et nom

  • Le nœud est un COMPONENT (ou un COMPONENT_SET de variantes de taille), pas un FRAME, GROUP ou INSTANCE. Seuls les composants s'exportent.

  • Premier caractère — vérifiez ceci en premier, cela change la signification du nom :

    • Commence par . ou _ → un composant interne, intentionnellement NON exporté. Le filterComponent de l'export dans .figmaexportrc.mjs supprime tout nom correspondant à ^[._]. C'est par conception, pas un bug — ne l'auditez pas comme une icône cassée. Signalez-le uniquement si l'utilisateur s'attendait à ce que ce nœud soit exporté (la correction est alors de le renommer sans le ./_ initial).
    • Commence par - → invalide, pas autorisé. Signalez comme un échec.
    • Commence par un chiffre → autorisé mais déconseillé. Il s'exporte quand même (par exemple 3-columns_32), mais un nom devrait de préférence commencer par une lettre anglaise — suggérez à l'utilisateur de le renommer. Recommandation souple, pas un blocage.
    • Commence par une lettre minuscule anglaise → le cas préféré.
  • Format du nom — un nom d'icône exportable doit correspondre à cette expression régulière :

    ^[a-z0-9]+(-[a-z0-9]+)*_(16|24|32|48|64)$
    

    Uniquement lettres minuscules anglaises et chiffres ; mots reliés par des traits d'union simples (pas de --, pas de trait d'union en tête/queue) ; puis exactement un trait de soulignement ; puis un suffixe de taille valide. Pas de majuscules, d'espaces, de cyrillique/autres écritures, ni d'autres signes de ponctuation.

    • ✅ floating-window_16, api_24, arrow-up-to-bracket_16 (et, format valide mais chiffre déconseillé, 3-columns_32)
    • ❌ Floating-Window_16 (majuscule) · плавающее-окно_16 (pas anglais) · floating_window_16 / icon__16 (deux traits de soulignement) · floating--window_16 (double trait d'union) · floating-window-16 (trait d'union au lieu de trait de soulignement avant la taille) · -floating-window_16 (trait d'union en tête) · floating-window_20 (taille non dans l'ensemble autorisé) · floating-window_16 (espace de fin)
  • Suffixe -o = variante contour. Le nom sans -o est la variante remplie. Une paire telle que cloud_24 / cloud-o_24 ou cloud-arrow-up_24 / cloud-arrow-up-o_24 est une icône en deux styles. C'est valide et ce n'est pas un conflit ou un doublon ; ne demandez pas de renommage à cause de cela.

  • Le suffixe numérique doit être égal à la taille réelle du composant (Règle B). Un ..._16 qui fait 24×24 est un bug.

B. Géométrie et mise en page

  • Pas de mise en page automatique : layoutMode === "NONE". La mise en page automatique réorganise les enfants et corrompt l'exportation.
  • Fixe et carré : width === height === size. La taille doit être un nombre entier de pixels (aligné sur la grille de pixels) ; les tailles de composant fractionnaires signifient que l'icône n'a pas été dessinée sur la grille.
  • Clip content DÉSACTIVÉ : clipsContent === false. Le bouton « Clip content » doit être désactivé. Il doit être le même (désactivé) pour chaque variante de taille de l'icône. Lorsqu'il est activé, toute illustration dépassant les limites du cadre est silencieusement rognée lors de l'exportation, produisant une icône coupée ou tronquée.

C. Structure racine (c'est là que se cachent la plupart des bugs réels)

  • Icône monochrome : exactement un enfant racine — un VECTOR nommé shape.
  • Icône bicolore : exactement deux enfants racines — shape (primaire) et shape-2 (secondaire). Rien d'autre.
  • Aucun autre nœud à la racine du composant : pas de trames, groupes, rectangles, tranches, vecteurs en double ou calques d'aide cachés. Chaque nœud supplémentaire se retrouve dans le SVG exporté.
  • Les contraintes de chaque forme sont SCALE sur les deux axes (horizontal: "SCALE", vertical: "SCALE") afin que l'illustration soit mise à l'échelle avec le cadre.
    • Gravité : avertissement (hygiène), pas un blocage d'exportation. Les contraintes contrôlent la façon dont le composant se redimensionne dans Figma, pas les données de chemin exportées. Corrigez-les avec les autres modifications Figma approuvées, car les instances et le redimensionnement en dépendent.
  • Idéalement, chaque forme est un chemin aplati unique (voir les étapes « Draw an icon » du README du dépôt : contour, aplatir, règle de remplissage Non-zero). Signalez plusieurs sous-chemins ou groupes non aplatis comme un avertissement.

D. Contrat de couleur de remplissage

Le contrat (README du dépôt « SVG Color Zones Guide ») :

  • Zone primaire shape → noir #21222C. L'exportation supprime son fill afin que le SVG hérite de currentColor.
  • Zone secondaire shape-2 → rouge #E21D03. L'exportation le réécrit en fill="currentColor".

Réalité pratique : dans le fichier de production, le remplissage primaire est lié à la variable partagée Icon/Contrast, qui se résout en #000819 avec une opacité de peinture de 0,85 — pas un #21222C littéral. Donc :

  • Clé de référence : 91eb54e0eae961c540c994192c4eed18e4ea1825 — Icon/Contrast de 🟥 koobiq · components 19 (clé de collection c78fab428cf2003c9aa53d86b132a2fa95acb2e2).
  • Comparez la clé de la variable liée de la peinture primaire avec cette référence ((await figma.variables.getVariableByIdAsync(boundId)).key), et vérifiez que l'opacité de la peinture est de 0,85. Ne comparez pas les noms : Icon/Contrast existe dans plusieurs bibliothèques et collections. La seule variable autorisée dans une icône est celle-ci, par sa clé. Une variable du même nom avec une clé différente (d'une autre bibliothèque ou collection) est un échec, pas un avertissement. Correction : reliez à la variable de clé de référence de la même collection de bibliothèque.
  • La shape-2 secondaire doit être soit un #E21D03 littéral solide (l'exportation le fait correspondre comme un hexadécimal littéral — secondaryZoneColorHex dans .figmaexportrc.mjs), soit liée par clé à Icon/Error de 🟥 koobiq · components 19 (clé e736157dcefc2a3e016ec2ddd41a7dc8cf8a5bc6). Pour le cas de la variable, l'opacité de la peinture n'est pas vérifiée. Tout autre remplissage échoue.
  • Un remplissage primaire qui est une couleur littérale simple ne correspondant à aucune icône sœur, ou un remplissage secondaire qui n'est pas #E21D03, sera exporté avec la valeur hexadécimale littérale, ne respectant pas le contrat currentColor — signalez-le comme un échec.

E. Cohérence entre les variantes de taille

Lisibilité : toutes les variantes de la même icône (foo_16, foo_24, foo_32, foo_48, foo_64) doivent avoir :

  • Le même nombre d'enfants racine (tous monochromes ou tous bicolores — pas de mélange).
  • Les mêmes noms d'enfants (tous shape / shape+shape-2).
  • Chaque forme a clipsContent === false (signalé dans la règle B, mais vérifié de manière homogène entre les tailles).
  • S'il s'agit d'un COMPONENT_SET, le nom du composant pour une taille donnée doit correspondre au nom de l'ensemble (foo) avec le suffixe de taille (par exemple foo_24). Les noms des composants frères peuvent différer des noms des pages — appliquez le tableau de correspondance explicite du fichier pour vérifier que la page 24 contient foo_24.

Densité visuelle (avertissement) : parmi les variantes de la même icône, il est inhabituel que le glyphe se réduise à moins de ~55 % de la taille du cadre. Une icône 64px dont le glyphe ne mesure que 24 px de large signale soit un glyphe trop petit, soit une requête pour une taille de cadre inférieure. Ne bloquez pas l'exportation, mais suggérez une vérification de conception.

F. Métadonnées de description

  • La description du composant (propriété description dans le panneau Design → Description) doit être non vide, en anglais, expliquer ce que représente le glyphe, et ne pas être la valeur par défaut (par exemple « Description de l'icône », vide). Une description n'est pas nécessaire sur les composants internes (nom commençant par ./_).
  • Chaque variante de taille de la même icône doit décrire le même concept. Par exemple, si foo_16 dit « Fenêtre flottante », foo_24 ne doit pas dire « widget ». Les divergences dans la description seront signalées comme un échec.

G. Cas particulier — icônes avec des calques cachés

Lorsque la règle C s'applique, mais que la forme secondaire n'est pas un enfant racine séparé ; il s'agit plutôt d'une BOOLEAN_OPERATION avec isMask ou un calque supplémentaire avec visible === false (par exemple, un calque de marque-page de conception). Ce n'est pas une violation de la règle structurelle si le calque caché est intentionnel (par exemple, calque de réserve pour les futures générations d'icônes).

  • Règle : invisible, pas placé. N'importe quel calque caché (visible === false) qui n'est ni shape ni shape-2 est autorisé tant qu'il a un nom raisonnable avec un préfixe _ (par exemple _old-arrow). Un calque visible supplémentaire sans nom explicite est toujours un échec.
  • Exception : un calque _ (tiret bas) est un calque de travail temporaire tout à fait normal que skipInvisibleInstanceChildren peut signaler ; ignorez-le lors de l'audit.

H. Exportabilité (vérification finale)

Avant de donner le feu vert pour une exportation (par exemple, pour la commande figma:export), vérifiez que l'icône est publiée. Figma n'exporte que les composants qui ont été explicitement marqués comme publiés dans le panneau Assets. Pour vérifier l'état de publication :

// Vérifiez l'état de publication pour chaque composant audité
const publishInfo = component.remoteData?.publishStatus; // 'CURRENT', 'UNPUBLISHED', 'EDITED', 'UNKNOWN'

Tout statut autre que CURRENT ou EDITED signifie que la dernière version du composant n'est pas disponible pour les utilisateurs du fichier de bibliothèque (si les exportations se font à partir d'une bibliothèque Figma, pas seulement à partir du fichier directement). Signalez UNPUBLISHED comme un avertissement. Un composant EDITED a été mis à jour mais pas republié — informez l'utilisateur qu'une republication est nécessaire avant que l'exportation ne voie la dernière version.

Proposer des corrections

Par défaut, rapportez uniquement l'audit. L'utilisateur peut dire « corrige ça » ou « répare-le » ; alors seulement, modifiez les nœuds Figma via use_figma avec les mêmes gardes. Les scripts de correction autorisés sont :

  • Renommer un composant (component.name = newName).
  • Définir component.clipsContent = false.
  • Supprimer les calques superflus (uniquement ceux qui ne sont pas shape/shape-2).
  • Renommer un calque en shape ou shape-2 (vérifiez qu'il devient le calque correct).
  • Définir les contraintes constraints: { horizontal: "SCALE", vertical: "SCALE" }.
  • Modifier la description d'un composant.
  • Définir les remplissages et les lier (via setBoundVariableAsync).

N'effectuez jamais de corrections de structure plus profondes (par exemple, vectoriser, décomposer, aplatir). Ces corrections doivent être effectuées par un designer dans l'application Figma. Si l'utilisateur vous demande de réparer de telles structures, dites-lui qu'il ne peut pas les effectuer par programmation et expliquez-lui la solution manuelle.

Rappelez-vous : chaque modification Figma, en particulier la modification des contraintes, reprogramme la façon dont l'icône se redimensionne. Vérifiez avec get_screenshot après la modification et réexécutez une inspection complète.

Skills associés