Figma का node tree rich लेकिन noisy है। Frame, Group, Component, Instance, Text, Rectangle, Ellipse, Vector — इनमें से प्रत्येक के दर्जनों optional fields हैं, जिनमें से कुछ एक-दूसरे से conflict करते हैं। Raw Figma API response पर directly काम करने वाला agent schema समझने में cognitive budget खर्च करता है बजाय code लिखने के।
figmascope tree को चार node kinds में normalize करता है: stack, overlay, absolute, और leaf। हर screens/*.json file में हर node इन चार में से एक है। कुछ और नहीं।
चार kinds
stack
Stack Figma Auto Layout वाला एक node है — layoutMode: "VERTICAL" या layoutMode: "HORIZONTAL"। इसके children axis के साथ flow-positioned हैं। Gaps और padding explicit हैं।
{
"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": [ ... ]
}
Jetpack Compose में Column (vertical axis) या Row (horizontal axis) के रूप में maps होता है। primaryAxisAlignItems और counterAxisAlignItems fields क्रमशः Arrangement और Alignment से map होते हैं। gap Arrangement.spacedBy() बन जाता है।
overlay
Overlay एक ऐसा node है जिसके children के भीतर absolute positions हैं। Figma इसे layoutMode: "NONE" वाले Frame के रूप में represent करता है जहां children के absoluteBoundingBox coordinates होते हैं। Overlay kind इसे agent को structure समझने के लिए raw coordinates reason करने की जरूरत के बिना capture करता है।
{
"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": { ... }
}
]
}
Compose में Box के रूप में maps होता है। Children Modifier.offset() या Modifier.align() का उपयोग करके positioned होते हैं।
absolute
Absolute node एक wrapper है जो parent overlay के भीतर specific (x, y) offset पर एक single child carry करता है। यह एक thin structural node है — यह position को content के साथ conflate किए बिना Figma से spatial relationship preserve करने के लिए exist करता है।
{
"kind": "absolute",
"offset": { "x": 24, "y": 140 },
"child": {
"kind": "leaf",
"name": "BadgeLabel",
"text": "NEW",
"stringRef": "badge.new",
...
}
}
Compose में, यह typically Modifier.offset(x.dp, y.dp) के साथ Box का child बन जाता है। अगर range में spacing tokens exist करते हैं तो offset values token substitution के candidates हैं।
leaf
Leaf एक terminal node है — कोई children नहीं। इसमें styling (fills, strokes, corner radius) है और optionally text content है। Text leaves में एक text field (literal string) और एक stringRef field (strings.json से i18n resource key) होती है।
{
"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
}
Text content के लिए Compose में Text() composable के रूप में, या fill type के आधार पर non-text leaves के लिए Surface, Box, या Image के रूप में maps होता है।
चार kinds किसी भी UI framework के compositional model से one-to-one map होते हैं। Stacks flow layouts हैं। Overlays z-positioned containers हैं। Absolutes spatial metadata carry करते हैं। Leaves content हैं। बस इतना। Figma node taxonomy में 12+ node types हैं — IR इसे चार तक reduce करता है।
Kind कैसे determine होती है
Classification logic:
- अगर
layoutMode"VERTICAL"या"HORIZONTAL"है →stack - अगर
layoutMode"NONE"है और node में children हैं →overlay(childrenabsoluteके रूप में wrapped) - अगर कोई node किसी overlay का direct child है और position carry करता है →
absolute - अगर node में कोई children नहीं है और यह absolute wrapper नहीं है →
leaf
_meta.json में layout-mode-none-inferred warning तब fire होती है जब layoutMode: "NONE" वाले Frame में non-trivially overlapping bounding boxes के children हों। figmascope इसे overlay treat करता है, लेकिन inference note करता है क्योंकि practice में कुछ layoutMode: "NONE" frames बस single child के लिए containers होते हैं और simplify किए जा सकते हैं। Warning agent को decide करने देती है कि इसे कैसे handle करना है।
absoluteBoundingBox — यह क्यों preserve किया जाता है
IR में हर node Figma से अपना absoluteBoundingBox retain करता है, भले ही parent एक stack हो (जहां layout के लिए absolute positions theoretically irrelevant हैं):
{
"kind": "stack",
"absoluteBoundingBox": { "x": 0, "y": 88, "width": 390, "height": 756 },
...
}
यह उन agents के लिए है जिन्हें उन nodes के बीच spatial relationships reason करने की जरूरत है जो direct parent-child relationship share नहीं करते। Tree के अलग-अलग branches से दो elements को overlap करने के लिए उनके absolute positions जानने होते हैं, केवल relative offsets नहीं। Coordinate system Figma का canvas है — top-left origin, y increasing downward।
यह PNG cross-reference में भी help करता है। _meta.json में एक pngCount field है और exported PNGs screen slug से named हैं। अगर आप IR को screenshot से compare कर रहे हैं, absoluteBoundingBox आपको image के भीतर specific nodes locate करने देता है।
Container kinds पर Fills और strokes
एक common confusion point: stack और overlay nodes में fills हो सकती हैं, न केवल leaves में। Background color वाला column अभी भी stack है — बस उसमें fills array भी है। figmascope इसे preserve करता है:
{
"kind": "stack",
"axis": "vertical",
"fills": [{ "type": "SOLID", "color": "#f6f2ea" }],
"cornerRadius": 12,
...
}
Compose में, यह typically Surface या Card के अंदर Column बन जाता है, fill color और corner radius container पर applied होकर। IR fill को children में collapse नहीं करता — यह इसे उस node पर रखता है जहां Figma ने इसे set किया।
Container kinds पर gradient fills background-gradient-not-supported:<name> warning emit करते हैं। Node अभी भी IR में अपने अन्य fields के साथ present है। Agent को fill को TODO treat करना चाहिए और CONTEXT.md scope notes के अनुसार या तो solid color से approximate करना चाहिए या custom drawing call generate करनी चाहिए।
stringRef + text relationship
Text leaf nodes दोनों carry करते हैं:
text: Figma से literal string value (जैसे"Speed Test")stringRef:strings.jsonसे resource key (जैसे"speed.test")
अगर किसी text node का content collision या filter (numeric-only, empty, too short) के कारण strings.json से drop हो गया, तो leaf में अभी भी text है लेकिन stringRef absent होगा। उस case में agent को literal पर fall back करना चाहिए। Full collision handling logic के लिए strings.json देखें।
जब दोनों present हों, CONTEXT.md constraint कहता है stringRef use करें। text field agent reasoning के लिए है (ताकि वह जान सके strings.json खोले बिना string क्या कहती है) और fallback के रूप में।
IR में component instances
जब कोई Figma node किसी component का INSTANCE है, IR node दो additional fields carry करता है:
{
"kind": "stack",
"componentId": "789:012",
"componentName": "PrimaryButton",
...
}
यह components/inventory.json से link करता है। Agent जानता है कि यह node एक bespoke layout की बजाय PrimaryButton का instance है, और duplicate code generate करने की बजाय existing component को reference करना चाहिए। इसका full coverage Component Inventory में है।
Real screen उदाहरण
Header, content column, और floating button के साथ एक screen का simplified लेकिन structurally accurate उदाहरण:
{
"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" }]
}
}
]
}
}
इससे agent correctly content के लिए absolute-positioned Column और bottom पर absolute-positioned PrimaryButton component के साथ Compose Box screen generate कर सकता है। हर layout decision IR से बिना guessing के derivable है।
इस structure में spacing और color values पर tokens कैसे apply होते हैं, इसके लिए tokens.json Explained देखें। Cursor या Claude Code के साथ इस IR को use करने के full agent workflow के लिए, Jetpack Compose from Figma देखें।