CommunityProgramación y desarrollogithub.com

Auditoría de iconos Koobiq en Figma

Valida que un componente de icono en el archivo Figma de iconos Koobiq esté organizado correctamente antes de exportarlo (figma:sync / figma-export). Verifica tipo de nodo, formato de nombre, tamaño, diseño, la estructura raíz shape/shape-2, restricciones de escala, contrato de color de relleno y metadatos de descripción, y asegura que las variantes de tamaño del mismo icono sean consistentes entre sí. Úsalo siempre que el usuario quiera comprobar, revisar, validar o verificar un componente de icono recién dibujado o no publicado según las convenciones de la biblioteca, o pregunte si un icono está listo para exportar, incluso si solo pega un enlace de Figma o un nombre de icono. Ejecútalo antes de figma:sync al añadir o editar iconos.

¿Qué es Auditoría de iconos Koobiq en Figma?

Esta habilidad (skill) realiza una auditoría automatizada de componentes de iconos en el archivo Figma de la biblioteca Koobiq, asegurando que cumplan con las convenciones estructurales antes de ser exportados mediante el pipeline `figma:sync` / `figma-export`. Está diseñada para agentes de IA como Claude Code y utiliza el MCP de Figma para inspeccionar nodos, verificar nombres, tamaños, restricciones, rellenos y metadatos, y comparar variantes de tamaño. La auditoría es de solo lectura por defecto y reporta una lista de verificación clara de aprobado/fallo con hallazgos específicos y procesables. Soporta la validación de iconos de un solo color y de dos colores, verificando su estructura raíz (shape/shape-2), contrato de color (variables de Figma), y que todos los tamaños (16, 24, 32, 48, 64) sean consistentes. Es especialmente útil antes de añadir o editar iconos para evitar errores costosos en la exportación.

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

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace Auditoría de iconos Koobiq en Figma?

Esta habilidad verifica que un componente de icono en el archivo Figma de iconos Koobiq siga las convenciones estructurales de la biblioteca, para que figma:sync (el pipeline @figma-export) produzca un SVG limpio y correcto. Detectar problemas en Figma es mucho más barato que descubrirlos después de la exportación, porque la exportación transforma silenciosamente lo que encuentra — un nombre de capa incorrecto, un nodo extra, o una coordenada fuera de la cuadrícula se convierte en un SVG roto sin ningún error.

Es una auditoría de solo lectura por defecto: inspecciona y luego reporta una lista de verificación clara de aprobado/fallo con hallazgos específicos y procesables. Solo modifica el archivo Figma si el usuario te pide explícitamente que arregles algo (ver "Ofrecer correcciones").

Prerrequisitos

  • El MCP de Figma debe estar conectado. Esta habilidad lo utiliza a través de get_metadata (resumen de la estructura), use_figma (inspección precisa mediante la API de Plugin) y get_screenshot (comprobación visual de cordura).

  • Antes de cualquier llamada a use_figma, carga la habilidad figma-use — documenta las reglas de la API de Plugin y previene fallos comunes difíciles de depurar.

  • La clave del archivo y las páginas de tamaño están fijas (verificadas contra el documento activo). Para saltarte un viaje de ida y vuelta de descubrimiento de páginas, salta directamente a una página por su id de nodo:

    tamañoid de nodo de página
    161320:17387
    2442149:860
    3242149:862
    4842149:861
    6442149:863

    Clave del archivo: WvUarBj8tO256vML4PkBLl. Cada nombre de página es el sufijo de tamaño; un icono llamado foo_24 vive en la página 24. Documento: https://www.figma.com/design/WvUarBj8tO256vML4PkBLl/%F0%9F%9F%A5-koobiq-%C2%B7-icons?node-id=1320-17387

    • Esta clave de archivo es la fuente de verdad — coincide con config.mjs. El enlace "Draw an icon" en packages/icons/README.md apunta a un archivo diferente e incorrecto — ignóralo y confía en la clave anterior.
    • get_metadata sin un nodeId solo lista la primera página (ICONS, que no contiene componentes de icono) — no enumera las páginas de tamaño. No lo uses para descubrir páginas; usa los ids de nodo anteriores.

Si no se puede acceder al archivo

Si una llamada a Figma falla — error de autenticación/permiso, "el nodo no existe", un archivo vacío o inesperado, o el MCP no responde — detente y comunícalo al usuario en lugar de adivinar. Dile qué falló y pídele que haga una de las siguientes acciones:

  • proporcionar un enlace de Figma diferente o correcto (la clave del archivo en config.mjs puede estar desactualizada, o pegaron un enlace a otro archivo o a una rama), o
  • volver a verificar el FIGMA_TOKEN en el .env del repositorio (el token de acceso figma-export / MCP puede faltar, haber caducado o haber sido revocado), o
  • confirmar que su cuenta de Figma tiene acceso al archivo (es un archivo de diseño privado — es posible que necesiten ser invitados o usar un token vinculado a una cuenta con permiso).

No fabriques un resultado de auditoría a partir de suposiciones; una comprobación solo tiene sentido contra el archivo activo.

Lecturas en paralelo y contexto de página

Las llamadas de lectura de Figma pueden ejecutarse en paralelo, pero solo antes de la primera edición de Figma de la tarea. Después de que haya comenzado cualquier edición, ejecuta las llamadas de Figma una a la vez.

Las lecturas en paralelo que cambian de página pueden interferir entre sí. En una ejecución observada, una lectura que apuntaba a la página 24 devolvió datos de la página 16 (el mismo recuento de componentes, nombres incorrectos), y la auditoría reportó las variantes de 24px como faltantes. Protege cada lectura que cambie de página:

// Úsalo en cada lectura que cambie de página. Devuelve datos solo para los nodos que pertenecen a PAGE_ID.
const PAGE_ID = "42149:860";   // id de nodo de página de la tabla anterior
const NAMES = ["foo_24"];       // nombres de componentes a buscar
const page = await figma.getNodeByIdAsync(PAGE_ID);
await figma.setCurrentPageAsync(page);
if (figma.currentPage.id !== PAGE_ID) throw new Error("desajuste de contexto de página antes de la lectura");
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("el contexto de página cambió durante la lectura");
return { pageId: PAGE_ID, hits };

Si un guardia lanza una excepción, descarta ese resultado y vuelve a ejecutar la lectura. Una afirmación de "falta" (por ejemplo, "no hay variante de 24px") debe basarse en una lectura protegida de esa página, o en una búsqueda por id de nodo. Nunca reportes ausencia a partir de una lectura que lanzó una excepción o de una página que no verificaste.

Paso 1 — Resolver el objetivo

El usuario puede darte cualquiera de los siguientes:

  • Una URL o id de nodo de Figma (ej. node-id=44731-6643) → inspecciona exactamente ese nodo, y luego también busca sus variantes de tamaño hermanas por nombre para la comprobación cruzada de variantes.
  • Un nombre de icono (ej. floating-window, o floating-window_16) → encuentra cada variante de tamaño en las páginas de iconos y verifícalas todas. Los iconos nuevos a menudo no están publicados e incluso pueden no tener nombre, así que si una coincidencia de nombre falla, lista los componentes en las páginas relevantes y pide al usuario que señale el nodo, o inspecciona por id de nodo.

Los nombres de página son iguales al sufijo de tamaño. Barrido de tamaño: verifica las cinco páginas (16 / 24 / 32 / 48 / 64) para cada nombre solicitado, porque un icono puede existir en tamaños que el usuario no mencionó. Usa los ids de nodo de página de la tabla de Prerrequisitos, una llamada use_figma por página, cada una con el guardia de "Lecturas en paralelo y contexto de página". Ejecútalas en paralelo solo antes de cualquier edición de Figma. Reporta el resultado como una tabla (nombre × tamaño → id de nodo o falta).

Paso 2 — Inspeccionar

Ejecuta este script de solo lectura (adapta los targets/id de página). Devuelve todo lo que las reglas a continuación necesitan. Acompáñalo con un get_screenshot para que puedas confirmar que el glifo realmente se renderiza.

// Pégalo en use_figma (skillNames: "figma-use"). Establece PAGE_ID y NAMES.
// Ids de nodo de página: 16=1320:17387  24=42149:860  32=42149:862  48=42149:861  64=42149:863
const PAGE_ID = "1320:17387";      // página cuyo nombre es el tamaño, ej. "16"
const NAMES = ["floating-window_16"]; // nombre(s) de componente(s) a auditar en esta página
figma.skipInvisibleInstanceChildren = false; // false: la regla G debe ver también las capas ocultas
const page = await figma.getNodeByIdAsync(PAGE_ID);
await figma.setCurrentPageAsync(page);
if (figma.currentPage.id !== PAGE_ID) throw new Error("desajuste de contexto de página antes de la lectura");

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("el contexto de página cambió durante la lectura");
return report;

Para validar el contrato de color de forma fiable, también lee un icono hermano conocido como bueno del mismo tamaño (ej. list_16) de la misma manera y compara la clave de la variable vinculada de la forma principal (Regla D). El valor hexadecimal nominal del contrato y el valor realmente almacenado en el archivo difieren (ver Regla D), por lo que comparar con un vecino real es más fiable que comparar con un valor hexadecimal literal.

Paso 3 — Verificar contra las reglas

Reporta cada una como ✅ aprobado / ❌ fallo con el valor observado y, en caso de fallo, lo que debería ser.

A. Tipo de nodo y nombre

  • El nodo es un COMPONENT (o un COMPONENT_SET de variantes de tamaño), no un FRAME, GROUP o INSTANCE. Solo los componentes se exportan.

  • Primer carácter — verifica esto primero, cambia lo que significa el nombre:

    • Empieza con . o _ → un componente interno, intencionalmente NO exportado. El filterComponent de la exportación en .figmaexportrc.mjs elimina cualquier nombre que coincida con ^[._]. Esto es por diseño, no un error — no lo audites como un icono roto. Solo señálalo si el usuario esperaba que este nodo se exportara (entonces la solución es renombrarlo sin el ./_ inicial).
    • Empieza con - → inválido, no permitido. Señálalo como un fallo.
    • Empieza con un dígito → permitido pero desaconsejado. Aún se exporta (ej. 3-columns_32), pero un nombre debería preferiblemente comenzar con una letra del alfabeto inglés — sugiere al usuario que lo renombre. Recomendación suave, no un bloqueante.
    • Empieza con una letra minúscula del alfabeto inglés → el caso preferido.
  • Formato del nombre — un nombre de icono exportable debe coincidir con esta expresión regular:

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

    Solo letras minúsculas del alfabeto inglés y dígitos; palabras unidas por un solo guión (sin --, sin guión inicial/final); luego exactamente un guión bajo; luego un sufijo de tamaño válido. Sin mayúsculas, espacios, cirílico/otros alfabetos, u otros signos de puntuación.

    • ✅ floating-window_16, api_24, arrow-up-to-bracket_16 (y, formato válido pero dígito desaconsejado, 3-columns_32)
    • ❌ Floating-Window_16 (mayúsculas) · плавающее-окно_16 (no inglés) · floating_window_16 / icon__16 (dos guiones bajos) · floating--window_16 (doble guión) · floating-window-16 (guión en lugar de guión bajo antes del tamaño) · -floating-window_16 (guión inicial) · floating-window_20 (tamaño no en el conjunto permitido) · floating-window_16 (espacio final)
  • Sufijo -o = variante de contorno. El nombre sin -o es la variante rellena. Un par como cloud_24 / cloud-o_24 o cloud-arrow-up_24 / cloud-arrow-up-o_24 es un icono en dos estilos. Eso es válido y no es un conflicto ni un duplicado; no pidas un renombramiento por ello.

  • El sufijo numérico debe ser igual al tamaño real del componente (Regla B). Un ..._16 que es 24×24 es un error.

B. Geometría y diseño

  • Sin diseño automático: layoutMode === "NONE". El diseño automático recoloca los hijos y corrompe la exportación.
  • Fijo y cuadrado: width === height === size. El tamaño debe ser un número entero de píxeles (alineado a la cuadrícula de píxeles); los tamaños fraccionarios de componente significan que el icono no se dibujó en la cuadrícula.
  • Recortar contenido DESACTIVADO: clipsContent === false. La opción "Recortar contenido" debe estar deshabilitada. Debe ser lo mismo (desactivado) para cada variante de tamaño del icono. Cuando está activada, cualquier ilustración que se extienda más allá de los límites del marco se recorta silenciosamente en la exportación, produciendo un icono recortado o truncado.

C. Estructura raíz (aquí es donde se esconden la mayoría de los errores reales)

  • Icono de un solo color: exactamente un hijo raíz — un VECTOR llamado shape.
  • Icono de dos colores: exactamente dos hijos raíz — shape (primario) y shape-2 (secundario). Nada más.
  • Sin otros nodos en la raíz del componente: sin marcos, grupos, rectángulos, slices, vectores duplicados o capas auxiliares ocultas perdidos. Cada nodo extra termina en el SVG exportado.
  • Las restricciones de cada forma son SCALE en ambos ejes (horizontal: "SCALE", vertical: "SCALE") para que la ilustración se escale con el marco.
    • Gravedad: advertencia (higiene), no un bloqueante de exportación. Las restricciones controlan cómo el componente se redimensiona en Figma, no los datos de la ruta exportada. Arréglelas con las otras ediciones Figma aprobadas, porque las instancias y el redimensionamiento dependen de ellas.
  • Idealmente, cada forma es una única ruta aplanada (ver los pasos "Draw an icon" del README del repositorio: contornear, aplanar, regla de relleno Non-zero). Señala múltiples subrutas o grupos no aplanados como una advertencia.

D. Contrato de color de relleno

El contrato (README del repositorio "Guía de zonas de color SVG"):

  • Zona primaria shape → negro #21222C. La exportación elimina su fill para que el SVG herede currentColor.
  • Zona secundaria shape-2 → rojo #E21D03. La exportación lo reescribe a fill="currentColor".

Realidad práctica: en el archivo de producción, el relleno primario está vinculado a la variable compartida Icon/Contrast, que se resuelve a #000819 con una opacidad de pintura de 0.85 — no un #21222C literal. Por lo tanto:

  • Clave de referencia: 91eb54e0eae961c540c994192c4eed18e4ea1825 — Icon/Contrast de 🟥 koobiq · components 19 (clave de colección c78fab428cf2003c9aa53d86b132a2fa95acb2e2).
  • Compara la clave de la variable vinculada de la pintura primaria con esa referencia ((await figma.variables.getVariableByIdAsync(boundId)).key), y verifica que la opacidad de la pintura sea 0.85. No compares nombres: Icon/Contrast existe en varias bibliotecas y colecciones. La única variable permitida en un icono es esta, por clave. Una variable con el mismo nombre pero una clave diferente (de otra biblioteca o colección) es un fallo, no una advertencia. Solución: volver a vincular a la variable de la clave de referencia de la misma colección de biblioteca.
  • El shape-2 secundario debe ser o un #E21D03 literal sólido (la exportación lo coincide como un valor hexadecimal literal — secondaryZoneColorHex en .figmaexportrc.mjs), o estar vinculado por clave a Icon/Error de 🟥 koobiq · components 19 (clave e736157dcefc2a3e016ec2ddd41a7dc8cf8a5bc6). Para el caso de la variable, no se verifica la opacidad de la pintura. Cualquier otro relleno falla.
  • Un relleno primario que es un color literal simple que no coincide con ningún hermano, o un relleno secundario que no es #E21D03, se exportará con el color real en lugar de currentColor, rompiendo la capacidad del icono de heredar el color.

E. Metadatos de descripción

Cada componente debe tener un campo de descripción no vacío. El texto de la descripción debe ser un número de la issue de GitHub correspondiente (sin el prefijo #). No importa si la issue está cerrada o abierta, pero debe tener el formato 12345. No es necesario verificar la existencia real de la issue. Una descripción vacía o un texto que no sea un número son un fallo.

F. Coherencia entre variantes de tamaño

Después de inspeccionar cada variante de tamaño para el mismo icono base (por ejemplo, cloud en 16–64px), verifica:

  • Coherencia de nombre: todas las variantes comparten el mismo nombre base y solo difieren en el sufijo de tamaño numérico. Si algunas se han quedado en un nombre antiguo (por ejemplo, alert vs warning), señálalo.
  • Coherencia de la estructura raíz: el mismo número de hijos raíz en todos los tamaños y los mismos nombres de hijos. Una variante que tiene shape y shape-2 mientras que otras solo tienen shape es una señal de alarma.
  • Coherencia de relleno en el primario: la clave de variable / valor hexadecimal y la opacidad del shape primario deben coincidir en todos los tamaños. Si una variante usa un relleno literal sin Icon/Contrast, es un fallo.
  • Coherencia de clipsContent: debe ser false (o undefined/ausente) en todas las variantes. Si alguna tiene true (o clipsContent activado), señálalo como un fallo.
  • Coherencia de descripción: todas las variantes deben compartir el mismo número de issue. Si difieren, señala la discrepancia.
  • Nota sobre cobertura de tamaño: no es necesario que existan los cinco tamaños. Es perfectamente válido tener solo cloud_16 y cloud_24 sin los demás. Simplemente reporta qué tamaños están presentes.

G. Capas ocultas

figma.skipInvisibleInstanceChildren debe establecerse en false para que la inspección pueda ver las capas ocultas. Si un componente raíz tiene hijos ocultos (por ejemplo, un shape oculto además del shape visible), la exportación puede incluir o no esos hijos dependiendo de cómo se exporte el SVG. Señala los hijos ocultos como una advertencia. Una capa oculta que es un rectángulo de relleno de documento / máscara o una referencia de imagen (que la exportación ignora) no necesita ser reportada.

Ofrecer correcciones

Por defecto, la auditoría es de solo lectura. No modifiques el archivo Figma ni llames a use_figma en modo edición a menos que el usuario diga explícitamente "arréglalo" o "aplica las correcciones". Si el usuario pide correcciones, ejecútalas en el orden en que aparecen arriba (A → G) porque algunas correcciones tempranas pueden cambiar los nombres de los nodos que los pasos posteriores necesitan.

Las correcciones permitidas (solo bajo petición explícita):

  1. Renombrar el componente a un nombre que coincida con el regex y tenga el sufijo de tamaño correcto.
  2. Desactivar Recortar contenido (clipsContent = false).
  3. Restablecer las restricciones de las formas hijas a Escala en ambos ejes.
  4. Volver a vincular el relleno primario a la variable Icon/Contrast (clave de referencia anterior) con opacidad 0.85.
  5. Volver a vincular shape-2 a #E21D03 literal o a la variable Icon/Error (clave anterior).
  6. Establecer la descripción al número de issue proporcionado por el usuario (si el usuario da un número). No reordenes, agregues, elimines ni fusiones hijos raíz, y no fusiones capas ni invoques complementos (por ejemplo, flatten, outline stroke). El usuario debe hacer eso manualmente en Figma.

Límites de velocidad y robustez

  • Las llamadas a la API de Figma pueden fallar de forma intermitente. Si una llamada de solo lectura falla y aún no se ha realizado ninguna edición, espera 1 segundo y vuelve a intentarlo hasta 3 veces. Si la llamada es de edición y falla, informa del error — no reintentes las ediciones automáticamente (podrían aplicarse parcialmente).
  • Si el usuario pega un enlace de nodo de Figma que incluye un parámetro node-id, extráelo. Si el enlace es a un archivo diferente (la clave del archivo no coincide con WvUarBj8tO256vML4PkBLl), informa que el enlace es para un archivo diferente y no se puede auditar. No intentes abrir otros archivos.
  • Las incorporaciones anuales de nuevas variantes de tamaño (por ejemplo, 40px, 72px) romperán esta habilidad. Si los ids de página en la tabla de Prerrequisitos no devuelven las páginas de iconos esperadas, informa al usuario que la habilidad puede estar desactualizada y que necesita actualizar la tabla de ids de página o las comprobaciones de tamaño de sufijo.

Resumen visual

Ejemplo de reporte de salida (marcado sencillo, sin tablas complejas):

## Auditoría de iconos Koobiq: `floating-window`

### Barrido de tamaño
| nombre | 16 | 24 | 32 | 48 | 64 |
| --- | --- | --- | --- | --- | --- |
| floating-window_16 | 1320:17387 | 42149:860 | 42149:862 | 42149:861 | 42149:863 |

### A. Tipo de nodo y nombre
✅ `floating-window_16` es un COMPONENT
✅ El nombre coincide con el regex
✅ El sufijo de tamaño 16 coincide con el tamaño real 16

### B. Geometría y diseño
✅ layoutMode: NONE
✅ 16 × 16, entero alineado a píxeles
✅ clipsContent: false

### C. Estructura raíz
✅ 1 hijo raíz: `shape`
✅ Restricciones: [SCALE, SCALE]

### D. Contrato de color de relleno
✅ `shape` vinculado a Icon/Contrast (clave correcta, opacidad 0.85)
⚠️ `shape-2` no presente (2 tonos no requerido)

### E. Metadatos de descripción
✅ Descripción: "44731"

### F. Coherencia entre variantes
✅ Todas las variantes tienen el mismo nombre base y estructura
⚠️ La variante de 24px no existe (nueva, no se requiere)

### G. Capas ocultas
✅ No se encontraron capas ocultas debajo de la raíz

Skills relacionados