Skip to content
Back to skills

Design Qa

ASecurity

Rigorous visual QA and polish pass over a component, a page, or a sweep across several. Renders the target in both themes, magnifies the details, judges the craft against a durable rubric and the rendered siblings, fixes the defects, and reports the taste calls. Use when asked to design-QA something, polish a component or page, judge whether something looks good enough, or find visual inconsistencies across components or pages.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 6, 2026
developmentrustgoshellreactnoderailsgit

Works with

  • cli

Security analysis

A100/100

Scanned November 11, 2026

npx -y skills add robritacca-dotcom/rift-ds --skill design-qa --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Design Qa?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Design Qa
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/robritacca-dotcom-design-qa/badge)](https://www.skillsdirectory.com/skills/robritacca-dotcom-design-qa)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: design-qa
description: Rigorous visual QA and polish pass over a component, a page, or a sweep across several. Renders the target in both themes, magnifies the details, judges the craft against a durable rubric and the rendered siblings, fixes the defects, and reports the taste calls. Use when asked to design-QA something, polish a component or page, judge whether something looks good enough, or find visual inconsistencies across components or pages.
icon: frame_inspect
displayDescription: "Renders the target in both themes, magnifies its seams, corners, and states, and lines it up against its nearest rendered siblings. Judges the arrangement against the fundamental principles (proximity, alignment, repetition, contrast, spacing) and the parts against component-scale craft checks, fixes what has one right answer, and reports the taste calls that need a decision."
invoke: ["design QA [Name]","polish the [Name] component","is [Name] good enough","design QA the [category] components"]
---

# design-qa

The taste gate. Find everything a designer who owns the system would notice and send back — especially the things nobody wants to spend time calling out — then fix what has one right answer and surface what doesn't.

This skill judges **rendered pixels**, not source code. Code review can confirm the tokens are right; this pass decides whether the thing is good.

## When invoked

Use this skill when asked to design-QA, polish, or judge something visual — phrases like "design QA [Name]", "polish the [Name] component", "is [Name] good enough", "look at these buttons", "review the [category] components together". It also runs as the mandatory quality gate inside the `new-component` skill (see the last section).

## Scope

Accept any of:

- **A component** → every one of its Storybook stories, plus its website showcase page if it has one (the page is where composition problems show)
- **A page** → a URL path on the website. Page reviews inherit the `visual-review` skill's viewport matrix — both themes at desktop *and* mobile widths — since an arrangement that only holds at one width isn't holding
- **A sweep** → several components or pages at once ("the form controls", "every page under /foundations"), each judged individually *and* against the others — cross-target inconsistency is the sweep's whole point. A sweep over a family starts from the `component-consistency-audit` skill's family table for it (the fill, border, radius, hover, selected and disabled each member takes, built from the stylesheets now), so the lineup is judged against a stated convention rather than against whichever sibling was captured first

If no target is given, default to what this session built or changed. Ask only when genuinely ambiguous.

## Ground rules — why this pass doesn't go stale

- The rubric below is principles, deliberately free of facts about real components. **Facts come fresh each run**: the spec is `design.md` read now, the component list is `src/components/registry.json` read now, and the standard for consistency is siblings **rendered** now — never a remembered lineup or a list written here.
- Judge the render first, the source second. A seam defect lives in pixels; the CSS that caused it comes after the finding, as the fix's address.
- Component names in this skill's examples are fictional by design — a factual claim about a real component inside an example rots silently.

## Evidence

Use the browser/preview tools the harness provides for every step below; never launch a dev server through a raw shell command.

1. **Render the real thing.** Components: the `storybook` configuration in `.claude/launch.json`. Pages: the `website` configuration (theme is `data-theme` on the root element, the theme preset is `data-brand` beside it and the background pick is `data-background`; the `visual-review` skill's step 3 and Key context document how to switch all three and which preset to confirm — verify the attribute actually changed before capturing — and what page chrome to expect).
2. **Capture the matrix.** Every variant and state, in light **and** dark. Then **magnify the details**: zoomed crops of every join, corner, divider, icon seat, and focus ring. Seam defects — a doubled border where two segments meet, a divider a pixel taller than its track, a radius that doesn't flow through a join — are invisible at 1x and glaring at 3x. If the harness offers a zoom or region capture, use it on every joint the component has; if not, scaling the render up (a transform on the story root works) is a fine substitute. One capture-environment trap: after a programmatic theme flip in a hidden browser pane, CSS transitions can freeze mid-flight (paused rendering never advances them), so a token can screenshot at neither theme's value and read as a broken palette. Before judging any colour, let the page settle in a fronted tab or force-finish the page's animations — and when a colour still looks wrong, confirm it with computed styles before writing the finding.
3. **Drive the states for real.** Hover, focus-visible (reached by keyboard, not click), active, disabled, loading, empty, error. Capture each. A state you didn't render is a state you didn't review. On a page review, the layout-mounted chat button's hover-summoned summary panel counts as one of the page's states — summon it and let the reveal settle. The chat panel and its suggestion chips animate on open, close, reveal, and a change of seat (design.md's ChatWidget spec owns the choreography), and so does a welcome with a widget board, whose composer, greeting and tiles enter in stages after a short hold: capture after they settle, and read a mid-flight frame — a part-transparent panel, shimmer pills where chips belong — as animation, not defect. A reply ending in a question card with no chips, a faded record row, and a dimmed composer while a question set is open are designed states, not defects (the same spec's Quick replies paragraph), as are a reply that is only a card, an entry button reporting the agent's state, and a composer that is one row or two depending on what it holds.
4. **Stress the content.** Longest plausible label, most items, zero items, a narrow container, wrapping text. Use story controls or a scratch story; don't ship the scratch.
5. **Line up the siblings.** Pick the two or three nearest relatives by role — same registry category, or same pattern family (everything pill-shaped, everything with a chevron, every card) — and capture the same crops of them. Consistency findings come from this lineup, not from memory. For a page: one or two established pages of the same type.
6. **Read the spec and the source.** The target's `design.md` component section, `design.md`'s **Composition** section — the authoritative page-level arrangement rules the principles below are the vocabulary for — the token rules, and the component or page source. After the visual pass, to name causes and to check behaviour pixels can't show.

## The eye — the design principles

These describe the arrangement, not the parts. The design system already governs the parts — the tokens, radii, type, and their validators decide what a component may be made of. A layout assembled one component at a time will satisfy every token and still be wrong, because these properties only exist between components. Evaluate them after assembly, looking at the whole. They are also the vocabulary findings are written in: "not good enough" only becomes fixable once the violated principle has a name.

### Proximity

Space encodes relationship, and it is read before anything else on the screen. Uniform spacing claims nothing is related to anything. The authoritative rule — and the rhythm ladder that makes it actionable — is `design.md`'s Composition section; this heading is the name the finding gets.

### Alignment

Every element belongs to a shared structure. Placement is never arbitrary and never local. An element positioned correctly relative to its neighbour but not to the composition is misaligned — and this is the most common failure when building a layout piece by piece.

### Repetition

A treatment used consistently becomes a signal. The same role gets the same treatment throughout, which is what makes deviation legible as emphasis rather than as inconsistency.

### Contrast

Differences must be unmistakable. Anything not the same must be clearly different, since near-sameness reads as error. Attention needs somewhere to land first.

### Spacing

Padding belongs to the component; margin belongs to the layout. The rule itself is `design.md`'s Composition rule 1 (parent owns spacing) — cite it there; the finding to watch for is a component asserting a relationship it cannot see by carrying its own outer margin.

### After assembly

Stop and look at the full composition before finishing:

- What structure do the elements share? If you cannot name it, there is no alignment.
- What does the spacing say about what belongs together? Is that true?
- What does the eye land on first? Is that correct?
- Which treatments repeat, and which are one-offs? Can each one-off be justified?

## The craft checks — the same principles at component scale

Inside and between a component's own parts, judged at magnification, per theme:

**Geometry and joins**

- **Optical beats mathematical.** Icons, chevrons, punctuation, and round shapes carry uneven visual weight, so a mathematically centred glyph often looks off-centre. Judge centring by eye at 3x, never by the box model.
- **Concentric corners.** A nested radius relates to its parent's through the padding between them; equal radii on nested boxes look wrong at the corner. (`design.md` records the system's worked example in the Composer geometry.)
- **Joins render once.** Where two segments share an edge — a split control, an attached input-and-button, a segmented anything — the shared border must not double, the group's outer radius must flow through as if it were one shape, and any divider spans exactly the height it should. The two halves must look designed together in *every* state: capture the compound in each state and ask whether the treatment of the inactive half was chosen or inherited.
- **Hairlines are crisp.** 1px lines land on the pixel grid; a soft, blurry border means a half-pixel offset somewhere.

- **A row lines up.** Controls that share a row (a field, a button, a picker, a segmented set) measure the same height at each size, `--control-height-default` and `-compact`; measure them side by side rather than trusting the token, since a border or a line height outside it shows here first.
- **A popup shows whole.** Open every menu, listbox, popover and tooltip inside a scrolling or clipping container and near each screen edge: it must escape the container, flip when its side has no room, stay a margin inside the screen, and follow its control on scroll (`src/stories/AnchoredPopups.stories.tsx` holds the clipping case; design.md's "Popups are placed by one behaviour" owns the rest).

**States as a family**

- **Every state designed, not derived.** A loading state is composed — spinner colour, size, and seat all look chosen — not "opacity plus a spinner". Disabled reads as one coherent treatment, not per-part fading.
- **States don't move geometry.** Hover, focus, and loading never shift layout, resize the control, or reflow the label. Compare each state crop pixel-for-pixel against the resting crop.
- **The family shares logic.** If hover deepens the fill on one variant, it deepens it on all. A state treatment that exists on one component of a pattern family and not its siblings is a Repetition finding, whichever side is right.
- **A gesture renders nothing until release.** Drag the grip, scrub the slider, move the card, and watch the subtree: during the gesture only the dragged node's style (or, for a pen stroke, its path's `d`) should change, and React should commit once, when the pointer lets go. React DevTools' render highlighting shows a per-frame commit as a subtree flashing with the pointer, and a drag that stutters while something beside it animates is the same finding seen at 1x. Per-move state over a re-animating sibling can reach React's nested-update limit and unmount the root, so this is a Defect, not polish, and the fix is the floating card's move in `src/chat/ChatLauncher.tsx` (the variables written per frame, one state commit on release; its widen grip is the pure-DOM case). A per-move update whose re-rendered subtree is genuinely small passes only with a comment beside the handler saying so; a fictional `GadgetDial` that re-renders nothing but its own needle is the shape that earns one.

**Theme parity**

- Dark is designed, not inverted. For each key crop, put light and dark side by side: fills, strokes, and elevation must make the same statement in both. A treatment that reads as a solid fill in light and dissolves into the background in dark is a Contrast finding. One asymmetry is by design: a tinted theme's light surfaces carry less of the tint than its dark ones (`LIGHT_SURFACE_TINT_RATIO` in `website/src/lib/theme/theme-overrides.ts`), so a floor that reads more neutral in light is not a finding.

**System fidelity**

- The right component is used — a page re-implementing an existing library pattern in local CSS is a Repetition finding even when it looks fine today.
- Icons match the type: an icon's stroke weight sits with the font weight beside it; a heavy icon next to light text reads as borrowed from another system.
- The action colour means action, status roles carry status, and visible copy follows `content-design.md`. Token *compliance* has its own skill (`token-audit`); here, judge what the token **choices** look like — a legal token in the wrong role is exactly the kind of thing this pass exists to catch.

**Consistency — the same thing drawn the same way**

- **One drawing per primitive.** A checkbox, radio, switch, chosen mark, close button or hidden label looks exactly like every other in the library, because it *is* the same one: the shared indicators, `ChosenMark`, `CircularButton` and `ds-visually-hidden` named in `design.md`'s Components intro. A control that reads a shade different from the standalone control beside it (a thinner ring, a glyph where the others have a box, a check in another colour) is a redrawn primitive, and the finding is a Defect whichever side looks better. `node scripts/validate-shared-primitives.mjs` catches the copies it can recognise; the eye catches the rest.
- **The surface is the family's.** Line the target up against its family (the rows in `design.md`'s "Surfaces by family"): a fill where the siblings are transparent, a radius step the family does not use, a hover or current-item treatment that differs, a disabled state that fades differently. A member outside its family's convention with no sentence in its spec is a Defect; a family with no convention yet is a Direction call, and the `component-consistency-audit` skill is where it gets decided and written down.

## Judging

The bar is a three-second glance from the designer who owns the system. The founding rule of this skill: **the findings nobody wants to spend time writing up are exactly the findings to write up.** "The buttons on the new component are not good enough" is a legitimate trigger; this pass exists to turn that sentence into named, located defects.

Every finding names the principle or craft check it violates, and each is classified:

- **Defect** — objectively wrong against the rubric, the spec, or the sibling lineup: a doubled seam, an off-grid hairline, a state that shifts layout, an inconsistent gap. One right answer. *Fix it.*
- **Polish** — a clearly better version is available, and the change is small and safe: an icon a shade too heavy, padding a step too tight, an abrupt transition where every sibling eases. *Fix it.*
- **Direction** — more than one defensible answer, or it changes the design: this variant shouldn't exist, this layout wants a rethink, this empty state needs different content. *Recommend one option; don't apply.*

## Polish loop

For every defect and polish finding:

1. Fix at the source — component CSS/TSX or the page module. The fix itself obeys all the library's token and motion rules (the `new-component` skill's `ComponentName.css` section is the reference).
2. Re-render and re-capture **the same crops**. Keep the before/after pairs.
3. Re-run the eye over the changed area — fixes cause regressions too.
4. Loop until a full pass yields no new defect or polish findings.

## Report

Lead with the verdict, evidence attached:

```
## Design QA: [target]

**Verdict:** [clean | N findings fixed, M decisions open | sent back — needs direction before polish helps]

### Fixed
- [what was wrong, one sentence] → [what changed] (before/after crops)

### Open decisions
- [the taste call] — recommendation: [one option and why]

### Checked and clean
[One short paragraph: which variants, states, themes, stress cases, and siblings
were actually reviewed — so "clean" has a defined coverage.]
```

Reference the exact element and file, e.g. "the divider in Gadget's split variant sits 1px proud of the fill (Gadget.css:47)" — the component in that example is fictional by design.

## Guardrails

- **Contrast findings:** the `color-contrast` axe rule is deliberately switched off — rule-wide, every pair — by a settled decision, and the comment beside the override in `.storybook/preview.ts` is its authoritative record (the shipped action pairings it discusses clear AA). The action fills are gated at token level regardless: `ACTION_PAIRINGS` in `scripts/validate-theme-presets.mjs` holds every action fill against what sits on it, in every state, theme and preset, so a contrast finding on one of those pairs is already enforced. Read the comment before raising any contrast finding, and never re-raise the decision itself as a finding without asking the owner first.
- **Page reviews** inherit the false-finding caveats in the `visual-review` skill's Key context — the ambient background's two renderers, the layout-mounted chrome, `desktopOnly` nav — read that section before judging a page screenshot.
- **A clean pass is a valid outcome.** Don't invent findings to justify the run; state what was covered and stop.

## Inside new-component

The `new-component` skill invokes this pass as soon as the component renders in Storybook, before registration. There it is a gate, not a report: loop until no defect or polish findings remain, fold any open direction calls into the hand-off summary, and treat "renders correctly" as necessary but nowhere near sufficient. Before registration `npm run storybook` cannot cold-start (its `prestorybook` hook runs the `validate-registry` chain, which fails on the unregistered folder) — use a running Storybook or the `storybook-raw` entry in `.claude/launch.json` (port 6016, no lifecycle hook), per new-component's step 4.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in development →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.