Dit is de workflow die nu standaard is geworden bij elk ontwerp-naar-code-team: exporteer een frame uit Figma, plak de PNG in Claude of Cursor, typ "bouw dit" en itereer vanuit de gehalluceerde uitvoer. Het werkt net goed genoeg om productief te voelen. Het werkt niet goed genoeg om mee te verzenden.

Dit is geen modelcapaciteitsprobleem. Het is een invoerprobleem. De schermafbeelding is de slechtst mogelijke weergave van een Figma-ontwerp voor een LLM om over te redeneren — en het is bijna universeel het eerste waarnaar teams grijpen. De figmascope-contextbundel is het gestructureerde alternatief.

De hiërarchie is weg

Een Figma-bestand is een boom. Frames bevatten auto-lay-outgroepen, die componentinstanties bevatten, die tekst- en vullagen bevatten. Die boom codeert de lay-outintentie: deze rij is een flex-container, deze kaart is een box met opvulling, deze drie items zijn broers met 16px-gaps ertussen.

Een schermafbeelding maakt die boom plat tot een pixelraster. Het LLM ziet vormen en kleuren. Het ziet de lay-outstructuur niet — het leidt die af. En inferentie is verliesgevend in beide richtingen: het model kan structuur reconstrueren die er visueel juist uitziet maar semantisch onjuist is (een div met vaste breedte in plaats van een flex-kind, absolute positionering in plaats van auto-lay-out), of het kan structurele dubbelzinnigheid zien en willekeurig één kiezen.

Je kunt aan een PNG niet zien of een horizontale rij items is geïmplementeerd met display: flex, CSS Grid, een aangepaste HStack, of drie absoluut gepositioneerde divs. Ze zijn visueel identiek. Het LLM kiest er één. De keuze verandert tussen runs.

Semantiek overleeft rastering niet

Het LLM kan zien dat een rechthoek met afgeronde hoeken wat tekst en een pictogram bevat. Wat het niet kan zien:

Semantiek in Figma leeft in de lagenboom: componentnamen, varianteigenschappen, knooppuntsoorten. Een Button/Primary/Large-component is expliciet getypt. In een schermafbeelding is het een afgeronde rechthoek met een schaduw en een label. Het model raadt "dit is waarschijnlijk een knop" de meeste keren correct — en raadt dan "dit is waarschijnlijk de primaire variant" op basis van kleur, wat al dan niet overeenkomt met de werkelijke naamgeving van je ontwerpsysteem.

Kleine discrepanties stapelen zich op. Een geestknop weergegeven als een omrande knop. Een tooltip weergegeven als een modaltrigger. Een uitgeschakelde toestand weergegeven als actief. Elk van deze is één schermafbeeldingsinferentiestap verwijderd van de bron van waarheid.

Spatiëringssystemen lossen niet op in getallen

Kijk naar een schermafbeelding van een kaart met opvulling. Wat is de opvulling? Je kunt het niet zien zonder pixels te meten, de canvasschaal te kennen, de exportresolutie te kennen en de berekening te doen. Het LLM doet de berekening slecht — het schat, het rondt af, en het kan niet weten of je spatiëringssysteem een 8px-basisraster gebruikt of een 4px-raster of iets aangepaст.

Dus raadt het. Het genereert padding: 12px wanneer het ontwerp 16 zegt. Het genereert gap: 8px wanneer het ontwerp 12 zegt. Deze getallen zien er plausibel uit afzonderlijk maar ze zijn onjuist — en als je ontwerpsysteem spatiëeringstokens gebruikt zoals spacing.md of Spacing/400, weet het LLM er helemaal niets van. Het codeert letterlijke waarden hard die afwijken van je systeem zodra er iets verandert.

Het LLM hallucineert niet. Het doet precies wat jij zou doen met alleen een schermafbeelding: raden. Je bent alleen verrast wanneer de gissingen fout zijn omdat je het juiste antwoord de hele tijd al in het Figma-bestand kon zien.

Tokenrelaties verdwijnen

Je ontwerper heeft die achtergrond ingesteld op #7F5CFE. In Figma is die hex gebonden aan een variabele: color/brand/primary. Die binding is betekenisvol — het betekent dat de kleur deelneemt aan theming, het betekent dat dark mode het wisselt, het betekent dat als de merkkleur verandert je één variabele bijwerkt en elke instantie wordt bijgewerkt.

In de schermafbeelding: het is paars. Het LLM genereert background-color: #7F5CFE. De tokenrelatie is weg. Je codebase heeft nu een hardgecodeerde hex die nooit mee zal gaan met je ontwerpsysteem. Vermenigvuldig dit met elk component op het scherm.

Hetzelfde geldt voor typografieschalen, randstralen en schaduwdefinities. Elke waarde in een goed onderhouden Figma-bestand is potentieel een benoemde token. Elke waarde in een schermafbeelding is gewoon een getal.

Componenthergebruik is onzichtbaar

Een goed samengesteld scherm hergebruikt componenten. De vier productkaarten zijn vier instanties van hetzelfde ProductCard-component. De avatar in de nav en de avatar in de commentaarthread zijn beide instanties van Avatar/Medium. Dit is van belang voor code: je wilt één React-component, niet vier handgeschreven varianten die zullen divergeren.

Vanuit een schermafbeelding ziet het LLM vier visueel vergelijkbare rechthoeken. Het kan één herbruikbaar component genereren — of het kan vier bijna-identieke JSX-blokken genereren omdat het niet merkte dat ze hetzelfde waren. Er is geen signaal in de afbeelding om het te vertellen welke correct is.

De IR die figmascope exporteert draagt componentId op elk instantieknooppunt. De agent weet: deze vier knooppunten zijn allemaal ProductCard. Genereer het eenmalig, render het vier keer met verschillende props. Dat is de uitvoer die je wilt. Dat is de uitvoer die je niet kunt krijgen van pixels.

Stringidentiteit gaat verloren

Je hebt een "Doorgaan"-knop op drie verschillende schermen. Zijn die drie instanties dezelfde string, of heeft een ontwerper ze onafhankelijk geschreven? In een goed gestructureerd Figma-bestand verwijzen ze naar dezelfde stringsleutel. Dat betekent één i18n-invoer, één wijziging die overal doorwerkt.

In drie schermafbeeldingen: drie keer genereert het LLM een hardgecodeerde string. Als je een geïnternationaliseerde app bouwt, heb je nu drie strings te vinden en te vervangen in plaats van één om op te zoeken. Kleine zaak. Stapelt zich op door een echte codebase.

Waarom het LLM hallucineert: het herleidt elke keer de structuur

Het model heeft geen geheugen van vorige runs. Elke keer dat je dezelfde schermafbeelding plakt, reconstrueert het de structuur van nul. De reconstructie is probabilistisch — wat betekent dat dezelfde schermafbeelding + dezelfde prompt + hetzelfde model meetbaar verschillende uitvoer kan produceren bij verschillende runs. Hetzelfde ontwerp, andere code. Andere componentnamen, andere className-patronen, andere lay-outkeuzes.

Dit is geen modelfout. Het is het verwachte gedrag van een probabilistisch model bij onvoldoende beperkingen. De schermafbeelding biedt onvoldoende beperkingen. Het model vult de gaten. De gaten worden elke keer anders gevuld.

Je kunt dit gedeeltelijk omzeilen met langere, meer gedetailleerde prompts — "gebruik Tailwind, gebruik 8px-raster, gebruik deze componentnamen..." — maar dan heb je handmatig de structuur gespecificeerd die van het begin af aan in het ontwerpbestand had moeten zitten. Je doet het extractiewerk dat de tool zou moeten doen.

Het reproduceerbaarheidsprobleem

Teams die schermafbeeldingen gebruiken voor ontwerp-naar-code-overdracht lopen tegen hetzelfde probleem aan: de uitvoer is niet reproduceerbaar. Twee ontwikkelaars, dezelfde Figma-schermafbeelding, vragen Claude onafhankelijk — ze krijgen verschillende componentstructuren, verschillende className-patronen, verschillende nestingbeslissingen. Nu heb je twee codebases die er visueel hetzelfde uitzien maar architecturaal inconsistent zijn.

Dit maakt codereview moeilijker. Het maakt refactoring moeilijker. Het maakt naleving van het ontwerpsysteem onmogelijk te controleren. Je kunt niet de diff maken van "wat genereerde de agent uit dit ontwerp" als het antwoord elke run verandert.

Gestructureerde context lost reproduceerbaarheid op omdat het de invoer oplost. Een deterministische invoerbundel — dezelfde JSON met dezelfde knooppunt-ID's, componentnamen, tokenwaarden en ruimtelijke relaties — zal veel consistentere uitvoer produceren over runs, agents en ontwikkelaars heen. Niet perfect deterministisch: het model is nog steeds probabilistisch. Maar de variantie daalt dramatisch wanneer de structuur is gespecificeerd in plaats van afgeleid.

Wat een schermafbeelding je geeft vs. wat de IR je geeft

Neem een productkaart: afbeelding, titel, ondertitel, prijs, een "Toevoegen aan winkelwagen"-knop. Dit is wat elke invoer de agent geeft:

Schermafbeeldingsinvoer: Een rechthoek met een afbeelding bovenaan, twee regels tekst, een getal en een knop. Kleuren zijn afgeleid. Opvulling is geschat. Of dit een component of eenmalig is, is onbekend. De knoopvariant is afgeleid uit kleur. Het spatiëringssysteem is onbekend.

IR-invoer: Knooppuntsoort FRAME, naam ProductCard, component-ID die verwijst naar de componentdefinitie. Auto-lay-out met verticale richting, 16px-gap, 16px horizontale opvulling, 12px verticale opvulling. Kindknooppunten: IMAGE (vult breedte, vaste hoogte), TEXT met stringRef.key: "product.title" en stijl typography/heading.sm, TEXT met stringRef.key: "product.subtitle" en stijl typography/body.md, TEXT met vulling color/price, INSTANCE van Button/Primary/Medium. Achtergrondvulling color/surface.card. Randstraal radius/card.

De IR geeft de agent een specificatie. De schermafbeelding geeft het een suggestie.

Het kader: dit is het documentatieprobleem

We hebben dit exacte probleem tientallen jaren geleden voor broncode opgelost. Je geeft een agent geen schermafbeelding van je codebase en vraagt het om over architectuur te redeneren. Je geeft het de code — de gestructureerde, parseerbare, semantisch-betekenisvolle weergave. De abstracte syntaxboom, niet een afbeelding van de editor.

Figma-ontwerpen zijn gestructureerde gegevens. Ze hebben een goed gedefinieerde boomstructuur met getypte knooppunten en benoemde waarden. De Figma API stelt deze structuur volledig bloot. De enige reden dat de schermafbeeldingsworkflow aanhoudt, is dat het extraheren van de structuur en het opmaken ervan als context frictie heeft.

Die frictie verminderen is wat figmascope doet. Je plakt de Figma-URL, de export wordt uitgevoerd in je browser, en je krijgt een ZIP met gestructureerde context: CONTEXT.md, tokens.json, per-scherm IR, componentinventaris, stringsmanifest. Alles wat de agent nodig heeft, niets ervan afgeleid uit pixels.

Bewaar de schermafbeeldingen voor visuele bevestiging — de bundel bevat 2x PNG's voor precies dat. Gebruik de structuur voor al het andere. Zie het in de praktijk: Cursor-workflow, Claude Code-workflow of Aider-workflow.