| name | ux-review |
| description | Use when the user asks to review, critique, or assess the UI/UX of a papai settings/admin section or `client/` component — e.g. "UX review ToolsSection", "review the UI of the task provider panel", "run a UX review on the members section". Produces a report-only, severity-ranked findings document; it never edits source. |
UX Review (guided, screenshot + source, report-only)
Review one client/ section by reading its Storybook screenshots together with its
source, scoring against the fixed rubric, and writing a severity-ranked findings document.
This skill is REVIEW-ONLY. While running it you MUST NOT:
- edit, create, or delete any
.svelte, .ts, .tsx, .js, .jsx file under client/ or src/;
- propose concrete edits, before→after diffs, or an ordered change-plan (findings carry only a one-line described fix);
- run any fix → re-shoot → verify loop.
Allowed outputs: markdown under docs/ux-reviews/; reading any repo file; running
bun shoot / bun shoot:gen to capture screenshots; reading the resulting PNGs. Applying
findings is a separate, human-initiated step in a separate session.
When to Use
- "UX review
<Section>", "review the UI of <X>", "run a UX review on <X>".
<X> is a settings/admin section or a client/ component with a Storybook story.
Do NOT use for: writing or fixing component code; visual-regression gating; whole-UI
batch sweeps (this is per-section, human-triggered).
Prerequisites
- Storybook running:
bun storybook (kept warm).
- One-time:
bunx playwright install chromium.
- Background reading:
docs/architecture/storybook-screenshots.md.
Procedure
-
Resolve the target. Find the component (client/**/<Section>.svelte) and its story
(client/**/<Section>.stories.svelte). Note the story id stem, e.g.
settings-sections-toolssection.
-
Capture the depth-B set. Shoot the existing state stories:
bun shoot -g <Section>
Then add the interaction + narrow-viewport states you need in the manual region of the
generated spec (tests/visual/**/<Section>.spec.ts, below // @generated-end auto-screenshots)
and re-shoot. Use the real @crvy/strybk API:
test('<Section> — expanded, narrow', async ({ sharedPage }) => {
await switchStory(sharedPage, 'settings-sections-<section>--populated')
await sharedPage.setViewportSize({ width: 640, height: 900 })
await sharedPage.getByText('tasks').click()
await expect(sharedPage).toHaveScreenshot()
})
Capture the states the rubric needs, only where they apply:
- State stories — populated / empty / error / loading (the generated set).
- Interaction & micro-states (dim 9) — hover and active on the primary action, focused
input, disabled control, invalid/validation, and any in-flight ("Saving…") frame. Use
Playwright
.hover() / .focus() / .click(); note that programmatic .focus() does
not trigger :focus-visible, so confirm the keyboard focus ring from source, not the shot.
- Spacing & sizing (dim 8) — the default desktop width plus the ~640px narrow width; a
long-content variant (long name / long error string) if a story or arg supports it, to
expose spacing/alignment/overflow the short fixtures hide.
-
Read screenshots + source together. Read the baseline PNGs under
.storybook-shots/**/<Section>.spec.ts/ with the Read tool, and read the component
source. Source is mandatory — it is what makes the findings real rather than guessed from
pixels:
- affordance / accessibility — semantic markup,
aria-*, focus order, disabled reasoning;
- spacing, alignment & sizing (dim 8) — read the actual gap/margin/padding/height/radius
values and check them against the shared spacing/size tokens; flag one-off px that drift
from sibling elements or the scale (a misaligned edge is often a hardcoded value in source);
- interaction & micro-states (dim 9) — confirm
:focus-visible, hover, disabled, and
busy styling exist in the stylesheet rather than inferring them from a single frame.
-
Score against the rubric. Walk every dimension in docs/ux-reviews/RUBRIC.md (visual
hierarchy, affordance, design-system consistency, feedback/state, content, accessibility,
responsive/layout, spacing/alignment/sizing, interaction/micro-states); assign each
pass / warn / fail with one line of rationale.
-
Write the findings doc. Copy docs/ux-reviews/_TEMPLATE.md to
docs/ux-reviews/<Section>.md and fill it in: the scorecard header, then severity-ranked
findings (High → Low). Each finding carries dimension · severity · where-visible · source
anchor (file:line) · one-line suggested fix. Nothing more — no edits, no change-plan.
-
Format and hand off. bun run format (the repo formatter is oxfmt, not prettier),
then report the path to the user. Do not commit unless asked. Stop — implementation is a
separate session.
Optional: cross-section consistency pass
When asked to review consistency rather than one component, read the composed SettingsApp
shots (Personal-ready, Group-ready, Admin-ready), compare sections against rubric
dimension 3, and write docs/ux-reviews/_consistency.md in the same findings format.