O que Auditoria de Ícones Koobiq no Figma faz?
Esta skill verifica se um componente de ícone no arquivo Figma de ícones Koobiq segue as convenções estruturais da biblioteca, para que figma:sync (o pipeline @figma-export) produza um SVG limpo e correto. Identificar problemas no Figma é muito mais barato do que descobri-los após a exportação, porque a exportação transforma silenciosamente tudo o que encontra — um nome de camada errado, um nó extra ou uma coordenada fora da grade se torna um SVG quebrado sem nenhum erro.
É uma auditoria somente leitura por padrão: inspecione e, em seguida, relate um checklist claro de aprovado/reprovado com achados específicos e acionáveis. Modifique o arquivo Figma apenas se o usuário solicitar explicitamente que você corrija algo (consulte "Oferecendo correções").
Pré-requisitos
-
O MCP do Figma deve estar conectado. Esta skill o utiliza através de
get_metadata(visão geral da estrutura),use_figma(inspeção precisa via API do Plugin) eget_screenshot(verificação visual de sanidade). -
Antes de qualquer chamada
use_figma, carregue a skillfigma-use— ela documenta as regras da API do Plugin e previne falhas comuns e difíceis de depurar. -
A chave do arquivo e as páginas de tamanho são fixas (verificadas em relação ao documento ativo). Para pular uma viagem de ida e volta de descoberta de página, vá direto para uma página pelo seu node id:
tamanho node id da página 16 1320:1738724 42149:86032 42149:86248 42149:86164 42149:863Chave do arquivo:
WvUarBj8tO256vML4PkBLl. Cada nome de página é o sufixo de tamanho; um ícone chamadofoo_24vive na página24. Documento: https://www.figma.com/design/WvUarBj8tO256vML4PkBLl/%F0%9F%9F%A5-koobiq-%C2%B7-icons?node-id=1320-17387- Esta chave de arquivo é a fonte da verdade — corresponde a
config.mjs. O link "Desenhe um ícone" empackages/icons/README.mdaponta para um arquivo diferente e errado — ignore-o e confie na chave acima. get_metadatasem umnodeIdlista apenas a primeira página (ICONS, que não contém componentes de ícone) — ela não enumera as páginas de tamanho. Não a use para descoberta de páginas; use os node ids acima.
- Esta chave de arquivo é a fonte da verdade — corresponde a
Se o arquivo não puder ser acessado
Se uma chamada do Figma falhar — erro de autenticação/permissão, "nó não existe", um arquivo vazio/inesperado ou o MCP não respondendo — pare e comunique ao usuário em vez de adivinhar. Diga a ele o que falhou e peça que faça uma das seguintes ações:
- fornecer um link diferente / correto do Figma (a chave do arquivo em
config.mjspode estar desatualizada, ou ele colou um link para outro arquivo ou branch), ou - verificar novamente o
FIGMA_TOKENno.envdo repositório (o token de acessofigma-export/ MCP pode estar ausente, expirado ou revogado), ou - confirmar que a conta Figma dele tem acesso ao arquivo (é um arquivo de design privado — pode ser necessário convidá-lo ou usar um token vinculado a uma conta com permissão).
Não invente um resultado de auditoria a partir de suposições; uma verificação só é significativa contra o arquivo ativo.
Leituras paralelas e contexto de página
Chamadas de leitura do Figma podem ser executadas em paralelo, mas apenas antes da primeira edição no Figma da tarefa. Após qualquer edição ter começado, execute as chamadas do Figma uma de cada vez.
Leituras paralelas que alternam páginas podem interferir umas nas outras. Em uma execução observada, uma leitura que visava a página 24 retornou dados da página 16 (a mesma contagem de componentes, nomes errados), e a auditoria relatou as variantes de 24px como ausentes. Proteja cada leitura que alterna páginas:
// Use em cada leitura que alterna páginas. Retorna dados apenas para nós que pertencem a PAGE_ID.
const PAGE_ID = "42149:860"; // node id da página da tabela acima
const NAMES = ["foo_24"]; // nomes de componentes a serem procurados
const page = await figma.getNodeByIdAsync(PAGE_ID);
await figma.setCurrentPageAsync(page);
if (figma.currentPage.id !== PAGE_ID) throw new Error("incompatibilidade de contexto de página antes da leitura");
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("contexto de página alterado durante a leitura");
return { pageId: PAGE_ID, hits };
Se uma proteção lançar um erro, descarte esse resultado e execute a leitura novamente. Uma alegação de "ausente" (por exemplo, "nenhuma variante de 24px") deve se basear em uma leitura protegida dessa página, ou em uma pesquisa por node id. Nunca relate ausência de uma leitura que lançou um erro ou de uma página que você não verificou.
Etapa 1 — Resolver o alvo
O usuário pode lhe fornecer qualquer um dos seguintes:
- Uma URL ou id de nó do Figma (ex:
node-id=44731-6643) → inspecione exatamente esse nó e também procure suas variantes de tamanho irmãs pelo nome para a verificação entre variantes. - Um nome de ícone (ex:
floating-window, oufloating-window_16) → encontre todas as variantes de tamanho nas páginas de ícones e verifique todas elas. Novos ícones geralmente são não publicados e podem até não ter nome, então, se uma correspondência de nome falhar, liste os componentes na(s) página(s) relevante(s) e peça ao usuário para apontar para o nó, ou inspecione pelo node id.
Os nomes das páginas são iguais ao sufixo de tamanho. Varredura de tamanho: verifique todas as cinco páginas (16 / 24 / 32 / 48 / 64) para cada nome solicitado, porque um ícone pode existir em tamanhos que o usuário não mencionou. Use os node ids de página da tabela de Pré-requisitos, uma chamada use_figma por página, cada uma com a proteção de "Leituras paralelas e contexto de página". Execute-as em paralelo apenas antes de qualquer edição no Figma. Relate o resultado como uma tabela (nome × tamanho → node id ou ausente).
Etapa 2 — Inspecionar
Execute este script somente leitura (adapte os targets/id da página). Ele retorna tudo que as regras abaixo precisam. Combine-o com um get_screenshot para confirmar que o glifo realmente renderiza.
// Cole em use_figma (skillNames: "figma-use"). Defina PAGE_ID e NAMES.
// Node ids 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 cujo nome é o tamanho, ex: "16"
const NAMES = ["floating-window_16"]; // nome(s) do(s) componente(s) a auditar nesta página
figma.skipInvisibleInstanceChildren = false; // false: a regra G deve ver também camadas ocultas
const page = await figma.getNodeByIdAsync(PAGE_ID);
await figma.setCurrentPageAsync(page);
if (figma.currentPage.id !== PAGE_ID) throw new Error("incompatibilidade de contexto de página antes da leitura");
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 ? "MISTURADO" : 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("contexto de página alterado durante a leitura");
return report;
Para validar o contrato de cor de forma confiável, leia também um ícone irmão conhecido como bom do mesmo tamanho (ex: list_16) da mesma forma e compare a chave da variável vinculada da forma primária (Regra D). O hexadecimial do contrato nominal e o valor realmente armazenado no arquivo diferem (veja Regra D), portanto comparar com um vizinho real é mais confiável do que corresponder a um hex literal.
Etapa 3 — Verificar em relação às regras
Relate cada uma como ✅ aprovado / ❌ reprovado com o valor observado e, na falha, o que deveria ser.
A. Tipo de nó e nome
-
O nó é um
COMPONENT(ou umCOMPONENT_SETde variantes de tamanho), não umFRAME,GROUPouINSTANCE. Apenas componentes exportam. -
Primeiro caractere — verifique isso primeiro, pois altera o que o nome significa:
- Começa com
.ou_→ um componente interno, intencionalmente NÃO exportado. OfilterComponentda exportação em.figmaexportrc.mjsremove qualquer nome que corresponda a^[._]. Isso é proposital, não um bug — não audite como um ícone quebrado. Apenas levante se o usuário esperava que este nó exportasse (então a correção é renomeá-lo sem o./_inicial). - Começa com
-→ inválido, não permitido. Sinalize como falha. - Começa com um dígito → permitido, mas desencorajado. Ainda exporta (ex:
3-columns_32), mas um nome deve preferencialmente começar com uma letra inglesa — sugira ao usuário renomeá-lo. Recomendação suave, não um bloqueador. - Começa com uma letra minúscula inglesa → o caso preferido.
- Começa com
-
Formato do nome — o nome de um ícone exportável deve corresponder a esta regex:
^[a-z0-9]+(-[a-z0-9]+)*_(16|24|32|48|64)$Apenas letras minúsculas inglesas e dígitos; palavras unidas por hifens simples (sem
--, sem hífen inicial/final); então exatamente um underscore; então um sufixo de tamanho válido. Sem maiúsculas, espaços, cirílico/outros scripts ou outra pontuação.- ✅
floating-window_16,api_24,arrow-up-to-bracket_16(e, formato válido mas dígito desencorajado,3-columns_32) - ❌
Floating-Window_16(maiúsculas) ·плавающее-окно_16(não inglês) ·floating_window_16/icon__16(dois underscores) ·floating--window_16(hífen duplo) ·floating-window-16(hífen em vez de underscore antes do tamanho) ·-floating-window_16(hífen inicial) ·floating-window_20(tamanho não no conjunto permitido) ·floating-window_16(espaço à direita)
- ✅
-
Sufixo
-o= variante outline. O nome sem-oé a variante preenchida. Um par comocloud_24/cloud-o_24oucloud-arrow-up_24/cloud-arrow-up-o_24é um ícone em dois estilos. Isso é válido e não é um conflito ou duplicata; não peça uma renomeação por causa disso. -
O sufixo numérico deve ser igual ao tamanho real do componente (Regra B). Um
..._16que é 24×24 é um bug.
B. Geometria e layout
- Sem auto-layout:
layoutMode === "NONE". Auto-layout refluxa os filhos e corrompe a exportação. - Fixo e quadrado:
width === height === size. O tamanho deve ser um número inteiro de pixels (alinhado à grade de pixels); tamanhos de componentes fracionários significam que o ícone não foi desenhado na grade. - Clip content DESLIGADO:
clipsContent === false. A opção "Clip content" deve estar desabilitada. Deve estar igual (desligada) para cada variante de tamanho do ícone. Quando está ligada, qualquer arte que se estenda além dos limites do quadro é silenciosamente cortada na exportação, produzindo um ícone cortado ou truncado.
C. Estrutura raiz (é aqui que a maioria dos bugs reais se esconde)
- Ícone de uma cor: exatamente um filho raiz — um
VECTORchamadoshape. - Ícone de duas cores: exatamente dois filhos raiz —
shape(primário) eshape-2(secundário). Nada mais. - Nenhum outro nó na raiz do componente: sem quadros soltos, grupos, retângulos, slices, vetores duplicados ou camadas auxiliares ocultas. Cada nó extra aparece no SVG exportado.
- As constraints de cada shape são
SCALEem ambos os eixos (horizontal: "SCALE",vertical: "SCALE") para que a arte escale com o quadro.- Gravidade: aviso (higiene), não um bloqueador de exportação. Constraints controlam como o componente redimensiona no Figma, não os dados do caminho exportado. Corrija-as com as outras edições aprovadas no Figma, porque instâncias e redimensionamento dependem delas.
- Idealmente, cada shape é um único caminho achatado (veja as etapas "Desenhe um ícone" no README do repositório: contorno, achatar, regra de preenchimento Non-zero). Sinalize vários subcaminhos ou grupos não achatados como um aviso.
D. Contrato de cor de preenchimento
O contrato (README do repositório "Guia de Zonas de Cores SVG"):
- Zona primária
shape→ preto#21222C. A exportação remove seufillpara que o SVG herdecurrentColor. - Zona secundária
shape-2→ vermelho#E21D03. A exportação o reescreve parafill="currentColor".
Realidade prática: no arquivo de produção, o preenchimento primário está vinculado à variável compartilhada Icon/Contrast, que resolve para #000819 com opacidade de pintura 0,85 — não um #21222C literal. Portanto:
- Chave de referência:
91eb54e0eae961c540c994192c4eed18e4ea1825—Icon/Contrastde🟥 koobiq · components 19(chave da coleçãoc78fab428cf2003c9aa53d86b132a2fa95acb2e2). - Compare a chave da variável vinculada da pintura primária com essa referência (
(await figma.variables.getVariableByIdAsync(boundId)).key) e verifique se a opacidade da pintura é 0,85. Não compare nomes:Icon/Contrastexiste em várias bibliotecas e coleções. A única variável permitida em um ícone é esta, pela chave. Uma variável com o mesmo nome, mas com uma chave diferente (de outra biblioteca ou coleção) é uma falha, não um aviso. Correção: reassocie à variável de chave de referência da mesma coleção de biblioteca. shape-2secundário deve ser ou um#E21D03literal sólido (a exportação o corresponde como um hex literal —secondaryZoneColorHexem.figmaexportrc.mjs), ou vinculado por chave aIcon/Errorde🟥 koobiq · components 19(chavee736157dcefc2a3e016ec2ddd41a7dc8cf8a5bc6). Para o caso de variável, a opacidade da pintura não é verificada. Qualquer outro preenchimento falha.- Um preenchimento primário que é uma cor literal simples que não corresponde a nenhum irmão, ou um preenchimento secundário que não é
#E21D03, exportará com a cor errada.
E. Descrição do componente
- A
descriptiondo componente deve ser não vazia e conter pelo menos o seguinte:- Nomes de variantes — uma linha ou duas descrevendo as variantes presentes ("filled", "outline"), ou a variante única.
- Zonas de cores — uma descrição de quais partes do ícone são
shapevsshape-2(se aplicável). - Qualquer contexto de uso (opcional, mas recomendado).
- Se a descrição estiver vazia ou for insuficiente, sinalize como uma falha com uma sugestão do que adicionar.
F. Consistência entre variantes
- Para um COMPONENT_SET ou para variantes de tamanho irmãs do mesmo nome base:
- Todas as variantes devem ter a mesma estrutura raiz (todas monocromáticas com um
shape, ou todas de duas cores comshape+shape-2). - A presença/ausência do sufixo
-odeve ser consistente: sefoo_24existe,foo-o_24pode ou não existir, masfoo_16efoo-o_16devem seguir o mesmo padrão. Se um ícone tem uma variante-oem um tamanho, deve tê-la em todos os tamanhos onde o ícone existe. - A chave da variável de preenchimento primário (
Icon/Contrast) deve ser a mesma em todas as variantes. A chave da variável de preenchimento secundário (se presente) também deve ser a mesma em todas as variantes.
- Todas as variantes devem ter a mesma estrutura raiz (todas monocromáticas com um
- Cruze todos os tamanhos encontrados na varredura da Etapa 1 e relate discrepâncias.
G. Camadas ocultas
- Nenhuma camada oculta na raiz do componente (filho com
visible === false). Camadas ocultas são normalmente deixadas para trás ao copiar/colar de outro lugar ou durante a edição. - Se uma camada oculta existir:
- Se for um VECTOR chamado
shapeoushape-2(ou seja, um candidato a caminho de ícone real) → muito provavelmente é um fantasma de edição. Um dos passos de desenho (contorno, achatar) deixou para trás o caminho original. Sinalize como falha: a camada oculta deve ser excluída. - Caso contrário → sinalize como aviso: poucas desculpas boas para uma camada oculta dentro de um ícone.
- Se for um VECTOR chamado
- Exceção: a exportação intencionalmente ignora camadas com nome começando por
_ou.(elas são privadas). Uma camada oculta com esse nome é um aviso leve.
Etapa 4 — Relatar
Produza um resumo:
## Resumo da Auditoria: <nome-do-ícone>
### Resultado Geral: ✅ APROVADO / ❌ REPROVADO
### Por Tamanho
| Tamanho | Nó | Tipo | A | B | C | D | E | F | G |
|---------|-----|------|---|---|---|---|---|---|---|
| 16 | … | COMP … | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ |
| 24 | … | COMP … | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
…
### Achados Detalhados
…
Não produza uma contagem de "passo 3", "passo 4" — apenas o resumo acima.
Oferecendo correções
Por padrão, esta skill é somente leitura. Se você encontrar problemas, relate-os e pergunte ao usuário se deseja que você os corrija. Se o usuário disser "sim" ou "corrija" ou "conserte", você pode executar use_figma com um script de edição para corrigir problemas. Edições permitidas (somente estas):
- Renomear o componente (corrigir formato do nome, maiúsculas, etc.)
- Definir
clipsContent = false - Definir
constraintspara SCALE - Excluir nós extras (incluindo camadas ocultas fantasmas)
- Atualizar a descrição
- Vincular a variável de preenchimento correta por id de chave (
Icon/Contrast)
Nunca modifique a geometria, mova ou redimensione o componente ou qualquer um de seus shape filhos, ou altere a ordem de empilhamento.
Se várias correções forem necessárias, aplique-as em uma única chamada use_figma (edição em lote) e, em seguida, execute uma segunda auditoria para confirmar que todas as verificações passam.
Boas práticas
- Sempre pegue um
get_screenshotdo ícone após a auditoria (ou correção) para verificação visual. - Se o arquivo Figma não puder ser acessado, não fabrique um relatório de auditoria. Pare e informe o usuário.
- A chave de arquivo
WvUarBj8tO256vML4PkBLlé a única fonte da verdade. Ignore quaisquer outras chaves de arquivo de documentação. - Ao verificar regras entre variantes, garanta leituras protegidas de cada página de tamanho.
- As regras F (Consistência entre variantes) e G (Camadas ocultas) são menos críticas, mas importantes para a saúde do código.