Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
One-time setup that gathers your project's design context and saves it to CLAUDE.md for future sessions.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/detector/registry/antipatterns.mjs
1const ANTIPATTERNS = [2// ── AI slop: tells that something was AI-generated ──3{4id: 'side-tab',5category: 'slop',6name: 'Side-tab accent border',7description:8'Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.',9skillSection: 'Visual Details',10skillGuideline: 'colored accent stripe',11},12{13id: 'border-accent-on-rounded',14category: 'slop',15name: 'Border accent on rounded element',16description:17'Thick accent border on a rounded card — the border clashes with the rounded corners. Remove the border or the border-radius.',18skillSection: 'Visual Details',19skillGuideline: 'colored accent stripe',20},21{22id: 'overused-font',23category: 'slop',24name: 'Overused font',25description:26'Inter, Roboto, Fraunces, Geist, Plus Jakarta Sans, and Space Grotesk are used on so many sites they no longer feel distinctive. Each new wave of AI-generated UIs converges on the same handful of faces. Choose a face that gives your interface personality.',27skillSection: 'Typography',28skillGuideline: 'overused fonts like Inter',29},30{31id: 'single-font',32category: 'slop',33name: 'Single font for everything',34description:35'Only one font family is used for the entire page. Pair a distinctive display font with a refined body font to create typographic hierarchy.',36skillSection: 'Typography',37skillGuideline: 'only one font family for the entire page',38},39{40id: 'flat-type-hierarchy',41category: 'slop',42name: 'Flat type hierarchy',43description:44'Font sizes are too close together — no clear visual hierarchy. Use fewer sizes with more contrast (aim for at least a 1.25 ratio between steps).',45skillSection: 'Typography',46skillGuideline: 'flat type hierarchy',47},48{49id: 'gradient-text',50category: 'slop',51name: 'Gradient text',52description:53'Gradient text is decorative rather than meaningful — a common AI tell, especially on headings and metrics. Use solid colors for text.',54skillSection: 'Color & Contrast',55skillGuideline: 'gradient text for',56},57{58id: 'ai-color-palette',59category: 'slop',60name: 'AI color palette',61description:62'Purple/violet gradients and cyan-on-dark are the most recognizable tells of AI-generated UIs. Choose a distinctive, intentional palette.',63skillSection: 'Color & Contrast',64skillGuideline: 'AI color palette',65},66{67id: 'cream-palette',68category: 'slop',69name: 'Cream / beige palette',70description:71'A warm cream or beige page background has become the default "tasteful" AI surface, reached for by reflex. Choose a background that comes from a deliberate palette, not the safe warm off-white.',72skillSection: 'Color & Contrast',73skillGuideline: 'cream and beige as the default surface',74},75{76id: 'nested-cards',77category: 'slop',78name: 'Nested cards',79description:80'Cards inside cards create visual noise and excessive depth. Flatten the hierarchy — use spacing, typography, and dividers instead of nesting containers.',81skillSection: 'Layout & Space',82skillGuideline: 'Nest cards inside cards',83},84{85id: 'monotonous-spacing',86category: 'slop',87name: 'Monotonous spacing',88description:89'The same spacing value used everywhere — no rhythm, no variation. Use tight groupings for related items and generous separations between sections.',90skillSection: 'Layout & Space',91skillGuideline: 'same spacing everywhere',92},93{94id: 'bounce-easing',95category: 'slop',96name: 'Bounce or elastic easing',97description:98'Bounce and elastic easing feel dated and tacky. Real objects decelerate smoothly — use exponential easing (ease-out-quart/quint/expo) instead.',99skillSection: 'Motion',100skillGuideline: 'bounce or elastic easing',101},102{103id: 'dark-glow',104category: 'slop',105name: 'Dark mode with glowing accents',106description:107'Dark backgrounds with colored box-shadow glows are the default "cool" look of AI-generated UIs. Use subtle, purposeful lighting instead — or skip the dark theme entirely.',108skillSection: 'Color & Contrast',109skillGuideline: 'dark mode with glowing accents',110},111{112id: 'icon-tile-stack',113category: 'slop',114name: 'Icon tile stacked above heading',115description:116'A small rounded-square icon container above a heading is the universal AI feature-card template — every generator outputs this exact shape. Try a side-by-side icon and heading, or let the icon sit in flow without its own container.',117skillSection: 'Typography',118skillGuideline: 'large icons with rounded corners above every heading',119},120{121id: 'italic-serif-display',122category: 'slop',123name: 'Italic serif display headline',124description:125'Oversized italic serif (Fraunces, Recoleta, Playfair, Newsreader-italic) as the primary hero headline reads as taste in isolation but has become the universal AI-startup landing page hero. Set roman, or move to a non-serif display face. Editorial / magazine register may legitimately want this — judge by context.',126skillSection: 'Typography',127skillGuideline: 'oversized italic serif as the hero headline',128},129{130id: 'hero-eyebrow-chip',131category: 'slop',132name: 'Hero eyebrow / pill chip',133description:134'A tiny uppercase letter-spaced label sitting immediately above an oversized hero headline — or the same shape rendered as a pill chip — is now the default AI SaaS hero. Drop the eyebrow, integrate the kicker into the headline, or run it as a navigation breadcrumb instead.',135skillSection: 'Typography',136skillGuideline: 'tiny uppercase tracked label above the hero headline',137},138{139id: 'repeated-section-kickers',140category: 'slop',141severity: 'advisory',142name: 'Repeated section kicker labels',143description:144'Repeating tiny uppercase tracked labels above section headings turns a brand page into AI editorial scaffolding. Replace them with stronger structure, artifacts, imagery, or a deliberate brand system.',145skillSection: 'Typography',146skillGuideline: 'repeated eyebrow or kicker labels as section scaffolding',147},148{149id: 'numbered-section-markers',150category: 'slop',151severity: 'advisory',152name: 'Numbered section markers (01 / 02 / 03)',153description:154'Numbered display markers as section labels (01, 02, 03) are the AI editorial scaffold one tier deeper than tracked eyebrow chips. If you find yourself reaching for them, choose a different section cadence.',155skillSection: 'Layout & Space',156skillGuideline: 'numbered section markers',157},158{159id: 'em-dash-overuse',160category: 'slop',161name: 'Em-dash overuse',162description:163'More than two em-dashes (— or --) in body copy is an AI cadence tell. Use commas, colons, periods, or parentheses instead.',164skillSection: 'Copy',165skillGuideline: 'no em dashes',166},167{168id: 'marketing-buzzword',169category: 'slop',170name: 'Marketing buzzword',171description:172'Generic SaaS phrases (streamline / empower / supercharge / world-class / enterprise-grade / next-generation / cutting-edge / etc) are instant AI tells. Pick a specific verb and noun that says what the product literally does.',173skillSection: 'Copy',174skillGuideline: 'marketing buzzwords',175},176{177id: 'aphoristic-cadence',178category: 'slop',179name: 'Aphoristic-cadence copy',180description:181'Three or more sections landing on a short rebuttal sentence ("X. No Y." / "X. Just Y.") or a manufactured-contrast aphorism ("Not a feature. A platform.") reads as AI cadence, not voice. Once is fine; the pattern is the tell.',182skillSection: 'Copy',183skillGuideline: 'aphoristic cadence',184},185{186id: 'oversized-h1',187category: 'slop',188name: 'Oversized hero headline',189description:190'A full-sentence headline set at display size ends up dominating the viewport, leaving no room for anything else above the fold. A punchy one- or two-word headline at that size is fine — the problem is a long headline blown up too large. Set long headlines smaller, or tighten the copy.',191skillSection: 'Typography',192skillGuideline: 'long headline set at display size',193},194{195id: 'extreme-negative-tracking',196category: 'slop',197name: 'Crushed letter spacing',198description:199'Letter-spacing pulled tighter than the point where characters keep their own shapes costs legibility. Tighten display type optically, not destructively.',200skillSection: 'Typography',201skillGuideline: 'letter spacing crushed past legibility',202},203{204id: 'broken-image',205category: 'quality',206name: 'Broken or placeholder image',207description:208'<img> tags with empty src, missing src, or placeholder values ship as broken-image boxes. Use real images, generated assets, or remove the tag.',209skillSection: 'Imagery',210skillGuideline: 'broken image references',211},212213// ── Quality: general design and accessibility issues ──214{215id: 'gray-on-color',216category: 'quality',217name: 'Gray text on colored background',218description:219'Gray text looks washed out on colored backgrounds. Use a darker shade of the background color instead, or white/near-white for contrast.',220skillSection: 'Color & Contrast',221skillGuideline: 'gray text on colored backgrounds',222},223{224id: 'low-contrast',225category: 'quality',226name: 'Low contrast text',227description:228'Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.',229},230{231id: 'layout-transition',232category: 'quality',233name: 'Layout property animation',234description:235'Animating width, height, padding, or margin causes layout thrash and janky performance. Use transform and opacity instead, or grid-template-rows for height animations.',236skillSection: 'Motion',237skillGuideline: 'Animate layout properties',238},239{240id: 'line-length',241category: 'quality',242name: 'Line length too long',243description:244'Text lines wider than ~80 characters are hard to read. The eye loses its place tracking back to the start of the next line. Add a max-width (65ch to 75ch) to text containers.',245skillSection: 'Layout & Space',246skillGuideline: 'wrap beyond ~80 characters',247},248{249id: 'cramped-padding',250category: 'quality',251name: 'Cramped padding',252description:253'Text is too close to the edge of its container. Two shapes: (1) an element with its own text where the padding is too low for the font size, and (2) a wrapper with text-bearing children and near-zero padding against a visible boundary (border, outline, or non-transparent background) — children land flush against the boundary line. Add at least 8px (ideally 12–16px) of padding inside bordered, outlined, or colored containers.',254skillSection: 'Layout & Space',255skillGuideline: 'inside bordered or colored containers',256},257{258id: 'body-text-viewport-edge',259category: 'quality',260name: 'Body text touching viewport edge',261description:262'Body paragraphs render flush against the left or right viewport edge with no container providing horizontal padding. Wrap content in a container with at least 16px (ideally 24-32px) of horizontal padding, or apply max-width with mx-auto.',263},264{265id: 'tight-leading',266category: 'quality',267name: 'Tight line height',268description:269'Line height below 1.3x the font size makes multi-line text hard to read. Use 1.5 to 1.7 for body text so lines have room to breathe.',270},271{272id: 'skipped-heading',273category: 'quality',274name: 'Skipped heading level',275description:276'Heading levels should not skip (e.g. h1 then h3 with no h2). Screen readers use heading hierarchy for navigation. Skipping levels breaks the document outline.',277},278{279id: 'justified-text',280category: 'quality',281name: 'Justified text',282description:283'Justified text without hyphenation creates uneven word spacing ("rivers of white"). Use text-align: left for body text, or enable hyphens: auto if you must justify.',284},285{286id: 'tiny-text',287category: 'quality',288name: 'Tiny body text',289description:290'Body text below 12px is hard to read, especially on high-DPI screens. Use at least 14px for body content, 16px is ideal.',291},292{293id: 'all-caps-body',294category: 'quality',295name: 'All-caps body text',296description:297'Long passages in uppercase are hard to read. We recognize words by shape (ascenders and descenders), which all-caps removes. Reserve uppercase for short labels and headings.',298skillSection: 'Typography',299skillGuideline: 'long body passages in uppercase',300},301{302id: 'wide-tracking',303category: 'quality',304name: 'Wide letter spacing on body text',305description:306'Letter spacing above 0.05em on body text disrupts natural character groupings and slows reading. Reserve wide tracking for short uppercase labels only.',307},308{309id: 'text-overflow',310category: 'quality',311name: 'Content overflowing its container',312description:313'Content renders wider than its container, spilling out or forcing a horizontal scrollbar. Let text wrap, constrain widths, or give the region a deliberate scroll affordance.',314skillSection: 'Layout & Space',315skillGuideline: 'content wider than its container',316},317{318id: 'clipped-overflow-container',319category: 'quality',320name: 'Positioned child clipped by overflow container',321description:322'A clipping container (overflow hidden or clip) wrapping an absolutely-positioned child cuts off tooltips, menus, and popovers that need to escape. Let the overflow be visible, or move the positioned layer out of the clip.',323skillSection: 'Layout & Space',324skillGuideline: 'overflow container clipping positioned children',325},326{327id: 'design-system-font',328category: 'quality',329name: 'Font outside DESIGN.md',330description:331'A font is used that is not declared in DESIGN.md typography. Use the documented type system or update DESIGN.md if this is an intentional brand addition.',332skillSection: 'Typography',333skillGuideline: 'font family outside the project design system',334},335{336id: 'design-system-color',337category: 'quality',338severity: 'advisory',339name: 'Color outside DESIGN.md',340description:341'A literal color is outside the DESIGN.md palette and sidecar tonal ramps. This may be legitimate, but it should be an intentional design-system addition rather than drift.',342skillSection: 'Color & Contrast',343skillGuideline: 'literal color outside the project design system',344},345{346id: 'design-system-radius',347category: 'quality',348severity: 'advisory',349name: 'Radius outside DESIGN.md',350description:351'A border-radius value is outside the DESIGN.md rounded scale. Use a documented radius token or update the design system if the new shape is intentional.',352skillSection: 'Visual Details',353skillGuideline: 'border radius outside the project design system',354},355356// ── Provider tells: opt-in via --gpt / --gemini (gated off by default) ──357{358id: 'gpt-thin-border-wide-shadow',359category: 'slop',360severity: 'advisory',361gated: 'gpt',362name: 'Hairline border with wide shadow',363description:364'A hairline border paired with a wide, diffuse shadow is a recurring generated-UI signature. Commit to one — a defined edge or a soft elevation — rather than both at once.',365skillSection: 'Visual Details',366skillGuideline: 'hairline border plus wide diffuse shadow',367},368{369id: 'repeating-stripes-gradient',370category: 'slop',371severity: 'advisory',372gated: 'gpt',373name: 'Repeating-gradient stripes',374description:375'Repeating-gradient stripes used as surface decoration are a recurring generated-UI signature. Reach for a deliberate texture or leave the surface plain.',376skillSection: 'Visual Details',377skillGuideline: 'repeating-gradient decorative stripes',378},379{380id: 'theater-slop-phrase',381category: 'slop',382severity: 'advisory',383gated: 'gpt',384name: 'Theater framing copy',385description:386'Dismissing something as "theater" is a recurring generated-copy tic. Say plainly what the thing does or does not do.',387skillSection: 'Copy',388skillGuideline: 'theater framing copy',389},390{391id: 'image-hover-transform',392category: 'slop',393severity: 'advisory',394gated: 'gemini',395name: 'Image hover transform',396description:397'Scaling or rotating an image on hover is a recurring generated-UI signature. Let imagery sit still, or use a subtler, purposeful interaction.',398skillSection: 'Motion',399skillGuideline: 'image scale or rotate on hover',400},401];402403const RULE_ENGINE_SUPPORT = {404regex: new Set(['source', 'page-analyzer']),405'static-html': new Set(['element', 'page']),406browser: new Set(['element', 'page', 'layout']),407visual: new Set(['visual-contrast']),408};409410function getAntipattern(id) {411return ANTIPATTERNS.find(rule => rule.id === id);412}413414function getRulesForCategory(category) {415return ANTIPATTERNS.filter(rule => rule.category === category);416}417418function getRuleEngineSupport(engine) {419return RULE_ENGINE_SUPPORT[engine] || new Set();420}421422// Set of provider tags that gate rules off by default (e.g. 'gpt', 'gemini').423const GATED_PROVIDERS = new Set(424ANTIPATTERNS.map(rule => rule.gated).filter(Boolean),425);426427// Drop findings for rules gated behind a provider tag unless that provider428// was explicitly enabled (CLI --gpt / --gemini). Non-gated findings always429// pass through. `findings` carry the rule id on `.antipattern`.430function filterByProviders(findings, providers = []) {431const enabled = new Set(providers || []);432if (!GATED_PROVIDERS.size) return findings;433return findings.filter(f => {434const rule = getAntipattern(f.antipattern);435if (!rule || !rule.gated) return true;436return enabled.has(rule.gated);437});438}439440export {441ANTIPATTERNS,442RULE_ENGINE_SUPPORT,443GATED_PROVIDERS,444getAntipattern,445getRulesForCategory,446getRuleEngineSupport,447filterByProviders,448};449