Ahmed UI Craft
Modelos de linguagem tendem à média estatística da web: Inter, um gradiente roxo, três cartões arredondados idênticos, um emoji por funcionalidade. Essa saída é reconhecível de imediato e diz ao usuário que ninguém tomou uma decisão. Esta skill força que as decisões sejam tomadas, escritas como tokens e verificadas antes de você entregar qualquer coisa.
Siga o fluxo de trabalho em ordem. Cada etapa existe porque pulá-la é como UI genérica acontece.
Etapa 0 – Leia o projeto antes de projetar
Olhe antes de inventar. Verifique, nesta ordem:
- Framework:
package.json(next, react, vue, svelte, astro) ou.htmlpuro. - Estilização:
tailwind.config.*ou@import "tailwindcss"/@theme(Tailwind v4),*.module.css, styled-components ou CSS puro. - Tokens existentes:
greppor--color-,--space-,@theme,theme.extend. - Biblioteca de componentes:
components/ui/+components.json(shadcn/ui),@mui/material, Radix, Headless UI, Vuetify.
Por quê: um componente bonito que ignora os tokens e a biblioteca existentes do projeto
é uma regressão, não uma melhoria. Se o projeto já possui um sistema de design,
trabalhe dentro dele: estenda seus tokens, reestilize seus primitivos
(para shadcn/ui, edite as variáveis CSS em globals.css e os arquivos de componente,
não os envolva em wrappers). Só traga assets/tokens.css quando não houver sistema
a ser estendido.
Se nada existir, padrão para: HTML semântico + propriedades personalizadas CSS de
assets/tokens.css, mapeadas para o Tailwind se o Tailwind estiver presente.
Etapa 1 – Pensamento de design (antes de qualquer código)
Escreva quatro linhas curtas, mentalmente ou na resposta:
- Propósito: qual trabalho esta tela realiza? (ex.: "convencer um líder de equipe a iniciar um teste")
- Público: quem está olhando, em qual dispositivo, com qual humor? (ex.: "engenheiros de operações, desktop, escaneando rápido")
- Tom: três adjetivos. (ex.: "exato, calmo, denso")
- Diferenciador: uma coisa que alguém lembraria depois de fechar a aba.
O diferenciador deve ser concreto e visível, não "limpo e moderno". Bons exemplos: "preços definidos em um numeral condensado enorme que vai de ponta a ponta"; "cada cartão tem uma linha fina e um número de índice mono como uma ficha técnica"; "o título principal está em itálico serifado sobre uma textura de papel off-white".
Por quê: se você não consegue nomear o diferenciador, a saída será a média, porque a média é o que o modelo produz quando nada o puxa para outro lugar.
Se o usuário forneceu uma marca, captura de tela ou site existente, o tom vem daí. Não imponha uma nova direção a uma marca estabelecida.
Etapa 2 – Comprometa-se com uma direção estética
Escolha uma direção e aplique-a em tudo: tipo, cor, raio, sombra, movimento, imagens e ritmo de texto. Direções mistas parecem indecisão.
| Direção | Tipo | Cor | Forma e profundidade | Movimento |
|---|---|---|---|---|
| Editorial | Serifa display, corpo humanista | Papel off-white, tinta, um acento forte | Linhas finas, raio próximo de zero, sem sombras | Fades lentos, nenhum ao rolar |
| Brutalista | Grotesk pesado ou mono, tamanhos enormes | Preto/branco puro + uma cor vibrante | Raio 0, bordas grossas, sombras duras deslocadas | Instantâneo, rápido |
| Suave / orgânico | Serifa display arredondada ou suave | Neutros quentes matizados, acento terroso suave | Raio grande apenas em contêineres, sombras difusas | Elástico, suave |
| Industrial / técnico | Condensado ou grotesk + mono | Neutro escuro, acento de sinal (âmbar, lima, ciano) | Raio pequeno, bordas de 1px, linhas de grade visíveis | Rápido, linear |
| Luxo | Serifa de alto contraste, espaçamento amplo em caps | Quase preto, creme, acento metálico ou joia profunda | Espaço generoso, bordas finas | Lento, easing longo |
| Brincalhão | Display encorpado, sans amigável | Duas cores saturadas que combinam de propósito | Formas de adesivo, sombras deslocadas | Overshoot saltitante |
Cada linha tem um preset pronto em assets/directions/ (fontes, paleta clara e escura
com contraste verificado, raio, sombra, movimento) e uma lista de movimentos característicos em references/directions.md.
Carregue o preset depois de tokens.css, use pelo menos dois de seus movimentos característicos e desloque seus matizes
em direção à marca. O minimalismo suíço é o sétimo preset.
Regras para a escolha:
- Derive-a da Etapa 1, não do hábito. Um dashboard para SREs não é "luxo".
- Nomeie-a em sua resposta ("Direção: industrial / técnico") para que o usuário possa redirecionar cedo.
- Se o usuário pedir algo genérico ("simples, limpo"), ainda escolha: "minimalismo suíço" é uma direção (grade rigorosa, um grotesk, preto + uma cor, zero decoração).
Etapa 3 – Defina os tokens primeiro
Antes de escrever qualquer componente, defina tokens para: cor, tipo, espaçamento,
raio, sombra, movimento, z-index. Comece de assets/tokens.css: mantenha os nomes,
substitua os valores.
Os valores iniciais (Fraunces + Instrument Sans, neutros de papel, acento vermelhão)
são um placeholder, não um estilo. Antes de escrever componentes, mude pelo menos o par
de fontes (de references/typography.md, combinado com sua direção), o matiz de acento
e o matiz para o qual os neutros são matizados. Por quê: em testes, os tokens iniciais
inalterados fizeram um formulário de login e uma página de preços de produtos não
relacionados parecerem idênticos. Esse é um novo padrão, que é o problema que esta
skill existe para resolver. Mantenha-os apenas se a direção for realmente editorial
quente com acento vermelho-alaranjado.
A maneira mais rápida de obter uma nova paleta acessível: gere-a e cole sobre os tokens de cor no bloco 2.
node scripts/palette.mjs --hue 250 --accent 130 --dark-first # neutros ardósia, acento lima
--hue matiza os neutros (use o matiz da marca), --accent é o matiz de acento. Cada
par texto/fundo é resolvido para passar WCAG AA em claro e escuro antes de imprimir.
Para direções escuro-primeiro (dashboards de monitoramento, ferramentas de desenvolvedor,
temas de luxo noturnos), defina :root { color-scheme: dark; } para que escuro seja o
padrão e claro seja opt-in.
Por quê: tokens tornam a direção aplicável. Um #6366f1 ou 13px codificado
em um componente é uma decisão tomada isoladamente, e vinte delas fazem a
UI derivar. Com tokens, modo escuro, temas e reestilizações posteriores são alterações
em um único arquivo.
Regras:
- Duas camadas: paleta bruta (
--ink-900,--clay-500) e tokens semânticos (--color-text,--color-accent,--color-surface). Os componentes usam apenas tokens semânticos. - Sem números mágicos nos componentes. Toda cor, tamanho, gap, raio, sombra,
duração e z-index vêm de um token. Exceções:
0, linhas finas1px,100%e1fr. - Modo escuro: toda cor semântica é
light-dark(CLARO, ESCURO), para que ambos os temas vivam em uma declaração e os componentes nunca mudem. Vejareferences/color-and-theming.md.
Tailwind: torne os tokens o tema, para que bg-surface, text-text-muted,
font-display e rounded-md existam e bg-indigo-500 não.
- v4: o segundo bloco em
assets/tokens.cssjá usa os namespaces do Tailwind (--color-*,--font-*,--text-*,--radius-*,--shadow-*,--ease-*). Mude:rootdesse bloco para@themee adicione--color-*: initial;como sua primeira linha para descartar a paleta padrão. Mantenha o bloco 3 (color-scheme) como CSS puro. Utilitários resolvemlight-dark()por tema, porque referenciamvar(--color-*). Não escreva@theme inline { --color-x: var(--color-x) }; uma variável que referencia seu próprio nome é um ciclo e resolve para nada. - v3: em
tailwind.config, definatheme.colors(nãoextend) para{ surface: "var(--color-surface)", ... }e estendafontFamily,borderRadius,boxShadowda mesma forma.
Etapa 4 – Construa mobile-first, com todos os estados
Escreva estilos base para uma viewport de 360px, depois adicione media queries de
min-width ou consultas de contêiner. Por quê: é mais fácil adicionar espaço do que
retirar, e a maioria dos bugs de layout (scroll horizontal, tabelas esmagadas) só aparece
em larguras pequenas.
Todo elemento interativo vem com todos os seus estados. Estados ausentes são o motivo mais comum pelo qual uma UI parece inacabada.
| Estado | O que deve mostrar |
|---|---|
| padrão | o design em repouso |
| hover | mudança sutil (cor ou sombra), apenas sob @media (hover: hover) |
| focus-visible | um anel claramente visível, nunca removido |
| active | feedback de pressionado (mais escuro, ou translateY(1px)) |
| disabled | contraste reduzido + cursor: not-allowed, e o atributo disabled real |
| loading | spinner ou skeleton, aria-busy="true", largura não pula |
| error | mensagem de texto perto do campo, não apenas uma borda vermelha |
| empty | uma mensagem real e uma próxima ação, nunca uma caixa vazia |
Use HTML semântico primeiro: <button> para ações, <a href> para navegação,
<label for> para cada input, <dialog> para modais, <table> para dados
tabulares, landmarks (<header> <nav> <main> <footer>). Adicione ARIA apenas quando o HTML não
tiver equivalente nativo. Por quê: elementos nativos vêm com comportamento de teclado e
semântica de leitor de tela gratuitamente; ARIA é uma promessa que você então precisa implementar.
Escreva copy real. Texto placeholder ("Lorem ipsum", "Funcionalidade 1", "João da Silva") esconde problemas de layout e faz o resultado parecer um template. Use conteúdo específico e plausível que se encaixe no propósito da Etapa 1.
Etapa 5 – Audite antes de entregar
Execute scripts/audit.md: bash scripts/audit.sh <arquivos alterados> (verificações de padrão mais
contraste de token), depois, se o Playwright estiver disponível ou o usuário concordar em instalá-lo,
node scripts/browser-check.mjs <página> e olhe as capturas de tela que ele salva. Corrija o que falhar. Razões escritas
em comentários são alegações, não medições; calcule-as. Não relate o trabalho como concluído com falhas conhecidas; se algo não
puder ser corrigido (por exemplo, uma cor de marca que falha no contraste), diga isso explicitamente.
Modo multi-agente (quando uma ferramenta de subagente estiver disponível)
O agente principal sempre faz as Etapas 0-4 sozinho: pensar e construir precisam do mesmo contexto, e dividi-los perde o que a Etapa 0 encontrou. Use subagentes em apenas dois pontos:
-
Propostas de direção (Etapa 2, apenas briefings abertos). Se não houver marca, captura de tela ou sistema de design existente, lance 2-3 subagentes em paralelo. Dê a cada as linhas da Etapa 1 e atribua a cada uma uma direção diferente da tabela. Diga a cada um para ler sua seção de
references/directions.mdereferences/typography.mdprimeiro, e dê a cada um as direções dos outros agentes para que as evitem. Cada um retorna apenas: direção, par de fontes, matiz de acento + neutro, diferenciador, dois movimentos característicos. Rejeite uma proposta que reutilize o par de fontes, matiz de acento ou diferenciador de outro, ou mantenha os valores iniciais detokens.css. Escolha uma (ou mostre as opções ao usuário), depois continue sozinho. Por quê: um agente converge para a média; pontos de partida diferentes forçados não. Pule isso quando a marca já define a direção. -
Revisão independente (Etapa 5, sempre para novas páginas ou telas). Após sua própria auditoria passar, lance um subagente novo que não escreveu o código. Dê a ele os arquivos alterados, as linhas da Etapa 1 e a direção escolhida, e peça para: ler
references/anti-patterns.md, executarscripts/audit.she listar cada lugar onde a UI parece genérica, perde um estado ou quebra a direção. Ele classifica cada achado como bloqueador / maior / menor e não edita. Corrija todos os bloqueadores e maiores, re-executescripts/audit.she liste os menores não corrigidos na resposta. Uma rodada de revisão, sem loop. Por quê: o construtor julga o resultado pelo que pretendia fazer, não pelo que está na tela.
Sem ferramenta de subagente: faça ambas as passagens você mesmo, em ordem. Para a revisão, releia os arquivos como se outra pessoa os tivesse escrito.
Regras de qualidade (e por quê)
Tipografia
- Não use como padrão Inter, Roboto, Arial, Helvetica ou system-ui para texto de display. Evite também os novos padrões de IA: Poppins, Montserrat, Space Grotesk, DM Sans. Por quê: essas são o que toda página gerada usa, então sinalizam "gerado".
- Combine uma face de display com uma face de corpo que contraste em estrutura (serifa + sans, condensada + larga, grotesk + mono). Duas famílias no máximo, mais uma mono opcional.
- Use uma escala modular com tamanhos fluidos (
clamp()) e torne o maior título dramaticamente maior que o texto do corpo. Hierarquia tímida (32px sobre 16px) parece inacabada. - Texto do corpo: mínimo de 16px, line-height 1.5-1.7, medida 60-75 caracteres. Dashboards densos podem usar 12-14px para metadados e células de tabela, nunca para parágrafos ou inputs.
Cor
- Uma cor dominante carrega a marca; um acento forte é reservado para a ação primária e dados importantes. Os neutros fazem a maior parte do trabalho. Aproximadamente 60/30/10. Por quê: uma paleta de cinco cores distribuída uniformemente não tem ponto focal, então nada parece importante.
- Matize seus neutros em direção ao matiz da marca em vez de usar cinza puro.
- Sem gradientes roxo-para-azul ou roxo-sobre-branco, a menos que a marca seja verdadeiramente roxa.
- Contraste de texto de pelo menos 4.5:1 (3:1 para textos 24px+ ou 18.66px+ em negrito, e para limites de componentes de UI e anéis de foco).
Layout e forma
- Evite a grade idêntica de três ou quatro cartões. Varie o tamanho e a ênfase: um item em destaque ocupando duas colunas, uma lista ao lado de um grande visual, uma divisão assimétrica.
- O raio segue a direção e é consistente por nível. Não coloque
rounded-2xlem tudo; controles pequenos recebem raio pequeno, ou nenhum. - Sem scroll horizontal em 320px. Use
min-width: 0em filhos de flex/grid,overflow-wrap: anywherepara strings longas e contêineres de scroll para tabelas largas. - Alvos de toque de pelo menos 44x44px (padding conta).
Ícones e imagens
- Sem emoji como ícones. Use um conjunto de ícones (Lucide, Phosphor, Heroicons, Tabler) com uma espessura de traço, ou SVG inline. Por quê: emoji renderizam de forma diferente por SO, não podem ser coloridos com tokens e são anunciados por leitores de tela ("foguete").
- Ícones decorativos recebem
aria-hidden="true"; botões somente com ícone recebem umaria-label.
Movimento
- Anime apenas
transformeopacity(maisfiltercom moderação). Por quê: outras propriedades disparam layout ou pintura em cada quadro e travam em celulares de baixo custo. - Durações de tokens: 120-200ms para feedback de UI, 250-400ms para elementos entrando.
- Respeite
prefers-reduced-motion: remova movimento, mantenha fades curtos ou instantâneos.
Acessibilidade – não negociável:
- Todo formulário:
<label for>ouaria-label, erros associados viaaria-describedby. - Toda imagem:
alt(vazio para decorativas). - Todo modal:
<dialog>com métodoshowModalourole="dialog"+aria-modal="true"+ foco armadilhado. - Navegação:
aria-current="page",aria-expanded, landmark roles. - Cor: instruções não dependem apenas de cor, gráficos têm texturas ou rótulos.
- Zoom: sem
user-scalable=no, semmaximum-scale=1, sem larguras fixas empx. - Animações: duração total < 5s ou desativadas
Assets incluídos
| Caminho | O que contém |
|---|---|
assets/tokens.css | Token scaffold completo; 3 blocos: paleta, semânticos (namespaces Tailwind), modo escuro |
assets/directions/ | Presets (6 + suíço) – CSS e JSON para @theme Tailwind v4 |
scripts/palette.mjs | Gera paleta de contraste garantido a partir de matiz e acento |
scripts/audit.sh | Verificações de padrão, contraste e leakage de token nos arquivos alterados |
scripts/browser-check.mjs | Navegador headless, captura de tela e verificação visual básica |
references/directions.md | Descrições, fontes, tokens e movimentos característicos por direção |
references/typography.md | Pares de fontes verificados: serifa/sans, grotesk/mono, pesos, tamanhos, escalas |
references/color-and-theming.md | light-dark(), modo escuro, temas de alto contraste, dicas de acessibilidade |
references/anti-patterns.md | Lista de verificação de "UI de IA" e como corrigir cada um |