Seu agente enxerga o screenshot, mas você ainda precisa definir o que é "igual"
Você anexa o screenshot de uma página, pede ao agente para ajustar o frontend e recebe uma resposta animadora: "Pronto, ficou igual".
Aí você abre a aplicação. No seu monitor, o título quebrou em outra linha. No celular, o botão sumiu abaixo da dobra. O card está com a cor certa, mas o estado de erro nem foi implementado. O resultado não está obviamente errado; só é impossível saber o que o agente quis dizer com "igual".
Esse tipo de atrito ficou mais comum porque a entrada visual melhorou bastante. O Copilot, por exemplo, já aceita imagens no VS Code, no GitHub e na CLI, inclusive durante planejamento e execução por agentes. Isso ajuda a mostrar uma referência sem escrever um tratado sobre cada margem. Mas a imagem resolve apenas a entrada do fluxo. Ela não define o critério de aprovação.
Se o time não declara ambiente, estado, tolerância e evidência esperada, o agente pode enxergar o screenshot e ainda assim trabalhar no escuro.
Ver a imagem não é saber aprovar
Um screenshot é ótimo para orientar. Ele mostra hierarquia, densidade, alinhamento, proporção e intenção visual de um jeito que cinquenta linhas de prompt dificilmente mostram.
Só que ele costuma esconder informações importantes:
- qual rota e quais dados produziram aquela tela;
- se o usuário estava autenticado;
- qual viewport, escala e tema foram usados;
- quais fontes já tinham carregado;
- o que é conteúdo real e o que é placeholder;
- quais áreas mudam a cada execução;
- se a referência mostra apenas aparência ou também implica comportamento.
Imagine uma tela de checkout mobile. O screenshot pode mostrar um endereço preenchido, um cupom aplicado e o botão de pagamento habilitado. Se o agente abre a rota sem seed, recebe um carrinho vazio e tenta reproduzir apenas o layout, ele não está testando a mesma coisa. A diferença começou no estado, não no CSS.
Visão multimodal aumenta o contexto. Verificabilidade vem de outro lugar.
O contrato visual tem três camadas
Eu gosto de separar o pedido em referência, especificação e evidência. Parece burocracia até você comparar isso com o tempo gasto discutindo se uma tela "está próxima".
1. Referência
É o artefato que orienta o trabalho: screenshot, frame do Figma, imagem exportada ou vídeo curto. A referência ajuda o agente a entender a direção, mas não deveria carregar sozinha todas as regras do pedido.
Quando o time ainda está escolhendo um padrão de interface, uma coleção de recursos de Generative UI pode ajudar a comparar SDKs, protocolos e implementações. Isso melhora o repertório para formular a referência. Não cria o baseline do seu produto e muito menos decide o que passa no review.
2. Especificação
É a parte escrita e executável do contrato. Ela fixa o cenário que deve ser reproduzido:
- rota, login, seed e estado da tela;
- browser, viewport, escala, tema e fontes;
- componente isolado ou página completa;
- interações necessárias antes da captura;
- animações, timestamps e conteúdo dinâmico;
- formato, proporção e limite do arquivo;
- regra de tolerância e pessoa responsável pela aprovação.
Não precisa virar um documento enorme. Para uma correção pequena, cinco ou seis linhas bem escolhidas já eliminam a maior parte da ambiguidade.
3. Evidência
É o que volta para permitir uma decisão. Para teste visual, normalmente significa baseline esperado, captura atual e imagem de diff. Para comportamento, pode incluir um vídeo curto, um trace ou um teste automatizado. Para acessibilidade, pode exigir navegação por teclado e resultado de uma verificação específica.
A resposta "concluído" não é evidência. O agente precisa devolver algo que outra pessoa consiga inspecionar sem reconstruir todo o contexto da tarefa.
Um exemplo que cabe no pull request
Vamos transformar o checkout mobile num contrato pequeno:
Rota: /checkout
Estado: usuário autenticado, carrinho com 2 itens, frete calculado
Ambiente: Chromium, 390 x 844, tema claro, escala 1
Fontes: aguardar document.fonts.ready
Dinâmico: mascarar apenas horário e identificador do pedido
Aceite: comparar com baseline versionado e anexar esperado, atual e diff
No Playwright, a parte visual pode começar assim:
test.use({
viewport: { width: 390, height: 844 },
colorScheme: 'light',
locale: 'pt-BR',
})
test('checkout mobile', async ({ page }) => {
await page.goto('/checkout?fixture=filled-cart')
await page.evaluate(() => document.fonts.ready)
await expect(page).toHaveScreenshot('checkout-mobile.png', {
animations: 'disabled',
maxDiffPixels: 120,
mask: [
page.getByTestId('current-time'),
page.getByTestId('order-id'),
],
})
})
O número 120 não é uma recomendação universal. Ele só faz sentido depois de olhar os diffs reais e entender o ruído do ambiente. Aumentar a tolerância até o CI ficar verde é uma forma elegante de desligar o teste sem admitir que ele foi desligado.
O mesmo vale para máscaras. Esconder um relógio que muda a cada execução é razoável. Mascarar o preço porque ele está falhando com frequência provavelmente encobre o defeito que o teste deveria revelar.
A documentação do Playwright chama atenção para outro detalhe fácil de ignorar: sistema operacional, hardware, configurações e modo de execução podem alterar a renderização. Gere e compare screenshots no mesmo ambiente. Caso contrário, o diff pode medir a máquina, não a mudança do produto.
Baseline versionado não é verdade eterna
O baseline precisa entrar no controle de versão porque ele faz parte do contrato. Quando uma mudança visual é intencional, o novo snapshot deve aparecer no pull request e receber review como qualquer alteração de código.
Mesmo assim, baseline não é sinônimo de produto correto.
Um teste pode passar e a interface continuar ruim para quem usa zoom, teclado ou leitor de tela. Também pode falhar porque houve uma alteração legítima de copy, fonte ou densidade. Comparação visual detecta diferença; a decisão sobre essa diferença continua sendo do time.
Não vejo disputa entre revisão humana e automação. Cada uma resolve um pedaço:
- o agente implementa e produz os artefatos;
- o teste encontra divergências repetíveis;
- uma pessoa avalia intenção, clareza e impacto para o usuário.
Tirar a pessoa desse último passo pode acelerar o merge e piorar o produto ao mesmo tempo.
Screenshot, imagem social e vídeo não usam a mesma régua
O raciocínio do contrato também serve para outros artefatos visuais, mas os critérios mudam.
Numa interface, viewport, estado e comportamento importam. Numa imagem social, proporção, recorte, área segura, formato e peso costumam pesar mais. Antes de comparar uma arte para Instagram, por exemplo, faz sentido normalizar o arquivo para 1:1, 4:5 ou 9:16. Uma opção prática é o Resize Image for Instagram, que faz o ajuste localmente no navegador e permite usar o modo Fit quando a imagem inteira precisa caber sem corte. Isso prepara o artefato; não substitui a avaliação visual.
Vídeo pede outro contrato. Você precisa declarar pelo menos duração, resolução, proporção, FPS, tamanho máximo, timeout e quais quadros ou eventos devem ser conferidos. Duas saídas podem ter a mesma duração e resolução e ainda contar histórias diferentes.
O AI SDK 7 amplia a superfície multimodal com geração e edição de imagem, além de geração experimental de vídeo. Quanto mais tipos de saída entram no fluxo, menos útil fica uma aprovação genérica como "parece certo". Cada artefato precisa de uma régua compatível com o que ele tenta entregar.
O que eu pediria ao agente
Um pedido operacional para esse checkout poderia terminar assim:
Implemente o ajuste usando o screenshot como referência.
Antes de concluir:
1. reproduza o estado descrito com os dados de teste;
2. rode o teste no ambiente fixado;
3. não atualize o baseline automaticamente;
4. devolva o screenshot esperado, o atual e o diff;
5. explique qualquer máscara ou tolerância adicionada;
6. sinalize separadamente mudanças de acessibilidade ou comportamento.
Repare que o prompt não tenta descrever cada pixel. Ele define como o trabalho será julgado. Isso dá liberdade para o agente implementar sem transformar "liberdade" em "qualquer resultado serve".
Também deixa o review mais honesto. Se o diff mostra uma alteração intencional, alguém aprova o novo baseline. Se a diferença veio de fonte não carregada, dado instável ou viewport incorreto, o agente corrige o ambiente antes de tocar na tolerância.
Antes de aceitar o "ficou igual"
Anexar uma imagem ao prompt é uma melhoria real. Economiza explicação, aproxima a referência do código e torna tarefas visuais mais acessíveis para agentes.
Mas o screenshot não carrega sozinho o estado da aplicação, o ambiente de renderização nem a regra de aceite. Essas decisões ainda pertencem ao contrato que o time escreve.
Antes do próximo pedido visual, faça um teste: apague a frase "ficou igual" e veja se os artefatos devolvidos ainda permitem aceitar ou rejeitar o trabalho. Se você tem o cenário reproduzível, o baseline, a captura atual e o diff, a resposta provavelmente é sim.
Se a decisão ainda depende da memória de quem abriu a tarefa, o agente não terminou. Ele só devolveu uma impressão.