Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ jobs:
exit 1
fi

- name: Token contrast (WCAG AA on every style palette)
run: python3 scripts/check_contrast.py

- name: Context budget
run: python3 scripts/validate.py --budget

Expand All @@ -47,3 +50,30 @@ jobs:
test -f "$tmp/.cursor/rules/agent-design-taste.mdc"
test -f "$tmp/.windsurf/rules/agent-design-taste.md"
test -f "$tmp/.github/copilot-instructions.md"

render:
name: Rendered verification of the 15 example pages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "20"

- name: Install Playwright Chromium
run: |
npm init -y >/dev/null 2>&1
npm install --no-save playwright@1.56.1
npx playwright install --with-deps chromium

- name: Render every example at 1440 / 768 / 390 / 360
run: node scripts/screenshot.mjs

- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v4
with:
name: example-screenshots
path: screenshots/
retention-days: 7
46 changes: 46 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,52 @@ For a skill, "breaking" means: a renamed or moved file that installations
reference, a changed workflow contract, or a removed rule an agent may be
relying on.

## [2.1.0] β€” 2026-09-08

Enforcement release. 2.0.0 wrote the accessibility rules down; this one measures
them. Both new checks found real failures in this repository on their first run.

### Added
- `scripts/check_contrast.py` β€” measures every style palette against WCAG AA:
text pairs at 4.5:1, focus indicators at 3:1, in both themes. It resolves dark
as light-then-dark (dark blocks are partial overrides, so the pairs most
likely to fail were the ones never being checked) and composites translucent
colors before measuring. Waivers require a written reason.
- CI now runs the contrast check, and **renders all 15 example pages** at
1440/768/390/360 with `scripts/screenshot.mjs`, failing on mobile overflow and
uploading the screenshots as an artifact. The render check existed in 2.0.0
but only ever ran by hand.

### Fixed
- **Focus rings were invisible across 14 of 15 styles.** Every one used a
translucent color (alpha 0.30–0.45), compositing to 1.2–1.8:1 against its own
background β€” the exact πŸ”΄ BLOCKER `ANTI-SLOP.md` defines. All are now solid.
Two styles were also contradicting their own Β§13: 05 documents a "thick black
outline" and shipped a pink ring at 1.98:1; 06 documents a "high-contrast
outline" and shipped neon yellow at 1.04:1. Both now use their text color.
- **14 of 15 example pages had no authored focus style at all** β€” no
`:focus-visible`, no `:focus`, no `outline`. Each now ships one, using a
palette color verified at 3:1 against that page's own background.
- **11 button/label pairs failed 4.5:1** β€” white-on-mid-tone labels at 1.86–4.48:1.
Fixed by adapting the label where the fill is a light tint, and by an
imperceptible darkening of the fill elsewhere; brand hues are preserved.
- **Glassmorphism's accent was `#8B5CF6`** β€” the exact hex `ANTI-SLOP.md` names
as the over-used default violet, and it failed contrast at 4.23:1. Now
`#7C3AED`: still unmistakably violet, off the flagged default, 5.70:1.
- `scripts/gen_tokens.py` treated **every** `:root` as the light palette,
including one nested inside `@media (prefers-reduced-motion: reduce)`. A token
misplaced there looked correct in the generated JSON while applying only to
reduced-motion users in a browser. At-rule blocks are now excluded.
- Example palettes re-synced to the corrected tokens, so no reference page
demonstrates a failure the tokens no longer have.

### Changed
- `design-tokens/TOKENS-GUIDE.md`, `accessibility/ACCESSIBILITY.md`,
`CONTRIBUTING.md` and both READMEs document the enforced checks β€” including
why `--color-border` is deliberately *not* held to 3:1 (WCAG 1.4.11 exempts
boundaries not needed to identify a component; failing all 15 styles on
hairlines would get the check switched off).

## [2.0.0] β€” 2026-09-04

The onboarding and routing release. The design knowledge was already here; this
Expand Down
11 changes: 7 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ measurably better, and bad if it only makes the documentation longer.**
## Before you open a PR

```bash
python3 scripts/validate.py # what CI runs
python3 scripts/validate.py # structure, links, generated files
python3 scripts/check_contrast.py # WCAG AA on every style palette
node scripts/screenshot.mjs # render all 15 examples, catch overflow
```

The first is what CI runs. It checks every style folder, every required file, every
All three run in CI. It checks every style folder, every required file, every
internal link, every generated file's freshness, and the 24-section structure
of the style DNAs.

Expand Down Expand Up @@ -84,8 +85,10 @@ styles/16-your-style/
spacing, radius, shadows, borders, container, motion, motion-ease β€”
including `--shadow-focus`.
- [ ] Light theme in `:root`, dark theme in `[data-theme="dark"]`.
- [ ] Contrast verified: every text/background pair used together passes
4.5:1 (body) or 3:1 (large text and UI boundaries).
- [ ] `python3 scripts/check_contrast.py` passes for the new style β€” every
text/background pair and the focus indicator, in both themes. Focus rings
must be **solid**: a translucent ring composites to roughly a third of the
contrast it looks like it has.
- [ ] `example.html` opens in a browser with no build step and no network
dependency beyond webfonts, and holds at **1440 / 768 / 390 / 360** β€”
verify with `node scripts/screenshot.mjs <your-style-id>`.
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
**Teach your coding agent *how to design* β€” not just how to code.**

[![License: MIT](https://img.shields.io/badge/License-MIT-black.svg)](LICENSE)
[![Skill v2.0.0](https://img.shields.io/badge/skill-v2.0.0-black.svg)](SKILL.md)
[![Skill v2.0.0](https://img.shields.io/badge/skill-v2.1.0-black.svg)](SKILL.md)
[![15 styles](https://img.shields.io/badge/styles-15-black.svg)](#the-15-styles)
[![validate](https://github.com/aievolutionpl/agent-design-taste/actions/workflows/validate.yml/badge.svg)](https://github.com/aievolutionpl/agent-design-taste/actions/workflows/validate.yml)

Expand Down Expand Up @@ -394,6 +394,7 @@ Fifteen is noise with a brief buried in it.**

```bash
python3 scripts/validate.py # full structural check β€” what CI runs
python3 scripts/check_contrast.py # WCAG AA on every style palette
python3 scripts/validate.py --budget # measured context cost per file
python3 scripts/gen_tokens.py # regenerate tokens.json + tokens.tailwind.css
python3 scripts/gen_manifest.py # regenerate styles/index.json + manifest
Expand All @@ -403,7 +404,9 @@ node scripts/screenshot.mjs 10 # render a style at 1440/768/390/360
CI verifies that every style folder is complete, every required token category
exists (including `--shadow-focus`), every internal link resolves, every
`example.html` parses, all 15 DNAs share the 24-section architecture, and every
generated file is in sync with its source.
generated file is in sync with its source. It also **measures** every palette
against WCAG AA and **renders** all 15 example pages at 1440/768/390/360,
failing on horizontal overflow. The rules are enforced, not just written down.

Adding style #16? [`CONTRIBUTING.md`](CONTRIBUTING.md) and
[`docs/STYLE-TEMPLATE.md`](docs/STYLE-TEMPLATE.md) have the full checklist.
Expand Down
8 changes: 6 additions & 2 deletions README.pl.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
**Naucz swojego agenta *jak projektować* — nie tylko jak kodować.**

[![Licencja: MIT](https://img.shields.io/badge/License-MIT-black.svg)](LICENSE)
[![Skill v2.0.0](https://img.shields.io/badge/skill-v2.0.0-black.svg)](SKILL.md)
[![Skill v2.0.0](https://img.shields.io/badge/skill-v2.1.0-black.svg)](SKILL.md)
[![15 stylΓ³w](https://img.shields.io/badge/style-15-black.svg)](#15-stylΓ³w)
[![validate](https://github.com/aievolutionpl/agent-design-taste/actions/workflows/validate.yml/badge.svg)](https://github.com/aievolutionpl/agent-design-taste/actions/workflows/validate.yml)

Expand Down Expand Up @@ -408,6 +408,7 @@ szum z briefem gdzieΕ› w Ε›rodku.**

```bash
python3 scripts/validate.py # peΕ‚na kontrola strukturalna β€” to samo co CI
python3 scripts/check_contrast.py # WCAG AA dla palety kaΕΌdego stylu
python3 scripts/validate.py --budget # zmierzony koszt kontekstu per plik
python3 scripts/gen_tokens.py # regeneruje tokens.json + tokens.tailwind.css
python3 scripts/gen_manifest.py # regeneruje styles/index.json + manifest
Expand All @@ -417,7 +418,10 @@ node scripts/screenshot.mjs 10 # renderuje styl w 1440/768/390/360
CI sprawdza, czy kaΕΌdy folder stylu jest kompletny, czy istniejΔ… wszystkie
wymagane kategorie tokenΓ³w (w tym `--shadow-focus`), czy kaΕΌdy link wewnΔ™trzny
dziaΕ‚a, czy kaΕΌdy `example.html` siΔ™ parsuje, czy wszystkie 15 DNA ma tΔ™ samΔ…
24-sekcyjnΔ… strukturΔ™ i czy pliki generowane sΔ… zgodne ze ΕΊrΓ³dΕ‚em.
24-sekcyjnΔ… strukturΔ™ i czy pliki generowane sΔ… zgodne ze ΕΊrΓ³dΕ‚em. CI dodatkowo
**mierzy** kaΕΌdΔ… paletΔ™ wzglΔ™dem WCAG AA i **renderuje** wszystkie 15 stron
przykΕ‚adowych w 1440/768/390/360, koΕ„czΔ…c bΕ‚Δ™dem przy przewijaniu poziomym.
ReguΕ‚y sΔ… egzekwowane, nie tylko zapisane.

Dodajesz styl #16? [`CONTRIBUTING.md`](CONTRIBUTING.md) i
[`docs/STYLE-TEMPLATE.md`](docs/STYLE-TEMPLATE.md) majΔ… peΕ‚nΔ… listΔ™ kontrolnΔ….
Expand Down
2 changes: 1 addition & 1 deletion SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: agent-design-taste
description: Use when generating, redesigning or reviewing any UI β€” landing page, dashboard, app screen, component, or design system. Teaches the agent to analyze product and audience first, choose one design style deliberately, build from real tokens, render it, and audit it β€” instead of producing generic "modern premium AI SaaS" output.
license: MIT
version: 2.0.0
version: 2.1.0
metadata:
repository: https://github.com/aievolutionpl/agent-design-taste
styles: 15
Expand Down
8 changes: 8 additions & 0 deletions accessibility/ACCESSIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ outlines without replacing them makes the interface unusable by keyboard β€”

- The ring needs **3:1 against both** the component and the page behind it.
A blue ring on a blue button is invisible.
- **Make the ring solid.** A ring at 30–40% opacity composites to roughly a
third of the contrast its hue suggests β€” `rgb(37 99 235 / 0.35)` on white
measures about 1.8:1, not the 5.2:1 the colour alone would give. Every style
in this repository shipped a translucent ring once; all of them failed. If
you want a soft glow, put it *outside* a solid ring, not instead of one.
- Verify it, don't eyeball it: `python3 scripts/check_contrast.py` resolves each
style's `--shadow-focus`, composites any alpha, and measures it against both
the page and the surface.
- Style-specific traps: glass and neumorphism swallow thin rings β€” go thicker
and solid; brutalism already *is* a thick outline, so keep it and add offset.
- Never let a sticky header cover the focused element. `scroll-margin-top` on
Expand Down
5 changes: 3 additions & 2 deletions design-taste.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"name": "agent-design-taste",
"title": "Agent Design Taste",
"tagline": "Design Intelligence for AI Agents",
"repositoryVersion": "2.0.0",
"skillVersion": "2.0.0",
"repositoryVersion": "2.1.0",
"skillVersion": "2.1.0",
"license": "MIT",
"repository": "https://github.com/aievolutionpl/agent-design-taste",
"entrypoints": {
Expand Down Expand Up @@ -126,6 +126,7 @@
"generateManifest": "scripts/gen_manifest.py",
"validate": "scripts/validate.py",
"screenshot": "scripts/screenshot.mjs",
"checkContrast": "scripts/check_contrast.py",
"install": "scripts/install.sh"
},
"styleCount": 15,
Expand Down
17 changes: 14 additions & 3 deletions design-tokens/TOKENS-GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,20 @@ Minimum color roles: `bg` Β· `surface` Β· `text` Β· `text-secondary` Β· `border`
consuming project, and should be documented where it is added.
3. **No ad-hoc values.** If you type `13px` or `#7c3aed` in a component, either
it should be a token or the tokens are wrong. Fix the tokens.
4. **Contrast is part of the token contract.** Every text/background pair used
together passes 4.5:1 (body) or 3:1 (large text and UI boundaries) β€” in both
themes. See `accessibility/ACCESSIBILITY.md`.
4. **Contrast is part of the token contract, and it is enforced.**
`python3 scripts/check_contrast.py` measures every text/background pair and
every focus indicator in both themes, and CI fails on a miss. It resolves the
dark palette as light-then-dark (dark blocks are partial overrides) and
composites translucent colors before measuring β€” a ring at 35% opacity is
measured as what it actually paints, not as the hue it was authored in.
A style that genuinely cannot pass a pair adds a waiver **with a reason**
rather than silencing the check. See `accessibility/ACCESSIBILITY.md`.

Not checked at 3:1: `--color-border` against surfaces. WCAG 1.4.11 requires
that of boundaries *needed to identify a component*, not of every hairline β€”
dividers and subtle card edges are exempt, and failing all 15 styles on it
would get the check switched off. `--shadow-focus` carries that requirement
instead, and it is checked.
5. **Semantic over literal** where hierarchy matters: `--color-text-secondary`,
not `--color-gray-500`. Literal scales are fine for spacing.

Expand Down
Loading
Loading