CommunityCodierung & Entwicklunggithub.com

rmnturov/koobiq-icons-figma-audit

Überprüft, ob eine Figma-Icon-Komponente gemäß den Konventionen der Koobiq-Icons-Bibliothek organisiert ist, bevor sie exportiert wird (figma:sync / figma-export). Prüft Knotentyp, Namensformat, Größe, Layout, die Struktur shape/shape-2, Skalierungsbeschränkungen, Füllfarbvertrag und Metadaten sowie die Konsistenz der Größenvarianten.

Was ist koobiq-icons-figma-audit?

Dieses Skill validiert, ob eine Icon-Komponente in der Koobiq-Icons-Figma-Datei den strukturellen Konventionen der Bibliothek folgt, sodass der `figma:sync`-Export (über die `@figma-export`-Pipeline) ein sauberes, korrektes SVG erzeugt. Es prüft Knotentyp und -name (Regex-Format mit Größenangabe), Größe und Layout (keine Auto-Layout, fixe Pixelmaße, deaktiviertes Clipping), die Wurzelstruktur (genau ein `shape`- oder ein `shape`/`shape-2`-Paar) sowie die Skalierungsbeschränkungen auf `SCALE` für beide Achsen. Besonderes Augenmerk liegt auf dem Farbvertrag: Die Primärzone `shape` muss an die Variable `Icon/Contrast` (Key `91eb54e0eae961c540c994192c4eed18e4ea1825`) mit 0,85 Deckkraft gebunden sein; die Sekundärzone `shape-2` muss entweder das reine `#E21D03` oder die Variable `Icon/Error` (Key `e736157dcefc2a3e016ec2ddd41a7dc8cf8a5bc6`) verwenden. Das Skill führt einen schreibgeschützten Audit durch und meldet eindeutig bestandene/fehlgeschlagene Prüfungen. Es unterstützt die Plattformen Figma (über MCP) und wird vor dem Exportbefehl ausgeführt, um Fehler frühzeitig zu erkennen.

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

Installed? Explore more Codierung & Entwicklung skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

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) und get_screenshot (visuelle Plausibilitätsprüfung).

  • Vor jedem use_figma-Aufruf das figma-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ößeSeitenknoten-ID
    161320:17387
    2442149:860
    3242149:862
    4842149:861
    6442149:863

    Dateischlüssel: WvUarBj8tO256vML4PkBLl. Jeder Seitenname ist das Größensuffix; ein Icon mit dem Namen foo_24 befindet sich auf Seite 24. 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“ in packages/icons/README.md zeigt auf eine andere, falsche Datei – ignorieren Sie ihn und vertrauen Sie dem obigen Schlüssel.
    • get_metadata ohne nodeId listet 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.

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.mjs könnte veraltet sein, oder er hat einen Link zu einer anderen Datei oder einem Branch eingefügt), oder
  • das FIGMA_TOKEN in der .env des Repos zu überprüfen (der figma-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, oder floating-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 ein COMPONENT_SET von Größenvarianten), kein FRAME, GROUP oder INSTANCE. 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. Der filterComponent des Exports in .figmaexportrc.mjs entfernt 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.
  • 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)
  • -o Suffix = Outline-Variante. Der Name ohne -o ist die gefüllte Variante. Ein Paar wie cloud_24 / cloud-o_24 oder cloud-arrow-up_24 / cloud-arrow-up-o_24 ist 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 VECTOR mit dem Namen shape.
  • Zweifarbiges Icon: genau zwei Wurzelkinder – shape (primär) und shape-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 seine fill, damit das SVG currentColor erbt.
  • Sekundärzone shape-2 → rot #E21D03. Der Export überschreibt es zu fill="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/Contrast aus 🟥 koobiq · components 19 (Sammlungs-Key c78fab428cf2003c9aa53d86b132a2fa95acb2e2).
  • 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/Contrast existiert 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-2 muss entweder ein reines literales #E21D03 sein (der Export gleicht es als literalen Hex ab – secondaryZoneColorHex in .figmaexportrc.mjs) oder nach Key an Icon/Error aus 🟥 koobiq · components 19 gebunden sein (Key e736157dcefc2a3e016ec2ddd41a7dc8cf8a5bc6). 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 #E21D03 ist, wird mit dem falschen Farbwert exportiert.

E. Metadaten (Beschreibung)

  • Die description der 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 === true hat und eine andere false, 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 = false im 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.currentPage schlägt fehl: Stellen Sie sicher, dass Sie figma-use als Skill geladen haben, bevor Sie use_figma aufrufen. 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 #000819 bei 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/Contrast in seiner Bibliothek. Bitten Sie ihn, die Bibliothek 🟥 koobiq · components 19 zu installieren.

Verwandte Skills