
Ux Extract
- 493 installs
- 954 repo stars
- Updated July 2, 2026
- jezweb/claude-skills
Extract layout, component, and interaction patterns from screenshots or live pages to inform prototypes and design specs before full build.
About
Helps extract UX structure from screenshots or pages into actionable design briefs: component inventories, layout grids, interaction flows, and token hints so Claude accelerates prototype and validation work before frontend implementation begins.
- screenshot-to-pattern extraction
- component and layout inventory
- interaction and flow notes
- design-token hints
- prototype-ready UX briefs
Ux Extract by the numbers
- 493 all-time installs (skills.sh)
- +27 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #597 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/jezweb/claude-skills --skill ux-extractAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 493 |
|---|---|
| repo stars | ★ 954 |
| Last updated | July 2, 2026 |
| Repository | jezweb/claude-skills ↗ |
What it does
Extract layout, component, and interaction patterns from screenshots or live pages to inform prototypes and design specs before full build.
Files
UX Extract
Exhaustively study a reference web app and produce a reusable pattern library. Goes everywhere, captures everything, then organises it into a document another audit or build can reference.
The inverse of ux-audit:
- Audit asks: does this match a bar?
- Extract asks: what is the bar?
Audits without extracts implicitly compare to "my memory of other apps" — fragile and inconsistent. Extracts turn that memory into a concrete, navigable artifact. An audit can then say: "Empty state on /app/clients shows no CTA. Reference (claude.ai) shows 3 keyboard shortcuts plus 'New chat' in the same position" instead of "feels a bit sparse".
When to use
- Before building a new feature — study how best-in-class apps handle it
- Benchmarking a build — extract the reference, then audit against it
- Onboarding designers or engineers — here's what good looks like, concretely
- Competitor research — document the competitor's UX so you can meaningfully differentiate
- Refreshing an old app — extract patterns from modern equivalents to guide the update
Scope and ethics
Before starting, confirm the target is fair game:
1. Use your own account — don't scrape anything that requires credentials you don't legitimately hold 2. Respect `robots.txt` for unauthenticated crawling 3. Rate-limit — act like a human user, not a crawler. Pause between pages. 4. Check ToS — most SaaS Terms of Service permit individual inspection but prohibit automated scraping 5. Don't redistribute screenshots of a live competitor's app publicly — pattern libraries are internal references
If the target is behind a paywall or requires a trial account, ask the user whether they have legitimate access before proceeding.
Setup
1. Browser tool
| Target | Tool | Notes |
|---|---|---|
| Authenticated reference (you have an account) | Chrome MCP | Uses your logged-in session |
| Public reference (marketing pages, docs, public demos) | Playwright MCP | No login needed |
See ../ux-audit/references/browser-tools.md for commands.
2. Viewport
Pin 1440×900 as baseline (MacBook standard). Also capture 768 and 375 for responsive patterns. Don't exceed 2000px wide.
2b. Screenshot post-processing
On Retina Macs, Chrome captures at 2× the logical viewport — a 1440-wide window produces a 2880-wide PNG. Post-process after each batch so the library isn't full of oversized files:
img-process batch ./screenshots --action optimise --max-width 1440Idempotent — no-op on already-small files. Run at the end of each route's capture, or across the whole screenshots/ folder at the end of the extract. Playwright MCP users can set deviceScaleFactor: 1 in the context options and skip this step.
3. Scope
Decide before starting:
- Whole app — traverse everything reachable (can take hours, produces a comprehensive library)
- Feature area — one section ("the settings flow", "the dashboard", "the billing flow")
- Pattern class — just empty states, just error handling, just onboarding
Narrower scope produces tighter, more useful libraries. "Whole app" is only worth it for apps you'll be building a direct analogue of.
4. Focus lens (optional)
Optional bias for capture. Examples:
- "Focus on patterns for data-heavy lists" — prioritise table, filter, search, virtualisation screenshots
- "Focus on onboarding and empty states" — prioritise first-run flows and zero-data views
- "Focus on permission boundaries" — log in as multiple roles, document the differences
If no focus is given, capture broadly.
Discovery
Sitemap crawl
Build the full route inventory:
1. Public sitemap — check /sitemap.xml, /robots.txt for discoverability 2. Nav crawl — click through every section visible in the top nav, sidebar, footer 3. In-app discovery — once inside, note every link that appears (breadcrumbs, tabs, contextual menus) 4. URL inspection — some apps have useful patterns in /settings, /preferences, /admin that aren't in the main nav
Record each route with its purpose: /settings/billing — subscription plan, payment method, invoice history.
Pattern inventory
Before deep-capture, scan the app once and list pattern types you'll document. Typical categories:
- Wayfinding (nav, breadcrumbs, current-location, back)
- Lists & tables (row, hover, action reveal, selection, sort, filter, paginate, empty)
- Forms (label, validation, error, required, inline help)
- Modals & dialogs (trigger, focus, escape, scroll, confirm)
- Feedback (toast, inline, progress, loading, saved)
- Onboarding & empty states (first-run, zero-data CTA, guided tour)
- Permissions & roles (restricted views, denied-access, role indicators)
- Copy & microcopy (buttons, headings, errors, placeholders, tooltips)
- Keyboard (shortcut sheet, focus, tab order, command palette)
- Motion (transition, reveal, loading, gesture)
- Responsive (breakpoints, mobile-specific: bottom sheet, tabs, swipe)
Not every app uses every category. Mark which apply.
Capture Phase
For each route, capture exhaustively. Screenshots are cheap — err toward more.
Screenshot all states
Per meaningful element, capture:
| State | Trigger |
|---|---|
| Default | page loaded, nothing interacted with |
| Hover | mouse over a button, row, nav item |
| Focus | keyboard-focused via Tab |
| Active | button mid-click, input being typed into |
| Open | dropdown open, menu expanded |
| Closed | dropdown closed, menu collapsed |
| Expanded | accordion open, detail panel expanded |
| Collapsed | accordion closed |
| Selected | checkbox ticked, row selected, tab active |
| Loading | skeleton, spinner, pending state |
| Empty | list with no items |
| Populated | list with many items |
| Error | inline, toast, or full-page error |
| Success | post-action confirmation |
See references/capture-checklist.md for the full per-pattern checklist.
Capture copy verbatim
Copy the text exactly, including punctuation, ellipses, and tone:
- Button labels:
"Start chat","Upgrade plan","Delete forever" - Empty states: "No conversations yet. Start one to see it here."
- Error messages: "We couldn't save that change. Try again, or contact support if it keeps happening."
- Confirmation dialogs: "Delete this project? All 14 tasks and 3 members will be removed. This cannot be undone."
- Placeholder text:
"e.g. smith@company.com" - Tooltips:
"Pressing Cmd+K opens this from anywhere"
Raw copy is gold for writers and informs your app's voice.
Capture interactions
For each interactive element, note:
- Trigger: click / hover / keyboard / long-press / drag
- Target: what it affects (opens modal, filters list, navigates)
- Feedback: immediate visual response? delayed confirmation?
- Reversibility: undoable? destructive?
Capture keyboard patterns
- Shortcut sheet: is there a
?orCmd+/that reveals the shortcut list? Capture it. - Command palette:
Cmd+Kor similar? Capture the palette open, searching, a result selected, and an action executed. - Focus indicators: tab through the page, note the ring style, colour, thickness
- Tab order: is it logical? Any unexpected jumps?
Capture responsive treatments
For each route, screenshot at 1440, 768, 375. Note what changes, not just "it works":
- Navigation moves from sidebar to hamburger at [breakpoint]
- Table collapses to stacked cards at [breakpoint]
- Modal becomes full-screen at [breakpoint]
- Multi-column form becomes single-column at [breakpoint]
Capture motion
Record a GIF (Chrome MCP's gif_creator) of any animation worth documenting:
- Page transitions
- Modal enter/exit
- List item enter/exit
- Loading → loaded
- Success animations (confetti, checkmarks)
- Drag-and-drop feedback
One 3-second GIF is worth a paragraph of description.
Dedup Phase
After capture, many patterns will appear on multiple pages. Deduplicate:
- Same row pattern on 5 list pages → one "list row" entry with a note "used on: /clients, /projects, /invoices, /reports, /team"
- Same empty state layout with different copy → one "empty state" entry with copy variants listed
- Same modal chrome → one "modal" entry; specific modals listed as usages
Keep two counts per pattern:
- Occurrences — how many times this pattern appears
- Variants — meaningful differences (icon vs no icon, small vs large, with CTA vs without)
A pattern that appears once is rarely worth documenting unless it's unique and notable.
Output
Write to docs/ux-extracts/<app-name>/ (or .jez/artifacts/ux-extracts/<app-name>/ if that directory exists):
docs/ux-extracts/claude-ai/
├── pattern-library.md ← main document
├── copy-corpus.md ← optional, raw copy by page (for writers)
└── screenshots/
├── 001-home-default.png
├── 002-home-hover-cta.png
├── 003-new-chat-empty.png
└── ...See references/pattern-library-template.md for the output structure.
The pattern library should be:
- Navigable — table of contents at the top, jump links to every section
- Cross-referenced — "see also: Modal Chrome"
- Screenshot-dense — every claim backed by a referenced screenshot
- Copy-accurate — verbatim text in code blocks or blockquotes, not paraphrased
- Honest — note what's missing or weak as well as what's good. A reference library isn't gospel.
How ux-audit consumes this
ux-audit checks for pattern libraries at .jez/artifacts/ux-extracts/<ref>/pattern-library.md or docs/ux-extracts/<ref>/pattern-library.md. If found, it uses them as the bar for comparison. Audit findings can then cite specific patterns:
"Empty state on /app/clients has no explanatory copy and no CTA. Reference library [claude.ai § Empty States] shows CTA + 2 example prompts in the same position."
No integration is required beyond producing the library in the expected path.
Autonomy
- Just do it: Navigate, screenshot, copy text, inject JavaScript to read computed styles, download static assets (logo, icons) for reference
- Ask first: Any login that requires credentials the user hasn't authorised you to use, any scraping of a site where ToS or rate limiting is ambiguous
- Stop and confirm: If the target has a login wall and you don't have clear authorisation, stop and confirm before proceeding
Reference files
| When | Read |
|---|---|
| Building the pattern-library.md output | references/pattern-library-template.md |
| Per-pattern capture checklist (what to screenshot, what to note) | references/capture-checklist.md |
| Browser tool commands | ../ux-audit/references/browser-tools.md |
Tips
- Screenshots are cheap — capture generously. Easier to drop a screenshot from the library than to rerun the extract to get one.
- Capture copy the moment you see it — don't plan to come back; come back and it'll be behind a different state.
- Note what's absent — if an app has no keyboard shortcut sheet, that's a pattern decision worth documenting too.
- Separate observation from evaluation — extract records what exists, not whether it's good. Opinions belong in an audit, not an extract.
- Extracts decay — apps change. Timestamp the library, link to the date on archive.org if possible, plan to re-extract every 6–12 months for apps you compare against often.
- Build incrementally — open the library file at the start, append as you go. Don't try to structure it all at the end.
Capture Checklist
Per-pattern checklist of what to screenshot and note during extraction. Use as a walking reference while browsing the target app.
Per-Route Baseline
On arriving at every route, before interacting:
- [ ] Screenshot at 1440×900 (baseline)
- [ ] Read the
<h1>and note the page title style - [ ] Note the URL pattern (semantic? slug? numeric ID?)
- [ ] Check for breadcrumbs — screenshot if present
- [ ] Check the browser console for errors (mentionable but not central to extract)
- [ ] Note page load time impression (instant / skeleton shown / slow)
Lists & Tables
- [ ] Empty state (0 items)
- [ ] Populated state (many items)
- [ ] Row hover (trigger hover on a non-first row to see non-edge styling)
- [ ] Row selection (click checkbox, capture with action bar visible)
- [ ] Multi-selection (select 5+ rows)
- [ ] Sort: click a column header, capture the sorted state and the sort indicator
- [ ] Filter: apply one filter, capture; apply two, capture; clear all
- [ ] Search: type a query matching items, capture results; type garbage, capture no-results
- [ ] Pagination: at page 1, page 2, last page; change items-per-page
- [ ] Action menu on a row: hover or click the overflow menu, capture open
- [ ] Row click: capture the detail or drawer that opens
Forms
- [ ] Default state (empty form, no interactions)
- [ ] Focused field (tab into one, note focus indicator)
- [ ] Partially filled (some valid, some empty)
- [ ] Validation error: submit with bad data or leave required field empty, screenshot the error
- [ ] Inline help text visible (hover or focus a help icon if present)
- [ ] Disabled state (fields that grey out based on other choices)
- [ ] Success state (after submission, capture the confirmation)
- [ ] Submit button: default, hover, active (mid-click), loading, disabled
- [ ] Cancel behaviour: click cancel from a dirty form — does it warn?
Buttons
- [ ] Default
- [ ] Hover
- [ ] Focus (via Tab)
- [ ] Active (click and hold)
- [ ] Loading (click a button that triggers an async action, capture mid-load)
- [ ] Disabled
- [ ] All variants: primary, secondary, destructive, ghost, icon-only
Modals & Dialogs
- [ ] Trigger: screenshot the button/link that opens the modal (before click)
- [ ] Open: modal fully visible with backdrop
- [ ] Focused field inside modal
- [ ] Filled and validated (if it has a form)
- [ ] Error state (form error inside modal)
- [ ] Success: post-submit confirmation (toast? modal replaces content?)
- [ ] Close methods tested: X button, Escape key, backdrop click
- [ ] Animation: record a GIF of open + close (
gif_creator, 3 seconds) - [ ] Nested modals if they exist (confirmation inside an edit modal)
Confirmation Dialogs (destructive)
- [ ] Trigger the destructive action
- [ ] Capture the confirmation dialog with the exact copy visible
- [ ] Note the button placement (destructive left vs right)
- [ ] Note the destructive button style (red fill? outline? which variant?)
- [ ] Note default keyboard focus (on Cancel or on Destroy?)
- [ ] Cancel flow: click cancel, verify nothing destructive happened
- [ ] Do NOT complete destructive actions without explicit user approval
Navigation
- [ ] Primary nav: default state, hover on an item, focus via Tab
- [ ] Current page indicator: how is the active item visually marked?
- [ ] Sub-nav / tabs: default and active states
- [ ] Collapsed/expanded nav (if it has a toggle)
- [ ] Mobile hamburger: tap trigger, drawer open, drawer close
- [ ] User menu: click user avatar, capture the menu open
Empty States
For every route that can be empty:
- [ ] Capture with zero data
- [ ] Note: illustration? headline? description? CTA? secondary link?
- [ ] Copy the text verbatim
- [ ] If CTA is present, click it and capture what happens next
Error States
- [ ] Inline form error (invalid input)
- [ ] Field-level error message position and styling
- [ ] Page-level error banner (e.g. after a failed save)
- [ ] Toast error
- [ ] 404 page: navigate to
/nonsense-route-12345 - [ ] 403 / permission denied page (if you can trigger one)
- [ ] 500 / server error (rare — screenshot if you see one)
- [ ] Network-offline behaviour if you can simulate it (DevTools throttle → offline)
Loading States
- [ ] Skeleton: reload a data-heavy page and capture the skeleton before data arrives
- [ ] Spinner: trigger a slow action and capture
- [ ] Progress bar: if you can trigger a known-slow operation (file upload, bulk action)
- [ ] Step indicator: multi-step flows, capture at steps 1, 2, 3
Feedback
- [ ] Toast: trigger a save, screenshot the toast (and capture the copy verbatim)
- [ ] Toast variants: success, info, warning, error — trigger each if possible
- [ ] Inline confirmation (e.g. "Copied" next to a copy button)
- [ ] Unsaved-changes warning: try to navigate away from a dirty form
Keyboard
- [ ] Press
?andCmd+/— does a shortcut sheet appear? Screenshot it - [ ] Press
Cmd+K— does a command palette open? Screenshot default state and with a query typed - [ ] Tab through the page, screenshot the focus indicator on different element types (button, input, link, card)
- [ ] Try app-specific shortcuts from the sheet — verify they work
- [ ] Escape key: does it close modals? Clear search? Do something unexpected?
Motion (record GIFs)
- [ ] Page transition between two main routes
- [ ] Modal open and close
- [ ] Toast appearing
- [ ] List item being added (submit a form that adds to a visible list)
- [ ] List item being deleted
- [ ] Skeleton → populated crossfade
- [ ] Any celebratory moments (upgrade success, onboarding milestone)
- [ ] Hover animations on cards or buttons if they have any (not just colour change)
Responsive (repeat key captures at each width)
- [ ] 768px: nav behaviour, form layout, table-to-card transition
- [ ] 375px: mobile nav, floating buttons, bottom sheets, full-screen modals
- [ ] Note any width where the layout obviously breaks or transitions awkwardly — screenshot it
Dark Mode (repeat key captures)
- [ ] Home / dashboard
- [ ] A list view
- [ ] A detail view
- [ ] A modal
- [ ] An empty state
- [ ] An error state (often forgotten in dark mode design)
Permissions (if you can test multiple roles)
- [ ] Log in as lowest-privilege role
- [ ] Screenshot what's different in the nav
- [ ] Try to access a denied page directly (paste URL)
- [ ] Note what message/UX you get
- [ ] Try to take an action you shouldn't be able to — what happens?
- [ ] Log back in as admin; note items that were hidden
Copy Corpus
Throughout the extraction, capture the exact text of:
- [ ] Every button label
- [ ] Every empty-state message
- [ ] Every error message (inline, toast, page)
- [ ] Every confirmation dialog
- [ ] Every tooltip
- [ ] Every placeholder
- [ ] Headings on main pages
- [ ] Onboarding copy (welcome messages, tour steps)
- [ ] Success messages
- [ ] Footer copy, legal text (quickly note but don't analyse)
Save these in copy-corpus.md, grouped by page or by category.
Things to explicitly not do
- Don't scrape content rapidly with automation — act like a human
- Don't save or redistribute screenshots of copyrighted content (illustrations, logos) beyond internal reference
- Don't attempt to access paid features without a paid account
- Don't extract from apps that explicitly prohibit inspection in their ToS
- Don't complete real destructive actions on a live reference account — use a test account or stop at the confirmation dialog
Pattern Library Output Template
Structure for the pattern library produced by ux-extract. Write to docs/ux-extracts/<app-name>/pattern-library.md.
# Pattern Library: [App Name]
**Extracted**: YYYY-MM-DD
**URL**: https://app.example.com
**Scope**: [Whole app / Settings flow / Empty states only / etc.]
**Focus lens**: [optional — e.g. "data-heavy lists"]
**Viewport captured**: 1440×900 baseline + 768 + 375
**Browser**: Chrome MCP / Playwright
**Screenshots**: [N] in `./screenshots/`
## Contents
1. [Wayfinding](#wayfinding)
2. [Lists & Tables](#lists--tables)
3. [Forms](#forms)
4. [Modals & Dialogs](#modals--dialogs)
5. [Feedback](#feedback)
6. [Onboarding & Empty States](#onboarding--empty-states)
7. [Permissions & Roles](#permissions--roles)
8. [Copy & Microcopy](#copy--microcopy)
9. [Keyboard](#keyboard)
10. [Motion](#motion)
11. [Responsive](#responsive)
12. [Notable Absences](#notable-absences)
---
## Wayfinding
### Primary Navigation
- **Layout**: [sidebar / top bar / hybrid]
- **Width / height**: [specific values observed]
- **Sections**: [list each section with its items]
- **Current-location indicator**: [bold text / background fill / border / left-edge stripe]
- **Collapse behaviour**: [at what breakpoint does it collapse? to what?]
- **Screenshots**: `screenshots/010-nav-default.png`, `screenshots/011-nav-collapsed.png`, `screenshots/012-nav-mobile-drawer.png`
- **Used on**: every page
### Breadcrumbs
- **Present**: Yes / No / Partial (only on N routes)
- **Style**: [separator character, truncation behaviour, home icon present?]
- **Example**: `Home › Clients › Jenny O'Brien › Policy #123`
- **Screenshots**: `screenshots/020-breadcrumb.png`
- **Used on**: detail pages
### Back Navigation
- **Explicit back button**: [present / absent / contextual]
- **Browser back**: [preserves filters? / resets view?]
- **Deep links**: [all routes linkable / some require navigation from parent]
---
## Lists & Tables
### List Row (primary pattern)
- **Height**: 56px
- **Layout**: `[Avatar] [Name + subtitle stack] [Metadata columns] [Actions on hover]`
- **Hover state**: background fill, action buttons fade in on right
- **Selected state**: left-edge stripe in accent colour, subtle background tint
- **Click target**: entire row → navigates to detail
- **Screenshots**: `screenshots/100-list-row-default.png`, `screenshots/101-list-row-hover.png`, `screenshots/102-list-row-selected.png`
- **Used on**: /clients, /projects, /invoices, /team (4 occurrences)
- **Variants**:
- *Compact* (32px height) on /settings/integrations
- *Dense* with 2 lines of subtitle on /reports
### Table (data-heavy)
- **Used instead of list when**: [N+ columns, user needs to scan comparatively]
- **Header**: sticky on scroll, sortable indicators on clickable columns
- **Row**: [same as list row or different?]
- **Selection**: checkbox column, select-all in header, count shown in action bar
- **Action bar**: appears at top when rows selected, with [Actions] [Export] [Delete] buttons
- **Screenshots**: `screenshots/110-table-default.png`, `screenshots/111-table-selection.png`, `screenshots/112-table-action-bar.png`
### Filters
- **Style**: [chip filters / sidebar / toolbar dropdown]
- **Multi-select**: Y/N
- **Active filter display**: [chips at top / text summary / counter badge]
- **Clear all**: [present / absent]
- **URL reflection**: [filters in query string? reload-safe?]
- **Screenshots**: `screenshots/120-filters-default.png`, `screenshots/121-filters-active.png`
### Pagination
- **Style**: [page numbers / prev-next / infinite scroll / load more]
- **Items per page**: [options: 25, 50, 100]
- **Position**: bottom-right
- **Deep link to page N**: [works / redirects to 1]
### Empty State (list)
- **Layout**: centred, with illustration, headline, description, CTA button
- **Copy example**: *"No clients yet"* / *"Add your first client to see them here"*
- **CTA**: `"Add Client"` (primary style)
- **Screenshots**: `screenshots/130-empty-list.png`
---
## Forms
### Field Layout
- **Label position**: above input
- **Required marker**: asterisk in accent colour, after label text
- **Help text position**: below input, muted
- **Error text position**: below input, replaces help text, red
- **Inline validation**: on blur (not on keystroke)
- **Screenshots**: `screenshots/200-form-default.png`, `screenshots/201-form-error.png`
### Input Styles
- **Height**: 40px standard, 48px large (for primary CTAs like search)
- **Border**: 1px neutral, 2px accent on focus
- **Rounded corners**: 8px
- **Focus ring**: 2px accent offset by 2px
### Buttons
- **Primary**: accent fill, white text, 40px height, 12px h-padding
- **Secondary**: neutral outline, dark text
- **Destructive**: red fill on solid / red text on outline
- **Disabled**: 40% opacity
- **Loading state**: spinner replaces label, button remains same width
- **Copy style**: verb-first, specific (`"Save Client"` not `"Save"`)
- **Screenshots**: `screenshots/210-button-primary.png` through `215-button-disabled.png`
### Form Feedback
- **Save confirmation**: toast top-right, dismisses after 3s
- **Unsaved changes warning**: browser beforeunload on form with dirty state
- **Autosave**: [present / absent — where used]
---
## Modals & Dialogs
### Modal Chrome
- **Backdrop**: 60% black overlay, blur 4px
- **Sizing**: 560px wide default, max-height 80vh with scroll
- **Position**: centred horizontally, 10vh from top
- **Close**: X top-right + Escape key + click backdrop
- **Focus**: auto-focused on first input, trapped within modal
- **Animation**: fade + slight scale-up on enter (150ms), fade on exit
- **Screenshots**: `screenshots/300-modal-open.png`, `screenshots/301-modal-form.png`
### Confirmation Dialog
- **Used for**: destructive actions (delete, archive, revoke)
- **Copy pattern**: *"[Verb] [specific thing]? [Consequence]. This [can / cannot] be undone."*
- Example: *"Delete Jenny O'Brien? 3 policies will also be removed. This cannot be undone."*
- **Buttons**: destructive action on right in red, cancel on left in neutral
- **Keyboard**: Escape cancels, Enter activates primary (which is cancel — safer default)
- **Screenshots**: `screenshots/310-confirm-destructive.png`
### Drawer (side panel)
- **Used instead of modal when**: editing a record inline, showing detail alongside a list
- **Position**: right side, 480px wide
- **Overlay**: lighter (30% black)
- **Close behaviour**: same as modal
---
## Feedback
### Toast
- **Position**: top-right
- **Stack**: new toasts push old ones down, max 3 visible
- **Duration**: 3s default, 5s for errors, sticky for critical
- **Dismiss**: X button + auto-timeout
- **Variants**: success (green), info (blue), warning (amber), error (red)
- **Copy**: specific (*"Client Jenny O'Brien saved"*, not *"Saved"*)
- **Screenshots**: `screenshots/400-toast-success.png`, `screenshots/401-toast-error.png`
### Inline Confirmation
- **Pattern**: next to the triggering button, short label appears for 2s
- **Example**: *"✓ Copied"* next to a copy-link button
### Loading States
- **Skeleton**: used for list/table loads, matches final layout
- **Spinner**: used for action feedback (button click → spinner in button)
- **Full-page skeleton**: used on route change if data > 500ms
- **Screenshots**: `screenshots/410-skeleton-list.png`, `screenshots/411-skeleton-detail.png`
### Progress
- **Determinate**: progress bar with % for file uploads, bulk operations
- **Indeterminate**: looping bar at top of page for slow nav transitions
- **Step indicator**: numbered pills across top for multi-step flows
---
## Onboarding & Empty States
### First-Run Experience
- **Welcome screen**: Y/N — [description]
- **Tour**: Y/N — [steps, dismissable?]
- **Sample data**: [seeded / placeholder / none]
- **Screenshots**: `screenshots/500-first-run.png`
### Empty State Anatomy
| Element | Present? | Treatment |
|---------|----------|-----------|
| Illustration | Y | Abstract, brand-coloured, 120px square |
| Headline | Y | Bold, sentence case, ends without period |
| Description | Y | One sentence, explains *what this is* and *why it's empty* |
| CTA | Y | Primary button, verb-first, specific |
| Secondary link | Sometimes | "Learn more" link to docs |
### Copy Patterns for Empty States
- *"No [thing] yet. [One-line explanation]. [CTA]."*
- Examples:
- *"No conversations yet. Start one below to see it here. [Start chat]"*
- *"No clients yet. Add your first to begin tracking policies. [Add Client]"*
---
## Permissions & Roles
### Role Indicator
- **Visible?**: [always visible in nav / only in settings / not shown]
- **Placement**: near user avatar / in sidebar footer
- **Example**: *"Jane · Admin"*
### Denied Access
- **Page-level**: redirect to dashboard with toast *"You don't have access to that page"*
- **Action-level**: button hidden (not disabled with tooltip)
- **Data-level**: records silently filtered out of lists
### Role-Specific UX
- **Admins see**: [what's added]
- **Viewers see**: [what's removed]
- **Clients see**: [totally different nav? same nav with subset?]
---
## Copy & Microcopy
High-signal examples extracted verbatim. Full corpus in [copy-corpus.md](./copy-corpus.md).
### Button labels
- `Start chat` (not "New conversation" or "Create")
- `Upgrade plan` (not "Upgrade")
- `Delete forever` (used for hard-delete vs soft-delete "Archive")
- `Try again` (error recovery, not "Retry")
### Error messages
- *"We couldn't save that change. Try again, or contact support if it keeps happening."* — apologetic, actionable
- *"That email's already in use. Sign in instead?"* — redirect option
- *"This link expired. Ask the sender for a new one."* — blame-free
### Empty states
- *"You're all caught up. Check back later or create a new [thing]."*
- *"No results for '[query]'. Try a different search or browse all [things]."*
### Confirmation dialogs
- *"Delete project 'Launch Q2'? 14 tasks and 3 members will lose access. This cannot be undone."*
### Tone notes
- [first-person plural "we" used throughout / second-person "you" / neutral]
- [apostrophes used / not used]
- [emoji used / not used / only in celebratory moments]
- [exclamation marks rare / common / only in errors]
---
## Keyboard
### Shortcut Sheet
- **Access**: `?` or `Cmd+/` opens a modal listing all shortcuts
- **Organisation**: grouped by context (Global, Navigation, Editing)
- **Screenshot**: `screenshots/700-shortcut-sheet.png`
### Global Shortcuts
- `Cmd+K` — command palette
- `G then C` — go to Clients
- `G then P` — go to Projects
- `/` — focus search
- `Esc` — close modal / clear search
### Command Palette (`Cmd+K`)
- **Style**: centred modal, single input with live results
- **Categories**: Pages, Actions, Recent
- **Fuzzy match**: Y
- **Keyboard**: arrows navigate, Enter selects, Tab dismisses
- **Screenshots**: `screenshots/710-palette-open.png`, `screenshots/711-palette-search.png`
### Focus Indicators
- **Style**: 2px solid accent ring, offset 2px from element
- **Visibility**: high contrast in both light and dark mode
- **Tab order**: top-to-bottom, left-to-right, matches visual grouping
---
## Motion
### Page Transitions
- **Style**: fade-through, 150ms
- **Exception**: auth flows use slide left/right
### Modal Enter / Exit
- **Enter**: backdrop fade 150ms, modal fade + scale-up (98→100%) 200ms
- **Exit**: reverse
- **GIF**: `screenshots/800-modal-open.gif`
### List Item Enter / Exit
- **New item**: fade + slight slide-down, 200ms
- **Removed item**: fade + slide-up, 150ms
### Loading → Loaded
- **Skeleton replacement**: crossfade 100ms
- **No layout shift** on content arrival
### Success Moments
- *"Task complete" checkmark draws in 400ms*
- *Confetti on plan upgrade*
- *GIF: `screenshots/810-success.gif`*
---
## Responsive
### Breakpoints Observed
- **1440px**: baseline desktop
- **1280px**: standard desktop (same layout)
- **1024px**: sidebar collapses to icon-only, main content widens
- **768px**: sidebar becomes hamburger drawer, content stacks
- **375px**: mobile, bottom-tab nav replaces sidebar entirely
### Mobile-Specific Patterns
- **Bottom tab nav** with 5 icons on 375px
- **Floating action button** replaces in-page CTAs on list views
- **Full-screen modals** instead of centred modals
- **Bottom sheet** for action menus instead of dropdown
- **Screenshots**: `screenshots/900-mobile-nav.png`, `screenshots/901-mobile-fab.png`, `screenshots/902-bottom-sheet.png`
### Touch Targets
- Minimum 44×44px observed
- Primary CTAs 56px tall on mobile
---
## Notable Absences
Patterns that *aren't* present, worth documenting:
- **No undo** on destructive actions — only confirmation, no time-window restore
- **No bulk edit** — can select multiple but only delete in bulk, not update
- **No keyboard shortcut** for new-record creation on any list page
- **No offline mode** — blank screen if network fails
- **No activity feed** on dashboard — can't tell what changed since last visit
---
## Re-extraction
This library is a snapshot of [Date]. The app will change. Re-extract every 6–12 months for apps we reference often, sooner if a major redesign ships. Check `archive.org/wayback` for historical comparisons.Guidelines for writing the library
- Every claim needs a screenshot. If you can't point to a screenshot, you don't actually know.
- Copy is verbatim. Code blocks or blockquotes for exact text. Paraphrasing loses the voice.
- Notable Absences is as important as presence. What an app doesn't do is a design decision.
- Cross-reference freely. "See also Modal Chrome" prevents repetition.
- Timestamp everything. Apps change. A library without a date decays into misinformation.
- Write opinions into an audit, not an extract. Extracts describe what exists.