mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-16 16:16:32 +03:00
1057 lines
82 KiB
Plaintext
1057 lines
82 KiB
Plaintext
---
|
|
import Base from '../../layouts/Base.astro';
|
|
import '../../styles/sub-pages.css';
|
|
import '../../styles/slop-kinpaku.css';
|
|
---
|
|
|
|
<Base
|
|
title="Slop | Impeccable"
|
|
description="46 patterns that mark an interface as AI-generated, plus the live detection overlay that catches them in place. The rule catalog behind npx impeccable detect, the browser extension, and /impeccable critique."
|
|
activeNav="slop"
|
|
canonicalPath="/slop"
|
|
bodyClass="sub-page skills-layout-page slop-page slop-kinpaku kinpaku-chrome"
|
|
>
|
|
|
|
<div class="skills-layout">
|
|
|
|
<aside class="skills-sidebar slop-sidebar" aria-label="Slop page sections">
|
|
<button class="skills-sidebar-toggle" type="button" aria-expanded="false" aria-controls="slop-sidebar-inner">
|
|
<span class="skills-sidebar-toggle-label">On this page</span>
|
|
<svg class="skills-sidebar-toggle-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
|
|
</button>
|
|
<div class="skills-sidebar-inner" id="slop-sidebar-inner">
|
|
<p class="skills-sidebar-label">On this page</p>
|
|
<div class="skills-sidebar-group">
|
|
<ul class="skills-sidebar-list anti-patterns-sidebar-list">
|
|
<li><a href="#see-it"><span>See it</span></a></li>
|
|
<li><a href="#try-it-live"><span>Try it live</span><span class="anti-patterns-sidebar-count">11</span></a></li>
|
|
<li>
|
|
<a href="#catalog"><span>The catalog</span><span class="anti-patterns-sidebar-count">46</span></a>
|
|
<ul class="slop-sidebar-sublist">
|
|
<li><a href="#section-visual-details"><span>Visual Details</span><span class="anti-patterns-sidebar-count">7</span></a></li>
|
|
<li><a href="#section-typography"><span>Typography</span><span class="anti-patterns-sidebar-count">10</span></a></li>
|
|
<li><a href="#section-color-contrast"><span>Color & Contrast</span><span class="anti-patterns-sidebar-count">5</span></a></li>
|
|
<li><a href="#section-layout-space"><span>Layout & Space</span><span class="anti-patterns-sidebar-count">8</span></a></li>
|
|
<li><a href="#section-motion"><span>Motion</span><span class="anti-patterns-sidebar-count">3</span></a></li>
|
|
<li><a href="#section-copy"><span>Copy</span><span class="anti-patterns-sidebar-count">4</span></a></li>
|
|
<li><a href="#section-imagery"><span>Imagery</span><span class="anti-patterns-sidebar-count">1</span></a></li>
|
|
<li><a href="#section-general-quality"><span>General quality</span><span class="anti-patterns-sidebar-count">8</span></a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#run-it"><span>Run it yourself</span></a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
<div class="skills-main">
|
|
|
|
<div class="anti-patterns-content slop-content">
|
|
<header class="anti-patterns-header slop-header">
|
|
<h1 class="sub-page-title">Slop</h1>
|
|
<p class="sub-page-lede">46 patterns that mark an interface as AI-generated, and the detection overlay that catches them in place. Watch it flag them live, try it on 11 synthetic specimens, or browse the full catalog. 41 rules run deterministically (<code>npx impeccable detect</code> or the browser extension), 4 of them opt-in provider tells behind <code>--gpt</code> / <code>--gemini</code>; 5 need <a href="/docs/critique">/impeccable critique</a>'s LLM review pass.</p>
|
|
</header>
|
|
|
|
<section class="slop-section slop-then-now" id="see-it" aria-label="Detection overlay demo">
|
|
<h2 class="slop-section-heading">See it</h2>
|
|
<div class="slop-then-now-intro">
|
|
<p class="slop-then-now-lede">Every wave of AI-generated UIs converges on a recognizable aesthetic. The detector catches both. The patterns just change.</p>
|
|
<div class="slop-era-toggle slop-era-toggle--ink" role="tablist" aria-label="Select slop era">
|
|
<button class="slop-era-tab is-active" role="tab" aria-selected="true" data-era="2022">2022</button>
|
|
<button class="slop-era-tab" role="tab" aria-selected="false" data-era="2026">2026</button>
|
|
</div>
|
|
</div>
|
|
<div class="visual-mode-preview">
|
|
<div class="visual-mode-preview-header">
|
|
<span class="visual-mode-preview-dot red"></span>
|
|
<span class="visual-mode-preview-dot yellow"></span>
|
|
<span class="visual-mode-preview-dot green"></span>
|
|
<span class="visual-mode-preview-title" data-title-2022="Purple gradients, glassmorphism, neon glow" data-title-2026="Fraunces, warm cream, editorial restraint">Purple gradients, glassmorphism, neon glow</span>
|
|
</div>
|
|
<iframe src="/antipattern-examples/old-slop-2022.html" class="visual-mode-frame slop-era-frame" data-era="2022" loading="lazy" title="Impeccable overlay on 2022-era AI slop"></iframe>
|
|
<iframe src="/antipattern-examples/new-slop-2026.html" class="visual-mode-frame slop-era-frame" data-era="2026" loading="lazy" title="Impeccable overlay on 2026-era AI slop" style="display:none"></iframe>
|
|
</div>
|
|
<p class="visual-mode-demo-caption">Hover or tap any outlined element to see which rule fired. Toggle the era to see how the patterns shifted.</p>
|
|
</section>
|
|
|
|
<section class="slop-section visual-mode-gallery" id="try-it-live" aria-label="Try the overlay on synthetic specimens">
|
|
<header class="visual-mode-gallery-header">
|
|
<h2 class="slop-section-heading">Try it live</h2>
|
|
<p class="visual-mode-gallery-lede">These 11 synthetic slop pages ship with the detector script baked in. Click any to see the overlay running on a real page, then hover the outlined elements.</p>
|
|
</header>
|
|
<div class="gallery-grid">
|
|
|
|
<a class="gallery-card" href="/antipattern-examples/purple-gradients.html">
|
|
<div class="gallery-card-thumb">
|
|
<img src="/antipattern-images/purple-gradients.png" alt="Purple Gradients Everywhere specimen" loading="lazy" width="540" height="540">
|
|
</div>
|
|
<div class="gallery-card-body">
|
|
<h3 class="gallery-card-title">Purple Gradients Everywhere</h3>
|
|
<p class="gallery-card-desc">The AI color palette: purple-to-blue gradients on everything. Buttons, text, backgrounds, orbs. The new "make it pop."</p>
|
|
</div>
|
|
</a>
|
|
|
|
<a class="gallery-card" href="/antipattern-examples/lazy-cool.html">
|
|
<div class="gallery-card-thumb">
|
|
<img src="/antipattern-images/lazy-cool.png" alt="Lazy "Cool" specimen" loading="lazy" width="540" height="540">
|
|
</div>
|
|
<div class="gallery-card-body">
|
|
<h3 class="gallery-card-title">Lazy "Cool"</h3>
|
|
<p class="gallery-card-desc">Glassmorphism, neon glows, blurred orbs, monospace everything. Looks like a hackathon project, not a product.</p>
|
|
</div>
|
|
</a>
|
|
|
|
<a class="gallery-card" href="/antipattern-examples/lazy-impact.html">
|
|
<div class="gallery-card-thumb">
|
|
<img src="/antipattern-images/lazy-impact.png" alt="Lazy "Impact" specimen" loading="lazy" width="540" height="540">
|
|
</div>
|
|
<div class="gallery-card-body">
|
|
<h3 class="gallery-card-title">Lazy "Impact"</h3>
|
|
<p class="gallery-card-desc">When in doubt, animate everything. Bouncing buttons, wiggling icons, gradient text, floating badges. Motion without meaning.</p>
|
|
</div>
|
|
</a>
|
|
|
|
<a class="gallery-card" href="/antipattern-examples/thick-border-cards.html">
|
|
<div class="gallery-card-thumb">
|
|
<img src="/antipattern-images/thick-border-cards.png" alt="Side-Tab Cards specimen" loading="lazy" width="540" height="540">
|
|
</div>
|
|
<div class="gallery-card-body">
|
|
<h3 class="gallery-card-title">Side-Tab Cards</h3>
|
|
<p class="gallery-card-desc">A thick colored border on one side of a rounded card. The single most recognizable tell of AI-generated UI.</p>
|
|
</div>
|
|
</a>
|
|
|
|
<a class="gallery-card" href="/antipattern-examples/cardocalypse.html">
|
|
<div class="gallery-card-thumb">
|
|
<img src="/antipattern-images/cardocalypse.png" alt="Cardocalypse specimen" loading="lazy" width="540" height="540">
|
|
</div>
|
|
<div class="gallery-card-body">
|
|
<h3 class="gallery-card-title">Cardocalypse</h3>
|
|
<p class="gallery-card-desc">Cards inside cards inside cards. Five levels of nesting, each with its own padding and shadow.</p>
|
|
</div>
|
|
</a>
|
|
|
|
<a class="gallery-card" href="/antipattern-examples/layout-templates.html">
|
|
<div class="gallery-card-thumb">
|
|
<img src="/antipattern-images/layout-templates.png" alt="Copy-Paste Layouts specimen" loading="lazy" width="540" height="540">
|
|
</div>
|
|
<div class="gallery-card-body">
|
|
<h3 class="gallery-card-title">Copy-Paste Layouts</h3>
|
|
<p class="gallery-card-desc">The same hero-metric-features template repeated with different colors. When every section looks the same, nothing stands out.</p>
|
|
</div>
|
|
</a>
|
|
|
|
<a class="gallery-card" href="/antipattern-examples/inter-everywhere.html">
|
|
<div class="gallery-card-thumb">
|
|
<img src="/antipattern-images/inter-everywhere.png" alt="Inter Everywhere specimen" loading="lazy" width="540" height="540">
|
|
</div>
|
|
<div class="gallery-card-body">
|
|
<h3 class="gallery-card-title">Inter Everywhere</h3>
|
|
<p class="gallery-card-desc">One font for everything. Headings, body, labels, buttons. No typographic hierarchy, no personality, no design.</p>
|
|
</div>
|
|
</a>
|
|
|
|
<a class="gallery-card" href="/antipattern-examples/massive-icons.html">
|
|
<div class="gallery-card-thumb">
|
|
<img src="/antipattern-images/massive-icons.png" alt="Massive Icons specimen" loading="lazy" width="540" height="540">
|
|
</div>
|
|
<div class="gallery-card-body">
|
|
<h3 class="gallery-card-title">Massive Icons</h3>
|
|
<p class="gallery-card-desc">Icon containers larger than the content they introduce. When the decoration is bigger than the message, priorities are backwards.</p>
|
|
</div>
|
|
</a>
|
|
|
|
<a class="gallery-card" href="/antipattern-examples/bad-contrast.html">
|
|
<div class="gallery-card-thumb">
|
|
<img src="/antipattern-images/bad-contrast.png" alt="Bad Contrast Choices specimen" loading="lazy" width="540" height="540">
|
|
</div>
|
|
<div class="gallery-card-body">
|
|
<h3 class="gallery-card-title">Bad Contrast Choices</h3>
|
|
<p class="gallery-card-desc">Gray text on colored backgrounds, low-contrast labels, unreadable combinations. Looking good and being readable should not conflict.</p>
|
|
</div>
|
|
</a>
|
|
|
|
<a class="gallery-card" href="/antipattern-examples/redundant-ux-writing.html">
|
|
<div class="gallery-card-thumb">
|
|
<img src="/antipattern-images/redundant-ux-writing.png" alt="Redundant UX Writing specimen" loading="lazy" width="540" height="540">
|
|
</div>
|
|
<div class="gallery-card-body">
|
|
<h3 class="gallery-card-title">Redundant UX Writing</h3>
|
|
<p class="gallery-card-desc">Label, sublabel, helper text, and hint text all saying the same thing in slightly different words. Say it once, say it well.</p>
|
|
</div>
|
|
</a>
|
|
|
|
<a class="gallery-card" href="/antipattern-examples/modal-abuse.html">
|
|
<div class="gallery-card-thumb">
|
|
<img src="/antipattern-images/modal-abuse.png" alt="Modal Abuse specimen" loading="lazy" width="540" height="540">
|
|
</div>
|
|
<div class="gallery-card-body">
|
|
<h3 class="gallery-card-title">Modal Abuse</h3>
|
|
<p class="gallery-card-desc">Complex settings crammed into a modal. If it needs a scroll bar and three columns, it deserves its own page.</p>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="slop-section slop-catalog" id="catalog" aria-label="Rule catalog">
|
|
<header class="slop-catalog-header">
|
|
<h2 class="slop-section-heading">The catalog</h2>
|
|
<p class="slop-catalog-lede">Every pattern <a href="/docs/impeccable">/impeccable</a> teaches against. <strong>AI slop</strong> rules flag the tells of AI-generated UIs; <strong>Quality</strong> rules flag general design mistakes that hurt regardless of who wrote them.</p>
|
|
</header>
|
|
|
|
<details class="anti-patterns-legend">
|
|
<summary class="anti-patterns-legend-summary">
|
|
<span class="anti-patterns-legend-title">How to read this</span>
|
|
<svg class="anti-patterns-legend-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
|
|
</summary>
|
|
<div class="anti-patterns-legend-body">
|
|
<p>Each rule shows how it is detected:</p>
|
|
<dl class="anti-patterns-legend-layers">
|
|
<div><dt><span class="rule-card-layer" data-layer="cli">CLI</span></dt><dd>Deterministic. Runs from <code>npx impeccable detect</code> on files, no browser required.</dd></div>
|
|
<div><dt><span class="rule-card-layer" data-layer="browser">Browser</span></dt><dd>Deterministic, but needs real browser layout. Runs via the browser extension or Puppeteer, not the plain CLI.</dd></div>
|
|
<div><dt><span class="rule-card-layer" data-layer="llm">LLM only</span></dt><dd>No deterministic detector. Caught by <a href="/docs/critique">/impeccable critique</a> during its LLM design review.</dd></div>
|
|
<div><dt><span class="rule-card-layer" data-layer="optin">opt-in</span></dt><dd>Deterministic, but a provider-specific tell that is off by default. Enable with <code>--gpt</code> or <code>--gemini</code>.</dd></div>
|
|
</dl>
|
|
</div>
|
|
</details>
|
|
|
|
<div class="anti-patterns-sections">
|
|
|
|
<section class="anti-patterns-section" id="section-visual-details">
|
|
<header class="anti-patterns-section-header">
|
|
<h3 class="anti-patterns-section-title">Visual Details</h3>
|
|
<p class="anti-patterns-section-count">7 rules</p>
|
|
</header>
|
|
<div class="rule-card-grid">
|
|
|
|
<article class="rule-card" id="rule-border-accent-on-rounded" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #fff; border: 2px solid oklch(60% 0.22 290); border-radius: 16px; padding: 14px 18px; width: 220px; font-family: system-ui, sans-serif; font-size: 13px; color: #111;"><div style="font-weight: 600;">Rounded card</div><div style="color: #666; font-size: 12px;">Thick colored border clashes with the radius.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Border accent on rounded element</h3>
|
|
<p class="rule-card-desc">Thick accent border on a rounded card. The border clashes with the rounded corners. Remove the border or the border-radius.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#visual-details">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-glassmorphism" data-layer="llm">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="position: relative; width: 100%; height: 100%; background: linear-gradient(135deg, oklch(70% 0.22 265), oklch(70% 0.25 340)); border-radius: 10px; overflow: hidden; display: flex; align-items: center; justify-content: center;"><div style="background: rgba(255,255,255,0.25); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); border: 1px solid rgba(255,255,255,0.4); border-radius: 10px; padding: 14px 18px; color: #fff; font-family: system-ui, sans-serif; font-size: 12px; font-weight: 600; box-shadow: 0 8px 30px rgba(0,0,0,0.12);">Frosted glass card</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Glassmorphism everywhere</h3>
|
|
<p class="rule-card-desc">Blur effects, glass cards, and glow borders used as decoration rather than to solve a real layering problem.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#visual-details">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-side-tab" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #fff; border: 1px solid #e8e4df; border-left: 4px solid oklch(60% 0.22 265); border-radius: 6px; padding: 14px 16px; width: 220px; font-family: system-ui, sans-serif; font-size: 13px; color: #111;"><div style="font-weight: 600; margin-bottom: 4px;">Alert title</div><div style="color: #666; font-size: 12px;">Thick colored stripe on one side.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Side-tab accent border</h3>
|
|
<p class="rule-card-desc">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.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#visual-details">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-gpt-thin-border-wide-shadow" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #fff; border: 1px solid #9aa0a6; border-radius: 10px; padding: 14px 18px; width: 200px; box-shadow: 0 0 30px rgba(0,0,0,0.22); font-family: system-ui, sans-serif;"><div style="font-weight: 600; font-size: 13px; color: #111;">Ghost card</div><div style="font-size: 11px; color: #888;">1px hairline plus a wide soft shadow.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
<span class="rule-card-layer" data-layer="optin" title="Off by default. Enable with --gpt.">opt-in</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Hairline border with wide shadow</h3>
|
|
<p class="rule-card-desc">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, not both at once.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#visual-details">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-repeating-stripes-gradient" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="width: 100%; height: 90px; border-radius: 10px; background: repeating-linear-gradient(45deg, oklch(93% 0.02 80), oklch(93% 0.02 80) 10px, oklch(88% 0.04 80) 10px, oklch(88% 0.04 80) 20px);"></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
<span class="rule-card-layer" data-layer="optin" title="Off by default. Enable with --gpt.">opt-in</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Repeating-gradient stripes</h3>
|
|
<p class="rule-card-desc">Repeating-gradient stripes used as surface decoration are a recurring generated-UI signature. Reach for a deliberate texture, or leave the surface plain.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#visual-details">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-over-round" data-layer="llm">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 44px; padding: 18px 24px; width: 200px; font-family: system-ui, sans-serif;"><div style="font-weight: 600; font-size: 13px; color: #111;">44px radius</div><div style="font-size: 11px; color: #888;">A small card rounded into a blob.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Extreme border-radius on cards</h3>
|
|
<p class="rule-card-desc">Over-rounding cards, sections, and inputs (24px and up on a small card) rounds everything into the same soft blob. Cards top out around 12 to 16px; reserve full-pill for tags and buttons.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#visual-details">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-sketchy-svg" data-layer="llm">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; display: flex; flex-direction: column; align-items: center; gap: 6px;"><svg width="110" height="70" viewBox="0 0 110 70" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round"><path d="M22 56 q6 -34 32 -32 q26 2 30 30"/><circle cx="44" cy="30" r="3" fill="#bbb" stroke="none"/><circle cx="62" cy="29" r="3" fill="#bbb" stroke="none"/><path d="M46 40 q8 6 16 0"/><path d="M30 60 l-6 8 M78 58 l7 9"/></svg><div style="font-size: 10px; color: #888;">A crude hand-coded mascot.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Amateurish hand-drawn SVG</h3>
|
|
<p class="rule-card-desc">Hand-coded SVG illustrations of scenes or mascots read as amateur doodles, not whimsy. If you cannot render it with real assets, ship no illustration rather than a sketchy fallback.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#visual-details">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
<section class="anti-patterns-section" id="section-typography">
|
|
<header class="anti-patterns-section-header">
|
|
<h3 class="anti-patterns-section-title">Typography</h3>
|
|
<p class="anti-patterns-section-count">10 rules</p>
|
|
</header>
|
|
<div class="rule-card-grid">
|
|
|
|
<article class="rule-card" id="rule-flat-type-hierarchy" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111; line-height: 1.3;"><div style="font-size: 17px; font-weight: 600;">Heading</div><div style="font-size: 16px; font-weight: 500; margin: 2px 0;">Subheading</div><div style="font-size: 15px; color: #555;">Body text at almost the same size.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Flat type hierarchy</h3>
|
|
<p class="rule-card-desc">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).</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-icon-tile-stack" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111;"><div style="width: 44px; height: 44px; border-radius: 10px; background: linear-gradient(135deg, oklch(62% 0.22 265), oklch(70% 0.20 320)); display: flex; align-items: center; justify-content: center; font-size: 20px; color: #fff; margin-bottom: 10px;">✦</div><div style="font-size: 14px; font-weight: 600; margin-bottom: 2px;">Feature name</div><div style="font-size: 12px; color: #666;">Rounded icon tile above heading.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Icon tile stacked above heading</h3>
|
|
<p class="rule-card-desc">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.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-italic-serif-display" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: Georgia, 'Times New Roman', serif; font-style: italic; font-size: 32px; font-weight: 500; color: #111; line-height: 1.05;">Beautifully<br>Crafted</div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Italic serif display headline</h3>
|
|
<p class="rule-card-desc">Oversized italic serif as the primary hero headline reads as taste in isolation but has become the universal AI-startup landing page hero. Set it roman, or move to a non-serif display face. Editorial registers may legitimately want it; judge by context.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-hero-eyebrow-chip" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111;"><div style="display: inline-block; font-size: 10px; text-transform: uppercase; letter-spacing: 0.18em; color: oklch(60% 0.18 265); background: oklch(60% 0.18 265 / 0.12); padding: 3px 8px; border-radius: 999px; margin-bottom: 8px;">Introducing</div><div style="font-size: 22px; font-weight: 700;">The hero headline</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Hero eyebrow / pill chip</h3>
|
|
<p class="rule-card-desc">A tiny uppercase letter-spaced label sitting immediately above an oversized hero headline, or the same shape rendered as a pill chip, is the default AI SaaS hero. Drop the eyebrow, fold the kicker into the headline, or run it as a breadcrumb instead.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-repeated-section-kickers" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111; display: flex; flex-direction: column; gap: 10px;"><div><div style="font-size: 9px; text-transform: uppercase; letter-spacing: 0.18em; color: #999;">Features</div><div style="font-size: 14px; font-weight: 600;">What you get</div></div><div><div style="font-size: 9px; text-transform: uppercase; letter-spacing: 0.18em; color: #999;">Pricing</div><div style="font-size: 14px; font-weight: 600;">Simple plans</div></div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Repeated section kicker labels</h3>
|
|
<p class="rule-card-desc">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.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-oversized-h1" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner" style="align-items: stretch;"><div style="font-family: system-ui, sans-serif; font-size: 58px; font-weight: 800; color: #111; line-height: 0.95; letter-spacing: -0.02em; padding: 12px 14px;">Everything your whole team needs to ship faster</div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Oversized hero headline</h3>
|
|
<p class="rule-card-desc">A full-sentence headline set at display size dominates 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.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-extreme-negative-tracking" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; font-size: 34px; font-weight: 700; color: #111; letter-spacing: -0.14em; line-height: 1.1;">Crushed Together</div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Crushed letter spacing</h3>
|
|
<p class="rule-card-desc">Letter spacing pulled tighter than the point where characters keep their own shapes costs legibility. Tighten display type optically, not destructively.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-overused-font" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: Inter, system-ui, sans-serif; font-size: 15px; color: #111; line-height: 1.4;"><div style="font-weight: 600; margin-bottom: 4px;">Just another Inter headline</div><div style="color: #555; font-size: 13px;">Every SaaS homepage looks like this.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Overused font</h3>
|
|
<p class="rule-card-desc">Inter, Geist, Space Grotesk, and the newest reflex, Instrument Serif, 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.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-single-font" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; font-size: 14px; color: #111;"><div style="font-size: 19px; font-weight: 600; margin-bottom: 6px;">Heading in the body font</div><div style="color: #555;">Body in the same font. No contrast. Flat.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Single font for everything</h3>
|
|
<p class="rule-card-desc">Only one font family is used for the entire page. Pair a distinctive display font with a refined body font to create typographic hierarchy.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-all-caps-body" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111; font-size: 12px; text-transform: uppercase; letter-spacing: 0.03em; line-height: 1.5;">Long passages in uppercase are hard to read. We recognize words by their shape, which all-caps removes.</div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">All-caps body text</h3>
|
|
<p class="rule-card-desc">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.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
<section class="anti-patterns-section" id="section-color-contrast">
|
|
<header class="anti-patterns-section-header">
|
|
<h3 class="anti-patterns-section-title">Color & Contrast</h3>
|
|
<p class="anti-patterns-section-count">5 rules</p>
|
|
</header>
|
|
<div class="rule-card-grid">
|
|
|
|
<article class="rule-card" id="rule-ai-color-palette" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="display: flex; gap: 6px;"><div style="width: 44px; height: 44px; border-radius: 6px; background: oklch(60% 0.22 265);"></div><div style="width: 44px; height: 44px; border-radius: 6px; background: oklch(62% 0.25 300);"></div><div style="width: 44px; height: 44px; border-radius: 6px; background: oklch(64% 0.25 340);"></div><div style="width: 44px; height: 44px; border-radius: 6px; background: oklch(70% 0.20 200);"></div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">AI color palette</h3>
|
|
<p class="rule-card-desc">Purple/violet gradients and cyan-on-dark are the most recognizable tells of AI-generated UIs. Choose a distinctive, intentional palette.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#color-contrast">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-dark-glow" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #0a0b14; padding: 18px 20px; border-radius: 10px; font-family: system-ui, sans-serif;"><div style="color: oklch(78% 0.22 280); text-shadow: 0 0 12px oklch(78% 0.22 280 / 0.7); font-size: 16px; font-weight: 600;">Neon on dark</div><div style="color: oklch(60% 0.12 260); font-size: 12px; margin-top: 4px;">Cyberpunk-by-default slop.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Dark mode with glowing accents</h3>
|
|
<p class="rule-card-desc">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.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#color-contrast">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-gradient-text" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif;"><div style="font-size: 28px; font-weight: 700; background: linear-gradient(135deg, oklch(65% 0.25 320), oklch(60% 0.25 265)); -webkit-background-clip: text; background-clip: text; color: transparent; line-height: 1.1;">Build the Future</div><div style="font-size: 12px; color: #888; margin-top: 4px;">Gradient text kills scannability.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Gradient text</h3>
|
|
<p class="rule-card-desc">Gradient text is decorative rather than meaningful. A common AI tell, especially on headings and metrics. Use solid colors for text.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#color-contrast">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-gray-on-color" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: oklch(60% 0.20 265); padding: 18px 24px; border-radius: 8px; width: 240px; font-family: system-ui, sans-serif;"><div style="color: #9ca3af; font-size: 13px; line-height: 1.5;">Gray text on a colored background. Washed out and hard to read.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Gray text on colored background</h3>
|
|
<p class="rule-card-desc">Gray text looks washed out on colored backgrounds. Use a darker shade of the background color instead, or white/near-white for contrast.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#color-contrast">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-cream-palette" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #f5efe2; border-radius: 8px; width: 240px; padding: 18px 22px; font-family: Georgia, serif;"><div style="font-size: 17px; font-weight: 600; color: #2a2622; margin-bottom: 4px;">The tasteful default</div><div style="font-size: 12px; color: #6b6358;">Warm cream surface, reached for by reflex.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Cream / beige palette</h3>
|
|
<p class="rule-card-desc">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.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#color-contrast">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
</div>
|
|
</section>
|
|
<section class="anti-patterns-section" id="section-layout-space">
|
|
<header class="anti-patterns-section-header">
|
|
<h3 class="anti-patterns-section-title">Layout & Space</h3>
|
|
<p class="anti-patterns-section-count">8 rules</p>
|
|
</header>
|
|
<div class="rule-card-grid">
|
|
|
|
<article class="rule-card" id="rule-hero-metric-layout" data-layer="llm">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; text-align: left;"><div style="font-size: 42px; font-weight: 800; background: linear-gradient(135deg, oklch(65% 0.25 265), oklch(65% 0.25 340)); -webkit-background-clip: text; background-clip: text; color: transparent; line-height: 1;">10M+</div><div style="font-size: 10px; color: #888; text-transform: uppercase; letter-spacing: 0.1em; margin-top: 2px;">Active users</div><div style="display: flex; gap: 14px; margin-top: 10px; font-size: 10px; color: #555;"><span><strong>99.9%</strong> uptime</span><span><strong>200ms</strong> p50</span></div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Hero metric layout</h3>
|
|
<p class="rule-card-desc">Big number, small label, three supporting stats, gradient accent. Used everywhere, trusted nowhere.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-identical-card-grids" data-layer="llm">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; font-family: system-ui, sans-serif;"><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;"><div style="width: 18px; height: 18px; background: oklch(62% 0.20 265); border-radius: 4px;"></div><div style="font-size: 10px; font-weight: 600; color: #111;">Feature</div><div style="font-size: 9px; color: #888;">Short copy.</div></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;"><div style="width: 18px; height: 18px; background: oklch(62% 0.20 265); border-radius: 4px;"></div><div style="font-size: 10px; font-weight: 600; color: #111;">Feature</div><div style="font-size: 9px; color: #888;">Short copy.</div></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;"><div style="width: 18px; height: 18px; background: oklch(62% 0.20 265); border-radius: 4px;"></div><div style="font-size: 10px; font-weight: 600; color: #111;">Feature</div><div style="font-size: 9px; color: #888;">Short copy.</div></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;"><div style="width: 18px; height: 18px; background: oklch(62% 0.20 265); border-radius: 4px;"></div><div style="font-size: 10px; font-weight: 600; color: #111;">Feature</div><div style="font-size: 9px; color: #888;">Short copy.</div></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;"><div style="width: 18px; height: 18px; background: oklch(62% 0.20 265); border-radius: 4px;"></div><div style="font-size: 10px; font-weight: 600; color: #111;">Feature</div><div style="font-size: 9px; color: #888;">Short copy.</div></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;"><div style="width: 18px; height: 18px; background: oklch(62% 0.20 265); border-radius: 4px;"></div><div style="font-size: 10px; font-weight: 600; color: #111;">Feature</div><div style="font-size: 9px; color: #888;">Short copy.</div></div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Identical card grids</h3>
|
|
<p class="rule-card-desc">Same-sized cards with icon + heading + text repeated endlessly. The default AI homepage layout.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-monotonous-spacing" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="display: flex; flex-direction: column; gap: 13px; width: 210px;"><div style="height: 14px; background: #2f3338; border-radius: 3px; width: 70%;"></div><div style="height: 14px; background: #cfcabf; border-radius: 3px;"></div><div style="height: 14px; background: #cfcabf; border-radius: 3px;"></div><div style="height: 14px; background: #cfcabf; border-radius: 3px;"></div><div style="height: 14px; background: #cfcabf; border-radius: 3px; width: 85%;"></div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Monotonous spacing</h3>
|
|
<p class="rule-card-desc">The same spacing value used everywhere. No rhythm, no variation. Use tight groupings for related items and generous separations between sections.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-nested-cards" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #f5f3ef; border: 1px solid #e0dcd4; border-radius: 10px; padding: 10px;"><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 8px; padding: 10px;"><div style="background: #f5f3ef; border: 1px solid #e8e4df; border-radius: 6px; padding: 8px; font-size: 12px; font-family: system-ui, sans-serif; color: #555;">Card inside card inside card.</div></div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Nested cards</h3>
|
|
<p class="rule-card-desc">Cards inside cards create visual noise and excessive depth. Flatten the hierarchy: use spacing, typography, and dividers instead of nesting containers.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-numbered-section-markers" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111; display: flex; flex-direction: column; gap: 8px;"><div style="display: flex; align-items: baseline; gap: 8px;"><span style="font-size: 16px; font-weight: 800; color: oklch(60% 0.18 265);">01</span><span style="font-size: 13px; font-weight: 600;">About</span></div><div style="display: flex; align-items: baseline; gap: 8px;"><span style="font-size: 16px; font-weight: 800; color: oklch(60% 0.18 265);">02</span><span style="font-size: 13px; font-weight: 600;">Process</span></div><div style="display: flex; align-items: baseline; gap: 8px;"><span style="font-size: 16px; font-weight: 800; color: oklch(60% 0.18 265);">03</span><span style="font-size: 13px; font-weight: 600;">Pricing</span></div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Numbered section markers (01 / 02 / 03)</h3>
|
|
<p class="rule-card-desc">Numbered display markers as section labels are the AI editorial scaffold one tier deeper than tracked eyebrow chips. Numbers earn their place only when the section actually is a sequence.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-line-length" data-layer="browser">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner" style="align-items: center; justify-content: flex-start;"><div style="font-family: system-ui, sans-serif; font-size: 12px; color: #111; line-height: 1.8; white-space: nowrap; padding-left: 14px;">This one line of running text keeps going<br>well past the comfortable measure of about<br>seventy-five characters before it ever wraps,<br>so the eye loses its place on the way back.</div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="browser" title="Deterministic, but needs real browser layout. Runs via the browser extension or Puppeteer, not the plain CLI.">Browser</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Line length too long</h3>
|
|
<p class="rule-card-desc">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.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-text-overflow" data-layer="browser">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="width: 150px; border: 1px solid #e8e4df; border-radius: 6px; padding: 8px 10px; font-family: system-ui, sans-serif; font-size: 12px; color: #111; white-space: nowrap;">A long line of text that refuses to wrap and spills past its box</div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="browser" title="Deterministic, but needs real browser layout. Runs via the browser extension or Puppeteer, not the plain CLI.">Browser</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Content overflowing its container</h3>
|
|
<p class="rule-card-desc">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.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-clipped-overflow-container" data-layer="browser">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="position: relative; width: 150px; height: 64px; border: 1px solid #e8e4df; border-radius: 6px; overflow: hidden; font-family: system-ui, sans-serif;"><div style="padding: 8px 10px; font-size: 11px; font-weight: 600; color: #111;">Menu</div><div style="position: absolute; top: 38px; left: 10px; width: 150px; background: #1a1a1a; color: #fff; font-size: 10px; padding: 6px 8px; border-radius: 4px;">Dropdown clipped by the box</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="browser" title="Deterministic, but needs real browser layout. Runs via the browser extension or Puppeteer, not the plain CLI.">Browser</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Positioned child clipped by overflow container</h3>
|
|
<p class="rule-card-desc">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.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
<section class="anti-patterns-section" id="section-motion">
|
|
<header class="anti-patterns-section-header">
|
|
<h3 class="anti-patterns-section-title">Motion</h3>
|
|
<p class="anti-patterns-section-count">3 rules</p>
|
|
</header>
|
|
<div class="rule-card-grid">
|
|
|
|
<article class="rule-card" id="rule-bounce-easing" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; display: flex; flex-direction: column; align-items: center; gap: 8px;"><div style="background: #fff; border: 1px solid #d8d4cc; border-radius: 8px; padding: 11px 16px; box-shadow: 0 10px 26px rgba(0,0,0,0.14); font-size: 12px; font-weight: 600; color: #111; animation: elasticpop 1.8s cubic-bezier(0.68, -0.55, 0.27, 1.55) infinite;">Confirm action</div><div style="font-size: 11px; color: #888;">A dialog that springs in with overshoot.</div><style>@keyframes elasticpop { 0% { transform: scale(0.4); opacity: 0; } 45% { transform: scale(1.12); opacity: 1; } 65% { transform: scale(0.96); } 82%,100% { transform: scale(1); opacity: 1; } }</style></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Bounce or elastic easing</h3>
|
|
<p class="rule-card-desc">Bounce and elastic easing on interface elements (a dialog that springs in, a card that overshoots) feels dated and tacky. Reserve spring physics for things that are actually physical; ease interface motion out smoothly (ease-out-quart/quint/expo).</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#motion">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-layout-transition" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111; display: flex; align-items: center; gap: 10px;"><div style="background: oklch(65% 0.22 265); border-radius: 6px; animation: janky 1.2s ease-in-out infinite; width: 60px; height: 30px;"></div><div style="font-size: 12px; color: #555;">Animating width/height causes layout jank.</div><style>@keyframes janky { 0%,100% { width: 60px; } 50% { width: 120px; } }</style></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Layout property animation</h3>
|
|
<p class="rule-card-desc">Animating width, height, padding, or margin causes layout thrash and janky performance. Use transform and opacity instead, or grid-template-rows for height animations.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#motion">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-image-hover-transform" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="display: flex; flex-direction: column; align-items: center; gap: 8px; font-family: system-ui, sans-serif;"><div style="width: 104px; height: 70px; border-radius: 8px; overflow: hidden;"><img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='104'%20height='70'%3E%3Cdefs%3E%3ClinearGradient%20id='g'%20x1='0'%20y1='0'%20x2='1'%20y2='1'%3E%3Cstop%20offset='0'%20stop-color='%23c9a86a'/%3E%3Cstop%20offset='1'%20stop-color='%237a8b6f'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect%20width='104'%20height='70'%20fill='url(%23g)'/%3E%3Ccircle%20cx='80'%20cy='20'%20r='10'%20fill='%23f0e6c8'/%3E%3C/svg%3E" alt="" style="width: 100%; height: 100%; display: block; animation: imgzoom 2.4s ease-in-out infinite;" /></div><div style="font-size: 11px; color: #888;">Image scales up on hover.</div><style>@keyframes imgzoom { 0%,100% { transform: scale(1); } 50% { transform: scale(1.22); } }</style></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
<span class="rule-card-layer" data-layer="optin" title="Off by default. Enable with --gemini.">opt-in</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Image hover transform</h3>
|
|
<p class="rule-card-desc">Scaling or rotating an image on hover is a recurring generated-UI signature. Let imagery sit still, or use a subtler, purposeful interaction.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#motion">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
<section class="anti-patterns-section" id="section-copy">
|
|
<header class="anti-patterns-section-header">
|
|
<h3 class="anti-patterns-section-title">Copy</h3>
|
|
<p class="anti-patterns-section-count">4 rules</p>
|
|
</header>
|
|
<div class="rule-card-grid">
|
|
|
|
<article class="rule-card" id="rule-em-dash-overuse" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: Georgia, serif; font-size: 13px; color: #111; line-height: 1.6; max-width: 230px;">It works <span style="color: oklch(58% 0.15 35);">—</span> really well <span style="color: oklch(58% 0.15 35);">—</span> for teams <span style="color: oklch(58% 0.15 35);">—</span> of any size <span style="color: oklch(58% 0.15 35);">—</span> anywhere.</div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Em-dash overuse</h3>
|
|
<p class="rule-card-desc">More than a couple of em-dashes in body copy is an AI cadence tell. Use commas, colons, periods, or parentheses instead.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#copy">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-marketing-buzzword" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111; line-height: 1.5;"><div style="font-size: 16px; font-weight: 700;">Supercharge your workflow</div><div style="font-size: 11px; color: #888;">World-class, enterprise-grade, next-generation.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Marketing buzzword</h3>
|
|
<p class="rule-card-desc">Generic SaaS phrases (streamline, empower, supercharge, world-class, enterprise-grade) are instant AI tells. Pick a specific verb and noun that says what the product literally does.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#copy">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-aphoristic-cadence" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: Georgia, serif; color: #111; line-height: 1.4;"><div style="font-size: 15px; font-weight: 600;">Not a feature.</div><div style="font-size: 15px; font-weight: 600;">A platform.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Aphoristic-cadence copy</h3>
|
|
<p class="rule-card-desc">Sections landing on a short rebuttal or a manufactured-contrast aphorism read as AI cadence, not voice. Once is fine; the repeated pattern is the tell.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#copy">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-theater-slop-phrase" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111; line-height: 1.5;"><div style="font-size: 15px; font-weight: 700;">We killed the growth <span style="color: oklch(58% 0.15 35);">theater</span>.</div><div style="font-size: 11px; color: #888;">Dismissing things as performative.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="slop">AI slop</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
<span class="rule-card-layer" data-layer="optin" title="Off by default. Enable with --gpt.">opt-in</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Theater framing copy</h3>
|
|
<p class="rule-card-desc">Dismissing something as "theater" is a recurring generated-copy tic. Say plainly what the thing does or does not do.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#copy">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
<section class="anti-patterns-section" id="section-imagery">
|
|
<header class="anti-patterns-section-header">
|
|
<h3 class="anti-patterns-section-title">Imagery</h3>
|
|
<p class="anti-patterns-section-count">1 rule</p>
|
|
</header>
|
|
<div class="rule-card-grid">
|
|
|
|
<article class="rule-card" id="rule-broken-image" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif;"><div style="width: 120px; height: 80px; border: 1px solid #d8d4cc; border-radius: 6px; display: flex; align-items: center; justify-content: center; background: #f5f3ef; color: #b3ada3;"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 16l5-5 4 4 3-3 6 6"/><path d="M3 21L21 3"/></svg></div><div style="font-size: 10px; color: #888; margin-top: 6px;">Empty or missing src ships broken.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Broken or placeholder image</h3>
|
|
<p class="rule-card-desc"><img> tags with empty src, missing src, or placeholder values ship as broken-image boxes. Use real images, generated assets, or remove the tag.</p>
|
|
<a class="rule-card-skill-link" href="/docs/impeccable#imagery">See in /impeccable</a>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
<section class="anti-patterns-section" id="section-general-quality">
|
|
<header class="anti-patterns-section-header">
|
|
<h3 class="anti-patterns-section-title">General quality</h3>
|
|
<p class="anti-patterns-section-count">8 rules</p>
|
|
</header>
|
|
<div class="rule-card-grid">
|
|
|
|
<article class="rule-card" id="rule-cramped-padding" data-layer="browser">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif;"><button style="background: #111; color: #fff; border: none; border-radius: 4px; padding: 2px 6px; font-size: 13px; font-weight: 500;">Buy now</button> <span style="color: #555; font-size: 12px; margin-left: 8px;">2px vertical padding.</span></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="browser" title="Deterministic, but needs real browser layout. Runs via the browser extension or Puppeteer, not the plain CLI.">Browser</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Cramped padding</h3>
|
|
<p class="rule-card-desc">Text is too close to the edge of its container. Add at least 8px (ideally 12-16px) of padding inside bordered or colored containers.</p>
|
|
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-body-text-viewport-edge" data-layer="browser">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="border: 1px dashed #d8d4cc; border-radius: 6px; overflow: hidden;"><div style="font-family: system-ui, sans-serif; font-size: 11px; color: #111; line-height: 1.5;">Body text running flush against the very edge of the viewport with no container padding to hold it in.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="browser" title="Deterministic, but needs real browser layout. Runs via the browser extension or Puppeteer, not the plain CLI.">Browser</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Body text touching viewport edge</h3>
|
|
<p class="rule-card-desc">Body paragraphs render flush against the left or right viewport edge with no container padding. Wrap content in a container with at least 16px of horizontal padding, or apply max-width with mx-auto.</p>
|
|
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-justified-text" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; font-size: 12px; color: #111; text-align: justify; max-width: 230px; line-height: 1.5;">Justified text on screens creates rivers of whitespace because browsers can't hyphenate well. Leave this for print.</div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Justified text</h3>
|
|
<p class="rule-card-desc">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.</p>
|
|
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-low-contrast" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #fff; padding: 16px 18px; font-family: system-ui, sans-serif;"><div style="color: #d4d4d4; font-size: 13px;">Light gray text on a white background. 1.6:1 contrast, fails WCAG.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Low contrast text</h3>
|
|
<p class="rule-card-desc">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.</p>
|
|
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-skipped-heading" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111;"><h1 style="font-size: 20px; font-weight: 700; margin: 0 0 4px;">Page title (h1)</h1><h3 style="font-size: 13px; font-weight: 600; margin: 0; color: #555;">Subsection (h3), skipped h2</h3></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Skipped heading level</h3>
|
|
<p class="rule-card-desc">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.</p>
|
|
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-tight-leading" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; font-size: 13px; color: #111; line-height: 1.0; max-width: 220px;">Tight leading makes multi-line body text feel crammed and hard for the eye to track between lines.</div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Tight line height</h3>
|
|
<p class="rule-card-desc">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.</p>
|
|
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-tiny-text" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111;"><div style="font-size: 15px; margin-bottom: 6px;">Regular body text</div><div style="font-size: 9px; color: #555;">And then fine print at 9 pixels that no one will ever read.</div></div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Tiny body text</h3>
|
|
<p class="rule-card-desc">Body text below 12px is hard to read, especially on high-DPI screens. Use at least 14px for body content, 16px is ideal.</p>
|
|
|
|
</div>
|
|
</article>
|
|
|
|
<article class="rule-card" id="rule-wide-tracking" data-layer="cli">
|
|
<div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; font-size: 13px; color: #111; letter-spacing: 0.22em; max-width: 230px; line-height: 1.6;">Wide tracking on body text slows reading by breaking up natural character groupings.</div></div></div>
|
|
<div class="rule-card-body">
|
|
<div class="rule-card-head">
|
|
<span class="rule-card-category" data-category="quality">Quality</span>
|
|
<span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
|
|
</div>
|
|
<h3 class="rule-card-name">Wide letter spacing on body text</h3>
|
|
<p class="rule-card-desc">Letter spacing above 0.05em on body text disrupts natural character groupings and slows reading. Reserve wide tracking for short uppercase labels only.</p>
|
|
|
|
</div>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="slop-section visual-mode-methods" id="run-it" aria-label="Where to run the overlay">
|
|
<h2 class="slop-section-heading">Run it yourself</h2>
|
|
<div class="visual-mode-methods-grid">
|
|
<article class="visual-mode-method">
|
|
<p class="visual-mode-method-label">Inside /impeccable critique</p>
|
|
<h3 class="visual-mode-method-name"><a href="/docs/critique">/impeccable critique</a></h3>
|
|
<p class="visual-mode-method-desc">The design review command opens the overlay automatically during its browser assessment pass. Deterministic findings highlighted in place while the LLM runs its separate heuristic review.</p>
|
|
</article>
|
|
<article class="visual-mode-method">
|
|
<p class="visual-mode-method-label">Standalone CLI</p>
|
|
<h3 class="visual-mode-method-name"><a href="/docs/detector"><code>npx impeccable detect</code></a></h3>
|
|
<p class="visual-mode-method-desc">Runs the deterministic detector from the terminal on files, directories, stdin, or rendered URLs. Use it for CI and local checks without opening an AI harness.</p>
|
|
</article>
|
|
<article class="visual-mode-method">
|
|
<p class="visual-mode-method-label">Easiest</p>
|
|
<h3 class="visual-mode-method-name">Chrome extension</h3>
|
|
<p class="visual-mode-method-desc">One-click activation on any tab. <a href="https://chromewebstore.google.com/detail/impeccable/bdkgmiklpdmaojlpflclinlofgjfpabf" target="_blank" rel="noopener">Install from Chrome Web Store →</a></p>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script is:inline>
|
|
// Copy buttons on rendered code blocks
|
|
document.addEventListener('click', (e) => {
|
|
const btn = e.target.closest('[data-copy]');
|
|
if (!btn) return;
|
|
const text = btn.getAttribute('data-copy');
|
|
if (!text) return;
|
|
navigator.clipboard.writeText(text).then(() => {
|
|
btn.classList.add('is-copied');
|
|
setTimeout(() => btn.classList.remove('is-copied'), 1500);
|
|
}).catch(() => {});
|
|
});
|
|
|
|
// Mobile sidebar toggle (shown on narrow viewports, hidden on desktop).
|
|
document.addEventListener('click', (e) => {
|
|
const toggle = e.target.closest('.skills-sidebar-toggle');
|
|
if (!toggle) return;
|
|
const expanded = toggle.getAttribute('aria-expanded') === 'true';
|
|
toggle.setAttribute('aria-expanded', String(!expanded));
|
|
});
|
|
|
|
// Slop era toggle (2022 vs 2026)
|
|
document.addEventListener('click', (e) => {
|
|
const tab = e.target.closest('.slop-era-tab');
|
|
if (!tab) return;
|
|
const era = tab.getAttribute('data-era');
|
|
document.querySelectorAll('.slop-era-tab').forEach(t => {
|
|
t.classList.toggle('is-active', t === tab);
|
|
t.setAttribute('aria-selected', String(t === tab));
|
|
});
|
|
document.querySelectorAll('.slop-era-frame').forEach(f => {
|
|
f.style.display = f.getAttribute('data-era') === era ? '' : 'none';
|
|
});
|
|
const title = document.querySelector('.visual-mode-preview-title[data-title-2022]');
|
|
if (title) title.textContent = title.getAttribute('data-title-' + era);
|
|
});
|
|
|
|
// Before/after split-compare: drag on touch, hover OR drag on mouse.
|
|
// Pointer events attach to the padded .split-comparison wrapper so
|
|
// there is a ~20px invisible buffer around the visible box. The
|
|
// divider only snaps back when the pointer leaves that outer buffer.
|
|
(function initSplitCompare() {
|
|
const wrappers = document.querySelectorAll('.split-comparison');
|
|
if (wrappers.length === 0) return;
|
|
const hasHover = matchMedia('(hover: hover)').matches;
|
|
const DEFAULT_POSITION = 50;
|
|
|
|
for (const wrapper of wrappers) {
|
|
const container = wrapper.querySelector('.split-container');
|
|
const splitAfter = wrapper.querySelector('.split-after');
|
|
const splitDivider = wrapper.querySelector('.split-divider');
|
|
if (!container || !splitAfter || !splitDivider) continue;
|
|
|
|
const tanAngle = Math.tan(10 * Math.PI / 180);
|
|
let skewOffset = 8;
|
|
const recalcSkew = () => {
|
|
const r = container.getBoundingClientRect();
|
|
if (r.width > 0 && r.height > 0) {
|
|
skewOffset = 50 * r.height * tanAngle / r.width;
|
|
}
|
|
};
|
|
recalcSkew();
|
|
window.addEventListener('resize', recalcSkew, { passive: true });
|
|
|
|
let targetX = DEFAULT_POSITION;
|
|
let currentX = DEFAULT_POSITION;
|
|
let rafId = null;
|
|
|
|
const paint = (pct) => {
|
|
const x = Math.max(-skewOffset, Math.min(100 + skewOffset, pct));
|
|
splitAfter.style.clipPath =
|
|
`polygon(${x + skewOffset}% 0%, 100% 0%, 100% 100%, ${x - skewOffset}% 100%)`;
|
|
splitDivider.style.left = `${x}%`;
|
|
};
|
|
|
|
const step = () => {
|
|
currentX += (targetX - currentX) * 0.2;
|
|
if (Math.abs(targetX - currentX) < 0.1) {
|
|
currentX = targetX;
|
|
rafId = null;
|
|
} else {
|
|
rafId = requestAnimationFrame(step);
|
|
}
|
|
paint(currentX);
|
|
};
|
|
|
|
const setTarget = (pct) => {
|
|
targetX = pct;
|
|
if (rafId === null) rafId = requestAnimationFrame(step);
|
|
};
|
|
|
|
paint(DEFAULT_POSITION);
|
|
|
|
// Percentage is always relative to the VISIBLE .split-container,
|
|
// not the padded .split-comparison wrapper. The pointer event
|
|
// target is the wrapper but the clip-path math uses the inner box.
|
|
const pctFromClientX = (clientX) => {
|
|
const rect = container.getBoundingClientRect();
|
|
return ((clientX - rect.left) / rect.width) * 100;
|
|
};
|
|
|
|
let hovering = false;
|
|
let dragging = false;
|
|
|
|
wrapper.addEventListener('pointerenter', (e) => {
|
|
if (hasHover && e.pointerType === 'mouse') {
|
|
hovering = true;
|
|
}
|
|
});
|
|
|
|
wrapper.addEventListener('pointerdown', (e) => {
|
|
dragging = true;
|
|
wrapper.setPointerCapture(e.pointerId);
|
|
setTarget(pctFromClientX(e.clientX));
|
|
});
|
|
|
|
wrapper.addEventListener('pointermove', (e) => {
|
|
if (dragging || hovering) {
|
|
setTarget(pctFromClientX(e.clientX));
|
|
}
|
|
});
|
|
|
|
const endDrag = (e) => {
|
|
if (dragging) {
|
|
dragging = false;
|
|
try { wrapper.releasePointerCapture(e.pointerId); } catch {}
|
|
}
|
|
};
|
|
|
|
wrapper.addEventListener('pointerup', endDrag);
|
|
wrapper.addEventListener('pointercancel', endDrag);
|
|
|
|
wrapper.addEventListener('pointerleave', (e) => {
|
|
endDrag(e);
|
|
if (hovering) {
|
|
hovering = false;
|
|
setTarget(DEFAULT_POSITION);
|
|
}
|
|
});
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
</Base>
|