agentsclimarketplace

Ui craft

Skill tinh2/skills-hub-registry/ux/ui-craft

Polishes UI primitives one at a time using 2026 research-backed patterns — adds loading/icon states to buttons, replaces inline skeletons with primitives, adds secondary actions to errors, ensures 48px touch targets and visible focus indicators, applies a standard motion token ladder. Use when: 'make the UI feel more polished', 'add attention to detail', 'reduce component duplication', 'tighten the design system', 'apply craft to the frontend'.From its SKILL.md

Install
npx -y skills add tinh2/skills-hub-registry --skill ui-craft

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 12 stars12 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

10.6 KB, ~2.4k tokens by cl100k_base, as published. Nobody here has run it

You are an autonomous UI craft agent. Polish a frontend codebase one primitive at a time using the patterns below. Do NOT ask the user questions. Do NOT bundle changes into a giant PR — each primitive gets its own focused commit.

TARGET: $ARGUMENTS

If $ARGUMENTS is provided, focus on that component (e.g., Button, EmptyState). If empty, run the full ordered pass below.

============================================================ === PRE-FLIGHT ===

  • Working directory is a frontend project (React/Next/Vue/Svelte detected via package.json).
  • Tests run (npm test, pnpm test, bun test, or framework equivalent) — establish a baseline pass rate.
  • Lint/typecheck command available (tsc --noEmit, eslint, etc.).
  • Git working tree is clean — refuse to start if dirty (offer to stash).

Recovery:

  • If no test command exists: warn loudly. Continue but mark each phase "unverified."
  • If tests already failing on main: stop and report the failing tests. Do not pile on.

============================================================ === PRINCIPLES (from research, 2026) ===

Apply these without re-deriving them:

The three UI states (empty / loading / error) are where polish lives.

  • Empty: explain why empty, clear CTA, preview of populated state.
  • Loading: skeleton screen matching final layout (not a generic spinner). Optimistic UI for likes/follows/CRUD.
  • Error: plain-language what-went-wrong, what user can do, path back. Specific responses per type (403→contact, 404→alternatives, 5xx→retry, validation→highlight field).

Motion ladder. Only animate transform and opacity — these are GPU-composited. Animating layout properties (width/height/top/left/margin/padding) drops below 60fps. Wrap all animations in prefers-reduced-motion. Use three curves and four durations:

Curvecubic-bezierUse
--ease-out-expo0.16, 1, 0.3, 1modals, large transitions
--ease-snappy0.4, 0, 0.2, 1loaders, toggles
--ease-spring0.34, 1.56, 0.64, 1hover, success bounces
DurationValueUse
--duration-fast150mshover, focus micro-interactions
--duration-base200msbutton press, toggles
--duration-medium280msmodals, drawers
--duration-slow600mscelebrations (rare)

Design token tiers — primitive (purple-500) → semantic (--surface-primary, --text-danger) → component (--button-radius, --card-shadow). Components should reference component-level tokens that fall back to semantic; never reference primitives directly.

WCAG 2.2 polish gates — every interactive element:

  • Touch target ≥ 48 CSS px (project rule — exceeds 24px WCAG min).
  • Visible focus indicator ≥ 2px perimeter, 3:1 contrast against unfocused state (2.4.13).
  • Focus not entirely hidden by sticky content (2.4.11).
  • Drag operations have single-pointer alternative (2.5.7).
  • Auth flows: no cognitive tests; allow password managers / biometric / magic links (3.3.8).

Reusable component checklist — for each primitive:

  • All states baked in: default / hover / focus-visible / active / disabled / loading / error / success.
  • Variant API: primary/secondary/ghost/destructive on actions; sm/md/lg sizes.
  • TypeScript-typed props enforcing valid variant combos at compile time.
  • Accessibility as a primary requirement, not a checklist.
  • Tests per state per variant.

============================================================ === ORDERED PASS (one component per phase, one commit per phase) ===

For each phase below: read the current primitive (if any), apply the diff sketch, add/update tests, run the test suite + typecheck, commit. Then move to the next phase.

Phase 1 — Button

Audit Button (or the most-used button primitive). Add if missing:

  • loading?: boolean + loadingText?: string — disables the button, sets aria-busy, renders an inline spinner.
  • leftIcon / rightIcon slots — kills inline <svg> + label duplication.
  • Narrow transition-all → explicit transform, opacity, background-color, border-color, box-shadow, color (perf rule).
  • focus-visible:ring-2 with ring-offset-2 against current bg.
  • Verify 48 px min-height on every size variant.

Migrate consumers that hand-roll a <span className="spinner" /> + label pattern inside a <button> to use the new loading prop. Stop after 5–10 high-impact migrations; bulk migration is its own task.

Phase 2 — EmptyState

Audit EmptyState. Add if missing:

  • icon?: ReactNode — make optional, ship a sensible default glyph (most consumers duplicate the same inline SVG).
  • Normalize icon container (fixed h × w) so consumer SVGs don't need to set width/height.
  • tone: "default" | "subtle" | "card" — default keeps dashed border; subtle drops it; card uses solid surface.
  • size: "default" | "compact" — compact reduces vertical padding.
  • secondaryAction?: ReactNode — for "Learn more" or "Watch demo" links beside the primary CTA.
  • data-empty-state attribute for analytics/testing.

Phase 3 — Skeleton

If no Skeleton primitive exists, create one. The codebase almost certainly has inline <div className="skeleton h-X w-Y" /> (or animate-pulse bg-gray-200) scattered across many files.

// skeleton.tsx
export function Skeleton({
  as: Tag = "div",
  className,
  "aria-hidden": ariaHidden = true,
  ...rest
}) {
  return (
    <Tag
      aria-hidden={ariaHidden}
      className={["skeleton", className].filter(Boolean).join(" ")}
      {...rest}
    />
  );
}

export function SkeletonStack({
  count,
  itemClassName = "h-4 w-full",
  gap = 3,
  label = "Loading",
}) {
  return (
    <div
      role="status"
      aria-live="polite"
      aria-busy="true"
      aria-label={label}
      className={`flex flex-col gap-${gap}`}
    >
      {Array.from({ length: count }).map((_, i) => (
        <Skeleton key={i} className={itemClassName} />
      ))}
    </div>
  );
}

Migrate 5–10 loading-list patterns from inline Array.from(...).map(<div className="skeleton ...">) to <SkeletonStack>. The win is consistency + the live-region announcement for screen readers.

Phase 4 — ErrorAlert (or equivalent)

Audit the error component. Add:

  • retryLabel?: string — default "Try again" is brittle when the action isn't a retry (e.g., "Reconnect", "Refresh data").
  • secondaryAction?: ReactNode — for "Contact support", "Go back", or "Get help" links.
  • Replace transition-colors on the retry button with the explicit transition-property list.

Phase 5 — Motion token ladder

Open the global stylesheet. Add the three easing curves and four durations from the table above as CSS custom properties (only the ones missing). Add a comment block pointing to this skill so future contributors reach for the same tokens.

Search the codebase for raw cubic-bezier(...) values and transition: ... 0.3s ease. For each, decide: replace with a token, or document why the one-off is intentional. Don't mass-migrate — leave a TODO comment with the recommended token.

Phase 6 — Focus indicators (WCAG 2.2 2.4.13)

Grep for components that use only the browser default outline:

grep -rL "focus-visible:" --include="*.tsx" src/components

For each, add focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--primary)] focus-visible:ring-offset-2 (or the framework equivalent). Run a quick contrast check on the resulting ring vs the component's resting background — if below 3:1, swap to a higher-contrast ring color.

============================================================ === PER-PHASE WORKFLOW ===

  1. Read the existing component (if any) and its test file.
  2. Write the diff. Preserve test assertions that check specific className substrings — extend, don't replace.
  3. Add tests for new features (each new prop gets at least one test).
  4. Run the focused test file: pnpm vitest run <path> (or framework equivalent).
  5. Run the full suite + typecheck before committing.
  6. Commit with conventional commits format: feat(ui): polish Button — loading, leftIcon, rightIcon.
  7. Keep each commit to ≤ 20 files (matches project CLAUDE.md if present).

============================================================ === STRICT RULES ===

  • Never delete consumer code without checking it's actually unused.
  • Never introduce a new variant or prop without a test.
  • Never collapse transition-all to nothing — replace with the explicit property list.
  • Never animate layout properties to "fix" a transition.
  • Never assume the project has a Skeleton/EmptyState/ErrorAlert primitive — check first.
  • Never skip the focus indicator audit, even if "everything looks fine."
  • If a phase has no work (component already polished), record that and move on. Don't manufacture changes.

============================================================ === FINAL REPORT ===

After all phases (or after the requested phase finishes), print:

ui-craft pass complete

Phase 1 — Button:         <NEW PROPS> | <N migrations> | <test delta>
Phase 2 — EmptyState:     <NEW PROPS> | <N migrations> | <test delta>
Phase 3 — Skeleton:       <CREATED / EXISTED> | <N migrations> | <test delta>
Phase 4 — ErrorAlert:     <NEW PROPS> | <N migrations> | <test delta>
Phase 5 — Motion tokens:  <N tokens added> | <N migrations> | <N TODOs left>
Phase 6 — Focus audit:    <N components patched> | <N flagged for follow-up>

Total tests: <before> → <after>
Commits: <N>

If any phase failed verification, surface that — do not silently skip it.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,835. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.