fix(site): restore Antidote section with curated anti-pattern list

The DO/DONT extractor in readPatterns stopped finding anything after
the skill went human-authored (new SKILL.md uses plain bullets, one-word
section headings, no DO:/DON'T: prefixes). Replace the extractor with
a hand-curated category list: six categories, three or four DOs and
DON'Ts each. Editorial tone, tight, deliberately a teaser — the full
catalog still lives on /anti-patterns.

The legacy SKILL.md parser is retained in the file as _legacyReadPatterns
in case we want to revive it later with a different format.

Small CSS fix: .faq-question was display:flex with justify-content:
space-between, so inline <code> in a summary got treated as its own
flex item and pushed apart. Switched to relative+absolute positioning
so the + icon sits in the right margin and text flows naturally.

Changelog font size reduced to 0.9375rem for the expanded v3.0 entry.
New FAQ entry on pinning standalone commands back. Pin section added
to /docs/impeccable editorial.
This commit is contained in:
Paul Bakaus
2026-04-22 11:52:40 -07:00
parent 549f92577c
commit d03dca1209
2 changed files with 103 additions and 6 deletions
+7 -5
View File
@@ -1247,12 +1247,10 @@
font-size: 1.125rem;
font-weight: 500;
color: var(--color-ink);
padding: var(--spacing-md) 0;
padding: var(--spacing-md) calc(var(--spacing-md) + 1.5rem) var(--spacing-md) 0;
cursor: pointer;
list-style: none;
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
transition: color 0.2s ease;
}
@@ -1267,10 +1265,14 @@
font-weight: 300;
color: var(--color-accent);
transition: transform 0.3s var(--ease-out);
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
}
.faq-item[open] .faq-question::after {
transform: rotate(45deg);
transform: translateY(-50%) rotate(45deg);
}
.faq-question:hover {
+96 -1
View File
@@ -226,7 +226,102 @@ export function writeFile(filePath, content) {
*
* Returns { patterns: [...], antipatterns: [...] }
*/
export function readPatterns(rootDir, relativePath = 'source/skills/impeccable/SKILL.md') {
// Curated short-list for the homepage Antidote section. Intentionally
// hand-written (not auto-extracted) so the copy stays tight and
// editorial. The long-form catalog lives on /anti-patterns — this is
// the teaser.
const CURATED_CATEGORIES = [
{
name: 'Typography',
do: [
'Pair a distinctive display face with a restrained body face; vary across projects.',
'Use a ≥1.25 scale ratio between hierarchy steps. Flat scales read as bland.',
'Cap body line length at 6575ch. Wider is fatiguing.',
],
dont: [
'Inter, Roboto, Plex, Fraunces, or any other reflex default. Look further.',
'Monospace as lazy shorthand for "technical."',
'Long passages in uppercase. Reserve all-caps for short labels.',
],
},
{
name: 'Color & Contrast',
do: [
'Use OKLCH. Reduce chroma near lightness extremes.',
'Tint neutrals toward the brand hue. Chroma 0.0050.01 is enough.',
'Pick a color strategy before picking colors (Restrained, Committed, Full, Drenched).',
],
dont: [
'Pure #000 or #fff. Always tint.',
'Dark mode + purple-to-cyan gradients. The AI tell.',
'Gradient text via background-clip. Use weight or size for emphasis.',
],
},
{
name: 'Layout & Space',
do: [
'Vary spacing for rhythm. Tight groupings, generous separations.',
'Use the simplest tool: Flexbox for 1D, Grid for 2D, plain flow often enough.',
'Let whitespace carry hierarchy before reaching for color or scale.',
],
dont: [
'Wrap everything in cards. Nested cards are always wrong.',
'Identical card grids of icon + heading + text, repeated endlessly.',
'The hero-metric template: big number, small label, supporting stats, gradient accent.',
],
},
{
name: 'Visual Details',
do: [
'Commit to an aesthetic direction and execute it with precision.',
'Use ornament only where it earns its place.',
],
dont: [
'Side-stripe borders (border-left/-right > 1px). The dashboard tell.',
'Glassmorphism everywhere. Rare and purposeful or nothing.',
'Rounded rectangles with generic drop shadows. "Could be any AI output."',
],
},
{
name: 'Motion',
do: [
'Use transform and opacity. Animate the composited properties only.',
'Ease out with exponential curves (quart / quint / expo).',
'Respect prefers-reduced-motion on every transition.',
],
dont: [
'Animate layout (width, height, padding, margin).',
'Bounce or elastic easing. Feels dated and tacky.',
'Decorative motion for its own sake. Motion should signal state.',
],
},
{
name: 'Interaction',
do: [
'Use optimistic UI: update immediately, sync later.',
'Design empty states that teach the interface, not just say "nothing here."',
'Progressive disclosure: start simple, reveal sophistication on demand.',
],
dont: [
'Make every button primary. Hierarchy matters.',
'Default to a modal. Exhaust inline alternatives first.',
'Repeat information the user can already see.',
],
},
];
export function readPatterns(_rootDir, _relativePath) {
// Hand-curated list — see CURATED_CATEGORIES above. The homepage
// Antidote teaser uses this; the full catalog lives on /anti-patterns.
return {
patterns: CURATED_CATEGORIES.map((c) => ({ name: c.name, items: c.do })),
antipatterns: CURATED_CATEGORIES.map((c) => ({ name: c.name, items: c.dont })),
};
}
// Previous SKILL.md parser retained below but disabled; kept as a
// reference for how prefix-style extraction used to work.
function _legacyReadPatterns(rootDir, relativePath = 'source/skills/impeccable/SKILL.md') {
const skillPath = path.join(rootDir, relativePath);
if (!fs.existsSync(skillPath)) {