anti-slop-frontend
A flat, mechanical checklist of the concrete signatures an undirected model
emits when it tries to "look designed." Every rule here is countable or
binary - you can mechanically verify pass/fail, not argue taste. That is the
whole point: "it looks better" is not a check; "eyebrow count > ceil(sections/3)"
is.
What this is, and is NOT
- IS an advisory catalog of AI-tells, scoped by surface kind.
- IS standalone - works with no tooling, in any React/Tailwind/HTML project.
- IS NOT a design philosophy, a loop, or a gate. It scores; it never blocks.
Relationship to frontend-mockup-loop
Different jobs, intentionally separate:
|
frontend-mockup-loop |
anti-slop-frontend (this) |
| Shape |
ground→contract→mockup→test→fix→learn loop |
flat checklist |
| Basis |
cite an external public rule (Nielsen, WCAG, Laws of UX) |
codified AI-tell catalog |
| Authority |
owns the hard gates (WCAG-AA, severity-4) |
advisory only, drives the fix list |
| Domain |
product UI, dashboards, flows |
universal tells + marketing-surface tells |
When both are present: the loop's a11y floor and cite-a-source rule win.
This skill feeds concrete failing items into the loop's FIX step. It never
overrides a gate, and a tell here is never a reason to violate a cited rule.
Honesty note: these rules are curated taste, hardened into countable
form. They are good defaults, not laws of nature. Every rule has an override
path: when the brief explicitly asks for the "banned" thing, it is allowed -
execute it with intent, not by accident.
The three dials (set once, up front)
State these before reviewing or generating. They gate which rules fire and how hard.
VARIANCE (1-10) - 1 = perfect symmetry, 10 = artsy chaos
MOTION (1-10) - 1 = static, 10 = cinematic/physics
DENSITY (1-10) - 1 = art-gallery airy, 10 = cockpit/packed-data
Infer from the brief; don't silently use a baseline. Dashboards/data UI live high
on DENSITY and low on VARIANCE/MOTION. Landing/portfolio live the opposite.
PART A - Universal tells (apply to EVERY surface, dashboards included)
These fire regardless of surface kind. A dense admin panel is just as guilty of
AI-purple and Inter-everywhere as a landing page.
A1. Color
- No AI-purple/blue glow as default. No automatic violet button glows, no
random neon gradients ("the Lila tell"). Neutral base (Zinc/Slate/Stone) +
ONE high-contrast accent. Override: brand literally is purple.
- Max 1 accent color, saturation < 80% default. Lock it: the same accent on
the whole page. A warm-grey UI does not grow a blue CTA in section 7.
- One neutral temperature per project. Don't drift warm-grey ↔ cool-grey.
- No pure
#000000 / pure #ffffff. Off-black (zinc-950) and off-white;
pure values kill depth.
A2. Typography
- Inter is discouraged as the default. Reach past it (Geist, Outfit,
Cabinet Grotesk, Satoshi) unless the brief wants neutral/Linear-style or is
accessibility-first. Override exists.
- Serif is very discouraged as default. "Feels premium/creative" is not a
reason. Specifically banned as defaults: Fraunces, Instrument Serif.
Serif only when the brief names one or the family is genuinely
editorial/luxury/heritage.
- Emphasis = italic/bold of the SAME family. Never inject a random serif
word into a sans headline for "visual interest."
- One corner-radius scale per page (all-sharp / all-soft / all-pill), or a
documented rule followed everywhere.
A3. The em-dash ban (the #1 tell)
- Zero
— and zero –-as-separator anywhere visible. Headlines, labels,
pills, body, quotes, attribution, captions, buttons, alt text. No "sparingly."
Replace with a period, comma, colon, parentheses, line break, or a spaced
hyphen -. Ranges use a plain hyphen (2018-2026, €40-80k).
- Mechanical check: grep the rendered output for
—/–. Any hit = fail.
A4. Fake data ("Jane Doe" effect)
- No generic names. "John Doe / Sarah Chan / Jack Su" → realistic,
locale-appropriate names.
- No generic brand names. "Acme / Nexus / SmartFlow / Cloudly" → contextual
names that sound real.
- No fake-perfect numbers.
99.99%, 50%, 1234567 → organic values
(47.2%, real-looking phone formats). Fake-precise engineering specs
(5.8mm, 4.1×) are banned unless from real data or labeled mock.
- No filler verbs. "Elevate / Seamless / Unleash / Next-Gen / Revolutionize"
→ concrete verbs.
- No generic avatars (SVG "egg", default user glyph) → believable placeholders.
A5. Assets & icons
- No div-based fake screenshots. Building a fake dashboard/terminal/task-list
out of styled
<div>s is the single biggest tell. Use a real screenshot, a
generated image, a real mini component preview, or nothing.
- No hand-rolled SVG icons. Use one icon family (Phosphor / HugeIcons /
Radix / Tabler), standardized stroke width. Lucide only on explicit request.
- No hand-rolled decorative SVG illustrations as default.
- No broken image links. Use
picsum.photos/seed/{descriptive}/{w}/{h} or
generated assets, never dead Unsplash URLs.
A6. Interactive states (the "happy-path only" tell)
- Loading / empty / error states exist, not just the static success state.
Skeletons match final layout shape; avoid generic spinners.
- Button contrast (a11y). Every CTA's text passes WCAG AA against its own
background. No white-on-white, no transparent button on same-color bg with no
border. (This one is also a hard gate when frontend-mockup-loop runs.)
- Form contrast (a11y). Inputs, placeholders, focus rings, helper, error text
all pass AA against the section bg. Label above input; never placeholder-as-label.
A7. Motion must be motivated
- Every animation justifies itself in one sentence - hierarchy, storytelling,
feedback, or state-transition. "It looked cool" is not valid. Motion-for-show
is amateur.
- Motion claimed = motion shown. If
MOTION > 4, the page actually moves; if
you can't ship working motion, drop the dial and ship clean static.
- Banned mechanism:
window.addEventListener('scroll', …) and React-state
scroll/rAF loops. Use scroll-driven CSS, IntersectionObserver, or a motion
library's scroll primitives.
- Reduced-motion honored for anything above
MOTION 3.
PART B - Marketing-surface tells (landing / portfolio / about ONLY)
Skip Part B entirely for dashboards, data tables, wizards, editors, product UI.
These rules govern hero-driven marketing pages, where the model's worst
templating habits live.
B1. Hero discipline
- Hero fits the initial viewport. Headline ≤ 2 lines, subtext ≤ 20 words and
≤ 4 lines, CTA visible without scroll. A 4-line headline is a font-size error.
- Hero top padding ≤
pt-24 desktop (content must not float mid-viewport).
- Max 4 text elements in the hero: (eyebrow OR brand strip), headline,
subtext, CTAs. Banned in hero: trust micro-strip, pricing teaser, tagline
under CTAs, feature bullets, avatar row - those move to sections below.
- No version labels (
V0.6, BETA, INVITE-ONLY) unless the brief is a launch.
B2. The eyebrow tell (#1 violated rule)
- An "eyebrow" = small uppercase wide-tracking label above a section headline
(
text-[11px] uppercase tracking-[0.18em]).
- Max 1 eyebrow per 3 sections (hero counts as 1). Mechanical check: count
uppercase tracking micro-labels above headlines; fail if > ceil(sections/3).
- No section-number eyebrows (
00 / INDEX, 001 · Capabilities, 06 · how it works). The section's position already categorizes it.
- Default fix: drop the eyebrow. The headline alone is enough.
B3. Layout repetition
- No 3 equal feature cards. The "three identical horizontal cards" row is the
default. Use asymmetric grid, zig-zag, or a different family.
- Zigzag cap: max 2 consecutive image+text splits. The 3rd in a row is a fail.
- Section-layout-repetition ban. A layout family appears at most once. 8
sections → ≥ 4 distinct families.
- No split-header ("big left headline + small right floating paragraph") as
default. Stack headline over body instead.
- Bento: exact cell count, real rhythm, background diversity. N items → N
cells (no empty tiles); ≥ 2-3 cells have real visual variation (image,
gradient, pattern), not all white-on-white text cards.
- Marquee: max one per page.
B4. CTA & social proof
- No duplicate CTA intent. "Get in touch" + "Let's talk" + "Contact us" on one
page = fail. One label per intent, everywhere.
- No CTA wraps to 2+ lines at desktop (shorten label or widen button).
- Logo wall lives UNDER the hero, is logos only (no industry labels beneath),
uses real SVG marks (Simple Icons / devicon) or generated monograms, not plain
text wordmarks.
B5. Decoration tells (banned by default)
- No decoration text strip at hero bottom (
BRAND. MOTION. SPATIAL.).
- No locale / city / time / weather strips (
LIS 14:23 · 18°C) unless the
brief is genuinely place- or timezone-focused.
- No scroll cues (
Scroll, ↓ scroll, Scroll to explore).
- No version footers (
v1.4.2, Build 0048, last sync 4s ago) on
marketing pages - those are devtool fixtures.
- The middle-dot
· is rationed (max 1 per metadata line; not the default
separator for everything).
- No decorative status dots before every nav item / row / badge. Only for
real semantic state, sparingly.
- No pills/labels overlaid on images and no pretentious photo-credit
captions (
Field study no. 12 · Ines Caetano) on stock/placeholder images.
- No poetic section labels ("From the field", "Field notes", "On our desks")
→ plain functional labels or none.
- No
border-t + border-b on every row of a long list/spec table. Long
lists (>5 items) use a real component (grouped chunks, card grid, tabs,
scroll-snap), not a hairline-per-row <ul>.
B6. Copy self-audit
- Re-read every visible string. Flag and rewrite: grammatically broken phrases,
unclear referents, cute-but-wrong wordplay, fake-craftsman micro-meta. Plain
functional copy beats AI-cute copy.
Mechanical pre-flight (the grep-able subset)
The rules below can be checked by string-search, not judgment. Run them last.
If a box can't be honestly ticked, it's a flagged item - feed it to the fix step.
Pitfalls
- Do NOT treat these as hard gates. They are advisory; the WCAG/severity gates
(owned by frontend-mockup-loop) are the only hard blockers.
- Do NOT apply Part B to dashboards/product UI - it will fight dense, correct UI.
- Do NOT cite a tell from this catalog as justification to violate an external
documented rule. When the two conflict, the cited public rule wins.
- Do NOT forget the override path: when the brief explicitly asks for the
"banned" thing, allow it - done with intent, not by default-reaching.
Verification
- The three dials were declared and reasoned from the brief, not defaulted.
- The grep-able pre-flight subset was run; every hit is either fixed or has a
documented brief-driven override.
- Part B was applied only to marketing surfaces; skipped for product UI.
- No advisory tell was used to override a WCAG-AA or severity-4 gate.
Adapted from Leonxlnx/taste-skill
(design-taste-frontend, MIT). This is a distillation of its countable rules:
stack-coupling (Next RSC / Motion / GSAP / next/font) removed, rules re-scoped
into universal vs marketing-only, and reframed as an advisory catalog that pairs
with - never overrides - frontend-mockup-loop's cite-a-source loop and hard
gates. Original taste, original author's eye; full prose corpus and GSAP code
skeletons live in the upstream repo.
1---2name: anti-slop-frontend3description: A mechanical, countable anti-slop checklist for AI-generated frontend. Catches the specific signatures an undirected model defaults to: AI-purple glows, Inter-everywhere, em-dashes, div-based fake screenshots, eyebrow-on-every-section, beige+brass "premium" palettes, generic Jane Doe / Acme data. Advisory layer that pairs with frontend-mockup-loop (which owns the cite-a-source loop plus WCAG gates) but works standalone in any React/Tailwind/HTML project. Triggers: "does this look AI-generated", "anti-slop pass", "remove the AI tells", "why does this look templated", "design review for slop".4license: MIT5---67# anti-slop-frontend89A flat, **mechanical** checklist of the concrete signatures an undirected model10emits when it tries to "look designed." Every rule here is **countable or11binary** - you can mechanically verify pass/fail, not argue taste. That is the12whole point: "it looks better" is not a check; "eyebrow count > ceil(sections/3)"13is.1415## What this is, and is NOT1617- **IS** an advisory catalog of AI-tells, scoped by surface kind.18- **IS** standalone - works with no tooling, in any React/Tailwind/HTML project.19- **IS NOT** a design philosophy, a loop, or a gate. It scores; it never blocks.2021### Relationship to `frontend-mockup-loop`2223Different jobs, intentionally separate:2425| | frontend-mockup-loop | anti-slop-frontend (this) |26|---|---|---|27| Shape | ground→contract→mockup→test→fix→learn **loop** | flat **checklist** |28| Basis | cite an **external public rule** (Nielsen, WCAG, Laws of UX) | codified **AI-tell catalog** |29| Authority | owns the **hard gates** (WCAG-AA, severity-4) | **advisory only**, drives the fix list |30| Domain | product UI, dashboards, flows | universal tells + marketing-surface tells |3132When both are present: the loop's a11y floor and cite-a-source rule **win**.33This skill feeds concrete failing items into the loop's FIX step. It never34overrides a gate, and a tell here is never a reason to violate a cited rule.3536> **Honesty note:** these rules are curated *taste*, hardened into countable37> form. They are good defaults, not laws of nature. Every rule has an **override38> path**: when the brief explicitly asks for the "banned" thing, it is allowed -39> execute it with intent, not by accident.4041---4243## The three dials (set once, up front)4445State these before reviewing or generating. They gate which rules fire and how hard.4647- **`VARIANCE` (1-10)** - 1 = perfect symmetry, 10 = artsy chaos48- **`MOTION` (1-10)** - 1 = static, 10 = cinematic/physics49- **`DENSITY` (1-10)** - 1 = art-gallery airy, 10 = cockpit/packed-data5051Infer from the brief; don't silently use a baseline. Dashboards/data UI live high52on DENSITY and low on VARIANCE/MOTION. Landing/portfolio live the opposite.5354---5556## PART A - Universal tells (apply to EVERY surface, dashboards included)5758These fire regardless of surface kind. A dense admin panel is just as guilty of59AI-purple and Inter-everywhere as a landing page.6061### A1. Color62- **No AI-purple/blue glow as default.** No automatic violet button glows, no63 random neon gradients ("the Lila tell"). Neutral base (Zinc/Slate/Stone) +64 ONE high-contrast accent. *Override:* brand literally is purple.65- **Max 1 accent color, saturation < 80% default.** Lock it: the same accent on66 the whole page. A warm-grey UI does not grow a blue CTA in section 7.67- **One neutral temperature per project.** Don't drift warm-grey ↔ cool-grey.68- **No pure `#000000` / pure `#ffffff`.** Off-black (zinc-950) and off-white;69 pure values kill depth.7071### A2. Typography72- **Inter is discouraged as the *default*.** Reach past it (Geist, Outfit,73 Cabinet Grotesk, Satoshi) unless the brief wants neutral/Linear-style or is74 accessibility-first. *Override exists.*75- **Serif is very discouraged as default.** "Feels premium/creative" is not a76 reason. Specifically banned as defaults: **Fraunces, Instrument Serif**.77 Serif only when the brief names one or the family is genuinely78 editorial/luxury/heritage.79- **Emphasis = italic/bold of the SAME family.** Never inject a random serif80 word into a sans headline for "visual interest."81- **One corner-radius scale per page** (all-sharp / all-soft / all-pill), or a82 documented rule followed everywhere.8384### A3. The em-dash ban (the #1 tell)85- **Zero `—` and zero `–`-as-separator anywhere visible.** Headlines, labels,86 pills, body, quotes, attribution, captions, buttons, alt text. No "sparingly."87 Replace with a period, comma, colon, parentheses, line break, or a spaced88 hyphen ` - `. Ranges use a plain hyphen (`2018-2026`, `€40-80k`).89- Mechanical check: grep the rendered output for `—`/`–`. Any hit = fail.9091### A4. Fake data ("Jane Doe" effect)92- **No generic names.** "John Doe / Sarah Chan / Jack Su" → realistic,93 locale-appropriate names.94- **No generic brand names.** "Acme / Nexus / SmartFlow / Cloudly" → contextual95 names that sound real.96- **No fake-perfect numbers.** `99.99%`, `50%`, `1234567` → organic values97 (`47.2%`, real-looking phone formats). Fake-precise engineering specs98 (`5.8mm`, `4.1×`) are banned unless from real data or labeled mock.99- **No filler verbs.** "Elevate / Seamless / Unleash / Next-Gen / Revolutionize"100 → concrete verbs.101- **No generic avatars** (SVG "egg", default user glyph) → believable placeholders.102103### A5. Assets & icons104- **No div-based fake screenshots.** Building a fake dashboard/terminal/task-list105 out of styled `<div>`s is the single biggest tell. Use a real screenshot, a106 generated image, a real mini component preview, or nothing.107- **No hand-rolled SVG icons.** Use one icon family (Phosphor / HugeIcons /108 Radix / Tabler), standardized stroke width. Lucide only on explicit request.109- **No hand-rolled decorative SVG illustrations** as default.110- **No broken image links.** Use `picsum.photos/seed/{descriptive}/{w}/{h}` or111 generated assets, never dead Unsplash URLs.112113### A6. Interactive states (the "happy-path only" tell)114- **Loading / empty / error states exist**, not just the static success state.115 Skeletons match final layout shape; avoid generic spinners.116- **Button contrast (a11y).** Every CTA's text passes WCAG AA against its own117 background. No white-on-white, no transparent button on same-color bg with no118 border. *(This one is also a hard gate when frontend-mockup-loop runs.)*119- **Form contrast (a11y).** Inputs, placeholders, focus rings, helper, error text120 all pass AA against the section bg. Label above input; never placeholder-as-label.121122### A7. Motion must be motivated123- **Every animation justifies itself in one sentence** - hierarchy, storytelling,124 feedback, or state-transition. "It looked cool" is not valid. Motion-for-show125 is amateur.126- **Motion claimed = motion shown.** If `MOTION > 4`, the page actually moves; if127 you can't ship working motion, drop the dial and ship clean static.128- **Banned mechanism: `window.addEventListener('scroll', …)`** and React-state129 scroll/rAF loops. Use scroll-driven CSS, IntersectionObserver, or a motion130 library's scroll primitives.131- **Reduced-motion honored** for anything above `MOTION 3`.132133---134135## PART B - Marketing-surface tells (landing / portfolio / about ONLY)136137Skip Part B entirely for dashboards, data tables, wizards, editors, product UI.138These rules govern hero-driven marketing pages, where the model's worst139templating habits live.140141### B1. Hero discipline142- **Hero fits the initial viewport.** Headline ≤ 2 lines, subtext ≤ 20 words and143 ≤ 4 lines, CTA visible without scroll. A 4-line headline is a font-size error.144- **Hero top padding ≤ `pt-24` desktop** (content must not float mid-viewport).145- **Max 4 text elements in the hero**: (eyebrow OR brand strip), headline,146 subtext, CTAs. Banned in hero: trust micro-strip, pricing teaser, tagline147 under CTAs, feature bullets, avatar row - those move to sections below.148- **No version labels** (`V0.6`, `BETA`, `INVITE-ONLY`) unless the brief is a launch.149150### B2. The eyebrow tell (#1 violated rule)151- An "eyebrow" = small uppercase wide-tracking label above a section headline152 (`text-[11px] uppercase tracking-[0.18em]`).153- **Max 1 eyebrow per 3 sections** (hero counts as 1). Mechanical check: count154 `uppercase tracking` micro-labels above headlines; fail if > ceil(sections/3).155- **No section-number eyebrows** (`00 / INDEX`, `001 · Capabilities`, `06 · how it156 works`). The section's position already categorizes it.157- **Default fix: drop the eyebrow.** The headline alone is enough.158159### B3. Layout repetition160- **No 3 equal feature cards.** The "three identical horizontal cards" row is the161 default. Use asymmetric grid, zig-zag, or a different family.162- **Zigzag cap: max 2 consecutive image+text splits.** The 3rd in a row is a fail.163- **Section-layout-repetition ban.** A layout family appears at most once. 8164 sections → ≥ 4 distinct families.165- **No split-header** ("big left headline + small right floating paragraph") as166 default. Stack headline over body instead.167- **Bento: exact cell count, real rhythm, background diversity.** N items → N168 cells (no empty tiles); ≥ 2-3 cells have real visual variation (image,169 gradient, pattern), not all white-on-white text cards.170- **Marquee: max one per page.**171172### B4. CTA & social proof173- **No duplicate CTA intent.** "Get in touch" + "Let's talk" + "Contact us" on one174 page = fail. One label per intent, everywhere.175- **No CTA wraps to 2+ lines at desktop** (shorten label or widen button).176- **Logo wall lives UNDER the hero, is logos only** (no industry labels beneath),177 uses real SVG marks (Simple Icons / devicon) or generated monograms, not plain178 text wordmarks.179180### B5. Decoration tells (banned by default)181- **No decoration text strip** at hero bottom (`BRAND. MOTION. SPATIAL.`).182- **No locale / city / time / weather strips** (`LIS 14:23 · 18°C`) unless the183 brief is genuinely place- or timezone-focused.184- **No scroll cues** (`Scroll`, `↓ scroll`, `Scroll to explore`).185- **No version footers** (`v1.4.2`, `Build 0048`, `last sync 4s ago`) on186 marketing pages - those are devtool fixtures.187- **The middle-dot `·` is rationed** (max 1 per metadata line; not the default188 separator for everything).189- **No decorative status dots** before every nav item / row / badge. Only for190 real semantic state, sparingly.191- **No pills/labels overlaid on images** and **no pretentious photo-credit192 captions** (`Field study no. 12 · Ines Caetano`) on stock/placeholder images.193- **No poetic section labels** ("From the field", "Field notes", "On our desks")194 → plain functional labels or none.195- **No `border-t` + `border-b` on every row** of a long list/spec table. Long196 lists (>5 items) use a real component (grouped chunks, card grid, tabs,197 scroll-snap), not a hairline-per-row `<ul>`.198199### B6. Copy self-audit200- Re-read every visible string. Flag and rewrite: grammatically broken phrases,201 unclear referents, cute-but-wrong wordplay, fake-craftsman micro-meta. Plain202 functional copy beats AI-cute copy.203204---205206## Mechanical pre-flight (the grep-able subset)207208The rules below can be checked by string-search, not judgment. Run them last.209210- [ ] **Em-dash:** zero `—` / `–`-as-separator in rendered output (A3).211- [ ] **AI-purple:** no default violet glow/gradient unless brand-justified (A1).212- [ ] **Accent lock:** one accent hex family across all sections (A1).213- [ ] **Default font:** not Inter (unless justified); serif is not Fraunces /214 Instrument Serif (A2).215- [ ] **Fake data:** no "Doe / Acme / 99.99% / Elevate" (A4).216- [ ] **Fake screenshots:** no div-built product UI; no hand-rolled icon paths (A5).217- [ ] **CTA/form contrast:** every CTA + input passes WCAG AA (A6).218- [ ] **Motion:** no `addEventListener('scroll')`; reduced-motion present (A7).219- [ ] *(marketing only)* **Eyebrow count** ≤ ceil(sections/3) (B2).220- [ ] *(marketing only)* **Zigzag** ≤ 2 consecutive splits; ≥ 4 layout families (B3).221- [ ] *(marketing only)* **CTA intent** not duplicated; no CTA wrap at desktop (B4).222- [ ] *(marketing only)* no decoration/locale/scroll-cue/version strips (B5).223224If a box can't be honestly ticked, it's a flagged item - feed it to the fix step.225226---227228## Pitfalls229230- Do NOT treat these as hard gates. They are advisory; the WCAG/severity gates231 (owned by frontend-mockup-loop) are the only hard blockers.232- Do NOT apply Part B to dashboards/product UI - it will fight dense, correct UI.233- Do NOT cite a tell from this catalog as justification to violate an external234 documented rule. When the two conflict, the cited public rule wins.235- Do NOT forget the override path: when the brief explicitly asks for the236 "banned" thing, allow it - done with intent, not by default-reaching.237238## Verification239240- The three dials were declared and reasoned from the brief, not defaulted.241- The grep-able pre-flight subset was run; every hit is either fixed or has a242 documented brief-driven override.243- Part B was applied only to marketing surfaces; skipped for product UI.244- No advisory tell was used to override a WCAG-AA or severity-4 gate.245246---247248*Adapted from [Leonxlnx/taste-skill](https://github.com/Leonxlnx/taste-skill)249(`design-taste-frontend`, MIT). This is a distillation of its countable rules:250stack-coupling (Next RSC / Motion / GSAP / next/font) removed, rules re-scoped251into universal vs marketing-only, and reframed as an advisory catalog that pairs252with - never overrides - frontend-mockup-loop's cite-a-source loop and hard253gates. Original taste, original author's eye; full prose corpus and GSAP code254skeletons live in the upstream repo.*