¡He replicado la nueva interacción de interfaz generativa de Claude!

@op7418
CHINOhace 4 meses · 15 mar 2026
265K
446
63
34
815

TL;DR

Este artículo detalla la replicación de la interfaz generativa de Claude en Code Pilot. Cubre desafíos técnicos como el renderizado en iframe sandbox, el análisis de JSON en streaming y mejoras en la experiencia de usuario para garantizar una navegación fluida y sin parpadeos.

Anthropic lanzó recientemente una nueva interacción de UI generativa en Claude. Te ayuda a introducir conceptos e información visualmente dentro del flujo del chat, haciéndolo mucho más fácil de entender que el texto plano. !Image Ya estaba buscando soluciones similares, y cuando Claude lanzó la suya, sentí que tenía que acelerar mi trabajo. Al mismo tiempo, pude aplicar ingeniería inversa a su enfoque como referencia. Después de dos días de incitar intensamente a Codex y Claude, ¡realmente lo logré! !https://pbs.twimg.com/amplify_video_thumb/2033112086713364480/img/EUmHCjsTK7tfnToZ.jpg Esta función permite que la IA dibuje gráficos interactivos directamente en el chat con salida en streaming, renderizando a medida que genera. Anteriormente, al pedirle a la IA que escribiera una página web, tenías que esperar a que se generara todo el código antes de renderizar, lo que tomaba una eternidad. Ahora es diferente. Puedes ver cómo se dibujan los gráficos trazo a trazo en el lienzo, con los nodos SVG apareciendo uno tras otro. El proceso de generación en sí mismo es impresionante, y es interactivo inmediatamente después de completarse. Experiméntalo directamente en mi producto Agent, Code Pilot: https://github.com/op7418/CodePilot En esta publicación, presentaré su uso, el proceso de implementación específico y algunas precauciones. ## ¿Cuáles son algunos casos de uso divertidos? Análisis de datos: Por fin, los números tienen sentido Por ejemplo, pídele que dibuje un gráfico para la "Estimación del costo diario del conflicto entre EE. UU. e Irán". Anteriormente, la IA te daba un muro de texto donde las relaciones numéricas eran difíciles de ver. Ahora, genera un gráfico directamente, haciendo que la cantidad de cada parte sea clara de un vistazo. El texto y los gráficos se generan juntos, explicando donde sea necesario y dibujando donde sea necesario. !Image Pequeñas herramientas: Construye una calculadora interactiva o algo similar Pídele que haga una calculadora de interés compuesto. Arrastra los controles deslizantes para cambiar el monto inicial o los años de inversión, y los gráficos y números de abajo se actualizan en tiempo real. Esto no es una imagen estática; es una herramienta verdaderamente interactiva. Los cálculos de préstamos, las conversiones de unidades y cosas similares se pueden hacer. !Image Diagramas de arquitectura: El favorito de los programadores Puedes pedirle que te ayude a dibujar la arquitectura de un proyecto o visualizar un plan de implementación. Por ejemplo, aquí le pedí que dibujara el flujo completo desde la API hasta la autenticación JWT. Las comparaciones de funciones, los diagramas de flujo y las estructuras jerárquicas son todas gráficas, lo que hace que la arquitectura sea mucho más rápida de entender que leer descripciones de texto. !Image Analizar datos en línea Otra forma de jugar es lanzarle un enlace de repositorio de GitHub; rastreará los datos y realizará un análisis visual. Por ejemplo, le envié la dirección de mi propio proyecto, CodePilot, para su análisis. Las estrellas, los forks, el stack tecnológico, el diseño de la arquitectura y los módulos principales se dibujan en gráficos. Puedes ver la imagen completa del proyecto de un vistazo, lo cual es mucho mejor que leer un texto largo. !Image Explicaciones interactivas y profundas La parte más fuerte es su estrecha integración con el modelo; no es solo una salida única. Puedes interactuar con los diagramas generados y pedir explicaciones más detalladas. Por ejemplo, aquí le pedí que explicara la relación entre los monzones y las corrientes oceánicas. !Image Si queremos saber más, podemos hacer clic en el botón del mecanismo de corrientes oceánicas. Enviará automáticamente un comando al modelo actual para continuar generando un diagrama del mecanismo de corrientes oceánicas. !Image Por supuesto, podemos realizar interacciones más complejas, como visualizar fórmulas comunes de física y matemáticas. Esto es muy útil para los estudiantes; cada parámetro se puede controlar mediante controles deslizantes y entradas, y la animación cambia inmediatamente. !Image Soporte para modelos chinos Una vez implementado en CodePilot, no es solo para Claude. Kimi K2.5, Minimax M2.5 y los modelos nativos de Anthropic lo ejecutan bien. Creo que los gráficos dibujados por K2.5 son incluso más bonitos que Sonnet 3.5, y el análisis de la arquitectura es muy detallado. Si usas esta función, te recomiendo probar K2.5 primero. Bien, eso es básicamente todo para las demostraciones del modelo. Si no te importa cómo se implementa, puedes simplemente instalar CodePilot y divertirte. ## ¿Cómo se implementó? !Image Cómo lo hace Claude Claude.ai oficialmente usa el mecanismo tool_use. El modelo llama a una herramienta dedicada para generar contenido estructurado de widgets, y el frontend analiza los parámetros de entrada de la llamada a la herramienta para renderizar. Esta solución funciona bien bajo la propia arquitectura de Claude.ai. Pero no funciona para CodePilot por tres razones: Primero, limitaciones del SDK. CodePilot usa el modo preestablecido claude_code del SDK de Claude Agent, que no permite registrar herramientas personalizadas. El SDK expone un flujo de delta de texto, por lo que no se puede extender a nivel de herramienta. Segundo, la experiencia de streaming. Los resultados de tool_use deben esperar a que input_json_delta termine antes de renderizar, y no admite renderizado HTML incremental. Con los bloques de código, el HTML llega con el flujo de texto, lo que permite renderizar mientras se genera. Tercero, aislamiento de renderizado. Claude.ai usa Shadow DOM para el aislamiento. Nosotros elegimos un iframe sandbox. El aislamiento del iframe es más completo: un entorno de ejecución JS completamente independiente, CSP controla con precisión la carga de recursos y no hay fugas de estilo ni escape de scripts. Cómo lo hicimos nosotros Disparador: Bloques de código El modelo genera un bloque de código Markdown especial para activar el renderizado: ``show-widget {"title":"training_flow","widget_code":"<svg width=\"100%\" viewBox=\"0 0 680 400\">...</svg>"} ` Este formato reutiliza los modos de bloque de código existentes de CodePilot (image-gen-request, batch-plan, etc.), que la cadena de análisis del frontend soporta de forma natural. ![Image](https://pbs.twimg.com/media/HDcR5dyasAAtwTN?format=jpg&name=small) **Renderizado: Iframe Sandbox** Cada widget se renderiza en un iframe con sandbox="allow-scripts". El srcdoc del iframe es una página receptora cuidadosamente construida. La política CSP solo permite scripts externos de 4 dominios CDN, y connect-src 'none'' prohíbe todas las solicitudes de red. Las actualizaciones de contenido se reciben a través de postMessage. Durante la fase de vista previa en streaming, se envía widget:update sin ejecutar scripts. El renderizado final envía widget:finalize, que ejecuta scripts. Un ResizeObserver monitorea los cambios de altura del contenido y los informa a la página principal a través de postMessage. Todos los clics en <a> se interceptan y se reenvían a la página principal para abrirse en una nueva ventana. La sincronización del tema se basa en monitorear los cambios de clase en la página principal para cambiar entre los modos oscuro/claro en tiempo real. ![Image](https://pbs.twimg.com/media/HDcR8ilbgAATB-8?format=jpg&name=small) **Puente de variables CSS** Esto es clave para que el widget se integre visualmente con la aplicación. CodePilot usa variables CSS en el espacio de color OKLCH. Las pautas de diseño de widgets de Anthropic usan nombres de variables estándar como --color-background-primary. La capa de puente inyecta los valores de las variables de CodePilot en el :root del iframe cuando se inicializa. El CSS escrito por el modelo según las pautas puede usar directamente los colores del tema actual. Al cambiar al modo oscuro, la página principal detecta el cambio de clase, recalcula los valores de las variables y los envía al iframe. ![Image](https://pbs.twimg.com/media/HDcR_fLaYAAL88P?format=jpg&name=small) **Renderizado en streaming** Esta es la parte más compleja de toda la implementación. El modelo genera token por token. En cualquier momento, el código del widget recibido podría ser JSON incompleto, HTML incompleto o una etiqueta <script> incompleta. El flujo de procesamiento es el siguiente: La expresión regular coincide con `show-widget para distinguir entre estados "no cerrado" y "cerrado". Localiza manualmente el contenido después de "widget_code":" y desescapalo carácter por carácter. No se puede usar JSON.parse porque el JSON aún no está terminado. Cuando se detecta una etiqueta <script> no cerrada, trunca antes de <script para evitar mostrar código JavaScript como texto visible. Un debounce de 120 ms evita que el iframe se actualice con demasiada frecuencia. El contenido en streaming elimina todos los scripts y controladores de eventos; la interacción no es necesaria durante la fase de vista previa. ![Image](https://pbs.twimg.com/media/HDcSDCGb0AAwY7J?format=jpg&name=small) **Puliendo la experiencia: Detalles que no deberían notarse** Desde una perspectiva de código o implementación, no es tan complejo; la complejidad radica en pulir la experiencia. Hay demasiados lugares que pueden afectar la experiencia, y los usuarios no deben notar esos detalles ni el proceso de generación. Esto requiere manejar cada etapa de manera diferente: 1. Detalles que no parecen streaming 2. Contenido que no debería aparecer ![Image](https://pbs.twimg.com/media/HDcSKQLaEAABilZ?format=jpg&name=small) **Desaparición de texto** El modelo primero genera un texto introductorio ("Déjame explicarte visualmente..."), luego comienza el bloque del widget. Tan pronto como aparece el bloque, el texto anterior desaparece repentinamente y solo regresa después de que el widget termina de renderizar. La razón es que parseAllShowWidgets() devuelve un array vacío para texto plano. Cuando el bloque acaba de aparecer pero no está cerrado, el texto antes del bloque se pasa a esta función y se descarta. Solución: Cuando el texto antes del bloque no contiene un bloque de widget completo, se renderiza directamente como <MessageResponse>, omitiendo la función de análisis. **Saltos de altura** En el momento en que el widget termina de renderizar, toda el área del chat tiembla. La altura inicial del iframe es 0px. Cuando el contenido informa su altura real por primera vez, podría ser de 400px+, y una transición CSS hace que este cambio ocurra en 300 ms, lo que resulta en un salto notable. Solución: Deshabilitar temporalmente las transiciones CSS durante el primer informe de altura para que la altura se ajuste instantáneamente. Los ajustes de altura posteriores utilizan transiciones suaves. **Parpadeo al finalizar** Cuando el widget cambia de la vista previa en streaming al renderizado final, el contenido parpadea. El iframe receptor reemplaza todo el DOM con root.innerHTML = html durante la finalización. Incluso si el contenido nuevo y el antiguo son idénticos (widget SVG puro), el navegador activa un fotograma de repintado. Solución: Durante la finalización, primero analiza el nuevo HTML en un contenedor temporal y separa los elementos del script. Compara el HTML visual (sin scripts) con el DOM actual; si son iguales, omite el reemplazo de innerHTML y solo agrega los scripts para su ejecución. Los widgets SVG puros logran una finalización sin repintado. **Salto de desplazamiento** El chat se desplaza automáticamente hacia abajo, luego de repente retrocede varios cientos de píxeles y vuelve a saltar. Cuando el streaming termina, el componente StreamingMessage se desmonta y el componente MessageItem se monta. Estos son dos componentes React completamente diferentes, y el WidgetRenderer interno se destruye y se reconstruye. La altura del iframe de la nueva instancia comienza desde 0, lo que hace que la altura del área de contenido caiga bruscamente, lo que desencadena un ajuste de desplazamiento en use-stick-to-bottom. Solución: Caché de altura a nivel de módulo. Cada vez que un widget informa su altura, se escribe en un caché usando los primeros 200 caracteres del widgetCode como clave. La nueva instancia de WidgetRenderer lee la altura del caché durante la inicialización de useState, por lo que el iframe comienza a renderizar en la altura correcta, eliminando la transición de 0 a real. **Fuga de código de script** Cuando se carga un widget con Chart.js, se muestra un gran bloque de código JavaScript en la parte inferior. Las etiquetas <script> que genera el modelo llegan carácter por carácter. Cuando la etiqueta de apertura llega pero la de cierre no, sanitizeForStreaming elimina la etiqueta de apertura, pero el código JavaScript dentro se convierte en un nodo de texto sin formato que se renderiza como contenido visible. Solución: Después de extraer el código parcial en StreamingMessage, verifica si el último <script tiene un </script> coincidente. Si no, trunca en la posición de <script. Las pautas del widget especifican que los scripts van al final, por lo que el truncamiento no afecta el contenido visual. Durante el truncamiento, se muestra una máscara shimmer y la barra de estado muestra "Agregando animaciones interactivas a la visualización". **Condición de carrera de iframe listo** En casos raros, el widget no se renderiza en absoluto, manteniéndose a una altura de 0px. WidgetRenderer registra un listener de eventos de mensaje a través de useEffect. Sin embargo, el script receptor del iframe envía widget:ready tan pronto como se carga. Si el iframe se carga más rápido de lo que se ejecuta el efecto de React, widget:ready se envía antes de que se registre el listener, y iframeReady nunca se vuelve verdadero. Solución: Agregar una devolución de llamada onLoad al elemento iframe como respaldo. Cuando se activa onLoad, el script receptor debe haber terminado de ejecutarse, proporcionando una señal de preparación confiable. **Estabilidad del árbol de componentes de React** El widget parpadea en el momento en que se cierra el bloque. Dos problemas se superponen: el widget parcial en streaming no tiene clave de React, y después de cerrarse, obtiene key="w-0". El cambio de clave provoca un remontaje. Además, la superposición shimmer se implementó con un <div> envolvente, que cambió la estructura del árbol de componentes y provocó otro remontaje. Solución: Asignar una clave estable al widget parcial (w-N, donde N es la posición esperada en el array final de segmentos), consistente con la clave después del cierre. Mover la superposición shimmer dentro del WidgetRenderer, controlada a través de una prop showOverlay. El árbol de componentes permanece <WidgetRenderer key="w-N"> en todo momento. ## **Reflexiones finales** Para todo el sistema de UI generativa, la parte difícil no es "hacer que un fragmento de HTML se ejecute en un iframe". Eso es simple. La complejidad real radica en mantener ese iframe visualmente estable durante las transiciones de estado como el streaming, los cambios de ciclo de vida de los componentes y los cambios de tema. Cada "parpadeo", "salto" o "desaparición" requiere comprender la reconciliación de React, el pipeline de renderizado del navegador y la sincronización de postMessage`. El efecto final es que los usuarios ven gráficos y diagramas intercalados naturalmente en las respuestas del modelo, como si siempre hubieran estado destinados a estar allí. Eso es todo por hoy. Si te resultó útil, por favor dale un "me gusta" o compártelo con amigos que puedan necesitarlo.

Guardar con un clic

Lee artículos virales en profundidad con IA en YouMind

Guarda la fuente, haz preguntas concretas, resume el argumento y convierte un artículo viral en notas reutilizables en un único espacio de trabajo con IA.

Explora YouMind
Para creadores

Convierte tu Markdown en un artículo de 𝕏 impecable

Cuando publicas tus propios textos largos, dar formato en 𝕏 a imágenes, tablas y bloques de código es un fastidio. YouMind convierte un borrador completo en Markdown en un artículo de 𝕏 impecable y listo para publicar.

Prueba Markdown a 𝕏

Más patrones por descifrar

Artículos virales recientes

Explorar más artículos virales