Figma Craft -- desenhar certo na primeira passada
O use_figma executa JS pela Plugin API. Ele nao "desenha": ele constroi uma arvore de nos.
Layout quebrado quase nunca e erro de API -- e arvore errada, ou sizing decidido no reflexo.
Esta skill cobre a decisao. As regras de API vivem nas skills oficiais do MCP.
1. Pre-voo obrigatorio
Antes de QUALQUER escrita no Figma, carregar via get_figma_skill:
| Sempre |
skill://figma/figma-use/SKILL.md |
| Tela, pagina, modal, secao composta |
+ skill://figma/figma-generate-design/SKILL.md |
| Componente, variante, variable, token |
+ skill://figma/figma-generate-library/SKILL.md |
| FigJam (board) |
+ skill://figma/figma-use-figjam/SKILL.md |
| Arquivo novo |
+ skill://figma/figma-create-new-file/SKILL.md |
| Layout ja quebrado, conserto |
+ skill://figma/figma-use/references/gotchas.md |
Passar skillNames: "resource:figma-use,resource:figma-craft" na chamada use_figma.
Nao pular por ser "uma mudanca pequena". As falhas de auto layout aparecem justamente nas pequenas.
Alem das skills, dois groundings antes de gerar:
- Design system primeiro. Arquivo com library/tokens: analisar o DS antes de gerar
("Analyze this design system file"), ativar a library no arquivo destino e construir com
instancias reais bindadas a tokens. Componente que ja existe na library nunca e redesenhado.
Ordem de descoberta: Code Connect → engenharia reversa de telas existentes →
search_design_system.
- Fonte real do produto. Descobrir a font-family verdadeira antes de criar texto -- sem isso o
gerador cai no Inter. Depois do build, validar por assercao (ler
fontName dos textos criados).
2. Desenhar a arvore ANTES de escrever codigo
Erro numero um: comecar a criar nos e resolver o layout depois. Nao funciona -- no Figma o
sizing depende do pai, entao a arvore errada obriga a consertar tudo no fim.
Escrever a arvore em texto primeiro, na mensagem, antes do primeiro use_figma:
Screen (V, FILL x FIXED 1080, pad 0, gap 0)
├─ Topbar (H, FILL x HUG, pad 12/24, gap 16, align center/space-between)
│ ├─ Logo (FIXED 120x32)
│ └─ Actions (H, HUG x HUG, gap 8)
└─ Body (H, FILL x FILL, pad 24, gap 24)
├─ Sidebar (V, FIXED 280 x FILL, pad 16, gap 4)
└─ Content (V, FILL x FILL, pad 0, gap 16)
Notacao: (direcao, sizingH x sizingV, padding, gap, alinhamento).
Se nao souber dizer o sizing de um no, o layout ainda nao esta decidido -- decidir antes de criar.
Regras da arvore:
- Todo container com 2+ filhos relacionados e auto layout (
figma.createAutoLayout()), nunca frame com x/y.
- Nunca GROUP. Group nao tem sizing, nao tem padding, e quebra quando o conteudo muda.
- Um no so existe se tem papel: estrutura, agrupamento semantico ou espaco. Wrapper sem funcao vira ruido no painel de camadas e no handoff.
- Profundidade util raramente passa de 4-5 niveis. Se passou, provavelmente tem wrapper sobrando.
- Elemento repetido (card de grid, linha de tabela, chip) vira UM componente local + instancias --
nunca N frames quase iguais. Override de texto em instancia com
setProperties(), nao characters.
- Criar o frame wrapper da tela PRIMEIRO, longe do conteudo existente, e construir dentro dele.
Nunca criar secoes como filhas top-level da pagina pra reparentar depois -- mover no falha em silencio.
- Uma secao por chamada
use_figma, nunca a tela inteira num script so. Imports em lote com Promise.all.
3. Sizing por papel do elemento
Decidir por papel, nao por "o que parece certo agora". Tabela de referencia:
| Elemento |
Horizontal |
Vertical |
Por que |
| Frame da tela |
FIXED (largura do breakpoint) |
FIXED ou HUG |
Ancora do canvas |
| Topbar / header |
FILL |
HUG |
Acompanha a largura, altura vem do conteudo |
| Sidebar |
FIXED |
FILL |
Largura e decisao de design, altura acompanha a tela |
| Area de conteudo |
FILL |
FILL |
Absorve o espaco que sobra |
| Card em grid |
FILL |
HUG |
Divide a linha, cresce com o texto |
| Linha de lista |
FILL |
HUG |
-- |
| Botao |
HUG (ou FILL se full-width) |
HUG |
Padding define o tamanho |
| Icone |
FIXED (16/20/24) |
FIXED |
Nunca FILL, nunca HUG |
| Texto de uma linha (label) |
HUG |
HUG |
-- |
| Texto que quebra linha |
FILL + textAutoResize = 'HEIGHT' |
HUG |
FILL sozinho colapsa o texto pra largura ~0 |
| Divider |
FILL |
FIXED 1 |
-- |
| Avatar / thumb |
FIXED |
FIXED |
-- |
Ordem de operacoes que evita a maioria dos erros:
figma.createAutoLayout(direcao) no pai
parent.appendChild(filho)
resize() se precisar de dimensao fixa
- so entao
layoutSizingHorizontal / layoutSizingVertical
resize() reseta sizing pra FIXED -- por isso vem antes. E HUG/FILL sao rejeitados se o no
ainda nao esta dentro de um auto layout, por isso o appendChild vem antes.
Nao confundir os dois enums:
- filho:
layoutSizingHorizontal/Vertical = FIXED | HUG | FILL
- frame:
primaryAxisSizingMode/counterAxisSizingMode = FIXED | AUTO
4. Spacing e alinhamento
- Padding e gap sempre em multiplos de 4; preferir a escala 4 / 8 / 12 / 16 / 24 / 32 / 48 / 64.
- Nunca simular espaco com frame vazio, texto em branco ou x/y solto. Espaco e
itemSpacing e padding.
- Distribuir extremos com
primaryAxisAlignItems = 'SPACE_BETWEEN', nao com spacer.
- Alinhamento vertical de linha com icone + texto:
counterAxisAlignItems = 'CENTER' no pai. Nunca ajustar y do icone.
- Espaco negativo (avatares sobrepostos) e
itemSpacing negativo, nao posicao absoluta.
- Se o container e so estrutura, limpar o fill:
figma.createAutoLayout() vem com fill branco padrao
e ele aparece como retangulo branco sobre fundo tonal.
5. Gotchas que ja custaram retrabalho
Verificados em projeto real de cliente, nao teoricos:
- No movido entre containers carrega o layout antigo. Depois de
appendChild, resetar
layoutSizingHorizontal/Vertical E layoutPositioning = 'AUTO'. Sintomas: elemento colado no vizinho
ignorando o gap, altura colapsada pra 1px, conteudo cortado.
node.screenshot() renderiza o no ISOLADO -- mostra o elemento certo enquanto no canvas real
esta quebrado. Validar por propriedades primeiro, imagem depois (secao 6).
- Nunca usar
rotation pra virar icone dentro de auto layout. A rotacao gira em torno da origem e
joga o no pra fora da caixa reservada. Usar instance.swapComponent(outroComponente).
- No herdado que resiste a duas tentativas de conserto: remontar. Recriar o container com
createAutoLayout() e reanexar os filhos custa menos chamadas do que insistir.
query() nao aceita nome com espaco (FRAME[name=Product Context] retorna null).
Usar findOne(n => n.name === '...').
- Comentarios do Figma nao sao acessiveis pela Plugin API (
figma.comments nao existe).
Pedir o texto colado.
- Cor em 0-1, nao 0-255. Sem canal
a dentro de color -- opacidade fica no nivel do paint.
- O canvas do usuario fica em cache depois de escrita via plugin. Ele reporta texto cortado,
elemento fora do lugar ou artefato flutuando, e no arquivo esta tudo certo. Antes de "consertar" o
que nao esta quebrado: medir as propriedades e renderizar com
get_screenshot (render do servidor,
e a prova do estado salvo). Batendo os dois, pedir reload -- nao mexer no layout. Ja custou duas
idas e voltas em producao (seletor de area de topbar, campos de formulario).
textAutoResize = 'HEIGHT' e rejeitado silenciosamente se o no esta com altura fixa.
Em auto layout, soltar layoutSizingVertical = 'HUG' ANTES. Sintoma: setar HEIGHT e continuar
lendo NONE -- o pior modo, porque o texto nao cresce nem em altura, so corta.
6. Validar antes de dizer que esta pronto
Ordem obrigatoria: propriedades → screenshot do container pai → screenshot do canvas.
Screenshot do no isolado nunca e prova.
Rodar o script de auditoria em references/audit-layout.md no frame trabalhado. Ele varre a arvore
e sinaliza: GROUP, frame com varios filhos sem auto layout, layoutPositioning = ABSOLUTE dentro de
auto layout, dimensao colapsada, texto com FILL sem textAutoResize = HEIGHT, spacing fora da grade de 4.
Zero flags e o criterio de pronto. Flag que for decisao consciente, dizer qual e por que.
Complementos por secao, enquanto o conserto e barato:
- Screenshot da secao logo depois de construi-la (nao so no fim da tela): pega texto cortado,
overlap, variante errada e placeholder esquecido.
- Assercao de fonte: ler
fontName dos textos criados e comparar com a fonte do produto.
7. Checklist final
Fronteiras
- Craft visual estatico (cor, tipografia, hierarquia, polish) →
/ui-designer
- Tokens, arquitetura de DS, auditoria de consistencia →
/design-system
- Fluxo, IA, psicologia da tela →
/ux-designer
- Ler Figma e implementar em React → skill oficial
figma-design-to-code
1---2name: figma-craft3description: Craft de layout ao DESENHAR no Figma via MCP (code-to-design). Ativa sempre que a tarefa for criar, montar, editar, corrigir ou reorganizar qualquer coisa dentro de um arquivo Figma -- tela, frame, card, componente, variante, topbar, sidebar, tabela, FigJam. Triggers: 'criar no Figma', 'montar a tela no Figma', 'desenhar no Figma', 'atualizar o Figma', 'arrumar o auto layout', 'o layout quebrou', 'ficou desalinhado', 'consertar spacing no Figma', 'construir componente no Figma', 'use_figma', 'Plugin API', 'push pro Figma'. Cobre a camada que as skills oficiais do Figma NAO cobrem: decidir a arvore de frames antes de criar, escolher HUG/FILL/FIXED por papel do elemento, validar por propriedades em vez de screenshot, e os erros que ja custaram retrabalho em projeto real. NAO ativa para design-to-code (ler Figma e implementar em React) -- ali vale a skill oficial figma-design-to-code.4---56# Figma Craft -- desenhar certo na primeira passada78O `use_figma` executa JS pela Plugin API. Ele nao "desenha": ele constroi uma arvore de nos.9Layout quebrado quase nunca e erro de API -- e arvore errada, ou sizing decidido no reflexo.1011Esta skill cobre a decisao. As regras de API vivem nas skills oficiais do MCP.1213## 1. Pre-voo obrigatorio1415Antes de QUALQUER escrita no Figma, carregar via `get_figma_skill`:1617| Sempre | `skill://figma/figma-use/SKILL.md` |18|---|---|19| Tela, pagina, modal, secao composta | `+ skill://figma/figma-generate-design/SKILL.md` |20| Componente, variante, variable, token | `+ skill://figma/figma-generate-library/SKILL.md` |21| FigJam (board) | `+ skill://figma/figma-use-figjam/SKILL.md` |22| Arquivo novo | `+ skill://figma/figma-create-new-file/SKILL.md` |23| Layout ja quebrado, conserto | `+ skill://figma/figma-use/references/gotchas.md` |2425Passar `skillNames: "resource:figma-use,resource:figma-craft"` na chamada `use_figma`.2627Nao pular por ser "uma mudanca pequena". As falhas de auto layout aparecem justamente nas pequenas.2829Alem das skills, dois groundings antes de gerar:3031- **Design system primeiro.** Arquivo com library/tokens: analisar o DS antes de gerar32 ("Analyze this design system file"), ativar a library no arquivo destino e construir com33 instancias reais bindadas a tokens. Componente que ja existe na library nunca e redesenhado.34 Ordem de descoberta: Code Connect → engenharia reversa de telas existentes → `search_design_system`.35- **Fonte real do produto.** Descobrir a font-family verdadeira antes de criar texto -- sem isso o36 gerador cai no Inter. Depois do build, validar por assercao (ler `fontName` dos textos criados).3738## 2. Desenhar a arvore ANTES de escrever codigo3940Erro numero um: comecar a criar nos e resolver o layout depois. Nao funciona -- no Figma o41sizing depende do pai, entao a arvore errada obriga a consertar tudo no fim.4243**Escrever a arvore em texto primeiro**, na mensagem, antes do primeiro `use_figma`:4445```46Screen (V, FILL x FIXED 1080, pad 0, gap 0)47├─ Topbar (H, FILL x HUG, pad 12/24, gap 16, align center/space-between)48│ ├─ Logo (FIXED 120x32)49│ └─ Actions (H, HUG x HUG, gap 8)50└─ Body (H, FILL x FILL, pad 24, gap 24)51 ├─ Sidebar (V, FIXED 280 x FILL, pad 16, gap 4)52 └─ Content (V, FILL x FILL, pad 0, gap 16)53```5455Notacao: `(direcao, sizingH x sizingV, padding, gap, alinhamento)`.56Se nao souber dizer o sizing de um no, o layout ainda nao esta decidido -- decidir antes de criar.5758Regras da arvore:59- Todo container com 2+ filhos relacionados e auto layout (`figma.createAutoLayout()`), nunca frame com x/y.60- Nunca GROUP. Group nao tem sizing, nao tem padding, e quebra quando o conteudo muda.61- Um no so existe se tem papel: estrutura, agrupamento semantico ou espaco. Wrapper sem funcao vira ruido no painel de camadas e no handoff.62- Profundidade util raramente passa de 4-5 niveis. Se passou, provavelmente tem wrapper sobrando.63- Elemento repetido (card de grid, linha de tabela, chip) vira UM componente local + instancias --64 nunca N frames quase iguais. Override de texto em instancia com `setProperties()`, nao `characters`.65- Criar o frame wrapper da tela PRIMEIRO, longe do conteudo existente, e construir dentro dele.66 Nunca criar secoes como filhas top-level da pagina pra reparentar depois -- mover no falha em silencio.67- Uma secao por chamada `use_figma`, nunca a tela inteira num script so. Imports em lote com `Promise.all`.6869## 3. Sizing por papel do elemento7071Decidir por papel, nao por "o que parece certo agora". Tabela de referencia:7273| Elemento | Horizontal | Vertical | Por que |74|---|---|---|---|75| Frame da tela | FIXED (largura do breakpoint) | FIXED ou HUG | Ancora do canvas |76| Topbar / header | FILL | HUG | Acompanha a largura, altura vem do conteudo |77| Sidebar | FIXED | FILL | Largura e decisao de design, altura acompanha a tela |78| Area de conteudo | FILL | FILL | Absorve o espaco que sobra |79| Card em grid | FILL | HUG | Divide a linha, cresce com o texto |80| Linha de lista | FILL | HUG | -- |81| Botao | HUG (ou FILL se full-width) | HUG | Padding define o tamanho |82| Icone | FIXED (16/20/24) | FIXED | Nunca FILL, nunca HUG |83| Texto de uma linha (label) | HUG | HUG | -- |84| Texto que quebra linha | FILL + `textAutoResize = 'HEIGHT'` | HUG | **FILL sozinho colapsa o texto pra largura ~0** |85| Divider | FILL | FIXED 1 | -- |86| Avatar / thumb | FIXED | FIXED | -- |8788Ordem de operacoes que evita a maioria dos erros:89901. `figma.createAutoLayout(direcao)` no pai912. `parent.appendChild(filho)`923. `resize()` se precisar de dimensao fixa934. **so entao** `layoutSizingHorizontal / layoutSizingVertical`9495`resize()` reseta sizing pra FIXED -- por isso vem antes. E `HUG`/`FILL` sao rejeitados se o no96ainda nao esta dentro de um auto layout, por isso o `appendChild` vem antes.9798Nao confundir os dois enums:99- filho: `layoutSizingHorizontal/Vertical` = `FIXED | HUG | FILL`100- frame: `primaryAxisSizingMode/counterAxisSizingMode` = `FIXED | AUTO`101102## 4. Spacing e alinhamento103104- Padding e gap sempre em multiplos de 4; preferir a escala 4 / 8 / 12 / 16 / 24 / 32 / 48 / 64.105- Nunca simular espaco com frame vazio, texto em branco ou x/y solto. Espaco e `itemSpacing` e padding.106- Distribuir extremos com `primaryAxisAlignItems = 'SPACE_BETWEEN'`, nao com spacer.107- Alinhamento vertical de linha com icone + texto: `counterAxisAlignItems = 'CENTER'` no pai. Nunca ajustar y do icone.108- Espaco negativo (avatares sobrepostos) e `itemSpacing` negativo, nao posicao absoluta.109- Se o container e so estrutura, limpar o fill: `figma.createAutoLayout()` vem com fill branco padrao110 e ele aparece como retangulo branco sobre fundo tonal.111112## 5. Gotchas que ja custaram retrabalho113114Verificados em projeto real de cliente, nao teoricos:1151161. **No movido entre containers carrega o layout antigo.** Depois de `appendChild`, resetar117 `layoutSizingHorizontal/Vertical` E `layoutPositioning = 'AUTO'`. Sintomas: elemento colado no vizinho118 ignorando o gap, altura colapsada pra 1px, conteudo cortado.1192. **`node.screenshot()` renderiza o no ISOLADO** -- mostra o elemento certo enquanto no canvas real120 esta quebrado. Validar por propriedades primeiro, imagem depois (secao 6).1213. **Nunca usar `rotation` pra virar icone dentro de auto layout.** A rotacao gira em torno da origem e122 joga o no pra fora da caixa reservada. Usar `instance.swapComponent(outroComponente)`.1234. **No herdado que resiste a duas tentativas de conserto: remontar.** Recriar o container com124 `createAutoLayout()` e reanexar os filhos custa menos chamadas do que insistir.1255. **`query()` nao aceita nome com espaco** (`FRAME[name=Product Context]` retorna null).126 Usar `findOne(n => n.name === '...')`.1276. **Comentarios do Figma nao sao acessiveis** pela Plugin API (`figma.comments` nao existe).128 Pedir o texto colado.1297. **Cor em 0-1**, nao 0-255. Sem canal `a` dentro de `color` -- opacidade fica no nivel do paint.1308. **O canvas do usuario fica em cache depois de escrita via plugin.** Ele reporta texto cortado,131 elemento fora do lugar ou artefato flutuando, e no arquivo esta tudo certo. Antes de "consertar" o132 que nao esta quebrado: medir as propriedades e renderizar com `get_screenshot` (render do servidor,133 e a prova do estado salvo). Batendo os dois, pedir reload -- nao mexer no layout. Ja custou duas134 idas e voltas em producao (seletor de area de topbar, campos de formulario).1359. **`textAutoResize = 'HEIGHT'` e rejeitado silenciosamente se o no esta com altura fixa.**136 Em auto layout, soltar `layoutSizingVertical = 'HUG'` ANTES. Sintoma: setar HEIGHT e continuar137 lendo `NONE` -- o pior modo, porque o texto nao cresce nem em altura, so corta.138139## 6. Validar antes de dizer que esta pronto140141Ordem obrigatoria: **propriedades → screenshot do container pai → screenshot do canvas**.142Screenshot do no isolado nunca e prova.143144Rodar o script de auditoria em `references/audit-layout.md` no frame trabalhado. Ele varre a arvore145e sinaliza: GROUP, frame com varios filhos sem auto layout, `layoutPositioning = ABSOLUTE` dentro de146auto layout, dimensao colapsada, texto com FILL sem `textAutoResize = HEIGHT`, spacing fora da grade de 4.147148Zero flags e o criterio de pronto. Flag que for decisao consciente, dizer qual e por que.149150Complementos por secao, enquanto o conserto e barato:151152- Screenshot da secao logo depois de construi-la (nao so no fim da tela): pega texto cortado,153 overlap, variante errada e placeholder esquecido.154- Assercao de fonte: ler `fontName` dos textos criados e comparar com a fonte do produto.155156## 7. Checklist final157158- [ ] Arvore foi escrita em texto antes do primeiro `use_figma`159- [ ] Todo container com filhos relacionados e auto layout; nenhum GROUP160- [ ] Sizing decidido por papel (tabela da secao 3), nao no reflexo161- [ ] `appendChild` antes de `HUG`/`FILL`; `resize()` antes do sizing162- [ ] Texto que quebra linha: FILL + `textAutoResize = 'HEIGHT'`, e `width > 0`163- [ ] Padding e gap na grade de 4; nenhum spacer falso164- [ ] Containers de estrutura com `fills = []`165- [ ] Cor bindada em variable/token, nao hex solto (quando o arquivo tem tokens)166- [ ] Camadas nomeadas por papel (`Topbar`, `Card / Header`), nao `Frame 427`167- [ ] Script de auditoria rodado, zero flags168- [ ] DS analisado e library ativada antes de gerar (quando o projeto tem DS)169- [ ] Componente existente na library entrou como instancia; elemento repetido virou componente local + instancias170- [ ] Fonte real do produto validada por assercao (nao caiu no Inter)171- [ ] Wrapper criado primeiro; uma secao por chamada; nenhuma secao reparentada de top-level172- [ ] Todos os IDs criados/mutados retornados no `return`173174## Fronteiras175176- Craft visual estatico (cor, tipografia, hierarquia, polish) → `/ui-designer`177- Tokens, arquitetura de DS, auditoria de consistencia → `/design-system`178- Fluxo, IA, psicologia da tela → `/ux-designer`179- Ler Figma e implementar em React → skill oficial `figma-design-to-code`