# Detection patterns

> Code-level signals the skill and scanner look for per tell: patterns, match targets, and how findings map back to taxonomy ids.

- Repository: yetone/kill-ai-slop
- GitHub: https://github.com/yetone/kill-ai-slop
- Human docs: https://grok-wiki.com/public/docs/yetone-kill-ai-slop-c0d8c9670cbb
- Complete Markdown: https://grok-wiki.com/public/docs/yetone-kill-ai-slop-c0d8c9670cbb/llms-full.txt

## Source Files

- `skill/references/detection.md`
- `skill/scripts/scan.mjs`
- `skill/references/taxonomy.md`
- `website/src/data/catalogue.ts`

---

---
title: "Detection patterns"
description: "Code-level signals the skill and scanner look for per tell: patterns, match targets, and how findings map back to taxonomy ids."
---

`skill/references/detection.md` is the human-facing pattern catalogue; `skill/scripts/scan.mjs` encodes the same 23 tells as executable line-level regexes and emits grouped findings. Matches are leads for manual confirmation, never automatic verdicts or file edits.

## Two surfaces, one numbering scheme

| Surface | Path | Role |
| --- | --- | --- |
| Human reference | `skill/references/detection.md` | `rg` recipes, confirm notes, false-positive guidance; place to widen patterns for a stack |
| Scanner runtime | `skill/scripts/scan.mjs` | Walks a project tree, applies `TELLS[].patterns`, prints console or `--json` report |
| Taxonomy names | `skill/references/taxonomy.md` | Numbered **01–23** names, groups, fix one-liners; points at `detection.md` for signals |
| Site chips | `website/src/data/catalogue.ts` → `Entry.detect: string[]` | Short mono-chip strings for the field guide; aligned by tell, not a second matcher |

Scanner tell ids are zero-padded strings `"01"`…`"23"`. Taxonomy uses the same numbers (`**01 · …**`). Catalogue entries use kebab-case string ids (for example `indigo-violet-gradient`) and an auto-assigned position `n`; they do not replace the scanner id in findings.

```text
project tree
    │
    ▼
walk()  →  allowed files only
    │
    ▼
scanFile()  line-by-line regex vs TELLS
    │
    ▼
byTell Map  →  console groups  |  --json findings[]
    │
    ▼
human confirms against detection.md notes
```

## Scan scope and filters

Implementation authority is `scan.mjs` (detection.md states the intent more briefly).

### Included files

- Extensions: `.html`, `.css`, `.scss`, `.sass`, `.less`, `.tsx`, `.jsx`, `.ts`, `.js`, `.mjs`, `.cjs`, `.vue`, `.svelte`, `.astro`, `.md`, `.mdx`
- Also: any basename matching `tailwind.config.*`

### Skipped directories

`node_modules`, `.git`, `dist`, `build`, `out`, `.next`, `.astro`, `.output`, `.svelte-kit`, `.nuxt`, `coverage`, `vendor`, `.cache`, `.vercel`, `.turbo`

### Skipped files

- `*.min.js` / `*.min.css`
- lockfiles matching `package-lock`, `pnpm-lock`, or `yarn.lock`
- files larger than **512 KiB**
- individual lines longer than **2000** characters (treated as minified-ish)

### Code vs copy tells

Most tells run only on non-prose files (`isCode = ext ∉ { .md, .mdx }`).

Tells with `copy: true` also run on Markdown:

| Scanner id | Name | `copy` |
| --- | --- | --- |
| `10` | highlighted keywords | yes |
| `11` | AI copywriting voice | yes |
| `12` | emoji everywhere | yes |

## Tell record shape (scanner)

Each entry in `TELLS` is:

| Field | Type | Purpose |
| --- | --- | --- |
| `id` | string `"01"`–`"23"` | Stable finding key; groups report sort by this |
| `group` | `color` \| `type` \| `copy` \| `component` \| `layout` \| `evolved` | Report / taxonomy group |
| `name` | string | Short human label in console and JSON |
| `fix` | string | One-line remediation hint on the report line |
| `patterns` | `RegExp[]` | Any match on a line counts as a hit |
| `copy` | optional boolean | When true, patterns also apply to `.md` / `.mdx` |

Hit object (internal → report):

| Field | Meaning |
| --- | --- |
| `file` | Path relative to scan root |
| `line` | 1-based line number |
| `text` | Trimmed line, first 100 characters |

## How findings map to taxonomy and catalogue

| Layer | Identifier | Example |
| --- | --- | --- |
| Scanner / detection / taxonomy number | `"05"` / **05** | one-hue status box |
| Scanner report fields | `id`, `group`, `name`, `fix` | `id: "05"`, `group: "color"` |
| Catalogue (site) | kebab-case `id` + `detect[]` chips | `mono-hue-alert` |

Known catalogue id alignment from supplied catalogue entries:

| Scanner / taxonomy | Catalogue `id` |
| --- | --- |
| 01 Indigo→violet gradient | `indigo-violet-gradient` |
| 02 Gradient headline text | `gradient-text` |
| 03 Warm cozy palette | `warm-cozy-palette` |
| 04 Default semantic palette | `default-semantic-palette` |
| 05 One-hue status box | `mono-hue-alert` |
| 06 Gradients as atmosphere | `atmosphere-gradient` |
| 07 Serif-italic on one word | `serif-emphasis` |
| 08 Serif where sans belongs | `serif-body-misuse` |

Catalogue `detect` strings are illustrative chips for the field guide (for example `"bg-clip-text text-transparent"`), not the full scanner regex set. Use `scan.mjs` `patterns` for executable matching and `detection.md` for confirmation criteria.

## Match semantics

1. Walk the tree under `root` (CLI path argument, default `"."`).
2. For each eligible file, split lines and test every tell’s patterns with `RegExp.prototype.test`.
3. First matching pattern on a line is enough; multiple tells can hit the same line.
4. Hits aggregate under tell `id`; console shows up to **12** hits per tell; JSON includes all hits for that tell.
5. No writes: the scanner only reports.

<Warning>
Every match is a **lead**. Open the file and confirm with the per-tell notes below. Brand-true purple, deliberate hero gradient text, real status badges, and intentional monospace chrome are not slop by pattern alone.
</Warning>

### CLI entry

```bash
node skill/scripts/scan.mjs [root] [--json] [--no-color]
```

`--json` shape (fields present in source):

```json
{
  "root": ".",
  "filesScanned": 0,
  "groups": 0,
  "hits": 0,
  "findings": [
    {
      "id": "01",
      "group": "color",
      "name": "indigo→violet gradient",
      "fix": "one solid, chosen accent",
      "hits": [{ "file": "src/App.tsx", "line": 42, "text": "..." }]
    }
  ]
}
```

## Pattern catalogue by tell

Executable patterns are the `scan.mjs` regexes. `detection.md` may list extra `rg` recipes or glob hints used for manual review (for example emoji Unicode ranges, icon library names, extra HTML tags); those are human aids when they differ.

### Color (`01`–`06`)

#### `01` · indigo→violet gradient

| | |
| --- | --- |
| Group | `color` |
| Scanner name / fix | `indigo→violet gradient` → `one solid, chosen accent` |
| Patterns | `from-(indigo\|violet\|purple\|fuchsia)-\d+…to-(purple\|violet\|fuchsia\|pink)-\d+`; `(linear-gradient\|bg-gradient)` near `#6366f1` / `#8b5cf6` / `#a855f7` / `#7c3aed`; `shadow-(purple\|violet\|indigo)-\d+/\d+` |
| Confirm | Slop is the **combination** (purple gradient + glow + pill + “AI-powered” eyebrow), not a genuine brand purple or one-off illustration |

#### `02` · gradient-clip headline

| | |
| --- | --- |
| Group | `color` |
| Scanner name / fix | `gradient-clip headline` → `solid ink, scale up` |
| Patterns | `bg-clip-text` near `text-transparent`; `(?:-webkit-)?background-clip:\s*text`; `-webkit-text-fill-color:\s*transparent` |
| Confirm | False positives: logo wordmark, single deliberate hero. Slop: gradient text as default heading style |

#### `03` · warm cozy palette

| | |
| --- | --- |
| Group | `color` |
| Scanner name / fix | `warm ‘cozy’ palette` → `neutral base + one warm accent` |
| Patterns | `\b(amber\|orange\|stone)-(50\|100\|200\|300)\b`; `bg-[#fdf6ec|fef3e2|faf3e8|fff7ed|fdf4e3]`; `(text\|border)-amber-\d+` |
| Confirm | False positives: food/coffee/craft brand identity. Slop: warm-as-default with no brand reason |

#### `04` · default semantic palette

| | |
| --- | --- |
| Group | `color` |
| Scanner name / fix | `default semantic palette` → `one palette: neutrals + a couple of chosen states` |
| Patterns | `bg-(blue\|indigo)-50`, `bg-amber-50`, `bg-(green\|emerald)-50`, `bg-red-50`; `(info\|success\|warning\|error)` near stock blue/green/amber/red steps |
| Confirm | Three or four stock `-50` / `-600`-style semantic pairs together, unrelated to brand. One deliberate status colour is fine |

#### `05` · one-hue status box

| | |
| --- | --- |
| Group | `color` |
| Scanner name / fix | `one-hue status box` → `state in words; one muted accent on neutral` |
| Patterns | `border-{hue}-\d+` then same hue `text-` (backref); `bg-(red\|amber\|yellow\|green)-\d+/(5\|10\|15\|20)`; `(error\|warning\|success)` near those hues |
| Confirm | Border, text, and `/10`-style background all one hue at three opacities. Single muted accent on neutral is fine |

#### `06` · gradients as atmosphere

| | |
| --- | --- |
| Group | `color` |
| Scanner name / fix | `gradients as atmosphere` → `one flat bg; depth from a hairline` |
| Patterns | `radial-gradient`; `linear-gradient` with `to bottom` / `180deg` / `to top`; `bg-gradient-to-[bt]` near `from-` |
| Confirm | Page-wide radial glow or card fills that are top-to-bottom gradients where a flat colour would do. Directional, purposeful gradients are choices |

### Type (`07`–`09`)

#### `07` · serif-italic emphasis

| | |
| --- | --- |
| Group | `type` |
| Scanner name / fix | `serif-italic emphasis` → `emphasise by weight, one voice` |
| Patterns | `\bfont-serif\b`; `font-family:` Georgia / Playfair / Lora / Cormorant |
| Confirm | Serif/italic span **inside** an otherwise-sans `<h1>` / `<h2>` (hard to prove with grep alone) |

#### `08` · serif where sans belongs

| | |
| --- | --- |
| Group | `type` |
| Scanner name / fix | `serif where sans belongs` → `one legible UI sans` |
| Patterns | `font-family` containing Playfair / Cormorant / Lora / DM Serif / Libre Baskerville; `fontFamily` with those display names |
| Confirm | False positives: editorial/publishing products. Slop: display serif as UI/body on tools or dashboards |

#### `09` · decorative strikes and highlights

| | |
| --- | --- |
| Group | `type` |
| Scanner name / fix | `decorative strikes & highlights` → `strike for edits, underline for links` |
| Patterns | `\bline-through\b`; `<(mark|s|u|del|strike)…>`; `text-decoration: line-through|underline` |
| Confirm | Decoration used for “emphasis,” not real edits, links, or annotation |

### Copy (`10`–`12`, `copy: true`)

#### `10` · highlighted keywords

| | |
| --- | --- |
| Group | `copy` |
| Scanner name / fix | `highlighted keywords` → `let structure carry emphasis` |
| Patterns | `<mark…>`; `text-(primary\|indigo\|purple\|violet)-\d+` |
| Confirm | Multiple colored/semibold spans in one body paragraph. One accented phrase is fine |

#### `11` · AI copywriting voice

| | |
| --- | --- |
| Group | `copy` |
| Scanner name / fix | `AI copywriting voice` → `say the specific thing` |
| Patterns | `not just … it's`; stock phrases (`say goodbye to`, `supercharge`, `unlock the power of`, …); hype adjectives (`blazing-fast`, `seamless`, `game-changer`, …) |
| Confirm | False positives: genuine quotes; docs that discuss the phrases. Also watch three-word sentence stacks and em-dash triplets manually |

#### `12` · emoji everywhere

| | |
| --- | --- |
| Group | `copy` |
| Scanner name / fix | `emoji everywhere` → `cut emoji from product copy` |
| Patterns | `/\p{Extended_Pictographic}/u` (scanner); detection.md also suggests leading 🚀✨⚡🔒🎉 on headings/buttons |
| Confirm | False positives: documented code samples, emoji pickers, UGC. Slop: emoji on every chrome heading/button/bullet |

### Components (`13`–`21`)

#### `13` · glowing status dot

| | |
| --- | --- |
| Patterns | `animate-ping` / `animate-pulse`; green/emerald/lime colored shadows; `(ready\|online\|live)` near `●` or `rounded-full` |
| Fix | `flat dot + a word; no halo` |
| Confirm | Pulsing halo / saturated green “Ready/Online.” Flat dots are fine |

#### `14` · left-border callout

| | |
| --- | --- |
| Patterns | `border-l-4` near `rounded`; `\b(admonition\|callout\|note-box)\b` |
| Fix | `one aside, rest is body` |
| Confirm | Stacked callouts decorating list items, not a scarce semantic aside |

#### `15` · pastel icon tiles

| | |
| --- | --- |
| Patterns | `rounded-(lg\|xl\|2xl) bg-(indigo\|purple\|blue\|green\|amber\|pink)-(50\|100)` |
| Fix | `labelled list with specifics` |
| Confirm | Grid of icon-in-tile features with icons unrelated to content. Manual: icon package imports (lucide, heroicons, …) are detection.md hints only |

#### `16` · max-radius / glassmorphism

| | |
| --- | --- |
| Patterns | `\brounded-full\b`; `backdrop-blur` / `backdrop-filter: blur` / `bg-(white\|black)/(5\|10\|20\|30)`; large `border-radius` (`9999px`, `50%`, `2rem`, `24px`) |
| Fix | `one small radius, solid surfaces` |
| Confirm | Full radius on cards/inputs (not only avatars/pills); blur as default surface |

#### `17` · oversized drop shadow

| | |
| --- | --- |
| Patterns | `box-shadow` / Tailwind arbitrary `shadow-[…]` / `filter: drop-shadow(…)` with blur/spread **≥ 60px** (`[6-9]\d` or `\d{3,}`) |
| Fix | `tight elevation, never bigger than the element` |
| Confirm | Shadow fog larger than the casting element. Proportionate modal/hero shadows and tight elevation are fine |

#### `18` · corners that don't nest

| | |
| --- | --- |
| Patterns | `rounded-(xl\|2xl\|3xl)`; `border-radius` `1rem` / `1.5rem` / `24px` / `32px` |
| Fix | `inner = outer − padding` |
| Confirm | Nested containers sharing the same large radius (non-concentric corners). Hard to prove by regex alone |

#### `19` · badge / pill spam

| | |
| --- | --- |
| Patterns | `rounded-full` near pastel `bg-(indigo\|purple\|green\|amber\|pink)-(50\|100\|200)`; text nodes like `new` / `beta` / `hot` / `popular` / `pro` / `coming soon` (optional leading ✨🔥🎉🚀) |
| Fix | `badges only for real status` |
| Confirm | Several decorative pills in chrome. Real version tags are fine |

#### `20` · AI-drawn SVG icon

| | |
| --- | --- |
| Patterns | `<circle` with `r="[1-9]…"`; `(mascot\|blob).svg` |
| Fix | `a real, high-quality icon (a designer, or a strong image model)` |
| Confirm | Visual judgment: blob-with-dot-eyes / primitive cartoon as product mark. Real icon sets and designed logos are fine |

#### `21` · icon in a tint of itself

| | |
| --- | --- |
| Patterns | same-hue `bg-…/\d+` near `text-…` (and reverse) for indigo/blue/green/amber/red/purple/pink opacities 5–20 |
| Fix | `no tinted tile; inherit text color` |
| Confirm | Icon tile wash matches icon hue. Opaque, deliberate button surfaces are fine |

### Layout and evolved (`22`–`23`)

#### `22` · all-caps card grid

| | |
| --- | --- |
| Group | `layout` |
| Patterns | `\bgrid-cols-3\b`; `\buppercase\b` near `text-xs` / `tracking-wide`; marketing stock (`everything you need`, `why you'll love` / `choose` / `teams`) |
| Fix | `show the one key thing fully` |
| Confirm | ALL-CAPS micro-label + number/icon repeated across interchangeable feature/stat cards |

#### `23` · tasteful-terminal (evolved)

| | |
| --- | --- |
| Group | `evolved` |
| Patterns | `\bfont-mono\b`; mono family names (JetBrains, Fira Code, IBM Plex Mono, Geist Mono, …); box-drawing / shade characters `╔╗╚╝║═▓▒░` |
| Fix | `mono for code only` |
| Confirm | Mono on non-code chrome; ASCII as decoration; near-black + single warm accent. Highest judgment load — weigh whether the terminal metaphor serves the product |

## Human vs machine pattern drift

Keep these differences in mind when extending or debugging detection:

| Topic | `detection.md` | `scan.mjs` |
| --- | --- | --- |
| Emoji | Broad Unicode ranges + leading-emoji `rg` | Single `\p{Extended_Pictographic}` |
| Tell 04 | Mentions multiple stock hues near each other | Stock `bg-*-50` + info/success/warning/error near hues |
| Tell 15 | Mentions lucide/heroicons/react-icons | Pastel rounded tile classes only |
| Tell 20 | `<svg` greps + visual judgment | Circle radius + `mascot`/`blob`.svg only |
| Scope lists | Slightly shorter skip/ext lists | Authoritative `SKIP_DIRS` / `EXTS` |

When widening stack-specific signals, update **both** the human recipes and the `TELLS` regexes so reports stay aligned with the skill references.

## Verification signals

| Signal | Expected |
| --- | --- |
| Empty project / clean UI | Console: `No slop signals found. (Still trust your eyes — open the pages.)` |
| Known Tailwind indigo hero | Finding group `01` with file:line and snippet |
| Markdown with “supercharge” | Finding under `11` when `copy: true` path includes `.md` |
| Scanner contract | Process never writes or rewrites project files |

## Related pages

<CardGroup>
  <Card title="Slop taxonomy" href="/slop-taxonomy">
    Numbered tells, groups, and the shared language for classic vs evolved slop.
  </Card>
  <Card title="Catalogue model" href="/catalogue-model">
    How `catalogue.ts` attaches `detect` chips and demos without owning the matcher.
  </Card>
  <Card title="Scan a web project" href="/scan-web-project">
    Point the scanner at a path and interpret grouped vs JSON reports against these rules.
  </Card>
  <Card title="Scanner CLI reference" href="/scanner-cli-reference">
    Invocation, flags, walk behavior, and the never-edit constraint.
  </Card>
  <Card title="Remediation playbook" href="/fixes-playbook">
    Map confirmed hits to clean replacements per tell.
  </Card>
  <Card title="Extend the catalogue" href="/extend-catalogue">
    Add a tell end-to-end: catalogue, demos, and skill detection alignment.
  </Card>
</CardGroup>
