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.
Files changed (177) hide show
  1. package/README.md +13 -34
  2. package/SKILL.md +69 -45
  3. package/bin/cli.js +22 -4
  4. package/bin/commands/clone-site.js +31 -171
  5. package/bin/commands/help.js +19 -6
  6. package/bin/commands/init.js +9 -86
  7. package/bin/commands/uninstall.js +105 -0
  8. package/bin/commands/update.js +70 -0
  9. package/bin/commands/verify.js +7 -14
  10. package/bin/utils/paths.js +28 -0
  11. package/bin/utils/validate.js +2 -22
  12. package/bin/utils/version.js +23 -0
  13. package/docs/code-standards.md +789 -0
  14. package/docs/codebase-summary.md +533 -286
  15. package/docs/index.md +74 -0
  16. package/docs/project-overview-pdr.md +797 -0
  17. package/docs/system-architecture.md +718 -0
  18. package/package.json +14 -17
  19. package/src/ai/prompts/design-tokens/basic.md +80 -0
  20. package/src/ai/prompts/design-tokens/section-with-css.md +41 -0
  21. package/src/ai/prompts/design-tokens/section.md +48 -0
  22. package/src/ai/prompts/design-tokens/with-css.md +87 -0
  23. package/src/ai/prompts/structure-analysis/basic.md +55 -0
  24. package/src/ai/prompts/structure-analysis/with-context.md +59 -0
  25. package/src/ai/prompts/structure-analysis/with-dimensions.md +63 -0
  26. package/src/ai/prompts/structure-analysis/with-hierarchy.md +73 -0
  27. package/src/ai/prompts/ux-audit/aggregation.md +42 -0
  28. package/src/ai/prompts/ux-audit/desktop.md +92 -0
  29. package/src/ai/prompts/ux-audit/mobile.md +93 -0
  30. package/src/ai/prompts/ux-audit/tablet.md +92 -0
  31. package/src/core/animation/animation-extractor-ast.js +183 -0
  32. package/src/core/animation/animation-extractor-output.js +152 -0
  33. package/src/core/animation/animation-extractor.js +178 -0
  34. package/src/core/animation/state-capture-detection.js +200 -0
  35. package/src/core/animation/state-capture.js +193 -0
  36. package/src/core/capture/browser-context-pool.js +96 -0
  37. package/src/core/capture/multi-page-screenshot-page.js +110 -0
  38. package/src/core/capture/multi-page-screenshot.js +208 -0
  39. package/src/core/capture/screenshot-extraction.js +186 -0
  40. package/src/core/capture/screenshot-helpers.js +175 -0
  41. package/src/core/capture/screenshot-orchestrator.js +174 -0
  42. package/src/core/capture/screenshot-viewport.js +93 -0
  43. package/src/core/capture/screenshot.js +192 -0
  44. package/src/core/content/content-counter-dom.js +191 -0
  45. package/src/core/content/content-counter.js +76 -0
  46. package/src/core/css/breakpoint-detector.js +66 -0
  47. package/src/core/css/chromium-defaults.json +23 -0
  48. package/src/core/css/computed-style-extractor.js +102 -0
  49. package/src/core/css/css-chunker.js +103 -0
  50. package/src/core/css/filter-css-dead-code.js +120 -0
  51. package/src/core/css/filter-css-html-analyzer.js +110 -0
  52. package/src/core/css/filter-css-selector-matcher.js +172 -0
  53. package/src/core/css/filter-css.js +206 -0
  54. package/src/core/css/merge-css-atrule-processor.js +158 -0
  55. package/src/core/css/merge-css-file-io.js +68 -0
  56. package/src/core/css/merge-css.js +148 -0
  57. package/src/core/detection/framework-detector-routing.js +68 -0
  58. package/src/core/detection/framework-detector-signals.js +65 -0
  59. package/src/core/detection/framework-detector.js +198 -0
  60. package/src/core/dimension/dimension-extractor-card-detector.js +82 -0
  61. package/src/core/dimension/dimension-extractor.js +317 -0
  62. package/src/core/dimension/dimension-output-ai-summary.js +111 -0
  63. package/src/core/dimension/dimension-output.js +173 -0
  64. package/src/core/dimension/dom-tree-analyzer-tree-builders.js +95 -0
  65. package/src/core/dimension/dom-tree-analyzer.js +191 -0
  66. package/src/core/discovery/app-state-snapshot-capture.js +195 -0
  67. package/src/core/discovery/app-state-snapshot-utils.js +178 -0
  68. package/src/core/discovery/app-state-snapshot.js +131 -0
  69. package/src/core/discovery/discover-pages-routes.js +84 -0
  70. package/src/core/discovery/discover-pages-utils.js +177 -0
  71. package/src/core/discovery/discover-pages.js +191 -0
  72. package/src/core/html/html-extractor-inline-styler.js +70 -0
  73. package/src/core/html/html-extractor.js +147 -0
  74. package/src/core/html/semantic-enhancer-mappings.js +200 -0
  75. package/src/core/html/semantic-enhancer-page.js +148 -0
  76. package/src/core/html/semantic-enhancer.js +135 -0
  77. package/src/core/links/rewrite-links-css-rewriter.js +53 -0
  78. package/src/core/links/rewrite-links.js +173 -0
  79. package/src/core/media/asset-validator.js +118 -0
  80. package/src/core/media/extract-assets-downloader.js +187 -0
  81. package/src/core/media/extract-assets-page-scraper.js +115 -0
  82. package/src/core/media/extract-assets.js +159 -0
  83. package/src/core/media/video-capture-convert.js +200 -0
  84. package/src/core/media/video-capture.js +201 -0
  85. package/src/core/{lazy-loader.js → page-prep/lazy-loader.js} +37 -39
  86. package/src/core/section/section-cropper-helpers.js +43 -0
  87. package/src/core/{section-cropper.js → section/section-cropper.js} +11 -88
  88. package/src/core/section/section-detector-strategies.js +139 -0
  89. package/src/core/section/section-detector-utils.js +100 -0
  90. package/src/core/section/section-detector.js +88 -0
  91. package/src/core/tests/test-section-cropper.js +2 -2
  92. package/src/core/tests/test-section-detector.js +2 -2
  93. package/src/post-process/enhance-assets.js +29 -4
  94. package/src/post-process/fetch-images-unsplash-client.js +123 -0
  95. package/src/post-process/fetch-images.js +60 -263
  96. package/src/post-process/inject-gosnap.js +88 -0
  97. package/src/post-process/inject-icons-svg-replacer.js +76 -0
  98. package/src/post-process/inject-icons.js +47 -200
  99. package/src/route-discoverers/base-discoverer-utils.js +137 -0
  100. package/src/route-discoverers/base-discoverer.js +29 -118
  101. package/src/route-discoverers/index.js +1 -1
  102. package/src/shared/config.js +38 -0
  103. package/src/shared/error-codes.js +31 -0
  104. package/src/shared/viewports.js +46 -0
  105. package/src/utils/browser.js +0 -7
  106. package/src/utils/helpers.js +4 -0
  107. package/src/utils/log.js +12 -0
  108. package/src/utils/playwright-loader.js +76 -0
  109. package/src/utils/playwright.js +3 -69
  110. package/src/utils/progress.js +32 -0
  111. package/src/verification/generate-audit-report-css-fixes.js +52 -0
  112. package/src/verification/generate-audit-report-sections.js +158 -0
  113. package/src/verification/generate-audit-report.js +5 -281
  114. package/src/verification/quality-scorer.js +92 -0
  115. package/src/verification/verify-footer-checks.js +103 -0
  116. package/src/verification/verify-footer-helpers.js +178 -0
  117. package/src/verification/verify-footer.js +23 -381
  118. package/src/verification/verify-header-checks.js +104 -0
  119. package/src/verification/verify-header-helpers.js +156 -0
  120. package/src/verification/verify-header.js +23 -365
  121. package/src/verification/verify-layout-report.js +101 -0
  122. package/src/verification/verify-layout.js +13 -259
  123. package/src/verification/verify-menu-checks.js +104 -0
  124. package/src/verification/verify-menu-helpers.js +112 -0
  125. package/src/verification/verify-menu.js +17 -285
  126. package/src/verification/verify-slider-checks.js +115 -0
  127. package/src/verification/verify-slider-constants.js +65 -0
  128. package/src/verification/verify-slider-helpers.js +164 -0
  129. package/src/verification/verify-slider.js +23 -414
  130. package/.env.example +0 -14
  131. package/docs/basic-clone.md +0 -63
  132. package/docs/cli-reference.md +0 -316
  133. package/docs/design-clone-architecture.md +0 -492
  134. package/docs/pixel-perfect.md +0 -117
  135. package/docs/project-roadmap.md +0 -382
  136. package/docs/troubleshooting.md +0 -170
  137. package/requirements.txt +0 -5
  138. package/src/ai/__pycache__/analyze-structure.cpython-313.pyc +0 -0
  139. package/src/ai/__pycache__/extract-design-tokens.cpython-313.pyc +0 -0
  140. package/src/ai/analyze-structure.py +0 -375
  141. package/src/ai/extract-design-tokens.py +0 -782
  142. package/src/ai/prompts/__init__.py +0 -2
  143. package/src/ai/prompts/__pycache__/__init__.cpython-313.pyc +0 -0
  144. package/src/ai/prompts/__pycache__/design_tokens.cpython-313.pyc +0 -0
  145. package/src/ai/prompts/__pycache__/structure_analysis.cpython-313.pyc +0 -0
  146. package/src/ai/prompts/__pycache__/ux_audit.cpython-313.pyc +0 -0
  147. package/src/ai/prompts/design_tokens.py +0 -316
  148. package/src/ai/prompts/structure_analysis.py +0 -592
  149. package/src/ai/prompts/ux_audit.py +0 -198
  150. package/src/ai/ux-audit.js +0 -596
  151. package/src/core/animation-extractor.js +0 -526
  152. package/src/core/app-state-snapshot.js +0 -511
  153. package/src/core/content-counter.js +0 -342
  154. package/src/core/design-tokens.js +0 -103
  155. package/src/core/dimension-extractor.js +0 -438
  156. package/src/core/dimension-output.js +0 -305
  157. package/src/core/discover-pages.js +0 -542
  158. package/src/core/dom-tree-analyzer.js +0 -298
  159. package/src/core/extract-assets.js +0 -468
  160. package/src/core/filter-css.js +0 -499
  161. package/src/core/framework-detector.js +0 -538
  162. package/src/core/html-extractor.js +0 -212
  163. package/src/core/merge-css.js +0 -407
  164. package/src/core/multi-page-screenshot.js +0 -380
  165. package/src/core/rewrite-links.js +0 -226
  166. package/src/core/screenshot.js +0 -701
  167. package/src/core/section-detector.js +0 -386
  168. package/src/core/semantic-enhancer.js +0 -492
  169. package/src/core/state-capture.js +0 -598
  170. package/src/core/video-capture.js +0 -546
  171. package/src/utils/__init__.py +0 -16
  172. package/src/utils/__pycache__/__init__.cpython-313.pyc +0 -0
  173. package/src/utils/__pycache__/env.cpython-313.pyc +0 -0
  174. package/src/utils/env.py +0 -134
  175. /package/src/core/{css-extractor.js → css/css-extractor.js} +0 -0
  176. /package/src/core/{cookie-handler.js → page-prep/cookie-handler.js} +0 -0
  177. /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)