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 executarPlugins → Development → Figma Bridgena janela do arquivo que eles desejam modificar. Tentar novamente não ajuda.503de/runsignifica a mesma coisa.504 PLUGIN_GONEsignifica que eles fecharam a janela do plugin.409significa 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
- Orientar-se.
./bin/figma status→ nome do arquivo, página atual, seleção, todas as páginas. - Ler.
selection 2,node <id> 2,find {"name":"Header","allPages":true}. Nunca adivinhe umnodeId— ids do Figma parecem4022:2e não são deriváveis. - Planejar. Decida pai, tamanho, ordem. Novos nós vão para a página atual, a menos que
parentIdseja fornecido. - Escrever.
./bin/figma run '[{...},{...}]'. - Verificar.
./bin/figma export <id> out/check.png PNG 2e 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. Usecolumns/rowsapenas quando eles disserem colunas, uma grade de 12 colunas, ou fornecerem valores de gutter/margem. Nunca finja uma grade com retângulos;applyStylecomkind:"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:
createInstancecom um idCOMPONENT, depoisinstancePropspara variantes (leia os nomes primeiro) einstanceTextpara alterar o texto sem desanexar;applyStylepara 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:
saveStylecria ou atualiza um estilotext/paint/effect/gridpor nome, eapplyStyleo aplica. Crie o token uma vez, aplique-o em todos os lugares. - responsivo:
sizingdefineHUG/FILL/FIXEDpor eixo mais min/max;constraintscobre filhos sem auto-layout (STRETCH/MIN/MAX/CENTER/SCALE). Leia ambos denodeantes de alterá-los —sizingretornaskippedcom 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.
{"op":"inventory"}— os frames, seus tamanhos e estatísticas tipográficas.{"op":"structure","nodeId":"<frame>"}— filhos agrupados em linhas com lacunas e umreadingOrder; esse é o agrupamento que o autor escolheu.{"op":"node",…,"depth":2}fornece a mesma árvore com mais profundidade.- 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á.
- 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
iddo 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 relatarfree: false, pergunte para onde deve ir. Substitua elementos no lugar apenas quando o usuário solicitar explicitamente. gotoaltera a visualização do usuário — somente mediante solicitação.execé um último recurso. Funciona (o sandbox do Figma permitenew 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, nunca127.0.0.1: o manifesto do plugin permite apenashttp://localhost:3847(devAllowedDomains); o Figma rejeita IPs. O servidor escuta em ambos127.0.0.1e::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
parentIdomitido significa a página atual. - Perguntas de tipografia (quais fontes, tamanhos, contagens) são uma chamada:
{"op":"fonts"}; adicione"allPages":truepara 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.
summarycarregafont,fontSize,lineHeighteletterSpacingpara TEXT; todo o resto vem deexeccom 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 →
variablesretornacollections: []evarFillfalha. Verifique primeiro. - Texto precisa de uma fonte:
createTexta carrega vialoadFontAsync; se a família estiver faltando, useInter. exporttem limite de 8 MB — reduzascaleem vez de tentar novamente.- Ler filhos de uma página não atual requer
loadAllPagesAsync; a bridge tenta novamente uma vez automaticamente, mas prefirafindcomallPages: true. - Após editar arquivos do plugin (
code.js,ui.html), o usuário deve executar o plugin novamente; alterações emmanifest.jsonprecisam de uma reimportação.