PROOFPUNK krzemienski/proofpunk ⑂ main 18 skills 6+6 commands 13 doctrine refs 20 themes
DOCTRINE / DEFECT-PATTERN-DATABASE

UI Defect Pattern Database

Common defects across iOS, web, and cross-platform with root causes and fix patterns. Organized by audit phase: triage (Phase 0), visual (Phase 1), interactive (Phase 2), content (Phase 3), and UX heuristic (Phase 4).

Phase 0 — Triage Defects (CRITICAL by default)

Defect Visual Symptom Root Cause Fix
Missing chart content Chart container present but bars / lines / points absent Data not loaded, render bug, CSS height percent without parent height Verify data flow, fix render logic
Broken <img> Alt text or browser-default broken-image icon Bad URL, CORS failure, missing asset Fix path, add error fallback
Lorem ipsum visible "Lorem ipsum dolor sit amet" or "[TODO]" rendered Placeholder copy not replaced before ship Replace with real copy
Hardcoded test data "John Doe", "test@test.com", "555-555-5555" in production-looking UI Test fixtures leaked to production build Replace with real / dynamic data
Raw error in UI Stack trace, "TypeError: undefined", "500 Internal Server Error" Unhandled exception surfaced to user Add error boundary + user-friendly message
undefined / null / NaN text Literal "undefined" rendered as content Missing fallback in template (${user.name ?? 'Guest'}) Add nullish-coalesce or default
Blank where content should be Empty bordered container, list with no rows or empty state Missing empty-state UI, data fetch failure Add explicit empty state with message
Unstyled content flash captured Default browser button styling, default font on custom design FOUC — CSS not loaded before screenshot Capture after networkidle / load fonts before render
Console errors / warnings in-page DevTools error count visible, in-page warning banners from dev tooling Dev mode left enabled in evidence Re-capture in production-like build

Phase 1 — Visual Defects

iOS / SwiftUI

Defect Visual Symptom Root Cause Fix
VStack overflow Content clipped at bottom, no scroll VStack in constrained height without ScrollView Wrap in ScrollView(.vertical)
Fixed frame too small Content overlapping card boundaries .frame(height: N) too small for dynamic content .frame(minHeight: N) + .clipped()
Environment crash Blank screen or crash on navigation @Observable not injected on sibling NavigationDestination .environment() on ALL destination branches
LazyVGrid misalign Grid items offset from each other Missing .alignment on GridItem Set explicit alignment on GridItem
GeometryReader zero Blank view on first render GeometryReader reports 0,0 before layout pass Default size fallback
Sheet wrong color scheme Sheet content in light mode when app is dark Missing .preferredColorScheme(.dark) on sheet Add color scheme to sheet content
@AppStorage stale Feature flags don't update after reinstall UserDefaults cached from previous install simctl uninstall before install
Safe area violation Text under status bar or home indicator Content outside safeAreaInset Respect safe area insets
Tab bar occlusion Last list item hidden behind tab bar Missing content inset on ScrollView Add .safeAreaInset(edge: .bottom) or proper padding
Nav bar overlap Custom nav overlapping status bar Incorrect navigation bar height Use system NavigationStack / navigationTitle
Sidebar clipping Nav items below fold invisible (no scroll) Plain VStack with 20+ items, no ScrollView Wrap sidebar nav in ScrollView(.vertical)
Badge overflow Badge "17" clips outside icon bounds Badge not constrained to parent .clipShape() or constrain badge frame
Shimmer flash White flash before shimmer gradient starts No initial fill color on shimmer layer Set .fill(theme.glassBackground) as base
Text size violation Hardcoded size: 10 or size: 12 Not using Dynamic Type / theme tokens Use .font(.system(...)) or theme font tokens
Monospaced digit shift Numbers shift layout when values change Proportional digit widths .monospacedDigit() on counters/badges

Web / CSS

Defect Visual Symptom Root Cause Fix
Horizontal scroll Scrollbar at narrow viewports Element exceeds viewport width max-width: 100%, overflow-x: hidden on container
Text overflow Long words break layout No word-break strategy overflow-wrap: break-word or word-break: break-word
Invisible focus ring No visible focus indicator on tab outline: none with no replacement outline: 2px solid with 3:1 contrast
Placeholder contrast fail Light gray placeholder text Placeholder not meeting 4.5:1 ratio Darken placeholder color or use floating label
CLS layout shift Elements jump during page load Images without dimensions, late-loading fonts aspect-ratio or width/height on images
FOIT text flash Text invisible then suddenly appears Web font blocking render font-display: swap or preload critical fonts
Stacking context break Modal behind content, z-index war Unmanaged z-index values Establish z-index scale, use CSS layers
Touch target too small Tiny icon buttons (16x16) No padding expansion padding to expand clickable area to 44x44
Dark mode border invisible Borders vanish in dark mode Hardcoded border-gray-200 Semantic tokens: border-gray-200 light / border-gray-700 dark
Glass card invisible (light) Card background transparent in light mode bg-white/10 opacity too low bg-white/80 or higher for light mode
Muted text too light Secondary text unreadable gray-400 on white background slate-600 (#475569) minimum for muted text
Sticky covers content Fixed/sticky header hides scrolled content No scroll-margin or padding offset scroll-margin-top matching header height
Form label missing Input has no visible label Placeholder-only pattern Add visible <label> with for attribute
Skip link absent No keyboard shortcut to skip nav Missing skip-to-content link Add as first focusable element

Cross-Platform / General

Defect Visual Symptom Root Cause Fix
Color-only status Status conveyed only by color No icon or text supplement Add icon + text alongside color indicator
Empty state blank White/blank space where content should be No empty state handler Add meaningful empty state message + icon
Loading frozen UI appears frozen during data fetch No loading indicator Show skeleton/shimmer/spinner during load
Truncation without ellipsis Text cut off abruptly overflow: hidden without text-overflow: ellipsis Add text-overflow: ellipsis + white-space: nowrap
Double spacing Extra vertical gap between sections Two margins stacking (CSS) or double padding (SwiftUI) Collapse margins or audit spacing modifiers
Icon-text misalign Icon vertically offset from adjacent text Different alignment defaults Explicit vertical centering (.alignmentGuide / align-items: center)
Modal viewport overflow Dialog taller than screen Fixed height modal on small viewport max-height: 90vh + scroll internal content
Error state swallowed No error feedback to user catch block with no UI update Show inline error message near the failure point
Badge zero shown "0" badge displayed when it shouldn't be No zero-check before rendering badge if count > 0 { Badge(count) }
White flash on transition Brief white screen between views Background color not set on destination view Set background color on all views in navigation stack
Shared-token cascade Fixing one element's color/spacing breaks another semantically-different element One design token reused across multiple selectors with different visual roles (e.g. --color-muted for caption AND badge text) Audit token reuse: grep "var(--color-X)" to find all consumers; if consumers belong to different visual roles, split into separate tokens BEFORE changing the value. iter-16 findings F-1B-cascade and F-2D-latent are canonical — fixing dark-mode caption contrast unmasked badge contrast because both used --color-text-muted.

Phase 2 — Interactive Element Defects

Defect Visual Symptom Root Cause Fix
False affordance — colored text Bold colored inline text that isn't a link Color-only emphasis with no anchor Either make it a real link or remove the link-like styling
False affordance — card Card-styled element that doesn't respond to tap Card visual treatment with no onTapGesture / onClick Wire up handler, or remove card chrome
False affordance — disabled-looking Button that looks disabled but is enabled Insufficient contrast for active state Increase active-state saturation / contrast
Hidden affordance — swipe-only Feature exists, no signifier Swipe gesture without icon, hint, or onboarding Add visual cue (drag handle, animation, first-use tooltip)
Hidden affordance — long-press Long-press menu with no signal iOS context menu with no button alternative Provide both gesture and visible button
Hidden affordance — hover menu Submenu only on hover CSS :hover with no touch fallback Add tap-to-toggle for touch devices
Sub-minimum target Icon button too small to tap reliably 16×16 icon with no padding Expand to 44×44pt iOS / 24×24px WCAG via padding
Target overlap Mis-tap between adjacent buttons < 8 pt gap between targets Add gap, or merge / restructure
Focus trap Tab key cycles forever inside modal Missing focus-trap exit logic Wire Esc + boundary cycling
Invisible focus No outline on Tab outline: none with no replacement 2 px outline with 3:1 contrast
Wrong tab order Tab jumps unexpectedly Positive tabindex values (tabindex="3") Remove positive tabindex; use DOM order
Occluded target Bottom row hidden behind sticky / tab bar No content inset Add safeAreaInset(.bottom) (iOS) or padding-bottom (web)
Disabled button no cursor Disabled button looks identical to enabled Missing cursor: not-allowed + opacity Add disabled styling + ARIA aria-disabled
Form field no label Input has placeholder but no label Placeholder-only pattern Add visible <label> with for attr
Missing accessibility name Icon button has no screen-reader label Missing aria-label / accessibilityLabel Add descriptive label

Phase 3 — Content Quality Defects

Defect Visual Symptom Root Cause Fix
Code block low contrast Comment color vs code bg below 4.5:1 Default theme syntax-highlight palette Use accessible theme (e.g. GitHub Dark Default, Solarized) and verify each token
Code block silent truncation Long line clipped at right edge, no scroll overflow: hidden without overflow-x: auto Enable horizontal scroll with visible scrollbar, or wrap with white-space: pre-wrap
Code in proportional font Code looks like prose Missing <code>/<pre> or CSS not loaded Apply font-family: ui-monospace, SF Mono, Menlo, Consolas
No copy affordance User must select code by hand No copy button Add hover-revealed copy button (desktop) or always-visible (mobile)
Code/output indistinguishable User can't tell what to type vs what's printed Same styling for both Different bg or label ("Output:" header)
Line numbers selectable Copy includes line numbers Line numbers in same <pre> Use CSS counters or user-select: none on numbers
Diagram color-only Lines distinguished only by red/green No patterns / shapes / direct labels Add dashed/dotted line styles, shapes, or direct labels
Diagram no alt SVG with no <title> / <desc> Plain <svg> export Add <title> + <desc>, or descriptive caption below
Hover-only chart info Tooltip required to read values All values in tooltip only Show key values inline (axis labels, direct callouts), or pair with data table
Chart not keyboard-reachable Mouse-only data exploration No tabindex, no key handlers Add tabindex="0" to data points + arrow-key navigation
Table no header semantics Screen reader can't navigate All <td>, no <th> with scope Use <th scope="col"> / <th scope="row">
Tabular numerals misaligned Digits shift between rows Proportional digit widths font-variant-numeric: tabular-nums (web) / .monospacedDigit() (SwiftUI)
Mobile table overflow Table extends past viewport Fixed-width table Wrap in scroll container OR collapse to cards on narrow viewport
Body text too small < 16 px on mobile Hardcoded 12–14 px Use 16 px (1 rem) min on mobile
Line length too long Body text spans full 1440 px viewport No max-width on prose container max-width: 65ch on body container
Muted text contrast fail "Secondary" text below 4.5:1 text-gray-400 (#9CA3AF) on white Use slate-600 (#475569) minimum for muted
Heading skip h1 → h3 with no h2 Designer-driven hierarchy ignoring DOM levels Use semantic h2 (style separately if visual differs)
Placeholder-only label Form field label vanishes on focus placeholder used as label Add <label> with for=; placeholder for examples only

Phase 4 — UX Heuristic Violations

Heuristic Violation symptom Common cause Fix
1 (Visibility of system status) Submit button no loading state Missing async-state UI Spinner on tap, disable button while pending
1 (Visibility) Sidebar nav item not highlighted on current page No active-route style Style active route with bg + accent border
2 (Match real world) Error: "401 Unauthorized" shown to user Raw HTTP response surfaced Translate to "Please sign in to continue"
2 (Match real world) Date in MM/DD when locale is DD/MM Hardcoded format Use locale-aware date formatter
3 (User control & freedom) Multi-step form loses data on Back No state persistence between steps Persist to local state or session storage
3 (User control & freedom) Modal with no close, no Esc handler Missing dismiss controls Add × button + Esc key handler
4 (Consistency & standards) "Save" / "Update" / "Apply" for same op Different teams owning different screens Pick one verb in design system, enforce
4 (Consistency & standards) iOS bottom-sheet on one screen, modal on another Different presentation patterns Standardize per use-case in design system
5 (Error prevention) Delete button next to Save, same style No visual differentiation of destructive actions Destructive = red / outlined / requires confirm
5 (Error prevention) Free-text date entry No constraint on format Use date picker
6 (Recognition over recall) Active filter not visible after applied No filter chip / pill Add chip showing filter, × to clear
6 (Recognition over recall) "Format: YYYY-MM-DD" only in help text Format hidden Show inline placeholder example
7 (Flexibility & efficiency) No keyboard shortcuts in daily-use tool Power-user features absent Add shortcuts + visible hint (e.g. ⌘K)
8 (Aesthetic & minimalist) Five primary buttons on one screen No clear primary action Promote one to primary, others secondary/tertiary
9 (Recognize / diagnose / recover) "An error occurred" with no detail Generic catch-all error message State problem + cause + recovery in plain text
9 (Recognize / diagnose / recover) Toast vanishes in 3s, error unread Auto-dismiss too short Persistent inline error at field
10 (Help & documentation) Icon-only button with no tooltip Missing tooltip / aria-label Add tooltip + aria-label
Affordance — false Bold colored text isn't a link Decorative styling using link conventions Either make link or remove conventions
Affordance — hidden Swipe-to-archive with no signifier Gesture-only feature Add visual cue or onboarding hint

source → plugins/proofpunk/references/defect-pattern-database.md · ← all docs

REF:DEFECT-PATTERN-DATABASEv2.2.0 · ⑂ main · 18 skills · 6+6 commands · 13 refs · generated 2026-09-04