chill-agent 1.5.0 → 1.6.1

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.
Files changed (188) hide show
  1. package/.claude-plugin/contrast-mcp-launcher.mjs +31 -0
  2. package/.claude-plugin/plugin.json +8 -3
  3. package/.cline-plugin/plugin.js +6 -0
  4. package/.codex-plugin/plugin.json +4 -3
  5. package/.cursor-plugin/marketplace.json +16 -0
  6. package/.cursor-plugin/plugin.json +2 -2
  7. package/.devin-plugin/plugin.json +2 -2
  8. package/.kimi-plugin/plugin.json +11 -29
  9. package/.omp-plugin/marketplace.json +15 -0
  10. package/.openclaw/skills/ponytail/SKILL.md +2 -7
  11. package/.openclaw/skills/ponytail-audit/SKILL.md +3 -6
  12. package/.openclaw/skills/ponytail-debt/SKILL.md +3 -4
  13. package/.openclaw/skills/ponytail-gain/SKILL.md +3 -4
  14. package/.openclaw/skills/ponytail-help/SKILL.md +3 -3
  15. package/.openclaw/skills/ponytail-review/SKILL.md +3 -6
  16. package/.opencode/plugins/ponytail.mjs +1 -1
  17. package/.qoder-plugin/plugin.json +12 -26
  18. package/AGENTS.md +32 -19
  19. package/__init__.py +1 -1
  20. package/assets/antislop-banner.png +0 -0
  21. package/assets/band/band.png +0 -0
  22. package/assets/band/board.png +0 -0
  23. package/assets/benchmark-3model.svg +21 -0
  24. package/assets/benchmark-agentic.svg +62 -0
  25. package/assets/codex-icon.png +0 -0
  26. package/assets/compare/code/after.webp +0 -0
  27. package/assets/compare/code/before.webp +0 -0
  28. package/assets/compare/text/after.webp +0 -0
  29. package/assets/compare/text/before.webp +0 -0
  30. package/assets/compare/ui/w-all.webp +0 -0
  31. package/assets/compare/ui/w-antislop.webp +0 -0
  32. package/assets/compare/ui/w-design.webp +0 -0
  33. package/assets/compare/ui/without.webp +0 -0
  34. package/assets/logo-dark.png +0 -0
  35. package/assets/logo-dark.svg +115 -0
  36. package/assets/logo-greenpt-dark.svg +27 -0
  37. package/assets/logo-greenpt.svg +27 -0
  38. package/assets/logo.png +0 -0
  39. package/assets/photoreunion-logo-dark.svg +4 -0
  40. package/assets/photoreunion-logo-light.svg +4 -0
  41. package/assets/profile.png +0 -0
  42. package/assets/retriever-logo-dark.svg +4 -0
  43. package/assets/retriever-logo-light.svg +4 -0
  44. package/assets/stories-banner.png +0 -0
  45. package/assets/v5/audit-es.png +0 -0
  46. package/assets/v5/audit-ja.png +0 -0
  47. package/assets/v5/audit-ko.png +0 -0
  48. package/assets/v5/audit-zh-CN.png +0 -0
  49. package/assets/v5/audit.png +0 -0
  50. package/assets/v5/beforeafter-es.png +0 -0
  51. package/assets/v5/beforeafter-ja.png +0 -0
  52. package/assets/v5/beforeafter-ko.png +0 -0
  53. package/assets/v5/beforeafter-zh-CN.png +0 -0
  54. package/assets/v5/beforeafter.png +0 -0
  55. package/assets/v5/chart-es.png +0 -0
  56. package/assets/v5/chart-ja.png +0 -0
  57. package/assets/v5/chart-ko.png +0 -0
  58. package/assets/v5/chart-zh-CN.png +0 -0
  59. package/assets/v5/chart.png +0 -0
  60. package/assets/v5/hero-es.jpg +0 -0
  61. package/assets/v5/hero-ja.jpg +0 -0
  62. package/assets/v5/hero-ko.jpg +0 -0
  63. package/assets/v5/hero-zh-CN.jpg +0 -0
  64. package/assets/v5/hero.jpg +0 -0
  65. package/assets/v5/ladder-es.png +0 -0
  66. package/assets/v5/ladder-ja.png +0 -0
  67. package/assets/v5/ladder-ko.png +0 -0
  68. package/assets/v5/ladder-zh-CN.png +0 -0
  69. package/assets/v5/ladder.png +0 -0
  70. package/assets/v5/review-es.png +0 -0
  71. package/assets/v5/review-ja.png +0 -0
  72. package/assets/v5/review-ko.png +0 -0
  73. package/assets/v5/review-zh-CN.png +0 -0
  74. package/assets/v5/review.png +0 -0
  75. package/assets/v5/tests-es.png +0 -0
  76. package/assets/v5/tests-ja.png +0 -0
  77. package/assets/v5/tests-ko.png +0 -0
  78. package/assets/v5/tests-zh-CN.png +0 -0
  79. package/assets/v5/tests.png +0 -0
  80. package/assets/waitlist-banner-es.png +0 -0
  81. package/assets/waitlist-banner-ja.png +0 -0
  82. package/assets/waitlist-banner-ko.png +0 -0
  83. package/assets/waitlist-banner-zh-CN.png +0 -0
  84. package/assets/waitlist-banner.png +0 -0
  85. package/benchmarks/.env.example +2 -0
  86. package/benchmarks/agentic/README.md +201 -0
  87. package/benchmarks/agentic/answer.py +288 -0
  88. package/benchmarks/agentic/compare.py +93 -0
  89. package/benchmarks/agentic/complete.py +178 -0
  90. package/benchmarks/agentic/judge.py +198 -0
  91. package/benchmarks/agentic/run.py +543 -0
  92. package/benchmarks/agentic/tasks.py +1544 -0
  93. package/benchmarks/arms/baseline.js +2 -0
  94. package/benchmarks/arms/caveman-SKILL.md +67 -0
  95. package/benchmarks/arms/caveman.js +8 -0
  96. package/benchmarks/arms/ponytail.js +8 -0
  97. package/benchmarks/behavior.js +54 -0
  98. package/benchmarks/behavior.yaml +40 -0
  99. package/benchmarks/correctness.js +291 -0
  100. package/benchmarks/loc.js +17 -19
  101. package/benchmarks/promptfooconfig.gemini.yaml +32 -0
  102. package/benchmarks/promptfooconfig.gpt-newest.yaml +33 -0
  103. package/benchmarks/promptfooconfig.yaml +41 -0
  104. package/benchmarks/results/2026-06-12-caveman-vs-ponytail.md +71 -0
  105. package/benchmarks/results/2026-06-12-v4-hardening-vs-caveman.md +125 -0
  106. package/benchmarks/results/2026-06-15-llama3.2-local.md +82 -0
  107. package/benchmarks/results/2026-06-16-correctness-gate-fix.md +113 -0
  108. package/benchmarks/results/2026-06-16-robustness-audit.md +135 -0
  109. package/benchmarks/results/2026-06-17-agentic-safety.md +164 -0
  110. package/benchmarks/results/2026-06-17-cost-verification.md +93 -0
  111. package/benchmarks/results/2026-06-18-agentic.md +219 -0
  112. package/benchmarks/results/2026-06-22-issue-245-217-comprehension.md +98 -0
  113. package/benchmarks/results/2026-10-07-agentic.md +186 -0
  114. package/bin/chill-agent.js +6 -6
  115. package/bin/chill-agent.mjs +7 -0
  116. package/cli/index.mjs +241 -0
  117. package/cli/lib/banner.mjs +21 -0
  118. package/cli/lib/install.mjs +498 -0
  119. package/cli/lib/settings.mjs +48 -0
  120. package/cli/package-lock.json +87 -0
  121. package/cli/package.json +42 -0
  122. package/cli/scripts/smoke-test.mjs +95 -0
  123. package/cli/scripts/smoke-worker.mjs +411 -0
  124. package/cli/scripts/sync-skills.mjs +81 -0
  125. package/examples/email-validation.md +156 -0
  126. package/examples/group-by.md +35 -0
  127. package/examples/infinite-scroll.md +58 -0
  128. package/examples/number-formatting.md +37 -0
  129. package/examples/rate-limit.md +272 -0
  130. package/examples/react-countdown.md +390 -0
  131. package/examples/url-params.md +41 -0
  132. package/gemini-extension.json +2 -2
  133. package/hooks/band/board.ts +560 -0
  134. package/hooks/band/logo.ts +3 -0
  135. package/hooks/band/metrics.ts +311 -0
  136. package/hooks/band/register.tsx +495 -0
  137. package/hooks/band/types.d.ts +34 -0
  138. package/hooks/claude-band.json +6 -0
  139. package/hooks/claude-codex-hooks.json +34 -4
  140. package/hooks/copilot-hooks.json +12 -2
  141. package/hooks/cursor-hooks.json +2 -2
  142. package/hooks/ponytail-band-import.js +274 -0
  143. package/hooks/ponytail-config.js +175 -0
  144. package/hooks/ponytail-map.js +111 -0
  145. package/hooks/ponytail-subagent.js +94 -0
  146. package/hooks/qoder-hooks.json +19 -4
  147. package/i18n/README.ko.md +230 -0
  148. package/package.json +12 -7
  149. package/pi-extension/test/extension.test.js +367 -0
  150. package/pi-extension/test/helpers.test.js +179 -0
  151. package/plugin.yaml +21 -12
  152. package/rules/antislop.mdc +18 -0
  153. package/scripts/build-openclaw-skills.js +60 -0
  154. package/scripts/check-repo.mjs +389 -0
  155. package/scripts/publish-openclaw-skills.js +75 -0
  156. package/scripts/skill-index.mjs +81 -0
  157. package/skills/antislop/SKILL.md +700 -0
  158. package/skills/antislop/VERSION +1 -0
  159. package/skills/antislop-code/SKILL.md +128 -0
  160. package/skills/antislop-copywriting/SKILL.md +407 -0
  161. package/skills/antislop-human/LICENSE-web-quality-skills +21 -0
  162. package/skills/antislop-human/SKILL.md +204 -0
  163. package/skills/antislop-human/contrast-check.py +168 -0
  164. package/skills/antislop-human/contrast-mcp.py +121 -0
  165. package/skills/antislop-human/references/A11Y-PATTERNS.md +249 -0
  166. package/skills/antislop-human/references/WCAG.md +127 -0
  167. package/skills/antislop-layoutmobile/SKILL.md +170 -0
  168. package/skills/antislop-ui/LICENSE-web-quality-skills +21 -0
  169. package/skills/antislop-ui/SKILL.md +344 -0
  170. package/skills/antislop-ui/references/CORE-WEB-VITALS.md +181 -0
  171. package/skills/antislop-ui/references/WEB-BASELINE.md +28 -0
  172. package/skills/plugin.json +5 -0
  173. package/src/package.json +3 -0
  174. package/tests/activation-map.test.js +63 -0
  175. package/tests/band-import.test.js +111 -0
  176. package/tests/band.test.tsx +520 -0
  177. package/tests/behavior.test.js +80 -0
  178. package/tests/gemini-extension.test.js +2 -2
  179. package/tests/grok-plugin.test.js +1 -1
  180. package/tests/hermes-plugin.test.js +1 -1
  181. package/tests/hooks-windows.test.js +205 -0
  182. package/tests/kimi-plugin.test.js +1 -1
  183. package/tests/map.test.js +30 -0
  184. package/tests/package-scripts.test.js +35 -0
  185. package/tests/package.test.js +23 -0
  186. package/tests/uninstall.test.js +202 -0
  187. /package/tests/{manifests.test.js → manifests.test.mjs} +0 -0
  188. /package/tests/{rules.test.js → rules.test.mjs} +0 -0
@@ -0,0 +1,249 @@
1
+ # Accessibility Code Patterns
2
+
3
+ > Reference for antislop. Adapted from the MIT-licensed web-quality-skills by Addy Osmani (https://github.com/addyosmani/web-quality-skills); see LICENSE-web-quality-skills in the skill folder.
4
+
5
+ Practical, copy-paste-ready patterns for common accessibility requirements. Each pattern is self-contained and linked from the main [SKILL.md](../SKILL.md).
6
+
7
+ ---
8
+
9
+ ## Pointer cursor base layer
10
+
11
+ Set once, in the base CSS layer, so no component has to remember it (R-39). A CSS reset such as Tailwind preflight sets `button` to `cursor: default`, so this layer comes after the reset.
12
+
13
+ ```css
14
+ a[href], button, summary, select, label[for],
15
+ label:has(> input[type="checkbox"], > input[type="radio"]),
16
+ [role="button"], [role="link"], [role="tab"], [role="menuitem"], [role="option"], [role="switch"],
17
+ input[type="checkbox"], input[type="radio"], input[type="file"],
18
+ input[type="submit"], input[type="button"], input[type="reset"], input[type="range"], input[type="color"] {
19
+ cursor: pointer;
20
+ }
21
+ :disabled, [aria-disabled="true"] { cursor: not-allowed; }
22
+ ```
23
+
24
+ Text inputs keep `cursor: text`, and drag handles use `grab` / `grabbing`. An implicit label that wraps a checkbox or radio is included, since clicking it toggles the control.
25
+
26
+ ## Modal focus trap
27
+
28
+ Trap keyboard focus inside a modal dialog so Tab/Shift+Tab cycle through its focusable elements and Escape closes it.
29
+
30
+ ```javascript
31
+ function trapFocus(modal, onClose) {
32
+ const focusable = modal.querySelectorAll(
33
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
34
+ );
35
+ if (focusable.length === 0) return () => {};
36
+
37
+ const first = focusable[0];
38
+ const last = focusable[focusable.length - 1];
39
+
40
+ function onKeydown(e) {
41
+ if (e.key === 'Escape') return onClose();
42
+ if (e.key !== 'Tab') return;
43
+ if (e.shiftKey && document.activeElement === first) {
44
+ e.preventDefault();
45
+ last.focus();
46
+ } else if (!e.shiftKey && document.activeElement === last) {
47
+ e.preventDefault();
48
+ first.focus();
49
+ }
50
+ }
51
+
52
+ modal.addEventListener('keydown', onKeydown);
53
+ first.focus();
54
+ return () => modal.removeEventListener('keydown', onKeydown);
55
+ }
56
+ ```
57
+
58
+ Call the returned function when the dialog closes, or a second open stacks a second listener:
59
+
60
+ ```javascript
61
+ const release = trapFocus(dialog, () => dialog.close());
62
+ dialog.addEventListener('close', release, { once: true });
63
+ ```
64
+
65
+ The native `<dialog>` element handles focus trapping automatically, prefer it when browser support allows.
66
+
67
+ ---
68
+
69
+ ## Skip link
70
+
71
+ Allows keyboard users to bypass repetitive navigation and jump straight to main content.
72
+
73
+ ```html
74
+ <body>
75
+ <a href="#main-content" class="skip-link">Skip to main content</a>
76
+ <header><!-- navigation --></header>
77
+ <main id="main-content" tabindex="-1">
78
+ <!-- main content -->
79
+ </main>
80
+ </body>
81
+ ```
82
+
83
+ ```css
84
+ .skip-link {
85
+ position: absolute;
86
+ top: -40px;
87
+ left: 0;
88
+ background: #000;
89
+ color: #fff;
90
+ padding: 8px 16px;
91
+ z-index: 100;
92
+ }
93
+
94
+ .skip-link:focus {
95
+ top: 0;
96
+ }
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Error handling
102
+
103
+ Announce errors to screen readers and focus the first invalid field on submit.
104
+
105
+ ```html
106
+ <form novalidate>
107
+ <div id="error-summary" tabindex="-1" hidden></div>
108
+ <div class="field" aria-live="polite">
109
+ <label for="email">Email</label>
110
+ <input type="email" id="email"
111
+ aria-invalid="true"
112
+ aria-describedby="email-error">
113
+ <p id="email-error" class="error" role="alert">
114
+ Please enter a valid email address (e.g., name@example.com)
115
+ </p>
116
+ </div>
117
+ </form>
118
+ ```
119
+
120
+ ```javascript
121
+ const form = document.querySelector('form');
122
+ const summary = document.getElementById('error-summary');
123
+
124
+ form.addEventListener('submit', (e) => {
125
+ const invalid = [...form.querySelectorAll('[aria-invalid="true"]')];
126
+ if (invalid.length === 0) return;
127
+
128
+ e.preventDefault();
129
+ summary.textContent =
130
+ `${invalid.length} errors found. Please fix them and try again.`;
131
+ summary.hidden = false;
132
+ invalid[0].focus();
133
+ });
134
+ ```
135
+
136
+ This handler reports what the validation already marked: set `aria-invalid="true"` and the field's error text before submit runs.
137
+
138
+ ---
139
+
140
+ ## Form labels
141
+
142
+ Every input needs an associated label, either explicit (`for`/`id`) or implicit (wrapping `<label>`).
143
+
144
+ ```html
145
+ <!-- ❌ No label association -->
146
+ <input type="email" placeholder="Email">
147
+
148
+ <!-- ✅ Explicit label -->
149
+ <label for="email">Email address</label>
150
+ <input type="email" id="email" name="email"
151
+ autocomplete="email" required>
152
+
153
+ <!-- ✅ Implicit label -->
154
+ <label>
155
+ Email address
156
+ <input type="email" name="email" autocomplete="email" required>
157
+ </label>
158
+
159
+ <!-- ✅ With instructions -->
160
+ <label for="password">Password</label>
161
+ <input type="password" id="password"
162
+ aria-describedby="password-requirements">
163
+ <p id="password-requirements">
164
+ Must be at least 8 characters with one number.
165
+ </p>
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Dragging movements
171
+
172
+ Any action triggered by dragging must offer a single-pointer alternative (WCAG 2.5.7).
173
+
174
+ ```html
175
+ <!-- ❌ Drag-only reorder -->
176
+ <ul class="sortable-list" draggable="true">
177
+ <li>Item 1</li>
178
+ <li>Item 2</li>
179
+ </ul>
180
+
181
+ <!-- ✅ Drag + button alternatives -->
182
+ <ul class="sortable-list">
183
+ <li>
184
+ <span>Item 1</span>
185
+ <button aria-label="Move Item 1 up">↑</button>
186
+ <button aria-label="Move Item 1 down">↓</button>
187
+ </li>
188
+ <li>
189
+ <span>Item 2</span>
190
+ <button aria-label="Move Item 2 up">↑</button>
191
+ <button aria-label="Move Item 2 down">↓</button>
192
+ </li>
193
+ </ul>
194
+ ```
195
+
196
+ Also applies to sliders, map panning, colour pickers, and similar drag-based widgets, always provide an equivalent click/tap or keyboard path.
197
+
198
+ ---
199
+
200
+ ## ARIA tabs
201
+
202
+ Tabs require `role="tablist"`, `role="tab"`, and `role="tabpanel"` with proper `aria-selected`, `aria-controls`, and keyboard support.
203
+
204
+ ```html
205
+ <div role="tablist" aria-label="Product information">
206
+ <button role="tab" id="tab-1" aria-selected="true"
207
+ aria-controls="panel-1">Description</button>
208
+ <button role="tab" id="tab-2" aria-selected="false"
209
+ aria-controls="panel-2" tabindex="-1">Reviews</button>
210
+ </div>
211
+ <div role="tabpanel" id="panel-1" aria-labelledby="tab-1">
212
+ <!-- Panel content -->
213
+ </div>
214
+ <div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
215
+ <!-- Panel content -->
216
+ </div>
217
+ ```
218
+
219
+ Arrow keys should move focus between tabs; the active tab receives `tabindex="0"` while inactive tabs use `tabindex="-1"`.
220
+
221
+ ---
222
+
223
+ ## Live regions and notifications
224
+
225
+ Use `aria-live` to announce dynamic content changes to screen readers without moving focus.
226
+
227
+ ```html
228
+ <!-- Status updates (polite, waits for pause in speech) -->
229
+ <div id="polite-announcer" aria-live="polite" aria-atomic="true" class="status">
230
+ <!-- Content updates announced to screen readers -->
231
+ </div>
232
+
233
+ <!-- Urgent alerts (assertive, interrupts) -->
234
+ <div id="assertive-announcer" role="alert" aria-live="assertive">
235
+ <!-- Interrupts current announcement -->
236
+ </div>
237
+ ```
238
+
239
+ ```javascript
240
+ function showNotification(message, type = 'polite') {
241
+ const container = document.getElementById(`${type}-announcer`);
242
+ container.textContent = '';
243
+ requestAnimationFrame(() => {
244
+ container.textContent = message;
245
+ });
246
+ }
247
+ ```
248
+
249
+ Clear the container before writing to ensure the same message triggers a new announcement.
@@ -0,0 +1,127 @@
1
+ # WCAG 2.2 Quick Reference
2
+
3
+ > Reference for antislop. Adapted from the MIT-licensed web-quality-skills by Addy Osmani (https://github.com/addyosmani/web-quality-skills); see LICENSE-web-quality-skills in the skill folder.
4
+
5
+ ## Success criteria by level
6
+
7
+ ### Level A (minimum)
8
+
9
+ | Criterion | Description |
10
+ |-----------|-------------|
11
+ | **1.1.1** Non-text Content | All images, icons have text alternatives |
12
+ | **1.2.1** Audio-only/Video-only | Provide transcript or audio description |
13
+ | **1.2.2** Captions | Video with audio has captions |
14
+ | **1.2.3** Audio Description | Video has audio description |
15
+ | **1.3.1** Info and Relationships | Information conveyed through presentation is available programmatically |
16
+ | **1.3.2** Meaningful Sequence | Reading order is logical |
17
+ | **1.3.3** Sensory Characteristics | Instructions don't rely solely on shape, color, size, location, orientation, or sound |
18
+ | **1.4.1** Use of Color | Color is not the only visual means of conveying information |
19
+ | **1.4.2** Audio Control | Audio playing automatically can be paused/stopped |
20
+ | **2.1.1** Keyboard | All functionality available via keyboard |
21
+ | **2.1.2** No Keyboard Trap | Keyboard focus can be moved away from any component |
22
+ | **2.1.4** Character Key Shortcuts | Single-key shortcuts can be turned off or remapped |
23
+ | **2.2.1** Timing Adjustable | Time limits can be extended |
24
+ | **2.2.2** Pause, Stop, Hide | Moving/blinking content can be paused |
25
+ | **2.3.1** Three Flashes | Nothing flashes more than 3 times per second |
26
+ | **2.4.1** Bypass Blocks | Skip link or landmark navigation available |
27
+ | **2.4.2** Page Titled | Pages have descriptive titles |
28
+ | **2.4.3** Focus Order | Focus order preserves meaning |
29
+ | **2.4.4** Link Purpose | Link purpose clear from link text or context |
30
+ | **2.5.1** Pointer Gestures | Multi-point gestures have single-pointer alternatives |
31
+ | **2.5.2** Pointer Cancellation | Down-event doesn't trigger action (use up-event or click) |
32
+ | **2.5.3** Label in Name | Accessible name contains visible label text |
33
+ | **2.5.4** Motion Actuation | Motion-triggered functions have alternatives |
34
+ | **3.1.1** Language of Page | Default language specified in HTML |
35
+ | **3.2.1** On Focus | Focus doesn't trigger unexpected changes |
36
+ | **3.2.2** On Input | Input doesn't trigger unexpected changes |
37
+ | **3.2.6** Consistent Help | Help mechanisms appear in the same relative order across pages |
38
+ | **3.3.1** Error Identification | Input errors clearly described |
39
+ | **3.3.2** Labels or Instructions | Form inputs have labels or instructions |
40
+ | **3.3.7** Redundant Entry | Information previously entered is auto-populated or available to select |
41
+ | **4.1.2** Name, Role, Value | UI components have accessible names and correct roles |
42
+
43
+ ### Level AA (standard)
44
+
45
+ | Criterion | Description |
46
+ |-----------|-------------|
47
+ | **1.2.4** Captions (Live) | Live audio has captions |
48
+ | **1.2.5** Audio Description | Pre-recorded video has audio description |
49
+ | **1.3.4** Orientation | Content doesn't restrict orientation |
50
+ | **1.3.5** Identify Input Purpose | Input purpose can be programmatically determined |
51
+ | **1.4.3** Contrast (Minimum) | 4.5:1 for normal text, 3:1 for large text |
52
+ | **1.4.4** Resize Text | Text can be resized to 200% without loss of functionality |
53
+ | **1.4.5** Images of Text | Text used instead of images of text |
54
+ | **1.4.10** Reflow | Content reflows at 320px width without horizontal scroll |
55
+ | **1.4.11** Non-text Contrast | UI components have 3:1 contrast |
56
+ | **1.4.12** Text Spacing | Content adapts to text spacing changes |
57
+ | **1.4.13** Content on Hover/Focus | Additional content is dismissible, hoverable, persistent |
58
+ | **2.4.5** Multiple Ways | Multiple ways to find pages |
59
+ | **2.4.6** Headings and Labels | Headings and labels are descriptive |
60
+ | **2.4.7** Focus Visible | Focus indicator is visible |
61
+ | **2.4.11** Focus Not Obscured (Minimum) | Focused element is not entirely hidden by author-created content |
62
+ | **2.5.7** Dragging Movements | Dragging actions have single-pointer alternatives |
63
+ | **2.5.8** Target Size (Minimum) | Interactive targets are at least 24×24 CSS pixels (with exceptions) |
64
+ | **3.1.2** Language of Parts | Language changes are marked |
65
+ | **3.2.3** Consistent Navigation | Navigation is consistent across pages |
66
+ | **3.2.4** Consistent Identification | Same functionality uses same labels |
67
+ | **3.3.3** Error Suggestion | Error corrections suggested when known |
68
+ | **3.3.4** Error Prevention (Legal) | Actions can be reversed or confirmed |
69
+ | **3.3.8** Accessible Authentication (Minimum) | No cognitive function test for login unless an alternative or assistance is provided |
70
+ | **4.1.3** Status Messages | Status messages announced to screen readers |
71
+
72
+ ### Level AAA (enhanced)
73
+
74
+ | Criterion | Description |
75
+ |-----------|-------------|
76
+ | **1.2.6** Sign Language (Prerecorded) | Pre-recorded video has a sign language interpretation |
77
+ | **1.2.7** Extended Audio Description (Prerecorded) | Video pauses long enough for audio description to convey the visuals |
78
+ | **1.2.8** Media Alternative (Prerecorded) | A text alternative covers everything the pre-recorded media shows |
79
+ | **1.2.9** Audio-only (Live) | Live audio-only content has a text alternative |
80
+ | **1.3.6** Identify Purpose | Icons and regions have a programmatically determined purpose |
81
+ | **1.4.6** Contrast (Enhanced) | 7:1 for normal text, 4.5:1 for large text |
82
+ | **1.4.7** Low or No Background Audio | Speech stays understandable over background sound |
83
+ | **1.4.8** Visual Presentation | Foreground/background colors can be selected |
84
+ | **1.4.9** Images of Text (No Exception) | No images of text |
85
+ | **2.1.3** Keyboard (No Exception) | All functionality keyboard accessible |
86
+ | **2.2.3** No Timing | No time limits |
87
+ | **2.2.4** Interruptions | Interruptions can be postponed |
88
+ | **2.2.5** Re-authenticating | Data preserved on re-authentication |
89
+ | **2.2.6** Timeouts | Users warned about data loss from inactivity |
90
+ | **2.3.2** Three Flashes | No content flashes more than 3 times |
91
+ | **2.3.3** Animation from Interactions | Motion animation can be disabled |
92
+ | **2.4.8** Location | User location within site is available |
93
+ | **2.4.9** Link Purpose (Link Only) | Link purpose clear from link text alone |
94
+ | **2.4.10** Section Headings | Sections have headings |
95
+ | **2.4.12** Focus Not Obscured (Enhanced) | No part of the focused element is hidden by author-created content |
96
+ | **2.4.13** Focus Appearance | Focus indicator has sufficient area, contrast, and is not obscured |
97
+ | **2.5.5** Target Size (Enhanced) | Interactive targets are at least 44×44 CSS pixels |
98
+ | **2.5.6** Concurrent Input Mechanisms | Content does not restrict which input modality a person uses |
99
+ | **3.1.3** Unusual Words | Definitions available for unusual words |
100
+ | **3.1.4** Abbreviations | Abbreviations expanded |
101
+ | **3.1.5** Reading Level | Alternative content for complex text |
102
+ | **3.1.6** Pronunciation | Pronunciation available where needed |
103
+ | **3.2.5** Change on Request | Changes initiated only by user |
104
+ | **3.3.5** Help | Context-sensitive help available |
105
+ | **3.3.6** Error Prevention (All) | All form submissions can be reviewed |
106
+ | **3.3.9** Accessible Authentication (Enhanced) | No cognitive function test for login (no object or personal content recognition exceptions) |
107
+
108
+ ## What changed from 2.1 to 2.2
109
+
110
+ | Change | Criterion | Level |
111
+ |--------|-----------|-------|
112
+ | **Removed** | 4.1.1 Parsing | A |
113
+ | **Added** | 2.4.11 Focus Not Obscured (Minimum) | AA |
114
+ | **Added** | 2.4.12 Focus Not Obscured (Enhanced) | AAA |
115
+ | **Added** | 2.4.13 Focus Appearance | AAA |
116
+ | **Added** | 2.5.7 Dragging Movements | AA |
117
+ | **Added** | 2.5.8 Target Size (Minimum) | AA |
118
+ | **Added** | 3.2.6 Consistent Help | A |
119
+ | **Added** | 3.3.7 Redundant Entry | A |
120
+ | **Added** | 3.3.8 Accessible Authentication (Minimum) | AA |
121
+ | **Added** | 3.3.9 Accessible Authentication (Enhanced) | AAA |
122
+
123
+ ## Sources
124
+
125
+ - [WCAG 2.2 W3C Recommendation](https://www.w3.org/TR/WCAG22/)
126
+ - [WCAG 2.2 Quick Reference](https://www.w3.org/WAI/WCAG22/quickref/)
127
+ - [What's New in WCAG 2.2](https://www.w3.org/WAI/standards-guidelines/wcag/new-in-22/)
@@ -0,0 +1,170 @@
1
+ ---
2
+ name: antislop-layoutmobile
3
+ description: "Mobile layout skill for antislop. Use for layouts that reflow across screen sizes, phone to desktop: grids, overflow, tap targets. Load with the core."
4
+ allowed-tools: Read Write Edit Glob Grep
5
+ ---
6
+ # antislop-layoutmobile
7
+
8
+ > Anti Slop: Rules for AI Coding Agents. Mobile Layout skill
9
+
10
+ > Part of the antislop system. Read together with `antislop.md` (the core). This skill deep-dives the responsive layout concern: how a layout must reflow across screen sizes, phone to desktop. Breakpoints, scale, grids, overflow, tap targets, and navigation. It references core rules by number and never duplicates or renumbers them. Load it when the task builds or edits a layout that has to hold up at any screen width.
11
+
12
+ ## How to use this skill
13
+
14
+ - Load together with `antislop.md` whenever the task is mobile or responsive layout work. The core holds the mechanism (the purpose test, the three tiers, the Delivery Gate); this skill holds mobile-layout depth.
15
+ - Every entry has the same shape: **Tell** (the pattern), **Why** (why it reads as slop), **Fix** (what to do instead), with the governing core rule cited as R-XX.
16
+ - The principle behind this skill: **mobile layout is a different layout, not the desktop layout at a smaller size.** It must reflow: re-stack, rescale, and re-order with intent. Every pattern below is a way a layout fails to reflow.
17
+ - The Delivery Gate in the core remains the gate. The "Layoutmobile Skill Checklist" at the end of this file is the mobile-specific supplement to run alongside it.
18
+
19
+ ## Breakpoints
20
+
21
+ ### Desktop-Only Layout
22
+
23
+ - **Tell:** one layout state for every screen; the mobile view is the desktop layout squeezed into a phone.
24
+ - **Why:** R-03 requires a mobile layout that is perfect, not an afterthought. A page that only shrinks has no mobile design at all: cards that worked side by side overlap, and text meant for a wide canvas crowds into a narrow one.
25
+ - **Fix:** define a real mobile state at the breakpoint where the content stops working. The mobile layout reflows: columns stack, sizes drop, and order changes where the content needs it. If the mobile view is just the desktop view at a smaller width, the layout is not done.
26
+
27
+ ### Breakpoint Driven by Device List
28
+
29
+ - **Tell:** breakpoints named after phone widths (375px, 414px, 768px) chosen because "that is the iPhone size", not because the content breaks there.
30
+ - **Why:** device widths change every year and every model. A breakpoint is a point where the layout stops holding; forcing it to match a device list makes the layout follow a spec sheet instead of the content (R-03).
31
+ - **Fix:** place breakpoints where the content actually breaks: when a column stops being readable, when a row of cards gets too narrow. Test by narrowing the viewport and watching where it snaps, then set the breakpoint there.
32
+
33
+ ### Mobile Styled Last
34
+
35
+ - **Tell:** mobile rules bolted on as a trailing override: a long desktop stylesheet with a small media query at the end fixing one or two things.
36
+ - **Why:** an override patch is not a mobile design. It fixes the symptom that got reported and leaves the next one, and the base styles stay tuned for a wide screen (R-03).
37
+ - **Fix:** treat mobile as a designed state, not an override. Give the narrow viewport its own deliberate sizes and stacking, and verify the whole layout there, not just the patched spots (R-35).
38
+
39
+ ### Two-State Layout
40
+
41
+ - **Tell:** a layout with exactly two states: a single stacked column below one breakpoint, and a wide multi-column grid above it, with nothing defined in between. A tablet or small laptop width then inherits whichever state is closest: the phone stack stretched absurdly wide, or the desktop grid crammed into a fraction of its intended canvas.
42
+ - **Why:** a page is a continuous range of widths, and R-03 demands it hold up at every one of them, not just two chosen breakpoints. Two states leave the whole middle band of the range (roughly 600 to 1024 px, where tablets and small laptops live) as an accident: content that neither stacks with intent nor sits in a grid that fits. The layout reads as designed only at its two sample points and broken everywhere between.
43
+ - **Fix:** define real states at the widths where the content stops working, and let them be as many as the content needs. A typical reflow is three states, not two: single column, then a two-column grid when cards get too wide as a single stack, then the full multi-column grid only when it genuinely fits. Verify by dragging the viewport through the whole range, not by checking two widths and calling it done (R-35).
44
+
45
+ ## Scale & Sizing
46
+
47
+ ### Desktop-Sized Everything
48
+
49
+ - **Tell:** padding, gaps, hero heights, and card sizes carried unchanged from desktop to mobile, so every section looks blown up on a phone.
50
+ - **Why:** an element sized for a 1440px canvas dominates a 375px one. What reads as confident on desktop becomes oversized on mobile: nothing fits, nothing breathes, and the page feels like it was designed for a screen that is not the one in hand (R-03). Spacing and type should follow the design rhythm (R-05), and that rhythm has a smaller register on mobile.
51
+ - **Fix:** give mobile its own size step: a smaller type scale, tighter section padding, smaller gaps. Keep tap targets at their minimum size (see Tap Targets), but shrink everything else with intent at the breakpoint.
52
+
53
+ ### Fixed Pixel Type
54
+
55
+ - **Tell:** font sizes in fixed px that never change between desktop and mobile, so headings and body text stay oversized on a phone.
56
+ - **Why:** type that does not respond to the viewport is type sized for one screen. R-03 demands the mobile layout hold up, and R-06 requires typography that improves readability. A headline that spans the whole phone width or a body size tuned for a wide line breaks both.
57
+ - **Fix:** use fluid type (`clamp()`) so sizes scale with the viewport, or set a smaller type step at the breakpoint. Verify the result at a narrow width (R-35), not just in the desktop preview.
58
+
59
+ ### 100vh Sections
60
+
61
+ - **Tell:** hero and section heights set to `100vh`, so a section fills the whole phone screen and pushes everything else below the fold.
62
+ - **Why:** a full-viewport section designed for a desktop monitor becomes a giant slab on a phone, and `100vh` includes the browser chrome, so it overflows the visible area on mobile browsers. It dominates the layout instead of introducing it (R-03).
63
+ - **Fix:** let sections size to their content (`auto`), or use the dynamic viewport unit (`dvh`) where a real full-height section is intended. Nothing below the fold should be an accident of viewport units.
64
+
65
+ ### Huge Empty Padding
66
+
67
+ - **Tell:** desktop-scale section padding (96px, 128px) kept on mobile, creating tall empty gaps between sections on a phone.
68
+ - **Why:** padding tuned for a large canvas turns into wasted vertical space on a small one. The page scrolls through emptiness, and the rhythm R-05 calls for becomes a void between every section.
69
+ - **Fix:** reduce section padding at the breakpoint to a mobile register (roughly half or less), and check that the page scrolls at a natural density instead of through deserts of space.
70
+
71
+ ## Grids & Stacking
72
+
73
+ ### Columns That Don't Collapse
74
+
75
+ - **Tell:** a multi-column grid keeps its side-by-side columns on mobile, so the columns shrink, the text wraps awkwardly, and elements collide.
76
+ - **Why:** a grid is a promise about how much width is available. When the viewport narrows and the grid does not re-stack, every column gets a sliver, text becomes unreadable, and cards overlap (R-03). This is the collision failure: desktop's side-by-side becomes mobile's pileup.
77
+ - **Fix:** collapse the grid to a single reflowing column at the breakpoint. Side-by-side becomes stacked, and each item gets the full width again. Re-verify at a narrow width (R-35).
78
+
79
+ ### Fixed-Width Grid
80
+
81
+ - **Tell:** `grid-template-columns` set in fixed px, or grid areas that cannot reflow, so the grid stays rigid when the viewport shrinks.
82
+ - **Why:** a fixed-px track does not care about the viewport; it keeps its width and forces overflow or collision. The layout was built for one canvas and cannot change shape (R-03).
83
+ - **Fix:** size tracks with `minmax()` or `auto-fit` and `auto-fill` so columns shrink and wrap with the content, and define grid areas that collapse at the breakpoint. The grid should be fluid by default, rigid only where a fixed size is deliberate.
84
+
85
+ ### Forced 12-Column
86
+
87
+ - **Tell:** a 12-column grid forced onto mobile content that needs one or two columns, so spans look arbitrary and the math fights the layout.
88
+ - **Why:** a 12-column system is for a wide canvas with many columns of content. Forcing it on a phone makes every element a fraction of an invisible grid the user never sees, and the content gets fitted to the grid instead of the grid to the content (R-03).
89
+ - **Fix:** let columns follow the content. On mobile the content usually wants one column, or two at most; the 12-column span only makes sense where the layout genuinely has that many things side by side.
90
+
91
+ ## Overflow
92
+
93
+ ### Horizontal Scroll Leak
94
+
95
+ - **Tell:** the page scrolls sideways because some element is wider than the viewport: a table, a code block, an image, a long unbroken string.
96
+ - **Why:** horizontal scrolling is a broken promise on mobile. The user cannot see where the page ends, and the layout visibly spills off the screen (R-03). It is the most common overflow slop because the offender is off-screen in the desktop preview and goes unnoticed until a phone opens it.
97
+ - **Fix:** find the element wider than the viewport (a table that needs a reflow layout or a scroll container, a code block that wraps, images with `max-width: 100%`), then contain or reflow it. Verify the whole page has zero horizontal scroll at the narrowest target (R-35).
98
+
99
+ ### Overflow Hidden Clipping
100
+
101
+ - **Tell:** `overflow: hidden` on a container that clips content at narrow widths, hiding text or controls instead of letting them fit.
102
+ - **Why:** clipping is hiding a failure. When a container cuts off its content because the layout cannot fit it, the user loses information and interaction (R-03). The zoom and text-resize angle on this is covered by `antislop-human`.
103
+ - **Fix:** let the content reflow instead of clipping: allow the container to grow, wrap its content, or collapse it at the breakpoint. Clip only where cropping is the design intent (like a thumbnail), never where it hides content.
104
+
105
+ ### Fixed-Width Children
106
+
107
+ - **Tell:** flex or grid children with a fixed px width or `min-width` that burst out of their parent on a narrow screen.
108
+ - **Why:** a child sized in absolute px does not care how much room its parent has. On mobile the parent shrinks and the child stays wide, so it overflows the container and the page (R-03).
109
+ - **Fix:** size children with relative units and let them wrap (`flex-wrap`, fluid widths, `min-width: 0` on grid children). A child should be allowed to shrink with its container, not hold a desktop size.
110
+
111
+ ## Tap Targets
112
+
113
+ ### Under-Sized Targets
114
+
115
+ - **Tell:** buttons, links, and controls smaller than about 44 x 44 px, easy to hit on desktop with a cursor but hard to hit with a thumb.
116
+ - **Why:** a desktop cursor has pixel accuracy; a thumb does not. A target that is fine at 16px becomes an exercise in frustration on a phone, and it fails the promise that the UI is usable on mobile (R-03).
117
+ - **Fix:** give interactive targets a minimum touch area of 44 x 44 px, using padding or a larger hit box even when the visual is smaller. Verify the whole set of controls at a phone width (R-35).
118
+
119
+ ### Targets Too Close
120
+
121
+ - **Tell:** 44px targets packed together with no gap, so a thumb tap hits the wrong one.
122
+ - **Why:** target size matters only with target spacing. Two large controls touching each other behave like one large control: the user cannot reliably pick either (R-03).
123
+ - **Fix:** leave a clear gap between adjacent interactive targets, at least a few px and ideally enough that the finger press area does not overlap. Spacing is the other half of tappability.
124
+
125
+ ### Hover-Only Interactions
126
+
127
+ - **Tell:** menus, reveals, and tooltips that exist only on hover, so a touch user can never open them.
128
+ - **Why:** there is no hover on a touchscreen. An interaction that only responds to hover simply does not exist for mobile users, and any control that relies on it is a dead end (R-03).
129
+ - **Fix:** give every hover-only interaction a tap equivalent: a menu that opens on hover also opens on tap, a reveal also shows on click, and interactive elements show visible `:active` feedback so a tap registers. Test by using the UI with touch alone (R-35).
130
+
131
+ ## Mobile Navigation
132
+
133
+ ### Nav That Stays Desktop
134
+
135
+ - **Tell:** the desktop top bar with its row of links kept side by side on mobile, so the links crowd, wrap into two rows, or spill past the viewport.
136
+ - **Why:** a desktop nav is sized for a wide canvas. Kept as a row on a phone it becomes a mess of cramped links, and it is the first thing a mobile user meets (R-03). Navigation is where reflow matters most: the user has to find where to go before they can go anywhere.
137
+ - **Fix:** collapse the nav into a mobile pattern at the breakpoint: a bottom nav for the handful of primary destinations, or a menu for the rest. The links reflow out of the row, and the primary destinations stay one thumb tap away. Verify it holds at a narrow width (R-35).
138
+
139
+ ### The Bare Hamburger
140
+
141
+ - **Tell:** everything hidden behind a hamburger icon with no label and no hint, so a user never realizes the menu exists or cannot tell what it opens.
142
+ - **Why:** a bare hamburger assumes the user already knows what the icon means and that a menu hides behind it. That is knowledge the mobile user may not have, and on mobile the hidden menu can hold the only way around the app (R-03).
143
+ - **Fix:** keep the menu discoverable: label the hamburger ("Menu"), or keep the primary destinations visible and hide only the secondary ones. If a menu is the only way to reach something important, that reachability has to be obvious.
144
+
145
+ ### Bottom Nav That Eats Content
146
+
147
+ - **Tell:** a fixed bottom nav bar that sits over the content, covering the last list items, the final button, or the form the user was trying to finish.
148
+ - **Why:** a fixed bar takes real space on a small screen. If nothing reserves that space, the content scrolls under it and the user cannot reach what is hidden, especially at the very bottom of the page (R-03).
149
+ - **Fix:** reserve the bar's height for the content: scroll padding on the page and safe-area insets where the device needs them, so nothing important is ever hidden behind it. Verify at a narrow width that the last item is reachable (R-35).
150
+
151
+ ### Sticky Nav Steals the Screen
152
+
153
+ - **Tell:** a sticky header or tall bottom bar that holds a large fixed height, so a big slice of the phone screen is always taken by navigation.
154
+ - **Why:** on a small viewport every fixed pixel of chrome is a pixel of content lost. A tall sticky header turns the visible area into a letterbox and the content into a sliver (R-03).
155
+ - **Fix:** keep fixed nav compact: small enough that the content stays dominant, and collapse or shrink it on scroll where appropriate. Navigation should be present, not the main occupant of the screen.
156
+
157
+ ## Layoutmobile Skill Checklist
158
+
159
+ Run these alongside the core Delivery Gate when the task is mobile or responsive layout work. All answers must be **yes**:
160
+
161
+ - [ ] Does the layout reflow into a distinct mobile state rather than a squeezed desktop? (R-03)
162
+ - [ ] Are there defined states across the width range, not just phone and desktop, so tablet and small-laptop widths are never a stretched stack or a crammed grid? (R-03, R-35)
163
+ - [ ] Do sizes (type, padding, gaps, section heights) use a mobile scale, not desktop sizes unchanged? (R-03, R-05)
164
+ - [ ] Do multi-column grids collapse and stack instead of colliding? (R-03)
165
+ - [ ] Is there no horizontal overflow and nothing clipped? (R-03)
166
+ - [ ] Are interactive targets at least 44 x 44 px with spacing between them? (R-03)
167
+ - [ ] Do hover-only interactions have a tap equivalent with visible feedback? (R-03)
168
+ - [ ] Does the navigation reflow into a mobile pattern (bottom nav or menu) instead of a squeezed desktop row? (R-03)
169
+ - [ ] Do fixed nav bars (bottom nav, sticky headers) never cover content and respect safe areas? (R-03)
170
+ - [ ] Is the layout verified at mobile breakpoints? (R-35)
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Addy Osmani
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.