design-clone 2.1.0 → 2.3.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 +13 -34
- package/SKILL.md +69 -45
- package/bin/cli.js +22 -4
- package/bin/commands/clone-site.js +31 -171
- package/bin/commands/help.js +19 -6
- package/bin/commands/init.js +9 -86
- package/bin/commands/uninstall.js +105 -0
- package/bin/commands/update.js +70 -0
- package/bin/commands/verify.js +7 -14
- package/bin/utils/paths.js +28 -0
- package/bin/utils/validate.js +2 -22
- package/bin/utils/version.js +23 -0
- package/docs/code-standards.md +789 -0
- package/docs/codebase-summary.md +533 -286
- package/docs/index.md +74 -0
- package/docs/project-overview-pdr.md +797 -0
- package/docs/system-architecture.md +718 -0
- package/package.json +14 -17
- package/src/ai/prompts/design-tokens/basic.md +80 -0
- package/src/ai/prompts/design-tokens/section-with-css.md +41 -0
- package/src/ai/prompts/design-tokens/section.md +48 -0
- package/src/ai/prompts/design-tokens/with-css.md +87 -0
- package/src/ai/prompts/structure-analysis/basic.md +55 -0
- package/src/ai/prompts/structure-analysis/with-context.md +59 -0
- package/src/ai/prompts/structure-analysis/with-dimensions.md +63 -0
- package/src/ai/prompts/structure-analysis/with-hierarchy.md +73 -0
- package/src/ai/prompts/ux-audit/aggregation.md +42 -0
- package/src/ai/prompts/ux-audit/desktop.md +92 -0
- package/src/ai/prompts/ux-audit/mobile.md +93 -0
- package/src/ai/prompts/ux-audit/tablet.md +92 -0
- package/src/core/animation/animation-extractor-ast.js +183 -0
- package/src/core/animation/animation-extractor-output.js +152 -0
- package/src/core/animation/animation-extractor.js +178 -0
- package/src/core/animation/state-capture-detection.js +200 -0
- package/src/core/animation/state-capture.js +193 -0
- package/src/core/capture/browser-context-pool.js +96 -0
- package/src/core/capture/multi-page-screenshot-page.js +110 -0
- package/src/core/capture/multi-page-screenshot.js +208 -0
- package/src/core/capture/screenshot-extraction.js +186 -0
- package/src/core/capture/screenshot-helpers.js +175 -0
- package/src/core/capture/screenshot-orchestrator.js +174 -0
- package/src/core/capture/screenshot-viewport.js +93 -0
- package/src/core/capture/screenshot.js +192 -0
- package/src/core/content/content-counter-dom.js +191 -0
- package/src/core/content/content-counter.js +76 -0
- package/src/core/css/breakpoint-detector.js +66 -0
- package/src/core/css/chromium-defaults.json +23 -0
- package/src/core/css/computed-style-extractor.js +102 -0
- package/src/core/css/css-chunker.js +103 -0
- package/src/core/css/filter-css-dead-code.js +120 -0
- package/src/core/css/filter-css-html-analyzer.js +110 -0
- package/src/core/css/filter-css-selector-matcher.js +172 -0
- package/src/core/css/filter-css.js +206 -0
- package/src/core/css/merge-css-atrule-processor.js +158 -0
- package/src/core/css/merge-css-file-io.js +68 -0
- package/src/core/css/merge-css.js +148 -0
- package/src/core/detection/framework-detector-routing.js +68 -0
- package/src/core/detection/framework-detector-signals.js +65 -0
- package/src/core/detection/framework-detector.js +198 -0
- package/src/core/dimension/dimension-extractor-card-detector.js +82 -0
- package/src/core/dimension/dimension-extractor.js +317 -0
- package/src/core/dimension/dimension-output-ai-summary.js +111 -0
- package/src/core/dimension/dimension-output.js +173 -0
- package/src/core/dimension/dom-tree-analyzer-tree-builders.js +95 -0
- package/src/core/dimension/dom-tree-analyzer.js +191 -0
- package/src/core/discovery/app-state-snapshot-capture.js +195 -0
- package/src/core/discovery/app-state-snapshot-utils.js +178 -0
- package/src/core/discovery/app-state-snapshot.js +131 -0
- package/src/core/discovery/discover-pages-routes.js +84 -0
- package/src/core/discovery/discover-pages-utils.js +177 -0
- package/src/core/discovery/discover-pages.js +191 -0
- package/src/core/html/html-extractor-inline-styler.js +70 -0
- package/src/core/html/html-extractor.js +147 -0
- package/src/core/html/semantic-enhancer-mappings.js +200 -0
- package/src/core/html/semantic-enhancer-page.js +148 -0
- package/src/core/html/semantic-enhancer.js +135 -0
- package/src/core/links/rewrite-links-css-rewriter.js +53 -0
- package/src/core/links/rewrite-links.js +173 -0
- package/src/core/media/asset-validator.js +118 -0
- package/src/core/media/extract-assets-downloader.js +187 -0
- package/src/core/media/extract-assets-page-scraper.js +115 -0
- package/src/core/media/extract-assets.js +159 -0
- package/src/core/media/video-capture-convert.js +200 -0
- package/src/core/media/video-capture.js +201 -0
- package/src/core/{lazy-loader.js → page-prep/lazy-loader.js} +37 -39
- package/src/core/section/section-cropper-helpers.js +43 -0
- package/src/core/{section-cropper.js → section/section-cropper.js} +11 -88
- package/src/core/section/section-detector-strategies.js +139 -0
- package/src/core/section/section-detector-utils.js +100 -0
- package/src/core/section/section-detector.js +88 -0
- package/src/core/tests/test-section-cropper.js +2 -2
- package/src/core/tests/test-section-detector.js +2 -2
- package/src/post-process/enhance-assets.js +29 -4
- package/src/post-process/fetch-images-unsplash-client.js +123 -0
- package/src/post-process/fetch-images.js +60 -263
- package/src/post-process/inject-gosnap.js +88 -0
- package/src/post-process/inject-icons-svg-replacer.js +76 -0
- package/src/post-process/inject-icons.js +47 -200
- package/src/route-discoverers/base-discoverer-utils.js +137 -0
- package/src/route-discoverers/base-discoverer.js +29 -118
- package/src/route-discoverers/index.js +1 -1
- package/src/shared/config.js +38 -0
- package/src/shared/error-codes.js +31 -0
- package/src/shared/viewports.js +46 -0
- package/src/utils/browser.js +0 -7
- package/src/utils/helpers.js +4 -0
- package/src/utils/log.js +12 -0
- package/src/utils/playwright-loader.js +76 -0
- package/src/utils/playwright.js +3 -69
- package/src/utils/progress.js +32 -0
- package/src/verification/generate-audit-report-css-fixes.js +52 -0
- package/src/verification/generate-audit-report-sections.js +158 -0
- package/src/verification/generate-audit-report.js +5 -281
- package/src/verification/quality-scorer.js +92 -0
- package/src/verification/verify-footer-checks.js +103 -0
- package/src/verification/verify-footer-helpers.js +178 -0
- package/src/verification/verify-footer.js +23 -381
- package/src/verification/verify-header-checks.js +104 -0
- package/src/verification/verify-header-helpers.js +156 -0
- package/src/verification/verify-header.js +23 -365
- package/src/verification/verify-layout-report.js +101 -0
- package/src/verification/verify-layout.js +13 -259
- package/src/verification/verify-menu-checks.js +104 -0
- package/src/verification/verify-menu-helpers.js +112 -0
- package/src/verification/verify-menu.js +17 -285
- package/src/verification/verify-slider-checks.js +115 -0
- package/src/verification/verify-slider-constants.js +65 -0
- package/src/verification/verify-slider-helpers.js +164 -0
- package/src/verification/verify-slider.js +23 -414
- package/.env.example +0 -14
- package/docs/basic-clone.md +0 -63
- package/docs/cli-reference.md +0 -316
- package/docs/design-clone-architecture.md +0 -492
- package/docs/pixel-perfect.md +0 -117
- package/docs/project-roadmap.md +0 -382
- package/docs/troubleshooting.md +0 -170
- package/requirements.txt +0 -5
- package/src/ai/__pycache__/analyze-structure.cpython-313.pyc +0 -0
- package/src/ai/__pycache__/extract-design-tokens.cpython-313.pyc +0 -0
- package/src/ai/analyze-structure.py +0 -375
- package/src/ai/extract-design-tokens.py +0 -782
- package/src/ai/prompts/__init__.py +0 -2
- package/src/ai/prompts/__pycache__/__init__.cpython-313.pyc +0 -0
- package/src/ai/prompts/__pycache__/design_tokens.cpython-313.pyc +0 -0
- package/src/ai/prompts/__pycache__/structure_analysis.cpython-313.pyc +0 -0
- package/src/ai/prompts/__pycache__/ux_audit.cpython-313.pyc +0 -0
- package/src/ai/prompts/design_tokens.py +0 -316
- package/src/ai/prompts/structure_analysis.py +0 -592
- package/src/ai/prompts/ux_audit.py +0 -198
- package/src/ai/ux-audit.js +0 -596
- package/src/core/animation-extractor.js +0 -526
- package/src/core/app-state-snapshot.js +0 -511
- package/src/core/content-counter.js +0 -342
- package/src/core/design-tokens.js +0 -103
- package/src/core/dimension-extractor.js +0 -438
- package/src/core/dimension-output.js +0 -305
- package/src/core/discover-pages.js +0 -542
- package/src/core/dom-tree-analyzer.js +0 -298
- package/src/core/extract-assets.js +0 -468
- package/src/core/filter-css.js +0 -499
- package/src/core/framework-detector.js +0 -538
- package/src/core/html-extractor.js +0 -212
- package/src/core/merge-css.js +0 -407
- package/src/core/multi-page-screenshot.js +0 -380
- package/src/core/rewrite-links.js +0 -226
- package/src/core/screenshot.js +0 -701
- package/src/core/section-detector.js +0 -386
- package/src/core/semantic-enhancer.js +0 -492
- package/src/core/state-capture.js +0 -598
- package/src/core/video-capture.js +0 -546
- package/src/utils/__init__.py +0 -16
- package/src/utils/__pycache__/__init__.cpython-313.pyc +0 -0
- package/src/utils/__pycache__/env.cpython-313.pyc +0 -0
- package/src/utils/env.py +0 -134
- /package/src/core/{css-extractor.js → css/css-extractor.js} +0 -0
- /package/src/core/{cookie-handler.js → page-prep/cookie-handler.js} +0 -0
- /package/src/core/{page-readiness.js → page-prep/page-readiness.js} +0 -0
|
@@ -1,592 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Structure Analysis Prompts
|
|
3
|
-
|
|
4
|
-
Prompts for analyzing website structure from screenshots using Gemini Vision.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
# Structure analysis prompt (basic - screenshot only)
|
|
8
|
-
STRUCTURE_PROMPT = """Analyze this website screenshot and describe the page structure in detail.
|
|
9
|
-
|
|
10
|
-
Output a markdown document with the following sections:
|
|
11
|
-
|
|
12
|
-
# Page Structure Analysis
|
|
13
|
-
|
|
14
|
-
## 1. Header Section
|
|
15
|
-
- Logo: [position, size, type (text/image)]
|
|
16
|
-
- Navigation: [number of items, layout (horizontal/vertical)]
|
|
17
|
-
- CTA Button: [text, position, style]
|
|
18
|
-
- Mobile menu: [hamburger icon visible?]
|
|
19
|
-
|
|
20
|
-
## 2. Hero Section
|
|
21
|
-
- Layout: [centered/left-aligned/split]
|
|
22
|
-
- Headline: [estimated font size, weight, color]
|
|
23
|
-
- Subheadline: [if present, describe]
|
|
24
|
-
- Primary CTA: [button text, style]
|
|
25
|
-
- Secondary CTA: [if present]
|
|
26
|
-
- Background: [solid color/gradient/image]
|
|
27
|
-
- Visual elements: [images, illustrations, icons]
|
|
28
|
-
|
|
29
|
-
## 3. Content Sections
|
|
30
|
-
For each distinct section, describe:
|
|
31
|
-
- Section name/purpose: [features, testimonials, pricing, etc.]
|
|
32
|
-
- Layout pattern: [grid columns, cards, alternating left-right]
|
|
33
|
-
- Number of items: [e.g., 3 feature cards, 4 testimonials]
|
|
34
|
-
- Key components: [icons, images, headings, descriptions]
|
|
35
|
-
|
|
36
|
-
## 4. Footer Section
|
|
37
|
-
- Layout: [columns, stacked]
|
|
38
|
-
- Content blocks: [logo, links, social, newsletter]
|
|
39
|
-
- Copyright: [position, content]
|
|
40
|
-
|
|
41
|
-
## 5. Global Patterns
|
|
42
|
-
- Container max-width: [estimated px]
|
|
43
|
-
- Section padding: [estimated vertical spacing]
|
|
44
|
-
- Card/component style: [shadows, borders, rounded corners]
|
|
45
|
-
- Color scheme: [light/dark mode, accent colors]
|
|
46
|
-
- Typography style: [modern/classic, serif/sans-serif]
|
|
47
|
-
|
|
48
|
-
## 6. Responsive Hints
|
|
49
|
-
- Mobile-friendly indicators
|
|
50
|
-
- Collapsible elements
|
|
51
|
-
- Stack vs grid on small screens
|
|
52
|
-
|
|
53
|
-
## 7. BEM Class Suggestions
|
|
54
|
-
Suggest semantic BEM class names for main components:
|
|
55
|
-
- header, header__logo, header__nav, header__cta
|
|
56
|
-
- hero, hero__title, hero__subtitle, hero__cta
|
|
57
|
-
- section--features, feature-card, feature-card__icon
|
|
58
|
-
- footer, footer__links, footer__social
|
|
59
|
-
|
|
60
|
-
Be specific and detailed. This analysis will be used to generate HTML/CSS."""
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
# Enhanced prompt when HTML/CSS context is available
|
|
64
|
-
STRUCTURE_PROMPT_WITH_CONTEXT = """Analyze this website using the screenshot AND the provided source HTML/CSS.
|
|
65
|
-
|
|
66
|
-
You have access to:
|
|
67
|
-
1. A screenshot showing the visual design
|
|
68
|
-
2. The actual HTML structure of the page
|
|
69
|
-
3. The CSS rules used on the page
|
|
70
|
-
|
|
71
|
-
IMPORTANT: Use the actual HTML/CSS to provide ACCURATE information, not estimates.
|
|
72
|
-
|
|
73
|
-
## Source HTML Structure
|
|
74
|
-
```html
|
|
75
|
-
{html_snippet}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## Source CSS (key rules)
|
|
79
|
-
```css
|
|
80
|
-
{css_snippet}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
Based on the above context, output a markdown document:
|
|
86
|
-
|
|
87
|
-
# Page Structure Analysis
|
|
88
|
-
|
|
89
|
-
## 1. Header Section
|
|
90
|
-
- Logo: [exact class/id from HTML, position from CSS]
|
|
91
|
-
- Navigation: [exact nav structure from HTML]
|
|
92
|
-
- CTA Button: [exact button text and classes]
|
|
93
|
-
- Mobile menu: [presence and class name if exists]
|
|
94
|
-
|
|
95
|
-
## 2. Hero Section
|
|
96
|
-
- Layout: [from CSS flexbox/grid rules]
|
|
97
|
-
- Headline: [exact text and classes from HTML]
|
|
98
|
-
- Subheadline: [exact text if present]
|
|
99
|
-
- Primary CTA: [exact button text and styles]
|
|
100
|
-
- Background: [from CSS background rules]
|
|
101
|
-
- Visual elements: [images/icons from HTML]
|
|
102
|
-
|
|
103
|
-
## 3. Content Sections
|
|
104
|
-
For each section found in HTML, describe:
|
|
105
|
-
- Section class/id: [exact from HTML]
|
|
106
|
-
- Layout: [from CSS grid/flex rules]
|
|
107
|
-
- Items: [exact count from HTML]
|
|
108
|
-
- Components: [exact structure]
|
|
109
|
-
|
|
110
|
-
## 4. Footer Section
|
|
111
|
-
- Layout: [from CSS]
|
|
112
|
-
- Content blocks: [exact from HTML]
|
|
113
|
-
- Links: [exact href patterns]
|
|
114
|
-
|
|
115
|
-
## 5. Actual CSS Values (from source)
|
|
116
|
-
- Container max-width: [exact from CSS]
|
|
117
|
-
- Section padding: [exact from CSS]
|
|
118
|
-
- Border-radius values: [exact from CSS]
|
|
119
|
-
- Primary color: [exact hex from CSS]
|
|
120
|
-
- Font-family: [exact from CSS]
|
|
121
|
-
- Font-sizes: [exact from CSS]
|
|
122
|
-
|
|
123
|
-
## 6. Responsive Breakpoints (from CSS @media queries)
|
|
124
|
-
- Breakpoint values: [exact from CSS]
|
|
125
|
-
- Layout changes: [what changes at each breakpoint]
|
|
126
|
-
|
|
127
|
-
## 7. Recommended BEM Classes
|
|
128
|
-
Based on the actual HTML structure, suggest clean BEM names that map to existing classes.
|
|
129
|
-
|
|
130
|
-
CRITICAL: Extract EXACT values from the CSS where possible. Do not estimate."""
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
# Enhanced prompt when extracted dimensions are available (highest accuracy)
|
|
134
|
-
STRUCTURE_PROMPT_WITH_DIMENSIONS = """Analyze this website screenshot using the EXACT extracted dimensions below.
|
|
135
|
-
|
|
136
|
-
## CRITICAL INSTRUCTIONS
|
|
137
|
-
1. USE ONLY the exact values provided - DO NOT estimate or approximate
|
|
138
|
-
2. All measurements below are extracted from the actual DOM via getBoundingClientRect + getComputedStyle
|
|
139
|
-
3. When describing layout, reference these exact numbers
|
|
140
|
-
4. Section 5 MUST repeat these exact values verbatim
|
|
141
|
-
|
|
142
|
-
## EXACT EXTRACTED DIMENSIONS
|
|
143
|
-
|
|
144
|
-
### Layout
|
|
145
|
-
- Container max-width: {container_max_width}
|
|
146
|
-
- Section padding: {section_padding}
|
|
147
|
-
- Gap between elements: {gap}
|
|
148
|
-
|
|
149
|
-
### Cards
|
|
150
|
-
- Card width: {card_width}
|
|
151
|
-
- Card height: {card_height}
|
|
152
|
-
- Card padding: {card_padding}
|
|
153
|
-
|
|
154
|
-
### Typography (EXACT from source)
|
|
155
|
-
- H1 font-size: {h1}
|
|
156
|
-
- H2 font-size: {h2}
|
|
157
|
-
- H3 font-size: {h3}
|
|
158
|
-
- Body font-size: {body}
|
|
159
|
-
|
|
160
|
-
### Responsive Breakpoints
|
|
161
|
-
- Desktop: {desktop_breakpoint}
|
|
162
|
-
- Tablet: {tablet_breakpoint}
|
|
163
|
-
- Mobile: {mobile_breakpoint}
|
|
164
|
-
|
|
165
|
-
### Typography Scaling
|
|
166
|
-
- H1: {h1} → {h1_tablet} (tablet) → {h1_mobile} (mobile)
|
|
167
|
-
- H2: {h2} → {h2_tablet} (tablet) → {h2_mobile} (mobile)
|
|
168
|
-
|
|
169
|
-
---
|
|
170
|
-
|
|
171
|
-
Now output a markdown document following this structure.
|
|
172
|
-
IMPORTANT: In section 5, you MUST repeat the exact values above - do not change them.
|
|
173
|
-
|
|
174
|
-
# Page Structure Analysis
|
|
175
|
-
|
|
176
|
-
## 1. Header Section
|
|
177
|
-
- Logo: [describe position and layout]
|
|
178
|
-
- Navigation: [describe navigation structure]
|
|
179
|
-
- CTA Button: [if present]
|
|
180
|
-
- Mobile menu: [hamburger toggle if visible]
|
|
181
|
-
|
|
182
|
-
## 2. Hero Section
|
|
183
|
-
- Layout: [describe arrangement]
|
|
184
|
-
- Headline: font-size {h1} (EXACT), [describe style]
|
|
185
|
-
- Subheadline: [if present]
|
|
186
|
-
- Primary CTA: [button description]
|
|
187
|
-
- Background: [describe]
|
|
188
|
-
|
|
189
|
-
## 3. Content Sections
|
|
190
|
-
For each section describe:
|
|
191
|
-
- Section name/purpose
|
|
192
|
-
- Layout pattern using the EXACT gap value: {gap}
|
|
193
|
-
- Card dimensions: {card_width} x {card_height} (EXACT)
|
|
194
|
-
- Components within
|
|
195
|
-
|
|
196
|
-
## 4. Footer Section
|
|
197
|
-
- Layout: [describe]
|
|
198
|
-
- Content blocks
|
|
199
|
-
|
|
200
|
-
## 5. EXACT CSS Values (use these for generation - DO NOT MODIFY)
|
|
201
|
-
- Container max-width: {container_max_width}
|
|
202
|
-
- Section padding: {section_padding}
|
|
203
|
-
- Card dimensions: {card_width} x {card_height}
|
|
204
|
-
- Card padding: {card_padding}
|
|
205
|
-
- Gap: {gap}
|
|
206
|
-
- H1: {h1}
|
|
207
|
-
- H2: {h2}
|
|
208
|
-
- H3: {h3}
|
|
209
|
-
- Body: {body}
|
|
210
|
-
- Desktop breakpoint: {desktop_breakpoint}
|
|
211
|
-
- Tablet breakpoint: {tablet_breakpoint}
|
|
212
|
-
- Mobile breakpoint: {mobile_breakpoint}
|
|
213
|
-
|
|
214
|
-
## 6. Responsive Behavior
|
|
215
|
-
- At {tablet_breakpoint}: [describe layout changes]
|
|
216
|
-
- At {mobile_breakpoint}: [describe layout changes]
|
|
217
|
-
- Typography scales: H1 {h1} → {h1_tablet} → {h1_mobile}
|
|
218
|
-
|
|
219
|
-
## 7. BEM Class Suggestions
|
|
220
|
-
[Suggest semantic class names for main components]"""
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
# Enhanced prompt when DOM hierarchy is available (highest accuracy)
|
|
224
|
-
STRUCTURE_PROMPT_WITH_HIERARCHY = """Analyze this website screenshot using the EXACT extracted dimensions and DOM hierarchy below.
|
|
225
|
-
|
|
226
|
-
## CRITICAL INSTRUCTIONS
|
|
227
|
-
1. USE ONLY the exact values provided - DO NOT estimate
|
|
228
|
-
2. All measurements are from actual DOM via getBoundingClientRect + getComputedStyle
|
|
229
|
-
3. Typography varies BY SECTION - use section-specific values
|
|
230
|
-
4. Reference DOM hierarchy for nesting structure
|
|
231
|
-
|
|
232
|
-
## EXTRACTED DOM HIERARCHY
|
|
233
|
-
|
|
234
|
-
### Landmarks Found
|
|
235
|
-
- Header: {header_found}
|
|
236
|
-
- Main content: {main_found}
|
|
237
|
-
- Footer: {footer_found}
|
|
238
|
-
- Sidebars: {sidebar_count}
|
|
239
|
-
- Nav elements: {nav_count}
|
|
240
|
-
|
|
241
|
-
### Heading Hierarchy (by section)
|
|
242
|
-
{heading_hierarchy}
|
|
243
|
-
|
|
244
|
-
### Section Structure
|
|
245
|
-
{section_structure}
|
|
246
|
-
|
|
247
|
-
## EXACT DIMENSIONS
|
|
248
|
-
|
|
249
|
-
### Container Layout
|
|
250
|
-
- Max container width: {container_max_width}
|
|
251
|
-
- Section padding: {section_padding}
|
|
252
|
-
- Element gap: {gap}
|
|
253
|
-
|
|
254
|
-
### Cards
|
|
255
|
-
- Card width: {card_width}
|
|
256
|
-
- Card height: {card_height}
|
|
257
|
-
- Card padding: {card_padding}
|
|
258
|
-
|
|
259
|
-
### Typography BY SECTION (use these exact values per context)
|
|
260
|
-
|
|
261
|
-
#### Hero Section
|
|
262
|
-
- H1: {hero_h1}
|
|
263
|
-
- H2: {hero_h2}
|
|
264
|
-
- Body: {hero_body}
|
|
265
|
-
|
|
266
|
-
#### Content Section
|
|
267
|
-
- H2: {content_h2}
|
|
268
|
-
- H3: {content_h3}
|
|
269
|
-
- Body: {content_body}
|
|
270
|
-
|
|
271
|
-
#### Footer Section
|
|
272
|
-
- Body: {footer_body}
|
|
273
|
-
|
|
274
|
-
### Responsive Breakpoints
|
|
275
|
-
- Desktop: {desktop_breakpoint}
|
|
276
|
-
- Tablet: {tablet_breakpoint}
|
|
277
|
-
- Mobile: {mobile_breakpoint}
|
|
278
|
-
|
|
279
|
-
### Typography Scaling
|
|
280
|
-
- H1: {hero_h1} → {h1_tablet} (tablet) → {h1_mobile} (mobile)
|
|
281
|
-
- H2: {content_h2} → {h2_tablet} (tablet) → {h2_mobile} (mobile)
|
|
282
|
-
|
|
283
|
-
---
|
|
284
|
-
|
|
285
|
-
Output a markdown document following this structure.
|
|
286
|
-
IMPORTANT: Use section-specific typography values. Hero H1 differs from Content H1.
|
|
287
|
-
|
|
288
|
-
# Page Structure Analysis
|
|
289
|
-
|
|
290
|
-
## 1. Header Section
|
|
291
|
-
- Logo: [describe position and layout]
|
|
292
|
-
- Navigation: [count items from hierarchy]
|
|
293
|
-
- CTA: [if present]
|
|
294
|
-
|
|
295
|
-
## 2. Hero Section
|
|
296
|
-
- Layout: [from section structure]
|
|
297
|
-
- Headline: font-size {hero_h1} (EXACT)
|
|
298
|
-
- Subheadline: [if present]
|
|
299
|
-
- CTA: [button description]
|
|
300
|
-
|
|
301
|
-
## 3. Content Sections
|
|
302
|
-
For each section in the hierarchy:
|
|
303
|
-
- Heading sizes: Use CONTENT section typography ({content_h2}, {content_h3})
|
|
304
|
-
- Layout: Reference section structure
|
|
305
|
-
- Card dimensions: {card_width} x {card_height} with gap {gap}
|
|
306
|
-
- Components: [describe]
|
|
307
|
-
|
|
308
|
-
## 4. Footer Section
|
|
309
|
-
- Layout: [from hierarchy]
|
|
310
|
-
- Typography: {footer_body} body text
|
|
311
|
-
|
|
312
|
-
## 5. EXACT CSS Values (DO NOT MODIFY)
|
|
313
|
-
### Layout
|
|
314
|
-
- Container max-width: {container_max_width}
|
|
315
|
-
- Section padding: {section_padding}
|
|
316
|
-
- Card dimensions: {card_width} x {card_height}
|
|
317
|
-
- Card padding: {card_padding}
|
|
318
|
-
- Gap: {gap}
|
|
319
|
-
|
|
320
|
-
### Typography per Section
|
|
321
|
-
- Hero H1: {hero_h1}
|
|
322
|
-
- Hero H2: {hero_h2}
|
|
323
|
-
- Content H2: {content_h2}
|
|
324
|
-
- Content H3: {content_h3}
|
|
325
|
-
- Content Body: {content_body}
|
|
326
|
-
- Footer Body: {footer_body}
|
|
327
|
-
|
|
328
|
-
### Breakpoints
|
|
329
|
-
- Desktop: {desktop_breakpoint}
|
|
330
|
-
- Tablet: {tablet_breakpoint}
|
|
331
|
-
- Mobile: {mobile_breakpoint}
|
|
332
|
-
|
|
333
|
-
## 6. Responsive Behavior
|
|
334
|
-
- At {tablet_breakpoint}: [describe layout changes]
|
|
335
|
-
- At {mobile_breakpoint}: [describe layout changes]
|
|
336
|
-
- Typography scales: H1 {hero_h1} → {h1_tablet} → {h1_mobile}
|
|
337
|
-
|
|
338
|
-
## 7. DOM Nesting Structure
|
|
339
|
-
Reproduce this exact nesting in generated HTML:
|
|
340
|
-
{dom_nesting}
|
|
341
|
-
|
|
342
|
-
## 8. BEM Class Suggestions
|
|
343
|
-
[Based on hierarchy, suggest semantic names]"""
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
def format_heading_hierarchy(heading_tree: list) -> str:
|
|
347
|
-
"""Format heading tree for prompt.
|
|
348
|
-
|
|
349
|
-
Args:
|
|
350
|
-
heading_tree: List of heading objects with level, section, text
|
|
351
|
-
|
|
352
|
-
Returns:
|
|
353
|
-
Formatted string showing heading hierarchy
|
|
354
|
-
"""
|
|
355
|
-
if not heading_tree:
|
|
356
|
-
return "No headings detected"
|
|
357
|
-
|
|
358
|
-
lines = []
|
|
359
|
-
for h in heading_tree[:10]: # Limit for token efficiency
|
|
360
|
-
indent = ' ' * (h.get('level', 1) - 1)
|
|
361
|
-
section = h.get('section', 'content')
|
|
362
|
-
text = h.get('text', '')[:30] if h.get('text') else ''
|
|
363
|
-
lines.append(f"{indent}- H{h.get('level', 1)} ({section}): \"{text}...\"")
|
|
364
|
-
|
|
365
|
-
return '\n'.join(lines)
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
def format_section_structure(landmarks: dict, sections: dict) -> str:
|
|
369
|
-
"""Format section structure for prompt.
|
|
370
|
-
|
|
371
|
-
Args:
|
|
372
|
-
landmarks: W3C landmarks from DOM hierarchy
|
|
373
|
-
sections: Section info from dimensions
|
|
374
|
-
|
|
375
|
-
Returns:
|
|
376
|
-
Formatted string showing section structure
|
|
377
|
-
"""
|
|
378
|
-
lines = []
|
|
379
|
-
|
|
380
|
-
if landmarks.get('header'):
|
|
381
|
-
lines.append("- Header: Present (semantic <header>)")
|
|
382
|
-
if sections.get('hero', {}).get('found'):
|
|
383
|
-
width = sections['hero'].get('containerWidth', 'unknown')
|
|
384
|
-
lines.append(f"- Hero: Present (container width: {width}px)")
|
|
385
|
-
if landmarks.get('main'):
|
|
386
|
-
lines.append("- Main: Present (semantic <main>)")
|
|
387
|
-
if sections.get('content', {}).get('found'):
|
|
388
|
-
width = sections['content'].get('containerWidth', 'unknown')
|
|
389
|
-
lines.append(f"- Content: Present (container width: {width}px)")
|
|
390
|
-
if landmarks.get('aside'):
|
|
391
|
-
lines.append(f"- Sidebars: {len(landmarks['aside'])} detected")
|
|
392
|
-
if landmarks.get('footer'):
|
|
393
|
-
lines.append("- Footer: Present (semantic <footer>)")
|
|
394
|
-
|
|
395
|
-
return '\n'.join(lines) if lines else "No sections detected"
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
def format_dom_nesting(root: dict, max_depth: int = 4) -> str:
|
|
399
|
-
"""Format simplified DOM nesting for prompt.
|
|
400
|
-
|
|
401
|
-
Args:
|
|
402
|
-
root: Root node from DOM hierarchy
|
|
403
|
-
max_depth: Maximum depth to traverse
|
|
404
|
-
|
|
405
|
-
Returns:
|
|
406
|
-
Formatted string showing DOM nesting structure
|
|
407
|
-
"""
|
|
408
|
-
if not root:
|
|
409
|
-
return "No DOM structure available"
|
|
410
|
-
|
|
411
|
-
lines = []
|
|
412
|
-
|
|
413
|
-
def walk(node, depth):
|
|
414
|
-
if depth > max_depth or not node:
|
|
415
|
-
return
|
|
416
|
-
if not node.get('role'):
|
|
417
|
-
# Skip non-semantic nodes in output
|
|
418
|
-
for child in node.get('children', [])[:5]:
|
|
419
|
-
walk(child, depth)
|
|
420
|
-
return
|
|
421
|
-
|
|
422
|
-
indent = ' ' * depth
|
|
423
|
-
tag = node.get('tagName', 'div')
|
|
424
|
-
role = node.get('role', '')
|
|
425
|
-
lines.append(f"{indent}<{tag}> <!-- {role} -->")
|
|
426
|
-
|
|
427
|
-
for child in node.get('children', [])[:5]: # Limit children
|
|
428
|
-
walk(child, depth + 1)
|
|
429
|
-
|
|
430
|
-
walk(root, 0)
|
|
431
|
-
return '\n'.join(lines[:30]) # Limit total lines
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
def build_hierarchy_prompt(dimensions: dict, hierarchy: dict) -> str:
|
|
435
|
-
"""Build prompt with DOM hierarchy context.
|
|
436
|
-
|
|
437
|
-
Args:
|
|
438
|
-
dimensions: Extracted dimensions summary
|
|
439
|
-
hierarchy: DOM hierarchy data
|
|
440
|
-
|
|
441
|
-
Returns:
|
|
442
|
-
Formatted prompt string with hierarchy context
|
|
443
|
-
"""
|
|
444
|
-
exact = dimensions.get('EXACT_DIMENSIONS', {})
|
|
445
|
-
typo = dimensions.get('EXACT_TYPOGRAPHY', {})
|
|
446
|
-
typo_by_section = dimensions.get('TYPOGRAPHY_BY_SECTION', {})
|
|
447
|
-
resp = dimensions.get('RESPONSIVE', {})
|
|
448
|
-
sections = dimensions.get('SECTIONS', {})
|
|
449
|
-
card = exact.get('card_dimensions', {})
|
|
450
|
-
scaling = resp.get('typography_scaling', {})
|
|
451
|
-
|
|
452
|
-
# Extract hierarchy data
|
|
453
|
-
landmarks = hierarchy.get('landmarks', {})
|
|
454
|
-
heading_tree = hierarchy.get('headingTree', [])
|
|
455
|
-
|
|
456
|
-
# Format heading hierarchy
|
|
457
|
-
heading_hierarchy = format_heading_hierarchy(heading_tree)
|
|
458
|
-
|
|
459
|
-
# Format section structure
|
|
460
|
-
section_structure = format_section_structure(landmarks, sections)
|
|
461
|
-
|
|
462
|
-
# Format DOM nesting (simplified)
|
|
463
|
-
dom_nesting = format_dom_nesting(hierarchy.get('root'))
|
|
464
|
-
|
|
465
|
-
# Get section-specific typography
|
|
466
|
-
hero_typo = typo_by_section.get('hero', {})
|
|
467
|
-
content_typo = typo_by_section.get('content', {})
|
|
468
|
-
footer_typo = typo_by_section.get('footer', {})
|
|
469
|
-
|
|
470
|
-
return STRUCTURE_PROMPT_WITH_HIERARCHY.format(
|
|
471
|
-
# Landmarks
|
|
472
|
-
header_found='Yes' if landmarks.get('header') else 'No',
|
|
473
|
-
main_found='Yes' if landmarks.get('main') else 'No',
|
|
474
|
-
footer_found='Yes' if landmarks.get('footer') else 'No',
|
|
475
|
-
sidebar_count=len(landmarks.get('aside', [])),
|
|
476
|
-
nav_count=len(landmarks.get('nav', [])),
|
|
477
|
-
|
|
478
|
-
# Heading hierarchy
|
|
479
|
-
heading_hierarchy=heading_hierarchy,
|
|
480
|
-
section_structure=section_structure,
|
|
481
|
-
|
|
482
|
-
# Dimensions
|
|
483
|
-
container_max_width=exact.get('container_max_width', '1200px'),
|
|
484
|
-
section_padding=exact.get('section_padding', '64px 0'),
|
|
485
|
-
gap=exact.get('gap', '24px'),
|
|
486
|
-
card_width=card.get('width', '380px') if isinstance(card, dict) else '380px',
|
|
487
|
-
card_height=card.get('height', 'auto') if isinstance(card, dict) else 'auto',
|
|
488
|
-
card_padding=card.get('padding', '24px') if isinstance(card, dict) else '24px',
|
|
489
|
-
|
|
490
|
-
# Typography by section
|
|
491
|
-
hero_h1=hero_typo.get('h1', typo.get('h1', '64px')),
|
|
492
|
-
hero_h2=hero_typo.get('h2', typo.get('h2', '48px')),
|
|
493
|
-
hero_body=hero_typo.get('p', typo.get('body', '18px')),
|
|
494
|
-
content_h2=content_typo.get('h2', typo.get('h2', '32px')),
|
|
495
|
-
content_h3=content_typo.get('h3', typo.get('h3', '24px')),
|
|
496
|
-
content_body=content_typo.get('p', typo.get('body', '16px')),
|
|
497
|
-
footer_body=footer_typo.get('p', '14px'),
|
|
498
|
-
|
|
499
|
-
# Breakpoints
|
|
500
|
-
desktop_breakpoint=resp.get('desktop_breakpoint', '1440px'),
|
|
501
|
-
tablet_breakpoint=resp.get('tablet_breakpoint', '768px'),
|
|
502
|
-
mobile_breakpoint=resp.get('mobile_breakpoint', '375px'),
|
|
503
|
-
|
|
504
|
-
# Typography scaling
|
|
505
|
-
h1_tablet=scaling.get('h1', {}).get('tablet', '36px') if isinstance(scaling.get('h1'), dict) else '36px',
|
|
506
|
-
h1_mobile=scaling.get('h1', {}).get('mobile', '28px') if isinstance(scaling.get('h1'), dict) else '28px',
|
|
507
|
-
h2_tablet=scaling.get('h2', {}).get('tablet', '28px') if isinstance(scaling.get('h2'), dict) else '28px',
|
|
508
|
-
h2_mobile=scaling.get('h2', {}).get('mobile', '24px') if isinstance(scaling.get('h2'), dict) else '24px',
|
|
509
|
-
|
|
510
|
-
# DOM nesting
|
|
511
|
-
dom_nesting=dom_nesting
|
|
512
|
-
)
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
def build_structure_prompt(
|
|
516
|
-
html_content: str = None,
|
|
517
|
-
css_content: str = None,
|
|
518
|
-
dimensions: dict = None,
|
|
519
|
-
content_summary: str = None,
|
|
520
|
-
hierarchy: dict = None
|
|
521
|
-
) -> str:
|
|
522
|
-
"""Build the appropriate prompt based on available context.
|
|
523
|
-
|
|
524
|
-
Priority:
|
|
525
|
-
1. With hierarchy + dimensions (most accurate - full DOM context)
|
|
526
|
-
2. With dimensions (accurate - uses exact extracted values)
|
|
527
|
-
3. With HTML/CSS (accurate - extracts from source)
|
|
528
|
-
4. Screenshot only (least accurate - estimates)
|
|
529
|
-
|
|
530
|
-
Args:
|
|
531
|
-
html_content: Source HTML (optional)
|
|
532
|
-
css_content: Source CSS (optional)
|
|
533
|
-
dimensions: Extracted dimensions summary (optional)
|
|
534
|
-
content_summary: Content counts markdown (optional)
|
|
535
|
-
hierarchy: DOM hierarchy data (optional)
|
|
536
|
-
|
|
537
|
-
Returns:
|
|
538
|
-
Appropriate prompt string based on available context
|
|
539
|
-
"""
|
|
540
|
-
|
|
541
|
-
# Helper to append content summary
|
|
542
|
-
def append_content_counts(prompt: str) -> str:
|
|
543
|
-
if content_summary:
|
|
544
|
-
return prompt + "\n\n---\n\n" + content_summary + "\n\nIMPORTANT: Use the EXACT item counts above when describing sections. Do NOT estimate."
|
|
545
|
-
return prompt
|
|
546
|
-
|
|
547
|
-
# Priority 1: Use hierarchy + dimensions if available (highest accuracy)
|
|
548
|
-
if hierarchy and dimensions:
|
|
549
|
-
return append_content_counts(build_hierarchy_prompt(dimensions, hierarchy))
|
|
550
|
-
|
|
551
|
-
# Priority 2: Use dimensions if available
|
|
552
|
-
if dimensions:
|
|
553
|
-
exact = dimensions.get('EXACT_DIMENSIONS', {})
|
|
554
|
-
typo = dimensions.get('EXACT_TYPOGRAPHY', {})
|
|
555
|
-
resp = dimensions.get('RESPONSIVE', {})
|
|
556
|
-
card = exact.get('card_dimensions', {})
|
|
557
|
-
scaling = resp.get('typography_scaling', {})
|
|
558
|
-
|
|
559
|
-
return append_content_counts(STRUCTURE_PROMPT_WITH_DIMENSIONS.format(
|
|
560
|
-
container_max_width=exact.get('container_max_width', '1200px'),
|
|
561
|
-
section_padding=exact.get('section_padding', '64px 0'),
|
|
562
|
-
gap=exact.get('gap', '24px'),
|
|
563
|
-
card_width=card.get('width', '380px') if isinstance(card, dict) else '380px',
|
|
564
|
-
card_height=card.get('height', 'auto') if isinstance(card, dict) else 'auto',
|
|
565
|
-
card_padding=card.get('padding', '24px') if isinstance(card, dict) else '24px',
|
|
566
|
-
h1=typo.get('h1', '48px'),
|
|
567
|
-
h2=typo.get('h2', '36px'),
|
|
568
|
-
h3=typo.get('h3', '28px'),
|
|
569
|
-
body=typo.get('body', '16px'),
|
|
570
|
-
desktop_breakpoint=resp.get('desktop_breakpoint', '1440px'),
|
|
571
|
-
tablet_breakpoint=resp.get('tablet_breakpoint', '768px'),
|
|
572
|
-
mobile_breakpoint=resp.get('mobile_breakpoint', '375px'),
|
|
573
|
-
h1_tablet=scaling.get('h1', {}).get('tablet', '36px') if isinstance(scaling.get('h1'), dict) else '36px',
|
|
574
|
-
h1_mobile=scaling.get('h1', {}).get('mobile', '28px') if isinstance(scaling.get('h1'), dict) else '28px',
|
|
575
|
-
h2_tablet=scaling.get('h2', {}).get('tablet', '28px') if isinstance(scaling.get('h2'), dict) else '28px',
|
|
576
|
-
h2_mobile=scaling.get('h2', {}).get('mobile', '24px') if isinstance(scaling.get('h2'), dict) else '24px'
|
|
577
|
-
))
|
|
578
|
-
|
|
579
|
-
# Priority 2: Use HTML/CSS if available
|
|
580
|
-
if html_content and css_content:
|
|
581
|
-
# Truncate for token limits - Gemini 2.5 Flash supports 1M tokens (~4MB)
|
|
582
|
-
# Using 100KB each to capture full page structure while staying well within limits
|
|
583
|
-
html_snippet = html_content[:100000] if len(html_content) > 100000 else html_content
|
|
584
|
-
css_snippet = css_content[:100000] if len(css_content) > 100000 else css_content
|
|
585
|
-
|
|
586
|
-
return append_content_counts(STRUCTURE_PROMPT_WITH_CONTEXT.format(
|
|
587
|
-
html_snippet=html_snippet,
|
|
588
|
-
css_snippet=css_snippet
|
|
589
|
-
))
|
|
590
|
-
|
|
591
|
-
# Priority 3: Screenshot only (fallback)
|
|
592
|
-
return append_content_counts(STRUCTURE_PROMPT)
|