apca-compliance-figma
March 31, 2026 · View on GitHub
A skill that integrates APCA (Advanced Perceptual Contrast Algorithm) directly into the Figma design process — not as a post-design compliance checker, but as a generative, design-time tool.
It works in two parts:
- Part 1 — Variable Remapping: Audit a component's color variables, calculate their Lc contrast values, identify failures, and propose or apply compliant replacements
- Part 2 — Component Iterator: Generate a range of component variations at user-specified Lc targets, covering light mode, dark mode, or both
What is APCA?
APCA (Advanced Perceptual Contrast Algorithm) is the contrast method developed for WCAG 3.0. Unlike WCAG 2.x, it is:
- Polarity-aware — correctly handles dark mode (light text on dark backgrounds), where WCAG 2.x fails
- Perceptually uniform — contrast values map to how humans actually see text, not raw luminance ratios
- Use-case aware — different Lc thresholds apply depending on font size, weight, and reading context
Lc Level Reference
| Lc Level | Use Case |
|---|---|
| Lc 15 | Minimum for non-text elements (dividers, borders, focus outlines) |
| Lc 30 | Minimum for any text — placeholder and disabled states only |
| Lc 45 | Minimum for large/heavy text (headings ≥ 36px/400w or 24px/700w) |
| Lc 60 | Minimum for UI labels and captions (≥ 24px/400w or 16px/700w) |
| Lc 75 | Minimum for body text columns (≥ 18px/400w) |
| Lc 90 | Preferred for fluent reading — also the dark mode maximum (above this causes halation) |
WCAG 2.x approximations (light mode only): Lc 60 ≈ 3:1 · Lc 75 ≈ 4.5:1 · Lc 90 ≈ 7:1. APCA and WCAG 2.x diverge significantly for dark mode — do not use WCAG 2.x to evaluate dark mode contrast.
What It Does
Part 1 — Variable Remapping
- Reads all color variables from the selected component via
get_variable_defs+get_design_context - Infers color roles (text, background, icon, border) from variable names and layer structure
- Builds contrast pairs and calculates current Lc values for each
- Identifies failures against your target threshold
- Proposes replacement colors that meet or exceed the target — staying within the same hue family
- Applies approved changes directly to Figma variables via
use_figmaPlugin API - Verifies the write succeeded by recalculating Lc values post-update
Example audit output:
Variable Pair Current Lc Target Lc Status
────────────────────────────────────────────────────────────────
color/label on color/btn-bg Lc 41 Lc 60 ❌ Fails
color/title on color/surface Lc 78 Lc 75 ✅ Passes
color/caption on color/card Lc 52 Lc 60 ❌ Fails
Part 2 — Component Iterator
- Reads the component structure and current variable values
- Calculates a contrast matrix across all variants (Primary, Secondary, Disabled, etc.)
- Generates three variations per target — minimal compliance, comfortable, and high contrast
- Writes variations to Figma as new variable modes or new component variants on canvas
- Presents a visual comparison with Lc values labeled for quick review
Example variation output:
Variation A — Lc 47 (Minimal Compliance)
Variation B — Lc 62 (Comfortable)
Variation C — Lc 78 (High Contrast)
Prerequisites
- A Figma file open with a component selected
- The Figma MCP server connected to Claude (see below)
- A Figma personal access token — get one from Figma → Account Settings → Personal Access Tokens
This skill uses the Figma MCP server, not a Figma plugin. Claude reads and writes directly to your Figma file through the MCP connection — no plugin panel or Figma Community install required.
Connecting the Figma MCP Server
Using Claude.ai (browser)
- Go to Claude.ai → Settings → Integrations
- Find Figma and click Connect
- Authorize with your Figma account
- The Figma MCP server will be available in all your Claude conversations
Using Claude Code (terminal)
Add the Figma MCP server to your Claude config file (~/.claude.json or claude_desktop_config.json):
{
"mcpServers": {
"figma": {
"url": "https://mcp.figma.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_FIGMA_ACCESS_TOKEN"
}
}
}
}
Replace YOUR_FIGMA_ACCESS_TOKEN with your personal access token. Store it in .component-contracts (gitignored) and reference it from there — never hardcode it in the config directly.
Installation
- Clone the repo
git clone https://github.com/your-username/figma-apca-accessibility.git
cd figma-apca-accessibility
- Store your Figma access token
Create a .component-contracts file in the root (gitignored — never commit this):
FIGMA_ACCESS_TOKEN=your_token_here
- Add the skill to Claude
Place the SKILL.md file in your Claude skills directory:
/mnt/skills/public/figma-apca-accessibility/SKILL.md
How to Trigger It
Use any of these prompts in Claude with a Figma component selected:
Part 1 — Audit and remap variables:
"Audit the color variables in this component for APCA compliance. My button labels need to be at least Lc 60."
"My success surface is #14ae5c and nothing passes against it. Give me my options."
"My button label must stay white. Find me a dark mode background that hits at least Lc 60 against white, staying in the same blue family."
Part 2 — Generate variations:
"Using the current light mode button variables, create a dark mode version where button labels are at least Lc 45. Generate three variations so I can compare."
Combined flow:
"First remap my existing variables to Lc 75 for body text. Then generate three dark mode variants of this card at Lc 45, Lc 60, and Lc 75."
Edge Cases This Skill Handles
Mid-Luminance Surface Trap
When a background sits in the middle luminance range (roughly Y 0.15–0.40), neither black nor white text can achieve the target Lc. Common culprits: mid-tone greens, yellows, reds, and oranges used as semantic status colors.
The skill detects these automatically and presents three resolution options — it never auto-applies a fix without your review.
Dark Mode Halation
When Lc exceeds 90 in dark mode (e.g., pure white on near-black), the glow effect reduces readability despite the high contrast number. The skill detects halation and recommends raising the dark background slightly — not graying out the text.
Disabled / Placeholder States
These are intentionally kept at Lc 30 maximum to signal inactivity. The skill does not force disabled states to body-text contrast levels.
Licensing Notice
APCA is developed by Myndex Research / Accessible Reading Technologies (ART). This skill implements the APCA-W3 0.0.98G algorithm under the W3C open license for design tooling.
- Does not claim "APCA Compliant" certification (which requires formal evaluation by Myndex/ART)
- Does not use WCAG 2.x contrast ratios — APCA Lc values are not interchangeable with WCAG 2.x ratios
- Is prohibited for use in medical, clinical, aerospace, transportation, automotive, or military applications without a specific written license from Myndex Research
For more information: https://git.apcacontrast.com/documentation/WhyAPCA
Reference implementation: npm i apca-w3
Contributing
Contributions are welcome. Here's how to get started:
- Fork the repo
- Create a branch:
git checkout -b feature/your-improvement - Make your changes to
SKILL.md - Test against at least two component types — one light mode, one dark mode
- Open a pull request with a clear description of what changed and why
Guidelines
- Keep the two-part structure intact — Variable Remapping and Component Iterator are distinct workflows
- Any new Lc threshold rules must cite the APCA-W3 specification or Myndex documentation
- Do not commit
.component-contracts,scripts/, or any generated artifacts - Edge case handling (mid-luminance traps, halation, disabled states) must always present options to the user — never auto-apply
License
MIT