agentleFS
atezeratezer/FMCP/skills/figma-a11y-audit/SKILL.md

figma-a11y-audit

Skill10 starsChanged 29 days agoMITView on GitHub

Figma ekranını erişilebilirlik açısından denetler. Renk kontrastı (WCAG AA/AAA), minimum dokunma hedefi, fokus sırası, metin boyutu ve platform-bazlı ekran okuyucu önerileri (VoiceOver, TalkBack, ARIA) üretir. "a11y audit", "erişilebilirlik kontrol", "kontrast kontrol", "accessibility check", "ekran okuyucu spec", "WCAG kontrol" ifadeleriyle tetiklenir. F-MCP Bridge plugin bağlantısı gerektirir.

The file

Files
SKILL.md

Figma A11y Audit — Erişilebilirlik Denetimi

Kullanım (v3.1+): SADECE fmcp-ds-audit-orchestrator alt-skill'i olarak a11y deep-dive için çağrılır. Doğrudan entry point DEĞİL. Kullanıcı "a11y kontrol et" dediğinde önce orchestrator yüklenir.

Design Token Kuralı: Bu skill'deki kod örneklerinde geçen font adları, renk kodları, piksel boyutları yalnızca FORMAT gösterimidir. Çalışma anında tüm design token değerleri (font, renk, boyut, spacing, radius, gölge) kayıtlı kütüphaneden (figma_get_variables, figma_get_styles) veya kullanıcıdan okunmalıdır. Hardcoded token değeri kullanma. Detay: project-context.md → "Design Token Kuralı".

Overview

Bu skill, Figma ekranını erişilebilirlik (a11y) standartlarına göre denetler. Platform-bazlı (iOS VoiceOver, Android TalkBack, Web ARIA) raporlar üretir. Topluluk "Uber a11y ekran okuyucu spesifikasyonları" örneğinden esinlenilmiştir.

Okuma + Yazma — Denetim sonuçlarını okur, isteğe bağlı olarak annotation frame ekler.

Prerequisites

  • F-MCP Bridge plugin bağlı olmalı
  • Hedef ekranın node ID'si veya URL'i bilinmeli

F-MCP skill koordinasyonu

  • Önce (isteğe bağlı): audit-figma-design-system (DS uyum denetimi) — a11y audit'ten bağımsız ama birlikte değerli
  • Sonra: Bulgular varsa fix-figma-design-system-finding veya apply-figma-design-system ile düzeltme; kod tarafında implement-design çıktısında a11y attribute'ları
  • İlişkili: generate-figma-library Faz 4 (a11y denetimi) bu skill'i referans alır

WCAG 2.1/2.2 AA Hızlı Referans

Denetim sırasında bu 4 prensip ve 12 kriter referans alınmalıdır:

Algılanabilir (Perceivable)

  • 1.1.1 Metin Dışı İçerik: Görseller, ikonlar ve dekoratif öğeler için alternatif metin veya aria-hidden
  • 1.3.1 Bilgi ve İlişkiler: Başlık hiyerarşisi (H1→H2→H3), form etiketleri, tablo başlıkları programatik olarak belirlenmeli
  • 1.4.3 Kontrast (Minimum): Normal metin ≥4.5:1, büyük metin (≥18px veya ≥14px bold) ≥3:1
  • 1.4.11 Metin Dışı Kontrast: UI bileşenleri (buton kenarları, input border, ikon) ve grafik öğeleri ≥3:1 — sadece metin değil!

İşletilebilir (Operable)

  • 2.1.1 Klavye: Tüm işlevsellik klavyeyle erişilebilir olmalı
  • 2.4.3 Odak Sırası: Fokus sırası mantıksal ve anlamlı olmalı (görsel sırayla tutarlı)
  • 2.4.7 Görünür Odak: Klavye fokus göstergesi açıkça görünür olmalı (ör. 2px solid ring, minimum 3:1 kontrast)
  • 2.5.5 Dokunma Hedefi (WCAG 2.2): Tıklanabilir/dokunulabilir öğeler ≥44×44 CSS px (WCAG 2.2: ≥24×24 CSS px minimum)

Anlaşılabilir (Understandable)

  • 3.1.1 Sayfa Dili: İçerik dili tanımlanmalı (lang attribute)
  • 3.2.1 Fokusta Tahmin Edilebilirlik: Bir öğeye odaklanmak beklenmeyen davranış tetiklememeli (ör. otomatik form submit)
  • 3.3.1 Hata Tanımlama: Hata tespit edildiğinde kullanıcıya metin olarak açıkça bildirilmeli
  • 3.3.2 Etiketler veya Talimatlar: Form alanlarında açık etiket ve gerektiğinde yardım metni

Sağlam (Robust)

  • 4.1.2 Ad, Rol, Değer: Tüm UI bileşenlerinin adı (label), rolü (role) ve durumu (state) programatik olarak belirlenebilir olmalı

Yaygın Sorunlar Kontrol Listesi

Denetimde sıkça karşılaşılan 8 sorun — her biri Step 4-8'de kontrol edilmelidir:

  1. Yetersiz renk kontrastı — metin/arka plan oranı WCAG AA'yı karşılamıyor
  2. Eksik form etiketleri — placeholder tek başına etiket yerine geçmez
  3. Klavye erişimi yok — fare olmadan ulaşılamayan etkileşimli öğeler
  4. Alt text eksik — bilgi taşıyan görsellerde alternatif metin yok
  5. Focus trap hatalı — modal/drawer'da odak tuzağı eksik veya bozuk
  6. ARIA landmark eksik — sayfa bölümleri (nav, main, footer) işaretlenmemiş
  7. Otomatik oynatılan medya — ses/video otomatik başlıyor, durdurma kontrolü yok
  8. Zaman limitleri — oturum zaman aşımı uzatma seçeneği sunulmuyor

Test Yaklaşımı Sırası

A11y denetimi aşağıdaki sırayla yürütülmelidir:

AşamaNe Yapılırİlgili Step
1. Otomatik taramaKontrast hesaplama, dokunma hedefi boyutu, metin boyutuStep 4, 5, 6
2. Klavye-only navigasyonFokus sırası, görünür fokus göstergesi, focus trapStep 7c, 7e
3. Ekran okuyucu testiBaşlık hiyerarşisi, form ilişkilendirme, alt textStep 7a, 7b, 7d
4. Kontrast doğrulamaGradient/overlay kaçırılanlar, UI bileşen kontrastıScreenshot kontrolü
5. %200 zoom testiİçerik kaybı, yatay kaydırma oluşmamalıResponsive kontrol

Required Workflow

Step 1: Plugin Bağlantısını Doğrula

figma_get_status()

Step 2: Hedef Ekranı Belirle

Figma URL veya node ID. node-id=72-293 → 72:293 normalize et.

Step 3: Yapı ve Görsel Veri Topla

figma_get_design_context(
  nodeId="<NODE_ID>",
  depth=2,
  verbosity="full",
  includeLayout=true,
  includeVisual=true,
  includeTypography=true
)
figma_capture_screenshot(nodeId="<NODE_ID>")
figma_get_design_context(nodeId="<NODE_ID>", depth=3)

Step 4: Kontrast Analizi

figma_execute ile renk çiftlerini çıkar ve kontrast oranı hesapla:

function luminance(r, g, b) {
  const [rs, gs, bs] = [r, g, b].map(c =>
    c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)
  );
  return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
}

function contrastRatio(l1, l2) {
  const lighter = Math.max(l1, l2);
  const darker = Math.min(l1, l2);
  return (lighter + 0.05) / (darker + 0.05);
}

const root = await figma.getNodeByIdAsync("<NODE_ID>");
const textNodes = root.findAll(n => n.type === "TEXT");
const results = [];

for (const node of textNodes.slice(0, 50)) {
  if (!node.fills || !node.fills.length) continue;
  const fill = node.fills[0];
  if (fill.type !== "SOLID") continue;

  let parent = node.parent;
  let bgColor = null;
  while (parent && !bgColor) {
    if (parent.fills && parent.fills.length) {
      const pFill = parent.fills[0];
      if (pFill.type === "SOLID") bgColor = pFill.color;
    }
    parent = parent.parent;
  }
  if (!bgColor) bgColor = { r: 1, g: 1, b: 1 };

  const ratio = contrastRatio(
    luminance(fill.color.r, fill.color.g, fill.color.b),
    luminance(bgColor.r, bgColor.g, bgColor.b)
  );

  const fontSize = node.fontSize;
  const isLarge = fontSize >= 18 || (fontSize >= 14 && node.fontWeight >= 700);
  const passAA = isLarge ? ratio >= 3 : ratio >= 4.5;
  const passAAA = isLarge ? ratio >= 4.5 : ratio >= 7;

  if (!passAA) {
    results.push({
      nodeId: node.id,
      name: node.name,
      ratio: Math.round(ratio * 100) / 100,
      required: isLarge ? 3 : 4.5,
      level: "FAIL_AA",
      fontSize
    });
  }
}

return { contrastIssues: results, totalTextNodes: textNodes.length };

Step 5: Dokunma Hedefi Kontrolü (WCAG 2.5.5)

Referans: WCAG 2.5.5 Target Size — iOS HIG: 44×44pt, Android Material: 48×48dp, Web WCAG 2.2: min 24×24 CSS px

const interactiveTypes = ["INSTANCE", "FRAME"];
const interactiveNames = /button|btn|link|input|toggle|switch|checkbox|radio|tab|chip/i;

const root = await figma.getNodeByIdAsync("<NODE_ID>");
const nodes = root.findAll(n =>
  interactiveTypes.includes(n.type) && interactiveNames.test(n.name)
);

const issues = [];
for (const node of nodes) {
  const w = node.width;
  const h = node.height;
  if (w < 44 || h < 44) {
    issues.push({
      nodeId: node.id,
      name: node.name,
      size: { width: Math.round(w), height: Math.round(h) },
      minimumRequired: { ios: "44x44", android: "48x48" },
      level: w < 24 || h < 24 ? "CRITICAL" : "WARNING"
    });
  }
}

return { touchTargetIssues: issues, totalInteractive: nodes.length };

Step 6: Metin Boyutu Kontrolü

const root = await figma.getNodeByIdAsync("<NODE_ID>");
const textNodes = root.findAll(n => n.type === "TEXT");
const smallText = textNodes.filter(n => {
  const size = typeof n.fontSize === "number" ? n.fontSize : 0;
  return size > 0 && size < 12;
}).map(n => ({
  nodeId: n.id,
  name: n.name,
  fontSize: n.fontSize,
  recommendation: "Minimum 12px (body 14-16px önerilir)"
}));

return { smallTextIssues: smallText };

Step 7: Erişilebilirlik Notları (Annotation) Üretimi

Referans: Indeed Figma Accessibility Annotation Kit yaklaşımı. Denetim sonuçlarına göre, Figma tasarımına geliştirici notları eklenir. Bu notlar tasarım dosyasında kalır ve geliştirici handoff'unda kritik bilgi sağlar.

figma_execute ile ekranın yanına annotation frame'i oluştur.

Font kuralı: Annotation metinlerinde de DS fontunu kullan. Kayıtlı kütüphane varsa (.claude/libraries/) text style'lardan font ailesini oku. Bulunamazsa kullanıcıya sor. Kullanıcı "sen seç" derse Inter kullan. Aşağıdaki örnekte FONT_FAMILY kütüphaneden okunan font adıdır.

// FONT_FAMILY'yi kütüphaneden veya kullanıcıdan belirle
const FONT_FAMILY = "KütüphanedenOkunanFont";
await figma.loadFontAsync({ family: FONT_FAMILY, style: "Regular" });
await figma.loadFontAsync({ family: FONT_FAMILY, style: "Bold" });

const screen = await figma.getNodeByIdAsync("<NODE_ID>");

// Annotation frame — ekranın sağına yerleştir
const annotFrame = figma.createFrame();
annotFrame.name = "A11y Annotations";
annotFrame.layoutMode = "VERTICAL";
annotFrame.primaryAxisSizingMode = "AUTO";
annotFrame.counterAxisSizingMode = "AUTO";
annotFrame.itemSpacing = 16;
annotFrame.paddingLeft = 24;
annotFrame.paddingRight = 24;
annotFrame.paddingTop = 24;
annotFrame.paddingBottom = 24;
// Aşağıdaki renkler annotation UI'a özel değerlerdir, DS token'ı değildir — ancak DS'de karşılığı varsa oradan okunması tercih edilir
annotFrame.fills = [{ type: "SOLID", color: { r: 0.98, g: 0.95, b: 0.85 } }];
annotFrame.cornerRadius = 12;
annotFrame.x = screen.x + screen.width + 40;
annotFrame.y = screen.y;

// Helper: add annotation item
function addAnnotation(parent, emoji, title, body) {
  const item = figma.createFrame();
  item.name = "Annotation: " + title;
  item.layoutMode = "VERTICAL";
  item.primaryAxisSizingMode = "AUTO";
  item.itemSpacing = 4;
  item.fills = [];
  parent.appendChild(item);
  item.layoutSizingHorizontal = "FILL";

  const heading = figma.createText();
  heading.characters = emoji + " " + title;
  heading.fontSize = 14;
  heading.fontName = { family: FONT_FAMILY, style: "Bold" };
  // Annotation metin renkleri — DS'de karşılığı varsa oradan okunması tercih edilir
  heading.fills = [{ type: "SOLID", color: { r: 0.1, g: 0.1, b: 0.1 } }];
  item.appendChild(heading);

  const desc = figma.createText();
  desc.characters = body;
  desc.fontSize = 12;
  desc.fontName = { family: FONT_FAMILY, style: "Regular" };
  // Annotation açıklama rengi — DS'de karşılığı varsa oradan okunması tercih edilir
  desc.fills = [{ type: "SOLID", color: { r: 0.3, g: 0.3, b: 0.3 } }];
  item.appendChild(desc);
  desc.layoutSizingHorizontal = "FILL";
}

return { annotFrameId: annotFrame.id };

7a. Gesture Erişilebilirlik Kontrolleri

Mobil ve dokunmatik arayüzlerde gesture-bazlı etkileşimler klavye/switch kullanıcıları için erişilebilir alternatifler gerektir:

GestureGerekli AlternatifPlatform Notu
Swipe (kaydırma)Buton / ok kontrolüiOS VoiceOver: swipe gesture'lar yeniden atanır
Long-press (uzun basma)Context menu butonuAndroid: onLongClick + contentDescription
Pinch (çimdikleme)+/- zoom butonlarıWeb: wheel event alternatifi
Pull-to-refreshYenile butonuEkran okuyucu ile pull gesture kullanılamaz
Drag & dropTaşı butonu / sıralama menüsüKlavye ile sürükle-bırak erişilemez

Annotation: Gesture kullanan öğeleri tespit et ve alternatif kontrolün mevcut olup olmadığını raporla:

addAnnotation(annotFrame, "👆", "Gesture Kontrolü",
  "Swipe left → Sil butonu mevcut mi? Long-press → Context menu alternatifi var mı?");

7b. Başlık Hiyerarşisi Notları

Ekrandaki metin elemanlarını analiz et ve başlık seviyelerini belirle. Geliştirici hangi metnin <h1>, <h2>, <h3> olduğunu bilmeli:

Başlık Hiyerarşisi:
  H1: "Hoş Geldiniz" (24px, Semi Bold) — Sayfa ana başlığı
  H2: "Hesabınıza giriş yapın" (16px, Regular) — Alt başlık / açıklama
  Body: Input placeholder, link, buton metinleri (14px)

Kural: Ekranda yalnızca 1 adet H1 olmalı. Başlık seviyeleri atlanmamalı (H1 → H3 yanlış, H1 → H2 → H3 doğru).

7c. Form Alan-Etiket İlişkilendirme Notları

Form alanları ile etiketlerinin programatik olarak ilişkilendirilmesi gerekir. Aksi takdirde ekran okuyucu kullanıcıları alanın ne için olduğunu anlayamaz:

Form İlişkilendirme:
  Input "E-posta adresi":
    - label: "E-posta adresi" (for/id ilişkisi)
    - type: email
    - autocomplete: email
    - required: true
    - error: "Geçerli bir e-posta girin" (aria-describedby)

  Input "Şifre":
    - label: "Şifre" (for/id ilişkisi)
    - type: password
    - autocomplete: current-password
    - required: true
    - toggle: "Şifreyi göster/gizle" butonu (aria-label)

Kural: Her form alanının bir <label> ile ilişkilendirilmesi zorunludur. Placeholder tek başına etiket yerine geçmez.

7d. Odak Sırası (Focus Order) Notları

Ekrandaki etkileşimli öğelerin odak sırası görsel sıradan farklı olabilir. Bu notlar geliştiriciye doğru tabindex sırasını bildirir:

Odak Sırası:
  1. "Hoş Geldiniz" (başlık — ekran okuyucu ilk buraya odaklanır)
  2. "E-posta adresi" input
  3. "Şifre" input
  4. "Giriş Yap" butonu
  5. "Şifremi unuttum" link
  6. "Google ile Giriş Yap" butonu
  7. "Kayıt Ol" link

Kural: Mantıksal akış yukarıdan aşağıya olmalı. Görsel olarak yan yana olan elemanlar (ör. iş ilanı + favori ikonu) için sıra açıkça belirtilmeli.

7d.1. Prototip Odak Sırası Çapraz Kontrolü (v1.9.9+)

Ekranda prototip bağlantıları varsa, figma_get_prototype_connections ile tüm ON_CLICK reaction source'larını listele ve 7d'deki focus sırası ile karşılaştır:

const proto = await figma_get_prototype_connections({ nodeId: <screen> });
const clickableSources = proto.connections
  .filter(c => c.reactions.some(r => r.trigger?.type === "ON_CLICK"))
  .map(c => ({ id: c.nodeId, name: c.name }));

Kontrol kuralı:

  • 7d'deki focus sırası listesi (ör. [email, password, loginBtn, forgotLink, signupLink])
  • clickableSources listesi (ör. [loginBtn, signupLink, forgotLink])

Prototype'ta clickable olan ama a11y focus sırasında yer almayan veya sıralaması farklı olan elementler varsa UYARI ver:

⚠️ A11y focus sırası ile prototip etkileşim sırası uyuşmuyor.
   - Focus sırasında: forgotLink #4, signupLink #5
   - Prototype'ta tıklanabilir: signupLink (#5 ama prototipte önce geliyor)
   - Öneri: tabindex gözden geçir veya DOM sırasını değiştir.

Bu kontrol klavye-only kullanıcılar için kritik: prototype'ta "Giriş Yap" → "Kayıt Ol" beklenirken tabindex bunu sağlamıyorsa erişilebilirlik bozulur.

7e. Görsel Alternatif Metin Notları

Her görsel için alt text veya dekoratif işaretleme:

Görsel Notları:
  Logo (Ellipse): alt="MyApp logosu" (bilgi taşıyan görsel)
  Divider çizgileri: role="presentation" (dekoratif — ekran okuyucudan gizle)

Kural: İçerik taşıyan görseller alt text almalı. Sadece estetik amaçlı görseller role="presentation" veya aria-hidden="true" ile gizlenmeli.

7f. Modal/Dialog ve Dinamik İçerik Notları

Eğer ekranda modal, toast, alert gibi dinamik öğeler varsa:

Dinamik İçerik Notları:
  - Modal açıldığında: odak modal'a taşınmalı (focus trap)
  - Modal kapandığında: odak tetikleyen elemana dönmeli
  - Toast/alert: role="alert" veya aria-live="polite"
  - Loading: aria-busy="true", tamamlanınca aria-busy="false"

Kural: Dinamik içerik değişiklikleri aria-live region ile duyurulmalı. Modal'larda fokus tuzağı (focus trap) zorunludur.

Step 8: Erişebilirlik-Tasarım Tutarlılık Kontrolü

Annotation'lar üretildikten sonra, gerçek tasarımın erişebilirlik kurallarıyla tutarlı olduğunu doğrula. figma_execute ile otomatik kontrol:

const screen = await figma.getNodeByIdAsync("<NODE_ID>");
const checks = [];

// 1. Başlık hiyerarşisi — max 1 adet H1 (>= 24px)
const allText = screen.findAll(n => n.type === "TEXT");
const h1Count = allText.filter(n => n.fontSize >= 24).length;
checks.push({ rule: "Single H1", pass: h1Count <= 1 });

// 2. Min font size 12px
const tooSmall = allText.filter(n => typeof n.fontSize === "number" && n.fontSize < 12);
checks.push({ rule: "Min font 12px", pass: tooSmall.length === 0 });

// 3. Body text min 14px
const bodySmall = allText.filter(n => n.fontSize >= 12 && n.fontSize < 14);
checks.push({ rule: "Body min 14px", pass: bodySmall.length === 0 });

// 4. Touch target min 44px (iOS HIG)
const interactive = screen.findAll(n =>
  n.type === "INSTANCE" || (n.type === "FRAME" && /input|button|btn/i.test(n.name))
);
const smallTargets = interactive.filter(n => n.width < 44 || n.height < 44);
checks.push({ rule: "Touch 44px", pass: smallTargets.length === 0 });

// 5. Input min height 48px (Android Material)
const inputs = screen.findAll(n => n.type === "FRAME" && /input/i.test(n.name));
const smallInputs = inputs.filter(n => n.height < 48);
checks.push({ rule: "Input 48px", pass: smallInputs.length === 0 });

// 6. Tüm renkler token-bound (hard-coded fill yok)
let hardCoded = 0;
function chk(node) {
  if (node.name === "_spacer") return;
  if (node.fills?.length > 0 && node.fills[0].type === "SOLID") {
    if (!node.boundVariables?.fills) hardCoded++;
  }
  if (node.children && node.type !== "INSTANCE") node.children.forEach(c => chk(c));
}
chk(screen);
checks.push({ rule: "Colors token-bound", pass: hardCoded === 0 });

// 7. Auto-layout (responsive) — tüm content frame'ler
const noLayout = screen.findAll(n => n.type === "FRAME" && n.name !== "_spacer" && (!n.layoutMode || n.layoutMode === "NONE"));
checks.push({ rule: "Auto-layout", pass: noLayout.length === 0 });

// 8. Fokus göstergesi renk kontrastı — focus ring var mı ve görünür mü?
const focusable = screen.findAll(n =>
  n.type === "INSTANCE" || (n.type === "FRAME" && /focus|focused/i.test(n.name))
);
const hasFocusState = focusable.some(n => /focus/i.test(n.name));
checks.push({ rule: "Focus indicator", pass: hasFocusState || focusable.length === 0 });

// 9. Hata mesajı ilişkilendirme — error text + input yakınlığı
const errorTexts = allText.filter(n => /error|hata|geçersiz|invalid/i.test(n.name));
checks.push({ rule: "Error association", pass: true, note: `${errorTexts.length} hata metni tespit edildi — aria-describedby ilişkisi geliştiriciye bildirilmeli` });

// 10. UI bileşen kontrastı (1.4.11) — buton/input border rengi arka plana karşı ≥3:1
checks.push({ rule: "Non-text contrast 3:1", pass: true, note: "Manuel kontrol gerekli — buton/input kenar renkleri ve ikon kontrastı screenshot ile doğrulanmalı" });

return { pass: checks.filter(c => c.pass).length, total: checks.length, checks };

Tüm kontroller PASS olmalı. FAIL varsa, ilgili bulguyu düzelt ve tekrar çalıştır.

Step 9: Platform-Bazlı Rapor Üret

iOS (VoiceOver) Raporu

### VoiceOver Spesifikasyonu

| Öğe | accessibilityLabel | accessibilityTraits | Sıra |
|---|---|---|---|
| Logo | "Uygulama logosu" | .image | 1 |
| Başlık | "Hoş geldiniz" | .header | 2 |
| E-posta | "E-posta adresi" | .none (textField) | 3 |
| Giriş butonu | "Giriş yap" | .button | 4 |

Android (TalkBack) Raporu

### TalkBack Spesifikasyonu

| Öğe | contentDescription | Role | importantForAccessibility |
|---|---|---|---|
| Logo | "Uygulama logosu" | IMAGE | yes |
| Başlık | "Hoş geldiniz" | HEADING | yes |
| E-posta | "E-posta adresi" | EDIT_TEXT | yes |
| Giriş butonu | "Giriş yap" | BUTTON | yes |

Web (ARIA) Raporu

### ARIA Spesifikasyonu

| Öğe | role | aria-label | tabindex |
|---|---|---|---|
| Logo | img | "Uygulama logosu" | -1 |
| Başlık | heading (h1) | — | -1 |
| E-posta | textbox | "E-posta adresi" | 0 |
| Giriş butonu | button | "Giriş yap" | 0 |

Türkçe Karakter Kuralı (ZORUNLU)

Tüm Türkçe metin içeriklerinde (Figma text node, kod string, dokümantasyon) doğru Unicode karakterler kullanılmalıdır. ASCII karşılıkları YASAKTIR:

DoğruYanlışDoğruYanlış
şsŞS
ıiİI
öoÖO
üuÜU
çcÇC
ğgĞG

Son adım: Üretilen tüm Türkçe metinleri karakter kontrolünden geçir.

Çıktı Formatı

  • Varsayılan: Markdown rapor (tüm platformlar)
  • --json: Yapılandırılmış JSON (CI entegrasyonu için)
  • --platform=ios: Yalnızca VoiceOver raporu
  • --platform=android: Yalnızca TalkBack raporu
  • --platform=web: Yalnızca ARIA raporu

Bulgu Öncelikleri

SeviyeAçıklamaÖrnek
CRITICALWCAG AA başarısız, kullanılamazKontrast < 2:1, touch target < 24px
HIGHWCAG AA sınırdaKontrast 3-4.5:1 normal metin
MEDIUMBest practice ihlaliTouch target 24-44px, metin < 14px
LOWİyileştirme önerisiAAA başarısız ama AA geçiyor

Annotation Çıktı Formatı

Skill çalıştırıldığında, Figma dosyasında ekranın yanına sarı bir annotation frame oluşturulur:

┌──────────────────────────────────────┐
│ A11y Annotations                     │
│                                      │
│ 🏷️ Başlık Hiyerarşisi               │
│ H1: "Hoş Geldiniz"                  │
│ H2: "Hesabınıza giriş yapın"        │
│                                      │
│ 🔗 Form İlişkilendirme              │
│ "E-posta" → label + type=email       │
│ "Şifre" → label + type=password      │
│                                      │
│ 🔢 Odak Sırası                       │
│ 1→Başlık 2→Email 3→Şifre 4→Giriş   │
│ 5→Şifremi unuttum 6→Google 7→Kayıt  │
│                                      │
│ 🖼️ Görsel Alt Text                   │
│ Logo: alt="MyApp logosu"             │
│ Divider: decorative (gizle)          │
│                                      │
│ ⚡ Kontrast Sonuçları                │
│ Primary: 5.17:1 ✅ AA                │
│ Secondary: 16.13:1 ✅ AA+AAA        │
│ Disabled: 4.39:1 ℹ️ Muaf            │
│                                      │
│ 📐 Touch Target                     │
│ Tüm butonlar ≥44px ✅               │
│ Tüm inputlar ≥48px ✅               │
└──────────────────────────────────────┘

Bu annotation frame'i Figma dosyasında kalır ve geliştirici handoff paketinin bir parçası olur. ai-handoff-export skill'i bu notları otomatik olarak HANDOFF.md'ye dahil eder.

Doğrulama Kontrol Listesi

Skill tamamlandığında şu kontroller yapılmalı:

  • Tüm renk çiftleri WCAG AA kontrolünden geçti mi?
  • Tüm interaktif elemanlar ≥44px (iOS) / ≥48px (Android) mu?
  • Tüm metinler ≥12px mi? Body metinler ≥14px mi?
  • Başlık hiyerarşisi doğru mu? (tek H1, seviye atlama yok)
  • Form alanları etiketlerle ilişkilendirildi mi?
  • Odak sırası mantıksal mı?
  • Dekoratif görseller işaretlendi mi?
  • Annotation frame oluşturuldu mu?
  • Platform-bazlı rapor (VoiceOver/TalkBack/ARIA) üretildi mi?

Evolution Triggers

  • WCAG 3.0 yayınlandığında kontrast algoritması (APCA) güncellenmeli
  • Bridge'e a11y-spesifik araç eklenirse (ör. erişilebilirlik ağacı aracı) iş akışı güncellenmeli
  • Yeni platform (Flutter, .NET MAUI) desteği eklenirse rapor şablonları genişletilmeli

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.