taste-lint 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/data/config.schema.json +7 -0
- package/data/corpus/copywriting.jsonl +4 -4
- package/data/rule-drafts/interaction/interaction-layout-shift.yaml +3 -3
- package/data/rules/copywriting/copywriting-anthropomorphism.yaml +4 -3
- package/data/rules/copywriting/copywriting-antithesis-contrast.yaml +43 -0
- package/data/rules/copywriting/copywriting-antithesis-frame.yaml +23 -0
- package/data/rules/copywriting/copywriting-artificial-balance.yaml +4 -1
- package/data/rules/copywriting/copywriting-boilerplate-offer.yaml +1 -1
- package/data/rules/copywriting/copywriting-canned-phrasing.yaml +1 -1
- package/data/rules/copywriting/copywriting-claim-without-evidence.yaml +10 -1
- package/data/rules/copywriting/copywriting-click-here-links.yaml +4 -3
- package/data/rules/copywriting/copywriting-conditions-first.yaml +2 -2
- package/data/rules/copywriting/copywriting-copula-avoidance.yaml +21 -0
- package/data/rules/copywriting/copywriting-dead-link.yaml +28 -0
- package/data/rules/copywriting/copywriting-em-dash-in-ui.yaml +23 -0
- package/data/rules/copywriting/copywriting-error-descriptions.yaml +2 -2
- package/data/rules/copywriting/copywriting-excessive-hedging.yaml +1 -1
- package/data/rules/copywriting/copywriting-external-arrow-internal-link.yaml +26 -0
- package/data/rules/copywriting/copywriting-fabricated-specificity.yaml +6 -3
- package/data/rules/copywriting/copywriting-filler-words.yaml +4 -3
- package/data/rules/copywriting/copywriting-generic-framing.yaml +12 -6
- package/data/rules/copywriting/copywriting-generic-language.yaml +12 -4
- package/data/rules/copywriting/copywriting-generic-validation.yaml +1 -1
- package/data/rules/copywriting/copywriting-latinisms.yaml +6 -4
- package/data/rules/copywriting/copywriting-machine-prose.yaml +4 -1
- package/data/rules/copywriting/copywriting-mechanism-over-outcome.yaml +4 -1
- package/data/rules/copywriting/copywriting-meta-commentary.yaml +1 -1
- package/data/rules/copywriting/copywriting-missing-reasoning-link.yaml +4 -1
- package/data/rules/copywriting/copywriting-nominalisations.yaml +4 -3
- package/data/rules/copywriting/copywriting-over-explanation.yaml +4 -1
- package/data/rules/copywriting/copywriting-participle-tail.yaml +21 -0
- package/data/rules/copywriting/copywriting-passive-voice.yaml +4 -3
- package/data/rules/copywriting/copywriting-promotional-docs-voice.yaml +4 -3
- package/data/rules/copywriting/copywriting-prompt-restatement.yaml +5 -2
- package/data/rules/copywriting/copywriting-punctuation-tics.yaml +4 -1
- package/data/rules/copywriting/copywriting-reader-first.yaml +4 -1
- package/data/rules/copywriting/copywriting-repetitive-transitions.yaml +1 -1
- package/data/rules/copywriting/copywriting-requirements-language.yaml +2 -2
- package/data/rules/copywriting/copywriting-searchable-headings.yaml +2 -2
- package/data/rules/copywriting/copywriting-semantic-links.yaml +2 -2
- package/data/rules/copywriting/copywriting-slogan-headings.yaml +27 -0
- package/data/rules/copywriting/copywriting-structural-symmetry.yaml +4 -1
- package/data/rules/copywriting/copywriting-tee-up.yaml +23 -0
- package/data/rules/copywriting/copywriting-temporal-words.yaml +4 -3
- package/data/rules/copywriting/copywriting-unexplained-action.yaml +5 -2
- package/data/rules/copywriting/copywriting-unnatural-polish.yaml +8 -5
- package/data/rules/copywriting/copywriting-unverifiable-proof.yaml +1 -1
- package/data/rules/copywriting/copywriting-vague-error.yaml +2 -0
- package/data/rules/craft/craft-atmosphere-gradient.yaml +28 -0
- package/data/rules/craft/craft-decoration-no-role.yaml +2 -1
- package/data/rules/craft/craft-decorative-ordinals.yaml +26 -0
- package/data/rules/craft/craft-default-indigo.yaml +28 -0
- package/data/rules/craft/craft-faux-product-chrome.yaml +4 -1
- package/data/rules/motion/motion-will-change-misuse.yaml +28 -0
- package/data/rules/product/product-nested-modals.yaml +1 -1
- package/data/rules/product/product-select-for-few-options.yaml +1 -1
- package/data/rules/schema/rule.schema.json +7 -1
- package/dist/cli.js +748 -131
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +38 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +459 -51
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/data/rules/copywriting/copywriting-idea-repetition.yaml +0 -34
|
@@ -9,7 +9,10 @@ source:
|
|
|
9
9
|
path: https://typesafe-parallel-judgment-lab.every-4573.chatgpt.site/downloads/typesafe-lab-source.zip (scripts/run-ai-checker.mjs)
|
|
10
10
|
line: 1
|
|
11
11
|
ruleId: over_explanation
|
|
12
|
-
|
|
12
|
+
# Prose wherever it is: a Markdown paragraph or a JSX sentence. Under five
|
|
13
|
+
# words is a label, button or greeting, not prose.
|
|
14
|
+
unit: [paragraph, jsx-text]
|
|
15
|
+
preconditions: { minWords: 5, notInCode: true }
|
|
13
16
|
question:
|
|
14
17
|
context: [docType]
|
|
15
18
|
instructions: >-
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Hand-cut from mblode/agent-skills skills/ghostwriter/references/tells.md (structure tells).
|
|
2
|
+
id: copywriting-participle-tail
|
|
3
|
+
title: Sentence ends in a participle tail
|
|
4
|
+
categoryId: machine-prose
|
|
5
|
+
source:
|
|
6
|
+
{
|
|
7
|
+
repo: mblode/agent-skills,
|
|
8
|
+
path: skills/ghostwriter/references/tells.md,
|
|
9
|
+
line: 16,
|
|
10
|
+
}
|
|
11
|
+
unit: [paragraph, jsx-text]
|
|
12
|
+
mechanical:
|
|
13
|
+
regex: "(?<![\"“‘']),\\s+(?:ensuring|highlighting|underscoring|showcasing|emphasi[sz]ing|reinforcing|cementing|solidifying|fostering|signall?ing)\\b"
|
|
14
|
+
flags: giu
|
|
15
|
+
severity: minor
|
|
16
|
+
fix:
|
|
17
|
+
hint: >-
|
|
18
|
+
Keep the fact and cut at the comma. "Tests run on every push, ensuring quality" becomes "Tests run on every push."
|
|
19
|
+
preconditions: { notInCode: true }
|
|
20
|
+
status: active
|
|
21
|
+
handWritten: [mechanical, fix, preconditions]
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
# Ported from mblode/agent-skills skills/docs-writing/rules/voice-defaults.md
|
|
1
|
+
# Ported from mblode/agent-skills skills/docs-writing/rules/voice-defaults.md, now
|
|
2
|
+
# skills/ghostwriter/references/docs.md after docs-writing was retired. (active voice, present tense).
|
|
2
3
|
id: copywriting-passive-voice
|
|
3
4
|
title: Passive voice where the actor is known
|
|
4
5
|
categoryId: machine-prose
|
|
5
6
|
source:
|
|
6
7
|
{
|
|
7
8
|
repo: mblode/agent-skills,
|
|
8
|
-
path: skills/
|
|
9
|
-
line:
|
|
9
|
+
path: skills/ghostwriter/references/docs.md,
|
|
10
|
+
line: 13,
|
|
10
11
|
}
|
|
11
12
|
unit: [paragraph, heading]
|
|
12
13
|
mechanical:
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
# Ported from mblode/agent-skills skills/docs-writing/rules/voice-defaults.md
|
|
1
|
+
# Ported from mblode/agent-skills skills/docs-writing/rules/voice-defaults.md, now
|
|
2
|
+
# skills/ghostwriter/references/docs.md after docs-writing was retired. (professional, not promotional).
|
|
2
3
|
id: copywriting-promotional-docs-voice
|
|
3
4
|
title: Marketing voice inside documentation
|
|
4
5
|
categoryId: evidence-over-claims
|
|
5
6
|
source:
|
|
6
7
|
{
|
|
7
8
|
repo: mblode/agent-skills,
|
|
8
|
-
path: skills/
|
|
9
|
-
line:
|
|
9
|
+
path: skills/ghostwriter/references/docs.md,
|
|
10
|
+
line: 13,
|
|
10
11
|
}
|
|
11
12
|
unit: [paragraph, heading]
|
|
12
13
|
mechanical:
|
|
@@ -10,11 +10,14 @@ source:
|
|
|
10
10
|
path: https://typesafe-parallel-judgment-lab.every-4573.chatgpt.site/downloads/typesafe-lab-source.zip (scripts/run-ai-checker.mjs)
|
|
11
11
|
line: 1
|
|
12
12
|
ruleId: prompt_restatement
|
|
13
|
-
|
|
13
|
+
# Prose wherever it is: a Markdown paragraph or a JSX sentence. Under five
|
|
14
|
+
# words is a label, button or greeting, not prose.
|
|
15
|
+
unit: [paragraph, jsx-text]
|
|
16
|
+
preconditions: { minWords: 5, notInCode: true }
|
|
14
17
|
question:
|
|
15
18
|
context: [docType]
|
|
16
19
|
instructions: >-
|
|
17
|
-
Does the writing read like it is restating an implied prompt or assignment? Ignore a heading or a stated question the passage then answers.
|
|
20
|
+
Does the writing read like it is restating an implied prompt or assignment? Ignore a heading or a stated question the passage then answers. Return false for a greeting, a sign-off, a button or link label, a bare list label, or a heading on its own: they are not prose.
|
|
18
21
|
criteria:
|
|
19
22
|
true:
|
|
20
23
|
what: The passage announces the task it was given instead of doing it.
|
|
@@ -10,7 +10,10 @@ source:
|
|
|
10
10
|
path: https://typesafe-parallel-judgment-lab.every-4573.chatgpt.site/downloads/typesafe-lab-source.zip (scripts/run-ai-checker.mjs)
|
|
11
11
|
line: 1
|
|
12
12
|
ruleId: punctuation_tics
|
|
13
|
-
|
|
13
|
+
# Prose wherever it is: a Markdown paragraph or a JSX sentence. Under five
|
|
14
|
+
# words is a label, button or greeting, not prose.
|
|
15
|
+
unit: [paragraph, jsx-text]
|
|
16
|
+
preconditions: { minWords: 5, notInCode: true }
|
|
14
17
|
question:
|
|
15
18
|
context: [docType]
|
|
16
19
|
instructions: >-
|
|
@@ -27,17 +27,20 @@ mechanical:
|
|
|
27
27
|
we made,
|
|
28
28
|
the tool,
|
|
29
29
|
a tool,
|
|
30
|
+
now with,
|
|
31
|
+
now available,
|
|
30
32
|
]
|
|
31
33
|
question:
|
|
32
34
|
context: [docType, headingAbove]
|
|
33
35
|
instructions: >-
|
|
34
|
-
The TEXT is a headline or hero line on a page selling or introducing a product. Return true when it opens by naming what the product is (a platform, a tool, a solution, "Introducing X") before saying why that matters to the reader. Return false when it leads with the reader's problem or outcome, when the DOC TYPE is documentation, reference or a lesson where naming the thing first is correct, or when it is not a headline.
|
|
36
|
+
The TEXT is a headline or hero line on a page selling or introducing a product. Return true when it opens by naming what the product is (a platform, a tool, a solution, "Introducing X") or what it now has ("Now with X") before saying why that matters to the reader. Return false when it leads with the reader's problem or outcome, when the DOC TYPE is documentation, reference or a lesson where naming the thing first is correct, or when it is not a headline.
|
|
35
37
|
criteria:
|
|
36
38
|
true:
|
|
37
39
|
what: What-first headline.
|
|
38
40
|
examples:
|
|
39
41
|
- "Introducing Northwind, the all-in-one platform for modern teams"
|
|
40
42
|
- "A collaboration tool for growing companies"
|
|
43
|
+
- "Now with dark mode"
|
|
41
44
|
false:
|
|
42
45
|
what: Why-first, or a context where What belongs first.
|
|
43
46
|
examples:
|
|
@@ -10,7 +10,7 @@ source:
|
|
|
10
10
|
path: https://typesafe-parallel-judgment-lab.every-4573.chatgpt.site/downloads/typesafe-lab-source.zip (scripts/run-ai-checker.mjs)
|
|
11
11
|
line: 1
|
|
12
12
|
ruleId: repetitive_transitions
|
|
13
|
-
unit: [paragraph]
|
|
13
|
+
unit: [paragraph, jsx-text]
|
|
14
14
|
mechanical:
|
|
15
15
|
phrases:
|
|
16
16
|
- moreover
|
|
@@ -3,8 +3,8 @@ title: A requirement presented as a recommendation
|
|
|
3
3
|
categoryId: reader-first-framing
|
|
4
4
|
source:
|
|
5
5
|
repo: mblode/agent-skills
|
|
6
|
-
path: skills/
|
|
7
|
-
line:
|
|
6
|
+
path: skills/ghostwriter/references/docs.md
|
|
7
|
+
line: 13
|
|
8
8
|
ruleId: voice-requirements-language
|
|
9
9
|
unit:
|
|
10
10
|
- paragraph
|
|
@@ -3,8 +3,8 @@ title: A documentation heading names no topic or action
|
|
|
3
3
|
categoryId: page-structure
|
|
4
4
|
source:
|
|
5
5
|
repo: mblode/agent-skills
|
|
6
|
-
path: skills/
|
|
7
|
-
line:
|
|
6
|
+
path: skills/ghostwriter/references/docs.md
|
|
7
|
+
line: 21
|
|
8
8
|
ruleId: nav-searchable-headings
|
|
9
9
|
unit:
|
|
10
10
|
- heading
|
|
@@ -4,7 +4,7 @@ id: copywriting-semantic-links
|
|
|
4
4
|
title: Use Semantic Links for Navigation
|
|
5
5
|
categoryId: page-structure
|
|
6
6
|
source:
|
|
7
|
-
line:
|
|
7
|
+
line: 10
|
|
8
8
|
path: skills/ui-design/rules/nav-semantic-links.md
|
|
9
9
|
repo: mblode/agent-skills
|
|
10
10
|
ruleId: nav-semantic-links
|
|
@@ -26,4 +26,4 @@ review:
|
|
|
26
26
|
exceptions: A redundant card shortcut around an accessible real link can be intentional.
|
|
27
27
|
evidence: The actual destination, nested links, handler behavior, and keyboard or browser navigation options.
|
|
28
28
|
verification: Verify keyboard navigation, open-in-new-tab, and copy-link behavior while preserving legitimate larger click targets.
|
|
29
|
-
sourceHash:
|
|
29
|
+
sourceHash: 156607414ec8464ecc9e40d0441c9242ec94547f5de51ed83d04d6333c305470
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Hand-ported: the upstream rg pattern, narrowed to heading text. The
|
|
2
|
+
# "X, not Y" heading is copywriting-antithesis-contrast.
|
|
3
|
+
id: copywriting-slogan-headings
|
|
4
|
+
title: Headings built from stacked slogan fragments
|
|
5
|
+
categoryId: machine-prose
|
|
6
|
+
source:
|
|
7
|
+
repo: mblode/agent-skills
|
|
8
|
+
path: skills/ui-design/rules/slop-slogan-headings.md
|
|
9
|
+
line: 10
|
|
10
|
+
ruleId: slop-slogan-headings
|
|
11
|
+
scope:
|
|
12
|
+
include: ["**/*.tsx", "**/*.jsx"]
|
|
13
|
+
unit: [source]
|
|
14
|
+
mechanical:
|
|
15
|
+
regex: '<h[1-3]\b[^>]*>(?:\s|<br\s*/>|<span[^>]*>|</span>)*[A-Z$\d][\w’''$,-]*(?:[ \t]+[\w’''$,-]+){0,3}[.!?](?:\s|<br\s*/>|<span[^>]*>|</span>)+[A-Z$\d][\w’''$,-]*(?:[ \t]+[\w’''$,-]+){0,3}[.!?]'
|
|
16
|
+
flags: gu
|
|
17
|
+
severity: minor
|
|
18
|
+
fix:
|
|
19
|
+
hint: Say the one thing the product does in a plain sentence a reader could check, instead of two or three clipped fragments.
|
|
20
|
+
status: review-only
|
|
21
|
+
review:
|
|
22
|
+
applicability: "A heading made of two or more clipped sentences of four words or fewer."
|
|
23
|
+
exceptions: "A real name or a quoted title, and a pair of short sentences that each state a checkable fact."
|
|
24
|
+
evidence: "Whether each fragment says something a reader could verify about the product."
|
|
25
|
+
verification: "Confirm the fragments carry no checkable claim, then rewrite as one plain sentence."
|
|
26
|
+
sourceHash: 253bbb9dd01304ad87bb0b924a6dd434780c829cec8a0fe91a4b149446fed284
|
|
27
|
+
handWritten: [mechanical]
|
|
@@ -10,7 +10,10 @@ source:
|
|
|
10
10
|
path: https://typesafe-parallel-judgment-lab.every-4573.chatgpt.site/downloads/typesafe-lab-source.zip (scripts/run-ai-checker.mjs)
|
|
11
11
|
line: 1
|
|
12
12
|
ruleId: structural_symmetry
|
|
13
|
-
|
|
13
|
+
# Prose wherever it is: a Markdown paragraph or a JSX sentence. Under five
|
|
14
|
+
# words is a label, button or greeting, not prose.
|
|
15
|
+
unit: [paragraph, jsx-text]
|
|
16
|
+
preconditions: { minWords: 5, notInCode: true }
|
|
14
17
|
question:
|
|
15
18
|
context: [docType]
|
|
16
19
|
instructions: >-
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Widened 2026-09-23 with the tee-ups Opus, Fable and Grok wrote in the
|
|
2
|
+
# generation test.
|
|
3
|
+
# Hand-cut from mblode/agent-skills skills/ghostwriter/references/tells.md (structure tells).
|
|
4
|
+
id: copywriting-tee-up
|
|
5
|
+
title: Tees up a point instead of stating it
|
|
6
|
+
categoryId: machine-prose
|
|
7
|
+
source:
|
|
8
|
+
{
|
|
9
|
+
repo: mblode/agent-skills,
|
|
10
|
+
path: skills/ghostwriter/references/tells.md,
|
|
11
|
+
line: 15,
|
|
12
|
+
}
|
|
13
|
+
unit: [paragraph, jsx-text]
|
|
14
|
+
mechanical:
|
|
15
|
+
regex: "(?<![\"“‘'])\\bhere['’]s the (?:thing|kicker|catch|deal|twist)\\b|(?<![\"“‘'])\\bthe (?:kicker|catch|twist)\\?|(?<![\"“‘'])\\bwhat struck me (?:was|is)\\b|(?<![\"“‘'])\\blet that sink in\\b|(?<![\"“‘'])\\bhere['’]s (?:a quick way to|the short version)\\b|(?<![\"“‘'])\\bthe part worth knowing\\b|(?<![\"“‘'])\\bthat['’]s the whole (?:pitch|idea|point|story)\\b"
|
|
16
|
+
flags: giu
|
|
17
|
+
severity: minor
|
|
18
|
+
fix:
|
|
19
|
+
hint: >-
|
|
20
|
+
Delete the tee-up and state the thing.
|
|
21
|
+
preconditions: { notInCode: true }
|
|
22
|
+
status: active
|
|
23
|
+
handWritten: [mechanical, fix, preconditions]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
# Ported from mblode/agent-skills skills/docs-writing/rules/hygiene-no-temporal.md
|
|
1
|
+
# Ported from mblode/agent-skills skills/docs-writing/rules/hygiene-no-temporal.md, now
|
|
2
|
+
# skills/ghostwriter/references/docs.md after docs-writing was retired. and
|
|
2
3
|
# rules/hygiene-update-metadata.md.
|
|
3
4
|
id: copywriting-temporal-words
|
|
4
5
|
title: Wording anchored to the time of writing
|
|
@@ -6,8 +7,8 @@ categoryId: reference-reading
|
|
|
6
7
|
source:
|
|
7
8
|
{
|
|
8
9
|
repo: mblode/agent-skills,
|
|
9
|
-
path: skills/
|
|
10
|
-
line:
|
|
10
|
+
path: skills/ghostwriter/references/docs.md,
|
|
11
|
+
line: 23,
|
|
11
12
|
}
|
|
12
13
|
unit: [paragraph, heading]
|
|
13
14
|
mechanical:
|
|
@@ -8,11 +8,14 @@ source:
|
|
|
8
8
|
repo: every.to
|
|
9
9
|
path: https://every.to/also-true-for-humans/mini-vibe-check-typesafe-s-jev-judged-everything-i-ve-written-in-0-7-seconds
|
|
10
10
|
line: 1
|
|
11
|
-
|
|
11
|
+
# Prose wherever it is: a Markdown paragraph or a JSX sentence. Under five
|
|
12
|
+
# words is a label, button or greeting, not prose.
|
|
13
|
+
unit: [paragraph, jsx-text]
|
|
14
|
+
preconditions: { minWords: 5, notInCode: true }
|
|
12
15
|
question:
|
|
13
16
|
context: [docType]
|
|
14
17
|
instructions: >-
|
|
15
|
-
Read the TEXT. Return true when it asks the reader to do, or describes someone doing, an action whose concrete steps cannot be pictured from the words (teach a calendar, activate the culture, leverage the learnings). Return false when the action names a thing a person could start doing now, or when the TEXT is a heading or label that a following paragraph will explain.
|
|
18
|
+
Read the TEXT. Return true when it asks the reader to do, or describes someone doing, an action whose concrete steps cannot be pictured from the words (teach a calendar, activate the culture, leverage the learnings). Return false when the action names a thing a person could start doing now, or when the TEXT is a heading or label that a following paragraph will explain, a button label, or a numbered step in a procedure.
|
|
16
19
|
criteria:
|
|
17
20
|
true:
|
|
18
21
|
what: An action with no picturable steps.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# One of the 21 AI-writing checks Every ran with Jev (Mike Taylor, "Jev judged
|
|
2
|
-
# everything I've written in 0.7 seconds", 15 Sep 2026). The question
|
|
3
|
-
# published wording;
|
|
2
|
+
# everything I've written in 0.7 seconds", 15 Sep 2026). The question started as
|
|
3
|
+
# the published wording; it now also says what cannot be a violation, because
|
|
4
|
+
# Jev read plain labels, identifiers and instructions as violations (2026-09-23 eval).
|
|
4
5
|
# Candidate list from EveryInc/compound-writing skills/cw-ai-check/SKILL.md, category 0 (structural overcompletion, performed voice).
|
|
5
6
|
id: copywriting-unnatural-polish
|
|
6
7
|
title: Polished in a way that suppresses personal texture
|
|
@@ -27,18 +28,20 @@ preconditions:
|
|
|
27
28
|
question:
|
|
28
29
|
context: [docType]
|
|
29
30
|
instructions: >-
|
|
30
|
-
|
|
31
|
+
Is the writing polished in a way that suppresses personal texture: smooth, abstract praise or summary where a specific fact, opinion or rough edge should be? Neutral, plain writing is not polish. Answer no for instructions, technical explanation, data, labels, names, identifiers and headings, and for any sentence that states a concrete fact, number or opinion, even if no person is visible. Ignore reference documentation and UI copy, where a neutral register is the point.
|
|
31
32
|
criteria:
|
|
32
33
|
true:
|
|
33
|
-
what: Even, frictionless prose
|
|
34
|
+
what: Even, frictionless prose that smooths over what should be specific.
|
|
34
35
|
examples:
|
|
35
36
|
- "The initiative delivered meaningful improvements across several dimensions, and stakeholders responded positively to the enhanced experience."
|
|
36
37
|
- "Each component was carefully considered to ensure a cohesive, thoughtful result that balances form and function."
|
|
37
38
|
false:
|
|
38
|
-
what: Prose with a specific person, opinion or rough edge in it.
|
|
39
|
+
what: Prose with a specific fact, person, opinion or rough edge in it, or plain functional text.
|
|
39
40
|
examples:
|
|
40
41
|
- "I hated the old settings page. It had 14 toggles and I could never remember which one hid the sidebar."
|
|
41
42
|
- "The first version was ugly and we shipped it anyway, because the two people who needed it were waiting."
|
|
43
|
+
- "Run commands from the repository root:"
|
|
44
|
+
- "Each enabled scout runs once per day and draws from the 24-run daily budget."
|
|
42
45
|
thresholds: { review: 0.4, act: 0.75 }
|
|
43
46
|
severity: minor
|
|
44
47
|
fix:
|
|
@@ -26,4 +26,4 @@ review:
|
|
|
26
26
|
exceptions: Clearly labeled placeholders, teaching examples, chart data, and claims supported by supplied evidence.
|
|
27
27
|
evidence: The exact claim and location, its displayed context, and a checkable source or an accountable owner.
|
|
28
28
|
verification: Verify the claim against its source or remove only the unsupported claim; preserve real evidence and clearly marked examples.
|
|
29
|
-
sourceHash:
|
|
29
|
+
sourceHash: fd0234fa235214885b51d0645416a224ec35fa32d3990bba46817f6c13932aba
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Hand-cut from mblode/agent-skills skills/ui-design/direction/aesthetic-direction.md (slop signals).
|
|
2
|
+
id: craft-atmosphere-gradient
|
|
3
|
+
title: Purple or cyan gradient used as atmosphere
|
|
4
|
+
categoryId: generic-decoration
|
|
5
|
+
source:
|
|
6
|
+
{
|
|
7
|
+
repo: mblode/agent-skills,
|
|
8
|
+
path: skills/ui-design/direction/aesthetic-direction.md,
|
|
9
|
+
line: 12,
|
|
10
|
+
}
|
|
11
|
+
scope:
|
|
12
|
+
include: ["**/*.tsx", "**/*.jsx"]
|
|
13
|
+
unit: [source]
|
|
14
|
+
mechanical:
|
|
15
|
+
regex: "\\bbg-(?:gradient-to|linear-to|radial)-?[\\w-]*[^\"'`\\n]*?\\b(?:from|via|to)-(?:purple|violet|fuchsia|indigo|cyan)-\\d{2,3}\\b|\\b(?:from|via)-(?:purple|violet|fuchsia|indigo|cyan)-\\d{2,3}\\b[^\"'`\\n]*?\\bbg-(?:gradient-to|linear-to|radial)"
|
|
16
|
+
flags: gu
|
|
17
|
+
severity: minor
|
|
18
|
+
fix:
|
|
19
|
+
hint: >-
|
|
20
|
+
Give the surface a content or brand role, or remove the gradient. Purple and cyan washes are the most common AI-generated backdrop.
|
|
21
|
+
status: review-only
|
|
22
|
+
review:
|
|
23
|
+
applicability: A class list pairs a gradient background with purple, violet, fuchsia, indigo or cyan stops.
|
|
24
|
+
exceptions: Brand colours, data visualisation ramps, and illustrations where the gradient carries meaning.
|
|
25
|
+
evidence: The brand palette and what the gradient surface contains.
|
|
26
|
+
verification: Confirm the gradient carries a brand or content role, or replace it with a flat surface from the theme.
|
|
27
|
+
sourceHash: fd4edd9d4dc8f0ec9c09c49390e37482535f899972c5d7c15c9d8f1344360f82
|
|
28
|
+
handWritten: [mechanical, fix, review, scope]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# The mechanical regex is widened from the source: an empty element hung off the box by a negative offset counts as decorative, and so does a large bordered ring (GPT-6 and Opus output, 2026-09-23).
|
|
1
2
|
id: craft-decoration-no-role
|
|
2
3
|
title: Stacked decorative layers with no role
|
|
3
4
|
categoryId: generic-decoration
|
|
@@ -14,7 +15,7 @@ unit:
|
|
|
14
15
|
- source
|
|
15
16
|
mechanical:
|
|
16
17
|
flags: gus
|
|
17
|
-
regex: <(?:div|span)\b(?=[^>]*?(?:\babsolute\b|\bfixed\b))(?=[^>]*?(?:pointer-events-none|aria-hidden))(?=[^>]*?(?:gradient|bg-linear|bg-radial|\bblur|backdrop-blur|mix-blend|opacity-))(?![^>]*?(?:size-\[max\(100%|pointer-fine:hidden|bg-clip-text|\bmask-))[^>]*?/>
|
|
18
|
+
regex: '<(?:div|span)\b(?=[^>]*?(?:\babsolute\b|\bfixed\b))(?=[^>]*?(?:pointer-events-none|aria-hidden|["\s]-(?:inset|top|right|bottom|left)-(?:[2-9]|\d{2})\b))(?=[^>]*?(?:gradient|bg-linear|bg-radial|\bblur|backdrop-blur|mix-blend|opacity-|(?=[^>]*?\brounded-full\b)(?=[^>]*?\bborder\b)(?=[^>]*?\b(?:h|w|size)-(?:[2-9]\d|\d{3})\b)))(?![^>]*?(?:size-\[max\(100%|pointer-fine:hidden|bg-clip-text|\bmask-))[^>]*?/>'
|
|
18
19
|
severity: minor
|
|
19
20
|
fix:
|
|
20
21
|
hint: "A blurred blob, a grid overlay, a noise layer and a radial glow behind the heading: absolutely positioned elements that contain nothing and mean nothing. Cut them until each remaining layer has a job a reader could name."
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Hand-ported: the upstream rg pattern, narrowed to JSX text.
|
|
2
|
+
id: craft-decorative-ordinals
|
|
3
|
+
title: Ordinal numbers on items that are not a sequence
|
|
4
|
+
categoryId: generic-decoration
|
|
5
|
+
source:
|
|
6
|
+
repo: mblode/agent-skills
|
|
7
|
+
path: skills/ui-design/rules/slop-decorative-ordinals.md
|
|
8
|
+
line: 10
|
|
9
|
+
ruleId: slop-decorative-ordinals
|
|
10
|
+
scope:
|
|
11
|
+
include: ["**/*.tsx", "**/*.jsx"]
|
|
12
|
+
unit: [source]
|
|
13
|
+
mechanical:
|
|
14
|
+
regex: '\b(?:number|num|step|index|idx|no|label|eyebrow)\s*:\s*["''`]0[1-9]\b|>\s*0[1-9]\s*[./)]?\s*<'
|
|
15
|
+
flags: gu
|
|
16
|
+
severity: minor
|
|
17
|
+
fix:
|
|
18
|
+
hint: Drop the numbers unless the order is real (install steps, a setup flow, a fallback chain). Cards a reader could shuffle need no number.
|
|
19
|
+
status: review-only
|
|
20
|
+
review:
|
|
21
|
+
applicability: "Zero-padded numbers label cards or sections."
|
|
22
|
+
exceptions: "A real sequence: install steps, a setup flow, a ranked list, a fallback chain."
|
|
23
|
+
evidence: "Whether the items could be reordered without changing their meaning."
|
|
24
|
+
verification: "Confirm the order means nothing, then remove the numbers."
|
|
25
|
+
sourceHash: ae618ad62bb446ec2c7019f60acfe8ca48d1f5adea14ba6286463446cf596be9
|
|
26
|
+
handWritten: [mechanical]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Hand-cut from mblode/agent-skills skills/ui-design/guidelines/colors.md.
|
|
2
|
+
id: craft-default-indigo
|
|
3
|
+
title: Indigo accent that looks like a template default
|
|
4
|
+
categoryId: colour-system
|
|
5
|
+
source:
|
|
6
|
+
{
|
|
7
|
+
repo: mblode/agent-skills,
|
|
8
|
+
path: skills/ui-design/guidelines/colors.md,
|
|
9
|
+
line: 5,
|
|
10
|
+
}
|
|
11
|
+
scope:
|
|
12
|
+
include: ["**/*.tsx", "**/*.jsx", "**/*.css"]
|
|
13
|
+
unit: [source]
|
|
14
|
+
mechanical:
|
|
15
|
+
regex: "\\b(?:bg|text|border|ring|from|via|to|fill|stroke|outline|accent|shadow|decoration)-indigo-\\d{2,3}\\b"
|
|
16
|
+
flags: gu
|
|
17
|
+
severity: minor
|
|
18
|
+
fix:
|
|
19
|
+
hint: >-
|
|
20
|
+
Pick an accent from the brand, or use the theme's primary token. Indigo is the colour every starter template ships with.
|
|
21
|
+
status: review-only
|
|
22
|
+
review:
|
|
23
|
+
applicability: Components use Tailwind indigo classes as the accent colour.
|
|
24
|
+
exceptions: A brand that is indigo, or a project whose theme already standardises on indigo.
|
|
25
|
+
evidence: The brand colour in the theme or design tokens, and how many components use indigo.
|
|
26
|
+
verification: Confirm indigo is the brand choice, or replace it with the theme's primary token.
|
|
27
|
+
sourceHash: cdd85836ef30c0827d41e0a07ed549a3b5a3d120b6f1aa39cf259aff87a8d0e8
|
|
28
|
+
handWritten: [mechanical, fix, review, scope]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# Ported from mblode/agent-skills skills/ui-design/rules/slop-faux-product-chrome.md by scripts/port-rules.ts.
|
|
2
|
+
# The mechanical regex is widened from the source: three adjacent empty dots of any colour (Opus, Astra and Sol drew them in pastel and hex, 2026-09-23).
|
|
2
3
|
# Keys listed in handWritten are preserved on re-run; everything else is regenerated.
|
|
3
4
|
id: craft-faux-product-chrome
|
|
4
5
|
title: Faux product chrome wrapping nothing
|
|
@@ -15,11 +16,13 @@ unit:
|
|
|
15
16
|
- source
|
|
16
17
|
mechanical:
|
|
17
18
|
flags: gu
|
|
18
|
-
regex:
|
|
19
|
+
regex: '(?:<(?:span|div|i)\b(?=[^>]*\brounded-full\b)(?=[^>]*\b(?:size|h)-(?:1|1\.5|2|2\.5|3|3\.5)\b)[^>]*/>\s*){3}'
|
|
19
20
|
severity: minor
|
|
20
21
|
fix:
|
|
21
22
|
hint: "Three coloured dots in a row, a rounded bar with a URL typed into it, a laptop outline around an empty gradient panel: this is a drawing of a product where the product should be. A visitor reads it as a screenshot, leans in to see what the app actually looks like, and finds there is nothing to see. "
|
|
22
23
|
status: review-only
|
|
24
|
+
handWritten:
|
|
25
|
+
- mechanical
|
|
23
26
|
review:
|
|
24
27
|
applicability: Decorative browser or device chrome presents itself as a product preview.
|
|
25
28
|
exceptions: Real screenshots, video, rendered product content, labeled status dots, and intentionally illustrative examples.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Hand-cut from mblode/agent-skills skills/ui-animation/references/performance-deep-dive.md.
|
|
2
|
+
id: motion-will-change-misuse
|
|
3
|
+
title: will-change promotes a property the compositor cannot animate
|
|
4
|
+
categoryId: motion-restraint
|
|
5
|
+
source:
|
|
6
|
+
{
|
|
7
|
+
repo: mblode/agent-skills,
|
|
8
|
+
path: skills/ui-animation/references/performance-deep-dive.md,
|
|
9
|
+
line: 161,
|
|
10
|
+
}
|
|
11
|
+
scope:
|
|
12
|
+
include: ["**/*.css", "**/*.scss", "**/*.tsx", "**/*.jsx"]
|
|
13
|
+
unit: [source]
|
|
14
|
+
mechanical:
|
|
15
|
+
regex: "will-change\\s*:\\s*[\"'`]?(?!\\s*(?:transform|opacity|auto)\\s*[\"'`]?\\s*[;},!])[a-z-]+|\\bwill-change-(?:scroll|contents|\\[(?!transform|opacity)[^\\]]+\\])"
|
|
16
|
+
flags: giu
|
|
17
|
+
severity: minor
|
|
18
|
+
fix:
|
|
19
|
+
hint: >-
|
|
20
|
+
Promote only transform or opacity, and only while the motion runs. Each promoted layer costs compositor memory.
|
|
21
|
+
status: review-only
|
|
22
|
+
review:
|
|
23
|
+
applicability: A stylesheet or class list sets will-change to a property other than transform or opacity.
|
|
24
|
+
exceptions: Measured scroll-performance fixes with a comment explaining the choice.
|
|
25
|
+
evidence: The declaration, the element it applies to, and whether it is toggled around the animation.
|
|
26
|
+
verification: Restrict will-change to transform or opacity and set it only during the animation.
|
|
27
|
+
sourceHash: f3f43c733bac58c4e64f13c769f7a360c39c0d446c886f79d929e76ae8b5fdfc
|
|
28
|
+
handWritten: [mechanical, fix, review, scope]
|
|
@@ -29,4 +29,4 @@ review:
|
|
|
29
29
|
exceptions: JSX nesting alone does not prove simultaneous visibility; mutually exclusive steps and nonmodal surfaces are exceptions.
|
|
30
30
|
evidence: Both open-state transitions, modal primitive implementations, and focus and Escape behavior.
|
|
31
31
|
verification: Open the second step using the keyboard; confirm one modal owns focus and Escape closes the intended surface.
|
|
32
|
-
sourceHash:
|
|
32
|
+
sourceHash: 9aab069ba1b93ab405a9741cd6d1e026eb08442ff881587b4f84a612653a2fbb
|
|
@@ -27,4 +27,4 @@ review:
|
|
|
27
27
|
exceptions: Dynamically loaded options, dependent choices, or a documented platform constraint can require a select.
|
|
28
28
|
evidence: The complete option source, dynamic branches, and the task requiring comparison.
|
|
29
29
|
verification: Confirm all choices remain available and selection, keyboard input, and form submission work.
|
|
30
|
-
sourceHash:
|
|
30
|
+
sourceHash: 9aab069ba1b93ab405a9741cd6d1e026eb08442ff881587b4f84a612653a2fbb
|
|
@@ -127,7 +127,9 @@
|
|
|
127
127
|
"writingFacts",
|
|
128
128
|
"writingProfile",
|
|
129
129
|
"writingInstructions",
|
|
130
|
-
"section"
|
|
130
|
+
"section",
|
|
131
|
+
"earlier",
|
|
132
|
+
"brief"
|
|
131
133
|
]
|
|
132
134
|
}
|
|
133
135
|
},
|
|
@@ -224,6 +226,10 @@
|
|
|
224
226
|
},
|
|
225
227
|
"smartQuotesAtBuild": {
|
|
226
228
|
"const": false
|
|
229
|
+
},
|
|
230
|
+
"minWords": {
|
|
231
|
+
"type": "integer",
|
|
232
|
+
"minimum": 1
|
|
227
233
|
}
|
|
228
234
|
}
|
|
229
235
|
},
|