figmascope का default export target Jetpack Compose है। यह arbitrary नहीं है — Compose का layout model (Column, Row, Box, Modifier) IR node kinds (stack, overlay, absolute, leaf) से closely map होता है। Figma में एक vertical stack Compose में एक Column है। Translation mechanical है, जो इसे agent-driven codegen के लिए well-suited बनाता है।
यह walkthrough IR-to-Compose mapping को detail में cover करता है, एक real JSON fragment और corresponding Composable दिखाता है, और token mapping layer explain करता है।
Compose default target क्यों है
तीन structural कारण:
- Auto-layout ↔ Column/Row। Figma के auto-layout frames (modern Figma designs का बड़ा हिस्सा)
kind: "stack"nodes के रूप में export होते हैं। Stack nodes मेंaxisproperty होती है —verticalColumnसे map होता है,horizontalRowसे। यह कोई interpretation step के बिना 1:1 mapping है। - Spacing tokens ↔ dp values। Compose सभी layout dimensions के लिए
Dpuse करता है।tokens.jsonमें token values unitless integers हैं (जैसेspacing.16 = 16) जो directly16.dpसे map होते हैं। कोई conversion नहीं, कोई scaling नहीं। - Color tokens ↔ Color composable।
tokens.jsonमें Figma hex values एक single transformation के साथColor(0xFFrrggbb)से map होते हैं। Token key आपके theme में एक semantic variable name बन जाती है।
IR node kinds और उनके Compose mappings
| IR kind | Properties | Compose primitive |
|---|---|---|
stack | axis: "vertical" | Column |
stack | axis: "horizontal" | Row |
overlay | layered children | Box |
absolute | x, y, width, height | Box with Modifier.offset(x.dp, y.dp) |
leaf | type: "text" | Text with TextStyle |
leaf | type: "rectangle" with fill | Box(Modifier.background(Color(...))) |
सभी node kinds एक spacing property (children के बीच gap) और एक padding object (top/right/bottom/left) carry कर सकते हैं। दोनों token keys reference करते हैं।
Token mapping विस्तार में
एक tokens.json file इस तरह दिखती है:
{
"spacing": {
"4": 4, "8": 8, "12": 12, "16": 16,
"20": 20, "24": 24, "32": 32, "48": 48
},
"radius": {
"4": 4, "8": 8, "12": 12, "16": 16, "full": 9999
},
"color": {
"7f5cfe": "#7F5CFE",
"1a1a2e": "#1A1A2E",
"f6f2ea": "#F6F2EA",
"ffffff": "#FFFFFF",
"e53935": "#E53935"
},
"typography": {
"heading.24": { "size": 24, "weight": 700, "lineHeight": 1.2 },
"body.14": { "size": 14, "weight": 400, "lineHeight": 1.5 },
"label.12": { "size": 12, "weight": 500, "lineHeight": 1.4 }
}
}
Mapping rules:
spacing.16→16.dpradius.12→RoundedCornerShape(12.dp)color.7f5cfe→Color(0xFF7F5CFE)(full alpha के लिए0xFFprepend करें)typography.heading.24→TextStyle(fontSize = 24.sp, fontWeight = FontWeight.Bold, lineHeight = 28.8.sp)
Token keys जानबूझकर opaque हैं (color के लिए hex strings, spacing के लिए numeric strings) ताकि वे model को किसी particular naming convention की ओर bias न करें। आपका Compose theme उन्हें semantic names पर alias कर सकता है — colorPrimary, spacingMd — IR से independently।
एक real उदाहरण: home screen JSON से Composable तक
यहां एक simplified home screen IR है। एक header leaf और एक card list के साथ vertical stack:
{
"name": "home",
"kind": "stack",
"axis": "vertical",
"spacing": "spacing.24",
"padding": { "top": "spacing.16", "right": "spacing.16",
"bottom": "spacing.16", "left": "spacing.16" },
"fill": "color.f6f2ea",
"children": [
{
"kind": "leaf",
"type": "text",
"stringRef": "home.title",
"typography": "typography.heading.24",
"fill": "color.1a1a2e"
},
{
"kind": "stack",
"axis": "vertical",
"spacing": "spacing.12",
"children": [
{
"kind": "overlay",
"radius": "radius.12",
"fill": "color.ffffff",
"padding": { "top": "spacing.16", "right": "spacing.16",
"bottom": "spacing.16", "left": "spacing.16" },
"children": [
{
"kind": "leaf",
"type": "text",
"stringRef": "home.card.label",
"typography": "typography.label.12",
"fill": "color.7f5cfe"
}
]
}
]
}
]
}
Corresponding Composable — एक agent को इस IR से क्या produce करना चाहिए:
@Composable
fun HomeScreen() {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFFF6F2EA))
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(24.dp)
) {
Text(
text = stringResource(R.string.home_title),
style = TextStyle(
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
lineHeight = 28.8.sp,
color = Color(0xFF1A1A2E)
)
)
Column(
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Box(
modifier = Modifier
.clip(RoundedCornerShape(12.dp))
.background(Color(0xFFFFFFFF))
.padding(16.dp)
) {
Text(
text = stringResource(R.string.home_card_label),
style = TextStyle(
fontSize = 12.sp,
fontWeight = FontWeight.Medium,
lineHeight = 16.8.sp,
color = Color(0xFF7F5CFE)
)
)
}
}
}
}
Composable की हर value IR में एक token key तक trace होती है। कुछ भी hardcoded नहीं है — 16.dp spacing.16 से आता है, 24.dp spacing.24 से, Color(0xFF7F5CFE) color.7f5cfe से।
String refs — stringResource mapping
IR में हर text node dot-notation key के साथ एक stringRef carry करता है। strings.json file keys को display values और fallbacks से map करती है:
{
"home.title": { "value": "Good morning", "fallback": "Good morning" },
"home.card.label": { "value": "Today's summary", "fallback": "Summary" }
}
Dot-notation dots को underscores से replace करके Android string resource IDs पर map होता है: home.title → R.string.home_title। fallback field वह है जिसे आप literal string के रूप में hardcode करते हैं अगर resource अभी strings.xml में exist नहीं करता:
text = stringResource(R.string.home_title, "Good morning")
Agent को हमेशा fallback field use करने के लिए कहें — empty string नहीं — ताकि strings.xml populate होने से पहले development के दौरान screen readable हो।
Absolute positioning
kind: "absolute" वाले Nodes Figma coordinates directly use करते हैं। ये overlapping elements या specific positions पर anchored elements वाले designs में appear होते हैं। Compose mapping parent के रूप में Box और children पर Modifier.offset use करता है:
// IR: { "kind": "absolute", "x": 24, "y": 80, "width": 120, "height": 40 }
Box(modifier = Modifier.fillMaxSize()) {
Box(
modifier = Modifier
.offset(x = 24.dp, y = 80.dp)
.size(width = 120.dp, height = 40.dp)
) {
// children
}
}
Absolute positioning well-structured Figma files में uncommon है (अधिकांश modern files auto-layout use करते हैं)। जब आप इसे देखें, check करें कि design intent truly absolute है या designer ने बस auto-layout constraints apply नहीं किए — IR intent infer नहीं कर सकता।
ईमानदार gaps
Bundle common case को अच्छी तरह cover करता है। कुछ चीज़ें जो यह नहीं करता:
- Gradient fills। IR gradient encounter होने पर एक warning export करता है। Node का background fill omit हो जाता है। एक
// TODO: gradientछोड़ें और manually implement करें। - Complex effects। Drop shadows और blurs IR में represented नहीं हैं। वे present होने पर
_meta.jsonwarnings में appear होते हैं। - Vector icons। IR icon nodes के लिए path data नहीं, एक reference ID store करता है। आपको icon को एक actual drawable या compose icon में separately resolve करना होगा।
- Nested components। IR instance nodes पर
componentIdinclude करता है।components/inventory.jsonIDs को names से map करता है। Component separately implement करें और parent Composable में नाम से reference करें।
ये gaps explicit हैं — वे _meta.json warnings और CONTEXT.md में दिखते हैं। Agent उनके through silently guess नहीं करता।
main figmascope app से context bundle export करें, फिर इसे Claude Code या Cursor के साथ IR से directly Composables implement करने के लिए use करें। कोई screenshot guessing नहीं, कोई hardcoded values नहीं।