الفرق بين ملف تصميم ومكتبة مكوّنات هو الهوية. ملف التصميم يحتوي أشكالاً. مكتبة المكوّنات تحتوي أجزاء مُسمَّاة وقابلة لإعادة الاستخدام بمعرّفات ثابتة. components/inventory.json هو إجابة figmascope على: "أي أجزاء في هذا التصميم مقصود أن تكون مكوّنات، وكيف ترتبط الحالات بها؟"
المخطط
components/inventory.json هو مصفوفة من الكائنات:
[
{
"id": "789:012",
"name": "PrimaryButton",
"type": "COMPONENT"
},
{
"id": "789:013",
"name": "SecondaryButton",
"type": "COMPONENT"
},
{
"id": "890:100",
"name": "Button",
"type": "COMPONENT_SET"
},
{
"id": "890:101",
"name": "Button/Primary/Default",
"type": "COMPONENT"
},
{
"id": "890:102",
"name": "Button/Primary/Pressed",
"type": "COMPONENT"
}
]
كل مدخل يحتوي ثلاثة حقول:
id: معرّف عقدة Figma، ثابت عبر الجلسات لنفس الملف.name: اسم المكوّن من Figma. للمتغيرات داخل COMPONENT_SET، يستخدم Figma ترميز الشرطة المائلة:Button/Primary/Default.type: إما"COMPONENT"(تعريف مكوّن واحد) أو"COMPONENT_SET"(مجموعة من المتغيرات).
هذا هو المخطط الكامل. بُسِّط عمداً.
كيف ترتبط الحالات
الرابط من الحالات إلى الجرد موجود في IR لكل شاشة. أي عقدة هي INSTANCE لمكوّن تحمل componentId وcomponentName:
// screens/home.json
{
"kind": "stack",
"id": "555:201",
"componentId": "789:012",
"componentName": "PrimaryButton",
"axis": "horizontal",
...
}
يطابق componentId معرّفاً في inventory.json. يطابق componentName الاسم. كلا الحقلين موجودان حتى لا يضطر الوكيل إلى تحميل inventory.json للحصول على الاسم — لكن إذا احتاج معرفة أن هذا المكوّن جزء من COMPONENT_SET، يتقاطع مع الجرد.
هكذا يعرف وكيل الكود أن عقدة الزر على الشاشة ليست تخطيطاً مخصصاً يجب إعادة إنتاجه بالتفصيل — بل هي حالة من PrimaryButton، ويجب استدعاء composable PrimaryButton() الموجود بدلاً من توليد كود جديد من التفاصيل الهيكلية في IR.
بدون هوية المكوّنات، يُولِّد الوكيل نفس الزر من الصفر في كل شاشة. بها، يستدعي الوكيل composable الموجود ويتخطى توليد الكود الهيكلي بالكامل. الفرق بين الحصول على 40 كتلة
Row { Text(...) Surface { ... } }أو 40 استدعاءPrimaryButton(...).
لماذا هذا مهم لأمان إعادة الهيكلة
أنظمة التصميم تُعاد هيكلتها. زر يحصل على شكل جديد وحشو جديد ولون مختلف. إذا كان كل الكود المُولَّد حرفياً هيكلياً، فإعادة الهيكلة تعني لمس كل شاشة تحتوي زراً. إذا استخدم الكود المُولَّد مرجع composable لـ PrimaryButton، فإعادة الهيكلة ملف واحد.
يجعل الجرد هذا ممكناً بإرساء العقد وقت التوليد: "هذه العقدة ليست تخطيطاً مخصصاً، بل هي حالة من مكوّن معروف." الوكيل الذي يحترم هذا العقد يُولِّد كوداً مُهيكَلاً بالفعل لإعادة هيكلة على مستوى المكوّنات.
هذه هي الميزة الهيكلية الرئيسية على التسليمات المبنية على لقطات الشاشة. لقطة شاشة زر هي بكسلات. ليس لها هوية. وكيل يعمل من لقطة شاشة سيُولِّد كوداً هيكلياً للزر في كل شاشة دائماً. وكيل يعمل من IR مع ربط الجرد يمكنه التعرف على الحالة واستخدام مرجع المكوّن بدلاً من ذلك.
COMPONENT مقابل COMPONENT_SET
نظام مكوّنات Figma له مستويان. COMPONENT هو تعريف واحد. COMPONENT_SET هو حاوية للمتغيرات — ما يسميه Figma "variants" (مثل زر بحالات Primary/Secondary/Destructive وDefault/Hovered/Pressed).
عملياً، حالة في شاشة ستُشير دائماً إلى COMPONENT (متغير محدد)، لا إلى COMPONENT_SET. COMPONENT_SET موجودة حتى يعرف الوكيل السطح الكامل للمتغيرات حين يحتاج تنفيذ آلة حالة المكوّن.
// Inventory entries for a Button set
{ "id": "890:100", "name": "Button", "type": "COMPONENT_SET" }
{ "id": "890:101", "name": "Button/Primary/Default", "type": "COMPONENT" }
{ "id": "890:102", "name": "Button/Primary/Pressed", "type": "COMPONENT" }
{ "id": "890:103", "name": "Button/Secondary/Default", "type": "COMPONENT" }
// Instance in screen IR references a specific variant
{ "componentId": "890:101", "componentName": "Button/Primary/Default" }
وكيل يُولِّد كود Compose لهذا يعرف: المكوّن هو Button بنمط Primary وحالة Default. يمكنه استنتاج أن توقيع الدالة يشمل على الأرجح معاملات style: ButtonStyle وstate: ButtonState، أو على الأقل استخدام Button/Primary/Default كمرجع دلالي لزر أساسي في حالته الافتراضية.
حد 300 مدخل
تحدّ figmascope inventory.json بـ 300 مدخل. ملفات Figma على نطاق واسع — خاصةً أنظمة التصميم ذات مكتبات المكوّنات الشاملة — يمكن أن تحتوي آلاف المكوّنات. إدراج جميعها في حزمة سياق مُرسَلة إلى LLM سيملأ نافذة السياق بتعريفات لن يستخدمها الوكيل للشاشات المُنفَّذة.
حين يُبلَغ الحد، يظهر حقل _truncated في الجرد:
[
{ "id": "...", "name": "...", "type": "COMPONENT" },
...
{ "_truncated": true, "totalCount": 847, "included": 300 }
]
يُخبرك totalCount بعدد المكوّنات الموجودة في الملف. يُخبرك included بعدد ما وصل إلى الجرد. الترتيب حسب أول ظهور في شجرة عقدة Figma، لذا المكوّنات المُشار إليها مبكراً في الوثيقة (عادةً الشاشات الأساسية) أكثر احتمالاً للإدراج.
إذا كنت تعمل على شاشات تستخدم مكوّنات مُعرَّفة في وقت متأخر من الوثيقة وليست في الجرد، فعقد IR لتلك الحالات لا تزال تحتوي componentId وcomponentName — معلومات الهوية محفوظة حتى حين لا يكون المكوّن مُدرَجاً في الجرد. يعرف الوكيل اسم المكوّن من IR حتى بدون مدخل الجرد.
ما لا يتضمّنه الجرد
الجرد هو قائمة هوية، لا مواصفة تنفيذ. يُخبرك أن مكوّناً باسم PrimaryButton بمعرّف 789:012 موجود. لا يُخبرك:
- ما هي الخصائص التي يقبلها المكوّن
- ما هي حالاته
- كيف المكوّن مُهيكَل داخلياً (ذلك في عقد IR التي هي حالات INSTANCE)
- ما هو ملف Figma المصدر للمكوّن (إذا كان من مكتبة مرتبطة)
هذه الفجوات مقصودة في v0.4. استنتاج خصائص المكوّن الكاملة من بنية IR ممكن لكنه سيُنتج نتائج غير موثوقة للمكوّنات ذات منطق المتغيرات المعقد. يمنح الجرد هوية ثابتة. تفاصيل التنفيذ تأتي من قاعدة الكود الموجودة لديك، والتي يملك الوكيل أيضاً إمكانية الوصول إليها.
سير العمل الصحيح: يرى الوكيل componentId: "789:012"، يبحث عنه في الجرد كـ PrimaryButton، ثم يبحث في قاعدة كود Kotlin الخاصة بك عن PrimaryButton لفهم توقيع الدالة الفعلي. الجرد هو الجسر بين التصميم والكود، لا بديل عن الكود. يمكنك تصدير جرد من أي ملف Figma على figmascope.dev.
هوية المكوّنات في IR هي ما يُفرِّق "توليد كود من هذا التصميم" عن "توليد كود يتناسب مع قاعدة كود موجودة." الأول لعبة. الثاني هو العمل الحقيقي.
مقارنة مع التسليم القائم على لقطات الشاشة فقط
وكيل يعمل من PNG لنفس الشاشة لا يملك هوية مكوّنات. يرى مستطيلاً أزرق مدوَّر الزوايا بنص في المنتصف ويُولِّد:
Box(
modifier = Modifier
.background(Color(0xFF7F5CFE), RoundedCornerShape(24.dp))
.padding(horizontal = 32.dp, vertical = 16.dp)
) {
Text("Start", color = Color.White, fontWeight = FontWeight.SemiBold)
}
وكيل يعمل من IR مع الجرد يرى componentId: "789:012"، يبحث عن PrimaryButton، يجد composable الموجود في قاعدة الكود، ويُولِّد:
PrimaryButton(
label = stringResource(R.string.start),
onClick = { /* TODO */ }
)
الإخراج الثاني يتكامل مع نظام تصميمك. الأول يُنشئ تباعداً. الجرد هو ما يجعل الإخراج الثاني ممكناً. لمزيد من المعلومات حول سبب فشل لقطات الشاشة كأدوات تسليم، انظر لماذا تفشل لقطات الشاشة.
IR لكل شاشة الذي يحتوي مراجع componentId مُغطَّى بالتفصيل في Per-Screen IR — Stack, Overlay, Absolute, Leaf. هيكل حزمة السياق الكاملة التي تحتوي كلا المصنوعتين مُقدَّمة عبر تشريح CONTEXT.md. للحصول على جرد المكوّنات الخاص بك، شغِّل figmascope على ملف Figma الخاص بك.