Strom uzlů Figmy je bohatý, ale hlučný. Frame, Group, Component, Instance, Text, Rectangle, Ellipse, Vector — každý má desítky volitelných polí, z nichž některá si navzájem odporují. Agent pracující přímo s raw odpovědí Figma API tráví kontextový rozpočet pochopením schématu namísto psaní kódu.
figmascope normalizuje strom do čtyř typů uzlů: stack, overlay, absolute a leaf. Každý uzel v každém souboru screens/*.json je jedním z těchto čtyř. Nic jiného.
Čtyři typy
stack
Stack je uzel s Figma Auto Layout — layoutMode: "VERTICAL" nebo layoutMode: "HORIZONTAL". Jeho děti jsou pozicovány podél osy toku. Mezery a vycpávky jsou explicitní.
{
"kind": "stack",
"id": "123:456",
"name": "ContentColumn",
"axis": "vertical",
"gap": 16,
"paddingTop": 24,
"paddingBottom": 24,
"paddingLeft": 20,
"paddingRight": 20,
"primaryAxisAlignItems": "SPACE_BETWEEN",
"counterAxisAlignItems": "CENTER",
"width": 390,
"height": 844,
"fills": [{ "type": "SOLID", "color": "#1a1a2e" }],
"children": [ ... ]
}
Mapuje se na Jetpack Compose jako Column (vertikální osa) nebo Row (horizontální osa). Pole primaryAxisAlignItems a counterAxisAlignItems se mapují na Arrangement a Alignment. gap se stane Arrangement.spacedBy().
overlay
Overlay je uzel, jehož děti mají absolutní pozice uvnitř něj. Figma to reprezentuje jako Frame s layoutMode: "NONE", kde děti mají souřadnice absoluteBoundingBox. Typ overlay toto zachycuje, aniž by agent musel uvažovat o raw souřadnicích pro pochopení struktury.
{
"kind": "overlay",
"id": "123:789",
"name": "CardOverlay",
"width": 358,
"height": 200,
"fills": [{ "type": "SOLID", "color": "#ffffff" }],
"children": [
{
"kind": "absolute",
"offset": { "x": 16, "y": 16 },
"child": { ... }
}
]
}
Mapuje se na Compose jako Box. Děti jsou pozicovány pomocí Modifier.offset() nebo Modifier.align() podle toho, jak se jejich pozice vztahují k hranicím rodiče.
absolute
Uzel absolute je obal, který nese jediné dítě na specifickém offsetu (x, y) uvnitř svého nadřazeného overlay. Je to tenký strukturální uzel — existuje pro zachování prostorového vztahu z Figmy bez sloučení pozice s obsahem.
{
"kind": "absolute",
"offset": { "x": 24, "y": 140 },
"child": {
"kind": "leaf",
"name": "BadgeLabel",
"text": "NEW",
"stringRef": "badge.new",
...
}
}
V Compose se to typicky stane dítětem Box s Modifier.offset(x.dp, y.dp). Hodnoty offsetu jsou kandidáty pro náhradu tokenem, pokud existují tokeny mezer v rozsahu.
leaf
Leaf je terminální uzel — bez dětí. Má styling (výplně, tahy, poloměr rohů) a volitelně textový obsah. Textové listy mají pole text (doslovný řetězec) a pole stringRef (klíč i18n zdroje z strings.json).
{
"kind": "leaf",
"id": "123:101",
"name": "SpeedLabel",
"text": "Speed Test",
"stringRef": "speed.test",
"fontSize": 18,
"fontWeight": 600,
"fills": [{ "type": "SOLID", "color": "#ffffff" }],
"width": 160,
"height": 28
}
Mapuje se na Compose jako composable Text() pro textový obsah, nebo jako Surface, Box nebo Image pro netextové listy v závislosti na typu výplně.
Čtyři typy se mapují 1:1 na kompoziční model jakéhokoli UI frameworku. Stacky jsou flow layouty. Overlaye jsou z-pozicované kontejnery. Absolutní uzly nesou prostorová metadata. Listy jsou obsah. To je vše. Taxonomie uzlů Figmy má 12+ typů uzlů — IR ho redukuje na čtyři.
Jak je typ určen
Logika klasifikace:
- Pokud je
layoutMode"VERTICAL"nebo"HORIZONTAL"→stack - Pokud je
layoutMode"NONE"a uzel má děti →overlay(děti zabaleny jakoabsolute) - Pokud je uzel přímým dítětem overlay a nese pozici →
absolute - Pokud uzel nemá děti a není obalem absolute →
leaf
Varování layout-mode-none-inferred v _meta.json se aktivuje, když má Frame s layoutMode: "NONE" děti s netriviálně překrývajícími se ohraničujícími rámečky. figmascope ho považuje za overlay, ale poznamenává odvození, protože některé rámce layoutMode: "NONE" jsou v praxi jen kontejnery pro jediné dítě (nulové překrývání) a mohly by být zjednodušeny. Varování umožňuje agentovi rozhodnout, jak to zpracovat.
absoluteBoundingBox — proč je zachován
Každý uzel v IR si zachovává svůj absoluteBoundingBox z Figmy, i když nadřazený uzel je stack (kde jsou absolutní pozice teoreticky irelevantní pro rozvržení):
{
"kind": "stack",
"absoluteBoundingBox": { "x": 0, "y": 88, "width": 390, "height": 756 },
...
}
Toto je pro agenty, kteří potřebují uvažovat o prostorových vztazích napříč uzly, které nesdílejí přímý vztah rodič-dítě. Překrývání dvou prvků z různých větví stromu vyžaduje znalost jejich absolutních pozic, nikoli jen relativních offsetů. Souřadnicový systém je plátno Figmy — počátek vlevo nahoře, y roste směrem dolů.
Pomáhá to také s křížovým odkazem na PNG. _meta.json obsahuje pole pngCount a exportované PNG jsou pojmenovány podle slugu obrazovky. Pokud porovnáváte IR se screenshotem, absoluteBoundingBox umožňuje lokalizovat konkrétní uzly v obrázku. Chcete-li to vidět na vlastním designu, exportujte balíček z figmascope.dev.
Výplně a tahy na typech kontejnerů
Běžný bod zmatení: uzly stack a overlay mohou mít výplně, nejen listy. Sloupec s barvou pozadí je stále stack — jen má také pole fills. figmascope to zachovává:
{
"kind": "stack",
"axis": "vertical",
"fills": [{ "type": "SOLID", "color": "#f6f2ea" }],
"cornerRadius": 12,
...
}
V Compose se to typicky stane Column uvnitř Surface nebo Card s barvou výplně a poloměrem rohu aplikovaným na kontejner. IR nesloučí výplň do dětí — zachová ji na uzlu, kde ji Figma nastavila.
Přechodové výplně na typech kontejnerů vydají varování background-gradient-not-supported:<name>. Uzel je stále přítomen v IR s ostatními poli nedotčenými. Agent by měl výplň považovat za TODO a buď ji přibližně nahradit plnou barvou nebo vygenerovat vlastní volání kreslení, podle poznámek o rozsahu CONTEXT.md.
Vztah stringRef + text
Textové listy nesou oboje:
text: doslovná hodnota řetězce z Figmy (např."Speed Test")stringRef: klíč zdroje zstrings.json(např."speed.test")
Pokud byl obsah textového uzlu vypuštěn ze strings.json kvůli kolizi nebo filtru (pouze číselný, prázdný, příliš krátký), list stále má text, ale stringRef bude chybět. Agent by měl v takovém případě použít doslovný text jako záložní. Viz strings.json pro úplnou logiku zpracování kolizí.
Pokud jsou přítomny oba, omezení CONTEXT.md říká použít stringRef. Pole text je pro uvažování agenta (aby věděl, co řetězec říká, bez otevření strings.json) a jako záložní.
Instance komponent v IR
Když je uzel Figmy INSTANCE komponenty, uzel IR nese dvě další pole:
{
"kind": "stack",
"componentId": "789:012",
"componentName": "PrimaryButton",
...
}
Toto odkazuje zpět na components/inventory.json. Agent ví, že tento uzel je instancí PrimaryButton spíše než ad-hoc rozvržením, a měl by odkazovat na existující komponentu namísto generování duplicitního kódu. Úplné pokrytí je v Inventáři komponent.
Příklad skutečné obrazovky
Zjednodušený, ale strukturálně přesný příklad obrazovky se záhlavím, sloupcem obsahu a plovoucím tlačítkem:
{
"screen": "home",
"root": {
"kind": "overlay",
"name": "HomeScreen",
"width": 390,
"height": 844,
"fills": [{ "type": "SOLID", "color": "#0d0d1a" }],
"children": [
{
"kind": "absolute",
"offset": { "x": 0, "y": 0 },
"child": {
"kind": "stack",
"name": "ContentArea",
"axis": "vertical",
"gap": 24,
"paddingTop": 56,
"paddingLeft": 20,
"paddingRight": 20,
"children": [
{
"kind": "leaf",
"name": "Title",
"text": "Speed Test",
"stringRef": "speed.test",
"fontSize": 28,
"fontWeight": 700
}
]
}
},
{
"kind": "absolute",
"offset": { "x": 111, "y": 752 },
"child": {
"kind": "stack",
"name": "StartButton",
"componentId": "321:654",
"componentName": "PrimaryButton",
"axis": "horizontal",
"gap": 8,
"paddingTop": 16,
"paddingBottom": 16,
"paddingLeft": 32,
"paddingRight": 32,
"cornerRadius": 24,
"fills": [{ "type": "SOLID", "color": "#7f5cfe" }]
}
}
]
}
}
Z tohoto může agent správně vygenerovat Compose obrazovku Box s absolutně-pozicovaným Column pro obsah a absolutně-pozicovanou komponentou PrimaryButton na spodku. Každé rozhodnutí o rozvržení je odvoditelné z IR bez hádání.
Jak se tokeny aplikují na hodnoty mezer a barev v této struktuře, viz tokens.json Vysvětleno. Pro úplný pracovní postup agenta s tímto IR pomocí Cursor nebo Claude Code viz Jetpack Compose z Figmy. Vyzkoušejte to sami vložením URL Figmy do figmascope.