Ho replicato l'interfaccia utente generativa appena rilasciata da Claude!

@op7418
CINESE4 mesi fa · 15 mar 2026
265K
446
63
34
815

TL;DR

Questo articolo descrive nel dettaglio la replica dell'interfaccia utente generativa di Claude in Code Pilot. Vengono trattati ostacoli tecnici come il rendering in sandbox iframe, il parsing di JSON in streaming e i perfezionamenti dell'UX per garantire un'esperienza fluida e priva di sfarfallii.

Anthropic ha recentemente lanciato una nuova interazione UI generativa in Claude. Ti aiuta a introdurre concetti e informazioni visivamente all'interno del flusso della chat, rendendo la comprensione molto più facile rispetto al semplice testo. !Image Stavo cercando soluzioni simili e, quando Claude ha rilasciato la sua, ho sentito di dover accelerare il mio lavoro. Allo stesso tempo, potevo fare reverse engineering del loro approccio come riferimento. Dopo due giorni di intense sollecitazioni a Codex e Claude, ce l'ho fatta! !https://pbs.twimg.com/amplify_video_thumb/2033112086713364480/img/EUmHCjsTK7tfnToZ.jpg Questa funzione permette all'AI di disegnare grafici interattivi direttamente nella chat con output in streaming, renderizzando mentre genera. In precedenza, quando si chiedeva all'AI di scrivere una pagina web, si doveva attendere la generazione dell'intero codice prima di renderizzare, il che richiedeva un'eternità. Ora è diverso. Puoi guardare i grafici mentre vengono disegnati tratto dopo tratto sulla tela, con i nodi SVG che appaiono uno dopo l'altro. Il processo di generazione stesso è sorprendente ed è interattivo immediatamente dopo il completamento. Provalo direttamente nel mio prodotto Agent, Code Pilot: https://github.com/op7418/CodePilot In questo post, introdurrò il suo utilizzo, il processo di implementazione specifico e alcune precauzioni. ## Quali sono alcuni casi d'uso divertenti? Analisi dei Dati: Finalmente i numeri hanno senso Ad esempio, chiedigli di disegnare un grafico per la "Stima del costo giornaliero del conflitto USA-Iran". In precedenza, l'AI ti dava un muro di testo in cui le relazioni numeriche erano difficili da vedere. Ora, genera direttamente un grafico, rendendo l'importo per ogni parte chiaro a colpo d'occhio. Testo e grafici vengono prodotti insieme, spiegando dove necessario e disegnando dove necessario. !Image Piccoli Strumenti: Crea un calcolatore interattivo o qualcosa di simile Chiedigli di creare un calcolatore di interesse composto. Trascina i cursori per modificare l'importo iniziale o gli anni di investimento, e i grafici e i numeri sottostanti si aggiornano in tempo reale. Questa non è un'immagine statica; è uno strumento veramente interattivo. Calcoli di prestiti, conversioni di unità e cose simili possono essere tutti realizzati. !Image Diagrammi di Architettura: Il preferito dei programmatori Puoi chiedergli di aiutarti a disegnare l'architettura di un progetto o visualizzare un piano di implementazione. Ad esempio, qui gli ho chiesto di disegnare il flusso completo dall'API all'autenticazione JWT. Confronti di funzionalità, diagrammi di flusso e strutture gerarchiche sono tutti grafici, rendendo l'architettura molto più veloce da capire rispetto alla lettura di descrizioni testuali. !Image Analizza Dati Online Un altro modo di giocare è lanciargli un link di un repository GitHub; analizzerà i dati ed eseguirà un'analisi visiva. Ad esempio, gli ho inviato l'indirizzo del mio progetto, CodePilot, per l'analisi. Stelle, fork, stack tecnologico, design dell'architettura e moduli principali sono tutti trasformati in grafici. Puoi vedere il quadro completo del progetto a colpo d'occhio, molto meglio che leggere un lungo testo. !Image Spiegazioni Interattive e Approfondite La parte più forte è la sua stretta integrazione con il modello; non è solo un output una tantum. Puoi interagire con i diagrammi generati e chiedere spiegazioni più dettagliate. Ad esempio, qui gli ho chiesto di spiegare la relazione tra monsoni e correnti oceaniche. !Image Se vogliamo saperne di più, possiamo cliccare il pulsante per il meccanismo delle correnti oceaniche. Invierà automaticamente un comando al modello corrente per continuare a generare un diagramma del meccanismo delle correnti oceaniche. !Image Naturalmente, possiamo eseguire interazioni più complesse, come visualizzare formule comuni di fisica e matematica. Questo è molto utile per gli studenti; ogni parametro può essere controllato tramite cursori e input, e l'animazione cambia immediatamente. !Image Supporto per Modelli Cinesi Una volta implementato in CodePilot, non è solo per Claude. Kimi K2.5, Minimax M2.5 e i modelli nativi di Anthropic funzionano tutti bene. Penso che i grafici disegnati da K2.5 siano persino più belli di Sonnet 3.5 e l'analisi dell'architettura sia molto dettagliata. Se usi questa funzione, ti consiglio di provare prima K2.5. Ok, questo è praticamente tutto per le dimostrazioni del modello. Se non ti interessa come è stato implementato, puoi semplicemente installare CodePilot e divertirti. ## Come è stato implementato? !Image Come lo fa Claude Claude.ai ufficialmente utilizza il meccanismo tool_use. Il modello chiama uno strumento dedicato per produrre contenuti strutturati del widget, e il frontend analizza i parametri di input della chiamata dello strumento per renderizzare. Questa soluzione funziona bene sotto l'architettura di Claude.ai. Ma non funziona per CodePilot per tre ragioni: Primo, limitazioni dell'SDK. CodePilot utilizza la modalità preimpostata claude_code dell'SDK Claude Agent, che non permette di registrare strumenti personalizzati. L'SDK espone un flusso delta di testo, quindi non può essere esteso a livello di strumento. Secondo, l'esperienza di streaming. I risultati di tool_use devono attendere la fine di input_json_delta prima di renderizzare e non supportano il rendering HTML incrementale. Con i blocchi di codice, l'HTML arriva con il flusso di testo, permettendo di renderizzare mentre si genera. Terzo, isolamento del rendering. Claude.ai utilizza Shadow DOM per l'isolamento. Noi abbiamo scelto un iframe sandbox. L'isolamento dell'iframe è più completo: un ambiente di esecuzione JS completamente indipendente, CSP controlla precisamente il caricamento delle risorse e non ci sono perdite di stile o fuga di script. Come abbiamo fatto noi Attivazione: Blocchi di Codice Il modello produce un blocco di codice Markdown speciale per attivare il rendering: ``show-widget {"title":"training_flow","widget_code":"<svg width=\"100%\" viewBox=\"0 0 680 400\">...</svg>"} ` Questo formato riutilizza le modalità esistenti dei blocchi di codice di CodePilot (image-gen-request, batch-plan, ecc.), che la catena del parser frontend supporta naturalmente. ![Image](https://pbs.twimg.com/media/HDcR5dyasAAtwTN?format=jpg&name=small) **Rendering: Iframe Sandbox** Ogni widget viene renderizzato in un iframe con sandbox="allow-scripts". Il srcdoc dell'iframe è una pagina ricevente accuratamente costruita. La politica CSP permette solo script esterni da 4 domini CDN e connect-src 'none' proibisce tutte le richieste di rete. Gli aggiornamenti dei contenuti vengono ricevuti tramite postMessage. Durante la fase di anteprima in streaming, viene inviato widget:update senza eseguire script. Il rendering finale invia widget:finalize, che esegue gli script. Un ResizeObserver monitora i cambiamenti di altezza del contenuto e li segnala alla pagina padre tramite postMessage. Tutti i clic su <a> vengono intercettati e inoltrati alla pagina padre per l'apertura in una nuova finestra. La sincronizzazione del tema si basa sul monitoraggio dei cambiamenti di classe sulla pagina padre per passare dalla modalità chiara/scura in tempo reale. ![Image](https://pbs.twimg.com/media/HDcR8ilbgAATB-8?format=jpg&name=small) **Ponte di Variabili CSS** Questo è fondamentale per far sì che il widget si fonda visivamente con l'app. CodePilot utilizza variabili CSS nello spazio colore OKLCH. Le linee guida per il design dei widget di Anthropic utilizzano nomi di variabili standard come --color-background-primary. Il livello di ponte inietta i valori delle variabili di CodePilot nel :root dell'iframe quando si inizializza. Il CSS scritto dal modello secondo le linee guida può utilizzare direttamente i colori del tema corrente. Quando si passa alla modalità scura, la pagina padre rileva il cambiamento di classe, ricalcola i valori delle variabili e li invia all'iframe. ![Image](https://pbs.twimg.com/media/HDcR_fLaYAAL88P?format=jpg&name=small) **Rendering in Streaming** Questa è la parte più complessa dell'intera implementazione. Il modello genera token dopo token. In qualsiasi momento, il codice del widget ricevuto potrebbe essere JSON incompleto, HTML incompleto o un tag <script> incompleto. Il flusso di elaborazione è il seguente: L'espressione regolare corrisponde a `show-widget per distinguere tra stati "non chiuso" e "chiuso". Individua manualmente il contenuto dopo "widget_code":" e lo de-escape carattere per carattere. JSON.parse non può essere utilizzato perché il JSON non è ancora finito. Quando viene rilevato un tag <script> non chiuso, tronca prima del <script per evitare di visualizzare il codice JavaScript come testo visibile. Un debounce di 120ms impedisce all'iframe di aggiornarsi troppo frequentemente. Il contenuto in streaming rimuove tutti gli script e i gestori di eventi; l'interazione non è necessaria durante la fase di anteprima. ![Image](https://pbs.twimg.com/media/HDcSDCGb0AAwY7J?format=jpg&name=small) **Perfezionare l'Esperienza: Dettagli che non dovrebbero essere notati** Dal punto di vista del codice o dell'implementazione, non è così complesso; la complessità sta nel perfezionare l'esperienza. Ci sono troppi punti che possono influenzare l'esperienza e gli utenti non devono notare quei dettagli e il processo di generazione. Questo richiede di gestire ogni fase in modo diverso: 1. Dettagli che non sembrano streaming 2. Contenuti che non dovrebbero apparire ![Image](https://pbs.twimg.com/media/HDcSKQLaEAABilZ?format=jpg&name=small) **Scomparsa del Testo** Il modello prima produce un testo introduttivo ("Lascia che ti spieghi visivamente..."), poi inizia il blocco del widget. Non appena appare il blocco, il testo precedente scompare improvvisamente e ritorna solo dopo che il widget ha finito di renderizzare. Il motivo è che parseAllShowWidgets() restituisce un array vuoto per il testo semplice. Quando il blocco appare ma non è ancora chiuso, il testo prima del blocco viene passato a questa funzione e viene eliminato. Correzione: Quando il testo prima del blocco non contiene un blocco widget completato, renderizzalo direttamente come <MessageResponse>, bypassando la funzione di analisi. **Salti di Altezza** Nel momento in cui il widget finisce di renderizzare, l'intera area della chat sussulta. L'altezza iniziale dell'iframe è 0px. Quando il contenuto riporta per la prima volta la sua altezza effettiva, potrebbe essere 400px+, e una transizione CSS fa sì che questo cambiamento avvenga in 300ms, risultando in un salto evidente. Correzione: Disabilita temporaneamente le transizioni CSS durante il primo rapporto di altezza per far sì che l'altezza si adatti istantaneamente. Le successive regolazioni di altezza utilizzano transizioni fluide. **Sfarfallio della Finalizzazione** Quando il widget passa dall'anteprima in streaming al rendering finale, il contenuto lampeggia. L'iframe ricevente sostituisce l'intero DOM con root.innerHTML = html durante la finalizzazione. Anche se il contenuto nuovo e vecchio sono identici (widget SVG puro), il browser attiva un frame di ripaint. Correzione: Durante la finalizzazione, analizza prima il nuovo HTML in un contenitore temporaneo e separa gli elementi script. Confronta l'HTML visivo (senza script) con il DOM corrente: se sono uguali, salta la sostituzione innerHTML e aggiungi solo gli script per l'esecuzione. I widget SVG puri ottengono una finalizzazione a zero ripaint. **Salto dello Scorrimento** La chat sta scorrendo automaticamente verso il basso, poi improvvisamente torna indietro di diverse centinaia di pixel e poi riscende di nuovo. Quando lo streaming termina, il componente StreamingMessage viene smontato e il componente MessageItem viene montato. Questi sono due componenti React completamente diversi e il WidgetRenderer interno viene distrutto e ricostruito. L'altezza dell'iframe della nuova istanza parte da 0, causando un forte calo dell'altezza dell'area di contenuto, che attiva una regolazione dello scorrimento in use-stick-to-bottom. Correzione: Memorizzazione nella cache dell'altezza a livello di modulo. Ogni volta che un widget riporta la sua altezza, viene scritta in una cache utilizzando i primi 200 caratteri del widgetCode come chiave. La nuova istanza di WidgetRenderer legge l'altezza dalla cache durante l'inizializzazione di useState, quindi l'iframe inizia a renderizzare all'altezza corretta, eliminando la transizione 0→effettiva. **Perdita di Codice Script** Quando un widget con Chart.js viene caricato, un grande blocco di codice JavaScript viene visualizzato in fondo. I tag <script> prodotti dal modello arrivano carattere per carattere. Quando il tag di apertura arriva ma il tag di chiusura non è ancora arrivato, sanitizeForStreaming rimuove il tag di apertura, ma il codice JavaScript all'interno diventa un nodo di testo nudo renderizzato come contenuto visibile. Correzione: Dopo aver estratto il codice parziale in StreamingMessage, controlla se l'ultimo <script ha un </script> corrispondente. In caso contrario, tronca alla posizione di <script. Le linee guida del widget specificano che gli script vanno alla fine, quindi la troncatura non influisce sul contenuto visivo. Durante la troncatura, viene mostrata una maschera shimmer e la barra di stato visualizza "Aggiunta di animazioni interattive alla visualizzazione." **Condizione di Gara Iframe Ready** In rari casi, il widget non viene renderizzato affatto, rimanendo a un'altezza di 0px. WidgetRenderer registra un listener di eventi del messaggio tramite useEffect. Tuttavia, lo script ricevente dell'iframe invia widget:ready non appena si carica. Se l'iframe si carica più velocemente dell'esecuzione dell'effetto React, widget:ready viene inviato prima che il listener sia registrato e iframeReady non diventa mai true. Correzione: Aggiungi un callback onLoad all'elemento iframe come fallback. Quando onLoad si attiva, lo script ricevente deve aver finito di eseguire, fornendo un segnale di prontezza affidabile. **Stabilità dell'Albero dei Componenti React** Il widget lampeggia nel momento in cui il blocco si chiude. Due problemi si sovrappongono: il widget parziale in streaming non ha una chiave React e, dopo la chiusura, ottiene key="w-0". Il cambiamento di chiave causa un rimontaggio. Inoltre, la sovrapposizione shimmer è stata implementata con un <div> di avvolgimento, che ha cambiato la struttura dell'albero dei componenti e ha causato un altro rimontaggio. Correzione: Assegna una chiave stabile al widget parziale (w-N, dove N è la posizione prevista nell'array finale dei segmenti), coerente con la chiave dopo la chiusura. Sposta la sovrapposizione shimmer all'interno di WidgetRenderer, controllata tramite una prop showOverlay. L'albero dei componenti rimane <WidgetRenderer key="w-N"> per tutto il tempo. ## **Considerazioni Finali** Per l'intero sistema UI generativo, la parte difficile non è "far funzionare un pezzo di HTML in un iframe". Questo è semplice. La vera complessità sta nel mantenere quell'iframe visivamente stabile durante le transizioni di stato come lo streaming, i cambiamenti del ciclo di vita dei componenti e i cambiamenti di tema. Ogni "lampeggiamento", "salto" o "scomparsa" richiede la comprensione della riconciliazione di React, della pipeline di rendering del browser e dei tempi di postMessage`. L'effetto finale è che gli utenti vedono grafici e diagrammi naturalmente intervallati nelle risposte del modello, come se fossero sempre stati destinati a essere lì. Questo è tutto per oggi. Se hai trovato utile questo articolo, per favore metti un like o condividilo con amici che potrebbero averne bisogno.

Salva con un clic

Leggi in profondità gli articoli virali con l’AI di YouMind

Salva la fonte, fai domande mirate, riassumi l’argomentazione e trasforma un articolo virale in note riutilizzabili in un unico spazio di lavoro AI.

Scopri YouMind
Per i creator

Trasforma il tuo Markdown in un articolo 𝕏 pulito

Quando pubblichi i tuoi testi lunghi, formattare immagini, tabelle e blocchi di codice per 𝕏 è una seccatura. YouMind trasforma un'intera bozza Markdown in un articolo 𝕏 pulito e pronto da pubblicare.

Prova Markdown verso 𝕏

Altri pattern da decodificare

Articoli virali recenti

Esplora altri articoli virali