extraktor 1.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.
@@ -0,0 +1,412 @@
1
+ import {
2
+ createLogger
3
+ } from "./chunk-5IH5TLAQ.js";
4
+
5
+ // src/generators/theme-package/theme-package-generator.ts
6
+ import fs from "fs-extra";
7
+ import path from "path";
8
+ var logger = createLogger({ prefix: "theme-generator" });
9
+ var ThemePackageGenerator = class {
10
+ async generate(tokens, options) {
11
+ const { outputDir, packageName } = options;
12
+ logger.info(`Generating theme package: ${packageName}`);
13
+ await fs.ensureDir(outputDir);
14
+ await this.generatePackageJson(outputDir, packageName);
15
+ await this.generateTypes(outputDir, tokens);
16
+ await this.generateThemeConfig(outputDir, tokens, options);
17
+ if (options.includeCSSVariables !== false) {
18
+ await this.generateCSSVariables(outputDir, tokens, options);
19
+ }
20
+ if (options.includeTailwindPreset !== false) {
21
+ await this.generateTailwindPreset(outputDir, tokens, options);
22
+ }
23
+ if (options.includeComponents) {
24
+ await this.generateComponentUtils(outputDir, tokens);
25
+ }
26
+ await this.generateReadme(outputDir, packageName, options);
27
+ await this.generateTsConfig(outputDir);
28
+ logger.info(`\u2705 Theme package generated at: ${outputDir}`);
29
+ }
30
+ async generatePackageJson(outputDir, packageName) {
31
+ const packageJson = {
32
+ name: packageName,
33
+ version: "1.0.0",
34
+ description: "Design system theme package generated by extraktor",
35
+ main: "dist/index.js",
36
+ types: "dist/index.d.ts",
37
+ type: "module",
38
+ exports: {
39
+ ".": {
40
+ import: "./dist/index.js",
41
+ types: "./dist/index.d.ts"
42
+ },
43
+ "./theme": {
44
+ import: "./dist/theme.js",
45
+ types: "./dist/theme.d.ts"
46
+ },
47
+ "./tailwind": {
48
+ import: "./dist/tailwind.js",
49
+ types: "./dist/tailwind.d.ts"
50
+ },
51
+ "./css": "./dist/theme.css"
52
+ },
53
+ files: ["dist", "README.md"],
54
+ scripts: {
55
+ build: "tsup src/index.ts src/theme.ts src/tailwind.ts --format esm --dts",
56
+ dev: "tsup src/index.ts src/theme.ts src/tailwind.ts --format esm --dts --watch",
57
+ prepublishOnly: "npm run build"
58
+ },
59
+ peerDependencies: {
60
+ tailwindcss: "^4.0.0"
61
+ },
62
+ devDependencies: {
63
+ tsup: "^8.5.1",
64
+ typescript: "^5.9.3",
65
+ tailwindcss: "^4.1.18"
66
+ }
67
+ };
68
+ await fs.writeJson(path.join(outputDir, "package.json"), packageJson, { spaces: 2 });
69
+ }
70
+ async generateTypes(outputDir, tokens) {
71
+ const srcDir = path.join(outputDir, "src");
72
+ await fs.ensureDir(srcDir);
73
+ const colorNames = tokens.colors?.map((c) => `'${c.name}'`).join(" | ") || "string";
74
+ const fontNames = tokens.fonts?.map((f) => `'${f.name}'`).join(" | ") || "string";
75
+ const typesContent = `// Auto-generated theme types
76
+ export interface ThemeColors {
77
+ ${tokens.colors?.map((c) => `${c.name}: '${c.value}';`).join("\n ") || ""}
78
+ }
79
+
80
+ export interface ThemeFonts {
81
+ ${tokens.fonts?.map((f) => `${f.name}: string;`).join("\n ") || ""}
82
+ }
83
+
84
+ export interface ThemeSpacing {
85
+ ${tokens.spacing?.map((s) => `${s.name}: '${s.value}';`).join("\n ") || ""}
86
+ }
87
+
88
+ export type ColorName = ${colorNames};
89
+ export type FontName = ${fontNames};
90
+
91
+ export interface Theme {
92
+ colors: ThemeColors;
93
+ fonts: ThemeFonts;
94
+ spacing: ThemeSpacing;
95
+ borderRadius: Record<string, string>;
96
+ shadows: Record<string, string>;
97
+ }
98
+ `;
99
+ await fs.writeFile(path.join(srcDir, "types.ts"), typesContent);
100
+ }
101
+ async generateThemeConfig(outputDir, tokens, options) {
102
+ const srcDir = path.join(outputDir, "src");
103
+ const colors = options.customColors ? this.mergeColors(tokens.colors || [], options.customColors) : tokens.colors || [];
104
+ const themeContent = `import type { Theme } from './types.js';
105
+
106
+ export const theme: Theme = {
107
+ colors: {
108
+ ${colors.map((c) => `${c.name}: '${c.value}',`).join("\n ")}
109
+ },
110
+ fonts: {
111
+ ${tokens.fonts?.map((f) => `${f.name}: '${f.name}',`).join("\n ") || ""}
112
+ },
113
+ spacing: {
114
+ ${tokens.spacing?.map((s) => `${s.name}: '${s.value}',`).join("\n ") || ""}
115
+ },
116
+ borderRadius: {
117
+ ${tokens.borderRadius?.map((br) => `${br.name}: '${br.value}',`).join("\n ") || ""}
118
+ },
119
+ shadows: {
120
+ ${tokens.shadows?.map((sh) => `${sh.name}: '${sh.value}',`).join("\n ") || ""}
121
+ }
122
+ };
123
+
124
+ ${options.darkMode ? this.generateDarkTheme(colors) : ""}
125
+
126
+ export default theme;
127
+ `;
128
+ await fs.writeFile(path.join(srcDir, "theme.ts"), themeContent);
129
+ const indexContent = `export * from './types.js';
130
+ export * from './theme.js';
131
+ `;
132
+ await fs.writeFile(path.join(srcDir, "index.ts"), indexContent);
133
+ }
134
+ mergeColors(colors, customColors) {
135
+ const colorMap = new Map(colors.map((c) => [c.name, c]));
136
+ for (const [name, value] of Object.entries(customColors)) {
137
+ colorMap.set(name, { name, value, type: "color" });
138
+ }
139
+ return Array.from(colorMap.values());
140
+ }
141
+ generateDarkTheme(colors) {
142
+ return `
143
+ export const darkTheme: Theme = {
144
+ ...theme,
145
+ colors: {
146
+ ...theme.colors,
147
+ ${colors.filter((c) => c.name.includes("background") || c.name.includes("foreground")).map((c) => `${c.name}: '${this.invertColor(c.value)}',`).join("\n ")}
148
+ }
149
+ };
150
+ `;
151
+ }
152
+ invertColor(hex) {
153
+ const num = parseInt(hex.replace("#", ""), 16);
154
+ const inverted = (16777215 ^ num).toString(16).padStart(6, "0");
155
+ return `#${inverted}`;
156
+ }
157
+ async generateCSSVariables(outputDir, tokens, options) {
158
+ const distDir = path.join(outputDir, "dist");
159
+ await fs.ensureDir(distDir);
160
+ const colors = options.customColors ? this.mergeColors(tokens.colors || [], options.customColors) : tokens.colors || [];
161
+ let cssContent = `:root {
162
+ /* Colors */
163
+ ${colors.map((c) => `--color-${c.name}: ${c.value};`).join("\n ")}
164
+
165
+ /* Fonts */
166
+ ${tokens.fonts?.map((f) => `--font-${f.name}: '${f.name}', sans-serif;`).join("\n ") || ""}
167
+
168
+ /* Spacing */
169
+ ${tokens.spacing?.map((s) => `--spacing-${s.name}: ${s.value};`).join("\n ") || ""}
170
+
171
+ /* Border Radius */
172
+ ${tokens.borderRadius?.map((br) => `--radius-${br.name}: ${br.value};`).join("\n ") || ""}
173
+
174
+ /* Shadows */
175
+ ${tokens.shadows?.map((sh) => `--shadow-${sh.name}: ${sh.value};`).join("\n ") || ""}
176
+ }
177
+ `;
178
+ if (options.darkMode) {
179
+ cssContent += `
180
+ [data-theme="dark"] {
181
+ /* Dark mode color overrides */
182
+ ${colors.filter((c) => c.name.includes("background") || c.name.includes("foreground")).map((c) => `--color-${c.name}: ${this.invertColor(c.value)};`).join("\n ")}
183
+ }
184
+ `;
185
+ }
186
+ await fs.writeFile(path.join(distDir, "theme.css"), cssContent);
187
+ }
188
+ async generateTailwindPreset(outputDir, tokens, options) {
189
+ const srcDir = path.join(outputDir, "src");
190
+ const colors = options.customColors ? this.mergeColors(tokens.colors || [], options.customColors) : tokens.colors || [];
191
+ const tailwindContent = `import type { Config } from 'tailwindcss';
192
+
193
+ const preset: Partial<Config> = {
194
+ theme: {
195
+ extend: {
196
+ colors: {
197
+ ${colors.map((c) => `'${c.name}': '${c.value}',`).join("\n ")}
198
+ },
199
+ fontFamily: {
200
+ ${tokens.fonts?.map((f) => `'${f.name}': ['${f.name}', 'sans-serif'],`).join("\n ") || ""}
201
+ },
202
+ spacing: {
203
+ ${tokens.spacing?.map((s) => `'${s.name}': '${s.value}',`).join("\n ") || ""}
204
+ },
205
+ borderRadius: {
206
+ ${tokens.borderRadius?.map((br) => `'${br.name}': '${br.value}',`).join("\n ") || ""}
207
+ },
208
+ boxShadow: {
209
+ ${tokens.shadows?.map((sh) => `'${sh.name}': '${sh.value}',`).join("\n ") || ""}
210
+ }
211
+ }
212
+ }${options.darkMode ? `,
213
+ darkMode: 'class'` : ""}
214
+ };
215
+
216
+ export default preset;
217
+ `;
218
+ await fs.writeFile(path.join(srcDir, "tailwind.ts"), tailwindContent);
219
+ }
220
+ async generateComponentUtils(outputDir, tokens) {
221
+ const srcDir = path.join(outputDir, "src");
222
+ const utilsContent = `import { theme } from './theme.js';
223
+ import type { ColorName, FontName } from './types.js';
224
+
225
+ export function getColor(name: ColorName): string {
226
+ return theme.colors[name];
227
+ }
228
+
229
+ export function getFont(name: FontName): string {
230
+ return theme.fonts[name];
231
+ }
232
+
233
+ export function getSpacing(name: string): string {
234
+ return theme.spacing[name] || '0';
235
+ }
236
+
237
+ export function cn(...classes: (string | undefined | false)[]): string {
238
+ return classes.filter(Boolean).join(' ');
239
+ }
240
+ `;
241
+ await fs.writeFile(path.join(srcDir, "utils.ts"), utilsContent);
242
+ const indexPath = path.join(srcDir, "index.ts");
243
+ const indexContent = await fs.readFile(indexPath, "utf-8");
244
+ await fs.writeFile(indexPath, indexContent + `export * from './utils.js';
245
+ `);
246
+ }
247
+ async generateReadme(outputDir, packageName, options) {
248
+ const readme = `# ${packageName}
249
+
250
+ Design system theme package generated by [extraktor](https://github.com/rainbow-me/extraktor).
251
+
252
+ ## Installation
253
+
254
+ \`\`\`bash
255
+ npm install ${packageName}
256
+ \`\`\`
257
+
258
+ ## Usage
259
+
260
+ ### Import Theme
261
+
262
+ \`\`\`typescript
263
+ import { theme } from '${packageName}';
264
+
265
+ console.log(theme.colors.primary);
266
+ console.log(theme.fonts.sans);
267
+ \`\`\`
268
+
269
+ ### CSS Variables
270
+
271
+ Import the CSS file in your app:
272
+
273
+ \`\`\`typescript
274
+ import '${packageName}/css';
275
+ \`\`\`
276
+
277
+ Then use variables in your CSS:
278
+
279
+ \`\`\`css
280
+ .button {
281
+ background-color: var(--color-primary);
282
+ font-family: var(--font-sans);
283
+ padding: var(--spacing-4);
284
+ border-radius: var(--radius-md);
285
+ box-shadow: var(--shadow-sm);
286
+ }
287
+ \`\`\`
288
+
289
+ ### Tailwind CSS
290
+
291
+ Add the preset to your \`tailwind.config.ts\`:
292
+
293
+ \`\`\`typescript
294
+ import preset from '${packageName}/tailwind';
295
+
296
+ export default {
297
+ presets: [preset],
298
+ content: ['./src/**/*.{js,ts,jsx,tsx}']
299
+ };
300
+ \`\`\`
301
+
302
+ Then use the theme in your components:
303
+
304
+ \`\`\`tsx
305
+ export function Button() {
306
+ return (
307
+ <button className="bg-primary text-white font-sans px-4 py-2 rounded-md shadow-sm">
308
+ Click me
309
+ </button>
310
+ );
311
+ }
312
+ \`\`\`
313
+
314
+ ${options.darkMode ? `
315
+ ### Dark Mode
316
+
317
+ Enable dark mode by adding \`data-theme="dark"\` to your HTML element:
318
+
319
+ \`\`\`typescript
320
+ import { darkTheme } from '${packageName}';
321
+
322
+ // Toggle dark mode
323
+ document.documentElement.setAttribute('data-theme', 'dark');
324
+
325
+ // Or in React
326
+ function App() {
327
+ const [isDark, setIsDark] = useState(false);
328
+
329
+ useEffect(() => {
330
+ document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
331
+ }, [isDark]);
332
+
333
+ return <YourApp />;
334
+ }
335
+ \`\`\`
336
+ ` : ""}
337
+
338
+ ${options.includeComponents ? `
339
+ ### Utility Functions
340
+
341
+ \`\`\`typescript
342
+ import { getColor, getFont, getSpacing, cn } from '${packageName}';
343
+
344
+ const primaryColor = getColor('primary');
345
+ const sansFont = getFont('sans');
346
+ const spacing = getSpacing('4');
347
+
348
+ // Combine class names
349
+ const className = cn(
350
+ 'button',
351
+ isActive && 'active',
352
+ isDisabled && 'disabled'
353
+ );
354
+ \`\`\`
355
+ ` : ""}
356
+
357
+ ## TypeScript
358
+
359
+ Full TypeScript support included:
360
+
361
+ \`\`\`typescript
362
+ import type { Theme, ColorName, FontName } from '${packageName}';
363
+
364
+ const color: ColorName = 'primary'; // Type-safe
365
+ const font: FontName = 'sans'; // Type-safe
366
+ \`\`\`
367
+
368
+ ## Customization
369
+
370
+ You can extend the theme in your project:
371
+
372
+ \`\`\`typescript
373
+ import { theme } from '${packageName}';
374
+
375
+ export const customTheme = {
376
+ ...theme,
377
+ colors: {
378
+ ...theme.colors,
379
+ brand: '#FF6B35'
380
+ }
381
+ };
382
+ \`\`\`
383
+
384
+ ## License
385
+
386
+ MIT
387
+ `;
388
+ await fs.writeFile(path.join(outputDir, "README.md"), readme);
389
+ }
390
+ async generateTsConfig(outputDir) {
391
+ const tsconfig = {
392
+ compilerOptions: {
393
+ target: "ES2022",
394
+ module: "ESNext",
395
+ moduleResolution: "bundler",
396
+ declaration: true,
397
+ declarationMap: true,
398
+ esModuleInterop: true,
399
+ forceConsistentCasingInFileNames: true,
400
+ strict: true,
401
+ skipLibCheck: true,
402
+ resolveJsonModule: true
403
+ },
404
+ include: ["src/**/*"],
405
+ exclude: ["node_modules", "dist"]
406
+ };
407
+ await fs.writeJson(path.join(outputDir, "tsconfig.json"), tsconfig, { spaces: 2 });
408
+ }
409
+ };
410
+ export {
411
+ ThemePackageGenerator
412
+ };
package/package.json ADDED
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "extraktor",
3
+ "version": "1.0.0",
4
+ "description": "Extract design systems from any website using Vision AI. Turn any URL into React components, design tokens, and Tailwind themes.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "private": false,
9
+ "publishConfig": {
10
+ "access": "public",
11
+ "registry": "https://registry.npmjs.org"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/aytuncyildizli/extraktor.git"
16
+ },
17
+ "homepage": "https://github.com/aytuncyildizli/extraktor#readme",
18
+ "bugs": {
19
+ "url": "https://github.com/aytuncyildizli/extraktor/issues"
20
+ },
21
+ "bin": {
22
+ "extraktor": "./dist/cli/index.js"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "skills",
27
+ "README.md",
28
+ "LICENSE"
29
+ ],
30
+ "scripts": {
31
+ "build": "tsup src/cli/index.ts src/index.ts --format esm --dts --clean",
32
+ "dev": "tsup src/cli/index.ts src/index.ts --format esm --watch",
33
+ "start": "node dist/cli/index.js",
34
+ "test": "vitest",
35
+ "test:run": "vitest run",
36
+ "lint": "eslint src --ext .ts",
37
+ "typecheck": "tsc --noEmit",
38
+ "extract": "node dist/cli/index.js extract",
39
+ "clone": "node dist/cli/index.js clone",
40
+ "generate": "node dist/cli/index.js generate",
41
+ "prepublishOnly": "npm run build",
42
+ "release": "npm version patch && npm publish"
43
+ },
44
+ "keywords": [
45
+ "design-system",
46
+ "design-tokens",
47
+ "ui-extraction",
48
+ "react-components",
49
+ "tailwind",
50
+ "nextjs",
51
+ "vision-ai",
52
+ "storybook",
53
+ "playwright",
54
+ "css-to-tailwind",
55
+ "framer-motion",
56
+ "component-extraction",
57
+ "style-guide",
58
+ "cli"
59
+ ],
60
+ "author": "Aytunc Yildizli",
61
+ "license": "MIT",
62
+ "engines": {
63
+ "node": ">=18.0.0"
64
+ },
65
+ "dependencies": {
66
+ "@anthropic-ai/sdk": "^0.71.2",
67
+ "@modelcontextprotocol/sdk": "^1.27.1",
68
+ "@svgr/core": "^8.1.0",
69
+ "chalk": "^5.6.2",
70
+ "cheerio": "^1.1.2",
71
+ "chroma-js": "^3.2.0",
72
+ "color": "^5.0.3",
73
+ "commander": "^14.0.2",
74
+ "cosmiconfig": "^9.0.0",
75
+ "css-tree": "^3.1.0",
76
+ "fs-extra": "^11.3.3",
77
+ "glob": "^13.0.0",
78
+ "nanoid": "^5.1.6",
79
+ "ora": "^9.0.0",
80
+ "playwright": "^1.57.0",
81
+ "postcss": "^8.5.6",
82
+ "postcss-selector-parser": "^7.1.1",
83
+ "postcss-value-parser": "^4.2.0",
84
+ "sharp": "^0.34.5",
85
+ "style-dictionary": "^5.1.4",
86
+ "svgo": "^4.0.0",
87
+ "tailwind-merge": "^3.4.0",
88
+ "tailwindcss": "^4.1.18",
89
+ "zod": "^3.25.76"
90
+ },
91
+ "devDependencies": {
92
+ "@types/chroma-js": "^3.1.2",
93
+ "@types/fs-extra": "^11.0.4",
94
+ "@types/node": "^25.0.9",
95
+ "tsup": "^8.5.1",
96
+ "typescript": "^5.9.3",
97
+ "vitest": "^4.0.17"
98
+ }
99
+ }
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: analyze-design
3
+ description: Quick analysis of any website's design - colors, fonts, spacing, layout patterns, framework detection. No files generated, no API key needed.
4
+ ---
5
+
6
+ # Analyze Design
7
+
8
+ Quick design analysis with no output files:
9
+
10
+ ```bash
11
+ npx extraktor analyze <url>
12
+ ```
13
+
14
+ No API key needed. Returns: color palette, font families, font sizes, spacing values, shadow count, animation count, SPA framework detection, element count, CSS variable count.
15
+
16
+ Use this when the user asks things like:
17
+ - "What colors does this site use?"
18
+ - "What font is that?"
19
+ - "How many design tokens does this site have?"
20
+ - "What framework is this built with?"
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: apply-style
3
+ description: Apply a website's design style to your existing project. Extracts tokens and integrates them into your Tailwind config, CSS, or component files.
4
+ ---
5
+
6
+ # Apply Style
7
+
8
+ Extract a site's design and apply it to the user's project:
9
+
10
+ 1. Extract tokens:
11
+ ```bash
12
+ npx extraktor extract <url> -o /tmp/style-source
13
+ ```
14
+
15
+ 2. Read the generated `tailwind.config.ts` and `variables.css`
16
+
17
+ 3. Merge the extracted theme into the user's existing Tailwind config:
18
+ - Add colors to `theme.extend.colors`
19
+ - Add fonts to `theme.extend.fontFamily`
20
+ - Add spacing to `theme.extend.spacing`
21
+
22
+ 4. If user has a `globals.css`, add the CSS variables from `variables.css`
23
+
24
+ This is the "make my site look like X" workflow. No API key needed.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: clone-site
3
+ description: Clone any website into a working Next.js project with images, fonts, videos, and animations. No API key needed for basic clone.
4
+ ---
5
+
6
+ # Clone Site
7
+
8
+ Clone a website into a complete Next.js project:
9
+
10
+ ```bash
11
+ npx extraktor clone <url> -o ./cloned --no-ai
12
+ ```
13
+
14
+ This downloads all assets (images, fonts, videos), preserves animations, and creates a runnable Next.js 15 project. No API key needed.
15
+
16
+ For AI-enhanced clone with clean React components (needs ANTHROPIC_API_KEY):
17
+ ```bash
18
+ npx extraktor clone <url> -o ./cloned
19
+ ```
20
+
21
+ After cloning, tell the user:
22
+ ```bash
23
+ cd ./cloned/<project-name>
24
+ npm install
25
+ npm run dev
26
+ # Visit http://localhost:3000
27
+ ```
28
+
29
+ Options: `--content` (extract content.json), `--crawl` (multi-page), `--handover` (zip package).
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: design-md
3
+ description: Generate a DESIGN.md file from any website. Stitch-compatible 9-section format that AI agents can use to build pixel-perfect UI. No API key needed.
4
+ ---
5
+
6
+ # Generate DESIGN.md
7
+
8
+ Generate a comprehensive DESIGN.md from any URL:
9
+
10
+ ```bash
11
+ npx extraktor design-md <url> -o ./DESIGN.md
12
+ ```
13
+
14
+ No API key needed. If ANTHROPIC_API_KEY is available, the Visual Theme section gets an AI-enhanced narrative description.
15
+
16
+ Output is a single markdown file with 9 sections:
17
+ 1. Visual Theme & Atmosphere
18
+ 2. Color Palette & Roles
19
+ 3. Typography Rules
20
+ 4. Component Stylings
21
+ 5. Layout Principles
22
+ 6. Depth & Elevation
23
+ 7. Do's and Don'ts
24
+ 8. Responsive Behavior
25
+ 9. Agent Prompt Guide
26
+
27
+ After generating, tell the user to drop DESIGN.md into their project root. Any AI coding agent (Claude Code, Cursor, Copilot) can then read it and build UI that matches the source design.
28
+
29
+ Compatible with the Stitch DESIGN.md format used by awesome-design-md.
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: devtools-extract
3
+ description: Extract design from authenticated pages (dashboards, admin panels) by connecting to the user's existing Chrome session via DevTools Protocol.
4
+ ---
5
+
6
+ # DevTools Extract
7
+
8
+ Extract from pages the user is logged into by connecting to their Chrome.
9
+
10
+ First, tell the user to start Chrome with remote debugging:
11
+ ```bash
12
+ # macOS
13
+ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
14
+
15
+ # Linux
16
+ google-chrome --remote-debugging-port=9222
17
+ ```
18
+
19
+ Then have them log into the site they want to extract from.
20
+
21
+ Then run extraktor with `--devtools`:
22
+ ```bash
23
+ npx extraktor extract <url> --devtools
24
+ npx extraktor genome <url> --devtools
25
+ npx extraktor clone <url> --devtools --no-ai
26
+ ```
27
+
28
+ This connects to the running Chrome via CDP. Cookies, sessions, and authentication are preserved. The user's browser stays running after extraction.
29
+
30
+ Custom endpoint: `--devtools http://localhost:9333`
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: extract-tokens
3
+ description: Extract design tokens (colors, fonts, spacing) from any URL into Tailwind config, CSS variables, and DTCG tokens. No API key needed.
4
+ ---
5
+
6
+ # Extract Design Tokens
7
+
8
+ Run extraktor to extract design tokens from a URL. No API key required.
9
+
10
+ ```bash
11
+ npx extraktor extract <url> -o ./tokens --format tailwind tokens css-vars
12
+ ```
13
+
14
+ After extraction, read the output files:
15
+ - `tailwind.config.ts` - drop into any Tailwind project
16
+ - `variables.css` - CSS custom properties
17
+ - `tokens.json` - DTCG standard design tokens
18
+
19
+ Present the extracted colors, fonts, and spacing to the user. If they want to use them, help integrate into their project.
20
+
21
+ Options: `--scroll` (lazy content), `--hover-states`, `--timeout <ms>`, `--no-headless` (visible browser).
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: genome
3
+ description: Reverse-engineer a website into a complete design system with React components, Storybook, and portable genome.json using Vision AI.
4
+ ---
5
+
6
+ # Genome - Design System Extraction
7
+
8
+ Extract a complete, reusable design system from any URL using Claude Vision:
9
+
10
+ ```bash
11
+ npx extraktor genome <url> -o ./genome-output
12
+ ```
13
+
14
+ Uses ANTHROPIC_API_KEY from your environment (already set in Claude Code).
15
+
16
+ This runs a 4-phase pipeline:
17
+ 1. Extracts design tokens (colors, fonts, spacing, animations)
18
+ 2. Takes screenshots and sends them to Claude Vision for component identification
19
+ 3. Generates clean React/Tailwind components by analyzing both screenshot and DOM
20
+ 4. Packages everything into a portable genome
21
+
22
+ Output structure:
23
+ - `genome.json` - portable design DNA
24
+ - `components/` - clean React/TSX components with TypeScript props
25
+ - `theme/` - Tailwind config, CSS variables, animation presets, DTCG tokens
26
+ - `stories/` - Storybook for every component
27
+ - `screenshots/` - vision analysis captures
28
+
29
+ After extraction, read `genome.json` and present the components to the user.
30
+
31
+ Options: `--max-components <n>`, `--skip-storybook`, `--skip-screenshots`, `--model <model>`.