@atezer/figma-mcp-bridge 1.7.29 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +403 -0
- package/README.md +4 -3
- package/agents/_orchestrator-protocol.md +185 -0
- package/agents/ds-auditor.md +73 -22
- package/agents/screen-builder.md +60 -22
- package/agents/token-syncer.md +63 -19
- package/dist/core/code-warnings.d.ts +38 -0
- package/dist/core/code-warnings.d.ts.map +1 -0
- package/dist/core/code-warnings.js +191 -0
- package/dist/core/code-warnings.js.map +1 -0
- package/dist/core/device-presets.d.ts +49 -0
- package/dist/core/device-presets.d.ts.map +1 -0
- package/dist/core/device-presets.js +141 -0
- package/dist/core/device-presets.js.map +1 -0
- package/dist/core/instructions.d.ts +4 -2
- package/dist/core/instructions.d.ts.map +1 -1
- package/dist/core/instructions.js +239 -29
- package/dist/core/instructions.js.map +1 -1
- package/dist/core/plugin-bridge-connector.d.ts +32 -0
- package/dist/core/plugin-bridge-connector.d.ts.map +1 -1
- package/dist/core/plugin-bridge-connector.js +31 -2
- package/dist/core/plugin-bridge-connector.js.map +1 -1
- package/dist/core/plugin-bridge-server.d.ts +8 -0
- package/dist/core/plugin-bridge-server.d.ts.map +1 -1
- package/dist/core/plugin-bridge-server.js +27 -2
- package/dist/core/plugin-bridge-server.js.map +1 -1
- package/dist/core/response-guard.d.ts +23 -0
- package/dist/core/response-guard.d.ts.map +1 -1
- package/dist/core/response-guard.js +113 -0
- package/dist/core/response-guard.js.map +1 -1
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.d.ts.map +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/version.js.map +1 -1
- package/dist/local-plugin-only.d.ts.map +1 -1
- package/dist/local-plugin-only.js +504 -85
- package/dist/local-plugin-only.js.map +1 -1
- package/f-mcp-plugin/code.js +514 -29
- package/f-mcp-plugin/ui.html +62 -6
- package/package.json +1 -1
- package/skills/SKILL_INDEX.md +13 -1
- package/skills/apply-figma-design-system/SKILL.md +37 -0
- package/skills/audit-figma-design-system/SKILL.md +38 -0
- package/skills/code-design-mapper/SKILL.md +37 -0
- package/skills/design-token-pipeline/SKILL.md +44 -0
- package/skills/figma-canvas-ops/SKILL.md +200 -240
- package/skills/fmcp-ds-audit-orchestrator/SKILL.md +205 -0
- package/skills/fmcp-intent-router/SKILL.md +574 -0
- package/skills/fmcp-project-rules/SKILL.md +9 -5
- package/skills/fmcp-screen-orchestrator/SKILL.md +166 -0
- package/skills/fmcp-screen-recipes/SKILL.md +528 -0
- package/skills/fmcp-token-sync-orchestrator/SKILL.md +198 -0
- package/skills/generate-figma-library/SKILL.md +38 -0
- package/skills/generate-figma-screen/SKILL.md +382 -19
- package/skills/implement-design/SKILL.md +32 -0
- package/skills/inspiration-intake/SKILL.md +220 -0
- package/skills/visual-qa-compare/SKILL.md +33 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fmcp-screen-orchestrator
|
|
3
|
+
description: DS-compliant Figma ekran üretimi için platform-agnostic orkestratör skill. DS GATE, Fast Path routing, intake mode, error recovery.
|
|
4
|
+
metadata:
|
|
5
|
+
mcp-server: user-figma-mcp-bridge
|
|
6
|
+
version: 3.0.0
|
|
7
|
+
priority: 95
|
|
8
|
+
phase: orchestrator
|
|
9
|
+
personas:
|
|
10
|
+
- designer
|
|
11
|
+
- uidev
|
|
12
|
+
token_budget: condensed-first
|
|
13
|
+
required_inputs:
|
|
14
|
+
- name: intake_mode
|
|
15
|
+
type: "enum: text_only | figma_benchmark | image_uploaded | image_url | no_idea"
|
|
16
|
+
- name: task_description
|
|
17
|
+
type: string
|
|
18
|
+
- name: source_ref
|
|
19
|
+
type: "string | null"
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# FMCP Screen Orchestrator
|
|
23
|
+
|
|
24
|
+
## Essentials
|
|
25
|
+
|
|
26
|
+
### Ortak Protokol
|
|
27
|
+
|
|
28
|
+
1. **Skill Registry** açık — tahmin yasak, sezgisel Read() yasak
|
|
29
|
+
2. **Intent Routing** — belirsiz → Read fmcp-intent-router
|
|
30
|
+
3. **Cheap-First** — `depth=1`, `verbosity="summary"`, screenshot sadece onay kapısında, ≤5 execute
|
|
31
|
+
4. **Cache-First** — `.claude/design-systems/<lib>/` cache'i API'den ÖNCE oku
|
|
32
|
+
5. **Onay Kapıları** — approach / destructive / evolution / 3. audit fail
|
|
33
|
+
6. **Self-Audit** — `figma_validate_screen(nodeId, minScore=80)` ZORUNLU
|
|
34
|
+
7. **Skill Evolution** — iki aşamalı onay + `# DRAFT — PENDING APPROVAL` banner
|
|
35
|
+
8. **Türkçe Raporlama** — metrik bloğu zorunlu
|
|
36
|
+
|
|
37
|
+
### Skill Registry
|
|
38
|
+
|
|
39
|
+
| Skill | Trigger | Common case? |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| `fmcp-intent-router` | Belirsiz intent | Sadece belirsizlikte |
|
|
42
|
+
| `inspiration-intake` | image/figma_benchmark | Sadece bu modlarda |
|
|
43
|
+
| `generate-figma-screen` | Net screen creation | HER ZAMAN (ana motor) |
|
|
44
|
+
| `figma-canvas-ops` | Her figma_execute öncesi | HER ZAMAN (pre-flight) |
|
|
45
|
+
| `fmcp-screen-recipes` | Fast Path match | Sadece Fast Path'te |
|
|
46
|
+
| `apply-figma-design-system` | Mevcut ekranı DS'ye hizala | Sadece remediation |
|
|
47
|
+
|
|
48
|
+
### Adım 0 — DS GATE (MUTLAK İLK KAPI)
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
1. Read(".claude/design-systems/active-ds.md")
|
|
52
|
+
2. ✅ Aktif → Library Name not al, devam
|
|
53
|
+
❌ Seçilmedi veya dosya yok → DUR, kullanıcıya "Hangi DS?" sor, hiçbir figma_* çağırma
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
DS belirsizken `figma_get_file_data`, `figma_search_assets` çağırmak YASAK. İstisnalar: `figma_get_status()`, filesystem read, Claude vision.
|
|
57
|
+
|
|
58
|
+
### Adım 0.5 — Fast Path Check
|
|
59
|
+
|
|
60
|
+
5 koşulun HEPSİ TRUE → `fmcp-screen-recipes` Read, recipe uygula:
|
|
61
|
+
1. Tek ekran (multi-screen değil)
|
|
62
|
+
2. Standart tip (login/payment/profile/list/detail/form/onboarding/dashboard/settings)
|
|
63
|
+
3. DS aktif
|
|
64
|
+
4. Platform belli (explicit keyword VEYA önceki intent'ten saved). Yoksa DUR, kullanıcıya sor. Default varsayım YASAK.
|
|
65
|
+
5. Animation/prototype YOK
|
|
66
|
+
|
|
67
|
+
Biri bile FALSE → Karar Akışı'na geç. Recipe kırılırsa da fallback.
|
|
68
|
+
|
|
69
|
+
### Karar Akışı
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
1. Intent net mi? EVET → sub-skill / HAYIR → Read fmcp-intent-router
|
|
73
|
+
2. image/figma_benchmark → Read inspiration-intake → structural_intent JSON
|
|
74
|
+
3. figma_execute yazacak mı? EVET → Read figma-canvas-ops
|
|
75
|
+
4. Ana motor → Read generate-figma-screen
|
|
76
|
+
5. build-from-scratch vs clone-to-device
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### DS Fallback Chain
|
|
80
|
+
|
|
81
|
+
1. **DS component instance** — en çok tercih
|
|
82
|
+
2. **DS primitive variant** — yakın variant + setProperties
|
|
83
|
+
3. **Token-bound primitive** — createFrame + tüm fill/padding/radius variable'a bağlı → meşru, ihlal DEĞİL
|
|
84
|
+
4. **Hardcoded shape** → GERÇEK İHLAL, DUR, kullanıcıya bildir
|
|
85
|
+
|
|
86
|
+
### Resmi Figma MCP Yasağı
|
|
87
|
+
|
|
88
|
+
`Figma:*` prefix'li tool'lar (mcp.figma.com) ASLA çağrılmaz. Sadece `figma_*` (figma-mcp-bridge) kullan. `figma_search_assets` boş → Rule 24 fallback (manuel instance scan), `Figma:search_design_system`'e düşME.
|
|
89
|
+
|
|
90
|
+
### Filesystem MCP
|
|
91
|
+
|
|
92
|
+
Skill Read için: `mcp__fmcp-filesystem__read_text_file(path="<absolute_path>/skills/<skill>/SKILL.md")`. Claude Desktop'ta prompt'ta absolute path belirtilmeli.
|
|
93
|
+
|
|
94
|
+
### Self-Audit Gate + Verification
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
figma_validate_screen(nodeId=<wrapper_id>, minScore=80)
|
|
98
|
+
```
|
|
99
|
+
- `<80` → SEVERE violation'ları oku, düzelt, yeniden validate
|
|
100
|
+
- 3 deneme fail → kullanıcıdan rebuild onayı al
|
|
101
|
+
|
|
102
|
+
Teslim öncesi kontrol: validate ≥80, ham shape yok, tüm değerler token'a bağlı, auto-layout eksiksiz, Türkçe rapor + metrikler.
|
|
103
|
+
|
|
104
|
+
### Rapor Formatı
|
|
105
|
+
|
|
106
|
+
```markdown
|
|
107
|
+
## 🎨 Ekran Üretimi — <ekran_adı>
|
|
108
|
+
**Mod:** <intake_mode> | **DS:** <active-ds> | **Yaklaşım:** <approach>
|
|
109
|
+
### Sonuç
|
|
110
|
+
<Figma node link>
|
|
111
|
+
📊 Metrikler: skill'ler, API çağrı, cache hit/miss, execute sayısı, validate score
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Advanced — Only Load If Needed
|
|
117
|
+
|
|
118
|
+
Bu bölüm: karmaşık intake, 3. audit fail, skill evolution, non-obvious error durumlarında okunur.
|
|
119
|
+
|
|
120
|
+
### Inspiration Handoff Contract
|
|
121
|
+
|
|
122
|
+
`inspiration-intake` → `structural_intent_json` üretir (layout_direction, sections, hierarchy_notes, spacing_intent). `generate-figma-screen` ise `reference_benchmark` olarak nodeId bekler. Handoff prompt-level'da yapılır:
|
|
123
|
+
1. structural_intent_json'u orchestrator context'te tut
|
|
124
|
+
2. generate-figma-screen'e: `reference_benchmark: "none"`, structural hints'i prompt context olarak ekle
|
|
125
|
+
3. Hints'ten sadece layout/hiyerarşi al, DEĞER ASLA (renk/font/spacing DS'den gelir)
|
|
126
|
+
|
|
127
|
+
### Intake Mode Router
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
text_only → (belirsizse intent-router) → generate-figma-screen
|
|
131
|
+
figma_benchmark → inspiration-intake → generate-figma-screen (build-from-scratch)
|
|
132
|
+
image_uploaded → inspiration-intake (vision) → generate-figma-screen
|
|
133
|
+
image_url → inspiration-intake → WebFetch dener → başarısızsa kullanıcıdan upload iste
|
|
134
|
+
no_idea → Kullanıcıya sor: ekran türü, kitle, içerik blokları, estetik → generate-figma-screen
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Inspiration Only Rule
|
|
138
|
+
|
|
139
|
+
Benchmark/görselden DEĞER alma YASAK. Sadece NİYET: layout yönü, hiyerarşi, bölüm sırası, spacing intent. Tüm değerler DS'ten.
|
|
140
|
+
|
|
141
|
+
### Step-by-Step Mode (≤5 execute)
|
|
142
|
+
|
|
143
|
+
1. **Skeleton** — wrapper + section frame'leri → screenshot → onay
|
|
144
|
+
2. **Content** — DS instance yerleşimi → screenshot → onay
|
|
145
|
+
3. **Polish** — spacing, states, edge cases → son screenshot → audit
|
|
146
|
+
|
|
147
|
+
### Error Recovery
|
|
148
|
+
|
|
149
|
+
| Hata | Aksiyon |
|
|
150
|
+
|---|---|
|
|
151
|
+
| Plugin kopması | `figma_get_status()` kontrol, gelmezse bildir |
|
|
152
|
+
| Tool timeout | Scope daralt, 1 retry, sonra raporla |
|
|
153
|
+
| SEVERE violation | Oku, düzelt, audit döngüsüne sok |
|
|
154
|
+
| Truncated response | Küçük scope ile yeniden iste |
|
|
155
|
+
| 3. validate fail | Kullanıcıya raporla, rebuild öner |
|
|
156
|
+
|
|
157
|
+
### Skill Evolution
|
|
158
|
+
|
|
159
|
+
1. Gap onayı: kullanıcıya "yeni skill mi, mevcut edit mi?" sor
|
|
160
|
+
2. İçerik onayı: yeni skill `# DRAFT — PENDING APPROVAL` banner ile, edit ise unified diff göster, onay → uygula
|
|
161
|
+
|
|
162
|
+
### Platform Notes
|
|
163
|
+
|
|
164
|
+
- **Claude Code:** Sub-agent isolation, cache: `.claude/design-systems/`
|
|
165
|
+
- **Cursor:** `.cursor/rules/` referans, sub-agent yok, `.cursor/mcp.json` gerekli
|
|
166
|
+
- **Claude Desktop:** Project knowledge'a yükle, ilk prompt'ta explicit referans ver
|
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fmcp-screen-recipes
|
|
3
|
+
description: Fast path cookbook — standart ekran tipleri (login/payment/profile/list/detail/form/onboarding/dashboard/settings) için 5 mega-adımlı recipe. Max 15 op/execute, cache-first discovery, her adımda Türkçe micro-report.
|
|
4
|
+
metadata:
|
|
5
|
+
mcp-server: user-figma-mcp-bridge
|
|
6
|
+
version: 3.0.0
|
|
7
|
+
priority: 96
|
|
8
|
+
phase: fast-path
|
|
9
|
+
personas:
|
|
10
|
+
- designer
|
|
11
|
+
- uidev
|
|
12
|
+
token_budget: condensed-first
|
|
13
|
+
required_inputs:
|
|
14
|
+
- name: screen_type
|
|
15
|
+
type: "enum: login | payment | profile | list | detail | form | onboarding | dashboard | settings"
|
|
16
|
+
- name: platform
|
|
17
|
+
type: "enum: mobile | tablet | desktop | web"
|
|
18
|
+
- name: device_preset
|
|
19
|
+
type: string
|
|
20
|
+
- name: variants
|
|
21
|
+
type: "array: [light] | [light, dark]"
|
|
22
|
+
- name: active_ds
|
|
23
|
+
type: string
|
|
24
|
+
outputs:
|
|
25
|
+
- name: light_frame_id
|
|
26
|
+
type: string
|
|
27
|
+
- name: dark_frame_id
|
|
28
|
+
type: "string | null"
|
|
29
|
+
- name: validate_scores
|
|
30
|
+
type: "{ light: number, dark: number | null }"
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
# FMCP Screen Recipes — Fast Path Cookbook
|
|
34
|
+
|
|
35
|
+
## Ne Zaman Kullanılır
|
|
36
|
+
|
|
37
|
+
**Fast Path DEVREYE GİRER** (hepsi TRUE olmalı):
|
|
38
|
+
- ✅ Tek ekran üretimi
|
|
39
|
+
- ✅ Standart ekran tipi: 9 recipe'ten biri match ediyor
|
|
40
|
+
- ✅ DS tanımlı: `active-ds.md` Status: ✅ Aktif
|
|
41
|
+
- ✅ Platform belli
|
|
42
|
+
- ✅ Custom animation / prototype YOK
|
|
43
|
+
|
|
44
|
+
**Devreye GİRMEZ:** Multi-screen flow, custom layout, animation, explicit generate-figma-screen talebi, DS GATE geçilmemişse.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 5 Mega-Adımlı Akış
|
|
49
|
+
|
|
50
|
+
Max **15 op/execute**. Her mega-adım sonrası tek satır Türkçe micro-report.
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
M1: Pre-Flight Discovery + Token + Text Style (1 execute, ~15 op)
|
|
54
|
+
M2: Frame + Structure + Modes (1 execute, ~12-14 op)
|
|
55
|
+
M3: Component Placement (toplu, 3-4/execute) (2-3 execute, ~12-15 op each)
|
|
56
|
+
M4: Dark Variant (1 execute, ~4 op)
|
|
57
|
+
M5: Validate + Final Report (1-2 validate çağrısı)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Toplam execute:** ~6-8. **Hedef süre:** ~10 dk.
|
|
61
|
+
|
|
62
|
+
### 3 MUTLAK KURAL
|
|
63
|
+
|
|
64
|
+
**KURAL 1 — Fill Bind Zorunlu (frame + text dahil):**
|
|
65
|
+
```js
|
|
66
|
+
const paint = { type: 'SOLID', color: { r: 1, g: 1, b: 1 } };
|
|
67
|
+
const bound = figma.variables.setBoundVariableForPaint(paint, 'color', dsColorVar);
|
|
68
|
+
node.fills = [bound];
|
|
69
|
+
```
|
|
70
|
+
Fill panel'de variable icon 🎨 GÖRÜNMELI. Hardcoded hex YASAK. Frame fill + text fill + primitive dahil TÜM node'lar.
|
|
71
|
+
|
|
72
|
+
**KURAL 2 — Variant Seçim: DEFAULT Koru:**
|
|
73
|
+
- `setProperties` ile SADECE recipe'de explicit belirtilen property'leri set et
|
|
74
|
+
- Diğer TÜM property'leri DEFAULT bırak
|
|
75
|
+
- `Product` → main (default), Boolean kontroller → recipe'de explicit yoksa DEFAULT
|
|
76
|
+
|
|
77
|
+
**KURAL 3 — Token Bind, Alias Resolve ETME:**
|
|
78
|
+
`setBoundVariable(property, importedVariable)` ile bind et. Figma runtime alias chain'i otomatik çözer. `valuesByMode` okuma, alias traversal YASAK (timeout riski).
|
|
79
|
+
|
|
80
|
+
### Mega-Adım Mapping
|
|
81
|
+
|
|
82
|
+
Aşağıdaki eski adımlar REFERANS amaçlıdır. AYRI AYRI execute ETME — mega-adım tablosunu takip et:
|
|
83
|
+
- **M1:** Adım 1 (validation) + 1.5 (discovery) + 1.6 (text style) → TEK execute
|
|
84
|
+
- **M2:** Adım 2 (frame) + 4b (mode) + 5.5 (content body) → TEK execute
|
|
85
|
+
- **M3:** Adım 6 (discovery) + 7 (placement) → 2-3 execute
|
|
86
|
+
- **M4:** Adım 8 (dark) → TEK execute
|
|
87
|
+
- **M5:** Adım 9 (validate) → 1-2 validate call
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### Adım 1 — Pre-Flight Check
|
|
92
|
+
|
|
93
|
+
Hiçbir figma_execute çağırma. Doğrula: active-ds.md ✅, screen_type geçerli, platform + device_preset geçerli, variants ≥1.
|
|
94
|
+
|
|
95
|
+
**Micro-report:** `✅ Pre-flight: screen_type=<X>, platform=<Y>, device=<Z>, variants=<V>`
|
|
96
|
+
|
|
97
|
+
### Adım 1.5 — Unified Pre-Flight Discovery
|
|
98
|
+
|
|
99
|
+
**Cache-First (v3.0+):** Önce `.claude/design-systems/sui/tokens.md` oku. Cache varsa ve <7 gün → token discovery ATLA, cache'ten kullan. Yoksa aşağıdaki execute'ları çalıştır, sonra cache'i güncelle.
|
|
100
|
+
|
|
101
|
+
Token name matching: SUI nested path formatı (`"Spacing/spacing-100"`). `endsWith` match kullan:
|
|
102
|
+
```js
|
|
103
|
+
vars.find(v => v.name.endsWith("/" + suffix) || v.name === suffix)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### Execute 1 — Collection & Mode Discovery (7 op)
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
const colls = await figma.teamLibrary.getAvailableLibraryVariableCollectionsAsync();
|
|
110
|
+
function findColl(keywords) {
|
|
111
|
+
return colls.find(c => {
|
|
112
|
+
const n = c.name.toLowerCase().trim();
|
|
113
|
+
return keywords.some(kw => n.includes(kw));
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const sizeColl = findColl(["semantic size", "semantic sizes", "size"]);
|
|
117
|
+
const colorsColl = findColl(["semantic color", "s theme"]);
|
|
118
|
+
const result = { availableColls: colls.map(c => ({name: c.name, key: c.key})), spacingTokenKeys: {}, collectionInfo: { colors: null, size: null }, surfaceKey: null };
|
|
119
|
+
|
|
120
|
+
if (sizeColl) {
|
|
121
|
+
const sizeVars = await figma.teamLibrary.getVariablesInLibraryCollectionAsync(sizeColl.key);
|
|
122
|
+
const suffixes = ["spacing-none","spacing-050","spacing-075","spacing-100","spacing-125","spacing-150","spacing-200"];
|
|
123
|
+
for (const s of suffixes) {
|
|
124
|
+
const f = sizeVars.find(v => v.name.endsWith("/"+s) || v.name === s);
|
|
125
|
+
if (f) result.spacingTokenKeys[s] = f.key;
|
|
126
|
+
}
|
|
127
|
+
if (sizeVars.length > 0) {
|
|
128
|
+
const first = await figma.variables.importVariableByKeyAsync(sizeVars[0].key);
|
|
129
|
+
const coll = await figma.variables.getVariableCollectionByIdAsync(first.variableCollectionId);
|
|
130
|
+
result.collectionInfo.size = { collId: coll.id, modes: coll.modes.map(m => ({name: m.name, modeId: m.modeId})) };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (colorsColl) {
|
|
134
|
+
const colorsVars = await figma.teamLibrary.getVariablesInLibraryCollectionAsync(colorsColl.key);
|
|
135
|
+
const bgVar = colorsVars.find(v => v.name.toLowerCase().includes("background") && v.name.toLowerCase().includes("level-0"));
|
|
136
|
+
if (bgVar) result.surfaceKey = bgVar.key;
|
|
137
|
+
if (colorsVars.length > 0) {
|
|
138
|
+
const first = await figma.variables.importVariableByKeyAsync(colorsVars[0].key);
|
|
139
|
+
const coll = await figma.variables.getVariableCollectionByIdAsync(first.variableCollectionId);
|
|
140
|
+
result.collectionInfo.colors = { collId: coll.id, modes: coll.modes.map(m => ({name: m.name, modeId: m.modeId})) };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
#### Execute 2 — Critical Token Import (7 op)
|
|
147
|
+
|
|
148
|
+
```js
|
|
149
|
+
const tokenKeyMap = {};
|
|
150
|
+
const spacingKeys = { /* Execute 1'den gelen spacingTokenKeys */ };
|
|
151
|
+
for (const [suffix, key] of Object.entries(spacingKeys)) {
|
|
152
|
+
try {
|
|
153
|
+
const imported = await figma.variables.importVariableByKeyAsync(key);
|
|
154
|
+
tokenKeyMap[suffix] = imported.id;
|
|
155
|
+
} catch(e) {}
|
|
156
|
+
}
|
|
157
|
+
return { tokenKeyMap };
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Micro-report:** `✅ Pre-Flight Discovery: <N> collection, <M> token imported, surface=<found/missing>`
|
|
161
|
+
|
|
162
|
+
### Adım 1.6 — Text Style Resolution
|
|
163
|
+
|
|
164
|
+
Dosyadaki mevcut text style'ları tara, role mapping üret. `importStyleByKeyAsync` ÇAĞIRMA — direkt `setTextStyleIdAsync(roleMap[role].id)` kullan.
|
|
165
|
+
|
|
166
|
+
```js
|
|
167
|
+
const allTexts = figma.currentPage.findAll(n => n.type === "TEXT");
|
|
168
|
+
const uniqueStyleIds = new Set();
|
|
169
|
+
for (const t of allTexts) { if (t.textStyleId && typeof t.textStyleId === 'string') uniqueStyleIds.add(t.textStyleId); }
|
|
170
|
+
|
|
171
|
+
const styleMap = {};
|
|
172
|
+
for (const id of uniqueStyleIds) {
|
|
173
|
+
try { const style = await figma.getStyleByIdAsync(id); if (style) styleMap[style.id] = { id: style.id, name: style.name, fontSize: style.fontSize || null }; } catch(e) {}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const roleKeywords = {
|
|
177
|
+
display: ["display","hero","amount","title-xl"], title: ["section-title","title","heading"],
|
|
178
|
+
subtitle: ["subtitle","body-semibold","body-bold"], body: ["body-medium","body-regular","body"],
|
|
179
|
+
caption: ["small","caption","footnote"], button: ["button"]
|
|
180
|
+
};
|
|
181
|
+
function findStyle(kws) { for (const kw of kws) { const m = Object.values(styleMap).find(s => (s.name||"").toLowerCase().includes(kw.toLowerCase())); if (m) return m; } return null; }
|
|
182
|
+
const roleMap = {};
|
|
183
|
+
for (const [role, kws] of Object.entries(roleKeywords)) { const m = findStyle(kws); if (m) roleMap[role] = { id: m.id, name: m.name, fontSize: m.fontSize }; }
|
|
184
|
+
if (!roleMap.display) {
|
|
185
|
+
const sorted = Object.values(styleMap).filter(s => s.fontSize).sort((a,b) => b.fontSize - a.fontSize);
|
|
186
|
+
if (sorted.length > 0) roleMap.display = { id: sorted[0].id, name: sorted[0].name, fontSize: sorted[0].fontSize };
|
|
187
|
+
}
|
|
188
|
+
return { totalStyles: Object.keys(styleMap).length, styleMap, roleMap };
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Micro-report:** `✅ Text Style: <N> style, <M> role eşleşti`
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### Adım 2 — Wrapper Frame + Background (Edge-to-Edge)
|
|
196
|
+
|
|
197
|
+
Ana frame: device preset boyutu, auto-layout VERTICAL, padding=0, gap=0, background DS variable'a bağlı.
|
|
198
|
+
|
|
199
|
+
**Edge-to-Edge yapı:**
|
|
200
|
+
```
|
|
201
|
+
Ana Frame (padding:0, gap:0, VERTICAL)
|
|
202
|
+
├── NavigationTopBar (FILL — edge-to-edge)
|
|
203
|
+
├── Content Body (FILL both, padding:spacing-100, gap:spacing-075)
|
|
204
|
+
│ └── Recipe component'leri
|
|
205
|
+
└── BottomNavBar (FILL — edge-to-edge, varsa)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
```js
|
|
209
|
+
const frame = figma.createFrame();
|
|
210
|
+
frame.name = "<Screen Name> — <Device Preset>";
|
|
211
|
+
frame.resize(<width>, <height>);
|
|
212
|
+
frame.layoutMode = "VERTICAL";
|
|
213
|
+
frame.primaryAxisSizingMode = "FIXED";
|
|
214
|
+
frame.counterAxisSizingMode = "FIXED";
|
|
215
|
+
frame.paddingTop = 0; frame.paddingBottom = 0; frame.paddingLeft = 0; frame.paddingRight = 0;
|
|
216
|
+
frame.itemSpacing = 0;
|
|
217
|
+
if (surfaceKey) {
|
|
218
|
+
const bgVar = await figma.variables.importVariableByKeyAsync(surfaceKey);
|
|
219
|
+
const paint = { type: 'SOLID', color: { r: 1, g: 1, b: 1 } };
|
|
220
|
+
frame.fills = [figma.variables.setBoundVariableForPaint(paint, 'color', bgVar)];
|
|
221
|
+
}
|
|
222
|
+
return { frameId: frame.id };
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Micro-report:** `✅ Frame: <device> (<w>×<h>), edge-to-edge, background bound`
|
|
226
|
+
|
|
227
|
+
### Adım 3 — ⏭️ DEVRE DIŞI
|
|
228
|
+
|
|
229
|
+
Breakpoint bind frame boyutunu bozuyor (375 vs 402). Device preset boyutu korunur.
|
|
230
|
+
|
|
231
|
+
### Adım 4 — Theme + Size Mode Setup
|
|
232
|
+
|
|
233
|
+
Collection/mode bilgisi Adım 1.5'ten gelir (ayrı execute yok).
|
|
234
|
+
|
|
235
|
+
**Adım 4b — Mode apply:**
|
|
236
|
+
```js
|
|
237
|
+
const frame = await figma.getNodeByIdAsync(frameId);
|
|
238
|
+
if (collectionInfo.colors) {
|
|
239
|
+
const coll = await figma.variables.getVariableCollectionByIdAsync(collectionInfo.colors.collId);
|
|
240
|
+
const lightMode = collectionInfo.colors.modes.find(m => m.name.toLowerCase().includes("light"));
|
|
241
|
+
if (lightMode) frame.setExplicitVariableModeForCollection(coll, lightMode.modeId);
|
|
242
|
+
}
|
|
243
|
+
if (collectionInfo.size) {
|
|
244
|
+
const coll = await figma.variables.getVariableCollectionByIdAsync(collectionInfo.size.collId);
|
|
245
|
+
const kws = { mobile:["mobil","mobile"], tablet:["tablet"], desktop:["web","desktop"], web:["web","desktop"] };
|
|
246
|
+
const sizeMode = collectionInfo.size.modes.find(m => (kws[platform]||["mobil"]).some(k => m.name.toLowerCase().includes(k)));
|
|
247
|
+
if (sizeMode) frame.setExplicitVariableModeForCollection(coll, sizeMode.modeId);
|
|
248
|
+
}
|
|
249
|
+
return { modesApplied: true };
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Micro-report:** `✅ Theme: Light, Size: <modeName>`
|
|
253
|
+
|
|
254
|
+
### Adım 5.5 — Content Body Wrapper
|
|
255
|
+
|
|
256
|
+
```js
|
|
257
|
+
const parentFrame = await figma.getNodeByIdAsync(frameId);
|
|
258
|
+
const contentBody = figma.createFrame();
|
|
259
|
+
contentBody.name = "Content Body";
|
|
260
|
+
contentBody.layoutMode = "VERTICAL";
|
|
261
|
+
parentFrame.appendChild(contentBody); // ÖNCE (Rule 11)
|
|
262
|
+
contentBody.layoutSizingHorizontal = "FILL"; // SONRA
|
|
263
|
+
contentBody.layoutSizingVertical = "FILL";
|
|
264
|
+
const paddingVar = await figma.variables.importVariableByKeyAsync(spacing100Key);
|
|
265
|
+
const gapVar = await figma.variables.importVariableByKeyAsync(spacing075Key);
|
|
266
|
+
contentBody.setBoundVariable("paddingLeft", paddingVar);
|
|
267
|
+
contentBody.setBoundVariable("paddingRight", paddingVar);
|
|
268
|
+
contentBody.setBoundVariable("paddingTop", paddingVar);
|
|
269
|
+
contentBody.setBoundVariable("paddingBottom", paddingVar);
|
|
270
|
+
contentBody.setBoundVariable("itemSpacing", gapVar);
|
|
271
|
+
contentBody.fills = [];
|
|
272
|
+
return { contentBodyId: contentBody.id };
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Micro-report:** `✅ Content Body: FILL both, padding=spacing-100, gap=spacing-075`
|
|
276
|
+
|
|
277
|
+
### Adım 6 — Component Discovery
|
|
278
|
+
|
|
279
|
+
**Cache-First (v3.0+):** Önce `.claude/design-systems/sui/components.md` oku. Cache varsa → `figma_search_assets` ATLA, direkt `importComponentByKeyAsync` kullan. Yoksa: `figma_search_assets(query="<keywords>")` + Rule 24 fallback.
|
|
280
|
+
|
|
281
|
+
**Micro-report:** `✅ Component keşfi: <N> bulundu, <M> eksik`
|
|
282
|
+
|
|
283
|
+
### Adım 7 — Recipe Component Placement
|
|
284
|
+
|
|
285
|
+
3-4 component TEK execute'ta. Parent routing: edge-to-edge (NavigationTopBar, BottomNavBar) → Ana Frame, diğer her şey → Content Body.
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
const edgeNames = /^(navigation|nav|top|bottom|status|tabbar|tab_bar)/i;
|
|
289
|
+
const parentId = edgeNames.test(spec.name) ? frameId : contentBodyId;
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**Text Style Binding:** `await textNode.setTextStyleIdAsync(roleMap[role].id)` — DİREKT bağla, `importStyleByKeyAsync` ÇAĞIRMA, `fontSize` set ETME.
|
|
293
|
+
|
|
294
|
+
**Text rolü mapping:** display→Amount/Hero, title→Section Header, subtitle→Card Title, body→Body text, caption→Small/Info.
|
|
295
|
+
|
|
296
|
+
### Adım 8 — Dark Variant
|
|
297
|
+
|
|
298
|
+
```js
|
|
299
|
+
const lightFrame = await figma.getNodeByIdAsync(lightFrameId);
|
|
300
|
+
const darkFrame = lightFrame.clone();
|
|
301
|
+
figma.currentPage.appendChild(darkFrame);
|
|
302
|
+
darkFrame.x = lightFrame.x + lightFrame.width + 80;
|
|
303
|
+
darkFrame.name = lightFrame.name + " — Dark";
|
|
304
|
+
const coll = await figma.variables.getVariableCollectionByIdAsync(semColorsCollId);
|
|
305
|
+
darkFrame.setExplicitVariableModeForCollection(coll, darkModeId);
|
|
306
|
+
return { darkFrameId: darkFrame.id };
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Adım 9 — Validation + Final Report
|
|
310
|
+
|
|
311
|
+
`figma_validate_screen(frameId, minScore=80)` her frame için. 3 deneme fail → kullanıcıya sor.
|
|
312
|
+
|
|
313
|
+
**Son Rapor:** Screen type, DS, device, variants, frame ID'leri, validate skorları, kullanılan component listesi, primitive fallback listesi, token binding sayıları, toplam execute, süre.
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Device Presets Lookup Table
|
|
318
|
+
|
|
319
|
+
### Mobile
|
|
320
|
+
|
|
321
|
+
| Device | W | H | Keywords |
|
|
322
|
+
|---|---|---|---|
|
|
323
|
+
| iPhone 17 | 402 | 874 | mobile, iphone, ios |
|
|
324
|
+
| iPhone 16 & 17 Pro | 402 | 874 | iphone pro |
|
|
325
|
+
| iPhone 16 | 393 | 852 | iphone 16 |
|
|
326
|
+
| iPhone 16 Pro Max | 440 | 956 | pro max |
|
|
327
|
+
| iPhone 16 Plus | 430 | 932 | iphone plus |
|
|
328
|
+
| iPhone Air | 420 | 912 | iphone air |
|
|
329
|
+
| iPhone 13 & 14 | 390 | 844 | iphone 13, iphone 14 |
|
|
330
|
+
| Android Compact | 412 | 917 | android |
|
|
331
|
+
| Android Medium | 700 | 840 | android tablet |
|
|
332
|
+
|
|
333
|
+
**Default:** mobile → iPhone 17, android → Android Compact.
|
|
334
|
+
|
|
335
|
+
### Tablet
|
|
336
|
+
|
|
337
|
+
| Device | W | H |
|
|
338
|
+
|---|---|---|
|
|
339
|
+
| iPad Pro 11" | 834 | 1194 |
|
|
340
|
+
| iPad Pro 12.9" | 1024 | 1366 |
|
|
341
|
+
|
|
342
|
+
**Default:** tablet → iPad Pro 11".
|
|
343
|
+
|
|
344
|
+
### Desktop / Web
|
|
345
|
+
|
|
346
|
+
| Device | W | H |
|
|
347
|
+
|---|---|---|
|
|
348
|
+
| Desktop | 1440 | 900 |
|
|
349
|
+
| Desktop HD | 1920 | 1080 |
|
|
350
|
+
| MacBook Pro 14" | 1512 | 982 |
|
|
351
|
+
| MacBook Pro 16" | 1728 | 1117 |
|
|
352
|
+
|
|
353
|
+
**Default:** desktop/web → Desktop 1440×900.
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## 9 Screen Type Recipes
|
|
358
|
+
|
|
359
|
+
Her recipe = component listesi + yerleşim sırası + search keyword'leri + setProperties.
|
|
360
|
+
|
|
361
|
+
### Recipe 1: Login
|
|
362
|
+
**Trigger:** login, giriş, oturum aç, sign in
|
|
363
|
+
|
|
364
|
+
1. **AppBar** — `["navigation top", "appbar"]`
|
|
365
|
+
**setProperties:** `{ "Subtitle": false, "Right Controls": false }`
|
|
366
|
+
2. **Logo** — `["logo", "brand"]`
|
|
367
|
+
3. **Welcome Text** (H1) — `["heading", "display"]`
|
|
368
|
+
4. **Subtitle Text** — `["body medium", "text body"]`
|
|
369
|
+
5. **Email Input** — `["text field", "input", "email"]`
|
|
370
|
+
6. **Password Input** — `["password", "text field password"]`
|
|
371
|
+
7. **Primary Button** ("Giriş Yap") — `["button primary"]`
|
|
372
|
+
**setProperties:** `{ "Value": "Giriş Yap" }`
|
|
373
|
+
8. **Forgot Password Link** — `["link", "text button"]`
|
|
374
|
+
9. **Divider** — `["divider"]`
|
|
375
|
+
10. **Register Link** — `["text button", "link"]`
|
|
376
|
+
|
|
377
|
+
### Recipe 2: Payment
|
|
378
|
+
**Trigger:** ödeme, payment, checkout, satın al
|
|
379
|
+
|
|
380
|
+
1. **NavigationTopBar** — `["navigation top", "appbar"]`
|
|
381
|
+
**setProperties:** `{ "Title Text": "Ödeme", "Right Controls": false, "Subtitle": false, "Product": "main" }`
|
|
382
|
+
2. **Amount Display** — `["display large", "hero text"]`
|
|
383
|
+
3. **Currency Label** — `["body small", "caption"]`
|
|
384
|
+
4. **Section Header** — `["section header", "subtitle"]`
|
|
385
|
+
5. **Payment Method Cards** (×3) — `["card payment", "list item"]`
|
|
386
|
+
6. **Add New Method Button** — `["button secondary"]`
|
|
387
|
+
7. **Divider** — `["divider"]`
|
|
388
|
+
8. **CTA Button** — `["button primary large"]`
|
|
389
|
+
**setProperties:** `{ "Value": "Ödemeyi Tamamla" }`
|
|
390
|
+
9. **Security Info** — `["text small", "caption"]`
|
|
391
|
+
|
|
392
|
+
### Recipe 3: Profile
|
|
393
|
+
**Trigger:** profil, profile, hesap, account
|
|
394
|
+
|
|
395
|
+
1. **AppBar** — `["navigation top"]`
|
|
396
|
+
**setProperties:** `{ "Title Text": "Profilim" }`
|
|
397
|
+
2. **Avatar** — `["avatar large", "profile picture"]`
|
|
398
|
+
3. **User Name Text** — `["heading", "display medium"]`
|
|
399
|
+
4. **User Email Text** — `["body", "text secondary"]`
|
|
400
|
+
5. **Divider** — `["divider"]`
|
|
401
|
+
6. **Menu List Items** (×4) — `["list item", "menu row"]`
|
|
402
|
+
7. **Destructive Button** ("Çıkış Yap") — `["button destructive"]`
|
|
403
|
+
**setProperties:** `{ "Value": "Çıkış Yap" }`
|
|
404
|
+
|
|
405
|
+
### Recipe 4: List
|
|
406
|
+
**Trigger:** liste, list, arama, search, katalog
|
|
407
|
+
|
|
408
|
+
1. **AppBar** — `["navigation top"]`
|
|
409
|
+
**setProperties:** `{ "Title Text": "Arama" }`
|
|
410
|
+
2. **Search Bar** — `["search", "search bar"]`
|
|
411
|
+
3. **Filter Chips Row** — `["chip", "filter chip"]`
|
|
412
|
+
4. **Card List Items** (×N) — `["card", "list card"]`
|
|
413
|
+
5. **Pagination** — `["pagination"]`
|
|
414
|
+
6. **FAB** (opsiyonel) — `["fab", "floating button"]`
|
|
415
|
+
|
|
416
|
+
### Recipe 5: Detail
|
|
417
|
+
**Trigger:** detay, detail, ürün detay, product
|
|
418
|
+
|
|
419
|
+
1. **AppBar** — `["navigation top"]`
|
|
420
|
+
**setProperties:** `{ "Right Controls": true }`
|
|
421
|
+
2. **Hero Image** — `["image large", "hero"]`
|
|
422
|
+
3. **Title Text** — `["heading large", "display"]`
|
|
423
|
+
4. **Price + Rating Row** — `["price", "rating"]`
|
|
424
|
+
5. **Description Text** — `["body", "text body"]`
|
|
425
|
+
6. **Stats Section** — `["stat", "info row"]`
|
|
426
|
+
7. **CTA Button** — `["button primary"]`
|
|
427
|
+
**setProperties:** `{ "Value": "Sepete Ekle" }`
|
|
428
|
+
|
|
429
|
+
### Recipe 6: Form
|
|
430
|
+
**Trigger:** form, başvuru, kayıt, application
|
|
431
|
+
|
|
432
|
+
1. **AppBar** — `["navigation top"]`
|
|
433
|
+
**setProperties:** `{ "Title Text": "Başvuru" }`
|
|
434
|
+
2. **Progress Indicator** — `["stepper", "progress"]`
|
|
435
|
+
3. **Field Group 1** (3-4 input) — `["text field", "input"]`
|
|
436
|
+
4. **Field Group 2** — `["select", "dropdown", "date picker"]`
|
|
437
|
+
5. **Checkbox / Terms** — `["checkbox", "agreement"]`
|
|
438
|
+
6. **Submit Button** — `["button primary"]`
|
|
439
|
+
**setProperties:** `{ "Value": "Gönder" }`
|
|
440
|
+
|
|
441
|
+
### Recipe 7: Onboarding
|
|
442
|
+
**Trigger:** onboarding, tanıtım, karşılama, welcome
|
|
443
|
+
|
|
444
|
+
1. **Hero Image** — `["illustration", "image hero"]`
|
|
445
|
+
2. **Title Text** — `["display", "heading large"]`
|
|
446
|
+
3. **Subtitle Text** — `["body", "text secondary"]`
|
|
447
|
+
4. **Pagination Dots** — `["dots", "page indicator"]`
|
|
448
|
+
5. **Primary Button** — `["button primary"]`
|
|
449
|
+
**setProperties:** `{ "Value": "Başla" }`
|
|
450
|
+
6. **Skip Link** — `["text button", "link"]`
|
|
451
|
+
|
|
452
|
+
### Recipe 8: Dashboard
|
|
453
|
+
**Trigger:** dashboard, özet, summary, panel
|
|
454
|
+
|
|
455
|
+
1. **AppBar** — `["navigation top"]`
|
|
456
|
+
**setProperties:** `{ "Title Text": "Özet" }`
|
|
457
|
+
2. **Stats Cards** (×4) — `["stat card", "metric card"]`
|
|
458
|
+
3. **Chart** — `["chart", "graph"]`
|
|
459
|
+
4. **Section Header** — `["section header"]`
|
|
460
|
+
5. **Activity List Items** (×N) — `["list item", "activity row"]`
|
|
461
|
+
|
|
462
|
+
### Recipe 9: Settings
|
|
463
|
+
**Trigger:** ayarlar, settings, tercihler
|
|
464
|
+
|
|
465
|
+
1. **AppBar** — `["navigation top"]`
|
|
466
|
+
**setProperties:** `{ "Title Text": "Ayarlar" }`
|
|
467
|
+
2. **Section Headers** — `["section header"]`
|
|
468
|
+
3. **Toggle Rows** — `["list item toggle", "setting row"]`
|
|
469
|
+
4. **Info Row** — `["list item", "nav row"]`
|
|
470
|
+
5. **Destructive Button** — `["button destructive"]`
|
|
471
|
+
**setProperties:** `{ "Value": "Hesabı Sil" }`
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Primitive Fallback Pattern
|
|
476
|
+
|
|
477
|
+
Component bulunamazsa token-bound primitive ile inşa et. Tüm visual properties variable'a bağlı olmalı:
|
|
478
|
+
```js
|
|
479
|
+
const card = figma.createFrame();
|
|
480
|
+
card.name = "... (primitive fallback)";
|
|
481
|
+
card.layoutMode = "HORIZONTAL";
|
|
482
|
+
card.setBoundVariable("cornerRadius", radiusSmVar);
|
|
483
|
+
card.setBoundVariable("paddingLeft", spacingMdVar);
|
|
484
|
+
// ... diğer padding/gap bind'ları
|
|
485
|
+
const paint = { type: 'SOLID', color: { r: 1, g: 1, b: 1 } };
|
|
486
|
+
card.fills = [figma.variables.setBoundVariableForPaint(paint, 'color', surfaceVar)];
|
|
487
|
+
parent.appendChild(card); // ÖNCE
|
|
488
|
+
card.layoutSizingHorizontal = "FILL"; // SONRA (Rule 11)
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
## Chunking Kuralları
|
|
494
|
+
|
|
495
|
+
- Max **15 atomic op / figma_execute**
|
|
496
|
+
- **3-4 component TEK execute'ta** yerleştir
|
|
497
|
+
- Timeout: `15000` ms yeterli (15 op ≈ 200-300ms)
|
|
498
|
+
- Her component için AYRI execute YASAK
|
|
499
|
+
|
|
500
|
+
## Error Recovery
|
|
501
|
+
|
|
502
|
+
| Hata | Aksiyon |
|
|
503
|
+
|---|---|
|
|
504
|
+
| DS GATE yok | Fast Path iptal, orchestrator'a dön |
|
|
505
|
+
| Device bulunamadı | Default kullan (iPhone 17 / Desktop 1440) |
|
|
506
|
+
| Colors collection yok | Light-only, dark skip |
|
|
507
|
+
| Component 0 sonuç | Primitive fallback |
|
|
508
|
+
| Execute timeout | Op sayısını azalt, böl |
|
|
509
|
+
| Style import fail | Rule 23 try-catch, roleMap fallback |
|
|
510
|
+
| 3× validate fail | Kullanıcıya generate-figma-screen öner |
|
|
511
|
+
|
|
512
|
+
## Known Limitations
|
|
513
|
+
|
|
514
|
+
1. SUI dışında test edilmedi — başka DS için isim farkı olabilir
|
|
515
|
+
2. Dark mode validate ayrı ölçülmez — manuel göz kontrolü gerekli
|
|
516
|
+
3. 9 recipe sabit — yeni tip → generate-figma-screen
|
|
517
|
+
4. Multi-screen ve prototype/interactions YOK
|
|
518
|
+
5. Component search false match riski — setProperties ile doğrula
|
|
519
|
+
|
|
520
|
+
---
|
|
521
|
+
|
|
522
|
+
## Skill References
|
|
523
|
+
|
|
524
|
+
- `skills/fmcp-screen-orchestrator/SKILL.md` — Fast Path tetiklenme
|
|
525
|
+
- `skills/figma-canvas-ops/SKILL.md` — Rule 5a CHUNKING + Rule 22 Async + Rule 23 Style zorunlu
|
|
526
|
+
- `.claude/design-systems/active-ds.md` — DS GATE state
|
|
527
|
+
- `.claude/design-systems/sui/tokens.md` — Token cache
|
|
528
|
+
- `.claude/design-systems/sui/components.md` — Component cache
|