@atezer/figma-mcp-bridge 1.9.5 → 1.9.7
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 +114 -0
- package/dist/core/blocking-tracker.d.ts +68 -0
- package/dist/core/blocking-tracker.d.ts.map +1 -0
- package/dist/core/blocking-tracker.js +152 -0
- package/dist/core/blocking-tracker.js.map +1 -0
- package/dist/core/bootstrap-injector.d.ts +50 -0
- package/dist/core/bootstrap-injector.d.ts.map +1 -0
- package/dist/core/bootstrap-injector.js +134 -0
- package/dist/core/bootstrap-injector.js.map +1 -0
- package/dist/core/embedded-skills.d.ts +17 -0
- package/dist/core/embedded-skills.d.ts.map +1 -0
- package/dist/core/embedded-skills.js +817 -0
- package/dist/core/embedded-skills.js.map +1 -0
- package/dist/core/plugin-bridge-connector.d.ts +10 -0
- package/dist/core/plugin-bridge-connector.d.ts.map +1 -1
- package/dist/core/plugin-bridge-connector.js +7 -0
- package/dist/core/plugin-bridge-connector.js.map +1 -1
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/local-plugin-only.d.ts.map +1 -1
- package/dist/local-plugin-only.js +98 -3
- package/dist/local-plugin-only.js.map +1 -1
- package/f-mcp-plugin/code.js +307 -2
- package/f-mcp-plugin/ui.html +19 -1
- package/package.json +3 -2
- package/skills/fmcp-intent-router/SKILL.md +56 -9
- package/skills/fmcp-screen-orchestrator/SKILL.md +26 -0
|
@@ -0,0 +1,817 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.9.7: Auto-generated embedded skill summary for Claude Desktop zero-click enforcement.
|
|
3
|
+
*
|
|
4
|
+
* Generated by: scripts/generate-embedded-skills.mjs
|
|
5
|
+
* Source: skills/fmcp-intent-router/SKILL.md, skills/fmcp-screen-orchestrator/SKILL.md, skills/figma-canvas-ops/SKILL.md, skills/fmcp-screen-recipes/SKILL.md, skills/fmcp-project-rules/SKILL.md
|
|
6
|
+
*
|
|
7
|
+
* DO NOT EDIT MANUALLY. Run `npm run generate:embedded-skills` to regenerate.
|
|
8
|
+
* This file is regenerated on prepublishOnly hook before npm publish.
|
|
9
|
+
*
|
|
10
|
+
* Generated: 2026-04-18T08:23:36.324Z
|
|
11
|
+
* Total estimated tokens: 9349
|
|
12
|
+
*/
|
|
13
|
+
export const EMBEDDED_SKILLS_SUMMARY = `<!-- fmcp-intent-router (2572 tokens) -->
|
|
14
|
+
---
|
|
15
|
+
name: fmcp-intent-router
|
|
16
|
+
description: F-MCP ile ilgili herhangi bir kullanıcı talebinin ilk giriş noktası. Kullanıcının niyetini analiz eder, hangi hedef SKILL'in çalıştırılacağına karar verir, o SKILL için gereken eksik input'ları tek turda toplar, özet+onay alır ve ondan sonra hedef SKILL'i çalıştırır. "figma", "ekran oluştur", "tasarım yap", "component üret", "DS denetle", "token sync", "kod üret", "design system" gibi her F-MCP-tetiklemesiyle aktive olur. Claude hiçbir figma_* yazma tool'u çalıştırmadan ÖNCE bu protokolü uygulamak zorundadır.
|
|
17
|
+
metadata:
|
|
18
|
+
mcp-server: user-figma-mcp-bridge
|
|
19
|
+
version: 1.8.1
|
|
20
|
+
priority: 100
|
|
21
|
+
phase: entry-gate
|
|
22
|
+
personas:
|
|
23
|
+
- designer
|
|
24
|
+
- uidev
|
|
25
|
+
- designops
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# F-MCP Intent Router — Universal Entry Gate
|
|
29
|
+
|
|
30
|
+
## Neden Var?
|
|
31
|
+
|
|
32
|
+
F-MCP Bridge'in 20+ SKILL'i var. Her biri farklı bir iş yapar (ekran oluşturma, denetim, kütüphane inşası, vb.) ve her biri farklı input'lar ister. Claude kullanıcı "figma'da ekran yap" dediğinde:
|
|
33
|
+
|
|
34
|
+
1. Hangi SKILL lazım? (\`generate-figma-screen\` mi \`generate-figma-library\` mi?)
|
|
35
|
+
2. Hangi bilgiler eksik? (device? DS? benchmark? içerik bölümleri?)
|
|
36
|
+
3. Kullanıcı ne onay verdi?
|
|
37
|
+
|
|
38
|
+
Bu SKILL bu üç soruyu **upstream** çözer. Claude intent'i netleştirmeden hiçbir \`figma_execute\`, \`figma_create_frame\`, \`figma_clone_screen_to_device\` çalıştırmaz. "Hızlı ve doğru" kuralı: yanlış varsayım yapmaktansa 1 soru sormak her zaman daha hızlıdır.
|
|
39
|
+
|
|
40
|
+
## Protokol (9 Adım — v1.9.1+)
|
|
41
|
+
|
|
42
|
+
Kullanıcı F-MCP ile ilgili herhangi bir talep yaptığında Claude bu 9 adımı SIRAYLA uygular. Hiçbir adım atlanmaz.
|
|
43
|
+
|
|
44
|
+
### 🚨 Adım 0 — DS GATE + BLANK FILE CHECK (v1.9.7+ MUTLAK İLK KAPI)
|
|
45
|
+
|
|
46
|
+
**Herhangi bir intent analysis veya figma_* tool çağrısından ÖNCE:**
|
|
47
|
+
|
|
48
|
+
1. \`figma_get_status\` çağır — plugin bağlı mı, response'ta \`_bootstrap\` varsa direktifleri OKU (v1.9.7)
|
|
49
|
+
2. \`.claude/design-systems/active-ds.md\` dosyasını oku
|
|
50
|
+
3. \`Status:\` alanını kontrol et:
|
|
51
|
+
- **\`✅ Aktif\`** → DS net, Blank File Sub-Check'e geç (madde 5)
|
|
52
|
+
- **\`❌ Henüz seçilmedi\`** VEYA dosya yok → kullanıcıya DS sorusu sor (madde 4)
|
|
53
|
+
4. **DS Sorusu (klasik):** "Aktif bir design system belirlenmemiş. Hangi DS ile ilerlemek istersiniz? (SUI / Material / kendi library)"
|
|
54
|
+
|
|
55
|
+
5. **BLANK FILE SUB-CHECK (v1.9.7, ZORUNLU):** \`figma_get_design_system_summary\` çağır.
|
|
56
|
+
- \`components === 0 && componentSets === 0 && variableCollections.length === 0\` ise **BOŞ DOSYA** tespit edildi.
|
|
57
|
+
- \`_nextStep: "BLANK_FILE_DIALOG_REQUIRED"\` response'ta görünüyorsa, **kullanıcıya 4 seçenek sun** (AskUserQuestion tek call, 4 option):
|
|
58
|
+
\`\`\`
|
|
59
|
+
Q: "Bu dosyada henüz Design System yok. Nasıl ilerleyelim?"
|
|
60
|
+
(a) Team library import — "Hangi library? SUI, Material 3, iOS HIG, veya kendi library'niz?"
|
|
61
|
+
(b) Mini DS kur otomatik — figma_create_mini_ds tool'u çağrılır (12 color + 8 sizing + 3 text style + Button/Input/Card)
|
|
62
|
+
(c) Referans DS kopyala — "Material 3 template / iOS HIG template"
|
|
63
|
+
(d) DS'siz ilerle — linter tolerant mode, hardcoded değerler kabul (explicit acceptance)
|
|
64
|
+
\`\`\`
|
|
65
|
+
- **Seçim yapılmadan \`figma_execute createFrame\` YASAK.** Claude ham createFrame denerse plugin \`_DESIGN_SYSTEM_VIOLATIONS_BLOCKING\` flag'i döndürür, retry zorunlu olur.
|
|
66
|
+
- Kullanıcı "(b)" derse Claude \`figma_create_mini_ds({ primaryColor, fontFamily, name })\` tek tool çağrısı yapar, sonra ekran üretimine geçer.
|
|
67
|
+
- Kullanıcı "(a)" derse Claude \`figma_get_library_variables(libraryName)\` ile listeleme yapar, seçenek sunar.
|
|
68
|
+
|
|
69
|
+
6. Seçim sonrası \`active-ds.md\`'yi güncelle (\`Status: ✅ Aktif\`, \`Library Name: <isim>\`), sonra Adım 1'e geç.
|
|
70
|
+
|
|
71
|
+
**Neden bu kadar katı:**
|
|
72
|
+
- DS belirsizken \`figma_search_assets\`, \`figma_get_file_data\`, \`figma_get_library_variables\` çağırmak = kullanıcının istemediği library'leri enumere etmek = **token israfı + UX bozulması**
|
|
73
|
+
- Test geçmişinde gözlenen hata: benchmark Figma dosyasının 24+ library component'i enumere edildi, sonra "hangi DS?" soruldu. **Bu sıra YASAK.**
|
|
74
|
+
|
|
75
|
+
**Bu adımda çağrılabilen tek Figma tool'u:**
|
|
76
|
+
- ✅ \`figma_get_status()\` — plugin bağlantı kontrolü, DS bağımsız
|
|
77
|
+
- **Başka HİÇBİR figma_* YASAK.** \`figma_get_file_data\`, \`figma_search_assets\`, \`figma_search_components\`, \`figma_get_library_variables\`, \`figma_get_variables\`, \`figma_get_styles\` — **hepsi YASAK** ta ki Adım 0 geçilene kadar.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### Adım 1 — Intent Analysis
|
|
82
|
+
|
|
83
|
+
Kullanıcı talebini oku. Anahtar kelimeleri tara:
|
|
84
|
+
|
|
85
|
+
| Kullanıcı ifadesi | Olası SKILL adayı |
|
|
86
|
+
|---|---|
|
|
87
|
+
| "ekran yap", "tasarım oluştur", "ui çiz", "UI'ı Figma'ya aktar", "landing page", "mobil ekran" | \`generate-figma-screen\` |
|
|
88
|
+
| "DS hizala", "SUI'ye uygula", "design system uygula", "token'lara bağla" | \`apply-figma-design-system\` |
|
|
89
|
+
| "denet", "audit", "DS sağlığı", "token bağlı mı", "ne kadar DS uyumlu" | \`audit-figma-design-system\` |
|
|
90
|
+
| "kütüphane yap", "component set üret", "DS kütüphane inşa" | \`generate-figma-library\` |
|
|
91
|
+
| "Figma'dan kod üret", "implement design", "SwiftUI/Compose/React kodu" | \`implement-design\` |
|
|
92
|
+
| "kod ↔ figma eşleştir", "Code Connect", "design mapping" | \`code-design-mapper\` |
|
|
93
|
+
| "görsel karşılaştır", "visual diff", "QA screenshot" | \`visual-qa-compare\` |
|
|
94
|
+
| "token sync", "design tokens export", "CSS/Swift/Kotlin token" | \`design-token-pipeline\` |
|
|
95
|
+
| "figjam diyagram", "flowchart", "mind map" | \`figjam-diagram-builder\` |
|
|
96
|
+
| "ekran özeti", "analiz et", "ne içeriyor" | \`figma-screen-analyzer\` |
|
|
97
|
+
| "accessibility", "a11y", "WCAG", "contrast check" | \`figma-a11y-audit\` |
|
|
98
|
+
| "drift", "kod/tasarım sapması", "out of sync" | \`design-drift-detector\` |
|
|
99
|
+
| "UX copy", "microcopy", "buton metni", "empty state" | \`ux-copy-guidance\` |
|
|
100
|
+
| "bu görselden ilham al", "şu resim gibi", "link'teki tasarımdan", "dribbble/behance", "benchmark'tan varyasyon" | \`inspiration-intake\` → \`generate-figma-screen\` |
|
|
101
|
+
|
|
102
|
+
**Not (v1.8.3+):** \`inspiration-intake\` bir **ön-işleme** skill'idir. Kullanıcı bir Figma benchmark linki, internet görsel linki veya sohbete yüklenmiş görsel ile gelirse önce bu skill çalıştırılır (structural_intent JSON üretir, DEĞER çıkarmaz), sonra çıktısı \`generate-figma-screen\`'in \`reference_benchmark\` parametresine beslenir. v1.8.2 build-from-scratch kuralı ile tam uyumludur — clone değil, inspiration.
|
|
103
|
+
|
|
104
|
+
Mode tespiti:
|
|
105
|
+
- Figma URL pattern (\`figma.com/file/...?node-id=\`) → \`inspiration-intake\` (source_type: figma_url)
|
|
106
|
+
- Dribbble/Behance/genel HTTP URL → \`inspiration-intake\` (source_type: image_url, WebFetch fallback'li)
|
|
107
|
+
- Kullanıcı mesajında görsel attachment → \`inspiration-intake\` (source_type: image_uploaded)
|
|
108
|
+
|
|
109
|
+
### Adım 2 — State Files Check
|
|
110
|
+
|
|
111
|
+
Claude her seferinde üç state dosyasını okur:
|
|
112
|
+
|
|
113
|
+
\`\`\`
|
|
114
|
+
1. .claude/design-systems/active-ds.md
|
|
115
|
+
→ Aktif DS belirtilmiş mi? (örn "❖ SUI")
|
|
116
|
+
|
|
117
|
+
2. .claude/design-systems/last-intent.md
|
|
118
|
+
→ Son tamamlanan intent nedir? (device, ds, skill, inputs)
|
|
119
|
+
|
|
120
|
+
3. .claude/design-systems/intent-history.md
|
|
121
|
+
→ Son 5 intent nedir? (LRU)
|
|
122
|
+
\`\`\`
|
|
123
|
+
|
|
124
|
+
Bu dosyalar Claude'un "öncekiyle aynı mı?" sorusu sormasını sağlar.
|
|
125
|
+
|
|
126
|
+
### Adım 3b — Approach Karar Mantığı (v1.8.2+)
|
|
127
|
+
|
|
128
|
+
Target skill \`generate-figma-screen\` ise, **yaklaşım ayrımı** yap.
|
|
129
|
+
Kullanıcının cümlesinde şu keyword'leri ara ve \`approach\` input'unu doldur:
|
|
130
|
+
|
|
131
|
+
| Keyword | Yaklaşım | Tool Önerisi |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| "alternatif", "varyasyon", "farklı", "yeni", "tasarla", "redesign", "iyileştir" | \`build-from-scratch\` ⭐ | \`figma_execute\` + Step 5, **\`figma_clone_screen_to_device\` KULLANMA** |
|
|
134
|
+
| "aynı ekranı X device'a migrate et", "boyut değiştir", "iPhone 13→17", "klonla" | \`clone-to-device\` | \`figma_clone_screen_to_device\` |
|
|
135
|
+
| "mevcut ekranı DS'ye hizala", "tokenize et", "tokens bind et" | \`apply-ds-to-existing\` | \`apply-figma-design-system\` SKILL |
|
|
136
|
+
| Hiçbiri net değil | **Kullanıcıya sor** | — |
|
|
137
|
+
|
|
138
|
+
**⭐ ÖNEMLİ:** Eğer kullanıcı "3 alternatif" veya "varyasyon" derse, \`approach = build-from-scratch\` **DEFAULT**'tur. \`figma_clone_screen_to_device\` tool'u **ASLA önerilmez**. Clone tool'u kopyalama yaparken benchmark'ın **mevcut yanlışlıklarını** (hardcoded rectangle, missing token binding, non-responsive layout) kopyalar. Bu kullanıcının istediği **gerçek varyasyon yaratmaz**.
|
|
139
|
+
|
|
140
|
+
Eğer \`approach = build-from-scratch\` ise, Claude'un akış haritası:
|
|
141
|
+
\`\`\`
|
|
142
|
+
figma_search_assets ile SUI bileşenlerini bul
|
|
143
|
+
↓
|
|
144
|
+
figma_get_library_variables ile DS token key'lerini topla
|
|
145
|
+
↓
|
|
146
|
+
figma_execute ile bölüm bölüm inşa et:
|
|
147
|
+
- figma.createFrame() + layoutMode + padding (variable binding)
|
|
148
|
+
- importComponentByKeyAsync + createInstance (DS instance'lar)
|
|
149
|
+
- setBoundVariableForPaint (fills token bind)
|
|
150
|
+
- setBoundVariable (padding/itemSpacing/cornerRadius token bind)
|
|
151
|
+
- importStyleByKeyAsync + setTextStyleIdAsync (text style bind)
|
|
152
|
+
- appendChild sonrası layoutSizingHorizontal/Vertical = FILL
|
|
153
|
+
↓
|
|
154
|
+
figma_validate_screen ile skor kontrolü (≥80)
|
|
155
|
+
\`\`\`
|
|
156
|
+
|
|
157
|
+
**Özet + Onay ekranında göster:**
|
|
158
|
+
\`\`\`
|
|
159
|
+
📋 Yaklaşım: build-from-scratch ⭐
|
|
160
|
+
Bu kullanıcının "alternatif tasarım" isteğine uygun doğru yol.
|
|
161
|
+
Clone tool kullanılmayacak. Her alternatif sıfırdan SUI bileşenleriyle inşa edilecek.
|
|
162
|
+
Benchmark (139:xxx) sadece ilham kaynağı — kopyalanmayacak.
|
|
163
|
+
\`\`\`
|
|
164
|
+
|
|
165
|
+
### Adım 3 — Decide Target Skill
|
|
166
|
+
|
|
167
|
+
Adım 1'deki keyword eşleşmesi + Adım 2'deki state bilgisi → tek bir SKILL seç.
|
|
168
|
+
|
|
169
|
+
**Karar mantığı:**
|
|
170
|
+
|
|
171
|
+
\`\`\`
|
|
172
|
+
IF user request EXACTLY matches one keyword pattern
|
|
173
|
+
→ Select that skill (single match, no question)
|
|
174
|
+
|
|
175
|
+
ELSE IF user request matches 2+ patterns (ambiguous)
|
|
176
|
+
→ Ask user: "Şunlardan hangisini yapayım?"
|
|
177
|
+
→ Use AskUserQuestion with matched skills as options
|
|
178
|
+
|
|
179
|
+
ELSE IF user request is generic ("figma'da bir şey yap")
|
|
180
|
+
→ Ask user: "Tam olarak ne yapmak istiyorsun?"
|
|
181
|
+
→ Offer top 5 common skills as options
|
|
182
|
+
|
|
183
|
+
ELSE (no match)
|
|
184
|
+
→ Ask user to clarify intent in natural language
|
|
185
|
+
\`\`\`
|
|
186
|
+
|
|
187
|
+
### Adım 4 — Read Target Skill Metadata
|
|
188
|
+
|
|
189
|
+
Seçilen SKILL'in frontmatter'ını oku. \`required_inputs\` bloğunu parse et:
|
|
190
|
+
|
|
191
|
+
\`\`\`yaml
|
|
192
|
+
required_inputs:
|
|
193
|
+
- name: device
|
|
194
|
+
type: enum
|
|
195
|
+
options: ["iPhone 17", "iPhone 16 Pro Max", ...]
|
|
196
|
+
question: "Hangi device boyutunda olsun?"
|
|
197
|
+
required: true
|
|
198
|
+
default_source: ".claude/design-systems/last-intent.md#device"
|
|
199
|
+
- name: design_system
|
|
200
|
+
type: from_state
|
|
201
|
+
source: ".claude/design-systems/active-ds.md#Library Name"
|
|
202
|
+
required: true
|
|
203
|
+
- name: reference_benchmark
|
|
204
|
+
type: node_id_or_none
|
|
205
|
+
question: "Referans benchmark node var mı?"
|
|
206
|
+
required: false
|
|
207
|
+
affects: ["screen_type", "sections"] # verilirse bunlar atlanır
|
|
208
|
+
- name: screen_type
|
|
209
|
+
type: enum
|
|
210
|
+
...
|
|
211
|
+
skip_if: "reference_benchmark != none"
|
|
212
|
+
\`\`\`
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
<!-- fmcp-screen-orchestrator (887 tokens) -->
|
|
217
|
+
### Ortak Protokol
|
|
218
|
+
|
|
219
|
+
1. **Skill Registry** açık — tahmin yasak, sezgisel Read() yasak
|
|
220
|
+
2. **Intent Routing** — belirsiz → Read fmcp-intent-router
|
|
221
|
+
3. **Cheap-First** — \`depth=1\`, \`verbosity="summary"\`, screenshot sadece onay kapısında, ≤5 execute
|
|
222
|
+
4. **Cache-First** — \`.claude/design-systems/<lib>/\` cache'i API'den ÖNCE oku
|
|
223
|
+
5. **Onay Kapıları** — approach / destructive / evolution / 3. audit fail
|
|
224
|
+
6. **Self-Audit** — \`figma_validate_screen(nodeId, minScore=80)\` ZORUNLU
|
|
225
|
+
7. **Skill Evolution** — iki aşamalı onay + \`# DRAFT — PENDING APPROVAL\` banner
|
|
226
|
+
8. **Türkçe Raporlama** — metrik bloğu zorunlu
|
|
227
|
+
|
|
228
|
+
### Skill Registry
|
|
229
|
+
|
|
230
|
+
| Skill | Trigger | Common case? |
|
|
231
|
+
|---|---|---|
|
|
232
|
+
| \`fmcp-intent-router\` | Belirsiz intent | Sadece belirsizlikte |
|
|
233
|
+
| \`inspiration-intake\` | image/figma_benchmark | Sadece bu modlarda |
|
|
234
|
+
| \`generate-figma-screen\` | Net screen creation | HER ZAMAN (ana motor) |
|
|
235
|
+
| \`figma-canvas-ops\` | Her figma_execute öncesi | HER ZAMAN (pre-flight) |
|
|
236
|
+
| \`fmcp-screen-recipes\` | Fast Path match | Sadece Fast Path'te |
|
|
237
|
+
| \`apply-figma-design-system\` | Mevcut ekranı DS'ye hizala | Sadece remediation |
|
|
238
|
+
|
|
239
|
+
### Adım 0 — DS GATE (MUTLAK İLK KAPI)
|
|
240
|
+
|
|
241
|
+
\`\`\`
|
|
242
|
+
1. Read(".claude/design-systems/active-ds.md")
|
|
243
|
+
2. ✅ Aktif → Library Name not al, devam
|
|
244
|
+
❌ Seçilmedi veya dosya yok → DUR, kullanıcıya "Hangi DS?" sor, hiçbir figma_* çağırma
|
|
245
|
+
\`\`\`
|
|
246
|
+
|
|
247
|
+
DS belirsizken \`figma_get_file_data\`, \`figma_search_assets\` çağırmak YASAK. İstisnalar: \`figma_get_status()\`, filesystem read, Claude vision.
|
|
248
|
+
|
|
249
|
+
### Adım 0.5 — Fast Path Check
|
|
250
|
+
|
|
251
|
+
5 koşulun HEPSİ TRUE → \`fmcp-screen-recipes\` Read, recipe uygula:
|
|
252
|
+
1. Tek ekran (multi-screen değil)
|
|
253
|
+
2. Standart tip (login/payment/profile/list/detail/form/onboarding/dashboard/settings)
|
|
254
|
+
3. DS aktif
|
|
255
|
+
4. Platform belli (explicit keyword VEYA önceki intent'ten saved). Yoksa DUR, kullanıcıya sor. Default varsayım YASAK.
|
|
256
|
+
5. Animation/prototype YOK
|
|
257
|
+
|
|
258
|
+
Biri bile FALSE → Karar Akışı'na geç. Recipe kırılırsa da fallback.
|
|
259
|
+
|
|
260
|
+
### Karar Akışı
|
|
261
|
+
|
|
262
|
+
\`\`\`
|
|
263
|
+
1. Intent net mi? EVET → sub-skill / HAYIR → Read fmcp-intent-router
|
|
264
|
+
2. image/figma_benchmark → Read inspiration-intake → structural_intent JSON
|
|
265
|
+
3. figma_execute yazacak mı? EVET → Read figma-canvas-ops
|
|
266
|
+
4. Ana motor → Read generate-figma-screen
|
|
267
|
+
5. build-from-scratch vs clone-to-device
|
|
268
|
+
\`\`\`
|
|
269
|
+
|
|
270
|
+
### DS Fallback Chain
|
|
271
|
+
|
|
272
|
+
1. **DS component instance** — en çok tercih
|
|
273
|
+
2. **DS primitive variant** — yakın variant + setProperties
|
|
274
|
+
3. **Token-bound primitive** — createFrame + tüm fill/padding/radius variable'a bağlı → meşru, ihlal DEĞİL
|
|
275
|
+
4. **Hardcoded shape** → GERÇEK İHLAL, DUR, kullanıcıya bildir
|
|
276
|
+
|
|
277
|
+
### Resmi Figma MCP Yasağı
|
|
278
|
+
|
|
279
|
+
\`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.
|
|
280
|
+
|
|
281
|
+
### Filesystem MCP
|
|
282
|
+
|
|
283
|
+
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.
|
|
284
|
+
|
|
285
|
+
### Self-Audit Gate + Verification
|
|
286
|
+
|
|
287
|
+
\`\`\`
|
|
288
|
+
figma_validate_screen(nodeId=<wrapper_id>, minScore=80)
|
|
289
|
+
\`\`\`
|
|
290
|
+
- \`<80\` → SEVERE violation'ları oku, düzelt, yeniden validate
|
|
291
|
+
- 3 deneme fail → kullanıcıdan rebuild onayı al
|
|
292
|
+
|
|
293
|
+
Teslim öncesi kontrol: validate ≥80, ham shape yok, tüm değerler token'a bağlı, auto-layout eksiksiz, Türkçe rapor + metrikler.
|
|
294
|
+
|
|
295
|
+
### Rapor Formatı
|
|
296
|
+
|
|
297
|
+
\`\`\`markdown
|
|
298
|
+
## 🎨 Ekran Üretimi — <ekran_adı>
|
|
299
|
+
**Mod:** <intake_mode> | **DS:** <active-ds> | **Yaklaşım:** <approach>
|
|
300
|
+
### Sonuç
|
|
301
|
+
<Figma node link>
|
|
302
|
+
📊 Metrikler: skill'ler, API çağrı, cache hit/miss, execute sayısı, validate score
|
|
303
|
+
\`\`\`
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
<!-- figma-canvas-ops (2369 tokens) -->
|
|
310
|
+
---
|
|
311
|
+
name: figma-canvas-ops
|
|
312
|
+
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.
|
|
313
|
+
metadata:
|
|
314
|
+
mcp-server: user-figma-mcp-bridge
|
|
315
|
+
personas:
|
|
316
|
+
- designer
|
|
317
|
+
- designops
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
# Figma Canvas Ops — figma_execute Güvenli Kullanım Kılavuzu
|
|
321
|
+
|
|
322
|
+
## Araç Eşleme (topluluk → F-MCP)
|
|
323
|
+
|
|
324
|
+
| Topluluk | F-MCP Bridge | Not |
|
|
325
|
+
|---|---|---|
|
|
326
|
+
| \`use_figma\` | \`figma_execute\` | JS çalıştırma |
|
|
327
|
+
| \`get_metadata\` | \`figma_get_file_data\` | Yapı/metadata |
|
|
328
|
+
| \`get_screenshot\` | \`figma_capture_screenshot\` | Görsel doğrulama |
|
|
329
|
+
| \`search_design_system\` | \`figma_search_components\` + \`figma_get_design_system_summary\` | İki araç birlikte |
|
|
330
|
+
|
|
331
|
+
## Prerequisites
|
|
332
|
+
|
|
333
|
+
- F-MCP Bridge plugin bağlı olmalı (\`figma_get_status()\`)
|
|
334
|
+
- Aktif DS context: \`.claude/design-systems/active-ds.md\` → \`Status: ✅\`
|
|
335
|
+
|
|
336
|
+
## 0. Design System Context (ZORUNLU)
|
|
337
|
+
|
|
338
|
+
### 0a — Active DS check
|
|
339
|
+
\`\`\`
|
|
340
|
+
1. Read .claude/design-systems/active-ds.md
|
|
341
|
+
2. ✅ Aktif → Library Name not al, 0b'ye geç
|
|
342
|
+
❌ Seçilmedi → 0c'ye geç
|
|
343
|
+
"DS bypass mode" → DS'siz devam
|
|
344
|
+
\`\`\`
|
|
345
|
+
|
|
346
|
+
### 0b — DS asset cache hazırlığı
|
|
347
|
+
\`\`\`
|
|
348
|
+
1. .claude/design-systems/<library-id>/components.md var mı?
|
|
349
|
+
2. .claude/design-systems/<library-id>/tokens.md var mı?
|
|
350
|
+
3. Yoksa: figma_get_library_variables + figma_search_assets ile keşfet, cache'e yaz
|
|
351
|
+
\`\`\`
|
|
352
|
+
|
|
353
|
+
### 0c — Kullanıcıya DS seçimi sor
|
|
354
|
+
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.
|
|
355
|
+
|
|
356
|
+
## 1. Kritik Kurallar
|
|
357
|
+
|
|
358
|
+
1. **\`return\` ile veri dön.** \`figma.closePlugin()\` çağırma.
|
|
359
|
+
|
|
360
|
+
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:
|
|
361
|
+
|
|
362
|
+
| ❌ YASAK (sync) | ✅ ZORUNLU (async) |
|
|
363
|
+
|---|---|
|
|
364
|
+
| \`instance.mainComponent\` | \`await instance.getMainComponentAsync()\` |
|
|
365
|
+
| \`figma.getNodeById(id)\` | \`await figma.getNodeByIdAsync(id)\` |
|
|
366
|
+
| \`figma.variables.importVariableByKey(key)\` | \`await figma.variables.importVariableByKeyAsync(key)\` |
|
|
367
|
+
| \`figma.importComponentByKey(key)\` | \`await figma.importComponentByKeyAsync(key)\` |
|
|
368
|
+
| \`figma.importStyleByKey(key)\` | \`await figma.importStyleByKeyAsync(key)\` |
|
|
369
|
+
| \`node.effectStyleId = x\` | \`await node.setEffectStyleIdAsync(x)\` |
|
|
370
|
+
| \`node.textStyleId = x\` | \`await node.setTextStyleIdAsync(x)\` |
|
|
371
|
+
| \`figma.listAvailableFonts()\` | \`await figma.listAvailableFontsAsync()\` |
|
|
372
|
+
| \`figma.loadFont(...)\` | \`await figma.loadFontAsync(...)\` |
|
|
373
|
+
| \`figma.variables.getVariableCollectionById(id)\` | \`await figma.variables.getVariableCollectionByIdAsync(id)\` |
|
|
374
|
+
|
|
375
|
+
3. **\`figma.notify()\` çalışmaz** — kullanma.
|
|
376
|
+
|
|
377
|
+
4. **\`console.log()\` dönmez** — \`return\` kullan.
|
|
378
|
+
|
|
379
|
+
5. **Küçük adımlarla çalış.** Timeout: varsayılan 15000ms, max 30000ms.
|
|
380
|
+
|
|
381
|
+
### 5a. CHUNKING MANDATE (v2.0)
|
|
382
|
+
|
|
383
|
+
Her \`figma_execute\` **max 15 atomic operation**. Atomic op'lar: node/instance oluşturma, variable/style/component import, font load, bind operasyonu, getNodeByIdAsync, getMainComponentAsync.
|
|
384
|
+
|
|
385
|
+
- 1 execute = 1 mega-goal (discovery, frame+structure, 3-4 component placement)
|
|
386
|
+
- 25+ op → 2-3 execute'a böl
|
|
387
|
+
- Execute arası state: nodeId'leri \`return\` et, sonraki execute \`getNodeByIdAsync\` ile al
|
|
388
|
+
- Her execute sonrası 1 satır Türkçe micro-report
|
|
389
|
+
|
|
390
|
+
6. **Renkler 0–1 aralığında** (0–255 değil). Hardcoded renk YASAK — DS'den oku.
|
|
391
|
+
|
|
392
|
+
7. **Fills/strokes read-only array** — klonla, değiştir, ata:
|
|
393
|
+
\`\`\`js
|
|
394
|
+
const fills = [...node.fills];
|
|
395
|
+
fills[0] = { ...fills[0], color: DS_COLOR };
|
|
396
|
+
node.fills = fills;
|
|
397
|
+
\`\`\`
|
|
398
|
+
|
|
399
|
+
8. **Font yükleme zorunlu.** Sıra: (a) DS cache'ten font oku → (b) Yoksa kullanıcıya sor → (c) "Sen seç" → Inter.
|
|
400
|
+
|
|
401
|
+
**8a-1) Font weight check (ZORUNLU):** \`loadFontAsync\` öncesi \`listAvailableFontsAsync\` ile kontrol et. Fallback helper:
|
|
402
|
+
\`\`\`js
|
|
403
|
+
const allFonts = await figma.listAvailableFontsAsync();
|
|
404
|
+
const styles = allFonts.filter(f => f.fontName.family === "SHBGrotesk").map(f => f.fontName.style);
|
|
405
|
+
function pickStyle(desired, available) {
|
|
406
|
+
if (available.indexOf(desired) >= 0) return desired;
|
|
407
|
+
var fb = { "Medium":["Semi Bold","Regular"], "ExtraBold":["Bold"], "Black":["Bold"], "Thin":["Light","Regular"] };
|
|
408
|
+
var alts = fb[desired] || [];
|
|
409
|
+
for (var i = 0; i < alts.length; i++) { if (available.indexOf(alts[i]) >= 0) return alts[i]; }
|
|
410
|
+
return available.find(s => s.indexOf("Italic") < 0) || available[0];
|
|
411
|
+
}
|
|
412
|
+
await figma.loadFontAsync({ family: "SHBGrotesk", style: pickStyle("Medium", styles) });
|
|
413
|
+
\`\`\`
|
|
414
|
+
**FigJam:** \`createShapeWithText()\` varsayılan "Inter Medium". Metin düzenlemeden önce \`await figma.loadFontAsync(shape.text.fontName)\`.
|
|
415
|
+
|
|
416
|
+
9. **Sayfa konteksti her çağrıda sıfırlanır.** Farklı sayfa: \`await figma.setCurrentPageAsync(page)\`.
|
|
417
|
+
|
|
418
|
+
10. **Tüm tasarım değerleri DS variable'a BAĞLANMALI (ZORUNLU).**
|
|
419
|
+
|
|
420
|
+
Renk, spacing, padding, radius — HİÇBİR değer hardcoded yazılmaz. Token yoksa DURDUR, kullanıcıya sor.
|
|
421
|
+
|
|
422
|
+
**Akış:**
|
|
423
|
+
- **Variable import:** \`const v = await figma.variables.importVariableByKeyAsync("KEY")\`
|
|
424
|
+
- **Renk bind:** \`node.fills = [figma.variables.setBoundVariableForPaint(fills[0], "color", v)]\`
|
|
425
|
+
- **Spacing bind:** \`node.setBoundVariable("paddingLeft", v)\`
|
|
426
|
+
- **Text style:** \`await textNode.setTextStyleIdAsync(style.id)\`
|
|
427
|
+
- **Text renk:** \`textNode.fills = [figma.variables.setBoundVariableForPaint(textFills[0], "color", textColorVar)]\`
|
|
428
|
+
|
|
429
|
+
Hardcoded \`node.fills = [{ type: "SOLID", color: {...} }]\` YASAK.
|
|
430
|
+
|
|
431
|
+
10a. **Inline Bind Verification (v1.9.4, ZORUNLU).** Her execute sonunda oluşturulan node'ları tara. Bind eksikse \`throw\` atılır — execute başarısız sayılır, Claude retry eder. Şablon:
|
|
432
|
+
|
|
433
|
+
\`\`\`js
|
|
434
|
+
// Execute'un sonunda, createdNodes listesini tarayıp bind kontrolü yap:
|
|
435
|
+
function assertBound(node) {
|
|
436
|
+
// Fill bind
|
|
437
|
+
if (Array.isArray(node.fills)) {
|
|
438
|
+
for (var i = 0; i < node.fills.length; i++) {
|
|
439
|
+
var f = node.fills[i];
|
|
440
|
+
if (f && f.visible !== false && f.type === "SOLID") {
|
|
441
|
+
var fbv = node.boundVariables && node.boundVariables.fills;
|
|
442
|
+
var bound = fbv && (Array.isArray(fbv) ? fbv[i] : true);
|
|
443
|
+
if (!bound) throw new Error("UNBOUND_FILL: " + node.name + " — setBoundVariableForPaint cagrisi eksik");
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
// Padding/itemSpacing/radius bind (auto-layout frame)
|
|
448
|
+
if (node.type === "FRAME" || node.type === "COMPONENT") {
|
|
449
|
+
var padProps = ["paddingTop","paddingBottom","paddingLeft","paddingRight"];
|
|
450
|
+
for (var j = 0; j < padProps.length; j++) {
|
|
451
|
+
var p = padProps[j];
|
|
452
|
+
if (typeof node[p] === "number" && node[p] > 0 && !(node.boundVariables && node.boundVariables[p])) {
|
|
453
|
+
throw new Error("UNBOUND_PADDING: " + node.name + "." + p + "=" + node[p] + " — setBoundVariable cagrisi eksik");
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (typeof node.itemSpacing === "number" && node.itemSpacing > 0 && !(node.boundVariables && node.boundVariables.itemSpacing)) {
|
|
457
|
+
throw new Error("UNBOUND_ITEMSPACING: " + node.name + " — setBoundVariable('itemSpacing', v) cagrisi eksik");
|
|
458
|
+
}
|
|
459
|
+
var radProps = ["cornerRadius","topLeftRadius","topRightRadius","bottomLeftRadius","bottomRightRadius"];
|
|
460
|
+
for (var k = 0; k < radProps.length; k++) {
|
|
461
|
+
var r = radProps[k];
|
|
462
|
+
if (typeof node[r] === "number" && node[r] > 0 && !(node.boundVariables && node.boundVariables[r])) {
|
|
463
|
+
throw new Error("UNBOUND_RADIUS: " + node.name + "." + r + "=" + node[r]);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
// Text style
|
|
468
|
+
if (node.type === "TEXT" && !(node.textStyleId && typeof node.textStyleId === "string" && node.textStyleId !== "")) {
|
|
469
|
+
throw new Error("UNBOUND_TEXTSTYLE: '" + (node.characters||"").slice(0,30) + "' — setTextStyleIdAsync(style.id) cagrisi eksik");
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Tüm oluşturulan node'ları doğrula:
|
|
474
|
+
for (var n = 0; n < createdNodes.length; n++) assertBound(createdNodes[n]);
|
|
475
|
+
\`\`\`
|
|
476
|
+
|
|
477
|
+
Bu kontrol atlanırsa \`figma_scan_ds_compliance\` final gate'te sonuç zaten BLOCKING olur — ama inline check erkendedir ve context'i az yer. **v1.9.4 önerisi:** Her mega-step sonunda bu assertion bloğunu execute'un sonuna koy.
|
|
478
|
+
|
|
479
|
+
11. **appendChild sıralaması kritik.** ÖNCE \`parent.appendChild(child)\`, SONRA \`child.layoutSizingHorizontal = "FILL"\` / \`layoutPositioning = "ABSOLUTE"\`:
|
|
480
|
+
\`\`\`js
|
|
481
|
+
parent.appendChild(child); // ÖNCE
|
|
482
|
+
child.layoutSizingHorizontal = "FILL"; // SONRA
|
|
483
|
+
\`\`\`
|
|
484
|
+
Hata: "Can only set layoutPositioning = ABSOLUTE if parent has layoutMode !== NONE" → child append edilmemiş.
|
|
485
|
+
|
|
486
|
+
12. **Yeni node'ları (0,0)'dan uzağa konumlandır.** Boş alan bul.
|
|
487
|
+
|
|
488
|
+
13. **Hata durumunda DUR.** Hata oku, düzelt, tekrar çalıştır. Atomik — hata olursa değişiklik uygulanmaz.
|
|
489
|
+
|
|
490
|
+
14. **Tüm node ID'lerini RETURN ET:** \`return { createdNodeIds: [...] }\`
|
|
491
|
+
|
|
492
|
+
15. **Variable scope'ları:** Arka plan: \`["FRAME_FILL"]\`, Metin: \`["TEXT_FILL"]\`, Boşluk: \`["GAP"]\`
|
|
493
|
+
|
|
494
|
+
16. **Her Promise'i \`await\` et.**
|
|
495
|
+
|
|
496
|
+
17. **v1.9.5 Concise Query Rule — tek satır boyut/metadata sorguları.**
|
|
497
|
+
|
|
498
|
+
Boyut, renk, layout sorgulamak için **20+ satır JS YAZMA**. Tek satır yeter:
|
|
499
|
+
|
|
500
|
+
\`\`\`js
|
|
501
|
+
// İYİ — tek satır, minimal context
|
|
502
|
+
return await figma.getNodeByIdAsync(id).then(n => ({ w: n.width, h: n.height, children: n.children?.length }));
|
|
503
|
+
|
|
504
|
+
// İYİ — toplu (birden fazla node)
|
|
505
|
+
return Promise.all(ids.map(async id => {
|
|
506
|
+
const n = await figma.getNodeByIdAsync(id);
|
|
507
|
+
return { id, name: n?.name, size: n ? [n.width, n.height] : null };
|
|
508
|
+
}));
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
<!-- fmcp-screen-recipes (2092 tokens) -->
|
|
513
|
+
---
|
|
514
|
+
name: fmcp-screen-recipes
|
|
515
|
+
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.
|
|
516
|
+
metadata:
|
|
517
|
+
mcp-server: user-figma-mcp-bridge
|
|
518
|
+
version: 3.0.0
|
|
519
|
+
priority: 96
|
|
520
|
+
phase: fast-path
|
|
521
|
+
personas:
|
|
522
|
+
- designer
|
|
523
|
+
- uidev
|
|
524
|
+
token_budget: condensed-first
|
|
525
|
+
required_inputs:
|
|
526
|
+
- name: screen_type
|
|
527
|
+
type: "enum: login | payment | profile | list | detail | form | onboarding | dashboard | settings"
|
|
528
|
+
- name: platform
|
|
529
|
+
type: "enum: mobile | tablet | desktop | web"
|
|
530
|
+
- name: device_preset
|
|
531
|
+
type: string
|
|
532
|
+
- name: variants
|
|
533
|
+
type: "array: [light] | [light, dark]"
|
|
534
|
+
- name: active_ds
|
|
535
|
+
type: string
|
|
536
|
+
outputs:
|
|
537
|
+
- name: light_frame_id
|
|
538
|
+
type: string
|
|
539
|
+
- name: dark_frame_id
|
|
540
|
+
type: "string | null"
|
|
541
|
+
- name: validate_scores
|
|
542
|
+
type: "{ light: number, dark: number | null }"
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
# FMCP Screen Recipes — Fast Path Cookbook
|
|
546
|
+
|
|
547
|
+
## Ne Zaman Kullanılır
|
|
548
|
+
|
|
549
|
+
**Fast Path DEVREYE GİRER** (hepsi TRUE olmalı):
|
|
550
|
+
- ✅ Tek ekran üretimi
|
|
551
|
+
- ✅ Standart ekran tipi: 9 recipe'ten biri match ediyor
|
|
552
|
+
- ✅ DS tanımlı: \`active-ds.md\` Status: ✅ Aktif
|
|
553
|
+
- ✅ Platform belli
|
|
554
|
+
- ✅ Custom animation / prototype YOK
|
|
555
|
+
|
|
556
|
+
**Devreye GİRMEZ:** Multi-screen flow, custom layout, animation, explicit generate-figma-screen talebi, DS GATE geçilmemişse.
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## 5 Mega-Adımlı Akış
|
|
561
|
+
|
|
562
|
+
Max **15 op/execute**. Her mega-adım sonrası tek satır Türkçe micro-report.
|
|
563
|
+
|
|
564
|
+
\`\`\`
|
|
565
|
+
M1: Pre-Flight Discovery + Token + Text Style (1 execute, ~15 op)
|
|
566
|
+
M2: Frame + Structure + Modes (1 execute, ~12-14 op)
|
|
567
|
+
M3: Component Placement (toplu, 3-4/execute) (2-3 execute, ~12-15 op each)
|
|
568
|
+
↳ Her M3 execute sonrası: figma_scan_ds_compliance(threshold=85) inline gate
|
|
569
|
+
M4: Dark Variant (1 execute, ~4 op)
|
|
570
|
+
M5: Validate + Final Report (ZORUNLU: figma_scan_ds_compliance(detailed) + figma_validate_screen)
|
|
571
|
+
\`\`\`
|
|
572
|
+
|
|
573
|
+
**Toplam execute:** ~6-8 + 2-3 scan call. **Hedef süre:** ~10 dk. **v1.9.4:** Scan call'ları hızlıdır (~150ms), execute bütçesini yemezler.
|
|
574
|
+
|
|
575
|
+
### 3 MUTLAK KURAL
|
|
576
|
+
|
|
577
|
+
**KURAL 1 — Fill Bind Zorunlu (frame + text dahil):**
|
|
578
|
+
\`\`\`js
|
|
579
|
+
const paint = { type: 'SOLID', color: { r: 1, g: 1, b: 1 } };
|
|
580
|
+
const bound = figma.variables.setBoundVariableForPaint(paint, 'color', dsColorVar);
|
|
581
|
+
node.fills = [bound];
|
|
582
|
+
\`\`\`
|
|
583
|
+
Fill panel'de variable icon 🎨 GÖRÜNMELI. Hardcoded hex YASAK. Frame fill + text fill + primitive dahil TÜM node'lar.
|
|
584
|
+
|
|
585
|
+
**KURAL 2 — Variant Seçim: DEFAULT Koru:**
|
|
586
|
+
- \`setProperties\` ile SADECE recipe'de explicit belirtilen property'leri set et
|
|
587
|
+
- Diğer TÜM property'leri DEFAULT bırak
|
|
588
|
+
- \`Product\` → main (default), Boolean kontroller → recipe'de explicit yoksa DEFAULT
|
|
589
|
+
|
|
590
|
+
**KURAL 3 — Token Bind, Alias Resolve ETME:**
|
|
591
|
+
\`setBoundVariable(property, importedVariable)\` ile bind et. Figma runtime alias chain'i otomatik çözer. \`valuesByMode\` okuma, alias traversal YASAK (timeout riski).
|
|
592
|
+
|
|
593
|
+
### Mega-Adım Mapping
|
|
594
|
+
|
|
595
|
+
Aşağıdaki eski adımlar REFERANS amaçlıdır. AYRI AYRI execute ETME — mega-adım tablosunu takip et:
|
|
596
|
+
- **M1:** Adım 1 (validation) + 1.5 (discovery) + 1.6 (text style) → TEK execute
|
|
597
|
+
- **M2:** Adım 2 (frame) + 4b (mode) + 5.5 (content body) → TEK execute
|
|
598
|
+
- **M3:** Adım 6 (discovery) + 7 (placement) → 2-3 execute
|
|
599
|
+
- **M4:** Adım 8 (dark) → TEK execute
|
|
600
|
+
- **M5:** Adım 9 (validate) → 1-2 validate call
|
|
601
|
+
|
|
602
|
+
---
|
|
603
|
+
|
|
604
|
+
### Adım 1 — Pre-Flight Check
|
|
605
|
+
|
|
606
|
+
Hiçbir figma_execute çağırma. Doğrula: active-ds.md ✅, screen_type geçerli, platform + device_preset geçerli, variants ≥1.
|
|
607
|
+
|
|
608
|
+
**Micro-report:** \`✅ Pre-flight: screen_type=<X>, platform=<Y>, device=<Z>, variants=<V>\`
|
|
609
|
+
|
|
610
|
+
### Adım 1.5 — Unified Pre-Flight Discovery
|
|
611
|
+
|
|
612
|
+
**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.
|
|
613
|
+
|
|
614
|
+
Token name matching: SUI nested path formatı (\`"Spacing/spacing-100"\`). \`endsWith\` match kullan:
|
|
615
|
+
\`\`\`js
|
|
616
|
+
vars.find(v => v.name.endsWith("/" + suffix) || v.name === suffix)
|
|
617
|
+
\`\`\`
|
|
618
|
+
|
|
619
|
+
#### Execute 1 — Collection & Mode Discovery (7 op)
|
|
620
|
+
|
|
621
|
+
\`\`\`js
|
|
622
|
+
const colls = await figma.teamLibrary.getAvailableLibraryVariableCollectionsAsync();
|
|
623
|
+
function findColl(keywords) {
|
|
624
|
+
return colls.find(c => {
|
|
625
|
+
const n = c.name.toLowerCase().trim();
|
|
626
|
+
return keywords.some(kw => n.includes(kw));
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
const sizeColl = findColl(["semantic size", "semantic sizes", "size"]);
|
|
630
|
+
const colorsColl = findColl(["semantic color", "s theme"]);
|
|
631
|
+
const result = { availableColls: colls.map(c => ({name: c.name, key: c.key})), spacingTokenKeys: {}, collectionInfo: { colors: null, size: null }, surfaceKey: null };
|
|
632
|
+
|
|
633
|
+
if (sizeColl) {
|
|
634
|
+
const sizeVars = await figma.teamLibrary.getVariablesInLibraryCollectionAsync(sizeColl.key);
|
|
635
|
+
const suffixes = ["spacing-none","spacing-050","spacing-075","spacing-100","spacing-125","spacing-150","spacing-200"];
|
|
636
|
+
for (const s of suffixes) {
|
|
637
|
+
const f = sizeVars.find(v => v.name.endsWith("/"+s) || v.name === s);
|
|
638
|
+
if (f) result.spacingTokenKeys[s] = f.key;
|
|
639
|
+
}
|
|
640
|
+
if (sizeVars.length > 0) {
|
|
641
|
+
const first = await figma.variables.importVariableByKeyAsync(sizeVars[0].key);
|
|
642
|
+
const coll = await figma.variables.getVariableCollectionByIdAsync(first.variableCollectionId);
|
|
643
|
+
result.collectionInfo.size = { collId: coll.id, modes: coll.modes.map(m => ({name: m.name, modeId: m.modeId})) };
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
if (colorsColl) {
|
|
647
|
+
const colorsVars = await figma.teamLibrary.getVariablesInLibraryCollectionAsync(colorsColl.key);
|
|
648
|
+
const bgVar = colorsVars.find(v => v.name.toLowerCase().includes("background") && v.name.toLowerCase().includes("level-0"));
|
|
649
|
+
if (bgVar) result.surfaceKey = bgVar.key;
|
|
650
|
+
if (colorsVars.length > 0) {
|
|
651
|
+
const first = await figma.variables.importVariableByKeyAsync(colorsVars[0].key);
|
|
652
|
+
const coll = await figma.variables.getVariableCollectionByIdAsync(first.variableCollectionId);
|
|
653
|
+
result.collectionInfo.colors = { collId: coll.id, modes: coll.modes.map(m => ({name: m.name, modeId: m.modeId})) };
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return result;
|
|
657
|
+
\`\`\`
|
|
658
|
+
|
|
659
|
+
#### Execute 2 — Critical Token Import (7 op)
|
|
660
|
+
|
|
661
|
+
\`\`\`js
|
|
662
|
+
const tokenKeyMap = {};
|
|
663
|
+
const spacingKeys = { /* Execute 1'den gelen spacingTokenKeys */ };
|
|
664
|
+
for (const [suffix, key] of Object.entries(spacingKeys)) {
|
|
665
|
+
try {
|
|
666
|
+
const imported = await figma.variables.importVariableByKeyAsync(key);
|
|
667
|
+
tokenKeyMap[suffix] = imported.id;
|
|
668
|
+
} catch(e) {}
|
|
669
|
+
}
|
|
670
|
+
return { tokenKeyMap };
|
|
671
|
+
\`\`\`
|
|
672
|
+
|
|
673
|
+
**Micro-report:** \`✅ Pre-Flight Discovery: <N> collection, <M> token imported, surface=<found/missing>\`
|
|
674
|
+
|
|
675
|
+
### Adım 1.6 — Text Style Resolution
|
|
676
|
+
|
|
677
|
+
Dosyadaki mevcut text style'ları tara, role mapping üret. \`importStyleByKeyAsync\` ÇAĞIRMA — direkt \`setTextStyleIdAsync(roleMap[role].id)\` kullan.
|
|
678
|
+
|
|
679
|
+
\`\`\`js
|
|
680
|
+
const allTexts = figma.currentPage.findAll(n => n.type === "TEXT");
|
|
681
|
+
const uniqueStyleIds = new Set();
|
|
682
|
+
for (const t of allTexts) { if (t.textStyleId && typeof t.textStyleId === 'string') uniqueStyleIds.add(t.textStyleId); }
|
|
683
|
+
|
|
684
|
+
const styleMap = {};
|
|
685
|
+
for (const id of uniqueStyleIds) {
|
|
686
|
+
try { const style = await figma.getStyleByIdAsync(id); if (style) styleMap[style.id] = { id: style.id, name: style.name, fontSize: style.fontSize || null }; } catch(e) {}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
const roleKeywords = {
|
|
690
|
+
display: ["display","hero","amount","title-xl"], title: ["section-title","title","heading"],
|
|
691
|
+
subtitle: ["subtitle","body-semibold","body-bold"], body: ["body-medium","body-regular","body"],
|
|
692
|
+
caption: ["small","caption","footnote"], button: ["button"]
|
|
693
|
+
};
|
|
694
|
+
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; }
|
|
695
|
+
const roleMap = {};
|
|
696
|
+
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 }; }
|
|
697
|
+
if (!roleMap.display) {
|
|
698
|
+
const sorted = Object.values(styleMap).filter(s => s.fontSize).sort((a,b) => b.fontSize - a.fontSize);
|
|
699
|
+
if (sorted.length > 0) roleMap.display = { id: sorted[0].id, name: sorted[0].name, fontSize: sorted[0].fontSize };
|
|
700
|
+
}
|
|
701
|
+
return { totalStyles: Object.keys(styleMap).length, styleMap, roleMap };
|
|
702
|
+
\`\`\`
|
|
703
|
+
|
|
704
|
+
**Micro-report:** \`✅ Text Style: <N> style, <M> role eşleşti\`
|
|
705
|
+
|
|
706
|
+
---
|
|
707
|
+
|
|
708
|
+
### Adım 2 — Wrapper Frame + Background (Edge-to-Edge)
|
|
709
|
+
|
|
710
|
+
Ana frame: device preset boyutu, auto-layout VERTICAL, padding=0, gap=0, background DS variable'a bağlı.
|
|
711
|
+
|
|
712
|
+
**Edge-to-Edge yapı:**
|
|
713
|
+
|
|
714
|
+
---
|
|
715
|
+
|
|
716
|
+
<!-- fmcp-project-rules (1370 tokens) -->
|
|
717
|
+
---
|
|
718
|
+
name: fmcp-project-rules
|
|
719
|
+
description: F-MCP Bridge kullanım kuralları — Design Token Kuralı, Bağlı Token Kuralı, kütüphane yönetimi, otomatik yanıt kuralları. Tüm F-MCP skill'leri için geçerli temel kurallar. Her Figma işleminde bu kurallar otomatik olarak geçerlidir.
|
|
720
|
+
metadata:
|
|
721
|
+
mcp-server: user-figma-mcp-bridge
|
|
722
|
+
personas:
|
|
723
|
+
- designer
|
|
724
|
+
- designops
|
|
725
|
+
- uidev
|
|
726
|
+
- po
|
|
727
|
+
---
|
|
728
|
+
|
|
729
|
+
# F-MCP Temel Kurallar
|
|
730
|
+
|
|
731
|
+
Bu skill, tüm F-MCP skill'leri ve komutları için geçerli olan temel kuralları tanımlar. Her Figma işleminde bu kurallar otomatik olarak uygulanır.
|
|
732
|
+
|
|
733
|
+
## Kullanıcı İstekleri — Otomatik Yanıt
|
|
734
|
+
|
|
735
|
+
### "F-MCP'yi güncelle" / "update" / "güncelle"
|
|
736
|
+
Terminal komutu verme. \`bash scripts/update.sh\` çalıştır, sonucu bildir:
|
|
737
|
+
> Güncelleme tamamlandı (vX.Y.Z). Claude'u yeniden başlat ve Figma'da plugin'i kapat-aç.
|
|
738
|
+
|
|
739
|
+
### "F-MCP'yi kur" / "setup" / "kur" / "bunu kur" / GitHub linki verildi
|
|
740
|
+
Kullanıcı GitHub linki (github.com/atezer/FMCP) verip "kur" derse veya herhangi bir şekilde kurulum isterse:
|
|
741
|
+
|
|
742
|
+
1. Repo zaten clone edilmişse: \`bash scripts/setup.sh\` çalıştır
|
|
743
|
+
2. Repo clone edilmemişse: \`git clone https://github.com/atezer/FMCP.git && cd FMCP && bash scripts/setup.sh\`
|
|
744
|
+
3. Kullanıcıya sadece sonucu bildir.
|
|
745
|
+
|
|
746
|
+
Kullanıcıya ASLA terminal komutu söyleme, teknik adım açıklama. Her şeyi sen yap.
|
|
747
|
+
|
|
748
|
+
### Dil
|
|
749
|
+
Kullanıcı Türkçe konuşuyor. Tüm dosyalarda Türkçe karakterler (ş, ç, ğ, ö, ü, ı, İ) doğru kullanılmalı.
|
|
750
|
+
|
|
751
|
+
---
|
|
752
|
+
|
|
753
|
+
## Design System Kütüphaneleri
|
|
754
|
+
|
|
755
|
+
Kullanıcı lokal olarak design system kütüphaneleri kaydedebilir. Kayıtlı kütüphaneler \`.claude/libraries/\` dizininde bulunur.
|
|
756
|
+
|
|
757
|
+
### Kullanım kuralları
|
|
758
|
+
|
|
759
|
+
1. **Skill çalıştırmadan önce** \`.claude/libraries/\` dizinini kontrol et. Kayıtlı kütüphane varsa oku.
|
|
760
|
+
2. **Varsayılan kütüphane:** Kullanıcı "hangi kütüphane?" demişse veya context'ten anlaşılamıyorsa, kayıtlı kütüphanelerden ilkini kullan.
|
|
761
|
+
3. **Figma file key'leri** kütüphane dosyasındaki tablolardan al — URL'den parse etme, doğrudan \`File Key\` alanını kullan.
|
|
762
|
+
4. **Token okuma** her zaman kütüphanenin WEB/ana dosyasından yapılır.
|
|
763
|
+
5. **Platform seçimi:** Web ekranı → WEB dosyası, Mobil ekran → Mobil dosyası (yoksa WEB fallback).
|
|
764
|
+
|
|
765
|
+
---
|
|
766
|
+
|
|
767
|
+
## Design Token Kuralı (TÜM skill'ler için geçerli — ZORUNLU)
|
|
768
|
+
|
|
769
|
+
Hiçbir skill gömülü/hardcoded design token değeri içeremez ve kullanamaz. Font ailesi, renk kodu, font boyutu, spacing, radius, gölge — hiçbir tasarım değeri skill içine yazılmaz.
|
|
770
|
+
|
|
771
|
+
**Her tasarım değeri çalışma anında tasarım sisteminden okunur:**
|
|
772
|
+
|
|
773
|
+
1. **Önce kayıtlı kütüphaneyi oku:** \`.claude/libraries/\` dizinindeki kütüphane dosyasını kontrol et. Font ailesi, variable collection'lar ve style listesi orada.
|
|
774
|
+
2. **Canlı değerleri Figma'dan al:**
|
|
775
|
+
- **Kütüphane variable'ları (renkler, spacing)** → \`figma_get_library_variables()\` veya \`figma_execute\` ile \`figma.teamLibrary.getAvailableLibraryVariableCollectionsAsync()\` + \`getVariablesInLibraryCollectionAsync()\` — DS dosyasına bağlanmak GEREKMEZ, hedef dosyadan çalışır
|
|
776
|
+
- **Lokal variable'lar** → \`figma_get_variables()\` — sadece dosya içi değerler
|
|
777
|
+
- **Lokal stiller** → \`figma_get_styles()\` — sadece dosya içi stiller
|
|
778
|
+
- **Kütüphane text style'ları** → cache'den key al, \`figma.importStyleByKeyAsync(key)\` ile import et. Cache yoksa REST API: \`figma_rest_api GET /v1/files/{fileKey}/styles\`
|
|
779
|
+
- Font → kütüphane text style'larından veya kütüphanenin \`Font Ailesi\` alanından
|
|
780
|
+
- Gölgeler → \`figma_get_styles()\` effect style'larından veya kütüphane cache'inden
|
|
781
|
+
3. **Bulunamazsa kullanıcıya sor.**
|
|
782
|
+
4. **Kullanıcı "sen seç" derse:** Önce DS kütüphanesi bağlıysa DS fontunu kullan (text style'lardan çıkar). DS fontu bulunamadıysa \`Inter\`, renkler için Figma varsayılanları kullan.
|
|
783
|
+
|
|
784
|
+
**ÖNEMLİ:** \`figma_get_styles()\` ve \`figma_get_variables()\` sadece dosya İÇİ (local) değerleri döndürür. Team library'den gelen token'lar için \`figma_get_library_variables\` veya \`figma.teamLibrary\` API'si kullanılmalıdır.
|
|
785
|
+
|
|
786
|
+
**Skill'lerdeki kod örnekleri:** Örneklerde geçen değerler (renk hex, font adı, piksel boyutu) yalnızca FORMAT gösterimidir. Çalışma anında bu değerler her zaman tasarım sisteminden okunmalıdır.
|
|
787
|
+
|
|
788
|
+
---
|
|
789
|
+
|
|
790
|
+
## Bağlı Token Kuralı (ZORUNLU — tüm ekran/bileşen oluşturma işlemlerinde)
|
|
791
|
+
|
|
792
|
+
Figma'da oluşturulan hiçbir node'da **bağlanmamış (unbound) tasarım değeri** bulunmamalıdır. Her renk, spacing, padding, radius ve metin stili DS variable'ına veya text style'ına **bağlı (bound)** olmalıdır.
|
|
793
|
+
|
|
794
|
+
- **Renk (fill/stroke):** \`figma.variables.importVariableByKeyAsync(key)\` ile import et, \`setBoundVariableForPaint()\` ile bağla
|
|
795
|
+
- **Spacing/padding/radius/gap:** \`setBoundVariable("paddingLeft", variable)\` ile bağla
|
|
796
|
+
- **Metin stili:** \`setTextStyleIdAsync(styleId)\` ile DS text style'ını uygula
|
|
797
|
+
- **Metin rengi:** Text node fill'ini \`setBoundVariableForPaint()\` ile bağla
|
|
798
|
+
|
|
799
|
+
**Hardcoded değer kabul edilmez.** \`node.fills = [{ type: "SOLID", color: {r,g,b} }]\` veya \`node.fontSize = 16\` gibi doğrudan değer atamaları YASAKTIR. Tüm değerler DS'ten import edilip bağlanmalıdır.
|
|
800
|
+
|
|
801
|
+
Detaylı API kullanımı: \`figma-canvas-ops\` skill'inin **madde 10** bölümüne bak.
|
|
802
|
+
|
|
803
|
+
---
|
|
804
|
+
|
|
805
|
+
## Mevcut kütüphaneler
|
|
806
|
+
|
|
807
|
+
Kayıtlı kütüphaneleri görmek için \`.claude/libraries/\` dizinini kontrol et. Her \`.md\` dosyası bir kütüphanedir. Kütüphane eklemek için \`/add-library\` komutunu kullan.
|
|
808
|
+
|
|
809
|
+
## Evolution Triggers
|
|
810
|
+
|
|
811
|
+
- Yeni DS kural kategorisi eklendiğinde bu skill güncellenmelidir.
|
|
812
|
+
- Yeni platform desteği (Flutter, React Native vb.) eklendiğinde platform seçimi kuralları genişletilmelidir.
|
|
813
|
+
- Kullanıcı geri bildirimine göre otomatik yanıt kuralları güncellenmelidir.`;
|
|
814
|
+
export const EMBEDDED_SKILLS_TOKEN_ESTIMATE = 9349;
|
|
815
|
+
export const EMBEDDED_SKILLS_VERSION = "1.9.7";
|
|
816
|
+
export const EMBEDDED_SKILLS_GENERATED_AT = "2026-04-18T08:23:36.324Z";
|
|
817
|
+
//# sourceMappingURL=embedded-skills.js.map
|