roast-my-design-system 3.2.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/LICENSE +21 -0
- package/README.md +119 -0
- package/bin/roast.mjs +93 -0
- package/package.json +35 -0
- package/skills/roast-my-design-system/scripts/benchmark/benchmark.json +1356 -0
- package/skills/roast-my-design-system/scripts/diagnose/index.mjs +870 -0
- package/skills/roast-my-design-system/scripts/harvest/components.mjs +189 -0
- package/skills/roast-my-design-system/scripts/harvest/context.mjs +42 -0
- package/skills/roast-my-design-system/scripts/harvest/duplicates.mjs +153 -0
- package/skills/roast-my-design-system/scripts/harvest/index.mjs +75 -0
- package/skills/roast-my-design-system/scripts/harvest/tokens.mjs +312 -0
- package/skills/roast-my-design-system/scripts/harvest/walk.mjs +147 -0
- package/skills/roast-my-design-system/scripts/lib/typefaces.mjs +19 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Greg Kozakiewicz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# roast-my-design-system
|
|
2
|
+
|
|
3
|
+
## A Claude Code skill that roasts your repo's design system with real data.
|
|
4
|
+
|
|
5
|
+
Run this skill on your codebase and get three things: a health score for your design system, the receipts behind it (every colour, spacing value, duplicated component and inline style, with real file paths), and the first fixes ranked by payoff. It benchmarks you against an Ideal Design System, 29 scanned public repos, and 10 reputable design systems (Primer, Polaris, Carbon, shadcn/ui…), and generates one shareable HTML report: **keep it as the audit, or hand it to Claude as the punch list for the fix.**
|
|
6
|
+
|
|
7
|
+
## Why this exists
|
|
8
|
+
|
|
9
|
+
Your AI agent (Claude, Cursor, Copilot) builds UI by imitating what's already in your repo. If your repo has 112 colours and four Button implementations, your agent guesses which one is canonical, and it picks wrong half the time. That's why AI-generated UI looks *almost-but-not-quite* right. The first step to fixing it is seeing the mess measured.
|
|
10
|
+
|
|
11
|
+
## Example use cases
|
|
12
|
+
|
|
13
|
+
- **Pre-refactor audit.** Run `/roast-my-design-system` before a design-system cleanup to get the measured baseline: every colour, spacing value, duplicated component and inline style, with real file paths.
|
|
14
|
+
- **Diagnosing almost-right AI output.** When Claude keeps generating UI that looks slightly off, the report shows which duplicated components and stray values it is imitating, and where the canonical ones live.
|
|
15
|
+
- **Making the case without a meeting.** Drop the self-contained HTML report in Slack: a health score and three benchmarks (ideal norms, the 29-repo median, 10 reputable systems) argue for the design system for you.
|
|
16
|
+
- **The fix loop.** Hand the report back to Claude as the punch list and work through the Where to start section, file by file.
|
|
17
|
+
|
|
18
|
+
The full report for vercel/ai-chatbot, top to bottom:
|
|
19
|
+
|
|
20
|
+

|
|
21
|
+
|
|
22
|
+
The same report in light mode (one file, built-in toggle):
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
## What makes the numbers trustworthy
|
|
27
|
+
|
|
28
|
+
- **Deterministic scanner, not AI sampling.** A zero-dependency Node script reads *every* file (a 5,000-file monorepo takes ~1.5s) and returns the same numbers every run. Claude narrates; it never counts.
|
|
29
|
+
- **Read-only.** Nothing in your repo is modified. The only outputs are a temp JSON and the HTML report.
|
|
30
|
+
- **No network, no telemetry.** Everything runs locally. Nothing about your code leaves your machine.
|
|
31
|
+
- **Honest exclusions.** Test files, Storybook stories, docs sites, example apps, SVG artwork, and email templates (which *must* inline styles) are excluded, so you can't discredit the numbers on a technicality.
|
|
32
|
+
- **Intent-aware counting (v3).** Runtime-computed inline styles, compound-component APIs and wrapper components are not crimes and are not counted as ones. Token-led repos are judged on their hardcoded strays, not their token architecture. Repeated arbitrary values are read as decisions without names, not drift.
|
|
33
|
+
- **A real benchmark.** The "Avg Design System" yardstick comes from scanning 29 public React repos (cal.com, excalidraw, outline, twenty, dub, langfuse…). Median: 88 colours, 12 greys, 17 duplicated components, 42 inline style blocks.
|
|
34
|
+
- **A second yardstick: reputable systems.** Curated, scoped scans of 10 well-known design systems (shadcn/ui, Primer, Polaris, Carbon, Material UI, Chakra, Ant Design, GOV.UK, Spectrum, Cloudscape) show what disciplined looks like at scale.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
**No install, no Claude needed — just try it:**
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx roast-my-design-system
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Run it inside any repo. Same scanner, same report, straight from npm. Add `--theme light`, `--out <file>` or `--no-open` if you want them. The Claude Code skill below adds the conversation on top: the roast in chat, then a punch list you can actually work through with Claude.
|
|
45
|
+
|
|
46
|
+
**Claude Code (recommended):**
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
/plugin marketplace add pencilrebel/roast-my-design-system
|
|
50
|
+
/plugin install roast-my-design-system@roast-my-design-system
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If those commands error, your Claude Code is likely older than the plugin marketplace feature: update Claude Code and retry, or just use the manual route below (it works everywhere and installs the same skill).
|
|
54
|
+
|
|
55
|
+
**Manual (Claude Code, any version):**
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/pencilrebel/roast-my-design-system.git
|
|
59
|
+
cp -r roast-my-design-system/skills/roast-my-design-system ~/.claude/skills/
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
(Use `.claude/skills/` inside a repo instead to share it with your team.)
|
|
63
|
+
|
|
64
|
+
**OpenAI Codex CLI** (same SKILL.md, same folder):
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git clone https://github.com/pencilrebel/roast-my-design-system.git
|
|
68
|
+
cp -r roast-my-design-system/skills/roast-my-design-system ~/.codex/skills/
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Invoke with `$roast-my-design-system` (or let Codex auto-match it). Use `.codex/skills/` inside a repo to share with your team.
|
|
72
|
+
|
|
73
|
+
**`npx skills`:** `npx skills add pencilrebel/roast-my-design-system` works for agents that read `~/.agents/skills/`. Claude Code currently reads `~/.claude/skills/`, so prefer one of the routes above.
|
|
74
|
+
|
|
75
|
+
Requires Node 18+.
|
|
76
|
+
|
|
77
|
+
## Use
|
|
78
|
+
|
|
79
|
+
Open Claude Code in the repo you want roasted and type:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
/roast-my-design-system
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
You get the roast in chat plus `design-system-roast.html` at your repo root: a self-contained page (open it, Slack it, email it, no external requests) with:
|
|
86
|
+
|
|
87
|
+
- a **health score** computed from how your numbers sit against the ideal
|
|
88
|
+
- stat tiles comparing you to all three yardsticks: Ideal, the 29-repo average, and the reputable systems
|
|
89
|
+
- a **light/dark theme toggle** in one file
|
|
90
|
+
- the usage-weighted palette bar, the grey ramp, the off-scale spacing receipts, the duplicate-component receipts with clickable file paths, and the worst-offenders ledger
|
|
91
|
+
- a **Where to start** close: up to three moves derived from your repo's own numbers, each with a file-path receipt
|
|
92
|
+
|
|
93
|
+
## Live examples
|
|
94
|
+
|
|
95
|
+
Three real roasts of public repos, hosted as-is (the same self-contained HTML the skill generates):
|
|
96
|
+
|
|
97
|
+
- **[excalidraw/excalidraw](https://pencilrebel.github.io/roast-my-design-system/examples/excalidraw-excalidraw.html)**
|
|
98
|
+
- **[dubinc/dub](https://pencilrebel.github.io/roast-my-design-system/examples/dubinc-dub.html)**
|
|
99
|
+
- **[vercel/ai-chatbot](https://pencilrebel.github.io/roast-my-design-system/examples/vercel-ai-chatbot.html)**
|
|
100
|
+
|
|
101
|
+
## What it measures
|
|
102
|
+
|
|
103
|
+
| Metric | Ideal Design System | Median of 29 scanned repos | Median of 10 reputable systems |
|
|
104
|
+
|---|---|---|---|
|
|
105
|
+
| Distinct colours | ~24 | 88 | 24 |
|
|
106
|
+
| Shades of grey | up to 13 | 12 | 5 |
|
|
107
|
+
| Off-scale spacing values | ~12 | 26 | 6 |
|
|
108
|
+
| Typefaces | 2–3 | 2 | 1 |
|
|
109
|
+
| Border radii | up to 10 | 12 | 2 |
|
|
110
|
+
| Duplicated components | 0 | 17 | 10 |
|
|
111
|
+
| Inline style blocks | 0 | 42 | 11 |
|
|
112
|
+
|
|
113
|
+
Yes, the median repo is already a mess. That's the point.
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
MIT
|
|
118
|
+
|
|
119
|
+
Built and designed by [Greg Kozakiewicz](https://gregkozakiewicz.com).
|
package/bin/roast.mjs
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* roast-my-design-system — npx entrypoint. Runs the same deterministic,
|
|
4
|
+
* zero-dependency scanner the Claude Code skill uses: harvest the repo,
|
|
5
|
+
* diagnose it against Ideal Design System norms and the 29-repo benchmark,
|
|
6
|
+
* write design-system-roast.html, open it, print the score.
|
|
7
|
+
*
|
|
8
|
+
* npx roast-my-design-system [path] [--theme dark|light] [--out report.html] [--no-open]
|
|
9
|
+
*/
|
|
10
|
+
import { spawnSync } from 'node:child_process';
|
|
11
|
+
import { mkdtempSync, rmSync, readFileSync, existsSync, statSync } from 'node:fs';
|
|
12
|
+
import { join, dirname, resolve } from 'node:path';
|
|
13
|
+
import { tmpdir } from 'node:os';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
|
|
16
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const SCRIPTS = join(HERE, '../skills/roast-my-design-system/scripts');
|
|
18
|
+
const VERSION = JSON.parse(readFileSync(join(HERE, '../package.json'), 'utf8')).version;
|
|
19
|
+
|
|
20
|
+
const argv = process.argv.slice(2);
|
|
21
|
+
function flag(name) {
|
|
22
|
+
const i = argv.indexOf(`--${name}`);
|
|
23
|
+
if (i === -1) return null;
|
|
24
|
+
argv.splice(i, 1);
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
function opt(name, fallback) {
|
|
28
|
+
const i = argv.indexOf(`--${name}`);
|
|
29
|
+
if (i === -1 || !argv[i + 1]) return fallback;
|
|
30
|
+
const v = argv[i + 1];
|
|
31
|
+
argv.splice(i, 2);
|
|
32
|
+
return v;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (flag('version') || flag('v')) { console.log(VERSION); process.exit(0); }
|
|
36
|
+
if (flag('help') || flag('h')) {
|
|
37
|
+
console.log(`roast-my-design-system ${VERSION}
|
|
38
|
+
|
|
39
|
+
Usage: npx roast-my-design-system [path] [options]
|
|
40
|
+
|
|
41
|
+
path repo to scan (default: current directory)
|
|
42
|
+
--theme <t> dark | light (default: dark)
|
|
43
|
+
--out <file> report path (default: design-system-roast.html in the repo)
|
|
44
|
+
--no-open write the report without opening it
|
|
45
|
+
|
|
46
|
+
Read-only scan. No network, no telemetry, nothing leaves your machine.`);
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const noOpen = flag('no-open') === true;
|
|
51
|
+
const theme = opt('theme', 'dark');
|
|
52
|
+
const target = resolve(argv.find((a) => !a.startsWith('--')) || process.cwd());
|
|
53
|
+
if (!existsSync(target) || !statSync(target).isDirectory()) {
|
|
54
|
+
console.error(`Not a directory: ${target}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
const outPath = resolve(opt('out', join(target, 'design-system-roast.html')));
|
|
58
|
+
|
|
59
|
+
const tmp = mkdtempSync(join(tmpdir(), 'roast-'));
|
|
60
|
+
const harvestPath = join(tmp, 'harvest.json');
|
|
61
|
+
const summaryPath = join(tmp, 'summary.json');
|
|
62
|
+
|
|
63
|
+
function run(script, args) {
|
|
64
|
+
const r = spawnSync(process.execPath, [join(SCRIPTS, script), ...args], { stdio: 'inherit' });
|
|
65
|
+
if (r.status !== 0) {
|
|
66
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
67
|
+
process.exit(r.status ?? 1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(`roast-my-design-system ${VERSION} · read-only scan, nothing leaves your machine\n`);
|
|
72
|
+
run('harvest/index.mjs', [target, '--out', harvestPath]);
|
|
73
|
+
console.log('');
|
|
74
|
+
run('diagnose/index.mjs', [harvestPath, '--out', outPath, '--theme', theme, '--summary', summaryPath]);
|
|
75
|
+
|
|
76
|
+
let summary = null;
|
|
77
|
+
try { summary = JSON.parse(readFileSync(summaryPath, 'utf8')); } catch { /* report still exists */ }
|
|
78
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
79
|
+
|
|
80
|
+
if (summary) {
|
|
81
|
+
const bad = summary.tiles.filter((t) => t.health === 'bad');
|
|
82
|
+
if (bad.length) {
|
|
83
|
+
console.log(`\n worst offenders: ${bad.map((t) => `${t.value} ${t.label}`).join(' · ')}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log(`\nWant the fixes, not just the roast? The free Claude Code skill runs this same
|
|
88
|
+
scan, then walks the punch list with you: https://github.com/pencilrebel/roast-my-design-system`);
|
|
89
|
+
|
|
90
|
+
if (!noOpen) {
|
|
91
|
+
const opener = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
92
|
+
spawnSync(opener, [outPath], { stdio: 'ignore', shell: process.platform === 'win32' });
|
|
93
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "roast-my-design-system",
|
|
3
|
+
"version": "3.2.0",
|
|
4
|
+
"description": "Roast your design system with real data. A deterministic, zero-dependency scanner that counts every colour, grey, spacing value, typeface, duplicated component and inline style in your repo, scores it 0-100 against Ideal Design System norms and a 29-repo benchmark, and generates a shareable HTML diagnosis.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"design-system",
|
|
7
|
+
"design-tokens",
|
|
8
|
+
"css",
|
|
9
|
+
"audit",
|
|
10
|
+
"lint",
|
|
11
|
+
"tailwind",
|
|
12
|
+
"ui",
|
|
13
|
+
"claude-code",
|
|
14
|
+
"developer-tools"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://pencilrebel.github.io/roast-my-design-system/",
|
|
17
|
+
"bugs": "https://github.com/pencilrebel/roast-my-design-system/issues",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/pencilrebel/roast-my-design-system.git"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"author": "Greg Kozakiewicz (https://gregkozakiewicz.com)",
|
|
24
|
+
"type": "module",
|
|
25
|
+
"bin": {
|
|
26
|
+
"roast-my-design-system": "bin/roast.mjs"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"bin/",
|
|
30
|
+
"skills/roast-my-design-system/scripts/"
|
|
31
|
+
],
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18"
|
|
34
|
+
}
|
|
35
|
+
}
|