- Home
- Skills
- UX & UI Design
- UX Laws
More screenshots
Works with the AI Agents you already use
UX Laws
The Laws of UX, Nielsen's heuristics and WCAG 2.2, rewritten as rules your coding agent can actually check, whether it's building a screen, changing one or reviewing your PR.
Free
UX Laws
Example session with this skill installed
/ux-laws review full examples/signup-before.tsx
- Read your context and instructions
- Compiled the ux laws
- Generated the UI component
This is the full review it wrote for the sample signup form that ships with the skill, so you can run the exact same thing yourself. It read the source first, then ran checks.sh and probe.js at 375 and 1280 px, and those two added FOCUS-1 and REGION-2 on top of what it had already found.
Verdict: blocked. 12 findings, and the one that blocks it is a P0: any error wipes every field, password included. The rest are 6 P1s, 4 P2s and a P3.
READ invoicing app · create an account · freelancers, phone + desktop · once per user · new
SCOPE examples/signup-before.tsx · /signup · 375 + 1280 · states: empty, invalid, server error, success
· not run: screen reader, Safari, real slow network
examples/signup-before.tsx:22 P0 RECOVER-4 Nielsen 9 · Recover [B source]
Any failure (duplicate email included) shows alert("Something went wrong") and then empties every
field, password too. The user retypes the whole form with no idea what was wrong.
Fix: keep the values; map the error to its field ("An account already uses this email. Sign in
instead?"); a generic retry message only for 5xx, in role="alert" (RECOVER-7). this change
examples/signup-before.tsx:42 P1 TESLER-2 Tesler · WCAG 3.3.7 · Postel [A checks.sh POSTEL-1 + B source]
"Confirm email" asks for data already entered in the same step, and blocks paste on it.
Fix: delete the field. Show the address back on the "check your inbox" screen (MEMORY-1),
which catches typos better than a blind second entry. this change
examples/signup-before.tsx:16 P1 DOHERTY-1 Doherty · Nielsen 1 [B checks.sh DOHERTY-1 + rendered]
Submit awaits createAccount with no pending state; a second tap during the request sends a
second signup.
Fix: useTransition or a pending flag set before the await; label "Creating account…"; aria-busy;
idempotency key server-side. this change
examples/signup-before.tsx:67 P1 RECOVER-3 Nielsen 5 · Nielsen 9 [B checks.sh RECOVER-3]
Submit stays disabled until every rule passes, so a user with an 11-character password sees a dead
button and no reason.
Fix: keep it enabled; validate on submit; focus the first invalid field. this change
examples/signup-before.tsx:29 P1 MILLER-1 Miller · Nielsen 6 · WCAG 3.3.2 [B checks.sh ×5, probe ×5]
All five fields use the placeholder as the label; it vanishes on the first keystroke, and
"Password (12+ characters)" takes the rule with it.
Fix: visible labels above each field; the 12-character rule as persistent hint text. this change
examples/signup-before.tsx:33 P1 FOCUS-1 WCAG 2.4.7 [A checks.sh FOCUS-1]
outline-none on every input, and no :focus-visible replacement in the file. Keyboard users can't
see which field they're in.
Fix: remove outline-none; the field token's focus ring applies. this change
examples/signup-before.tsx:33 P1 REGION-2 Common region · WCAG 1.4.11 [A probe 1.35:1]
border-[#ddd] on white is 1.35:1; at 375 px in daylight the fields are near-invisible boxes.
Fix: the product's field border token (≥ 3:1). this change
examples/signup-before.tsx:29 P2 PARKINSON-1 Parkinson · WCAG 1.3.5 [B checks.sh ×5]
No autocomplete tokens, so autofill and password managers can't help.
Fix: name, email, tel, new-password. this change
examples/signup-before.tsx:50 P2 POSTEL-2 Postel [B checks.sh POSTEL-2]
type="number" on phone: rejects "+44 20 …", strips a leading 0, and the wheel changes it.
Fix: type="tel" autocomplete="tel"; strip separators before validating. this change
examples/signup-before.tsx:72 P2 HICK-1 Hick [B source + probe HICK-1]
Cancel has the same filled style as Create account, side by side at equal width; two primaries.
Fix: Cancel becomes a secondary text link (it navigates, so <a>: JAKOB-1). this change
examples/signup-before.tsx:33 P2 INPUT-1 Input constraints [B probe INPUT-1 at 375]
text-sm (14 px) on inputs; iOS Safari zooms the page on focus.
Fix: text-base below md, md:text-sm. this change
examples/signup-before.tsx:68 P3 MOTION-1 Motion [A checks.sh MOTION-1]
transition-all plus hover:scale-105 on both buttons.
Fix: transition the background colour only; drop the scale. this change
QUESTIONS Is the phone number needed at signup? If it's only for delivery questions, ask for it later
or mark it optional with the reason (OCCAM-1).
DEBT none found outside this file
VERDICT blocked (P0: data loss on error) · severities provisional (one reviewer)
What it left out on purpose
A few things it deliberately didn't flag. Five fields isn't a Miller's law problem (that's MILLER-0), so the field count isn't a finding, and whether the phone number is needed went under QUESTIONS because only the team knows. The button text wasn't flagged either: white on indigo-600 passes 4.5:1, and the probe measured it. The redirect to /app after signup isn't a PEAK-1 finding, since whether /app greets a new user is outside this file and would need a look first. And twelve is the cap for a full review, anything past that would have gone under DEBT.
Next step
After this you just say fix. It applies all twelve as behaviour changes, tags each one with its check ID and leaves the form's styling alone. examples/signup-after.tsx is what that produced, and checks.sh passes it 26 out of 26.
signup-after.tsx
TSX · React component
Example file from a real run - the skill writes it into your workspace.
Connects securely to your tools. The creator never sees your data.
About this skill
Before writing this I went through the popular UX skills and the cheatsheets they're built on, and kept running into the same advice. Keep menus under seven items. Put the nav in a hamburger "because Hick's law". Animate at 400ms. And my favourite: "44px is the WCAG AA minimum". It isn't, AA is 24px and 44 is AAA. Your agent learned the same stuff, so that's what it hands back to you.
So I wrote ux-laws. All 30 laws are still in there, but the agent isn't allowed to just name-drop one anymore. It has to come back with a real number from a standard, or something it actually counted in your code, or a question only your team can answer. Every finding points at a file and line, gets a P0 to P3 severity, and says where the evidence came from (checks.sh, probe.js, or just reading the source).
What you get
Five modes, and you mostly don't have to pick. Ask for a new screen and it'll build it. Point it at something that already exists and it works as a feature or a fix. Give it a PR and it only reviews, it won't touch your code. In CI it just runs the checks and passes or fails.
It also won't throw all thirty laws at every screen. SkillsBench measured that kind of skill making agents about 3 points worse, while focused ones made them 17 to 19 points better. Tell it "it feels slow" or "people keep deleting stuff by accident" and the router picks the two or three checks that actually explain that.
If you already have UI, it looks at two of your existing screens before it writes anything and reuses your components. A new screen that works differently from the rest of your app gets treated as a bug, even if some textbook says it's right.
And every new or changed screen has to account for 15 states, not just the happy one: first use, no results, loading, server error, half the items failing, offline, no permission, destructive actions and so on.
How it checks
The static part is checks.sh. It's a plain bash script with 26 checks, mostly grep, so it runs pretty much anywhere, and with --diff main it only looks at what changed in your PR. Then there's probe.js, which runs inside the page once it's rendered. That's where contrast, tap target sizes, labels and accessible names actually get measured. Worth knowing: axe ships with its target-size rule switched off, so a default axe run will never tell you a button is too small. The skill turns it on. All the thresholds sit in numbers.md with a source and the date I checked them (October 2026).
Findings come graded too, A to D. A is measured against a standard. B is something counted in your code. C is the agent's call from the rendered screen, and D is a question for your team. Only A ever fails a build. And if a check couldn't run you'll see "not run" in the report, not a fake pass.
Does it work?
I've run it on two real codebases so far, an Astro marketing site and a Next.js app. In both, the automated checks passed pages that still had real problems on them, and it was the judgment pass that caught them. The worst was a P0 on the Next.js app: a report whose headline money total counted items the same page called free.
Good fit for
Where it helps most is reviewing a PR before you merge. Or when someone says "nobody finishes signup" and you want that fixed without it turning into a redesign. Anything out of scope gets written to UX.md as debt and you decide later. I'd also use it when a new feature has to match what's already there, for forms, checkout or settings where you want the empty and error states done from the start, and to fail CI on measured WCAG 2.2 problems.
What it doesn't do
Visual design. No colours, no fonts, no style direction, there are other skills for that. It's also not a full WCAG conformance audit or a VPAT, and nothing replaces watching real people use your product. The rendered checks need a browser the agent can control. Last thing: one agent rating severity on its own isn't very reliable, so the report marks severities as provisional.
It won't do visual design, so no colours, fonts or style direction. It's not a full WCAG conformance audit or a VPAT either, and honestly nothing beats watching real people use the thing. It's mostly been used on web stuff so far, React, Vue, Svelte, Astro, or just plain HTML. Without a browser the agent can drive, the rendered checks just say not run. Severity calls from one agent are a first opinion, so the report marks them provisional. I last checked the thresholds in October 2026.
How to use
- 1
Connect your agent to the Agensi MCP
Copy the prompt and paste it into Claude, ChatGPT, Cursor or any agent that supports MCP. It sets up the connection for you. Manual setup
- 2
Sign in to Agensi
Your agent shows a sign-in link. Sign in and click Allow.
- 3
Ask for what you need
Your agent loads this skill and uses it on your task. It always asks before any payment.
Reviews
This skill has been used 9 times.
Trust & safety
Security scan
Security scan passed 12 days ago
- Free with an Agensi account
- Software
- Bashgrep
- Optional
- Perl
GitBrowser automation
On Windows, use Git Bash. Perl ships with Git. Git is only for checks.sh --diff. The browser, such as Claude Code's browser pane or Playwright, runs probe.js.
Permissions
File Scopes
Shell is for checks.sh, which only reads your files (bash, grep, perl). It drops a temp folder while it works and deletes it after, and with --diff it asks git which files changed. Read Files because the agent reads your UI code and looks at two of your existing screens before changing anything. Write Files is only used in BUILD, FEATURE and FIX, to edit UI code and keep a UX.md file. REVIEW and CHECK don't change anything. Browser is for rendering each state at 375 and 1280 px and running probe.js in the page, and probe.js doesn't make network requests. Network only comes up if your project doesn't have axe-core installed, in which case the agent may load it from cdn.jsdelivr.net into the page it's testing. There are no accounts, API keys or environment variables involved.