@champpaba/claude-agent-kit 1.7.1 → 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.
Files changed (72) hide show
  1. package/.claude/CHANGELOG-v1.1.1.md +259 -259
  2. package/.claude/CLAUDE.md +79 -90
  3. package/.claude/agents/01-integration.md +11 -7
  4. package/.claude/agents/02-uxui-frontend.md +11 -6
  5. package/.claude/agents/03-test-debug.md +11 -7
  6. package/.claude/agents/04-frontend.md +11 -7
  7. package/.claude/agents/05-backend.md +11 -6
  8. package/.claude/agents/06-database.md +11 -7
  9. package/.claude/commands/cdev.md +110 -7
  10. package/.claude/commands/csetup.md +306 -39
  11. package/.claude/commands/cstatus.md +60 -60
  12. package/.claude/commands/cview.md +364 -364
  13. package/.claude/commands/designsetup.md +1401 -336
  14. package/.claude/commands/extract.md +520 -245
  15. package/.claude/commands/pageplan.md +171 -47
  16. package/.claude/contexts/design/accessibility.md +611 -611
  17. package/.claude/contexts/design/layout.md +400 -400
  18. package/.claude/contexts/design/responsive.md +551 -551
  19. package/.claude/contexts/design/shadows.md +522 -522
  20. package/.claude/contexts/design/typography.md +465 -465
  21. package/.claude/contexts/domain/README.md +164 -164
  22. package/.claude/contexts/patterns/agent-coordination.md +388 -388
  23. package/.claude/contexts/patterns/agent-discovery.md +3 -2
  24. package/.claude/contexts/patterns/change-workflow.md +538 -538
  25. package/.claude/contexts/patterns/code-standards.md +39 -0
  26. package/.claude/contexts/patterns/development-principles.md +513 -513
  27. package/.claude/contexts/patterns/error-handling.md +478 -478
  28. package/.claude/contexts/patterns/error-recovery.md +365 -365
  29. package/.claude/contexts/patterns/logging.md +424 -424
  30. package/.claude/contexts/patterns/task-breakdown.md +452 -452
  31. package/.claude/contexts/patterns/task-classification.md +523 -523
  32. package/.claude/contexts/patterns/tdd-classification.md +516 -516
  33. package/.claude/contexts/patterns/testing.md +413 -413
  34. package/.claude/contexts/patterns/validation-framework.md +776 -776
  35. package/.claude/lib/agent-executor.md +76 -1
  36. package/.claude/lib/agent-router.md +572 -572
  37. package/.claude/lib/flags-updater.md +469 -469
  38. package/.claude/lib/tdd-classifier.md +345 -345
  39. package/.claude/lib/validation-gates.md +484 -484
  40. package/.claude/settings.local.json +42 -42
  41. package/.claude/templates/context-template.md +45 -45
  42. package/.claude/templates/flags-template.json +42 -42
  43. package/.claude/templates/phase-templates.json +19 -29
  44. package/.claude/templates/phases-sections/accessibility-test.md +17 -17
  45. package/.claude/templates/phases-sections/api-design.md +37 -37
  46. package/.claude/templates/phases-sections/backend-tests.md +16 -16
  47. package/.claude/templates/phases-sections/backend.md +37 -37
  48. package/.claude/templates/phases-sections/business-logic-validation.md +16 -16
  49. package/.claude/templates/phases-sections/component-tests.md +17 -17
  50. package/.claude/templates/phases-sections/contract-backend.md +16 -16
  51. package/.claude/templates/phases-sections/contract-frontend.md +16 -16
  52. package/.claude/templates/phases-sections/database.md +35 -35
  53. package/.claude/templates/phases-sections/e2e-tests.md +16 -16
  54. package/.claude/templates/phases-sections/fix-implementation.md +17 -17
  55. package/.claude/templates/phases-sections/frontend-integration.md +18 -18
  56. package/.claude/templates/phases-sections/frontend-mockup.md +123 -123
  57. package/.claude/templates/phases-sections/manual-flow-test.md +15 -15
  58. package/.claude/templates/phases-sections/manual-ux-test.md +16 -16
  59. package/.claude/templates/phases-sections/refactor-implementation.md +17 -17
  60. package/.claude/templates/phases-sections/refactor.md +16 -16
  61. package/.claude/templates/phases-sections/regression-tests.md +15 -15
  62. package/.claude/templates/phases-sections/responsive-test.md +16 -16
  63. package/.claude/templates/phases-sections/script-implementation.md +43 -43
  64. package/.claude/templates/phases-sections/test-coverage.md +16 -16
  65. package/.claude/templates/phases-sections/user-approval.md +14 -14
  66. package/LICENSE +21 -21
  67. package/README.md +103 -351
  68. package/package.json +1 -1
  69. package/.claude/commands/agentsetup.md +0 -1464
  70. package/.claude/commands/psetup.md +0 -101
  71. package/.claude/templates/phases-sections/documentation.md +0 -17
  72. package/.claude/templates/phases-sections/report.md +0 -16
@@ -1,99 +1,91 @@
1
- # /extract - Extract Design System from Website (Component-Level)
1
+ # /extract - Extract Design Inspiration from Website(s)
2
2
 
3
3
  You are an expert design systems engineer with deep knowledge of CSS, animations, and UX patterns.
4
4
 
5
- Your task is to extract comprehensive design data from a website and save it as reusable YAML files with component-level detail.
5
+ Your task is to extract comprehensive design data from one or more websites and save as JSON files that `/designsetup` will use.
6
6
 
7
7
  ---
8
8
 
9
9
  ## 📖 Usage
10
10
 
11
11
  ```bash
12
- /extract <URL>
12
+ /extract <URL> [URL2] [URL3] ...
13
13
 
14
14
  Arguments:
15
- URL Required. Website URL to extract from
15
+ URL Required. One or more website URLs to extract from
16
16
 
17
17
  Examples:
18
- /extract https://airbnb.com
19
- /extract https://blackbird.com
20
- /extract https://linear.app
18
+ /extract https://motherduck.com
19
+ /extract https://linear.app https://stripe.com
20
+ /extract https://ref1.com https://ref2.com https://ref3.com
21
21
  ```
22
22
 
23
+ **Multi-URL Support:**
24
+ - Extract from multiple sites → Merge into `merged-insights.json`
25
+ - Pick animations from ref1, colors from ref2, scroll effects from ref3
26
+ - `/designsetup` will let user choose what to use from each
27
+
23
28
  ---
24
29
 
25
30
  ## 🎯 Mission
26
31
 
27
- Extract ALL design data from a website and save to `design-system/extracted/{site-name}/`:
28
- - `data.yaml` - Complete 17-section design data + animations
29
- - `analysis.md` - Psychology & design philosophy analysis
30
- - `screenshots/` - Component screenshots (default + hover/focus states)
32
+ Extract design inspiration from website(s) and save to `.claude/extractions/`:
33
+ - `{site-name}.json` - Design data per site (colors, typography, animations, style)
34
+ - `merged-insights.json` - Combined insights from all extracted sites
35
+ - `screenshots/{site-name}/` - Component screenshots
36
+
37
+ **Key Outputs for /designsetup:**
38
+ 1. **Style Classification** (Neo-Brutalism, Minimalist, Glassmorphism, etc.)
39
+ 2. **Animation Patterns** (button hover, scroll effects, GSAP detection)
40
+ 3. **Decorative Elements** (blobs, gradients, 3D shapes, illustrations)
41
+ 4. **Color Palette** (primary, secondary, accents)
42
+ 5. **Typography** (fonts, weights, sizes)
31
43
 
32
44
  **Key Principles:**
33
- 1. **Component-Level Detail**: Extract every component type with all states
34
- 2. **Animation Capture**: Before/after screenshots for all interactive states
35
- 3. **17 Sections Mandatory**: Template-based extraction (fallback if not found)
36
- 4. **Reusable**: Output can be used by multiple projects
45
+ 1. **Style Detection**: Classify design style automatically
46
+ 2. **Animation Capture**: Detect GSAP, ScrollTrigger, CSS animations
47
+ 3. **Multi-Site Merge**: Combine insights from multiple references
48
+ 4. **Lean Output**: JSON format for token efficiency (~500 tokens per site)
37
49
 
38
50
  ---
39
51
 
40
52
  ## 🔍 STEP 0: Parse Input & Setup
41
53
 
42
54
  ```javascript
43
- // Parse URL
44
- const input = args[0];
45
- if (!input) {
46
- return error('URL required. Usage: /extract https://airbnb.com');
55
+ // Parse URLs (support multiple)
56
+ const urls = args.filter(arg => arg.startsWith('http') || !arg.startsWith('-'));
57
+ if (urls.length === 0) {
58
+ return error('URL required. Usage: /extract https://motherduck.com [https://linear.app]');
47
59
  }
48
60
 
49
- // Normalize URL
50
- let url = input.trim();
51
- if (!url.startsWith('http://') && !url.startsWith('https://')) {
52
- url = 'https://' + url;
53
- }
61
+ // Normalize URLs
62
+ const sites = urls.map(url => {
63
+ let normalizedUrl = url.trim();
64
+ if (!normalizedUrl.startsWith('http://') && !normalizedUrl.startsWith('https://')) {
65
+ normalizedUrl = 'https://' + normalizedUrl;
66
+ }
54
67
 
55
- // Auto-detect site name
56
- const siteName = new URL(url).hostname
57
- .replace('www.', '')
58
- .replace(/\.[^.]+$/, ''); // Remove TLD
59
- // e.g., "airbnb.com" → "airbnb"
60
-
61
- // Check if already extracted
62
- const extractedPath = `design-system/extracted/${siteName}`;
63
- if (exists(extractedPath + '/data.yaml')) {
64
- const existingData = YAML.parse(Read(extractedPath + '/data.yaml'));
65
- const extractedDate = existingData.meta.extracted_at;
66
-
67
- const response = await AskUserQuestion({
68
- questions: [{
69
- question: `Site "${siteName}" was already extracted on ${extractedDate}. Re-extract?`,
70
- header: "Re-extract?",
71
- multiSelect: false,
72
- options: [
73
- { label: "Yes, re-extract", description: "Overwrite previous data" },
74
- { label: "No, cancel", description: "Keep existing data" }
75
- ]
76
- }]
77
- });
68
+ const siteName = new URL(normalizedUrl).hostname
69
+ .replace('www.', '')
70
+ .replace(/\.[^.]+$/, ''); // Remove TLD
78
71
 
79
- if (response.answers["Re-extract?"] === "No, cancel") {
80
- return output('Extraction cancelled. Existing data preserved.');
81
- }
82
- }
72
+ return { url: normalizedUrl, siteName };
73
+ });
83
74
 
84
75
  // Create directories
85
- Bash: mkdir -p design-system/extracted/${siteName}/screenshots
76
+ Bash: mkdir -p .claude/extractions/screenshots
86
77
  ```
87
78
 
88
79
  **Report:**
89
80
  ```
90
81
  🚀 Extraction Started
91
82
 
92
- 📍 URL: ${url}
93
- 📁 Site: ${siteName}
94
- 📂 Output: design-system/extracted/${siteName}/
83
+ 📍 Sites to extract: ${sites.length}
84
+ ${sites.map((s, i) => ` ${i + 1}. ${s.siteName} (${s.url})`).join('\n')}
85
+
86
+ 📂 Output: .claude/extractions/
95
87
 
96
- Navigating to site...
88
+ Processing sites...
97
89
  ```
98
90
 
99
91
  ---
@@ -542,6 +534,281 @@ async function extractAnimations() {
542
534
  - Inputs: ${inputs.length} extracted
543
535
  - Animations: ${animations.keyframes.length} @keyframes, ${animations.transitions.length} transitions
544
536
 
537
+ 🔄 Detecting style, scroll animations, and decorative elements...
538
+ ```
539
+
540
+ ---
541
+
542
+ ## STEP 2.5: Detect Design Style & Animation Libraries (NEW!)
543
+
544
+ ```javascript
545
+ async function detectStyleAndAnimations() {
546
+ return await mcp__chrome-devtools__evaluate_script({
547
+ function: `() => {
548
+ const result = {
549
+ style: { detected: null, confidence: 0, characteristics: [] },
550
+ animationLibraries: [],
551
+ scrollAnimations: [],
552
+ decorativeElements: []
553
+ };
554
+
555
+ // ========== DETECT ANIMATION LIBRARIES ==========
556
+
557
+ // Check for GSAP
558
+ if (window.gsap || window.TweenMax || window.TweenLite) {
559
+ result.animationLibraries.push({
560
+ name: 'GSAP',
561
+ version: window.gsap?.version || 'unknown',
562
+ detected: true
563
+ });
564
+ }
565
+
566
+ // Check for ScrollTrigger
567
+ if (window.ScrollTrigger) {
568
+ result.animationLibraries.push({
569
+ name: 'ScrollTrigger',
570
+ version: window.ScrollTrigger?.version || 'unknown',
571
+ detected: true,
572
+ instances: document.querySelectorAll('[data-scroll], [data-gsap]').length
573
+ });
574
+ }
575
+
576
+ // Check for Framer Motion (React)
577
+ if (document.querySelector('[data-framer-appear-id], [data-projection-id]')) {
578
+ result.animationLibraries.push({
579
+ name: 'Framer Motion',
580
+ detected: true
581
+ });
582
+ }
583
+
584
+ // Check for Lottie
585
+ if (window.lottie || document.querySelector('lottie-player, [data-lottie]')) {
586
+ result.animationLibraries.push({
587
+ name: 'Lottie',
588
+ detected: true
589
+ });
590
+ }
591
+
592
+ // Check for AOS (Animate on Scroll)
593
+ if (window.AOS || document.querySelector('[data-aos]')) {
594
+ result.animationLibraries.push({
595
+ name: 'AOS',
596
+ detected: true,
597
+ instances: document.querySelectorAll('[data-aos]').length
598
+ });
599
+ }
600
+
601
+ // ========== DETECT SCROLL ANIMATIONS ==========
602
+
603
+ // Find elements with scroll-triggered classes or attributes
604
+ const scrollElements = document.querySelectorAll(
605
+ '[data-scroll], [data-aos], [data-gsap], [data-animate], ' +
606
+ '[class*="scroll-"], [class*="animate-on-scroll"], ' +
607
+ '[class*="fade-in"], [class*="slide-"]'
608
+ );
609
+
610
+ scrollElements.forEach(el => {
611
+ const classes = el.className;
612
+ const dataAttrs = Object.keys(el.dataset || {});
613
+
614
+ result.scrollAnimations.push({
615
+ type: detectScrollAnimationType(classes, dataAttrs),
616
+ trigger: el.dataset.aos || el.dataset.scroll || 'scroll',
617
+ element: el.tagName.toLowerCase() + (el.className ? '.' + el.className.split(' ')[0] : '')
618
+ });
619
+ });
620
+
621
+ // Detect sticky/pinned sections (common in GSAP sites)
622
+ document.querySelectorAll('[class*="sticky"], [class*="pinned"], [style*="position: sticky"]')
623
+ .forEach(el => {
624
+ result.scrollAnimations.push({
625
+ type: 'sticky-section',
626
+ element: el.tagName.toLowerCase()
627
+ });
628
+ });
629
+
630
+ function detectScrollAnimationType(classes, dataAttrs) {
631
+ if (classes.includes('stack') || dataAttrs.includes('stack')) return 'stacking-cards';
632
+ if (classes.includes('parallax') || dataAttrs.includes('parallax')) return 'parallax';
633
+ if (classes.includes('fade')) return 'fade-in';
634
+ if (classes.includes('slide')) return 'slide-in';
635
+ if (classes.includes('scale')) return 'scale-in';
636
+ return 'custom-scroll';
637
+ }
638
+
639
+ // ========== DETECT DECORATIVE ELEMENTS ==========
640
+
641
+ const svgs = document.querySelectorAll('svg:not([class*="icon"]):not([width="24"]):not([width="16"])');
642
+ svgs.forEach(svg => {
643
+ const viewBox = svg.getAttribute('viewBox');
644
+ const width = parseInt(svg.getAttribute('width') || '0');
645
+ const height = parseInt(svg.getAttribute('height') || '0');
646
+
647
+ // Large SVGs are likely decorative
648
+ if (width > 100 || height > 100 || (viewBox && parseInt(viewBox.split(' ')[2]) > 100)) {
649
+ const paths = svg.querySelectorAll('path, circle, ellipse');
650
+ const isBlob = Array.from(paths).some(p => {
651
+ const d = p.getAttribute('d') || '';
652
+ return d.includes('C') && d.length > 200; // Curved paths = likely blob
653
+ });
654
+
655
+ result.decorativeElements.push({
656
+ type: isBlob ? 'blob' : 'svg-decoration',
657
+ size: { width, height },
658
+ colors: extractSvgColors(svg)
659
+ });
660
+ }
661
+ });
662
+
663
+ // Detect gradient backgrounds
664
+ document.querySelectorAll('*').forEach(el => {
665
+ const bg = window.getComputedStyle(el).backgroundImage;
666
+ if (bg && bg.includes('gradient')) {
667
+ result.decorativeElements.push({
668
+ type: 'gradient',
669
+ value: bg.substring(0, 100) + '...'
670
+ });
671
+ }
672
+ });
673
+
674
+ // Detect 3D elements
675
+ document.querySelectorAll('[class*="3d"], [style*="perspective"], [style*="rotateX"], [style*="rotateY"]')
676
+ .forEach(el => {
677
+ result.decorativeElements.push({
678
+ type: '3d-element',
679
+ element: el.tagName.toLowerCase()
680
+ });
681
+ });
682
+
683
+ function extractSvgColors(svg) {
684
+ const colors = new Set();
685
+ svg.querySelectorAll('[fill], [stroke]').forEach(el => {
686
+ const fill = el.getAttribute('fill');
687
+ const stroke = el.getAttribute('stroke');
688
+ if (fill && fill !== 'none') colors.add(fill);
689
+ if (stroke && stroke !== 'none') colors.add(stroke);
690
+ });
691
+ return Array.from(colors).slice(0, 5);
692
+ }
693
+
694
+ // ========== DETECT DESIGN STYLE ==========
695
+
696
+ const allElements = document.querySelectorAll('*');
697
+ const styleIndicators = {
698
+ neoBrutalism: 0,
699
+ minimalist: 0,
700
+ glassmorphism: 0,
701
+ neumorphism: 0,
702
+ modernSaas: 0,
703
+ playful: 0
704
+ };
705
+
706
+ allElements.forEach(el => {
707
+ const s = window.getComputedStyle(el);
708
+
709
+ // Neo-Brutalism indicators
710
+ if (s.borderWidth && parseInt(s.borderWidth) >= 2) styleIndicators.neoBrutalism += 2;
711
+ if (s.boxShadow && s.boxShadow.includes('0px 0px 0px') || !s.boxShadow.includes('blur')) {
712
+ styleIndicators.neoBrutalism += 1; // Solid shadows
713
+ }
714
+ if (s.borderRadius && parseInt(s.borderRadius) >= 8 && parseInt(s.borderRadius) <= 16) {
715
+ styleIndicators.neoBrutalism += 1;
716
+ }
717
+
718
+ // Minimalist indicators
719
+ if (s.borderWidth === '0px' || s.borderWidth === '1px') styleIndicators.minimalist += 0.5;
720
+ if (!s.boxShadow || s.boxShadow === 'none') styleIndicators.minimalist += 0.5;
721
+
722
+ // Glassmorphism indicators
723
+ if (s.backdropFilter && s.backdropFilter !== 'none') styleIndicators.glassmorphism += 3;
724
+ if (s.backgroundColor && s.backgroundColor.includes('rgba') && parseFloat(s.backgroundColor.split(',')[3]) < 0.8) {
725
+ styleIndicators.glassmorphism += 1;
726
+ }
727
+
728
+ // Neumorphism indicators
729
+ if (s.boxShadow && s.boxShadow.includes('inset')) styleIndicators.neumorphism += 2;
730
+
731
+ // Modern SaaS indicators
732
+ if (s.boxShadow && s.boxShadow.includes('rgba') && s.boxShadow.includes('blur')) {
733
+ styleIndicators.modernSaas += 1;
734
+ }
735
+ if (parseInt(s.borderRadius) >= 12) styleIndicators.modernSaas += 0.5;
736
+
737
+ // Playful indicators
738
+ if (s.borderRadius && parseInt(s.borderRadius) >= 24) styleIndicators.playful += 1;
739
+ if (s.transform && s.transform !== 'none') styleIndicators.playful += 0.5;
740
+ });
741
+
742
+ // Determine style
743
+ const maxStyle = Object.entries(styleIndicators)
744
+ .sort((a, b) => b[1] - a[1])[0];
745
+
746
+ const styleDescriptions = {
747
+ neoBrutalism: {
748
+ name: 'Neo-Brutalism',
749
+ characteristics: ['Bold borders (2-4px)', 'Solid shadows (no blur)', 'High contrast', 'Chunky rounded corners'],
750
+ feel: 'Bold, energetic, playful'
751
+ },
752
+ minimalist: {
753
+ name: 'Minimalist',
754
+ characteristics: ['Clean lines', 'Subtle or no shadows', 'Lots of whitespace', 'Simple typography'],
755
+ feel: 'Clean, professional, trustworthy'
756
+ },
757
+ glassmorphism: {
758
+ name: 'Glassmorphism',
759
+ characteristics: ['Frosted glass effect', 'Backdrop blur', 'Semi-transparent backgrounds', 'Layered depth'],
760
+ feel: 'Modern, premium, tech-forward'
761
+ },
762
+ neumorphism: {
763
+ name: 'Neumorphism',
764
+ characteristics: ['Soft inset shadows', 'Extruded elements', 'Monochromatic palette'],
765
+ feel: 'Soft, touchable, futuristic'
766
+ },
767
+ modernSaas: {
768
+ name: 'Modern SaaS',
769
+ characteristics: ['Soft shadows with blur', 'Rounded corners', 'Gradient accents', 'Card-based layout'],
770
+ feel: 'Professional, friendly, reliable'
771
+ },
772
+ playful: {
773
+ name: 'Playful/Creative',
774
+ characteristics: ['Large border radius', 'Animations', 'Bright colors', 'Asymmetric layouts'],
775
+ feel: 'Fun, creative, approachable'
776
+ }
777
+ };
778
+
779
+ result.style = {
780
+ detected: styleDescriptions[maxStyle[0]].name,
781
+ confidence: Math.min(Math.round((maxStyle[1] / 50) * 100), 100),
782
+ characteristics: styleDescriptions[maxStyle[0]].characteristics,
783
+ feel: styleDescriptions[maxStyle[0]].feel,
784
+ scores: styleIndicators
785
+ };
786
+
787
+ return result;
788
+ }`
789
+ });
790
+ }
791
+
792
+ const styleData = await detectStyleAndAnimations();
793
+ ```
794
+
795
+ **Report:**
796
+ ```
797
+ ✅ Style & Animations Detected!
798
+
799
+ 🎨 Design Style: ${styleData.style.detected} (${styleData.style.confidence}% confidence)
800
+ Characteristics: ${styleData.style.characteristics.join(', ')}
801
+ Feel: ${styleData.style.feel}
802
+
803
+ 📚 Animation Libraries:
804
+ ${styleData.animationLibraries.map(lib => ` ✅ ${lib.name} ${lib.version || ''}`).join('\n') || ' (none detected)'}
805
+
806
+ 🎬 Scroll Animations: ${styleData.scrollAnimations.length} detected
807
+ ${styleData.scrollAnimations.slice(0, 5).map(a => ` - ${a.type}`).join('\n')}
808
+
809
+ 🖼️ Decorative Elements: ${styleData.decorativeElements.length} found
810
+ ${styleData.decorativeElements.slice(0, 5).map(d => ` - ${d.type}`).join('\n')}
811
+
545
812
  🔄 Extracting component animations (hover/focus states)...
546
813
  ```
547
814
 
@@ -702,223 +969,226 @@ function generateDescription(defaultStyle, hoverStyle) {
702
969
 
703
970
  ```javascript
704
971
  // Create temp directory
705
- await Bash: mkdir -p design-system/extracted/${siteName}/screenshots
972
+ await Bash: mkdir -p .claude/extractions/screenshots/${siteName}
706
973
 
707
974
  // Try fullpage
708
975
  try {
709
976
  await mcp__chrome-devtools__take_screenshot({
710
977
  fullPage: true,
711
978
  format: 'png',
712
- filePath: `design-system/extracted/${siteName}/screenshots/full-page.png`
979
+ filePath: `.claude/extractions/screenshots/${siteName}/full-page.png`
713
980
  });
714
981
  } catch {
715
982
  // Fallback: viewport only
716
983
  await mcp__chrome-devtools__take_screenshot({
717
984
  fullPage: false,
718
985
  format: 'png',
719
- filePath: `design-system/extracted/${siteName}/screenshots/viewport.png`
986
+ filePath: `.claude/extractions/screenshots/${siteName}/viewport.png`
720
987
  });
721
988
  }
722
989
  ```
723
990
 
724
991
  ---
725
992
 
726
- ## STEP 5: AI Psychology Analysis
993
+ ## STEP 5: Generate Site JSON (Lean Format)
727
994
 
728
- Read screenshot and analyze:
995
+ Generate a lean JSON file per site (~500 tokens):
729
996
 
730
997
  ```javascript
731
- const screenshotPath = exists(`design-system/extracted/${siteName}/screenshots/full-page.png`)
732
- ? `design-system/extracted/${siteName}/screenshots/full-page.png`
733
- : `design-system/extracted/${siteName}/screenshots/viewport.png`;
998
+ const siteData = {
999
+ meta: {
1000
+ site_name: siteName,
1001
+ url: url,
1002
+ extracted_at: new Date().toISOString(),
1003
+ extractor_version: '3.0.0'
1004
+ },
734
1005
 
735
- const screenshot = Read(screenshotPath);
1006
+ // ========== STYLE (from STEP 2.5) ==========
1007
+ style: {
1008
+ detected: styleData.style.detected,
1009
+ confidence: styleData.style.confidence,
1010
+ characteristics: styleData.style.characteristics,
1011
+ feel: styleData.style.feel
1012
+ },
736
1013
 
737
- const analysisPrompt = `
738
- You are a UX/UI design psychologist and systems architect.
1014
+ // ========== ANIMATION LIBRARIES ==========
1015
+ animation_libraries: styleData.animationLibraries,
739
1016
 
740
- Analyze this website's design and provide deep psychology insights.
1017
+ // ========== SCROLL ANIMATIONS ==========
1018
+ scroll_animations: {
1019
+ detected: styleData.scrollAnimations.length > 0,
1020
+ patterns: [...new Set(styleData.scrollAnimations.map(a => a.type))],
1021
+ count: styleData.scrollAnimations.length
1022
+ },
741
1023
 
742
- Visual Screenshot: [attached]
1024
+ // ========== DECORATIVE ELEMENTS ==========
1025
+ decorative_elements: {
1026
+ types: [...new Set(styleData.decorativeElements.map(d => d.type))],
1027
+ has_blobs: styleData.decorativeElements.some(d => d.type === 'blob'),
1028
+ has_gradients: styleData.decorativeElements.some(d => d.type === 'gradient'),
1029
+ has_3d: styleData.decorativeElements.some(d => d.type === '3d-element')
1030
+ },
743
1031
 
744
- Extracted CSS Data:
745
- - Colors: ${JSON.stringify(colors, null, 2)}
746
- - Typography: ${JSON.stringify(typography, null, 2)}
747
- - Shadows: ${JSON.stringify(shadows, null, 2)}
748
- - Spacing: ${JSON.stringify(spacing, null, 2)}
749
- - Button Styles: ${JSON.stringify(buttons.slice(0, 2), null, 2)}
750
- - Card Styles: ${JSON.stringify(cards.slice(0, 2), null, 2)}
1032
+ // ========== COLORS (Simplified) ==========
1033
+ colors: {
1034
+ primary: colors.backgrounds.slice(0, 3).map(c => c.hex),
1035
+ text: colors.texts.slice(0, 3).map(c => c.hex),
1036
+ accent: colors.borders.slice(0, 2).map(c => c.hex)
1037
+ },
751
1038
 
752
- Component Animations:
753
- ${Object.entries(componentAnimations).slice(0, 3).map(([id, anim]) =>
754
- `- ${id}: ${anim.description}`
755
- ).join('\n')}
1039
+ // ========== TYPOGRAPHY (Simplified) ==========
1040
+ typography: {
1041
+ fonts: typography.allFonts.slice(0, 3),
1042
+ weights: typography.allWeights,
1043
+ heading_style: typography.h1[0] ? {
1044
+ fontSize: typography.h1[0].fontSize,
1045
+ fontWeight: typography.h1[0].fontWeight
1046
+ } : null
1047
+ },
756
1048
 
757
- Wrap your analysis in <pondering> tags and include:
1049
+ // ========== COMPONENT ANIMATIONS ==========
1050
+ component_animations: {
1051
+ button_hover: componentAnimations['button-0']?.description || 'none',
1052
+ card_hover: componentAnimations['card-0']?.description || 'none',
1053
+ input_focus: componentAnimations['input-0']?.description || 'none'
1054
+ },
758
1055
 
759
- 1. **Design Style Classification** (Neo-Brutalism, Minimalist, Modern SaaS, etc.)
760
- 2. **Visual Principles** (what design principles are used?)
761
- 3. **Psychology** (what emotions does it evoke? why?)
762
- 4. **Target Audience** (who is this for?)
763
- 5. **Key Differentiators** (how is it different from typical sites?)
764
- 6. **Design Philosophy** (core beliefs that guide this design)
1056
+ // ========== SPACING ==========
1057
+ spacing: {
1058
+ grid_base: spacing.detectedGrid,
1059
+ common: spacing.commonValues.slice(0, 8)
1060
+ },
765
1061
 
766
- Be specific with examples from the CSS data.
767
- `;
1062
+ // ========== SHADOWS ==========
1063
+ shadows: shadows.shadows.slice(0, 5),
768
1064
 
769
- const analysis = await LLM({
770
- prompt: analysisPrompt,
771
- images: [screenshot]
772
- });
1065
+ // ========== BORDER RADIUS ==========
1066
+ border_radius: shadows.borderRadii.slice(0, 5)
1067
+ };
773
1068
 
774
- Write(`design-system/extracted/${siteName}/analysis.md`, analysis);
1069
+ // Write site-specific JSON
1070
+ Write(`.claude/extractions/${siteName}.json`, JSON.stringify(siteData, null, 2));
775
1071
  ```
776
1072
 
777
1073
  **Report:**
778
1074
  ```
779
- Psychology Analysis Complete!
1075
+ Site Data Extracted: ${siteName}
780
1076
 
781
- 🧠 Design style detected from analysis
782
- 📁 Saved: analysis.md
1077
+ 🎨 Style: ${siteData.style.detected} (${siteData.style.confidence}% confidence)
1078
+ 📚 Animation Libraries: ${siteData.animation_libraries.map(l => l.name).join(', ') || 'none'}
1079
+ 🎬 Scroll Animations: ${siteData.scroll_animations.patterns.join(', ') || 'none'}
1080
+ 🖼️ Decorative: ${siteData.decorative_elements.types.join(', ') || 'none'}
783
1081
 
784
- 🔄 Generating final YAML output...
1082
+ 📁 Saved: .claude/extractions/${siteName}.json
785
1083
  ```
786
1084
 
787
1085
  ---
788
1086
 
789
- ## STEP 6: Generate data.yaml (17 Sections)
1087
+ ## STEP 6: Merge Multiple Sites (If Multi-URL)
790
1088
 
791
- ```javascript
792
- const yamlData = {
793
- meta: {
794
- site_name: siteName,
795
- url: url,
796
- extracted_at: new Date().toISOString(),
797
- extractor_version: '2.0.0',
798
- coverage: {
799
- total_sections: 17,
800
- detected_sections: 15, // Count how many have detected: true
801
- percentage: Math.round((15 / 17) * 100)
802
- }
803
- },
1089
+ If extracting from multiple sites, merge insights:
804
1090
 
805
- sections: {
806
- overview: {
807
- detected: true,
808
- style: 'Auto-detected from analysis',
809
- tech_stack: 'Framework-agnostic'
810
- },
811
-
812
- design_philosophy: {
813
- detected: true,
814
- from_analysis: true
815
- },
816
-
817
- color_palette: {
818
- detected: true,
819
- primary: colors.backgrounds.slice(0, 5),
820
- secondary: colors.backgrounds.slice(5, 10),
821
- text_colors: colors.texts,
822
- border_colors: colors.borders
823
- },
824
-
825
- typography: {
826
- detected: true,
827
- fonts: typography.allFonts,
828
- weights: typography.allWeights,
829
- sizes: typography.allSizes,
830
- h1: typography.h1,
831
- h2: typography.h2,
832
- h3: typography.h3,
833
- body: typography.body
834
- },
1091
+ ```javascript
1092
+ // Only run if multiple sites
1093
+ if (sites.length > 1) {
1094
+ const allSiteData = sites.map(site => {
1095
+ const data = JSON.parse(Read(`.claude/extractions/${site.siteName}.json`));
1096
+ return { siteName: site.siteName, ...data };
1097
+ });
835
1098
 
836
- spacing_system: {
837
- detected: true,
838
- grid_base: spacing.detectedGrid,
839
- paddings: spacing.paddings,
840
- margins: spacing.margins,
841
- gaps: spacing.gaps,
842
- common_values: spacing.commonValues
1099
+ const mergedInsights = {
1100
+ meta: {
1101
+ generated_at: new Date().toISOString(),
1102
+ sites_count: sites.length,
1103
+ sites: sites.map(s => s.siteName)
843
1104
  },
844
1105
 
845
- component_styles: {
846
- detected: true,
847
- buttons: buttons.map((btn, i) => ({
848
- ...btn,
849
- animation: componentAnimations[`button-${i}`] || null
850
- })),
851
- cards: cards.map((card, i) => ({
852
- ...card,
853
- animation: componentAnimations[`card-${i}`] || null
1106
+ // ========== STYLES FROM ALL SITES ==========
1107
+ styles: allSiteData.map(site => ({
1108
+ site: site.siteName,
1109
+ style: site.style.detected,
1110
+ confidence: site.style.confidence,
1111
+ characteristics: site.style.characteristics,
1112
+ feel: site.style.feel
1113
+ })),
1114
+
1115
+ // ========== ANIMATION LIBRARIES (Combined) ==========
1116
+ animation_libraries: [...new Set(
1117
+ allSiteData.flatMap(site => site.animation_libraries.map(l => l.name))
1118
+ )].map(name => {
1119
+ const sources = allSiteData
1120
+ .filter(site => site.animation_libraries.some(l => l.name === name))
1121
+ .map(site => site.siteName);
1122
+ return { name, sources };
1123
+ }),
1124
+
1125
+ // ========== SCROLL ANIMATIONS (Combined) ==========
1126
+ scroll_animations: [...new Set(
1127
+ allSiteData.flatMap(site => site.scroll_animations.patterns)
1128
+ )].map(pattern => {
1129
+ const sources = allSiteData
1130
+ .filter(site => site.scroll_animations.patterns.includes(pattern))
1131
+ .map(site => site.siteName);
1132
+ return { pattern, sources };
1133
+ }),
1134
+
1135
+ // ========== DECORATIVE ELEMENTS (Combined) ==========
1136
+ decorative_elements: [...new Set(
1137
+ allSiteData.flatMap(site => site.decorative_elements.types)
1138
+ )].map(type => {
1139
+ const sources = allSiteData
1140
+ .filter(site => site.decorative_elements.types.includes(type))
1141
+ .map(site => site.siteName);
1142
+ return { type, sources };
1143
+ }),
1144
+
1145
+ // ========== COMPONENT ANIMATIONS (Combined) ==========
1146
+ component_animations: {
1147
+ button_hover: allSiteData.map(site => ({
1148
+ site: site.siteName,
1149
+ animation: site.component_animations.button_hover
854
1150
  })),
855
- inputs: inputs.map((input, i) => ({
856
- ...input,
857
- animation: componentAnimations[`input-${i}`] || null
1151
+ card_hover: allSiteData.map(site => ({
1152
+ site: site.siteName,
1153
+ animation: site.component_animations.card_hover
858
1154
  }))
859
1155
  },
860
1156
 
861
- shadows_elevation: {
862
- detected: true,
863
- values: shadows.shadows
864
- },
865
-
866
- animations_transitions: {
867
- detected: true,
868
- keyframes: animations.keyframes,
869
- transitions: animations.transitions
870
- },
871
-
872
- border_styles: {
873
- detected: true,
874
- widths: shadows.borderWidths
875
- },
876
-
877
- border_radius: {
878
- detected: true,
879
- values: shadows.borderRadii
880
- },
881
-
882
- opacity_transparency: {
883
- detected: true,
884
- values: [0.5, 0.7, 0.9] // Standard
885
- },
886
-
887
- z_index_layers: {
888
- detected: false,
889
- fallback: 'standard'
890
- },
1157
+ // ========== COLORS (All Options) ==========
1158
+ color_palettes: allSiteData.map(site => ({
1159
+ site: site.siteName,
1160
+ primary: site.colors.primary,
1161
+ text: site.colors.text
1162
+ })),
1163
+
1164
+ // ========== TYPOGRAPHY (All Options) ==========
1165
+ typography_options: allSiteData.map(site => ({
1166
+ site: site.siteName,
1167
+ fonts: site.typography.fonts
1168
+ }))
1169
+ };
891
1170
 
892
- responsive_breakpoints: {
893
- detected: false,
894
- fallback: 'standard'
895
- },
1171
+ Write('.claude/extractions/merged-insights.json', JSON.stringify(mergedInsights, null, 2));
1172
+ }
1173
+ ```
896
1174
 
897
- css_variables: {
898
- generated: true
899
- },
1175
+ **Report (Multi-Site):**
1176
+ ```
1177
+ ✅ Merged Insights Generated!
900
1178
 
901
- layout_patterns: {
902
- detected: true,
903
- container_width: '1280px',
904
- grid_columns: 12
905
- },
1179
+ 📊 Combined from ${sites.length} sites:
1180
+ ${sites.map(s => ` - ${s.siteName}`).join('\n')}
906
1181
 
907
- example_components: {
908
- generated: true
909
- },
1182
+ 🎨 Styles found:
1183
+ ${mergedInsights.styles.map(s => ` - ${s.style} (${s.site})`).join('\n')}
910
1184
 
911
- additional_sections: {
912
- accessibility: { detected: true },
913
- best_practices: { generated: true }
914
- }
915
- },
1185
+ 📚 Animation Libraries:
1186
+ ${mergedInsights.animation_libraries.map(l => ` - ${l.name} (from: ${l.sources.join(', ')})`).join('\n')}
916
1187
 
917
- animations: componentAnimations
918
- };
1188
+ 🎬 Scroll Patterns:
1189
+ ${mergedInsights.scroll_animations.map(a => ` - ${a.pattern} (from: ${a.sources.join(', ')})`).join('\n')}
919
1190
 
920
- const yamlContent = YAML.stringify(yamlData, null, 2);
921
- Write(`design-system/extracted/${siteName}/data.yaml`, yamlContent);
1191
+ 📁 Saved: .claude/extractions/merged-insights.json
922
1192
  ```
923
1193
 
924
1194
  ---
@@ -926,42 +1196,47 @@ Write(`design-system/extracted/${siteName}/data.yaml`, yamlContent);
926
1196
  ## STEP 7: Final Report
927
1197
 
928
1198
  ```
929
- ✅ Extraction Complete: ${siteName}
930
-
931
- 📊 Coverage: ${yamlData.meta.coverage.detected_sections}/17 sections (${yamlData.meta.coverage.percentage}%)
932
- ✅ Colors (${colors.backgrounds.length + colors.texts.length + colors.borders.length} total)
933
- Typography (${typography.allFonts.length} fonts, ${typography.allWeights.length} weights)
934
- ✅ Spacing (${spacing.detectedGrid}px grid detected)
935
- Components (${buttons.length} buttons, ${cards.length} cards, ${inputs.length} inputs)
936
- Shadows (${shadows.shadows.length} unique values)
937
- Animations (${animations.keyframes.length} @keyframes, ${animations.transitions.length} transitions)
938
- ${yamlData.sections.z_index_layers.detected ? '✅' : ''} Z-index
939
- ${yamlData.sections.responsive_breakpoints.detected ? '✅' : ''} Breakpoints
1199
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1200
+ ✅ EXTRACTION COMPLETE
1201
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1202
+
1203
+ 📊 Sites Extracted: ${sites.length}
1204
+ ${sites.map(s => `
1205
+ ┌─ ${s.siteName} ─────────────────────────────────────────┐
1206
+ 🎨 Style: ${siteData.style.detected} (${siteData.style.confidence}%)
1207
+ 📚 Libraries: ${siteData.animation_libraries.map(l => l.name).join(', ') || 'none'}
1208
+ │ 🎬 Scroll: ${siteData.scroll_animations.patterns.join(', ') || 'none'}
1209
+ │ 🖼️ Decorative: ${siteData.decorative_elements.types.join(', ') || 'none'}
1210
+ │ 📁 File: .claude/extractions/${s.siteName}.json
1211
+ └─────────────────────────────────────────────────────────┘
1212
+ `).join('')}
1213
+
1214
+ ${sites.length > 1 ? `
1215
+ 📋 Merged Insights: .claude/extractions/merged-insights.json
1216
+ → Use this in /designsetup to pick features from each site
1217
+ ` : ''}
1218
+
1219
+ 📸 Screenshots: .claude/extractions/screenshots/
1220
+ ${sites.map(s => `- ${s.siteName}/full-page.png`).join('\n ')}
1221
+
1222
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
940
1223
 
941
- 📸 Screenshots: ${Object.keys(componentAnimations).length * 2 + 1} captured
942
- - full-page.png (or viewport.png)
943
- - ${Object.keys(componentAnimations).length} components × 2 states
944
-
945
- 📁 Output:
946
- ✓ design-system/extracted/${siteName}/data.yaml
947
- ✓ design-system/extracted/${siteName}/analysis.md
948
- ✓ design-system/extracted/${siteName}/screenshots/ (${Object.keys(componentAnimations).length * 2 + 1} files)
949
-
950
- ⏱️ Time: ${Date.now() - startTime}ms
1224
+ 🚀 Next Steps:
951
1225
 
952
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1226
+ 1. Extract more references (optional):
1227
+ /extract https://another-site.com
953
1228
 
954
- 🚀 Next Steps:
1229
+ 2. Generate design system:
1230
+ /designsetup
955
1231
 
956
- 1. Extract more sites:
957
- /extract https://blackbird.com
958
- /extract https://linear.app
1232
+ Will read: .claude/extractions/*.json
1233
+ Will ask you to pick: style, animations, theme
1234
+ → Will output: design-system/tokens.json
959
1235
 
960
- 2. Generate style guide:
961
- /designsetup @prd.md @project.md
1236
+ 3. Review extracted data:
1237
+ Read .claude/extractions/${sites[0].siteName}.json
962
1238
 
963
- 3. Or review extracted data:
964
- cat design-system/extracted/${siteName}/analysis.md
1239
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
965
1240
  ```
966
1241
 
967
1242
  ---