Communitygithub.com

iggypcnfsky/figma-bridge

Controle um arquivo Figma através do Figma Bridge local — leia a seleção, crie frames, texto e formas, vincule variáveis, coloque imagens, exporte PNG/SVG. Use quando uma tarefa exigir tocar em uma tela do Figma (inspecionar um design, implementar UI no Figma, trocar cores por tokens, exportar um ativo, inserir arte gerada). Requer o servidor bridge em localhost:3847 e o plugin Figma Bridge em execução no arquivo alvo; se indisponíveis, não improvise — peça ao usuário para iniciá-los.

O que é figma-bridge?

O Figma Bridge é uma habilidade (skill) que preenche uma lacuna crítica: o Figma não possui uma API de gravação pública. Esta solução utiliza uma bridge local que traduz operações nomeadas sobre HTTP em ações executadas dentro do Figma por um plugin, através da API de Plugin do Figma. Isso significa que os agentes de IA podem ler seleções, criar e modificar frames, texto e formas, vincular variáveis de design, gerar e colocar imagens, e exportar ativos em formatos como PNG e SVG — sem exigir autenticação OAuth ou tokens de API. A ferramenta é compatível com agentes como Claude Code, Cursor e Codex, e sua documentação completa pode ser encontrada no repositório `iggypcnfsky/figma-bridge`, que inclui um guia de operações. O fluxo de trabalho é iterativo: orientar-se, ler o estado atual, planejar as alterações, executar comandos em lote e verificar o resultado visualmente. A habilidade impõe regras importantes para evitar danos, como ler antes de escrever, nunca modificar camadas do usuário sem instrução explícita, e colocar novas versões ao lado das originais. Ela também gerencia pontas soltas como resolução de fontes, posicionamento relativo, e limitações de exportação, garantindo que o agente não improvise quando as pré-condições não são atendidas.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/iggypcnfsky/figma-bridge/tree/HEAD/.agents/skills/figma-bridge

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Figma Bridge

O Figma não possui uma API de gravação pública. Esta skill usa uma bridge local: operações nomeadas via HTTP, executadas dentro do Figma por um plugin, através da API de Plugin do Figma. Sem OAuth, sem tokens.

Repositório: https://github.com/iggypcnfsky/figma-bridge — AGENTS.md, docs/ops-reference.md.

Pré-condições — verifique antes de qualquer coisa

figma está no PATH, então nunca procure o repositório no sistema de arquivos:

figma doctor        # repositório, servidor, janelas conectadas, img-forge + chave FAL em um comando
figma clients       # id, arquivo, página de cada janela Figma conectada
figma rules         # restrições do projeto: tipo mínimo, grade, tamanho do frame, nomeação de versões

Leia figma rules antes de projetar. Ele carrega as limitações não óbvias — por exemplo, "Poppins 20/25 é o mínimo" — que nenhuma leitura da tela lhe dirá. Trate "confirmed": false como uma suposição a ser verificada com o usuário, e {} como "pergunte, não invente".

Se o comando estiver faltando, use node "$(figma where)/server.mjs" somente após perguntar; não execute find no repositório e não adivinhe caminhos.

  • pluginConnected: false → pare. Peça ao usuário para executar Plugins → Development → Figma Bridge na janela do arquivo que eles desejam modificar. Tentar novamente não ajuda.
  • 503 de /run significa a mesma coisa. 504 PLUGIN_GONE significa que eles fecharam a janela do plugin.
  • 409 significa que várias janelas do Figma estão conectadas e nenhuma foi escolhida. Selecione o arquivo que o usuário nomeou (--file <NOME>) ou um id de cliente (--client <ID>); nunca tente novamente cegamente, ou você pode editar o arquivo errado.

O ciclo

  1. Orientar-se. ./bin/figma status → nome do arquivo, página atual, seleção, todas as páginas.
  2. Ler. selection 2, node <id> 2, find {"name":"Header","allPages":true}. Nunca adivinhe um nodeId — ids do Figma parecem 4022:2 e não são deriváveis.
  3. Planejar. Decida pai, tamanho, ordem. Novos nós vão para a página atual, a menos que parentId seja fornecido.
  4. Escrever. ./bin/figma run '[{...},{...}]'.
  5. Verificar. ./bin/figma export <id> out/check.png PNG 2 e realmente olhe para a imagem.

Comandos

./bin/figma op '{"op":"status"}'
./bin/figma run '[{"op":"createFrame","name":"Card","width":320,"height":200,"fill":"#0B0B0F",
                   "props":{"cornerRadius":16,"layoutMode":"VERTICAL","paddingTop":24,"paddingLeft":24,"itemSpacing":12}}]'
./bin/figma run '[{"op":"createText","parentId":"12:34","characters":"Título","fontSize":24,"color":"#FFFFFF"}]'
./bin/figma op '{"op":"varFill","nodeId":"12:34","variableName":"color/bg/surface"}'
./bin/figma export 12:34 out/card.png PNG 2
./bin/figma image 12:34 out/cover.png FILL      # arquivo de imagem local → preenchimento (sem upload para nuvem)

Ops: ping status pages variables styles fonts inventory · selection node find · createFrame createRect createEllipse createText createPage createInstance · update clone reparent remove goto group ungroup select · grids setGrids align distribute effects · applyStyle varFill · export imageFill · exec. Parâmetros completos: docs/ops-reference.md.

Atalhos de trabalho de design que vale a pena conhecer:

  • grade significa GRADE: quando o usuário diz "definir uma grade", eles querem a grade de layout quadrada, não colunas: {"op":"setGrids","nodeId":"…","grid":true} (células de 40 px, 40% por padrão) ou "grid":40. Use columns/rows apenas quando eles disserem colunas, uma grade de 12 colunas, ou fornecerem valores de gutter/margem. Nunca finja uma grade com retângulos; applyStyle com kind:"grid" aplica um estilo de grade salvo.
  • linhas de itens: construa-os, depois {"op":"align","nodeIds":[…],"mode":"TOP"} e {"op":"distribute","nodeIds":[…],"axis":"HORIZONTAL","gap":24}.
  • profundidade: {"op":"effects","nodeId":"…","shadow":{"y":8,"blur":24,"color":"#00000033"}} ou {"op":"effects","nodeId":"…","blur":{"type":"BACKGROUND","radius":20}}.
  • gradientes: {"op":"gradient","nodeId":"…","kind":"linear","angle":135,"stops":[[0,"#8B76FF"],[1,"#0E0E12"]]} — ângulo 0 é esquerda → direita, 90 é topo → base. Nunca finja um gradiente com retângulos empilhados.
  • sistema de design: createInstance com um id COMPONENT, depois instanceProps para variantes (leia os nomes primeiro) e instanceText para alterar o texto sem desanexar; applyStyle para estilos. Não redesenhe o que a biblioteca já fornece e não desanexe uma instância para "corrigir" seu texto.
  • verificações de espaçamento: {"op":"measure","a":"1:2","b":"1:3"} retorna lacunas por lado e distância central; use em vez de exportar uma captura de tela para julgar alinhamento.
  • estilos: saveStyle cria ou atualiza um estilo text / paint / effect / grid por nome, e applyStyle o aplica. Crie o token uma vez, aplique-o em todos os lugares.
  • responsivo: sizing define HUG/FILL/FIXED por eixo mais min/max; constraints cobre filhos sem auto-layout (STRETCH/MIN/MAX/CENTER/SCALE). Leia ambos de node antes de alterá-los — sizing retorna skipped com o motivo do Figma quando uma propriedade não se aplica.

Imagens

Precisa de arte? Gere-a com o CLI irmão img-forge (https://github.com/iggypcnfsky/img-forge), depois coloque-a — a geração fica fora do Figma para que a chave da API nunca entre no código do plugin e uma renderização lenta não possa bloquear a tela:

cd ../img-forge
./img gen --prompt "capa gradiente abstrata, roxo a preto" --preset 16:9@2k --out out/cover.png
./img edit --prompt "torne-a noturna com acentos neon" --ref out/cover.png   # ou edite um ativo existente
cd ../figma-bridge
./bin/figma image 12:34 ../img-forge/out/cover.png FILL

FILL corta para o nó, FIT letterbox, TILE repete, CROP respeita o corte existente. Para editar o que o usuário selecionou, exporte-o primeiro (./bin/figma export <nodeId> out/sel.png PNG 2) e passe esse arquivo como --ref.

A janela do plugin também tem um painel Gerar / Editar para humanos (modelo, predefinições de tamanho, custo, inserir). Não acione o painel programaticamente — use o CLI; ele expõe mais (máscara, variantes, teste simulado). As predefinições salvas nesse painel residem em figma-bridge/presets.json.

Construindo sobre um rascunho existente

Um rascunho que "não está terminado" ainda codifica decisões: o que está ao lado do que, o que está agrupado, a ordem dos elementos, o ritmo de espaçamento. Leia-o antes de projetar, depois mantenha-o.

  1. {"op":"inventory"} — os frames, seus tamanhos e estatísticas tipográficas.
  2. {"op":"structure","nodeId":"<frame>"} — filhos agrupados em linhas com lacunas e um readingOrder; esse é o agrupamento que o autor escolheu. {"op":"node",…,"depth":2} fornece a mesma árvore com mais profundidade.
  3. Observe o padrão (uma margem esquerda que se repete, um título que sempre fica acima de três colunas) e mantenha-o. Altere o que a solicitação precisa, deixe o resto onde está.
  4. Relate os desvios que você fez — "moveu o rodapé para cima em 40", não apenas "melhorou o layout".

Nunca normalize um rascunho silenciosamente. Se a consistência exigir mover coisas que o usuário colocou, diga isso e pergunte; um slide de aparência organizada que perdeu seus agrupamentos é uma regressão, não uma melhoria.

Regras

  • Leia antes de escrever. Mínimo de duas chamadas: inspecione, depois modifique.
  • Um lote = um pensamento. Uma operação não pode referenciar o resultado de uma operação anterior, então se você precisar do id do novo nó, divida em duas chamadas.
  • Respeite o arranjo que você herda: ordem dos irmãos, proximidade e agrupamento são intenção. Não reorganize um rascunho para parecer mais arrumado a menos que solicitado; pergunte primeiro quando a consistência mover seus elementos.
  • Nunca toque nas camadas existentes do usuário (update, remove, reparent) sem instrução explícita. Prefixe suas próprias criações: Bridge / ….
  • Uma reformulação vai logo ao lado do original, o mais próximo possível. Se solicitado a refazer um slide/tela/seção: duplique-o, chame {"op":"placeNear","nodeId":"<novo id>","move":true,"gap":80,"name":"Bridge / v2 — <nome>"} para que a cópia caia no primeiro lado livre em vez de uma coordenada adivinhada, e deixe o original intacto. Se a ferramenta relatar free: false, pergunte para onde deve ir. Substitua elementos no lugar apenas quando o usuário solicitar explicitamente.
  • goto altera a visualização do usuário — somente mediante solicitação.
  • exec é um último recurso. Funciona (o sandbox do Figma permite new Function) e ignora toda validação de parâmetros. Retorne apenas valores serializáveis em JSON.
  • Limpe artefatos de teste ou pergunte se deve mantê-los.

Armadilhas

  • Use localhost, nunca 127.0.0.1: o manifesto do plugin permite apenas http://localhost:3847 (devAllowedDomains); o Figma rejeita IPs. O servidor escuta em ambos 127.0.0.1 e ::1.
  • figma.currentPage é a página aberta naquela janela do Figma — não um ponteiro salvo. Alterar abas muda o que você vê na próxima chamada.
  • As posições são relativas ao pai, e um parentId omitido significa a página atual.
  • Perguntas de tipografia (quais fontes, tamanhos, contagens) são uma chamada: {"op":"fonts"}; adicione "allPages":true para o arquivo inteiro. Não percorra frames com seu próprio script.
  • Uma visão geral de slides é uma chamada também: {"op":"inventory"} retorna cada frame com geometria, minFontSize, fontes, contagem de grades e preenchimentos — o suficiente para escolher "frames 11–19" ou encontrar texto abaixo de um tamanho mínimo.
  • Nunca indexe um campo que a referência não lista. summary carrega font, fontSize, lineHeight e letterSpacing para TEXT; todo o resto vem de exec com o nome real da API. Estilos mistos são a string "MIXED", então proteja com .get() e fallbacks.
  • Um retângulo não pode ter filhos; use um frame quando texto ou ícones devem ficar dentro de uma forma.
  • Sem variáveis locais → variables retorna collections: [] e varFill falha. Verifique primeiro.
  • Texto precisa de uma fonte: createText a carrega via loadFontAsync; se a família estiver faltando, use Inter.
  • export tem limite de 8 MB — reduza scale em vez de tentar novamente.
  • Ler filhos de uma página não atual requer loadAllPagesAsync; a bridge tenta novamente uma vez automaticamente, mas prefira find com allPages: true.
  • Após editar arquivos do plugin (code.js, ui.html), o usuário deve executar o plugin novamente; alterações em manifest.json precisam de uma reimportação.

Habilidades Relacionadas