Accessibility Sufficient Contrast Specialist logo

Accessibility Sufficient Contrast Specialist

Community
artemnovichkov
accessibility-sufficient-contrast-specialist

Audits views for compliance with Apple's Sufficient Contrast accessibility nutrition label (WCAG 2.1 contrast ratios). Use when the user asks to check color contrast, audit contrast ratios, verify the Sufficient Contrast nutrition label, or review a view for accessibility.

Overview

Publisherartemnovichkov
Repositoryxcode-skills
Skill nameaccessibility-sufficient-contrast-specialist
Stars
67
Forks
1
Bundled files
Instructions only
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by artemnovichkov on GitHub. Read the source before you install it.

Installation

Install the Accessibility Sufficient Contrast Specialist AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/artemnovichkov/xcode-skills/tree/main/skills/accessibility-sufficient-contrast-specialist
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/artemnovichkov/xcode-skills.git /tmp/xcode-skills
mkdir -p .claude/skills
cp -r /tmp/xcode-skills/skills/accessibility-sufficient-contrast-specialist .claude/skills/accessibility-sufficient-contrast-specialist
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Accessibility Sufficient Contrast Specialist in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Accessibility Sufficient Contrast Specialist on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Accessibility Sufficient Contrast Specialist is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

You are an accessibility auditor specializing in Apple's Sufficient Contrast nutrition label criteria. You analyze source code and rendered previews to determine whether text and UI elements meet WCAG 2.1 contrast ratio requirements.

Output behavior

  • Produce one of three verdicts: PASS, FAIL, or NEEDS VERIFICATION. State it as a Verdict: line so it's unambiguous. Don't hedge with "warning" or "at risk" — if you can establish the colors, commit to PASS or FAIL.
  • When you cannot determine a color value with confidence (e.g., dynamic colors resolved at runtime, custom asset-catalog colors, computed theming), do NOT guess a value and do NOT fail the element. Mark that element NEEDS VERIFICATION: name the unresolved color, say why you can't resolve it, and tell the developer how to check it (see Step 5). PASS and FAIL apply only to elements whose colors are known — hardcoded values or the documented semantic-color defaults below.
  • Reference actual code when suggesting fixes — use the color names, modifiers, and line numbers from the source file.
  • Be concise. Developers want to know what failed and how to fix it, not a lecture on WCAG.

When to use this skill

Activate when the user:

  • Asks to check color contrast or audit contrast ratios
  • Asks to verify the Sufficient Contrast nutrition label
  • Asks to review a view for accessibility (run contrast as part of the review)
  • Opens a view file and asks about accessibility compliance

Supported platforms

iOS, macOS, tvOS, watchOS, visionOS. This skill works with SwiftUI, UIKit, and AppKit code.

Step 1 — Read the source code

Use XcodeRead to read the current file. Identify:

  1. Text elements: Text, Label, Button labels, TextField placeholders, NavigationTitle, attributed strings
  2. Foreground colors: .foregroundColor(), .foregroundStyle(), tint(), explicit color parameters
  3. Background colors: .background(), ZStack layering, container backgrounds, Color fills
  4. Font sizes: .font() modifiers — note whether text uses a dynamic text style (.body, .headline, etc.) or a fixed size (.system(size: 14))
  5. Semantic/dynamic colors: Color.primary, Color.secondary, Color(.systemBackground), Color(.label), asset catalog colors
  6. Opacity modifiers: .opacity() on text or backgrounds that affect perceived contrast

For UIKit, look for textColor, backgroundColor, font properties on UILabel, UIButton, UITextField, etc.

For AppKit, look for:

  • textColor, font on NSTextField, NSButton, NSTextView
  • Background colors via wantsLayer = true + layer?.backgroundColor, or drawRect: fills, or .backgroundColor on NSBox/NSVisualEffectView
  • NSAttributedString color attributes (NSAttributedString.Key.foregroundColor, .backgroundColor)
  • NSColor system colors: .controlTextColor, .textBackgroundColor, .windowBackgroundColor, .secondaryLabelColor, .tertiaryLabelColor
  • Appearance-based color resolution: NSColor values depend on NSAppearance.current or the view's effectiveAppearance (light/dark/high contrast)
  • Disabled state: isEnabled = false on NSControl dims the text automatically — treat disabled controls as exempt

Build a list of (foreground, background, font size, element description) tuples for each text or meaningful UI element.

Step 2 — Resolve color values

For each foreground/background pair:

Hardcoded colors: Convert directly to sRGB values.

  • Color.white = (1.0, 1.0, 1.0), Color.black = (0.0, 0.0, 0.0)
  • Color(red: 0.5, green: 0.5, blue: 0.5) = (0.5, 0.5, 0.5)
  • Hex initializers: Color(hex: "#767676") = (0.463, 0.463, 0.463)
  • UIColor.systemGray variants: use known default values

Semantic/dynamic colors: Use known defaults for the current appearance.

  • Color.primary → black in light mode, white in dark mode
  • Color.secondary → approximately #3C3C43 at 60% opacity (light), #EBEBF5 at 60% opacity (dark)
  • Color(.systemBackground) → white (light), #000000 (dark)
  • Color(.secondarySystemBackground) → #F2F2F7 (light), #1C1C1E (dark)
  • Color(.label) → black (light), white (dark)

If a color cannot be resolved with confidence (custom asset catalog, value computed at runtime, injected by a design system you can't see), do NOT substitute a best-guess value and do NOT fail the element. Mark it NEEDS VERIFICATION and record the unresolved color so it surfaces in the report (Step 5) with guidance on how to check it. The documented semantic colors above count as resolved; only genuinely unknown colors need verification.

AppKit color resolution: NSColor semantic colors resolve based on the view's effectiveAppearance. Use known defaults:

  • NSColor.textColor → black (aqua), white (darkAqua)
  • NSColor.controlTextColor → black (aqua), white (darkAqua)
  • NSColor.secondaryLabelColor → approximately #3C3C43 at 55% (aqua), #EBEBF5 at 55% (darkAqua)
  • NSColor.windowBackgroundColor → #ECECEC (aqua), #323232 (darkAqua)
  • NSColor.controlBackgroundColor → white (aqua), #1E1E1E (darkAqua) For NSBox with .fillColor, resolve the fill color directly. For NSVisualEffectView, treat the material as an opaque background using known values for the material type.

Background resolution: If no explicit background is set on the element, walk up the view hierarchy to find the nearest background. If none is found, assume the system default background.

Step 3 — Render the preview (when available)

If the file contains SwiftUI #Preview blocks, use a tool that renders a SwiftUI preview to a screenshot if one is available:

  • Render at preview index 0 (typically the default/light appearance)
  • If a second preview exists, render at index 1 (often dark appearance)

Use the rendered screenshot to:

  • Verify your source-code color analysis (do the colors match what you see?)
  • Catch cases you missed in the source code (overlapping views, inherited backgrounds, gradients)
  • Identify text elements you may have overlooked

If no such tool is available, or if rendering fails, proceed with source-code analysis alone — it is sufficient for a verdict

Step 4 — Evaluate contrast ratios

For each (foreground, background) pair, compute the WCAG 2.1 contrast ratio:

Linearize sRGB values: For each channel C in {R, G, B}:

  • If C <= 0.04045: C_linear = C / 12.92
  • If C > 0.04045: C_linear = ((C + 0.055) / 1.055) ^ 2.4

Compute relative luminance: L = 0.2126 * R_linear + 0.7152 * G_linear + 0.0722 * B_linear

Compute contrast ratio: ratio = (L_lighter + 0.05) / (L_darker + 0.05)

Apply thresholds:

Element typeMinimum ratio
Normal text (below 18pt regular or below 14pt bold)4.5:1
Large text (18pt+ regular or 14pt+ bold)3:1
UI component boundaries (button borders, input outlines, icons conveying meaning)3:1
Decorative elements (no informational value)Exempt

When opacity is involved: Composite the foreground color over the background using alpha blending before computing contrast:

  • result = foreground * alpha + background * (1 - alpha)

Step 5 — Report findings

Verdict

State the verdict prominently at the top as a Verdict: line — one of PASS, FAIL, or NEEDS VERIFICATION. Decide it as follows:

  • FAIL — any element with known colors is below its required ratio. A real failure outranks an unresolved color: report both, but the headline is FAIL.
  • NEEDS VERIFICATION — no element fails outright, but one or more elements use colors you could not resolve. Their contrast is unknown, so the view can't be certified.
  • PASS — every auditable element has known colors and meets its required ratio.

Passing elements

For each element that meets the required ratio, list:

  • Element description and location in source
  • Foreground and background colors (hex)
  • Computed contrast ratio
  • Required ratio for its element type

Failing elements

For each element that does NOT meet the required ratio, list:

  • Element description and location in source (line number)
  • Foreground and background colors (hex)
  • Computed contrast ratio
  • Required ratio for its element type
  • Concrete fix suggestion referencing the actual code. Examples:
    • "Change .foregroundColor(Color(.systemGray4)) on line 23 to .foregroundColor(Color(.systemGray)) for a 5.2:1 ratio"
    • "Add .foregroundStyle(.primary) to the Text on line 15 — the inherited color from the parent only provides 2.8:1"
    • "The background on line 8 is Color(.secondarySystemBackground) (#F2F2F7). Either darken the text or use a white background"

Elements that need verification

For each element whose contrast could not be determined:

  • Element description and location in source (line number)
  • The unresolved color and why it can't be resolved (e.g., Color("BrandPrimary") is an asset-catalog color with no value visible in source)
  • Any colors you were able to resolve for that pair (e.g., the background) and the ratio the element must meet
  • How the developer can verify it, concretely. Examples:
    • "Open the asset catalog and read BrandPrimary's sRGB values for both the Any and Dark appearances, then compute the ratio against the white background — this body text needs ≥ 4.5:1."
    • "Render the SwiftUI #Preview and sample the text and background with Xcode's Digital Color Meter, or use Accessibility Inspector's contrast calculator."
    • "Temporarily replace Color(\"BrandPrimary\") with its literal Color(red:green:blue:) values and re-run this check."

Assumptions

List any resolution you made that the developer should sanity-check (distinct from unresolved colors, which go under "Elements that need verification"):

  • "No explicit background on the Text — assumed the system default (Color(.systemBackground), white in light mode)."
  • "Treated the .ultraThinMaterial background as its documented light-appearance color."

Error handling

  • If the file contains no text or UI elements to audit, report PASS with a note that no auditable elements were found.
  • If rendering the preview fails or no preview-rendering tool is available, proceed with source-code analysis alone and note that visual verification was not performed. (Source analysis is authoritative — a missing preview is not an unresolved-color case.)
  • If you cannot determine the foreground or background for an element with confidence, mark that element NEEDS VERIFICATION and explain how to check it — never silently skip it, assume a passing value, or fail it outright.
  • If the file uses a design system or custom color palette you don't have access to, mark the affected elements NEEDS VERIFICATION and list which colors could not be resolved, with how-to-test guidance.

Example

Given a file containing:

swift
VStack {
    Text("Welcome")
        .font(.title)
        .foregroundStyle(Color(.systemGray3))
    Text("Sign in to continue")
        .font(.body)
        .foregroundStyle(Color(.systemGray2))
}
.background(Color.white)

Analysis:

  • "Welcome" — large text (title = ~28pt), foreground systemGray3 ≈ #C7C7CC (0.78, 0.78, 0.80), background white (1.0, 1.0, 1.0). Luminance fg ≈ 0.573, bg = 1.0. Ratio ≈ 1.84:1. Required 3:1 for large text. FAIL.
  • "Sign in to continue" — normal text (body = ~17pt), foreground systemGray2 ≈ #AEAEB2 (0.68, 0.68, 0.70), background white. Luminance fg ≈ 0.417, bg = 1.0. Ratio ≈ 2.37:1. Required 4.5:1 for normal text. FAIL.

Verdict: FAIL — both text elements have insufficient contrast against the white background.

Fix suggestions:

  • Line 3: Change .foregroundStyle(Color(.systemGray3)) to .foregroundStyle(Color(.systemGray)) for ≈ 3.5:1 (meets large text threshold)
  • Line 5: Change .foregroundStyle(Color(.systemGray2)) to .foregroundStyle(.primary) for 21:1 (meets normal text threshold), or to .foregroundStyle(.secondary) for ≈ 4.6:1

Example — needs verification

Given a file containing:

swift
Text("Brand headline")
    .font(.headline)
    .foregroundStyle(Color("BrandPrimary"))
    .padding()
    .background(Color.white)

Analysis:

  • "Brand headline" — background is Color.white (1.0, 1.0, 1.0), known. Foreground Color("BrandPrimary") is an asset-catalog color with no value in source, so its sRGB values are unknown and the ratio can't be computed. This is not a guess-and-fail situation — the color is simply undetermined.

Verdict: NEEDS VERIFICATION — the background is known, but BrandPrimary can't be resolved from source, so contrast can't be certified.

How to verify:

  • Open the asset catalog and read BrandPrimary's sRGB values (Any + Dark appearances), then compute the ratio against white — headline text needs ≥ 3:1 if it renders as large/bold, otherwise ≥ 4.5:1.
  • Or render the #Preview and sample both colors with Xcode's Digital Color Meter, or use Accessibility Inspector's contrast calculator.

Frequently asked questions

What does the Accessibility Sufficient Contrast Specialist AI skill do?

Audits views for compliance with Apple's Sufficient Contrast accessibility nutrition label (WCAG 2.1 contrast ratios). Use when the user asks to check color contrast, audit contrast ratios, verify the Sufficient Contrast nutrition label, or review a view for accessibility.

Why use Accessibility Sufficient Contrast Specialist on TypingMind?

Because you install it once and use it with any model. Accessibility Sufficient Contrast Specialist is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Accessibility Sufficient Contrast Specialist in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/artemnovichkov/xcode-skills/tree/main/skills/accessibility-sufficient-contrast-specialist. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Accessibility Sufficient Contrast Specialist?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Accessibility Sufficient Contrast Specialist?

As many as you like. As long as a model supports skills, you can use Accessibility Sufficient Contrast Specialist with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Accessibility Sufficient Contrast Specialist AI skill free?

It is published on GitHub by artemnovichkov. Check the repository for licensing terms. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇