@brunosps00/dev-workflow 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -5
- package/lib/constants.js +20 -20
- package/lib/init.js +24 -1
- package/lib/migrate-skills.js +129 -0
- package/lib/removed-bundled-skills.js +16 -0
- package/lib/uninstall.js +6 -2
- package/lib/utils.js +43 -1
- package/package.json +1 -1
- package/scaffold/en/agent-instructions.md +68 -0
- package/scaffold/en/commands/dw-autopilot.md +1 -1
- package/scaffold/en/commands/dw-brainstorm.md +1 -1
- package/scaffold/en/commands/dw-bugfix.md +3 -3
- package/scaffold/en/commands/dw-create-techspec.md +1 -1
- package/scaffold/en/commands/dw-deps-audit.md +1 -1
- package/scaffold/en/commands/dw-fix-qa.md +1 -1
- package/scaffold/en/commands/dw-functional-doc.md +2 -2
- package/scaffold/en/commands/dw-help.md +1 -1
- package/scaffold/en/commands/dw-redesign-ui.md +7 -7
- package/scaffold/en/commands/dw-run-qa.md +4 -4
- package/scaffold/en/commands/dw-run-task.md +2 -2
- package/scaffold/en/templates/constitution-template.md +1 -1
- package/scaffold/pt-br/agent-instructions.md +68 -0
- package/scaffold/pt-br/commands/dw-autopilot.md +1 -1
- package/scaffold/pt-br/commands/dw-brainstorm.md +1 -1
- package/scaffold/pt-br/commands/dw-bugfix.md +3 -3
- package/scaffold/pt-br/commands/dw-create-techspec.md +1 -1
- package/scaffold/pt-br/commands/dw-deps-audit.md +1 -1
- package/scaffold/pt-br/commands/dw-fix-qa.md +1 -1
- package/scaffold/pt-br/commands/dw-functional-doc.md +2 -2
- package/scaffold/pt-br/commands/dw-help.md +1 -1
- package/scaffold/pt-br/commands/dw-redesign-ui.md +7 -7
- package/scaffold/pt-br/commands/dw-run-qa.md +4 -4
- package/scaffold/pt-br/commands/dw-run-task.md +2 -2
- package/scaffold/pt-br/templates/constitution-template.md +1 -1
- package/scaffold/skills/dw-council/SKILL.md +1 -1
- package/scaffold/skills/dw-testing-discipline/SKILL.md +148 -0
- package/scaffold/skills/dw-testing-discipline/references/ai-agent-gates.md +170 -0
- package/scaffold/skills/dw-testing-discipline/references/anti-patterns.md +336 -0
- package/scaffold/skills/dw-testing-discipline/references/flaky-discipline.md +163 -0
- package/scaffold/skills/dw-testing-discipline/references/iron-laws.md +128 -0
- package/scaffold/skills/dw-testing-discipline/references/playwright-recipes.md +282 -0
- package/scaffold/skills/dw-testing-discipline/references/positive-patterns.md +241 -0
- package/scaffold/skills/{webapp-testing → dw-testing-discipline}/references/security-boundary.md +1 -1
- package/scaffold/skills/dw-ui-discipline/SKILL.md +128 -0
- package/scaffold/skills/dw-ui-discipline/references/accessibility-floor.md +225 -0
- package/scaffold/skills/dw-ui-discipline/references/anti-slop.md +162 -0
- package/scaffold/skills/dw-ui-discipline/references/curated-defaults.md +195 -0
- package/scaffold/skills/dw-ui-discipline/references/hard-gate.md +142 -0
- package/scaffold/skills/dw-ui-discipline/references/state-matrix.md +101 -0
- package/scaffold/skills/ui-ux-pro-max/LICENSE +0 -21
- package/scaffold/skills/ui-ux-pro-max/SKILL.md +0 -659
- package/scaffold/skills/ui-ux-pro-max/data/_sync_all.py +0 -414
- package/scaffold/skills/ui-ux-pro-max/data/app-interface.csv +0 -31
- package/scaffold/skills/ui-ux-pro-max/data/charts.csv +0 -26
- package/scaffold/skills/ui-ux-pro-max/data/colors.csv +0 -162
- package/scaffold/skills/ui-ux-pro-max/data/design.csv +0 -1776
- package/scaffold/skills/ui-ux-pro-max/data/draft.csv +0 -1779
- package/scaffold/skills/ui-ux-pro-max/data/google-fonts.csv +0 -1924
- package/scaffold/skills/ui-ux-pro-max/data/icons.csv +0 -106
- package/scaffold/skills/ui-ux-pro-max/data/landing.csv +0 -35
- package/scaffold/skills/ui-ux-pro-max/data/products.csv +0 -162
- package/scaffold/skills/ui-ux-pro-max/data/react-performance.csv +0 -45
- package/scaffold/skills/ui-ux-pro-max/data/stacks/angular.csv +0 -51
- package/scaffold/skills/ui-ux-pro-max/data/stacks/astro.csv +0 -54
- package/scaffold/skills/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
- package/scaffold/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
- package/scaffold/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +0 -53
- package/scaffold/skills/ui-ux-pro-max/data/stacks/laravel.csv +0 -51
- package/scaffold/skills/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
- package/scaffold/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
- package/scaffold/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
- package/scaffold/skills/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
- package/scaffold/skills/ui-ux-pro-max/data/stacks/react.csv +0 -54
- package/scaffold/skills/ui-ux-pro-max/data/stacks/shadcn.csv +0 -61
- package/scaffold/skills/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
- package/scaffold/skills/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
- package/scaffold/skills/ui-ux-pro-max/data/stacks/threejs.csv +0 -54
- package/scaffold/skills/ui-ux-pro-max/data/stacks/vue.csv +0 -50
- package/scaffold/skills/ui-ux-pro-max/data/styles.csv +0 -85
- package/scaffold/skills/ui-ux-pro-max/data/typography.csv +0 -74
- package/scaffold/skills/ui-ux-pro-max/data/ui-reasoning.csv +0 -162
- package/scaffold/skills/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
- package/scaffold/skills/ui-ux-pro-max/scripts/core.py +0 -262
- package/scaffold/skills/ui-ux-pro-max/scripts/design_system.py +0 -1148
- package/scaffold/skills/ui-ux-pro-max/scripts/search.py +0 -114
- package/scaffold/skills/ui-ux-pro-max/skills/brand/SKILL.md +0 -97
- package/scaffold/skills/ui-ux-pro-max/skills/design/SKILL.md +0 -302
- package/scaffold/skills/ui-ux-pro-max/skills/design-system/SKILL.md +0 -244
- package/scaffold/skills/ui-ux-pro-max/templates/base/quick-reference.md +0 -297
- package/scaffold/skills/ui-ux-pro-max/templates/base/skill-content.md +0 -358
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/agent.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/augment.json +0 -18
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/claude.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/codebuddy.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/codex.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/continue.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/copilot.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/cursor.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/droid.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/gemini.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/kilocode.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/kiro.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/opencode.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/qoder.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/roocode.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/trae.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/warp.json +0 -18
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/windsurf.json +0 -21
- package/scaffold/skills/webapp-testing/SKILL.md +0 -138
- package/scaffold/skills/webapp-testing/assets/test-helper.js +0 -56
- /package/scaffold/skills/{webapp-testing → dw-testing-discipline}/references/three-workflow-patterns.md +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dw-ui-discipline
|
|
3
|
+
description: Use BEFORE any UI work — enforces a hard-gate (brand authorities or curated defaults, surface job, state matrix, scene sentence), 14 anti-slop patterns, and WCAG 2.2 AA floor so UI ships with discipline instead of training-data defaults.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# UI Discipline
|
|
7
|
+
|
|
8
|
+
> **Inspired by** [`pedronauck/skills/ui-craft`](https://github.com/pedronauck/skills/tree/main/skills/mine/ui-craft) (MIT). Hard-gate protocol, anti-slop catalog, state matrix enforcement, and accessibility-floor patterns adapted from Pedro Nauck's work; specifics rewritten for dev-workflow's redesign and review loops.
|
|
9
|
+
|
|
10
|
+
The fastest path through UI work is the disciplined one. "It's just a small change" is the most common slop excuse. This skill blocks that excuse at four checkpoints before any design decision lands.
|
|
11
|
+
|
|
12
|
+
## When this skill applies
|
|
13
|
+
|
|
14
|
+
- Any work invoked from `/dw-redesign-ui`, `/dw-create-techspec` (UI sections), `/dw-functional-doc`, or `/dw-code-review` when the diff touches UI.
|
|
15
|
+
- Adding new screens, components, or surfaces.
|
|
16
|
+
- Reviewing visual changes in a PR.
|
|
17
|
+
- Auditing accessibility on existing surfaces.
|
|
18
|
+
|
|
19
|
+
If you're tempted to skip the gate "because it's just a tweak" — that's the trigger. Run the gate.
|
|
20
|
+
|
|
21
|
+
## The hard-gate (4 mandatory items before any UI work)
|
|
22
|
+
|
|
23
|
+
Before proposing colors, layouts, components, or any visual decision, complete all four:
|
|
24
|
+
|
|
25
|
+
### 1. Brand authorities OR curated defaults
|
|
26
|
+
|
|
27
|
+
Locate the project's design source of truth:
|
|
28
|
+
- `.dw/rules/{frontend-module}.md` design system section
|
|
29
|
+
- `DESIGN.md`, `BRAND.md`, or design tokens config (Tailwind, CSS vars, theme file)
|
|
30
|
+
- Component library docs (shadcn/ui, MUI, Chakra, etc.)
|
|
31
|
+
|
|
32
|
+
If **none exist**, do NOT invent. Read `references/curated-defaults.md` — pick from the 10 neutral palettes + 10 font pairings shipped there. Mark the choice as a finding in the techspec ("no design authority found; used curated default <name>; recommend establishing one").
|
|
33
|
+
|
|
34
|
+
### 2. Surface job sentence
|
|
35
|
+
|
|
36
|
+
Write one sentence: "This surface helps the user <do what> so that <outcome>." Vague language ("show data", "manage settings") fails — be specific ("filter overdue invoices so they can chase late payers in <30s").
|
|
37
|
+
|
|
38
|
+
If you can't write the sentence, the requirements are unclear. Stop and clarify before proceeding.
|
|
39
|
+
|
|
40
|
+
### 3. Complete state matrix
|
|
41
|
+
|
|
42
|
+
Enumerate all states the surface can be in. See `references/state-matrix.md` for the full list:
|
|
43
|
+
- `default`, `hover`, `active`, `focus-visible`, `disabled`, `loading`, `empty`, `error`, `success`
|
|
44
|
+
- Plus any domain-specific states (read/unread, online/offline, etc.)
|
|
45
|
+
|
|
46
|
+
Missing a state at design time = production bug later. The "we'll add empty state later" trap is real.
|
|
47
|
+
|
|
48
|
+
### 4. Scene sentence
|
|
49
|
+
|
|
50
|
+
One sentence describing the physical context: **who** is using this, **where** (mobile bus, office desktop, on-call laptop), **what light** (dark room, bright outdoor), **what mood** (rushed, exploring, troubleshooting).
|
|
51
|
+
|
|
52
|
+
This forcing function prevents category-level defaults from becoming the answer. A "dashboard for an on-call engineer at 3am in a dark room troubleshooting a fire" produces different decisions than "dashboard for a manager during business hours."
|
|
53
|
+
|
|
54
|
+
## Required Reading Router
|
|
55
|
+
|
|
56
|
+
| Context | Read |
|
|
57
|
+
|---------|------|
|
|
58
|
+
| Any UI work | `references/hard-gate.md` (full protocol with examples) |
|
|
59
|
+
| Interactive widgets (buttons, forms, modals) | `references/accessibility-floor.md` (WCAG 2.2 AA non-negotiable) |
|
|
60
|
+
| Reviewing a UI diff | `references/anti-slop.md` (14 anti-patterns + 17 anti-defaults) |
|
|
61
|
+
| Designing state coverage | `references/state-matrix.md` (full enumeration + checklist) |
|
|
62
|
+
| No design authority exists in project | `references/curated-defaults.md` (10 palettes + 10 fonts) |
|
|
63
|
+
|
|
64
|
+
## Anti-slop summary (full list in references/anti-slop.md)
|
|
65
|
+
|
|
66
|
+
The 14 patterns this skill catches:
|
|
67
|
+
|
|
68
|
+
1. **Visual sameness** — every section looks like every other section.
|
|
69
|
+
2. **Weak hierarchy** — nothing draws the eye to what matters first.
|
|
70
|
+
3. **Fake interactivity** — hover states that don't change anything functional.
|
|
71
|
+
4. **Emoji spam** — emojis as decoration where icons or restraint would serve.
|
|
72
|
+
5. **Gradient crutch** — gradients used to mask weak composition.
|
|
73
|
+
6. **Glass everything** — frosted glass on every panel.
|
|
74
|
+
7. **Centered all the things** — center-aligned text when left-aligned reads better.
|
|
75
|
+
8. **AI gray washing** — neutral grays everywhere, no character.
|
|
76
|
+
9. **Generic CTAs** — "Get Started", "Learn More", "Click Here" with no specificity.
|
|
77
|
+
10. **Stock illustration** — generic figure-with-laptop hero art.
|
|
78
|
+
11. **Drop shadow soup** — shadows on cards on shadows on borders.
|
|
79
|
+
12. **Loading spinner default** — spinner as the only loading state for everything.
|
|
80
|
+
13. **Empty state void** — empty list with no guidance on what to do next.
|
|
81
|
+
14. **Notification-soup tray** — every UI event becomes a toast.
|
|
82
|
+
|
|
83
|
+
Plus 17 anti-defaults (specific values to NEVER use without intent — `#3B82F6` blue, `rounded-lg` everywhere, etc.) in `references/anti-slop.md`.
|
|
84
|
+
|
|
85
|
+
## Accessibility floor — non-negotiable
|
|
86
|
+
|
|
87
|
+
Before any interactive widget ships:
|
|
88
|
+
|
|
89
|
+
- [ ] Color contrast meets WCAG 2.2 AA (4.5:1 for body text, 3:1 for large text and UI components).
|
|
90
|
+
- [ ] Focus-visible state exists and is distinct from hover.
|
|
91
|
+
- [ ] Keyboard navigation works (tab order, escape closes modals, enter submits forms).
|
|
92
|
+
- [ ] ARIA labels for icon-only buttons.
|
|
93
|
+
- [ ] Form errors are announced to screen readers.
|
|
94
|
+
- [ ] No keyboard traps.
|
|
95
|
+
|
|
96
|
+
Full verification recipes in `references/accessibility-floor.md`. This is a hard gate — `/dw-code-review` fails verdict if any interactive widget ships without these.
|
|
97
|
+
|
|
98
|
+
## When the gate bends
|
|
99
|
+
|
|
100
|
+
Real-world UI can't always be perfect:
|
|
101
|
+
|
|
102
|
+
- **Bug fix in existing UI** — gate applies only to the area touched, not the whole surface.
|
|
103
|
+
- **Pure copy change** — gate is just "scene sentence still holds?" — quick check.
|
|
104
|
+
- **Spike / exploration** — gate skipped if the spike is explicitly marked throwaway; production code must run the gate.
|
|
105
|
+
|
|
106
|
+
In all bend cases, document the bend in the PR description (one line). "I skipped the state matrix because this is a one-line copy fix" is fine. "I skipped because I was in a hurry" is not.
|
|
107
|
+
|
|
108
|
+
## Integration with dev-workflow commands
|
|
109
|
+
|
|
110
|
+
- `/dw-redesign-ui` runs the gate end-to-end. Steps 4 (propose design) and 7 (validate WCAG) consult this skill.
|
|
111
|
+
- `/dw-create-techspec` UI sections must list which authorities were consulted (brand vs curated default) and reference the state matrix.
|
|
112
|
+
- `/dw-code-review` checks the diff against `references/anti-slop.md` and the accessibility floor.
|
|
113
|
+
- `/dw-functional-doc` documents the scene sentence in the overview.
|
|
114
|
+
|
|
115
|
+
## Anti-patterns this skill prevents
|
|
116
|
+
|
|
117
|
+
- "Just use the same hero as the marketing page" — without verifying the surface job differs.
|
|
118
|
+
- "We'll add empty/error states later" — they're never added later.
|
|
119
|
+
- "It looks fine on my desktop" — without checking mobile + keyboard + screen reader.
|
|
120
|
+
- Designing in isolation from `.dw/rules/` documented patterns.
|
|
121
|
+
- Inventing color values when the design system has tokens that fit.
|
|
122
|
+
- Shipping interactive widgets without WCAG 2.2 AA verification.
|
|
123
|
+
|
|
124
|
+
## Why this skill exists
|
|
125
|
+
|
|
126
|
+
The previous bundled skill (`ui-ux-pro-max`) provided 161 color palettes and 57 font pairings — a CATALOG of taste. It had no gates, no anti-patterns, no enforcement. Agents loaded KB of palette data and still produced slop because there was no DISCIPLINE.
|
|
127
|
+
|
|
128
|
+
This skill inverts that trade-off: 10 curated defaults (enough for 90% of cases) + a strong gate + an anti-slop catalog. Less context bytes, more leverage.
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Accessibility floor — WCAG 2.2 AA is the minimum, not the goal
|
|
2
|
+
|
|
3
|
+
This reference is read in full before any interactive widget ships. Skipping any item below is a hard-block in `/dw-code-review`.
|
|
4
|
+
|
|
5
|
+
## The non-negotiables
|
|
6
|
+
|
|
7
|
+
### 1. Color contrast
|
|
8
|
+
|
|
9
|
+
| Element | Minimum ratio (WCAG 2.2 AA) |
|
|
10
|
+
|---------|----------------------------|
|
|
11
|
+
| Body text (under 18pt or under 14pt bold) | 4.5:1 |
|
|
12
|
+
| Large text (18pt+ or 14pt+ bold) | 3:1 |
|
|
13
|
+
| UI components (button borders, icons, focus rings) | 3:1 |
|
|
14
|
+
| Decorative graphics | No requirement |
|
|
15
|
+
|
|
16
|
+
**Verification:**
|
|
17
|
+
- Use `axe DevTools` browser extension OR `playwright/test` with `@axe-core/playwright`.
|
|
18
|
+
- Manual quick check: `chrome://flags` → Enable "Simulate Vision Deficiencies" + try "Achromatopsia" (no colors). If buttons still legible, contrast is doing its job.
|
|
19
|
+
|
|
20
|
+
**Common violation:** Light gray text on white. `#9CA3AF` on white = 2.85:1. FAIL.
|
|
21
|
+
|
|
22
|
+
### 2. Focus-visible state
|
|
23
|
+
|
|
24
|
+
Every interactive element must have a distinct focus-visible state when keyboard-focused.
|
|
25
|
+
|
|
26
|
+
**Rules:**
|
|
27
|
+
- `:focus-visible` MUST be distinct from `:hover` — keyboard users need an affordance.
|
|
28
|
+
- Default browser outline is acceptable; replacing with `outline: none` requires alternative (border, ring, shadow).
|
|
29
|
+
- Focus must be visible against any background the element can appear on (dark + light themes).
|
|
30
|
+
|
|
31
|
+
**Tailwind pattern:**
|
|
32
|
+
```css
|
|
33
|
+
focus-visible:outline-none
|
|
34
|
+
focus-visible:ring-2
|
|
35
|
+
focus-visible:ring-offset-2
|
|
36
|
+
focus-visible:ring-blue-500
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Verification:**
|
|
40
|
+
- Tab through the entire surface with keyboard. Every interactive element must light up visibly.
|
|
41
|
+
- If you can't tell what's focused, the contrast on the focus ring is too low.
|
|
42
|
+
|
|
43
|
+
### 3. Keyboard navigation
|
|
44
|
+
|
|
45
|
+
| Capability | Requirement |
|
|
46
|
+
|------------|-------------|
|
|
47
|
+
| Tab order | Logical (left-to-right, top-to-bottom in LTR) |
|
|
48
|
+
| Modals | Tab cycles WITHIN modal; Escape closes; focus returns to trigger |
|
|
49
|
+
| Dropdowns / select | Arrow keys navigate options; Enter selects; Escape closes |
|
|
50
|
+
| Forms | Enter submits; Tab moves to next field; Shift+Tab moves back |
|
|
51
|
+
| Custom widgets | Match the ARIA Authoring Practices Guide patterns |
|
|
52
|
+
|
|
53
|
+
**Verification:**
|
|
54
|
+
- Unplug mouse. Complete the primary user flow with keyboard only.
|
|
55
|
+
- If you got stuck or couldn't reach an element, keyboard nav is broken.
|
|
56
|
+
|
|
57
|
+
### 4. ARIA labels for icon-only interactives
|
|
58
|
+
|
|
59
|
+
Icon-only buttons (e.g., a trash can icon as a delete button) need `aria-label` describing the action.
|
|
60
|
+
|
|
61
|
+
```html
|
|
62
|
+
<!-- BAD -->
|
|
63
|
+
<button><TrashIcon /></button>
|
|
64
|
+
|
|
65
|
+
<!-- GOOD -->
|
|
66
|
+
<button aria-label="Delete invoice"><TrashIcon /></button>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Same applies to:
|
|
70
|
+
- Icon-only links
|
|
71
|
+
- Icon-only toggles
|
|
72
|
+
- Tooltips (the trigger needs aria-describedby pointing to the tooltip)
|
|
73
|
+
- Decorative images (`aria-hidden="true"` if purely decorative; `alt=""` not enough)
|
|
74
|
+
|
|
75
|
+
### 5. Form errors announced to screen readers
|
|
76
|
+
|
|
77
|
+
When a form field errors:
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<label for="email">Email</label>
|
|
81
|
+
<input
|
|
82
|
+
id="email"
|
|
83
|
+
type="email"
|
|
84
|
+
aria-describedby="email-error"
|
|
85
|
+
aria-invalid="true"
|
|
86
|
+
/>
|
|
87
|
+
<span id="email-error" role="alert">
|
|
88
|
+
Email is required
|
|
89
|
+
</span>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Key points:
|
|
93
|
+
- `aria-invalid="true"` on the input.
|
|
94
|
+
- `aria-describedby` links the input to the error message.
|
|
95
|
+
- `role="alert"` on the error message announces it.
|
|
96
|
+
|
|
97
|
+
**Anti-pattern:** Red border + tooltip on hover. Screen reader users get nothing.
|
|
98
|
+
|
|
99
|
+
### 6. No keyboard traps
|
|
100
|
+
|
|
101
|
+
A "keyboard trap" is when focus enters a widget and can't leave with the keyboard. Most common cause: custom-built modals or carousels.
|
|
102
|
+
|
|
103
|
+
**Rule:** Every modal, drawer, or overlay must let Escape close it and return focus to the trigger element.
|
|
104
|
+
|
|
105
|
+
**Verification:**
|
|
106
|
+
- Open the widget with keyboard. Press Escape. Does focus return to where it was?
|
|
107
|
+
- Tab through the widget. After last element, does Tab cycle to first (within widget) instead of leaving the page?
|
|
108
|
+
|
|
109
|
+
### 7. Touch target size (mobile)
|
|
110
|
+
|
|
111
|
+
Minimum 24x24 CSS pixels (WCAG 2.2 AA minimum). Recommended 44x44 (Apple HIG / Android touch target).
|
|
112
|
+
|
|
113
|
+
**Pattern:** Even when the visual icon is 16x16, give the button 44x44 hit area:
|
|
114
|
+
|
|
115
|
+
```css
|
|
116
|
+
button {
|
|
117
|
+
width: 24px; height: 24px; /* WCAG 2.2 AA minimum */
|
|
118
|
+
/* Or */
|
|
119
|
+
width: 44px; height: 44px; /* Recommended */
|
|
120
|
+
padding: 14px; /* Visual icon inside */
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 8. Heading hierarchy
|
|
125
|
+
|
|
126
|
+
H1 → H2 → H3 etc. Don't skip levels. Don't use heading tags for visual sizing — use semantic level + CSS for size.
|
|
127
|
+
|
|
128
|
+
```html
|
|
129
|
+
<!-- BAD -->
|
|
130
|
+
<h2>Section A</h2>
|
|
131
|
+
<h4>Subsection</h4> <!-- skipped h3 -->
|
|
132
|
+
|
|
133
|
+
<!-- GOOD -->
|
|
134
|
+
<h2>Section A</h2>
|
|
135
|
+
<h3>Subsection</h3>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Screen readers navigate by heading; broken hierarchy disorients.
|
|
139
|
+
|
|
140
|
+
### 9. Language attribute
|
|
141
|
+
|
|
142
|
+
Root `<html lang="en">` (or correct ISO code) for primary language. Sections in other language need `lang` attribute too.
|
|
143
|
+
|
|
144
|
+
```html
|
|
145
|
+
<html lang="en">
|
|
146
|
+
<p>Welcome.</p>
|
|
147
|
+
<p lang="pt-br">Bem-vindo.</p>
|
|
148
|
+
</html>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Screen readers switch pronunciation based on this.
|
|
152
|
+
|
|
153
|
+
### 10. Reduced motion respect
|
|
154
|
+
|
|
155
|
+
Honor `prefers-reduced-motion`:
|
|
156
|
+
|
|
157
|
+
```css
|
|
158
|
+
@media (prefers-reduced-motion: reduce) {
|
|
159
|
+
*, *::before, *::after {
|
|
160
|
+
animation-duration: 0.01ms !important;
|
|
161
|
+
transition-duration: 0.01ms !important;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Or in Tailwind:
|
|
167
|
+
```html
|
|
168
|
+
<div className="transition-all motion-reduce:transition-none">
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Vestibular disorders trigger on parallax, large slide-ins, infinite scroll animations.
|
|
172
|
+
|
|
173
|
+
## Verification recipes
|
|
174
|
+
|
|
175
|
+
### Automated (CI)
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
// playwright + axe-core
|
|
179
|
+
import { test, expect } from '@playwright/test';
|
|
180
|
+
import AxeBuilder from '@axe-core/playwright';
|
|
181
|
+
|
|
182
|
+
test('homepage a11y', async ({ page }) => {
|
|
183
|
+
await page.goto('/');
|
|
184
|
+
const results = await new AxeBuilder({ page })
|
|
185
|
+
.withTags(['wcag2a', 'wcag2aa', 'wcag22a', 'wcag22aa'])
|
|
186
|
+
.analyze();
|
|
187
|
+
expect(results.violations).toEqual([]);
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Run on every PR. Block merge on violations.
|
|
192
|
+
|
|
193
|
+
### Manual (PR review)
|
|
194
|
+
|
|
195
|
+
1. Open the changed page.
|
|
196
|
+
2. Tab through with keyboard only. Verify focus visible at every stop.
|
|
197
|
+
3. Run axe DevTools, fix violations.
|
|
198
|
+
4. Toggle prefers-reduced-motion in DevTools rendering panel. Verify animations stop.
|
|
199
|
+
5. Test with screen reader (VoiceOver on Mac, NVDA on Windows) on at least one critical flow.
|
|
200
|
+
|
|
201
|
+
### Spot checks
|
|
202
|
+
|
|
203
|
+
Color contrast: chrome devtools → element inspector → "Contrast" indicator next to text color. Click for actual ratio.
|
|
204
|
+
|
|
205
|
+
Touch target: Inspect element → check computed width/height. If < 24, flag.
|
|
206
|
+
|
|
207
|
+
## When the floor bends
|
|
208
|
+
|
|
209
|
+
- **Iframes you don't control** — your wrapper still has to be accessible, the iframe is best-effort.
|
|
210
|
+
- **Third-party widgets** (analytics dashboards, payment SDKs) — wrap with ARIA landmarks; report violations upstream.
|
|
211
|
+
- **Legacy code being patched** — bring touched components up to floor; leave untouched ones for separate accessibility-debt work.
|
|
212
|
+
|
|
213
|
+
In all bend cases, file a tracking issue. Don't pretend the floor was met.
|
|
214
|
+
|
|
215
|
+
## Common AI-generated UI violations
|
|
216
|
+
|
|
217
|
+
LLM-produced UI commonly fails on:
|
|
218
|
+
- `<div onClick>` instead of `<button>` (not keyboard-accessible).
|
|
219
|
+
- Icon-only buttons with no aria-label.
|
|
220
|
+
- `text-gray-400` on white (contrast 2.8:1 — fail).
|
|
221
|
+
- `outline: none` with no replacement focus state.
|
|
222
|
+
- Modals that trap focus only on success path, not on error.
|
|
223
|
+
- Auto-playing carousels with no pause control.
|
|
224
|
+
|
|
225
|
+
`/dw-code-review` runs axe-style checks on the diff for these.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Anti-slop catalog — 14 patterns + 17 anti-defaults
|
|
2
|
+
|
|
3
|
+
Every pattern below is a category of slop that LLMs produce when ungrounded. Detection happens in `/dw-code-review` (UI diffs) and design proposals from `/dw-redesign-ui`.
|
|
4
|
+
|
|
5
|
+
## The 14 patterns
|
|
6
|
+
|
|
7
|
+
### 1. Visual sameness
|
|
8
|
+
|
|
9
|
+
**What it looks like:** Every section of the page uses the same card style, same padding, same text size, same emphasis weight. The eye finds no anchor.
|
|
10
|
+
|
|
11
|
+
**Why it happens:** LLM defaults to "consistent = good," missing that hierarchy needs deliberate variation.
|
|
12
|
+
|
|
13
|
+
**Fix:** Establish one primary section per scroll-height. Use size, weight, color saturation, or whitespace differential to anchor the eye. Everything else recedes.
|
|
14
|
+
|
|
15
|
+
**Example violation:** Dashboard with 6 identical-looking metric cards. **Fix:** One hero metric (largest, brightest, top), 3 supporting metrics, 2 minor metrics in a different visual treatment.
|
|
16
|
+
|
|
17
|
+
### 2. Weak hierarchy
|
|
18
|
+
|
|
19
|
+
**What it looks like:** Headings barely larger than body. Important CTAs same color as secondary. The user can't tell what to look at first.
|
|
20
|
+
|
|
21
|
+
**Why it happens:** Defaults to "elegant restraint" without ensuring guidance still works.
|
|
22
|
+
|
|
23
|
+
**Fix:** Verify hierarchy by squinting at the design (literally) — what jumps out? If nothing jumps out, hierarchy is failing. Increase contrast in size, weight, or color for the primary element by at least 30%.
|
|
24
|
+
|
|
25
|
+
### 3. Fake interactivity
|
|
26
|
+
|
|
27
|
+
**What it looks like:** Hover states that change opacity but the click does nothing meaningful. Buttons that look interactive but don't have a job. Cards with subtle hover but no on-click handler.
|
|
28
|
+
|
|
29
|
+
**Why it happens:** LLM applies hover styles to anything that looks card-shaped.
|
|
30
|
+
|
|
31
|
+
**Fix:** Hover state ONLY on elements that have an on-click. If it can't be clicked, don't suggest it can. Use cursor: default explicitly on non-interactive shapes.
|
|
32
|
+
|
|
33
|
+
### 4. Emoji spam
|
|
34
|
+
|
|
35
|
+
**What it looks like:** 🎯 Goals · 🚀 Launch · ✨ Features · 📊 Analytics · 🔥 Trending — emojis as decoration in headers, CTAs, and section labels where they add no information.
|
|
36
|
+
|
|
37
|
+
**Why it happens:** LLM training data has tons of "emoji in headers = engaging" patterns.
|
|
38
|
+
|
|
39
|
+
**Fix:** Use icons (lucide, heroicons, tabler) for semantic meaning; reserve emojis for genuinely emotive contexts (celebrations, errors that need empathy). If you can remove the emoji and the meaning survives, remove it.
|
|
40
|
+
|
|
41
|
+
### 5. Gradient crutch
|
|
42
|
+
|
|
43
|
+
**What it looks like:** Hero with diagonal purple-to-pink gradient. Buttons with subtle gradient. Card backgrounds with mesh gradients. Every empty space gets a gradient.
|
|
44
|
+
|
|
45
|
+
**Why it happens:** Stable Diffusion / midjourney aesthetics leaked into UI; gradients hide weak composition.
|
|
46
|
+
|
|
47
|
+
**Fix:** A gradient must earn its place — usually for hero zones with poetic copy, never for utility surfaces. Solid colors + good hierarchy beat gradients 9 times out of 10.
|
|
48
|
+
|
|
49
|
+
### 6. Glass everything
|
|
50
|
+
|
|
51
|
+
**What it looks like:** Frosted-glass effect on modals, cards, dropdowns, side panels — anywhere a surface can be layered.
|
|
52
|
+
|
|
53
|
+
**Why it happens:** Apple's macOS aesthetic. Looks "premium" without effort.
|
|
54
|
+
|
|
55
|
+
**Fix:** Glass only when there's meaningful content visible behind the surface (a hero image, a busy dashboard). Glass on top of plain backgrounds adds blur for no reason.
|
|
56
|
+
|
|
57
|
+
### 7. Centered all the things
|
|
58
|
+
|
|
59
|
+
**What it looks like:** Body paragraphs center-aligned. Headlines centered. Forms with labels centered above inputs. Every text block reads center.
|
|
60
|
+
|
|
61
|
+
**Why it happens:** Marketing-page training data biases toward center-aligned.
|
|
62
|
+
|
|
63
|
+
**Fix:** Center-align for hero headlines and small CTA labels only. Body text and forms read better left-aligned (in LTR scripts). Tabular data reads in columns, not centered.
|
|
64
|
+
|
|
65
|
+
### 8. AI gray washing
|
|
66
|
+
|
|
67
|
+
**What it looks like:** Neutral gray palette everywhere. `slate-50`, `gray-100`, `zinc-200` for backgrounds, borders, text, accents. Nothing has color personality.
|
|
68
|
+
|
|
69
|
+
**Why it happens:** "Neutral = safe" default, plus shadcn/ui's neutral start.
|
|
70
|
+
|
|
71
|
+
**Fix:** Establish ONE accent color from the curated defaults or brand. Use it intentionally — primary CTAs, active states, the one place the user looks first. Gray is the canvas, not the painting.
|
|
72
|
+
|
|
73
|
+
### 9. Generic CTAs
|
|
74
|
+
|
|
75
|
+
**What it looks like:** "Get Started" · "Learn More" · "Click Here" · "Submit" · "OK" buttons.
|
|
76
|
+
|
|
77
|
+
**Why it happens:** Default LLM verb library.
|
|
78
|
+
|
|
79
|
+
**Fix:** Use the verb the user is actually doing. "Approve refund" not "Submit". "Start free trial" not "Get Started". "Schedule a call" not "Contact us". Generic verbs are tells.
|
|
80
|
+
|
|
81
|
+
### 10. Stock illustration
|
|
82
|
+
|
|
83
|
+
**What it looks like:** Figure-with-laptop hero art. Diverse-team-around-table illustration. Abstract floating shapes.
|
|
84
|
+
|
|
85
|
+
**Why it happens:** "Illustration = friendly" default. Cheap to produce, generic to consume.
|
|
86
|
+
|
|
87
|
+
**Fix:** Either use product screenshots (real screens, real data — sanitized) or skip illustration entirely. A clean hero with strong typography beats a generic illustration every time.
|
|
88
|
+
|
|
89
|
+
### 11. Drop shadow soup
|
|
90
|
+
|
|
91
|
+
**What it looks like:** Cards with shadow. Buttons with shadow. Inputs with shadow. Tooltips with shadow on shadows. Borders AND shadows AND gradients on one element.
|
|
92
|
+
|
|
93
|
+
**Why it happens:** Material Design leftover; depth as decoration.
|
|
94
|
+
|
|
95
|
+
**Fix:** Pick ONE depth mechanism per layer. If cards have shadow, buttons inside should not. If you're using elevation systematically (Material 3), enforce the elevation hierarchy.
|
|
96
|
+
|
|
97
|
+
### 12. Loading spinner default
|
|
98
|
+
|
|
99
|
+
**What it looks like:** Spinner overlay for every async operation, regardless of duration or context.
|
|
100
|
+
|
|
101
|
+
**Why it happens:** Default fallback in every UI library.
|
|
102
|
+
|
|
103
|
+
**Fix:**
|
|
104
|
+
- <300ms: don't show anything. Spinner appearing then disappearing instantly is flicker.
|
|
105
|
+
- 300ms-2s: skeleton loader (shape of incoming content).
|
|
106
|
+
- 2s-10s: spinner + status text ("Loading orders...").
|
|
107
|
+
- 10s+: progress bar or step indicator + cancel button.
|
|
108
|
+
|
|
109
|
+
### 13. Empty state void
|
|
110
|
+
|
|
111
|
+
**What it looks like:** "No items found." Centered. Nothing else. User has no idea what to do.
|
|
112
|
+
|
|
113
|
+
**Why it happens:** Empty state treated as edge case, not a real screen.
|
|
114
|
+
|
|
115
|
+
**Fix:** Every empty state must answer: WHY is it empty (no data yet vs filter excluded everything vs error). WHAT should the user do next (CTA: "Create your first invoice"). Show example/illustration if it helps onboard.
|
|
116
|
+
|
|
117
|
+
### 14. Notification-soup tray
|
|
118
|
+
|
|
119
|
+
**What it looks like:** Every UI event becomes a toast. Save successful → toast. Validation error → toast. Network slow → toast. Now there are 5 stacked toasts and the user can't read any.
|
|
120
|
+
|
|
121
|
+
**Why it happens:** Toast is the default feedback mechanism in component libraries.
|
|
122
|
+
|
|
123
|
+
**Fix:** Reserve toasts for actions that need confirmation AWAY from the originating surface (background save completed, deletion can be undone). Inline feedback for form validation. Modal/banner for blocking errors. NEVER stack >2 toasts at once.
|
|
124
|
+
|
|
125
|
+
## The 17 anti-defaults
|
|
126
|
+
|
|
127
|
+
Specific values that signal "no thought was put in." Avoid unless you can articulate WHY you picked exactly this:
|
|
128
|
+
|
|
129
|
+
| Anti-default | Why it's a tell |
|
|
130
|
+
|--------------|-----------------|
|
|
131
|
+
| `#3B82F6` (Tailwind blue-500) | The internet's default blue |
|
|
132
|
+
| `rounded-lg` everywhere | Universal default; no surface character |
|
|
133
|
+
| `shadow-md` on every card | Universal default; no depth hierarchy |
|
|
134
|
+
| `bg-gradient-to-br from-purple-500 to-pink-500` | The "AI startup landing page" gradient |
|
|
135
|
+
| Inter font as the only choice | Default font of 60% of new SaaS |
|
|
136
|
+
| `font-bold` for everything emphasized | Bold is a tool, not the only tool |
|
|
137
|
+
| Lucide icons exclusively | One icon family is fine; signature is none |
|
|
138
|
+
| Stock "happy team" hero illustration | Generic placeholder energy |
|
|
139
|
+
| "Get Started" / "Learn More" CTA copy | Verb-less; says nothing |
|
|
140
|
+
| 4px / 8px / 12px / 16px spacing exclusively | The default 4-step scale; no rhythm |
|
|
141
|
+
| `border-gray-200` for every divider | Visual whisper; no intentionality |
|
|
142
|
+
| Sans-serif headlines + sans-serif body | No typographic contrast |
|
|
143
|
+
| Center-aligned everything | See pattern #7 |
|
|
144
|
+
| Animated CSS confetti on success | Cheesy; never matches the brand |
|
|
145
|
+
| `bg-white dark:bg-gray-900` only | No real dark-mode design pass |
|
|
146
|
+
| Single-column form on a wide screen | Vertical scroll where horizontal fits |
|
|
147
|
+
| Modal-for-everything | Most modals should be inline editing |
|
|
148
|
+
|
|
149
|
+
## How to use this catalog
|
|
150
|
+
|
|
151
|
+
In `/dw-redesign-ui` step 4 (propose) — before presenting design directions, self-check against this list. Flag any pattern you're consciously using AND say why (sometimes it's the right call; "gradient crutch" can be intentional for a marketing hero).
|
|
152
|
+
|
|
153
|
+
In `/dw-code-review` UI section — grep the diff for the anti-defaults table values and the patterns. Each hit becomes a finding with `dw-review-rigor` severity:
|
|
154
|
+
- Pattern violations on a NEW surface → `medium` severity.
|
|
155
|
+
- Pattern violations spreading EXISTING surface's slop further → `low` severity (consistency wins).
|
|
156
|
+
- Pattern violations on a redesign that was supposed to fix slop → `high` severity (regression).
|
|
157
|
+
|
|
158
|
+
## When the rules bend
|
|
159
|
+
|
|
160
|
+
- **Marketing pages** can use gradients and emojis with more freedom — different surface job.
|
|
161
|
+
- **Brand-mandated** anti-defaults override this list (if the brand IS `#3B82F6`, use it).
|
|
162
|
+
- **Component libraries** like shadcn ship with neutral defaults — the discipline is to ADD character on top, not remove their neutrality.
|