Eu repliquei a nova interação de UI generativa do Claude!

@op7418
CHINÊShá 4 meses · 15 de mar. de 2026
265K
446
63
34
815

TL;DR

Este artigo detalha a replicação da UI generativa do Claude no Code Pilot. Ele aborda obstáculos técnicos como renderização em sandbox iframe, análise de JSON via streaming e refinamentos de UX para garantir uma experiência fluida e sem oscilações.

A Anthropic lançou recentemente uma nova interação de UI generativa no Claude. Ela ajuda a introduzir conceitos e informações visualmente dentro do fluxo do chat, tornando tudo muito mais fácil de entender do que texto simples. !Image Eu estava procurando soluções semelhantes e, quando o Claude lançou a deles, senti que precisava acelerar meu trabalho. Ao mesmo tempo, pude fazer engenharia reversa da abordagem deles como referência. Depois de dois dias instruindo intensamente o Codex e o Claude, eu realmente consegui! !https://pbs.twimg.com/amplify_video_thumb/2033112086713364480/img/EUmHCjsTK7tfnToZ.jpg Esse recurso permite que a IA desenhe gráficos interativos diretamente no chat com saída em streaming, renderizando enquanto gera. Antes, ao pedir para a IA escrever uma página web, você precisava esperar todo o código ser gerado para renderizar, o que demorava uma eternidade. Agora é diferente. Você pode ver os gráficos sendo desenhados traço por traço no canvas, com os nós SVG aparecendo um após o outro. O próprio processo de geração é impressionante, e é interativo imediatamente após a conclusão. Experimente diretamente no meu produto Agent, o Code Pilot: https://github.com/op7418/CodePilot Neste post, vou apresentar seu uso, o processo de implementação específico e alguns cuidados. ## Quais são alguns casos de uso divertidos? Análise de Dados: Finalmente, os números fazem sentido Por exemplo, peça para desenhar um gráfico para "Estimativa de custo diário do conflito EUA-Irã". Antes, a IA te dava um monte de texto onde as relações numéricas eram difíceis de ver. Agora, ela gera um gráfico diretamente, tornando o valor de cada parte claro de imediato. Texto e gráficos são gerados juntos, explicando onde for necessário e desenhando onde for necessário. !Image Ferramentas Pequenas: Crie uma calculadora interativa ou algo similar Peça para fazer uma calculadora de juros compostos. Arraste controles deslizantes para mudar o valor inicial ou os anos de investimento, e os gráficos e números abaixo são atualizados em tempo real. Isso não é uma imagem estática; é uma ferramenta verdadeiramente interativa. Cálculos de empréstimos, conversões de unidades e coisas semelhantes podem ser feitas. !Image Diagramas de Arquitetura: O favorito dos programadores Você pode pedir para ajudar a desenhar a arquitetura de um projeto ou visualizar um plano de implementação. Por exemplo, aqui pedi para desenhar o fluxo completo da API até a autenticação JWT. Comparações de recursos, fluxogramas e estruturas hierárquicas são todos gráficos, tornando a arquitetura muito mais rápida de entender do que ler descrições em texto. !Image Analisar Dados Online Outra forma de usar é jogar um link de repositório do GitHub nele; ele vai rastrear os dados e fazer uma análise visual. Por exemplo, enviei o endereço do meu próprio projeto, CodePilot, para análise. Estrelas, forks, stack de tecnologia, design de arquitetura e módulos principais são todos desenhados em gráficos. Você pode ver o panorama completo do projeto de relance, o que é muito melhor do que ler um texto longo. !Image Explicações Interativas e Aprofundadas A parte mais forte é sua integração estreita com o modelo; não é apenas uma saída única. Você pode interagir com os diagramas gerados e pedir explicações mais detalhadas. Por exemplo, aqui pedi para explicar a relação entre monções e correntes oceânicas. !Image Se quisermos saber mais, podemos clicar no botão do mecanismo de corrente oceânica. Ele vai enviar automaticamente um comando para o modelo atual continuar gerando um diagrama do mecanismo de corrente oceânica. !Image Claro, podemos realizar interações mais complexas, como visualizar fórmulas comuns de física e matemática. Isso é muito útil para estudantes; cada parâmetro pode ser controlado via controles deslizantes e entradas, e a animação muda imediatamente. !Image Suporte para Modelos Chineses Uma vez implementado no CodePilot, não é só para o Claude. Kimi K2.5, Minimax M2.5 e os modelos nativos da Anthropic funcionam bem. Acho que os gráficos desenhados pelo K2.5 são ainda mais bonitos que o Sonnet 3.5, e a análise de arquitetura é muito detalhada. Se você usar esse recurso, recomendo testar o K2.5 primeiro. Ok, é basicamente isso para as demonstrações do modelo. Se você não se importa com como foi implementado, pode simplesmente instalar o CodePilot e se divertir. ## Como foi implementado? !Image Como o Claude faz O Claude.ai oficialmente usa o mecanismo tool_use. O modelo chama uma ferramenta dedicada para gerar conteúdo de widget estruturado, e o frontend analisa os parâmetros de entrada da chamada da ferramenta para renderizar. Essa solução funciona bem na própria arquitetura do Claude.ai. Mas não funciona para o CodePilot por três razões: Primeiro, limitações do SDK. O CodePilot usa o modo predefinido claude_code do SDK do Claude Agent, que não permite registrar ferramentas personalizadas. O SDK expõe um fluxo de texto delta, então não pode ser estendido no nível da ferramenta. Segundo, a experiência de streaming. Os resultados de tool_use precisam esperar o input_json_delta terminar antes de renderizar, e não suporta renderização HTML incremental. Com cercas de código, o HTML chega com o fluxo de texto, permitindo renderizar enquanto gera. Terceiro, isolamento de renderização. O Claude.ai usa Shadow DOM para isolamento. Nós escolhemos um iframe de sandbox. O isolamento por iframe é mais completo—um ambiente de execução JS completamente independente, CSP controla precisamente o carregamento de recursos, e não há vazamento de estilo ou escape de script. Como nós fizemos Gatilho: Cercas de Código O modelo gera uma cerca de código Markdown especial para acionar a renderização: ``show-widget {"title":"training_flow","widget_code":"<svg width=\"100%\" viewBox=\"0 0 680 400\">...</svg>"} ` Esse formato reutiliza os modos de cerca de código existentes do CodePilot (image-gen-request, batch-plan, etc.), que a cadeia do analisador do frontend suporta naturalmente. ![Image](https://pbs.twimg.com/media/HDcR5dyasAAtwTN?format=jpg&name=small) **Renderização: Iframe de Sandbox** Cada widget é renderizado em um iframe com sandbox="allow-scripts". O srcdoc do iframe é uma página receptora cuidadosamente construída. A política CSP só permite scripts externos de 4 domínios CDN, e connect-src 'none' proíbe todas as requisições de rede. As atualizações de conteúdo são recebidas via postMessage. Durante a fase de pré-visualização em streaming, widget:update é enviado sem executar scripts. A renderização final envia widget:finalize, que executa scripts. Um ResizeObserver monitora mudanças na altura do conteúdo e as reporta para a página pai via postMessage. Todos os cliques em <a> são interceptados e encaminhados para a página pai para abrir em uma nova janela. A sincronização de tema depende do monitoramento de mudanças de classe na página pai para alternar entre modos escuro/claro em tempo real. ![Image](https://pbs.twimg.com/media/HDcR8ilbgAATB-8?format=jpg&name=small) **Ponte de Variáveis CSS** Isso é chave para fazer o widget se misturar visualmente com o aplicativo. O CodePilot usa variáveis CSS no espaço de cor OKLCH. As diretrizes de design de widget da Anthropic usam nomes de variáveis padrão como --color-background-primary. A camada de ponte injeta os valores das variáveis do CodePilot no :root do iframe quando ele é inicializado. O CSS escrito pelo modelo de acordo com as diretrizes pode usar diretamente as cores do tema atual. Ao alternar para o modo escuro, a página pai detecta a mudança de classe, recalcula os valores das variáveis e os envia para o iframe. ![Image](https://pbs.twimg.com/media/HDcR_fLaYAAL88P?format=jpg&name=small) **Renderização em Streaming** Esta é a parte mais complexa de toda a implementação. O modelo gera token por token. A qualquer momento, o código do widget recebido pode ser um JSON incompleto, HTML incompleto ou uma tag <script> incompleta. O fluxo de processamento é o seguinte: A regex corresponde a `show-widget para distinguir entre estados "não fechado" e "fechado". Localize manualmente o conteúdo após "widget_code":" e desescape caractere por caractere. JSON.parse não pode ser usado porque o JSON não está terminado. Quando uma tag <script> não fechada é detectada, trunque antes do <script para evitar exibir código JavaScript como texto visível. Um debounce de 120ms impede que o iframe seja atualizado com muita frequência. O conteúdo em streaming remove todos os scripts e manipuladores de eventos; a interação não é necessária durante a fase de pré-visualização. ![Image](https://pbs.twimg.com/media/HDcSDCGb0AAwY7J?format=jpg&name=small) **Polindo a Experiência: Detalhes que não deveriam ser notados** Do ponto de vista de código ou implementação, não é tão complexo; a complexidade está em polir a experiência. Há muitos lugares que podem afetar a experiência, e os usuários precisam não notar esses detalhes e o processo de geração. Isso requer lidar com cada estágio de forma diferente: 1. Detalhes que não parecem streaming 2. Conteúdo que não deveria aparecer ![Image](https://pbs.twimg.com/media/HDcSKQLaEAABilZ?format=jpg&name=small) **Desaparecimento de Texto** O modelo primeiro gera um texto introdutório ("Deixe-me explicar visualmente..."), então inicia a cerca do widget. Assim que a cerca aparece, o texto anterior desaparece de repente e só retorna após o widget terminar de renderizar. A razão é que parseAllShowWidgets() retorna um array vazio para texto simples. Quando a cerca aparece mas não está fechada, o texto antes da cerca é passado para esta função e é descartado. Correção: Quando o texto antes da cerca não contém uma cerca de widget completa, renderize-o diretamente como <MessageResponse>, ignorando a função de análise. **Saltos de Altura** No momento em que o widget termina de renderizar, toda a área do chat treme. A altura inicial do iframe é 0px. Quando o conteúdo reporta sua altura real pela primeira vez, pode ser 400px+, e uma transição CSS faz essa mudança acontecer ao longo de 300ms, resultando em um salto perceptível. Correção: Desabilite temporariamente as transições CSS durante o primeiro relatório de altura para que a altura se ajuste instantaneamente. Ajustes de altura subsequentes usam transições suaves. **Cintilação na Finalização** Quando o widget muda da pré-visualização em streaming para a renderização final, o conteúdo pisca. O iframe receptor substitui todo o DOM com root.innerHTML = html durante a finalização. Mesmo que o conteúdo novo e antigo sejam idênticos (widget SVG puro), o navegador aciona um quadro de repintura. Correção: Durante a finalização, primeiro analise o novo HTML em um contêiner temporário e separe os elementos de script. Compare o HTML visual (sem scripts) com o DOM atual—se forem iguais, pule a substituição innerHTML e apenas anexe os scripts para execução. Widgets SVG puros alcançam finalização sem repintura. **Salto de Rolagem** O chat está rolando automaticamente para o fundo, então de repente volta várias centenas de pixels e volta novamente. Quando o streaming termina, o componente StreamingMessage é desmontado e o componente MessageItem é montado. Estes são dois componentes React completamente diferentes, e o WidgetRenderer interno é destruído e reconstruído. A altura do iframe da nova instância começa em 0, fazendo com que a altura da área de conteúdo caia drasticamente, o que aciona um ajuste de rolagem em use-stick-to-bottom. Correção: Cache de altura em nível de módulo. Sempre que um widget reporta sua altura, ela é escrita em um cache usando os primeiros 200 caracteres do widgetCode como chave. A nova instância de WidgetRenderer lê a altura do cache durante a inicialização useState, então o iframe começa a renderizar na altura correta, eliminando a transição 0→real. **Vazamento de Código de Script** Quando um widget com Chart.js carrega, um grande bloco de código JavaScript é exibido na parte inferior. As tags <script> geradas pelo modelo chegam caractere por caractere. Quando a tag de abertura chega mas a tag de fechamento não, sanitizeForStreaming remove a tag de abertura, mas o código JavaScript dentro se torna um nó de texto simples renderizado como conteúdo visível. Correção: Após extrair o código parcial em StreamingMessage, verifique se o último <script tem um </script> correspondente. Se não, trunque na posição <script. As diretrizes do widget especificam que os scripts vão no final, então o truncamento não afeta o conteúdo visual. Durante o truncamento, uma máscara shimmer é mostrada, e a barra de status exibe "Adicionando animações interativas à visualização." **Condição de Corrida do Iframe Ready** Em casos raros, o widget não renderiza, permanecendo com altura 0px. WidgetRenderer registra um ouvinte de evento de mensagem via useEffect. No entanto, o script receptor do iframe envia widget:ready assim que carrega. Se o iframe carregar mais rápido que o efeito React executar, widget:ready é enviado antes do ouvinte ser registrado, e iframeReady nunca se torna verdadeiro. Correção: Adicione um callback onLoad ao elemento iframe como fallback. Quando onLoad é acionado, o script receptor deve ter terminado de executar, fornecendo um sinal de prontidão confiável. **Estabilidade da Árvore de Componentes React** O widget pisca no momento em que a cerca fecha. Dois problemas se sobrepõem: o widget parcial em streaming não tem chave React, e após fechar, ele recebe key="w-0". A mudança de chave causa uma remontagem. Além disso, a sobreposição shimmer foi implementada com um <div> envolvente, que mudou a estrutura da árvore de componentes e causou outra remontagem. Correção: Atribua uma chave estável ao widget parcial (w-N, onde N é a posição esperada no array final de segmentos), consistente com a chave após o fechamento. Mova a sobreposição shimmer para dentro do WidgetRenderer, controlada via uma prop showOverlay. A árvore de componentes permanece <WidgetRenderer key="w-N"> durante todo o processo. ## **Considerações Finais** Para todo o sistema de UI generativa, a parte difícil não é "fazer um pedaço de HTML rodar em um iframe". Isso é simples. A complexidade real está em manter esse iframe visualmente estável durante transições de estado como streaming, mudanças de ciclo de vida de componentes e alterações de tema. Cada "flash", "salto" ou "desaparecimento" requer entender a reconciliação do React, o pipeline de renderização do navegador e o tempo do postMessage`. O efeito final é que os usuários veem gráficos e diagramas naturalmente intercalados nas respostas do modelo, como se sempre estivessem destinados a estar lá. É isso por hoje. Se você achou isso útil, por favor, dê um like ou compartilhe com amigos que possam precisar.

Salvar com um clique

Faça leitura profunda de artigos virais com IA no YouMind

Salve a fonte, faça perguntas específicas, resuma o argumento e transforme um artigo viral em notas reutilizáveis em um único espaço de trabalho com IA.

Explorar o YouMind
Para criadores

Transforme seu Markdown em um artigo 𝕏 impecável

Quando você publica seus próprios textos longos, formatar imagens, tabelas e blocos de código para o 𝕏 é uma dor de cabeça. O YouMind transforma um rascunho completo em Markdown em um artigo 𝕏 impecável e pronto para publicar.

Experimente Markdown para 𝕏

Mais padrões para decifrar

Artigos virais recentes

Explorar mais artigos virais