Koobiq Icons Figma Audit
Dieses Skill überprüft, ob eine Icon-Komponente in der Koobiq-Icons-Figma-Datei den strukturellen
Konventionen der Bibliothek folgt, sodass figma:sync (die @figma-export-Pipeline) ein sauberes,
korrektes SVG erzeugt. Fehler in Figma zu erkennen ist weit günstiger, als sie nach dem Export zu entdecken,
weil der Export stillschweigend umwandelt, was er vorfindet – eine falsche Ebenenbezeichnung, ein zusätzlicher
Knoten oder eine nicht am Raster ausgerichtete Koordinate wird zu einem defekten SVG ohne Fehlermeldung.
Standardmäßig handelt es sich um einen schreibgeschützten Audit: Überprüfen, dann eine eindeutige Bestanden/Nicht-bestanden-Liste mit spezifischen, umsetzbaren Ergebnissen melden. Ändern Sie die Figma-Datei nur, wenn der Benutzer Sie ausdrücklich bittet, etwas zu reparieren (siehe "Reparaturen anbieten").
Voraussetzungen
-
Der Figma MCP muss verbunden sein. Dieses Skill steuert ihn über
get_metadata(Strukturübersicht),use_figma(präzise Inspektion über die Plugin-API) undget_screenshot(visuelle Plausibilitätsprüfung). -
Vor jedem
use_figma-Aufruf dasfigma-use-Skill laden – es dokumentiert die Plugin-API-Regeln und verhindert häufige, schwer zu debuggende Fehler. -
Der Dateischlüssel und die Seitengrößen sind festgelegt (gegen das Live-Dokument verifiziert). Um einen Seitenfindungs-Roundtrip zu überspringen, springen Sie direkt zu einer Seite über ihre Knoten-ID:
Größe Seitenknoten-ID 16 1320:1738724 42149:86032 42149:86248 42149:86164 42149:863Dateischlüssel:
WvUarBj8tO256vML4PkBLl. Jeder Seitenname ist das Größensuffix; ein Icon mit dem Namenfoo_24befindet sich auf Seite24. Dokument: https://www.figma.com/design/WvUarBj8tO256vML4PkBLl/%F0%9F%9F%A5-koobiq-%C2%B7-icons?node-id=1320-17387- Dieser Dateischlüssel ist die maßgebliche Quelle – er stimmt mit
config.mjsüberein. Der Link „Ein Icon zeichnen“ inpackages/icons/README.mdzeigt auf eine andere, falsche Datei – ignorieren Sie ihn und vertrauen Sie dem obigen Schlüssel. get_metadataohnenodeIdlistet nur die erste Seite (ICONS, die keine Icon-Komponenten enthält) – es listet nicht die Größenseiten auf. Verwenden Sie es nicht zur Seitenfindung; nutzen Sie die obigen Knoten-IDs.
- Dieser Dateischlüssel ist die maßgebliche Quelle – er stimmt mit
Wenn die Datei nicht zugänglich ist
Wenn ein Figma-Aufruf fehlschlägt – Authentifizierungs-/Berechtigungsfehler, „Knoten existiert nicht“, eine leere/unerwartete Datei oder der MCP antwortet nicht – stoppen Sie und informieren Sie den Benutzer, statt zu raten. Teilen Sie ihm mit, was fehlgeschlagen ist, und bitten Sie ihn, eines der Folgenden zu tun:
- einen anderen/korrekten Figma-Link bereitzustellen (der Dateischlüssel in
config.mjskönnte veraltet sein, oder er hat einen Link zu einer anderen Datei oder einem Branch eingefügt), oder - das
FIGMA_TOKENin der.envdes Repos zu überprüfen (derfigma-export/MCP-Zugriffstoken fehlt möglicherweise, ist abgelaufen oder widerrufen), oder - zu bestätigen, dass sein Figma-Konto Zugriff auf die Datei hat (es ist eine private Designdatei – er muss möglicherweise eingeladen werden oder einen Token verwenden, der mit einem berechtigten Konto verknüpft ist).
Fertigen Sie kein Audit-Ergebnis aus Annahmen an; eine Prüfung ist nur gegen die Live-Datei aussagekräftig.
Parallele Lesevorgänge und Seitenkontext
Figma-Lesevorgänge können parallel ausgeführt werden, aber nur vor der ersten Figma-Bearbeitung des Auftrags. Nachdem eine Bearbeitung begonnen hat, führen Sie Figma-Aufrufe nacheinander aus.
Parallele Lesevorgänge, die die Seite wechseln, können sich gegenseitig stören. In einem beobachteten Durchlauf gab ein Lesevorgang, der auf Seite 24 zielte, die Daten von Seite 16 zurück (gleiche Komponentenanzahl, falsche Namen), und der Audit meldete die 24px-Varianten als fehlend. Schützen Sie jeden Lesevorgang, der die Seite wechselt:
// Verwenden Sie dies bei jedem Lesevorgang, der die Seite wechselt. Gibt nur Daten für Knoten zurück,
// die zu PAGE_ID gehören.
const PAGE_ID = "42149:860"; // Seitenknoten-ID aus obiger Tabelle
const NAMES = ["foo_24"]; // zu suchende Komponentennamen
const page = await figma.getNodeByIdAsync(PAGE_ID);
await figma.setCurrentPageAsync(page);
if (figma.currentPage.id !== PAGE_ID) throw new Error("Seitenkontext vor dem Lesen stimmt nicht überein");
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("Seitenkontext während des Lesens geändert");
return { pageId: PAGE_ID, hits };
Wenn eine Schutzmaßnahme einen Fehler auslöst, verwerfen Sie dieses Ergebnis und führen Sie den Lesevorgang erneut aus. Eine Behaupung des Fehlens (z. B. „keine 24px-Variante“) muss auf einem geschützten Lesevorgang dieser Seite oder auf einer Suche nach Knoten-ID beruhen. Melden Sie niemals Abwesenheit von einem Lesvorgang, der einen Fehler ausgelöst hat, oder von einer Seite, die Sie nicht überprüft haben.
Schritt 1 – Ziel auflösen
Der Benutzer kann Ihnen Folgendes geben:
- Eine Figma-Knoten-URL oder -ID (z. B.
node-id=44731-6643) → Überprüfen Sie genau diesen Knoten und suchen Sie dann auch nach seinen gleichnamigen Größenvarianten für die übergreifende Variantenprüfung. - Einen Icon-Namen (z. B.
floating-window, oderfloating-window_16) → Finden Sie jede Größenvariante auf den Icon-Seiten und prüfen Sie alle. Neue Icons sind oft unveröffentlicht und möglicherweise sogar unbenannt. Wenn daher eine Namensübereinstimmung fehlschlägt, listen Sie die Komponenten auf der/den relevanten Seite(n) auf und bitten Sie den Benutzer, auf den Knoten zu zeigen, oder überprüfen Sie nach Knoten-ID.
Seitennamen entsprechen dem Größensuffix. Größen-Sweep: Überprüfen Sie alle fünf Seiten (16 / 24 / 32 /
48 / 64) auf jeden angeforderten Namen, da ein Icon in Größen existieren kann, die der Benutzer nicht
angegeben hat. Verwenden Sie die Seitenknoten-IDs aus der Voraussetzungstabelle, einen use_figma-Aufruf
pro Seite, jeweils mit der Schutzmaßnahme aus „Parallele Lesevorgänge und Seitenkontext“. Führen Sie sie
nur parallel aus, bevor eine Figma-Bearbeitung stattfindet. Melden Sie das Ergebnis als Tabelle
(Name × Größe → Knoten-ID oder fehlend).
Schritt 2 – Überprüfen
Führen Sie dieses schreibgeschützte Skript aus (passen Sie die targets/Seiten-ID an). Es gibt alles
zurück, was die folgenden Regeln benötigen. Kombinieren Sie es mit einem get_screenshot, um zu
bestätigen, dass das Glyph tatsächlich gerendert wird.
// In use_figma einfügen (skillNames: "figma-use"). PAGE_ID und NAMES setzen.
// Seitenknoten-IDs: 16=1320:17387 24=42149:860 32=42149:862 48=42149:861 64=42149:863
const PAGE_ID = "1320:17387"; // Seite, deren Name die Größe ist, z. B. "16"
const NAMES = ["floating-window_16"]; // Name(n) der zu prüfenden Komponente(n) auf dieser Seite
figma.skipInvisibleInstanceChildren = false; // false: Regel G muss auch ausgeblendete Ebenen sehen
const page = await figma.getNodeByIdAsync(PAGE_ID);
await figma.setCurrentPageAsync(page);
if (figma.currentPage.id !== PAGE_ID) throw new Error("Seitenkontext vor dem Lesen stimmt nicht überein");
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 ? "GEMISCHT" : 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("Seitenkontext während des Lesens geändert");
return report;
Um den Farbvertrag zuverlässig zu validieren, lesen Sie auch ein bekanntes gutes Schwestericon
derselben Größe (z. B. list_16) auf dieselbe Weise und vergleichen Sie die gebundene Variable der
Primärform Key (Regel D). Der nominale Vertrag-Hex und der tatsächliche in der Datei gespeicherte Wert
unterscheiden sich (siehe Regel D), daher ist der Vergleich mit einem echten Nachbarn vertrauenswürdiger
als der Abgleich mit einem literalen Hex.
Schritt 3 – Gegen die Regeln prüfen
Melden Sie jede als ✅ bestanden / ❌ nicht bestanden mit dem beobachteten Wert und, bei Fehlschlag, was er sein sollte.
A. Knotentyp und -name
-
Der Knoten ist ein
COMPONENT(oder einCOMPONENT_SETvon Größenvarianten), keinFRAME,GROUPoderINSTANCE. Nur Komponenten werden exportiert. -
Erstes Zeichen – dies zuerst prüfen, es ändert die Bedeutung des Namens:
- Beginnt mit
.oder_→ eine interne Komponente, die absichtlich NICHT exportiert wird. DerfilterComponentdes Exports in.figmaexportrc.mjsentfernt jeden Namen, der auf^[._]passt. Das ist beabsichtigt, kein Fehler – auditieren Sie es nicht als defektes Icon. Weisen Sie nur darauf hin, wenn der Benutzer erwartet hat, dass dieser Knoten exportiert wird (dann besteht die Reparatur darin, ihn ohne das führende./_umzubenennen). - Beginnt mit
-→ ungültig, nicht erlaubt. Melden Sie als Fehler. - Beginnt mit einer Ziffer → erlaubt, aber nicht empfohlen. Es wird trotzdem exportiert (z. B.
3-columns_32), aber ein Name sollte vorzugsweise mit einem englischen Buchstaben beginnen – schlagen Sie dem Benutzer vor, ihn umzubenennen. Sanfte Empfehlung, kein Blockierer. - Beginnt mit einem englischen Kleinbuchstaben → der bevorzugte Fall.
- Beginnt mit
-
Namensformat – ein exportierbarer Icon-Name muss diesem regulären Ausdruck entsprechen:
^[a-z0-9]+(-[a-z0-9]+)*_(16|24|32|48|64)$Nur englische Kleinbuchstaben und Ziffern; Wörter durch einzelne Bindestriche verbunden (kein
--, kein führender/nachgestellter Bindestrich); dann genau ein Unterstrich; dann ein gültiges Größensuffix. Keine Großbuchstaben, Leerzeichen, Kyrillisch/andere Schriften oder andere Satzzeichen.- ✅
floating-window_16,api_24,arrow-up-to-bracket_16(und, formatgültig aber ziffern-unempfohlen,3-columns_32) - ❌
Floating-Window_16(Großbuchstaben) ·плавающее-окно_16(nicht Englisch) ·floating_window_16/icon__16(zwei Unterstriche) ·floating--window_16(doppelter Bindestrich) ·floating-window-16(Bindestrich statt Unterstrich vor der Größe) ·-floating-window_16(führender Bindestrich) ·floating-window_20(Größe nicht im erlaubten Satz) ·floating-window_16(nachgestelltes Leerzeichen)
- ✅
-
-oSuffix = Outline-Variante. Der Name ohne-oist die gefüllte Variante. Ein Paar wiecloud_24/cloud-o_24odercloud-arrow-up_24/cloud-arrow-up-o_24ist ein Icon in zwei Stilen. Das ist gültig und kein Konflikt oder Duplikat; bitten Sie nicht aufgrund dessen um eine Umbenennung. -
Das numerische Suffix muss der tatsächlichen Größe der Komponente entsprechen (Regel B). Ein
..._16, das 24×24 ist, ist ein Fehler.
B. Geometrie und Layout
- Kein Auto-Layout:
layoutMode === "NONE". Auto-Layout ordnet Kinder neu an und beschädigt den Export. - Fest und quadratisch:
width === height === size. Die Größe muss eine ganze Pixelzahl sein (am Pixelraster ausgerichtet); gebrochene Komponentengrößen bedeuten, dass das Icon nicht auf dem Raster gezeichnet wurde. - Inhalt beschneiden AUS:
clipsContent === false. Der Schalter „Inhalt beschneiden“ muss deaktiviert sein. Er muss für jede Größenvariante des Icons gleich (aus) sein. Wenn er eingeschaltet ist, wird jedes über die Rahmengrenzen hinausragende Kunstwerk im Export stillschweigend beschnitten, was zu einem abgeschnittenen oder abgeschnittenen Icon führt.
C. Wurzelstruktur (hier verstecken sich die meisten echten Fehler)
- Einfarbiges Icon: genau ein Wurzelkind – ein
VECTORmit dem Namenshape. - Zweifarbiges Icon: genau zwei Wurzelkinder –
shape(primär) undshape-2(sekundär). Nichts anderes. - Keine anderen Knoten auf der Komponentenwurzel: keine zusätzlichen Rahmen, Gruppen, Rechtecke, Slices, doppelte Vektoren oder ausgeblendete Hilfsebenen. Jeder zusätzliche Knoten landet im exportierten SVG.
- Die Beschränkungen jeder Form sind auf beiden Achsen
SCALE(horizontal: "SCALE",vertical: "SCALE"), sodass das Kunstwerk mit dem Rahmen skaliert.- Schweregrad: Warnung (Hygiene), kein Export-Blockierer. Beschränkungen steuern, wie die Komponente in Figma in der Größe verändert wird, nicht die exportierten Pfaddaten. Beheben Sie sie mit den anderen genehmigten Figma-Bearbeitungen, da Instanzen und Größenänderungen von ihnen abhängen.
- Idealerweise ist jede Form ein einzelner abgeflachter Pfad (siehe Repo-README „Ein Icon zeichnen“ Schritte: Kontur, Abflachen, Non-Zero-Füllregel). Markieren Sie mehrere Unterpfade oder nicht abgeflachte Gruppen als Warnung.
D. Füllfarbvertrag
Der Vertrag (Repo-README „SVG Color Zones Guide“):
- Primärzone
shape→ schwarz#21222C. Der Export entfernt seinefill, damit das SVGcurrentColorerbt. - Sekundärzone
shape-2→ rot#E21D03. Der Export überschreibt es zufill="currentColor".
Praktische Realität: In der Produktionsdatei ist die Primärfüllung an die gemeinsame Variable
Icon/Contrast gebunden, die zu #000819 bei 0,85 Deckkraft auflöst – nicht ein literales
#21222C. Also:
- Referenz-Key:
91eb54e0eae961c540c994192c4eed18e4ea1825–Icon/Contrastaus🟥 koobiq · components 19(Sammlungs-Keyc78fab428cf2003c9aa53d86b132a2fa95acb2e2). - Vergleichen Sie den Key der gebundenen Variable der Primärfüllung mit dieser Referenz
(
(await figma.variables.getVariableByIdAsync(boundId)).key) und überprüfen Sie, dass die Deckkraft 0,85 ist. Vergleichen Sie keine Namen:Icon/Contrastexistiert in mehreren Bibliotheken und Sammlungen. Die einzige Variable, die in einem Icon erlaubt ist, ist diese, anhand ihres Keys. Eine gleichnamige Variable mit einem anderen Key (aus einer anderen Bibliothek oder Sammlung) ist ein Fehler, keine Warnung. Reparatur: Binden Sie an die Referenz-Key-Variable aus derselben Bibliothekssammlung neu. - Die sekundäre
shape-2muss entweder ein reines literales#E21D03sein (der Export gleicht es als literalen Hex ab –secondaryZoneColorHexin.figmaexportrc.mjs) oder nach Key anIcon/Erroraus🟥 koobiq · components 19gebunden sein (Keye736157dcefc2a3e016ec2ddd41a7dc8cf8a5bc6). Für den Variablenfall wird die Deckkraft nicht geprüft. Jede andere Füllung schlägt fehl. - Eine Primärfüllung, die eine reine literale Farbe ist, die zu keinem Geschwister passt, oder eine
Sekundärfüllung, die nicht
#E21D03ist, wird mit dem falschen Farbwert exportiert.
E. Metadaten (Beschreibung)
- Die
descriptionder Komponente muss gesetzt sein. Sie wird als Tooltip im Koobiq-Icon-Selektor verwendet. - Die Beschreibung sollte kurz und eindeutig sein, normalerweise der englische Name des Icons (z. B.
floating-window_16→ „Floating window“). Sie ist nicht als detaillierte Dokumentation gedacht. - Wenn die Beschreibung fehlt oder leer ist: Fehler. Wenn sie vorhanden, aber offensichtlich falsch oder irreführend ist: Warnung.
F. Größenvarianten-Konsistenz
- Jedes Icon muss in einer Teilmenge der fünf Standardgrößen existieren (16, 24, 32, 48, 64). Prüfen Sie jede Seite auf den/die Namen (Schritt 1, Größendurchlauf).
- Jede vorhandene Variante muss einzeln gegen die Regeln A–E geprüft werden.
- Fehlende Übereinstimmung (ein Name existiert auf einer Seite, aber nicht auf einer anderen) ist normal – nicht jedes Icon hat alle fünf Größen. Prüfen Sie nur die, die existieren.
- Strukturgleichheit: Wenn eine Variante
clipsContent === truehat und eine anderefalse, melden Sie eine Inkonsistenz. Gleiches gilt für die Kinderstruktur (z. B. zwei Kinder auf der 16px-, aber eines auf der 24px- – das ist ein Fehler, es sei denn, der Benutzer hat eine klare Designbegründung).
G. Ausgeblendete Ebenen
- Keine ausgeblendeten Ebenen auf der Wurzel oder innerhalb von
shape/shape-2. Ausgeblendete Ebenen sind in Figma für Entwickler unsichtbar, können aber im exportierten SVG erscheinen, wenn sie nicht richtig behandelt werden. - Verwenden Sie
figma.skipInvisibleInstanceChildren = falseim Inspektionsskript (wie oben gezeigt), um sicherzustellen, dass Sie ausgeblendete Ebenen sehen. Wenn es welche gibt, markieren Sie sie als Warnung (nicht blockierend, aber weisen Sie darauf hin, dass sie bereinigt werden sollten).
Reparaturen anbieten
Der Audit ist standardmäßig schreibgeschützt. Ändern Sie die Figma-Datei nur, wenn der Benutzer ausdrücklich sagt: „Bitte repariere das / die Fehler“ oder etwas Ähnliches. Bieten Sie dann an, die von Ihnen identifizierten Probleme zu beheben. Gruppen Sie verwandte Reparaturen in einem einzigen Figma-Aufruf, wenn möglich (z. B. Umbenennen, Größe ändern, Variable neu binden), um die Anzahl der API-Aufrufe zu minimieren. Wenden Sie sich an den Benutzer, wenn eine Reparatur eine Designentscheidung betrifft (z. B. ob ein zweifarbiges Icon in ein einfarbiges geändert werden soll).
Fehlerbehebung
figma.currentPageschlägt fehl: Stellen Sie sicher, dass Siefigma-useals Skill geladen haben, bevor Sieuse_figmaaufrufen. Der MCP muss verbunden sein.- Keine Daten von einer Seite: Verwenden Sie die Knoten-IDs aus der Voraussetzungstabelle, nicht die Seitennamen. Überprüfen Sie, ob der Dateischlüssel korrekt ist.
- Farbvergleichsfehler: Das in der Produktion beobachtete
#000819bei 0,85 unterscheidet sich von#21222C. Verlassen Sie sich auf den Key-Vergleich, nicht auf literale Hex-Werte. - Variable nicht gefunden: Der Benutzer hat möglicherweise keine Variable
Icon/Contrastin seiner Bibliothek. Bitten Sie ihn, die Bibliothek🟥 koobiq · components 19zu installieren.