designlang 1.0.0 → 2.0.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 CHANGED
@@ -1,17 +1,21 @@
1
1
  <p align="center">
2
2
  <h1 align="center">designlang</h1>
3
- <p align="center">Extract the complete design language from any website.</p>
3
+ <p align="center">Extract the complete design language from any website in seconds.</p>
4
4
  </p>
5
5
 
6
6
  <p align="center">
7
7
  <a href="https://www.npmjs.com/package/designlang"><img src="https://img.shields.io/npm/v/designlang?color=blue&label=npm" alt="npm version"></a>
8
- <a href="https://github.com/Manavarya09/designlangtract/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Manavarya09/designlangtract" alt="license"></a>
8
+ <a href="https://github.com/Manavarya09/design-extract/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Manavarya09/design-extract" alt="license"></a>
9
9
  <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/designlang" alt="node version"></a>
10
10
  </p>
11
11
 
12
12
  ---
13
13
 
14
- **designlang** uses Playwright to headlessly crawl any website, extracts computed styles from the live DOM, and generates a full design system you can immediately use in your project. The primary output is an **AI-optimized markdown file** that an LLM can use to faithfully recreate the design.
14
+ **designlang** crawls any website with a headless browser, extracts every computed style from the live DOM, and generates **8 output files** including an AI-optimized markdown file, visual HTML preview, Tailwind config, Figma variables, React theme, shadcn/ui theme, W3C design tokens, and CSS custom properties.
15
+
16
+ It also does **WCAG accessibility scoring**, **component screenshot capture**, **multi-page crawling**, **design comparison** between two sites, and **historical tracking** of how a site's design evolves over time.
17
+
18
+ **No other tool does all of this from a single command.**
15
19
 
16
20
  ## Quick Start
17
21
 
@@ -19,134 +23,155 @@
19
23
  npx designlang https://stripe.com
20
24
  ```
21
25
 
22
- That's it. Four files appear in `./designlangtract-output/`:
26
+ ## What You Get (8 Files)
23
27
 
24
28
  | File | What it is |
25
29
  |------|------------|
26
- | `*-design-language.md` | AI-optimized markdown — the full design system in natural language with code examples |
27
- | `*-design-tokens.json` | [W3C Design Tokens](https://design-tokens.github.io/community-group/format/) format for tooling |
30
+ | `*-design-language.md` | AI-optimized markdown — the full design system described for LLMs |
31
+ | `*-preview.html` | Visual HTML report with swatches, type scale, shadows, a11y score |
32
+ | `*-design-tokens.json` | [W3C Design Tokens](https://design-tokens.github.io/community-group/format/) for tooling |
28
33
  | `*-tailwind.config.js` | Drop-in Tailwind CSS theme extension |
29
34
  | `*-variables.css` | CSS custom properties ready to import |
35
+ | `*-figma-variables.json` | Figma Variables import (with dark mode support) |
36
+ | `*-theme.js` | React/CSS-in-JS theme object (Chakra, Stitches, Vanilla Extract) |
37
+ | `*-shadcn-theme.css` | shadcn/ui globals.css theme variables |
30
38
 
31
39
  ## Install
32
40
 
33
41
  ```bash
34
- # Use directly with npx (no install needed)
42
+ # Use directly (no install needed)
35
43
  npx designlang https://example.com
36
44
 
37
45
  # Or install globally
38
46
  npm install -g designlang
39
- designlang https://example.com
40
47
  ```
41
48
 
42
- > Playwright's Chromium is auto-installed on first run via the `postinstall` script.
49
+ ## Features
43
50
 
44
- ## What It Extracts
45
-
46
- | Category | Details |
47
- |----------|---------|
48
- | **Colors** | Full palette with primary/secondary/accent/neutral classification, gradients, background & text colors |
49
- | **Typography** | Font families, type scale (heading/body/caption), weights, line heights, letter spacing |
50
- | **Spacing** | All unique values with automatic base-unit detection (e.g. 4px grid) |
51
- | **Border Radii** | Unique values labeled xs through full |
52
- | **Box Shadows** | Parsed and classified by visual weight (xs/sm/md/lg/xl) |
53
- | **CSS Variables** | All `:root` custom properties, categorized by type |
54
- | **Breakpoints** | Media query breakpoints with standard labels (sm/md/lg/xl) |
55
- | **Animations** | Transitions, easing functions, durations, `@keyframes` |
56
- | **Components** | Detected patterns for buttons, cards, inputs, links — with base styles |
51
+ ### Multi-Page Crawling
57
52
 
58
- ## CLI Options
53
+ Crawl multiple pages for a site-wide design system:
59
54
 
55
+ ```bash
56
+ designlang https://stripe.com --depth 5
60
57
  ```
61
- designlang <url> [options]
62
58
 
63
- Options:
64
- -o, --out <dir> Output directory (default: ./designlangtract-output)
65
- -n, --name <name> Output file prefix (default: derived from URL hostname)
66
- -w, --width <px> Viewport width (default: 1280)
67
- -h, --height <px> Viewport height (default: 800)
68
- --wait <ms> Wait after page load for SPAs (default: 0)
69
- --dark Also extract dark mode color scheme
70
- --verbose Show detailed extraction progress
71
- -V, --version Show version
72
- -h, --help Show help
59
+ ### WCAG Accessibility Scoring
60
+
61
+ Every extraction includes a WCAG 2.1 contrast analysis:
62
+
73
63
  ```
64
+ A11y: 94% WCAG score (7 failing pairs)
65
+ ```
66
+
67
+ Failing color pairs are highlighted in both the markdown and HTML preview with exact contrast ratios.
74
68
 
75
- ### Examples
69
+ ### Component Screenshots
70
+
71
+ Capture PNG screenshots of detected UI components:
76
72
 
77
73
  ```bash
78
- # Basic extraction
79
- designlang https://vercel.com
74
+ designlang https://vercel.com --screenshots
75
+ ```
76
+
77
+ Saves screenshots of buttons, cards, inputs, navigation, hero sections, and a full-page capture.
80
78
 
81
- # Custom output directory
82
- designlang https://stripe.com --out ./stripe-design
79
+ ### Visual HTML Preview
83
80
 
84
- # Extract dark mode too
85
- designlang https://github.com --dark
81
+ Every run generates a `*-preview.html` file — a gorgeous dark-themed report you can open in your browser with:
82
+ - Color swatches for the full palette
83
+ - Live type scale rendering
84
+ - Spacing scale visualization
85
+ - Shadow cards with actual CSS shadows
86
+ - Accessibility score and failing pair analysis
87
+ - Component screenshots (when `--screenshots` is used)
86
88
 
87
- # Wait for SPA to render
88
- designlang https://app.example.com --wait 3000
89
+ ### Design Comparison
89
90
 
90
- # Custom viewport
91
- designlang https://example.com --width 1440 --height 900
91
+ Compare two sites side-by-side:
92
+
93
+ ```bash
94
+ designlang diff https://vercel.com https://stripe.com
92
95
  ```
93
96
 
94
- ## The Markdown Output
97
+ Generates `diff.md` and `diff.html` showing color, typography, spacing, and accessibility differences.
95
98
 
96
- The `*-design-language.md` file is the hero output. It's structured for AI/LLM consumption with:
99
+ ### Historical Tracking
97
100
 
98
- - Color palette tables with hex, RGB, and HSL values
99
- - Typography scale with size, weight, line-height, and letter-spacing
100
- - Spacing scale with token names and px/rem conversions
101
- - CSS code blocks for shadows, component patterns, and animations
102
- - A "Quick Start" section with step-by-step instructions to recreate the design
101
+ Track how a site's design evolves over time:
103
102
 
104
- Feed it to any AI coding assistant and it can recreate the site's visual design from scratch.
103
+ ```bash
104
+ # Each extraction auto-saves a snapshot
105
+ designlang https://stripe.com
105
106
 
106
- ## Claude Code Plugin
107
+ # View history
108
+ designlang history https://stripe.com
109
+ ```
107
110
 
108
- **designlang** also works as a [Claude Code](https://claude.ai/claude-code) plugin.
111
+ Shows color changes, font swaps, accessibility score trends, and CSS variable count over time.
109
112
 
110
- After installing, use the `/extract-design` slash command:
113
+ ### Framework Themes
111
114
 
112
- ```
113
- /extract-design https://stripe.com
114
- ```
115
+ Generates ready-to-use theme files for:
115
116
 
116
- Claude will extract the design, read the markdown output, and help you integrate it into your project.
117
+ - **React/CSS-in-JS** theme object compatible with Chakra UI, Stitches, Vanilla Extract
118
+ - **shadcn/ui** — CSS variables in the exact format shadcn expects (paste into globals.css)
119
+ - **Tailwind** — full theme extension with colors, fonts, spacing, radii, shadows, screens
117
120
 
118
- ## How It Works
121
+ ## What It Extracts
122
+
123
+ | Category | Details |
124
+ |----------|---------|
125
+ | **Colors** | Full palette with primary/secondary/accent/neutral classification, gradients |
126
+ | **Typography** | Font families, type scale, heading/body styles, weight distribution |
127
+ | **Spacing** | All unique values with automatic base-unit detection (4px/8px grid) |
128
+ | **Border Radii** | Unique values labeled xs through full |
129
+ | **Box Shadows** | Parsed and classified by visual weight |
130
+ | **CSS Variables** | All `:root` custom properties, categorized |
131
+ | **Breakpoints** | Media query breakpoints with standard labels |
132
+ | **Animations** | Transitions, easing functions, durations, `@keyframes` |
133
+ | **Components** | Buttons, cards, inputs, links — with base styles |
134
+ | **Accessibility** | WCAG 2.1 contrast ratios for all fg/bg color pairs |
135
+
136
+ ## Full CLI Reference
119
137
 
120
- 1. **Crawl** — Launches headless Chromium via Playwright, navigates to the URL, waits for network idle and font loading
121
- 2. **Extract** — Runs a single `page.evaluate()` call that walks up to 5,000 DOM elements and collects computed styles, CSS custom properties, media queries, and keyframes
122
- 3. **Process** — Nine extractor modules parse, deduplicate, cluster, and classify the raw style data into a unified design object
123
- 4. **Format** — Four formatter modules generate the output files
138
+ ```
139
+ designlang <url> [options]
124
140
 
125
- ## Limitations
141
+ Options:
142
+ -o, --out <dir> Output directory (default: ./design-extract-output)
143
+ -n, --name <name> Output file prefix (default: derived from URL)
144
+ -w, --width <px> Viewport width (default: 1280)
145
+ --height <px> Viewport height (default: 800)
146
+ --wait <ms> Wait after page load for SPAs (default: 0)
147
+ --dark Also extract dark mode styles
148
+ --depth <n> Pages to crawl (default: 0, just the URL)
149
+ --screenshots Capture component screenshots
150
+ --framework <type> Only generate specific theme (react, shadcn)
151
+ --no-history Skip saving to history
152
+ --verbose Detailed progress output
153
+
154
+ Commands:
155
+ diff <urlA> <urlB> Compare two sites' design languages
156
+ history <url> View design history for a site
157
+ ```
126
158
 
127
- - **Cross-origin stylesheets** — CSS loaded from CDNs may not be inspectable via `document.styleSheets` (CORS). Computed styles are still captured since `getComputedStyle()` sees the final resolved values.
128
- - **Shadow DOM** — Elements inside closed shadow roots are not accessible. Open shadow roots are partially supported.
129
- - **CSS-in-JS** — Styles injected at runtime (styled-components, Emotion) are captured via computed styles but not as raw CSS rules.
130
- - **Element cap** — DOM traversal is capped at 5,000 elements to prevent hanging on very large pages.
159
+ ## How It Works
131
160
 
132
- ## Tech Stack
161
+ 1. **Crawl** — Launches headless Chromium via Playwright
162
+ 2. **Extract** — `page.evaluate()` walks up to 5,000 DOM elements collecting computed styles
163
+ 3. **Process** — 10 extractor modules parse, deduplicate, cluster, and classify the raw data
164
+ 4. **Format** — 8 formatter modules generate the output files
165
+ 5. **Score** — Accessibility extractor calculates WCAG contrast ratios
166
+ 6. **Capture** — Optional Playwright screenshots of detected components
133
167
 
134
- - [Playwright](https://playwright.dev/) headless browser automation
135
- - [Commander](https://github.com/tj/commander.js/) — CLI framework
136
- - [Chalk](https://github.com/chalk/chalk) + [Ora](https://github.com/sindresorhus/ora) — terminal styling
168
+ ## Claude Code Plugin
137
169
 
138
- Zero external dependencies for color parsing, clustering, or CSS processing all handled with ~200 lines of pure JS utilities.
170
+ **designlang** also works as a [Claude Code](https://claude.ai/claude-code) plugin. Use `/extract-design <url>` in your coding session.
139
171
 
140
172
  ## Contributing
141
173
 
142
- Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
143
-
144
- 1. Fork the repo
145
- 2. Create a feature branch (`git checkout -b feature/my-feature`)
146
- 3. Make your changes
147
- 4. Test on a few websites (`node bin/designlangtract.js https://example.com`)
148
- 5. Commit and push
149
- 6. Open a pull request
174
+ See [CONTRIBUTING.md](CONTRIBUTING.md). PRs welcome!
150
175
 
151
176
  ## License
152
177
 
@@ -10,6 +10,11 @@ import { formatMarkdown } from '../src/formatters/markdown.js';
10
10
  import { formatTokens } from '../src/formatters/tokens.js';
11
11
  import { formatTailwind } from '../src/formatters/tailwind.js';
12
12
  import { formatCssVars } from '../src/formatters/css-vars.js';
13
+ import { formatPreview } from '../src/formatters/preview.js';
14
+ import { formatFigma } from '../src/formatters/figma.js';
15
+ import { formatReactTheme, formatShadcnTheme } from '../src/formatters/theme.js';
16
+ import { diffDesigns, formatDiffMarkdown, formatDiffHtml } from '../src/diff.js';
17
+ import { saveSnapshot, getHistory, formatHistoryMarkdown } from '../src/history.js';
13
18
  import { nameFromUrl } from '../src/utils.js';
14
19
 
15
20
  const program = new Command();
@@ -17,40 +22,47 @@ const program = new Command();
17
22
  program
18
23
  .name('designlang')
19
24
  .description('Extract the complete design language from any website')
20
- .version('1.0.0')
25
+ .version('2.0.0');
26
+
27
+ // ── Main command: extract ──────────────────────────────────────
28
+ program
21
29
  .argument('<url>', 'URL to extract design language from')
22
30
  .option('-o, --out <dir>', 'output directory', './design-extract-output')
23
31
  .option('-n, --name <name>', 'output file prefix (default: derived from URL)')
24
32
  .option('-w, --width <px>', 'viewport width', parseInt, 1280)
25
- .option('-h, --height <px>', 'viewport height', parseInt, 800)
33
+ .option('--height <px>', 'viewport height', parseInt, 800)
26
34
  .option('--wait <ms>', 'wait after page load (ms)', parseInt, 0)
27
35
  .option('--dark', 'also extract dark mode styles')
36
+ .option('--depth <n>', 'number of internal pages to also crawl', parseInt, 0)
37
+ .option('--screenshots', 'capture component screenshots')
38
+ .option('--framework <type>', 'generate framework theme (react, shadcn)')
39
+ .option('--no-history', 'skip saving to history')
28
40
  .option('--verbose', 'show detailed progress')
29
41
  .action(async (url, opts) => {
30
- // Ensure URL has protocol
31
42
  if (!url.startsWith('http')) url = `https://${url}`;
32
-
33
43
  const prefix = opts.name || nameFromUrl(url);
34
44
  const outDir = resolve(opts.out);
35
45
 
36
46
  console.log('');
37
- console.log(chalk.bold(' design-extract'));
38
- console.log(chalk.gray(` ${url}`));
47
+ console.log(chalk.bold(' designlang'));
48
+ console.log(chalk.gray(` ${url}${opts.depth > 0 ? ` (+ ${opts.depth} pages)` : ''}`));
39
49
  console.log('');
40
50
 
41
51
  const spinner = ora('Launching browser...').start();
42
52
 
43
53
  try {
44
- spinner.text = 'Crawling page and extracting styles...';
54
+ spinner.text = `Crawling${opts.depth > 0 ? ` (depth: ${opts.depth})` : ''}...`;
45
55
  const design = await extractDesignLanguage(url, {
46
56
  width: opts.width,
47
- height: opts.height,
57
+ height: parseInt(opts.height) || 800,
48
58
  wait: opts.wait,
49
59
  dark: opts.dark,
60
+ depth: opts.depth,
61
+ screenshots: opts.screenshots,
62
+ outDir,
50
63
  });
51
64
 
52
- spinner.text = 'Generating output files...';
53
-
65
+ spinner.text = 'Generating outputs...';
54
66
  mkdirSync(outDir, { recursive: true });
55
67
 
56
68
  const files = [
@@ -58,12 +70,31 @@ program
58
70
  { name: `${prefix}-design-tokens.json`, content: formatTokens(design), label: 'Design Tokens (W3C)' },
59
71
  { name: `${prefix}-tailwind.config.js`, content: formatTailwind(design), label: 'Tailwind Config' },
60
72
  { name: `${prefix}-variables.css`, content: formatCssVars(design), label: 'CSS Variables' },
73
+ { name: `${prefix}-preview.html`, content: formatPreview(design), label: 'Visual Preview' },
74
+ { name: `${prefix}-figma-variables.json`, content: formatFigma(design), label: 'Figma Variables' },
61
75
  ];
62
76
 
77
+ // Framework-specific themes
78
+ if (opts.framework === 'react') {
79
+ files.push({ name: `${prefix}-theme.js`, content: formatReactTheme(design), label: 'React Theme' });
80
+ } else if (opts.framework === 'shadcn') {
81
+ files.push({ name: `${prefix}-shadcn-theme.css`, content: formatShadcnTheme(design), label: 'shadcn/ui Theme' });
82
+ } else {
83
+ // Generate both by default
84
+ files.push({ name: `${prefix}-theme.js`, content: formatReactTheme(design), label: 'React Theme' });
85
+ files.push({ name: `${prefix}-shadcn-theme.css`, content: formatShadcnTheme(design), label: 'shadcn/ui Theme' });
86
+ }
87
+
63
88
  for (const file of files) {
64
89
  writeFileSync(join(outDir, file.name), file.content, 'utf-8');
65
90
  }
66
91
 
92
+ // Save to history
93
+ if (opts.history !== false) {
94
+ const histInfo = saveSnapshot(design);
95
+ if (opts.verbose) spinner.info(`Snapshot #${histInfo.snapshotCount} saved for ${histInfo.hostname}`);
96
+ }
97
+
67
98
  spinner.succeed('Extraction complete!');
68
99
  console.log('');
69
100
  console.log(chalk.bold(' Output files:'));
@@ -72,12 +103,20 @@ program
72
103
  const sizeStr = size > 1024 ? `${(size / 1024).toFixed(1)}KB` : `${size}B`;
73
104
  console.log(` ${chalk.green('✓')} ${chalk.cyan(file.name)} ${chalk.gray(`(${sizeStr})`)} — ${file.label}`);
74
105
  }
106
+ if (opts.screenshots && design.componentScreenshots && Object.keys(design.componentScreenshots).length > 0) {
107
+ for (const [, info] of Object.entries(design.componentScreenshots)) {
108
+ console.log(` ${chalk.green('✓')} ${chalk.cyan(info.path)} — ${info.label} screenshot`);
109
+ }
110
+ }
75
111
  console.log('');
76
112
  console.log(chalk.gray(` Saved to ${outDir}`));
77
113
 
78
- // Summary stats
114
+ // Summary
79
115
  console.log('');
80
116
  console.log(chalk.bold(' Summary:'));
117
+ if (design.meta.pagesAnalyzed > 1) {
118
+ console.log(` ${chalk.gray('Pages:')} ${design.meta.pagesAnalyzed} pages analyzed`);
119
+ }
81
120
  console.log(` ${chalk.gray('Colors:')} ${design.colors.all.length} unique colors`);
82
121
  console.log(` ${chalk.gray('Fonts:')} ${design.typography.families.map(f => f.name).join(', ') || 'none detected'}`);
83
122
  console.log(` ${chalk.gray('Spacing:')} ${design.spacing.scale.length} values${design.spacing.base ? ` (base: ${design.spacing.base}px)` : ''}`);
@@ -86,6 +125,13 @@ program
86
125
  console.log(` ${chalk.gray('Breakpoints:')} ${design.breakpoints.length} breakpoints`);
87
126
  console.log(` ${chalk.gray('Components:')} ${Object.keys(design.components).length} patterns detected`);
88
127
  console.log(` ${chalk.gray('CSS Vars:')} ${Object.values(design.variables).reduce((s, v) => s + Object.keys(v).length, 0)} custom properties`);
128
+
129
+ // Accessibility summary
130
+ if (design.accessibility) {
131
+ const a = design.accessibility;
132
+ const scoreColor = a.score >= 80 ? chalk.green : a.score >= 50 ? chalk.yellow : chalk.red;
133
+ console.log(` ${chalk.gray('A11y:')} ${scoreColor(`${a.score}% WCAG score`)} (${a.failCount} failing pairs)`);
134
+ }
89
135
  console.log('');
90
136
 
91
137
  } catch (err) {
@@ -101,4 +147,73 @@ program
101
147
  }
102
148
  });
103
149
 
150
+ // ── Diff command ──────────────────────────────────────────────
151
+ program
152
+ .command('diff <urlA> <urlB>')
153
+ .description('Compare design languages of two websites')
154
+ .option('-o, --out <dir>', 'output directory', './design-diff-output')
155
+ .action(async (urlA, urlB, opts) => {
156
+ if (!urlA.startsWith('http')) urlA = `https://${urlA}`;
157
+ if (!urlB.startsWith('http')) urlB = `https://${urlB}`;
158
+
159
+ console.log('');
160
+ console.log(chalk.bold(' designlang diff'));
161
+ console.log(chalk.gray(` ${urlA}`));
162
+ console.log(chalk.gray(` ${urlB}`));
163
+ console.log('');
164
+
165
+ const spinner = ora('Extracting Site A...').start();
166
+
167
+ try {
168
+ const designA = await extractDesignLanguage(urlA);
169
+ spinner.text = 'Extracting Site B...';
170
+ const designB = await extractDesignLanguage(urlB);
171
+
172
+ spinner.text = 'Comparing...';
173
+ const diff = diffDesigns(designA, designB);
174
+
175
+ const outDir = resolve(opts.out);
176
+ mkdirSync(outDir, { recursive: true });
177
+
178
+ const mdContent = formatDiffMarkdown(diff);
179
+ const htmlContent = formatDiffHtml(diff);
180
+
181
+ writeFileSync(join(outDir, 'diff.md'), mdContent, 'utf-8');
182
+ writeFileSync(join(outDir, 'diff.html'), htmlContent, 'utf-8');
183
+
184
+ spinner.succeed('Comparison complete!');
185
+ console.log('');
186
+ console.log(` ${chalk.green('✓')} ${chalk.cyan('diff.md')} — Markdown comparison`);
187
+ console.log(` ${chalk.green('✓')} ${chalk.cyan('diff.html')} — Visual comparison`);
188
+ console.log('');
189
+ console.log(chalk.gray(` Saved to ${outDir}`));
190
+
191
+ // Quick summary
192
+ for (const s of diff.sections) {
193
+ if (s.changed && s.changed.length > 0) {
194
+ for (const c of s.changed) {
195
+ console.log(` ${chalk.yellow('≠')} ${s.name} — ${c.property}: ${c.a} → ${c.b}`);
196
+ }
197
+ }
198
+ }
199
+ console.log('');
200
+
201
+ } catch (err) {
202
+ spinner.fail('Comparison failed');
203
+ console.error(chalk.red(`\n ${err.message}\n`));
204
+ process.exit(1);
205
+ }
206
+ });
207
+
208
+ // ── History command ──────────────────────────────────────────
209
+ program
210
+ .command('history <url>')
211
+ .description('View design history for a website')
212
+ .action(async (url) => {
213
+ if (!url.startsWith('http')) url = `https://${url}`;
214
+ const history = getHistory(url);
215
+ console.log('');
216
+ console.log(formatHistoryMarkdown(url, history));
217
+ });
218
+
104
219
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "designlang",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "Extract the complete design language from any website — colors, typography, spacing, shadows, and more. Outputs AI-optimized markdown, W3C design tokens, Tailwind config, and CSS variables.",
5
5
  "type": "module",
6
6
  "bin": {