Add new design context document

This commit is contained in:
Abdul Wahab
2026-09-01 10:06:21 +05:00
parent bba73a2283
commit a5cf9266e6
58 changed files with 7397 additions and 569 deletions
+17 -1
View File
@@ -1,9 +1,11 @@
#!/usr/bin/env node
import { execFileSync } from 'node:child_process';
import { cp, copyFile, mkdir, rm } from 'node:fs/promises';
import { cp, copyFile, mkdir, rm, writeFile } from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { ANTIPATTERNS } from '../cli/engine/registry/antipatterns.mjs';
import { composeHookRules } from './lib/hook-rule-presentation.js';
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const buildDir = path.join(root, 'build-picker');
@@ -16,6 +18,10 @@ const outputDir = path.join(root, 'skill/scripts/picker');
const assetsSource = path.join(root, 'picker/assets');
const assetsOutput = path.join(outputDir, 'assets');
const runtimeAssets = ['hero-dark.jpg', 'kinpaku-gold-leaf.jpg'];
// The design context document's images, vendored from the standalone demo:
// per-section foil icons, the rail textures, the brand-asset placeholders, and
// the components photo. Whole directories, so a demo re-sync stays a plain copy.
const runtimeAssetDirs = ['audience', 'product', 'brand', 'color', 'typography', 'material', 'components'];
// The page links ./favicon.svg, so it is also served from the output root.
const faviconSource = path.join(assetsSource, 'favicon.svg');
const faviconOutput = path.join(outputDir, 'favicon.svg');
@@ -26,6 +32,13 @@ const iconDataSource = path.join(root, 'picker/data/icon-packs.json');
const iconDataOutput = path.join(outputDir, 'icon-packs.json');
await rm(buildDir, { recursive: true, force: true });
// The Hooks page's rule list, composed from the canonical detector registry so
// the document never drifts from what the hook actually enforces. Committed and
// regenerated every build; tests/hook-rule-presentation.test.js guards the sync.
await writeFile(
path.join(root, 'picker/data/hook-rules.json'),
`${JSON.stringify(composeHookRules(ANTIPATTERNS), null, 2)}\n`,
);
execFileSync(
'bun',
['x', 'astro', 'build', '--config', 'picker/astro.config.mjs'],
@@ -40,6 +53,9 @@ await copyFile(iconDataSource, iconDataOutput);
for (const asset of runtimeAssets) {
await copyFile(path.join(assetsSource, asset), path.join(assetsOutput, asset));
}
for (const dir of runtimeAssetDirs) {
await cp(path.join(assetsSource, dir), path.join(assetsOutput, dir), { recursive: true });
}
await rm(buildDir, { recursive: true, force: true });
console.log(`Built ${path.relative(root, outputDir)}/`);
+92
View File
@@ -0,0 +1,92 @@
/*
Presentation metadata for the Hooks page of the design context document.
The rule ids, names, and descriptions come from the canonical registry
(cli/engine/registry/antipatterns.mjs); this module adds only how the document
groups and labels them. `FINGERPRINT_IDS` promotes a handful of slop rules into
their own "Fingerprints" family (model-specific signatures); `DISCIPLINES` gives
every rule a discipline label for the collapsible groups. Both must cover the
registry exactly — tests/hook-rule-presentation.test.js fails the suite when a
rule is added without a discipline, so the document can never silently miss one.
*/
export const FINGERPRINT_IDS = new Set([
'gpt-thin-border-wide-shadow',
'repeating-stripes-gradient',
'codex-grid-background',
'theater-slop-phrase',
]);
export const DISCIPLINES = {
'side-tab': 'Visual Details',
'border-accent-on-rounded': 'Visual Details',
'overused-font': 'Typography',
'flat-type-hierarchy': 'Typography',
'gradient-text': 'Color & Contrast',
'ai-color-palette': 'Color & Contrast',
'cream-palette': 'Color & Contrast',
'nested-cards': 'Layout & Space',
'monotonous-spacing': 'Layout & Space',
'bounce-easing': 'Motion',
'pulsing-dot': 'Motion',
'blinking-cursor': 'Motion',
'shape-assembled-illustration': 'Imagery',
'dark-glow': 'Color & Contrast',
'radial-halo': 'Color & Contrast',
'radial-spotlight-glow': 'Color & Contrast',
'marquee': 'Motion',
'icon-tile-stack': 'Typography',
'italic-serif-display': 'Typography',
'hero-eyebrow-chip': 'Typography',
'kicker-above-heading': 'Typography',
'numbered-section-labels': 'Layout & Space',
'em-dash-overuse': 'Copy',
'marketing-buzzword': 'Copy',
'aphoristic-cadence': 'Copy',
'oversized-h1': 'Typography',
'extreme-negative-tracking': 'Typography',
'broken-image': 'Imagery',
'script-error': 'Quality',
'content-hidden-at-rest': 'Layout & Space',
'edge-flush-cards': 'Layout & Space',
'text-occlusion': 'Layout & Space',
'first-viewport-column-overflow': 'Layout & Space',
'gray-on-color': 'Color & Contrast',
'low-contrast': 'Quality',
'layout-transition': 'Motion',
'line-length': 'Layout & Space',
'cramped-padding': 'Layout & Space',
'body-text-viewport-edge': 'Layout & Space',
'tight-leading': 'Typography',
'skipped-heading': 'Typography',
'heading-rhythm': 'Layout & Space',
'justified-text': 'Typography',
'tiny-text': 'Typography',
'undersized-ui-text': 'Typography',
'all-caps-body': 'Typography',
'wide-tracking': 'Typography',
'text-overflow': 'Layout & Space',
'repeated-container-text': 'Quality',
'clipped-overflow-container': 'Layout & Space',
'design-system-font': 'Typography',
'design-system-color': 'Color & Contrast',
'design-system-radius': 'Visual Details',
'design-system-font-size': 'Typography',
'gpt-thin-border-wide-shadow': 'Visual Details',
'repeating-stripes-gradient': 'Visual Details',
'codex-grid-background': 'Visual Details',
'theater-slop-phrase': 'Copy',
'image-hover-transform': 'Motion',
};
/* One entry per registry rule, in registry order, in the exact shape the
document's Hooks module renders. */
export function composeHookRules(antipatterns) {
return antipatterns.map((rule) => ({
id: rule.id,
name: rule.name,
description: rule.description,
group: FINGERPRINT_IDS.has(rule.id) ? 'fingerprints' : rule.category,
discipline: DISCIPLINES[rule.id],
}));
}
+1
View File
@@ -48,6 +48,7 @@ export const SUITES = {
'tests/validate-plugin-versions.test.js',
'tests/validate-plugin-manifest.test.js',
'tests/plugin-paths.test.js',
'tests/hook-rule-presentation.test.js',
],
},
{