JSPM

apca-cli

0.1.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 7
  • Score
    100M100P100Q36935F
  • License MIT

CLI for APCA (Lc) accessibility contrast checking — the algorithm WCAG 3 is built around.

Package Exports

    This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (apca-cli) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

    Readme

    apca-cli

    CLI for APCA (Accessible Perceptual Contrast Algorithm) — the contrast model. Given a foreground color, a background color, and the font size + weight you'd render text at, it returns the signed Lc value and a pass / fail against the spec's font-size × weight lookup table.

    APCA replaces the old WCAG 2.x 4.5:1 ratio with a perceptually-grounded score (Lc, roughly −108 to +106) plus a per-weight minimum font size. The algorithm comes directly from apca-w3, maintained by Andrew Somers / Myndex Research — see the SAPC-APCA parent repo for the canonical spec. This CLI is just a thin wrapper; it does not reimplement the algorithm or the thresholds.

    Install

    curl -fsSL https://raw.githubusercontent.com/alikimovich/apca-cli/main/install.sh | bash

    Installs bun if missing, installs the CLI, and — if you use Claude Code or the Codex CLI — also drops in the matching skill so the tool gets invoked automatically. Re-running the installer updates everything in place; it's idempotent.

    Manual

    # npm (works under Node ≥ 18 or Bun)
    npm install -g apca-cli
    
    # or with Bun
    bun install -g apca-cli
    
    # one-shot, no install
    npx apca-cli check "#555" "#fff"
    bunx apca-cli check "#555" "#fff"

    The published package is a single bundled dist/cli.js produced by bun build --target=node, so it runs on either runtime.

    Usage

    apca-cli check <foreground> <background> [options]
    
    Options:
      --font-size <px>     Font size in px           (default: 16)
      --font-weight <n>    Font weight 100–900       (default: 400)
      --wcag2              Also report WCAG 2.x contrast ratio (AA/AAA)
      --format <fmt>       text | json               (default: text)
      -h, --help
    
    Exit codes:
      0  pass (and, with --wcag2, WCAG 2 AA or better)
      1  fail / non-text / spot-text / prohibited (or WCAG 2 fail)
      2  bad arguments

    Colors accept hex (#abc, #abcdef), rgb(), hsl(), and CSS named colors — anything colorparsley handles.

    Examples

    $ apca-cli check "#000" "#fff"
    ✓ PASS
    
      foreground:  #000
      background:  #fff
      font:        16px / weight 400
      Lc:          106.04
      min size:    14.5px at this Lc & weight
    
      Lc 106.0 passes — at weight 400, this contrast supports text down to 14.5px; your 16px is above that.
    $ apca-cli check "#555" "#fff" --font-size 16 --font-weight 400
    ✗ FAIL
    
      foreground:  #555
      background:  #fff
      font:        16px / weight 400
      Lc:          85.94
      min size:    16.5px at this Lc & weight
    
      Lc 85.9 fails — at weight 400, this contrast requires at least 16.5px text; your 16px is below that.
    $ apca-cli check "#000" "#fff" --format json
    {
      "foreground": "#000",
      "background": "#fff",
      "fontSizePx": 16,
      "fontWeight": 400,
      "lc": 106.04067321268862,
      "minFontSizePx": 14.5,
      "thresholdRaw": 14.5,
      "verdict": "pass",
      "message": "Lc 106.0 passes — …"
    }

    WCAG 2.x check (--wcag2)

    APCA is the contrast model WCAG 3 is built on, but a lot of teams still ship against the WCAG 2.1 / 2.2 ratio rules. Passing --wcag2 runs the WCAG 2 relative-luminance contrast check alongside APCA and prints both. APCA remains the headline verdict; WCAG 2 is shown as a second block.

    $ apca-cli check "#767676" "#fff" --wcag2
    ✗ FAIL
    
      foreground:  #767676
      background:  #fff
      font:        16px / weight 400
      Lc:          71.57
      min size:    19.5px at this Lc & weight
    
      Lc 71.6 fails — at weight 400, this contrast requires at least 19.5px text; your 16px is below that.
    
    ✓ WCAG 2 AA
    
      ratio:       4.54:1
      text class:  normal text (16px / weight 400)
      AA:          pass    AAA: fail    UI components (3:1): pass
    
      Ratio 4.54:1 passes WCAG 2 AA for normal text (4.5:1) but fails AAA (7:1).

    #767676 on #fff is the textbook "passes WCAG 2 AA, fails APCA at body text" case — exactly the gap APCA was designed to close.

    WCAG 2 thresholds applied:

    Text class Size + weight AA AAA
    Normal text < 18pt regular and < 14pt bold 4.5:1 7:1
    Large text ≥ 18pt (24px) regular, or ≥ 14pt bold 3:1 4.5:1
    UI components / graphics (SC 1.4.11) any 3:1

    JSON output with --wcag2 wraps both checks:

    $ apca-cli check "#777" "#fff" --wcag2 --format json
    {
      "apca":  { …same shape as without --wcag2… },
      "wcag2": {
        "ratio": 4.478089453577214,
        "ratioRounded": 4.48,
        "isLargeText": false,
        "AA": "fail",
        "AAA": "fail",
        "uiComponents": "pass",
        "verdict": "fail",
        "message": "Ratio 4.48:1 fails WCAG 2 AA for normal text — needs 4.5:1 (AA) or 7:1 (AAA)."
      }
    }

    How pass/fail is decided

    1. Lc = calcAPCA(foreground, background) — signed float, ≈ ±108. Positive = dark text on light bg, negative = light text on dark bg.
    2. fontLookupAPCA(Lc) returns the canonical APCA reference table row: the minimum px size at each font weight (100–900) that this Lc can carry.
    3. We index the row at your weight (snapped to nearest 100) and compare to your font size. Three sentinel verdicts also exist for very-low Lc:
    Lookup value Verdict Meaning
    px number pass / fail Real minimum size; pass iff your size ≥ this
    666 spot-text-only OK for copyright / placeholder, not fluent body text
    777 non-text-only Decorative graphics only
    999 prohibited Below APCA's usable floor

    The numeric thresholds are sourced verbatim from fontLookupAPCA in apca-w3 (Public Beta 0.1.7 lookup, May 2022). They are not reinterpreted here.

    Roadmap

    • Color suggestions on fail. Integrate chroma.js to walk the failing color along an OKLCH / lightness axis until it crosses the threshold, and report the nearest passing color. Architected to slot in without changing the check() API.

    Claude Code skill

    This repo ships a Claude Code skill at skill/apca-contrast-check/ that teaches Claude when to reach for apca-cli automatically — e.g. when reviewing CSS diffs, debating design tokens, or any "is this color combination readable?" question. Once installed, Claude will run the CLI, parse the JSON output, and report Lc + verdict back to you without being explicitly prompted.

    Install the skill

    # 1. Make sure apca-cli is on PATH
    cd /path/to/apca-cli
    bun install            # if you haven't already
    bun link               # registers `apca-cli` globally via bun
    
    # 2. Drop the skill into your user-level skills directory
    mkdir -p ~/.claude/skills
    cp -r skill/apca-contrast-check ~/.claude/skills/

    The skill will load on Claude Code's next session start. Verify with /help → it should appear in the skills list, or just ask Claude something like "is #6b7280 on white readable for body text?" — it should call the CLI without further prompting.

    If bun link isn't an option, the skill falls back to running bun /path/to/apca-cli/src/cli.ts directly — but you'll want to edit SKILL.md to point at your actual checkout path.

    Reference

    License

    MIT. The APCA algorithm is © Myndex Research / Andrew Somers and used under the terms of apca-w3.