Ecco il flusso di lavoro diventato predefinito in ogni team design-to-code: esporta un frame da Figma, incolla il PNG in Claude o Cursor, digita "costruisci questo" e itera sull'output allucinato. Funziona abbastanza bene da sembrare produttivo. Non funziona abbastanza bene da poter essere spedito in produzione.

Questo non è un problema di capacità del modello. È un problema di input. Lo screenshot è la rappresentazione peggiore possibile di un design Figma per un LLM che deve ragionarne — ed è quasi universalmente ciò che i team cercano per prima cosa. Il bundle di contesto di figmascope è l'alternativa strutturata.

La gerarchia è scomparsa

Un file Figma è un albero. I frame contengono gruppi auto-layout, che contengono istanze di componenti, che contengono layer di testo e fill. Quell'albero codifica l'intento di layout: questa riga è un flex container, questa card è una box con padding, questi tre elementi sono fratelli con gap di 16px tra loro.

Uno screenshot appiattisce quell'albero in una griglia di pixel. L'LLM vede forme e colori. Non vede la struttura di layout — la inferisce. E l'inferenza è con perdita in entrambe le direzioni: il modello può ricostruire una struttura che visivamente sembra giusta ma è semanticamente sbagliata (un div a larghezza fissa invece di un flex child, posizionamento assoluto invece di auto-layout), oppure può vedere ambiguità strutturale e scegliere arbitrariamente.

Non puoi capire da un PNG se una riga orizzontale di elementi è implementata con display: flex, CSS Grid, un HStack personalizzato, o tre div assolutamente posizionati. Sono visivamente identici. L'LLM ne sceglie uno. La scelta cambia tra le esecuzioni.

La semantica non sopravvive alla rasterizzazione

L'LLM può vedere che un rettangolo con angoli arrotondati contiene del testo e un'icona. Quello che non può vedere:

La semantica in Figma vive nell'albero dei layer: nomi dei componenti, proprietà delle varianti, tipi di nodo. Un componente Button/Primary/Large è esplicitamente tipizzato. In uno screenshot, è un rettangolo arrotondato con un'ombra e un'etichetta. Il modello indovina "questo è probabilmente un button" correttamente nella maggior parte dei casi — e poi indovina "questa è probabilmente la variante primary" in base al colore, che potrebbe o meno corrispondere al naming effettivo del tuo design system.

Le piccole discrepanze si accumulano. Un ghost button reso come outlined button. Un tooltip reso come trigger di modale. Uno stato disabilitato reso come attivo. Ognuno di questi è a un passo di inferenza screenshot dalla sorgente di verità.

I sistemi di spaziatura non si risolvono in numeri

Guarda uno screenshot di una card con padding. Qual è il padding? Non puoi dirlo senza misurare i pixel, conoscere la scala del canvas, conoscere la risoluzione di esportazione, e fare i calcoli. L'LLM fa i calcoli male — stima, arrotonda, e non ha modo di sapere se il tuo sistema di spaziatura usa una griglia base di 8px o 4px o qualcosa di personalizzato.

Quindi indovina. Genera padding: 12px quando il design dice 16. Genera gap: 8px quando il design dice 12. Questi numeri sembrano plausibili isolatamente ma sono sbagliati — e se il tuo design system usa token di spacing come spacing.md o Spacing/400, l'LLM non ne sa nulla. Hardcoda letterali che divergeranno dal tuo sistema nel momento in cui qualcosa cambia.

L'LLM non sta allucinando. Sta facendo esattamente quello che faresti tu con solo uno screenshot: indovinare. Sei solo sorpreso quando le ipotesi sono sbagliate perché potevi vedere la risposta giusta nel file Figma tutto il tempo.

Le relazioni tra token svaniscono

Il tuo designer ha impostato quello sfondo su #7F5CFE. In Figma, quel hex è vincolato a una variabile: color/brand/primary. Quel binding è significativo — significa che il colore partecipa al theming, significa che la dark mode lo sostituisce, significa che se il colore del brand cambia aggiorni una variabile e ogni istanza si aggiorna.

Nello screenshot: è viola. L'LLM genera background-color: #7F5CFE. La relazione con il token è scomparsa. Il tuo codebase ora ha un hex hardcoded che non seguirà mai il tuo design system. Moltiplica questo per ogni componente nella schermata.

Lo stesso vale per le scale tipografiche, i border radius e le definizioni delle ombre. Ogni valore in un file Figma ben mantenuto è potenzialmente un token nominato. Ogni valore in uno screenshot è solo un numero.

Il riuso dei componenti è invisibile

Una schermata ben composta riusa i componenti. Le quattro product card sono quattro istanze dello stesso componente ProductCard. L'avatar nella nav e l'avatar nel thread dei commenti sono entrambi istanze di Avatar/Medium. Questo è importante per il codice: vuoi un componente React, non quattro variazioni fatte a mano che divergeranno.

Da uno screenshot, l'LLM vede quattro rettangoli visivamente simili. Potrebbe generare un componente riutilizzabile — o potrebbe generare quattro blocchi di JSX quasi identici perché non ha notato che erano gli stessi. Non c'è nessun segnale nell'immagine che gli dica quale sia corretto.

L'IR che figmascope esporta porta componentId su ogni nodo istanza. L'agente sa: questi quattro nodi sono tutti ProductCard. Generalo una volta, renderizzalo quattro volte con prop diverse. Questo è l'output che vuoi. Questo è l'output che non puoi ottenere dai pixel.

L'identità delle stringhe è persa

Hai un button "Continua" su tre schermate diverse. Sono quelle tre istanze la stessa stringa, o un designer le ha scritte indipendentemente? In un file Figma ben strutturato, fanno riferimento alla stessa chiave stringa. Questo significa una voce i18n, una modifica si propaga ovunque.

In tre screenshot: tre volte l'LLM genera una stringa hardcoded. Se stai costruendo un'app internazionalizzata, ora hai tre stringhe da trovare e sostituire invece di una da cercare. Piccola cosa. Si accumula in un codebase reale.

Perché l'LLM allucinacina: ri-deriva la struttura ogni volta

Il modello non ha memoria delle esecuzioni precedenti. Ogni volta che incolli lo stesso screenshot, ricostruisce la struttura da zero. La ricostruzione è probabilistica — il che significa che lo stesso screenshot + lo stesso prompt + lo stesso modello può produrre output misurabili diversi in esecuzioni diverse. Stesso design, codice diverso. Nomi di componenti diversi, pattern className diversi, scelte di layout diverse.

Questo non è un bug del modello. È il comportamento atteso di un modello probabilistico dati vincoli insufficienti. Lo screenshot fornisce vincoli insufficienti. Il modello riempie i vuoti. I vuoti vengono riempiti diversamente ogni volta.

Puoi aggirare parzialmente questo problema con prompt più lunghi e dettagliati — "usa Tailwind, usa griglia 8px, usa questi nomi di componenti..." — ma a quel punto hai specificato manualmente la struttura che avrebbe dovuto essere nel file di design fin dall'inizio. Stai facendo il lavoro di estrazione che lo strumento dovrebbe fare.

Il problema della riproducibilità

I team che usano screenshot per il design-to-code handoff incorrono nello stesso problema: l'output non è riproducibile. Due sviluppatori, stesso screenshot Figma, chiedono indipendentemente a Claude — ottengono strutture di componenti diverse, pattern className diversi, decisioni di nidificazione diverse. Ora hai due codebase che visivamente sembrano uguali ma sono architetturalmente inconsistenti.

Questo rende la code review più difficile. Rende il refactoring più difficile. Rende l'audit di conformità al design system impossibile. Non puoi fare diff su "cosa ha generato l'agente da questo design" se la risposta cambia ad ogni esecuzione.

Il contesto strutturato risolve la riproducibilità perché fissa gli input. Un bundle di input deterministico — lo stesso JSON con gli stessi ID nodo, nomi di componenti, valori di token e relazioni spaziali — produrrà output molto più coerenti tra esecuzioni, agenti e sviluppatori. Non perfettamente deterministico: il modello è ancora probabilistico. Ma la varianza cala drasticamente quando la struttura è specificata piuttosto che inferita.

Cosa ti dà uno screenshot vs. cosa ti dà l'IR

Prendi una product card: immagine, titolo, sottotitolo, prezzo, un button "Aggiungi al carrello". Ecco cosa ogni input dà all'agente:

Input screenshot: Un rettangolo con un'immagine in cima, due righe di testo, un numero e un button. I colori sono inferiti. Il padding è stimato. Se questo è un componente o un caso isolato è sconosciuto. La variante del button è inferita dal colore. Il sistema di spaziatura è sconosciuto.

Input IR: Tipo di nodo FRAME, nome ProductCard, component ID che collega alla definizione del componente. Auto-layout con direzione verticale, gap 16px, padding orizzontale 16px, padding verticale 12px. Nodi figli: IMAGE (riempie la larghezza, altezza fissa), TEXT con stringRef.key: "product.title" e stile typography/heading.sm, TEXT con stringRef.key: "product.subtitle" e stile typography/body.md, TEXT con fill color/price, INSTANCE di Button/Primary/Medium. Fill sfondo color/surface.card. Border radius radius/card.

L'IR dà all'agente una specifica. Lo screenshot gli dà un suggerimento.

Il frame: questo è il problema della documentazione

Abbiamo risolto questo stesso problema per il codice sorgente decenni fa. Non dai a un agente uno screenshot del tuo codebase e gli chiedi di ragionare sull'architettura. Gli dai il codice — la rappresentazione strutturata, analizzabile e semanticamente significativa. L'abstract syntax tree, non un'immagine dell'editor.

I design Figma sono dati strutturati. Hanno una struttura ad albero ben definita con nodi tipizzati e valori nominati. L'API Figma espone questa struttura completamente. L'unica ragione per cui il flusso di lavoro con screenshot persiste è che estrarre la struttura e formattarla come contesto ha attrito.

Ridurre quell'attrito è ciò che fa figmascope. Incolla l'URL Figma, l'esportazione gira nel tuo browser, e ottieni un ZIP con contesto strutturato: CONTEXT.md, tokens.json, IR per-schermata, inventario dei componenti, manifesto delle stringhe. Tutto ciò di cui l'agente ha bisogno, nulla inferito dai pixel.

Tieni gli screenshot per la conferma visiva — il bundle include PNG 2x esattamente per questo. Usa la struttura per tutto il resto. Vedi tutto in pratica: flusso di lavoro Cursor, flusso di lavoro Claude Code, o flusso di lavoro Aider.