@atezer/figma-mcp-bridge 1.7.30 → 1.9.1
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 +408 -0
- package/README.md +8 -8
- 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 +26 -0
- package/dist/core/plugin-bridge-connector.d.ts.map +1 -1
- package/dist/core/plugin-bridge-connector.js +18 -2
- package/dist/core/plugin-bridge-connector.js.map +1 -1
- package/dist/core/plugin-bridge-server.d.ts +16 -0
- package/dist/core/plugin-bridge-server.d.ts.map +1 -1
- package/dist/core/plugin-bridge-server.js +83 -1
- 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 +334 -101
- package/dist/local-plugin-only.js.map +1 -1
- package/f-mcp-plugin/code.js +514 -29
- package/f-mcp-plugin/ui.html +90 -14
- 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 -243
- package/skills/fmcp-ds-audit-orchestrator/SKILL.md +205 -0
- package/skills/fmcp-intent-router/SKILL.md +574 -0
- 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 +360 -6
- 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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: figma-canvas-ops
|
|
3
|
-
description: F-MCP Bridge ile Figma tuvalinde güvenli yazma/düzenleme için zorunlu önkoşul kılavuzu. figma_execute çağrısı öncesi bu skill yüklenmelidir.
|
|
3
|
+
description: F-MCP Bridge ile Figma tuvalinde güvenli yazma/düzenleme için zorunlu önkoşul kılavuzu. figma_execute çağrısı öncesi bu skill yüklenmelidir.
|
|
4
4
|
metadata:
|
|
5
5
|
mcp-server: user-figma-mcp-bridge
|
|
6
6
|
personas:
|
|
@@ -10,175 +10,142 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
# Figma Canvas Ops — figma_execute Güvenli Kullanım Kılavuzu
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Araç Eşleme (topluluk → F-MCP)
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
**Tuval yazan her skill** (apply-figma-design-system, fix-figma-design-system-finding, generate-figma-screen, generate-figma-library, figjam-diagram-builder) bu kılavuzdaki kuralları uygulamalıdır.
|
|
18
|
-
|
|
19
|
-
## Araç eşleme (topluluk → F-MCP)
|
|
20
|
-
|
|
21
|
-
| Topluluk (resmi MCP) | F-MCP Bridge | Not |
|
|
15
|
+
| Topluluk | F-MCP Bridge | Not |
|
|
22
16
|
|---|---|---|
|
|
23
|
-
| `use_figma` | `figma_execute` | JS çalıştırma
|
|
24
|
-
| `get_metadata` | `figma_get_file_data` | Yapı/metadata
|
|
25
|
-
| `get_screenshot` | `figma_capture_screenshot` |
|
|
17
|
+
| `use_figma` | `figma_execute` | JS çalıştırma |
|
|
18
|
+
| `get_metadata` | `figma_get_file_data` | Yapı/metadata |
|
|
19
|
+
| `get_screenshot` | `figma_capture_screenshot` | Görsel doğrulama |
|
|
26
20
|
| `search_design_system` | `figma_search_components` + `figma_get_design_system_summary` | İki araç birlikte |
|
|
27
21
|
|
|
28
|
-
Detaylı eşleme: [TOOL_MAPPING.md](../TOOL_MAPPING.md)
|
|
29
|
-
|
|
30
22
|
## Prerequisites
|
|
31
23
|
|
|
32
|
-
- F-MCP Bridge plugin
|
|
33
|
-
- `
|
|
34
|
-
|
|
35
|
-
## 1. Kritik Kurallar
|
|
36
|
-
|
|
37
|
-
1. **`return` ile veri dön.** Return değeri otomatik JSON serialize edilir (object, array, string, number). `figma.closePlugin()` çağırma — bu bridge tarafından yönetilir.
|
|
24
|
+
- F-MCP Bridge plugin bağlı olmalı (`figma_get_status()`)
|
|
25
|
+
- Aktif DS context: `.claude/design-systems/active-ds.md` → `Status: ✅`
|
|
38
26
|
|
|
39
|
-
|
|
27
|
+
## 0. Design System Context (ZORUNLU)
|
|
40
28
|
|
|
41
|
-
|
|
29
|
+
### 0a — Active DS check
|
|
30
|
+
```
|
|
31
|
+
1. Read .claude/design-systems/active-ds.md
|
|
32
|
+
2. ✅ Aktif → Library Name not al, 0b'ye geç
|
|
33
|
+
❌ Seçilmedi → 0c'ye geç
|
|
34
|
+
"DS bypass mode" → DS'siz devam
|
|
35
|
+
```
|
|
42
36
|
|
|
43
|
-
|
|
37
|
+
### 0b — DS asset cache hazırlığı
|
|
38
|
+
```
|
|
39
|
+
1. .claude/design-systems/<library-id>/components.md var mı?
|
|
40
|
+
2. .claude/design-systems/<library-id>/tokens.md var mı?
|
|
41
|
+
3. Yoksa: figma_get_library_variables + figma_search_assets ile keşfet, cache'e yaz
|
|
42
|
+
```
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
### 0c — Kullanıcıya DS seçimi sor
|
|
45
|
+
active-ds.md `❌` ise: "Hangi DS? (SUI / Material / HIG / Kendi / Hiçbiri)". Yanıt sonrası active-ds.md güncelle, 0b'ye geç. Sonraki turlarda TEKRAR SORMA.
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
figma_execute({ code: "...", timeout: 15000 })
|
|
50
|
-
```
|
|
51
|
-
Kılavuz: 1-5 node → 5000ms | 6-12 node → 10000ms | 13+ node → işlemi böl veya 15000-30000ms
|
|
47
|
+
## 1. Kritik Kurallar
|
|
52
48
|
|
|
53
|
-
|
|
49
|
+
1. **`return` ile veri dön.** `figma.closePlugin()` çağırma.
|
|
54
50
|
|
|
55
|
-
|
|
56
|
-
```js
|
|
57
|
-
// Renk değerini DS'den oku, aşağıdaki sadece API FORMAT örneğidir
|
|
58
|
-
const fills = [...node.fills];
|
|
59
|
-
fills[0] = { ...fills[0], color: DS_COLOR }; // DS'den okunan değer
|
|
60
|
-
node.fills = fills;
|
|
61
|
-
```
|
|
51
|
+
2. **Düz JS, top-level `await`.** Kod otomatik async sarılır. `(async()=>{})()` sarma. **Async API zorunlu** — dynamic-page mode'da sync API'ler throws:
|
|
62
52
|
|
|
63
|
-
|
|
53
|
+
| ❌ YASAK (sync) | ✅ ZORUNLU (async) |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `instance.mainComponent` | `await instance.getMainComponentAsync()` |
|
|
56
|
+
| `figma.getNodeById(id)` | `await figma.getNodeByIdAsync(id)` |
|
|
57
|
+
| `figma.variables.importVariableByKey(key)` | `await figma.variables.importVariableByKeyAsync(key)` |
|
|
58
|
+
| `figma.importComponentByKey(key)` | `await figma.importComponentByKeyAsync(key)` |
|
|
59
|
+
| `figma.importStyleByKey(key)` | `await figma.importStyleByKeyAsync(key)` |
|
|
60
|
+
| `node.effectStyleId = x` | `await node.setEffectStyleIdAsync(x)` |
|
|
61
|
+
| `node.textStyleId = x` | `await node.setTextStyleIdAsync(x)` |
|
|
62
|
+
| `figma.listAvailableFonts()` | `await figma.listAvailableFontsAsync()` |
|
|
63
|
+
| `figma.loadFont(...)` | `await figma.loadFontAsync(...)` |
|
|
64
|
+
| `figma.variables.getVariableCollectionById(id)` | `await figma.variables.getVariableCollectionByIdAsync(id)` |
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
3. **`figma.notify()` çalışmaz** — kullanma.
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
4. **`console.log()` dönmez** — `return` kullan.
|
|
68
69
|
|
|
69
|
-
|
|
70
|
+
5. **Küçük adımlarla çalış.** Timeout: varsayılan 15000ms, max 30000ms.
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
// Fontu belirledikten sonra yükle:
|
|
73
|
-
await figma.loadFontAsync({ family: "FONT_ADI", style: "Regular" });
|
|
74
|
-
// Gerekli diğer ağırlıklar:
|
|
75
|
-
await figma.loadFontAsync({ family: "FONT_ADI", style: "Bold" });
|
|
76
|
-
```
|
|
77
|
-
**Asla** hardcoded font varsayma — her zaman bu sırayı takip et. Bu kural font, renk, boyut, spacing dahil TÜM design token'lar için geçerlidir. Detay: `project-context.md` → "Design Token Kuralı".
|
|
72
|
+
### 5a. CHUNKING MANDATE (v2.0)
|
|
78
73
|
|
|
79
|
-
|
|
80
|
-
```js
|
|
81
|
-
await figma.loadFontAsync({ family: "Inter", style: "Medium" });
|
|
82
|
-
const shape = figma.createShapeWithText();
|
|
83
|
-
shape.text.characters = "Metin"; // Medium yüklenmeden hata verir
|
|
84
|
-
```
|
|
85
|
-
Genel kural: metin düzenlemeden önce **mevcut fontu kontrol et** ve o fontu yükle:
|
|
86
|
-
```js
|
|
87
|
-
await figma.loadFontAsync(shape.text.fontName); // dinamik font algılama
|
|
88
|
-
```
|
|
74
|
+
Her `figma_execute` **max 15 atomic operation**. Atomic op'lar: node/instance oluşturma, variable/style/component import, font load, bind operasyonu, getNodeByIdAsync, getMainComponentAsync.
|
|
89
75
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
```
|
|
76
|
+
- 1 execute = 1 mega-goal (discovery, frame+structure, 3-4 component placement)
|
|
77
|
+
- 25+ op → 2-3 execute'a böl
|
|
78
|
+
- Execute arası state: nodeId'leri `return` et, sonraki execute `getNodeByIdAsync` ile al
|
|
79
|
+
- Her execute sonrası 1 satır Türkçe micro-report
|
|
95
80
|
|
|
96
|
-
|
|
81
|
+
6. **Renkler 0–1 aralığında** (0–255 değil). Hardcoded renk YASAK — DS'den oku.
|
|
97
82
|
|
|
98
|
-
|
|
83
|
+
7. **Fills/strokes read-only array** — klonla, değiştir, ata:
|
|
99
84
|
```js
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
var vars = await figma.teamLibrary.getVariablesInLibraryCollectionAsync(semCol.key);
|
|
104
|
-
return vars.map(function(v) { return { name: v.name, key: v.key, resolvedType: v.resolvedType }; });
|
|
85
|
+
const fills = [...node.fills];
|
|
86
|
+
fills[0] = { ...fills[0], color: DS_COLOR };
|
|
87
|
+
node.fills = fills;
|
|
105
88
|
```
|
|
106
|
-
Veya doğrudan: `figma_get_library_variables({ libraryName: "❖ SUI" })`
|
|
107
89
|
|
|
108
|
-
|
|
109
|
-
```js
|
|
110
|
-
const variable = await figma.variables.importVariableByKeyAsync("VARIABLE_KEY");
|
|
111
|
-
```
|
|
90
|
+
8. **Font yükleme zorunlu.** Sıra: (a) DS cache'ten font oku → (b) Yoksa kullanıcıya sor → (c) "Sen seç" → Inter.
|
|
112
91
|
|
|
113
|
-
**
|
|
92
|
+
**8a-1) Font weight check (ZORUNLU):** `loadFontAsync` öncesi `listAvailableFontsAsync` ile kontrol et. Fallback helper:
|
|
114
93
|
```js
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
|
|
94
|
+
const allFonts = await figma.listAvailableFontsAsync();
|
|
95
|
+
const styles = allFonts.filter(f => f.fontName.family === "SHBGrotesk").map(f => f.fontName.style);
|
|
96
|
+
function pickStyle(desired, available) {
|
|
97
|
+
if (available.indexOf(desired) >= 0) return desired;
|
|
98
|
+
var fb = { "Medium":["Semi Bold","Regular"], "ExtraBold":["Bold"], "Black":["Bold"], "Thin":["Light","Regular"] };
|
|
99
|
+
var alts = fb[desired] || [];
|
|
100
|
+
for (var i = 0; i < alts.length; i++) { if (available.indexOf(alts[i]) >= 0) return alts[i]; }
|
|
101
|
+
return available.find(s => s.indexOf("Italic") < 0) || available[0];
|
|
102
|
+
}
|
|
103
|
+
await figma.loadFontAsync({ family: "SHBGrotesk", style: pickStyle("Medium", styles) });
|
|
118
104
|
```
|
|
105
|
+
**FigJam:** `createShapeWithText()` varsayılan "Inter Medium". Metin düzenlemeden önce `await figma.loadFontAsync(shape.text.fontName)`.
|
|
119
106
|
|
|
120
|
-
|
|
121
|
-
```js
|
|
122
|
-
node.setBoundVariable("paddingLeft", variable);
|
|
123
|
-
node.setBoundVariable("paddingRight", variable);
|
|
124
|
-
node.setBoundVariable("itemSpacing", variable);
|
|
125
|
-
node.setBoundVariable("topLeftRadius", variable);
|
|
126
|
-
```
|
|
107
|
+
9. **Sayfa konteksti her çağrıda sıfırlanır.** Farklı sayfa: `await figma.setCurrentPageAsync(page)`.
|
|
127
108
|
|
|
128
|
-
|
|
129
|
-
```js
|
|
130
|
-
const textStyles = await figma.getLocalTextStylesAsync();
|
|
131
|
-
const bodyStyle = textStyles.find(s => s.name === "global/surface/body");
|
|
132
|
-
await textNode.setTextStyleIdAsync(bodyStyle.id);
|
|
133
|
-
```
|
|
109
|
+
10. **Tüm tasarım değerleri DS variable'a BAĞLANMALI (ZORUNLU).**
|
|
134
110
|
|
|
135
|
-
|
|
136
|
-
```js
|
|
137
|
-
const textFills = [...textNode.fills];
|
|
138
|
-
const boundTextPaint = figma.variables.setBoundVariableForPaint(textFills[0], "color", textColorVar);
|
|
139
|
-
textNode.fills = [boundTextPaint];
|
|
140
|
-
```
|
|
111
|
+
Renk, spacing, padding, radius — HİÇBİR değer hardcoded yazılmaz. Token yoksa DURDUR, kullanıcıya sor.
|
|
141
112
|
|
|
142
|
-
|
|
113
|
+
**Akış:**
|
|
114
|
+
- **Variable import:** `const v = await figma.variables.importVariableByKeyAsync("KEY")`
|
|
115
|
+
- **Renk bind:** `node.fills = [figma.variables.setBoundVariableForPaint(fills[0], "color", v)]`
|
|
116
|
+
- **Spacing bind:** `node.setBoundVariable("paddingLeft", v)`
|
|
117
|
+
- **Text style:** `await textNode.setTextStyleIdAsync(style.id)`
|
|
118
|
+
- **Text renk:** `textNode.fills = [figma.variables.setBoundVariableForPaint(textFills[0], "color", textColorVar)]`
|
|
143
119
|
|
|
144
|
-
|
|
120
|
+
Hardcoded `node.fills = [{ type: "SOLID", color: {...} }]` YASAK.
|
|
145
121
|
|
|
146
|
-
|
|
122
|
+
11. **appendChild sıralaması kritik.** ÖNCE `parent.appendChild(child)`, SONRA `child.layoutSizingHorizontal = "FILL"` / `layoutPositioning = "ABSOLUTE"`:
|
|
123
|
+
```js
|
|
124
|
+
parent.appendChild(child); // ÖNCE
|
|
125
|
+
child.layoutSizingHorizontal = "FILL"; // SONRA
|
|
126
|
+
```
|
|
127
|
+
Hata: "Can only set layoutPositioning = ABSOLUTE if parent has layoutMode !== NONE" → child append edilmemiş.
|
|
147
128
|
|
|
148
|
-
|
|
129
|
+
12. **Yeni node'ları (0,0)'dan uzağa konumlandır.** Boş alan bul.
|
|
149
130
|
|
|
150
|
-
|
|
151
|
-
```js
|
|
152
|
-
return { createdNodeIds: [...], mutatedNodeIds: [...] };
|
|
153
|
-
```
|
|
131
|
+
13. **Hata durumunda DUR.** Hata oku, düzelt, tekrar çalıştır. Atomik — hata olursa değişiklik uygulanmaz.
|
|
154
132
|
|
|
155
|
-
|
|
156
|
-
- Arka plan: `["FRAME_FILL", "SHAPE_FILL"]`
|
|
157
|
-
- Metin rengi: `["TEXT_FILL"]`
|
|
158
|
-
- Boşluk: `["GAP"]`
|
|
133
|
+
14. **Tüm node ID'lerini RETURN ET:** `return { createdNodeIds: [...] }`
|
|
159
134
|
|
|
160
|
-
|
|
135
|
+
15. **Variable scope'ları:** Arka plan: `["FRAME_FILL"]`, Metin: `["TEXT_FILL"]`, Boşluk: `["GAP"]`
|
|
161
136
|
|
|
162
|
-
|
|
137
|
+
16. **Her Promise'i `await` et.**
|
|
163
138
|
|
|
164
|
-
|
|
139
|
+
## 2. Sayfa Kuralları
|
|
165
140
|
|
|
166
141
|
```js
|
|
167
|
-
const
|
|
168
|
-
await figma.setCurrentPageAsync(
|
|
169
|
-
// targetPage.children artık yüklü
|
|
142
|
+
const page = figma.root.children.find(p => p.name === "Sayfa");
|
|
143
|
+
await figma.setCurrentPageAsync(page);
|
|
170
144
|
```
|
|
171
|
-
|
|
172
|
-
**Sync setter `figma.currentPage = page` hata verir** — her zaman `await figma.setCurrentPageAsync(page)` kullan.
|
|
173
|
-
|
|
174
|
-
### Çağrılar arası
|
|
175
|
-
|
|
176
|
-
Her `figma_execute` çağrısında `figma.currentPage` ilk sayfaya sıfırlanır. Çoklu çağrı gerektiren iş akışlarında her çağrının başında `setCurrentPageAsync` çağır.
|
|
145
|
+
Sync `figma.currentPage = page` HATA verir. Her `figma_execute`'ta `currentPage` sıfırlanır.
|
|
177
146
|
|
|
178
147
|
## 3. Auto-Layout Kalıpları
|
|
179
148
|
|
|
180
|
-
### Frame oluşturma
|
|
181
|
-
|
|
182
149
|
```js
|
|
183
150
|
const frame = figma.createFrame();
|
|
184
151
|
frame.layoutMode = "VERTICAL";
|
|
@@ -189,140 +156,130 @@ frame.paddingTop = frame.paddingBottom = 24;
|
|
|
189
156
|
frame.paddingLeft = frame.paddingRight = 24;
|
|
190
157
|
```
|
|
191
158
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
```js
|
|
195
|
-
const parent = figma.createFrame();
|
|
196
|
-
parent.layoutMode = "VERTICAL";
|
|
197
|
-
const child = figma.createFrame();
|
|
198
|
-
parent.appendChild(child); // ÖNCE ekle
|
|
199
|
-
child.layoutSizingHorizontal = "FILL"; // SONRA FILL ayarla
|
|
200
|
-
```
|
|
159
|
+
FILL boyutlandırma: ÖNCE appendChild, SONRA `layoutSizingHorizontal = "FILL"` (Rule 11).
|
|
201
160
|
|
|
202
161
|
## 4. Bileşen ve Instance Kalıpları
|
|
203
162
|
|
|
204
|
-
### Mevcut bileşen ile instance oluşturma
|
|
205
|
-
|
|
206
|
-
Tercihen `figma_instantiate_component` aracını kullan. `figma_execute` içinde:
|
|
207
|
-
|
|
208
163
|
```js
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
164
|
+
// Local component
|
|
165
|
+
const comp = figma.root.findOne(n => n.type === "COMPONENT" && n.name === "Button");
|
|
166
|
+
const instance = comp.createInstance();
|
|
167
|
+
|
|
168
|
+
// Variant seçimi
|
|
169
|
+
const set = figma.root.findOne(n => n.type === "COMPONENT_SET" && n.name === "Button");
|
|
170
|
+
const variant = set.children.find(c => c.name === "Size=Large, Type=Primary");
|
|
171
|
+
const inst = variant.createInstance();
|
|
215
172
|
```
|
|
216
173
|
|
|
217
|
-
|
|
174
|
+
## 5. Variable Bağlama
|
|
218
175
|
|
|
219
176
|
```js
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
);
|
|
223
|
-
const variant = componentSet.children.find(
|
|
224
|
-
c => c.name === "Size=Large, Type=Primary"
|
|
225
|
-
);
|
|
226
|
-
const instance = variant.createInstance();
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
## 5. Variable Bağlama Kalıpları
|
|
230
|
-
|
|
231
|
-
```js
|
|
232
|
-
const collections = await figma.variables.getLocalVariableCollectionsAsync();
|
|
233
|
-
const colorCollection = collections.find(c => c.name === "Colors");
|
|
234
|
-
const variables = await Promise.all(
|
|
235
|
-
colorCollection.variableIds.map(id =>
|
|
236
|
-
figma.variables.getVariableByIdAsync(id)
|
|
237
|
-
)
|
|
238
|
-
);
|
|
239
|
-
const primaryColor = variables.find(v => v.name === "primary/500");
|
|
240
|
-
|
|
241
|
-
// Fill'e bağla
|
|
177
|
+
const variable = await figma.variables.importVariableByKeyAsync("KEY");
|
|
178
|
+
// Fill bind
|
|
242
179
|
const fills = [...node.fills];
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
);
|
|
246
|
-
node.fills = [boundPaint]; // YENİ paint'i geri ata
|
|
180
|
+
node.fills = [figma.variables.setBoundVariableForPaint(fills[0], "color", variable)];
|
|
181
|
+
// Spacing bind
|
|
182
|
+
node.setBoundVariable("paddingLeft", variable);
|
|
247
183
|
```
|
|
248
184
|
|
|
249
|
-
## 6. Ek API Gotcha'lar
|
|
250
|
-
|
|
251
|
-
17. **`import` keyword yasağı.** Plugin sandbox'ta
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
await
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
185
|
+
## 6. Ek API Gotcha'lar
|
|
186
|
+
|
|
187
|
+
17. **`import` keyword yasağı.** Plugin sandbox'ta reserved word. `async function getVar(k)` kullan.
|
|
188
|
+
|
|
189
|
+
18. **`setEffectStyleIdAsync` zorunlu.** Sync `node.effectStyleId = id` hata verir.
|
|
190
|
+
|
|
191
|
+
19. **`setTextStyleIdAsync` kullan, fontSize binding YASAK:**
|
|
192
|
+
```js
|
|
193
|
+
const style = await figma.importStyleByKeyAsync("KEY");
|
|
194
|
+
await textNode.setTextStyleIdAsync(style.id);
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
20. **`setExplicitVariableModeForCollection` — string ID çalışmaz.** Library API chain ile collection OBJECT al:
|
|
198
|
+
```js
|
|
199
|
+
var colls = await figma.teamLibrary.getAvailableLibraryVariableCollectionsAsync();
|
|
200
|
+
var sem = colls.find(c => c.name.indexOf("Semantic Colors") !== -1);
|
|
201
|
+
var vars = await figma.teamLibrary.getVariablesInLibraryCollectionAsync(sem.key);
|
|
202
|
+
var first = await figma.variables.importVariableByKeyAsync(vars[0].key);
|
|
203
|
+
var coll = await figma.variables.getVariableCollectionByIdAsync(first.variableCollectionId);
|
|
204
|
+
var darkMode = coll.modes.find(m => m.name === "Dark");
|
|
205
|
+
frame.setExplicitVariableModeForCollection(coll, darkMode.modeId);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
21. **Escaped quote dikkat.** `figma_execute` code'da `\"` yerine düz `"` kullan.
|
|
209
|
+
|
|
210
|
+
23. **Style Import Sessiz Fail.** `importStyleByKeyAsync` null/throws olabilir. Her zaman try-catch:
|
|
211
|
+
```js
|
|
212
|
+
let style = null;
|
|
213
|
+
try { style = await figma.importStyleByKeyAsync("KEY"); } catch(e) {}
|
|
214
|
+
if (style) {
|
|
215
|
+
await textNode.setTextStyleIdAsync(style.id);
|
|
216
|
+
await figma.loadFontAsync(textNode.fontName);
|
|
217
|
+
textNode.characters = "Metin";
|
|
218
|
+
} else {
|
|
219
|
+
await figma.loadFontAsync({ family: "Inter", style: "Regular" });
|
|
220
|
+
textNode.fontName = { family: "Inter", style: "Regular" };
|
|
221
|
+
textNode.characters = "Metin (fallback)";
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
**Fast Path:** roleMap hazırsa `setTextStyleIdAsync(roleMap[role].id)` direkt kullan, import atla (bkz. fmcp-screen-recipes Adım 1.6).
|
|
225
|
+
|
|
226
|
+
24. **Component Discovery Fallback.** `figma_search_assets` boş dönerse manuel instance scan:
|
|
227
|
+
```js
|
|
228
|
+
const instances = figma.currentPage.findAll(n => n.type === "INSTANCE");
|
|
229
|
+
const map = new Map();
|
|
230
|
+
for (const inst of instances) {
|
|
231
|
+
const main = await inst.getMainComponentAsync();
|
|
232
|
+
if (main && main.remote && main.key && !map.has(main.name))
|
|
233
|
+
map.set(main.name, { name: main.name, key: main.key });
|
|
234
|
+
}
|
|
235
|
+
return Array.from(map.values());
|
|
236
|
+
```
|
|
237
|
+
Sıra: (1) Cache → (2) `figma_search_assets` → (3) Manuel scan → (4) Key biliniyor → `importComponentByKeyAsync(key)` direkt.
|
|
238
|
+
|
|
239
|
+
25. **`figma_validate_screen` Timeout Fallback.** 3 seviyeli:
|
|
240
|
+
- **Seviye 1:** `figma_validate_screen(nodeId, minScore=80)` — timeout olursa:
|
|
241
|
+
- **Seviye 2:** Content Body wrapper'ı validate et (daha küçük tree), minScore=70
|
|
242
|
+
- **Seviye 3:** Manuel QA Checklist üret:
|
|
243
|
+
- [ ] Instance coverage ≥60%
|
|
244
|
+
- [ ] Rastgele 5 fill'de variable icon 🎨 var mı
|
|
245
|
+
- [ ] Rastgele 3 spacing variable-bound mu
|
|
246
|
+
- [ ] Auto-layout tüm frame'lerde aktif mi
|
|
247
|
+
- [ ] Dark mode renkleri doğru mu
|
|
248
|
+
|
|
249
|
+
26. **Component Property Discovery — Tek Execute.**
|
|
250
|
+
```js
|
|
251
|
+
const comp = await figma.importComponentByKeyAsync(key);
|
|
252
|
+
let set = comp.parent?.type === "COMPONENT_SET" ? comp.parent : comp;
|
|
253
|
+
const propDefs = set.componentPropertyDefinitions || {};
|
|
254
|
+
return {
|
|
255
|
+
componentName: comp.name,
|
|
256
|
+
propertyDefinitions: Object.entries(propDefs).map(([n, d]) => ({
|
|
257
|
+
name: n, type: d.type, defaultValue: d.defaultValue, variantOptions: d.variantOptions || []
|
|
258
|
+
}))
|
|
259
|
+
};
|
|
260
|
+
```
|
|
261
|
+
`figma_instantiate_component` timeout olursa: `figma_execute` içinde `importComponentByKeyAsync(key)` + `comp.createInstance()`.
|
|
262
|
+
|
|
263
|
+
**Text Style Discovery:** (1) Instance scan: `findAll(TEXT)` → `textStyleId` → `getStyleByIdAsync` (2) Boşsa `figma_search_assets` (3) Boşsa team library API (4) Fallback Inter + hardcoded size.
|
|
295
264
|
|
|
296
265
|
## 7. Hata Kurtarma
|
|
297
266
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
## 7. Doğrulama Adımları
|
|
308
|
-
|
|
309
|
-
Her yazma işleminden sonra:
|
|
310
|
-
|
|
311
|
-
1. `figma_capture_screenshot` ile görsel doğrulama
|
|
312
|
-
2. Gerekirse `figma_get_file_data` ile yapı kontrolü
|
|
313
|
-
3. Oluşturulan node ID'lerini sonraki çağrılarda referans olarak kullan
|
|
267
|
+
| Hata | Çözüm |
|
|
268
|
+
|---|---|
|
|
269
|
+
| `Cannot read property of undefined` | Node ID geçersiz / sayfa yüklenmemiş |
|
|
270
|
+
| `Font not loaded` | `loadFontAsync` eksik |
|
|
271
|
+
| `Font could not be loaded` | Weight yok → `pickStyle()` fallback (Rule 8a-1) |
|
|
272
|
+
| `Cannot set FILL before appendChild` | Rule 11 sırası |
|
|
273
|
+
| `Maximum call stack` | Küçük parçalara böl |
|
|
274
|
+
| `Resource links not supported` | Yanlış MCP (resmi) → F-MCP kullan |
|
|
314
275
|
|
|
315
|
-
##
|
|
276
|
+
## 8. Doğrulama
|
|
316
277
|
|
|
317
|
-
|
|
318
|
-
- **generate-figma-screen** — Ekran oluşturma iş akışı
|
|
319
|
-
- **generate-figma-library** — DS kütüphanesi inşa
|
|
320
|
-
- **apply-figma-design-system** — DS hizalama
|
|
321
|
-
- **fix-figma-design-system-finding** — Tek bulgu düzeltme
|
|
322
|
-
- **figjam-diagram-builder** — FigJam diyagram oluşturma
|
|
278
|
+
Her yazma sonrası: `figma_capture_screenshot` + gerekirse `figma_get_file_data`.
|
|
323
279
|
|
|
324
|
-
##
|
|
280
|
+
## Skill Koordinasyonu
|
|
325
281
|
|
|
326
|
-
-
|
|
327
|
-
-
|
|
328
|
-
-
|
|
282
|
+
- **fmcp-screen-orchestrator** — DS GATE, Fast Path routing
|
|
283
|
+
- **fmcp-screen-recipes** — Fast Path (Rule 25 validate, Rule 26 discovery referans alınır)
|
|
284
|
+
- **generate-figma-screen** — Tam workflow
|
|
285
|
+
- **generate-figma-library** / **apply-figma-design-system** / **fix-figma-design-system-finding** / **figjam-diagram-builder**
|