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\".
npx skills add https://github.com/BlackBeltTechnology/pi-agent-dashboard --skill 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.
frontend-mockup-loopDifferent 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.
State these before reviewing or generating. They gate which rules fire and how hard.
VARIANCE (1-10) - 1 = perfect symmetry, 10 = artsy chaosMOTION (1-10) - 1 = static, 10 = cinematic/physicsDENSITY (1-10) - 1 = art-gallery airy, 10 = cockpit/packed-dataInfer 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.
These fire regardless of surface kind. A dense admin panel is just as guilty of
AI-purple and Inter-everywhere as a landing page.
random neon gradients ("the Lila tell"). Neutral base (Zinc/Slate/Stone) +
ONE high-contrast accent. *Override:* brand literally is purple.
the whole page. A warm-grey UI does not grow a blue CTA in section 7.
#000000 / pure #ffffff. Off-black (zinc-950) and off-white;pure values kill depth.
Cabinet Grotesk, Satoshi) unless the brief wants neutral/Linear-style or is
accessibility-first. *Override exists.*
reason. Specifically banned as defaults: Fraunces, Instrument Serif.
Serif only when the brief names one or the family is genuinely
editorial/luxury/heritage.
word into a sans headline for "visual interest."
documented rule followed everywhere.
— 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).
—/–. Any hit = fail.locale-appropriate names.
names that sound real.
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.
→ concrete verbs.
out of styled <div>s is the single biggest tell. Use a real screenshot, a
generated image, a real mini component preview, or nothing.
Radix / Tabler), standardized stroke width. Lucide only on explicit request.
picsum.photos/seed/{descriptive}/{w}/{h} orgenerated assets, never dead Unsplash URLs.
Skeletons match final layout shape; avoid generic spinners.
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.)*
all pass AA against the section bg. Label above input; never placeholder-as-label.
feedback, or state-transition. "It looked cool" is not valid. Motion-for-show
is amateur.
MOTION > 4, the page actually moves; ifyou can't ship working motion, drop the dial and ship clean static.
window.addEventListener('scroll', …) and React-statescroll/rAF loops. Use scroll-driven CSS, IntersectionObserver, or a motion
library's scroll primitives.
MOTION 3.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.
≤ 4 lines, CTA visible without scroll. A 4-line headline is a font-size error.
pt-24 desktop (content must not float mid-viewport).subtext, CTAs. Banned in hero: trust micro-strip, pricing teaser, tagline
under CTAs, feature bullets, avatar row - those move to sections below.
V0.6, BETA, INVITE-ONLY) unless the brief is a launch.(text-[11px] uppercase tracking-[0.18em]).
uppercase tracking micro-labels above headlines; fail if > ceil(sections/3).
00 / INDEX, 001 · Capabilities, `06 · how itworks`). The section's position already categorizes it.
default. Use asymmetric grid, zig-zag, or a different family.
sections → ≥ 4 distinct families.
default. Stack headline over body instead.
cells (no empty tiles); ≥ 2-3 cells have real visual variation (image,
gradient, pattern), not all white-on-white text cards.
page = fail. One label per intent, everywhere.
uses real SVG marks (Simple Icons / devicon) or generated monograms, not plain
text wordmarks.
BRAND. MOTION. SPATIAL.).LIS 14:23 · 18°C) unless thebrief is genuinely place- or timezone-focused.
Scroll, ↓ scroll, Scroll to explore).v1.4.2, Build 0048, last sync 4s ago) onmarketing pages - those are devtool fixtures.
· is rationed (max 1 per metadata line; not the defaultseparator for everything).
real semantic state, sparingly.
captions** (Field study no. 12 · Ines Caetano) on stock/placeholder images.
→ plain functional labels or none.
border-t + border-b on every row of a long list/spec table. Longlists (>5 items) use a real component (grouped chunks, card grid, tabs,
scroll-snap), not a hairline-per-row <ul>.
unclear referents, cute-but-wrong wordplay, fake-craftsman micro-meta. Plain
functional copy beats AI-cute copy.
The rules below can be checked by string-search, not judgment. Run them last.
— / –-as-separator in rendered output (A3).Instrument Serif (A2).
addEventListener('scroll'); reduced-motion present (A7).If a box can't be honestly ticked, it's a flagged item - feed it to the fix step.
(owned by frontend-mockup-loop) are the only hard blockers.
documented rule. When the two conflict, the cited public rule wins.
"banned" thing, allow it - done with intent, not by default-reaching.
documented brief-driven override.
*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.*
Take blackbelttechnology/anti-slop-frontend from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.