prism-design 2.13.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/CHANGELOG.md +292 -0
- package/LICENSE +21 -0
- package/README.md +203 -0
- package/bin/clone-architect.mjs +476 -0
- package/bin/prism.mjs +467 -0
- package/catalog/index.json +1155 -0
- package/extractions/airbnb.com/DESIGN.md +1068 -0
- package/extractions/airbnb.com/tokens.json +507 -0
- package/extractions/attio.com/DESIGN.md +1295 -0
- package/extractions/attio.com/tokens.json +438 -0
- package/extractions/auroxdashboard.com/DESIGN.md +724 -0
- package/extractions/auroxdashboard.com/tokens.json +195 -0
- package/extractions/careerexplorer.com/DESIGN.md +1178 -0
- package/extractions/careerexplorer.com/tokens.json +141 -0
- package/extractions/chance.co/DESIGN.md +1209 -0
- package/extractions/chance.co/tokens.json +160 -0
- package/extractions/choisis-ton-avenir.com/DESIGN.md +1265 -0
- package/extractions/choisis-ton-avenir.com/tokens.json +227 -0
- package/extractions/example.com/DESIGN.md +436 -0
- package/extractions/example.com/tokens.json +91 -0
- package/extractions/getdesign.md/DESIGN.md +1009 -0
- package/extractions/getdesign.md/tokens.json +219 -0
- package/extractions/github.com/DESIGN.md +1130 -0
- package/extractions/github.com/tokens.json +2092 -0
- package/extractions/hello-charly.com/DESIGN.md +1146 -0
- package/extractions/hello-charly.com/tokens.json +322 -0
- package/extractions/hyperliquid.xyz/DESIGN.md +779 -0
- package/extractions/hyperliquid.xyz/tokens.json +598 -0
- package/extractions/instagram.com/DESIGN.md +996 -0
- package/extractions/instagram.com/tokens.json +1240 -0
- package/extractions/jobirl.com/DESIGN.md +1160 -0
- package/extractions/jobirl.com/tokens.json +139 -0
- package/extractions/life360.com/DESIGN.md +1133 -0
- package/extractions/life360.com/tokens.json +491 -0
- package/extractions/lifesum.com/DESIGN.md +965 -0
- package/extractions/lifesum.com/tokens.json +170 -0
- package/extractions/linear.app/DESIGN.md +1301 -0
- package/extractions/linear.app/tokens.json +732 -0
- package/extractions/mavoie.org/DESIGN.md +1148 -0
- package/extractions/mavoie.org/tokens.json +128 -0
- package/extractions/miro.com/DESIGN.md +1237 -0
- package/extractions/miro.com/tokens.json +401 -0
- package/extractions/notion.so/DESIGN.md +1319 -0
- package/extractions/notion.so/tokens.json +906 -0
- package/extractions/onetonline.org/DESIGN.md +909 -0
- package/extractions/onetonline.org/tokens.json +280 -0
- package/extractions/posthog.com/DESIGN.md +1024 -0
- package/extractions/posthog.com/tokens.json +197 -0
- package/extractions/revolut.com/DESIGN.md +1080 -0
- package/extractions/revolut.com/tokens.json +401 -0
- package/extractions/stripe.com/DESIGN.md +1272 -0
- package/extractions/stripe.com/tokens.json +794 -0
- package/extractions/switchcollective.com/DESIGN.md +1040 -0
- package/extractions/switchcollective.com/tokens.json +98 -0
- package/extractions/truity.com/DESIGN.md +970 -0
- package/extractions/truity.com/tokens.json +166 -0
- package/extractions/uniquekicks.be/DESIGN.md +1171 -0
- package/extractions/uniquekicks.be/tokens.json +237 -0
- package/package.json +122 -0
- package/scripts/analyze.ts +281 -0
- package/scripts/bank-register.ts +379 -0
- package/scripts/bank.ts +374 -0
- package/scripts/browser-stealth.ts +189 -0
- package/scripts/clone.ts +198 -0
- package/scripts/compare-vs-gd-final.ts +273 -0
- package/scripts/compare-vs-gd.ts +269 -0
- package/scripts/compare.ts +405 -0
- package/scripts/deploy-site.ts +181 -0
- package/scripts/diff-snapshots.ts +340 -0
- package/scripts/enrich-catalog.ts +212 -0
- package/scripts/extract.ts +2038 -0
- package/scripts/extractors/advanced.ts +524 -0
- package/scripts/extractors/widgets.ts +711 -0
- package/scripts/generate-design-md.ts +5775 -0
- package/scripts/generate-final-pdf.ts +274 -0
- package/scripts/generate-og-image.ts +87 -0
- package/scripts/generate-showcase.ts +1588 -0
- package/scripts/generate-site.ts +847 -0
- package/scripts/mass-extract.sh +91 -0
- package/scripts/post-process-all.sh +55 -0
- package/scripts/regen-catalog.ts +203 -0
- package/scripts/shared/cache.ts +149 -0
- package/scripts/shared/css-helpers.ts +263 -0
- package/scripts/shared/logger.ts +57 -0
- package/scripts/shared/named-colors.ts +355 -0
- package/scripts/shared/types.ts +220 -0
- package/scripts/sync-catalog.ts +105 -0
- package/scripts/tokenize.ts +988 -0
- package/templates/layout-template.md +52 -0
- package/templates/tokens-template.json +34 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"source": "https://uniquekicks.be",
|
|
4
|
+
"domain": "uniquekicks.be",
|
|
5
|
+
"extractedAt": "2026-05-31T04:14:13.647Z",
|
|
6
|
+
"tokenizedAt": "2026-05-31T04:14:34.479Z"
|
|
7
|
+
},
|
|
8
|
+
"colors": {
|
|
9
|
+
"background": {
|
|
10
|
+
"primary": "rgb(240, 240, 240)",
|
|
11
|
+
"secondary": "rgb(255, 255, 255)",
|
|
12
|
+
"tertiary": "rgba(255, 255, 255, 0.12)"
|
|
13
|
+
},
|
|
14
|
+
"text": {
|
|
15
|
+
"primary": "rgb(26, 26, 26)",
|
|
16
|
+
"secondary": "rgba(26, 26, 26, 0.65)",
|
|
17
|
+
"muted": "rgb(26, 26, 26)"
|
|
18
|
+
},
|
|
19
|
+
"accent": {
|
|
20
|
+
"primary": "rgb(0, 111, 207)",
|
|
21
|
+
"secondary": "rgb(30, 55, 100)"
|
|
22
|
+
},
|
|
23
|
+
"border": "rgb(228, 222, 222)",
|
|
24
|
+
"shadow": "rgba(0,0,0,0.1)"
|
|
25
|
+
},
|
|
26
|
+
"typography": {
|
|
27
|
+
"fontFamily": {
|
|
28
|
+
"primary": "Barlow",
|
|
29
|
+
"secondary": "GTStandard-M",
|
|
30
|
+
"mono": "monospace"
|
|
31
|
+
},
|
|
32
|
+
"fontSize": {
|
|
33
|
+
"xs": "9px",
|
|
34
|
+
"sm": "14px",
|
|
35
|
+
"base": "16px",
|
|
36
|
+
"lg": "20px",
|
|
37
|
+
"xl": "24px",
|
|
38
|
+
"2xl": "30px",
|
|
39
|
+
"3xl": "36px",
|
|
40
|
+
"4xl": "48px"
|
|
41
|
+
},
|
|
42
|
+
"fontWeight": {
|
|
43
|
+
"normal": "400",
|
|
44
|
+
"medium": "500",
|
|
45
|
+
"semibold": "700",
|
|
46
|
+
"bold": "700"
|
|
47
|
+
},
|
|
48
|
+
"lineHeight": {
|
|
49
|
+
"tight": "1.6",
|
|
50
|
+
"normal": "1.6",
|
|
51
|
+
"relaxed": "1.6"
|
|
52
|
+
},
|
|
53
|
+
"letterSpacing": {
|
|
54
|
+
"tight": "-0.020em",
|
|
55
|
+
"normal": "0em",
|
|
56
|
+
"wide": "-0.060em"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"spacing": {
|
|
60
|
+
"xxs": "2px",
|
|
61
|
+
"xs": "4px",
|
|
62
|
+
"sm": "8px",
|
|
63
|
+
"md": "12px",
|
|
64
|
+
"base": "16px",
|
|
65
|
+
"lg": "24px",
|
|
66
|
+
"xl": "32px",
|
|
67
|
+
"2xl": "48px",
|
|
68
|
+
"3xl": "64px"
|
|
69
|
+
},
|
|
70
|
+
"borderRadius": {
|
|
71
|
+
"none": "0px",
|
|
72
|
+
"xs": "4px",
|
|
73
|
+
"sm": "8px",
|
|
74
|
+
"md": "12px",
|
|
75
|
+
"lg": "12px",
|
|
76
|
+
"xl": "12px",
|
|
77
|
+
"full": "9999px"
|
|
78
|
+
},
|
|
79
|
+
"shadows": {
|
|
80
|
+
"shadow-1": "rgba(63, 63, 68, 0.4) 0px 4px 10px 0px",
|
|
81
|
+
"shadow-2": "rgba(0, 0, 0, 0.4) 0px 9999px 0px 9999px",
|
|
82
|
+
"shadow-3": "rgba(26, 26, 26, 0.1) 0px 5px 15px 0px, rgba(26, 26, 26, 0.12) 0px 0px 0px 1px",
|
|
83
|
+
"shadow-4": "rgba(26, 26, 26, 0.12) 0px 0px 0px 1px",
|
|
84
|
+
"shadow-5": "rgba(0, 0, 0, 0.15) 0px 0px 30px 0px"
|
|
85
|
+
},
|
|
86
|
+
"transitions": {
|
|
87
|
+
"transition-1": "all",
|
|
88
|
+
"transition-2": "background 0.25s",
|
|
89
|
+
"transition-3": "opacity 0.2s ease-in-out",
|
|
90
|
+
"transition-4": "transform 0.2s ease-in-out",
|
|
91
|
+
"transition-5": "background-size 0.3s ease-in-out"
|
|
92
|
+
},
|
|
93
|
+
"layout": {
|
|
94
|
+
"maxWidth": "1600px",
|
|
95
|
+
"headerHeight": "94px",
|
|
96
|
+
"sidebarWidth": "1440px",
|
|
97
|
+
"gap": "normal",
|
|
98
|
+
"containerPadding": "0px"
|
|
99
|
+
},
|
|
100
|
+
"cssCustomProperties": {
|
|
101
|
+
"--on-sale-text": "248 58 58",
|
|
102
|
+
"--sticky-header-enabled": "1",
|
|
103
|
+
"--heading-font-weight": "700",
|
|
104
|
+
"--header-height": "94px",
|
|
105
|
+
"--spacing-4": "1rem",
|
|
106
|
+
"--text-font-family": "Barlow, sans-serif",
|
|
107
|
+
"--spacing-1": "0.25rem",
|
|
108
|
+
"--spacing-9": "2.25rem",
|
|
109
|
+
"--sold-out-badge-background": "0 0 0",
|
|
110
|
+
"--spacing-36": "9rem",
|
|
111
|
+
"--shadow-block": "0px 18px 50px rgb(26 26 26 / 0.1)",
|
|
112
|
+
"--product-card-background": "255 255 255",
|
|
113
|
+
"--spacing-64": "16rem",
|
|
114
|
+
"--accent": "26 26 26",
|
|
115
|
+
"--cursor-close-svg-url": "url(//www.uniquekicks.be/cdn/shop/t/19/assets/cursor-close.svg?v=147174565022153725511740963773)",
|
|
116
|
+
"--shadow-md": "0 5px 30px rgb(26 26 26 / 0.1)",
|
|
117
|
+
"--text-h2": "3rem",
|
|
118
|
+
"--spacing-48": "12rem",
|
|
119
|
+
"--text-lg": "1.25rem",
|
|
120
|
+
"--background-primary": "240 240 240",
|
|
121
|
+
"--product-list-row-gap": "3rem",
|
|
122
|
+
"--spacing-52": "13rem",
|
|
123
|
+
"--rounded-sm": "0.375rem",
|
|
124
|
+
"--footer-text": "26 26 26",
|
|
125
|
+
"--spacing-4-5": "1.125rem",
|
|
126
|
+
"--text-h6": "1.25rem",
|
|
127
|
+
"--spacing-56": "14rem",
|
|
128
|
+
"--dialog-background": "255 255 255",
|
|
129
|
+
"--spacing-6": "1.5rem",
|
|
130
|
+
"--heading-font-family": "Barlow, sans-serif",
|
|
131
|
+
"--section-inner-max-spacing-block": "4.5rem",
|
|
132
|
+
"--button-text-secondary": "26 26 26",
|
|
133
|
+
"--success-text": "0 163 65",
|
|
134
|
+
"--cursor-zoom-out-svg-url": "url(//www.uniquekicks.be/cdn/shop/t/19/assets/cursor-zoom-out.svg?v=16155520337305705181740963761)",
|
|
135
|
+
"--spacing-1-5": "0.375rem",
|
|
136
|
+
"--spacing-14": "3.5rem",
|
|
137
|
+
"--rounded-xs": "0.25rem",
|
|
138
|
+
"--sticky-announcement-bar-enabled": "0",
|
|
139
|
+
"--spacing-12": "3rem",
|
|
140
|
+
"--product-list-column-gap": "1.5rem",
|
|
141
|
+
"--star-color": "255 183 74",
|
|
142
|
+
"--warning-text": "255 183 74",
|
|
143
|
+
"--text-font-weight": "500",
|
|
144
|
+
"--on-sale-badge-background": "248 58 58",
|
|
145
|
+
"--success-background": "224 244 232",
|
|
146
|
+
"--transform-logical-flip": "1",
|
|
147
|
+
"--input-height": "3.125rem",
|
|
148
|
+
"--spacing-80": "20rem",
|
|
149
|
+
"--spacing-72": "18rem",
|
|
150
|
+
"--text-h4": "2rem",
|
|
151
|
+
"--sold-out-badge-text": "255 255 255",
|
|
152
|
+
"--transform-origin-end": "right",
|
|
153
|
+
"--spacing-32": "8rem",
|
|
154
|
+
"--checkmark-svg-url": "url(//www.uniquekicks.be/cdn/shop/t/19/assets/checkmark.svg?v=77552481021870063511740963761)",
|
|
155
|
+
"--button-background-primary": "26 26 26",
|
|
156
|
+
"--text-letter-spacing": "0.0em",
|
|
157
|
+
"--border-color": "26 26 26 / 0.12",
|
|
158
|
+
"--shadow": "0 5px 15px rgb(26 26 26 / 0.1)",
|
|
159
|
+
"--kl-reviews-color-light-gray": "#e9e9eb",
|
|
160
|
+
"--transform-origin-start": "left",
|
|
161
|
+
"--button-background-secondary": "240 196 23",
|
|
162
|
+
"--error-text": "248 58 58",
|
|
163
|
+
"--spacing-8": "2rem",
|
|
164
|
+
"--heading-letter-spacing": "-0.02em",
|
|
165
|
+
"--text-sm": "0.875rem",
|
|
166
|
+
"--announcement-bar-height": "48px",
|
|
167
|
+
"--section-inner-spacing-inline": "4.5rem",
|
|
168
|
+
"--spacing-20": "5rem",
|
|
169
|
+
"--rounded": "0.75rem",
|
|
170
|
+
"--spacing-2": "0.5rem",
|
|
171
|
+
"--rounded-input": "0.5rem",
|
|
172
|
+
"--section-outer-spacing-block": "6rem",
|
|
173
|
+
"--primary-badge-text": "255 255 255",
|
|
174
|
+
"--spacing-7-5": "1.875rem",
|
|
175
|
+
"--spacing-44": "11rem",
|
|
176
|
+
"--rounded-lg": "1.5rem",
|
|
177
|
+
"--text-h5": "1.5rem",
|
|
178
|
+
"--input-gap": "1rem",
|
|
179
|
+
"--primary-badge-background": "128 60 238",
|
|
180
|
+
"--heading-text-transform": "normal",
|
|
181
|
+
"--container-narrow-max-width": "1350px",
|
|
182
|
+
"--section-stack-spacing-block": "3rem",
|
|
183
|
+
"--error-background": "254 231 231",
|
|
184
|
+
"--shadow-sm": "0 2px 8px rgb(26 26 26 / 0.1)",
|
|
185
|
+
"--spacing-3": "0.75rem",
|
|
186
|
+
"--spacing-96": "24rem",
|
|
187
|
+
"--warning-background": "255 246 233",
|
|
188
|
+
"--text-primary": "26 26 26",
|
|
189
|
+
"--rounded-button": "0.25rem",
|
|
190
|
+
"--spacing-11": "2.75rem",
|
|
191
|
+
"--spacing-6-5": "1.625rem",
|
|
192
|
+
"--spacing-28": "7rem",
|
|
193
|
+
"--cursor-zoom-in-svg-url": "url(//www.uniquekicks.be/cdn/shop/t/19/assets/cursor-zoom-in.svg?v=154953035094101115921740963763)",
|
|
194
|
+
"--text-font-style": "normal",
|
|
195
|
+
"--rounded-full": "9999px",
|
|
196
|
+
"--container-max-width": "1600px",
|
|
197
|
+
"--text-xs": "0.75rem",
|
|
198
|
+
"--on-sale-badge-text": "255 255 255",
|
|
199
|
+
"--spacing-5": "1.25rem",
|
|
200
|
+
"--spacing-8-5": "2.125rem",
|
|
201
|
+
"--spacing-5-5": "1.375rem",
|
|
202
|
+
"--spacing-24": "6rem",
|
|
203
|
+
"--spacing-3-5": "0.875rem",
|
|
204
|
+
"--text-h1": "3.75rem",
|
|
205
|
+
"--spacing-7": "1.75rem",
|
|
206
|
+
"--header-text": "26 26 26",
|
|
207
|
+
"--spacing-40": "10rem",
|
|
208
|
+
"--spacing-10": "2.5rem",
|
|
209
|
+
"--button-text-primary": "255 255 255",
|
|
210
|
+
"--sticky-area-height": "calc(0 * 48px + 1 * 94px)",
|
|
211
|
+
"--spacing-16": "4rem",
|
|
212
|
+
"--spacing-0-5": "0.125rem",
|
|
213
|
+
"--heading-font-style": "normal",
|
|
214
|
+
"--header-background": "240 240 240",
|
|
215
|
+
"--container-gutter": "3rem",
|
|
216
|
+
"--spacing-18": "4.5rem",
|
|
217
|
+
"--text-h0": "5rem",
|
|
218
|
+
"--text-h3": "2.25rem",
|
|
219
|
+
"--input-padding-inline": "1.25rem",
|
|
220
|
+
"--footer-background": "255 255 255",
|
|
221
|
+
"--product-card-text": "26 26 26",
|
|
222
|
+
"--spacing-2-5": "0.625rem",
|
|
223
|
+
"--text-base": "1.0rem",
|
|
224
|
+
"--spacing-60": "15rem",
|
|
225
|
+
"--grid-gutter": "1.5rem",
|
|
226
|
+
"--spacing-9-5": "2.375rem",
|
|
227
|
+
"--background": "240 240 240",
|
|
228
|
+
"--text-color": "26 26 26",
|
|
229
|
+
"--header-logo-width": "125px",
|
|
230
|
+
"--header-padding-block": "2.125rem",
|
|
231
|
+
"--header-transparent-text-color": "255 255 255",
|
|
232
|
+
"--header-background-blur-radius": "0px",
|
|
233
|
+
"--header-grid-template": "\"logo main-nav secondary-nav\" / minmax(0, 1fr) fit-content(55%) minmax(0, 1fr)",
|
|
234
|
+
"--header-background-opacity": "1.0",
|
|
235
|
+
"--header-logo-height": "21px"
|
|
236
|
+
}
|
|
237
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "prism-design",
|
|
3
|
+
"version": "2.13.0",
|
|
4
|
+
"description": "Refract any website into its real design system — computed CSS, screenshots, narrative DESIGN.md — in 90 seconds. The verifiable alternative to manually-written design docs.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"prism": "bin/prism.mjs",
|
|
8
|
+
"clone-architect": "bin/prism.mjs"
|
|
9
|
+
},
|
|
10
|
+
"main": "./bin/clone-architect.mjs",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/paulsainton/prism.git"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/paulsainton/prism/issues"
|
|
17
|
+
},
|
|
18
|
+
"author": "Paul Sainton",
|
|
19
|
+
"files": [
|
|
20
|
+
"bin/",
|
|
21
|
+
"catalog/",
|
|
22
|
+
"extractions/*/DESIGN.md",
|
|
23
|
+
"extractions/*/tokens.json",
|
|
24
|
+
"scripts/clone.ts",
|
|
25
|
+
"scripts/extract.ts",
|
|
26
|
+
"scripts/analyze.ts",
|
|
27
|
+
"scripts/tokenize.ts",
|
|
28
|
+
"scripts/generate-design-md.ts",
|
|
29
|
+
"scripts/generate-showcase.ts",
|
|
30
|
+
"scripts/compare.ts",
|
|
31
|
+
"scripts/bank.ts",
|
|
32
|
+
"scripts/bank-register.ts",
|
|
33
|
+
"scripts/enrich-catalog.ts",
|
|
34
|
+
"scripts/regen-catalog.ts",
|
|
35
|
+
"scripts/generate-site.ts",
|
|
36
|
+
"scripts/deploy-site.ts",
|
|
37
|
+
"scripts/generate-og-image.ts",
|
|
38
|
+
"scripts/diff-snapshots.ts",
|
|
39
|
+
"scripts/compare-vs-gd.ts",
|
|
40
|
+
"scripts/compare-vs-gd-final.ts",
|
|
41
|
+
"scripts/generate-final-pdf.ts",
|
|
42
|
+
"scripts/sync-catalog.ts",
|
|
43
|
+
"scripts/mass-extract.sh",
|
|
44
|
+
"scripts/post-process-all.sh",
|
|
45
|
+
"scripts/verify-checklist.ts",
|
|
46
|
+
"scripts/browser-stealth.ts",
|
|
47
|
+
"scripts/extractors/",
|
|
48
|
+
"scripts/shared/",
|
|
49
|
+
"templates/",
|
|
50
|
+
"README.md",
|
|
51
|
+
"LICENSE",
|
|
52
|
+
"CHANGELOG.md"
|
|
53
|
+
],
|
|
54
|
+
"keywords": [
|
|
55
|
+
"design-system",
|
|
56
|
+
"design-tokens",
|
|
57
|
+
"design-md",
|
|
58
|
+
"css-extraction",
|
|
59
|
+
"computed-styles",
|
|
60
|
+
"playwright",
|
|
61
|
+
"design-extraction",
|
|
62
|
+
"clone-website",
|
|
63
|
+
"ai-coding",
|
|
64
|
+
"claude-code",
|
|
65
|
+
"cursor",
|
|
66
|
+
"design-dna",
|
|
67
|
+
"visual-design",
|
|
68
|
+
"frontend-tools",
|
|
69
|
+
"design-audit"
|
|
70
|
+
],
|
|
71
|
+
"homepage": "https://prism.ps-tools.dev", "license": "MIT",
|
|
72
|
+
"engines": {
|
|
73
|
+
"node": ">=18.0.0"
|
|
74
|
+
},
|
|
75
|
+
"scripts": {
|
|
76
|
+
"extract": "tsx scripts/extract.ts",
|
|
77
|
+
"analyze": "tsx scripts/analyze.ts",
|
|
78
|
+
"tokenize": "tsx scripts/tokenize.ts",
|
|
79
|
+
"compare": "tsx scripts/compare.ts",
|
|
80
|
+
"generate-design": "tsx scripts/generate-design-md.ts",
|
|
81
|
+
"showcase": "tsx scripts/generate-showcase.ts",
|
|
82
|
+
"clone": "tsx scripts/clone.ts",
|
|
83
|
+
"worktree-build": "tsx scripts/worktree-build.ts",
|
|
84
|
+
"section-build": "tsx scripts/section-builder.ts",
|
|
85
|
+
"extract-block": "tsx scripts/extract-block.ts",
|
|
86
|
+
"bank:inject": "tsx scripts/bank-inject.ts",
|
|
87
|
+
"test": "tsx tests/run-all.ts",
|
|
88
|
+
"bank": "tsx scripts/bank.ts",
|
|
89
|
+
"bank:register": "tsx scripts/bank.ts register --all",
|
|
90
|
+
"bank:stats": "tsx scripts/bank.ts stats",
|
|
91
|
+
"bank:query": "tsx scripts/bank.ts query",
|
|
92
|
+
"enrich-catalog": "tsx scripts/enrich-catalog.ts",
|
|
93
|
+
"regen-catalog": "tsx scripts/regen-catalog.ts",
|
|
94
|
+
"generate-site": "tsx scripts/generate-site.ts",
|
|
95
|
+
"deploy": "tsx scripts/deploy-site.ts",
|
|
96
|
+
"compare-vs-gd": "tsx scripts/compare-vs-gd.ts",
|
|
97
|
+
"compare-vs-gd-final": "tsx scripts/compare-vs-gd-final.ts",
|
|
98
|
+
"final-pdf": "tsx scripts/generate-final-pdf.ts",
|
|
99
|
+
"sync-catalog": "tsx scripts/sync-catalog.ts",
|
|
100
|
+
"mass-extract": "bash scripts/mass-extract.sh",
|
|
101
|
+
"post-process": "bash scripts/post-process-all.sh",
|
|
102
|
+
"verify-checklist": "tsx scripts/verify-checklist.ts",
|
|
103
|
+
"diff": "tsx scripts/diff-snapshots.ts",
|
|
104
|
+
"snapshot": "tsx scripts/diff-snapshots.ts --create",
|
|
105
|
+
"prepublishOnly": "tsc --noEmit && CI=true tsx tests/run-all.ts"
|
|
106
|
+
},
|
|
107
|
+
"dependencies": {
|
|
108
|
+
"@anthropic-ai/sdk": "^0.100.1",
|
|
109
|
+
"pixelmatch": "^6.0.0",
|
|
110
|
+
"playwright": "^1.52.0",
|
|
111
|
+
"playwright-extra": "^4.3.6",
|
|
112
|
+
"pngjs": "^7.0.0",
|
|
113
|
+
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
114
|
+
"tsx": "^4.19.0"
|
|
115
|
+
},
|
|
116
|
+
"devDependencies": {
|
|
117
|
+
"@types/node": "^22.0.0",
|
|
118
|
+
"@types/pngjs": "^6.0.5",
|
|
119
|
+
"typescript": "^5.7.0"
|
|
120
|
+
},
|
|
121
|
+
"postinstall": "echo '\\n🧬 Prism installed.\\n\\n Path A — Browse catalog (no setup required):\\n prism list\\n prism add linear.app\\n\\n Path B — Extract any URL (requires Playwright):\\n npx playwright install chromium\\n prism extract https://yoursite.com\\n'"
|
|
122
|
+
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prism — Layout Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Prend le raw-css.json d'une extraction et produit layout-analysis.md :
|
|
5
|
+
* - Type de layout (sidebar+main, top-nav, full-width, split)
|
|
6
|
+
* - Dimensions clés (sidebar width, header height, card sizes, gaps)
|
|
7
|
+
* - Navigation (type, items, active state)
|
|
8
|
+
* - Grille (columns, pattern, aspect-ratio)
|
|
9
|
+
* - Composants identifiés
|
|
10
|
+
* - Animations/transitions
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
14
|
+
import { join } from 'path';
|
|
15
|
+
import { parseRgb, luminanceSimple } from './shared/css-helpers.js';
|
|
16
|
+
|
|
17
|
+
interface ExtractionResult {
|
|
18
|
+
url: string;
|
|
19
|
+
domain: string;
|
|
20
|
+
viewport: { width: number; height: number };
|
|
21
|
+
pageTitle: string;
|
|
22
|
+
cssCustomProperties: Record<string, string>;
|
|
23
|
+
elements: Record<string, { tag: string; classes: string[]; text: string; styles: Record<string, string>; children: number; rect: { x: number; y: number; width: number; height: number } } | null>;
|
|
24
|
+
sections: Array<{ index: number; tag: string; classes: string[]; role: string; estimatedPurpose: string; rect: { x: number; y: number; width: number; height: number }; styles: Record<string, string>; childCount: number }>;
|
|
25
|
+
allColors: string[];
|
|
26
|
+
allFontFamilies: string[];
|
|
27
|
+
allFontSizes: string[];
|
|
28
|
+
allBorderRadii: string[];
|
|
29
|
+
allShadows: string[];
|
|
30
|
+
allTransitions: string[];
|
|
31
|
+
images: { src: string; alt: string; width: number; height: number }[];
|
|
32
|
+
links: { href: string; text: string; isNav: boolean }[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function detectLayoutType(data: ExtractionResult): string {
|
|
36
|
+
const sidebar = data.elements.sidebar;
|
|
37
|
+
const header = data.elements.header;
|
|
38
|
+
const nav = data.elements.nav;
|
|
39
|
+
const main = data.elements.main;
|
|
40
|
+
|
|
41
|
+
if (sidebar && sidebar.rect.height > 200) {
|
|
42
|
+
return 'sidebar + main content';
|
|
43
|
+
}
|
|
44
|
+
if (header && nav) {
|
|
45
|
+
if (main) return 'top-nav + main content';
|
|
46
|
+
return 'top-nav + full-width sections';
|
|
47
|
+
}
|
|
48
|
+
if (!header && !nav && !sidebar) {
|
|
49
|
+
return 'full-width (single column)';
|
|
50
|
+
}
|
|
51
|
+
return 'top-nav + content';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function parsePixels(val: string): number {
|
|
55
|
+
const match = val?.match(/^([\d.]+)px$/);
|
|
56
|
+
return match ? parseFloat(match[1]) : 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function formatColor(color: string): string {
|
|
60
|
+
return color.replace(/\s+/g, '');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function groupColors(colors: string[]): { backgrounds: string[]; text: string[]; accents: string[] } {
|
|
64
|
+
const backgrounds: string[] = [];
|
|
65
|
+
const text: string[] = [];
|
|
66
|
+
const accents: string[] = [];
|
|
67
|
+
|
|
68
|
+
for (const c of colors) {
|
|
69
|
+
const rgb = parseRgb(c);
|
|
70
|
+
if (!rgb) continue;
|
|
71
|
+
const lum = luminanceSimple(rgb);
|
|
72
|
+
|
|
73
|
+
if (lum > 0.85) backgrounds.push(c);
|
|
74
|
+
else if (lum < 0.2) text.push(c);
|
|
75
|
+
else accents.push(c);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { backgrounds, text, accents };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function generateAnalysis(data: ExtractionResult): string {
|
|
82
|
+
const layoutType = detectLayoutType(data);
|
|
83
|
+
const colorGroups = groupColors(data.allColors);
|
|
84
|
+
const navLinks = data.links.filter(l => l.isNav);
|
|
85
|
+
|
|
86
|
+
const lines: string[] = [];
|
|
87
|
+
|
|
88
|
+
lines.push(`# Layout Analysis — ${data.domain}`);
|
|
89
|
+
lines.push(`> Extracted from ${data.url} on ${new Date().toISOString().split('T')[0]}`);
|
|
90
|
+
lines.push(`> Viewport: ${data.viewport.width}x${data.viewport.height}`);
|
|
91
|
+
lines.push('');
|
|
92
|
+
|
|
93
|
+
// ── Layout Type ──
|
|
94
|
+
lines.push('## Layout Type');
|
|
95
|
+
lines.push(`**${layoutType}**`);
|
|
96
|
+
lines.push('');
|
|
97
|
+
|
|
98
|
+
// ── Dimensions ──
|
|
99
|
+
lines.push('## Key Dimensions');
|
|
100
|
+
|
|
101
|
+
const dims: string[] = [];
|
|
102
|
+
const { sidebar, header, main, hero } = data.elements;
|
|
103
|
+
if (header) dims.push(`- Header height: ${header.rect.height}px`);
|
|
104
|
+
if (sidebar) dims.push(`- Sidebar width: ${sidebar.rect.width}px`);
|
|
105
|
+
if (main) dims.push(`- Main content width: ${main.rect.width}px (max-width: ${main.styles.maxWidth})`);
|
|
106
|
+
if (hero) dims.push(`- Hero height: ${hero.rect.height}px`);
|
|
107
|
+
|
|
108
|
+
const body = data.elements.body;
|
|
109
|
+
if (body) {
|
|
110
|
+
dims.push(`- Page background: ${formatColor(body.styles.backgroundColor)}`);
|
|
111
|
+
dims.push(`- Base font: ${body.styles.fontFamily.split(',')[0].trim()}`);
|
|
112
|
+
dims.push(`- Base font size: ${body.styles.fontSize}`);
|
|
113
|
+
dims.push(`- Base text color: ${formatColor(body.styles.color)}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
lines.push(dims.length ? dims.join('\n') : '- No key dimensions detected');
|
|
117
|
+
lines.push('');
|
|
118
|
+
|
|
119
|
+
// ── Navigation ──
|
|
120
|
+
lines.push('## Navigation');
|
|
121
|
+
const navEl = data.elements.nav || data.elements.header;
|
|
122
|
+
if (navEl) {
|
|
123
|
+
lines.push(`- Type: ${navEl.tag} (${navEl.styles.display})`);
|
|
124
|
+
lines.push(`- Position: ${navEl.styles.position}`);
|
|
125
|
+
lines.push(`- Background: ${formatColor(navEl.styles.backgroundColor)}`);
|
|
126
|
+
lines.push(`- Height: ${navEl.rect.height}px`);
|
|
127
|
+
if (navLinks.length > 0) {
|
|
128
|
+
lines.push(`- Items (${navLinks.length}):`);
|
|
129
|
+
for (const link of navLinks.slice(0, 15)) {
|
|
130
|
+
lines.push(` - "${link.text}" → ${link.href}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
lines.push('- No navigation element detected');
|
|
135
|
+
}
|
|
136
|
+
lines.push('');
|
|
137
|
+
|
|
138
|
+
// ── Sections ──
|
|
139
|
+
lines.push('## Page Sections');
|
|
140
|
+
for (const section of data.sections.slice(0, 20)) {
|
|
141
|
+
lines.push(`### ${section.estimatedPurpose} (${section.tag}.${section.classes.slice(0, 2).join('.')})`);
|
|
142
|
+
lines.push(`- Position: y=${section.rect.y}px, height=${section.rect.height}px`);
|
|
143
|
+
lines.push(`- Layout: ${section.styles.display} ${section.styles.flexDirection || section.styles.gridTemplateColumns || ''}`);
|
|
144
|
+
lines.push(`- Background: ${formatColor(section.styles.backgroundColor)}`);
|
|
145
|
+
lines.push(`- Padding: ${section.styles.padding}`);
|
|
146
|
+
lines.push(`- Children: ${section.childCount}`);
|
|
147
|
+
lines.push('');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ── Components ──
|
|
151
|
+
lines.push('## Components Detected');
|
|
152
|
+
const componentKeys = ['card', 'button', 'input', 'badge', 'avatar', 'logo', 'dropdown', 'modal'];
|
|
153
|
+
for (const key of componentKeys) {
|
|
154
|
+
const el = data.elements[key];
|
|
155
|
+
if (!el) continue;
|
|
156
|
+
lines.push(`### ${key}`);
|
|
157
|
+
lines.push(`- Tag: ${el.tag}`);
|
|
158
|
+
lines.push(`- Classes: ${el.classes.join(', ') || 'none'}`);
|
|
159
|
+
lines.push(`- Size: ${el.rect.width}x${el.rect.height}px`);
|
|
160
|
+
lines.push(`- Background: ${formatColor(el.styles.backgroundColor)}`);
|
|
161
|
+
lines.push(`- Border: ${el.styles.border}`);
|
|
162
|
+
lines.push(`- Border radius: ${el.styles.borderRadius}`);
|
|
163
|
+
lines.push(`- Shadow: ${el.styles.boxShadow}`);
|
|
164
|
+
lines.push(`- Font: ${el.styles.fontSize} ${el.styles.fontWeight}`);
|
|
165
|
+
lines.push(`- Text: "${el.text.slice(0, 80)}"`);
|
|
166
|
+
lines.push('');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ── Colors ──
|
|
170
|
+
lines.push('## Color Palette');
|
|
171
|
+
lines.push(`Total unique colors: ${data.allColors.length}`);
|
|
172
|
+
lines.push('');
|
|
173
|
+
if (colorGroups.backgrounds.length) {
|
|
174
|
+
lines.push(`### Backgrounds (${colorGroups.backgrounds.length})`);
|
|
175
|
+
for (const c of colorGroups.backgrounds.slice(0, 10)) lines.push(`- ${formatColor(c)}`);
|
|
176
|
+
lines.push('');
|
|
177
|
+
}
|
|
178
|
+
if (colorGroups.text.length) {
|
|
179
|
+
lines.push(`### Text (${colorGroups.text.length})`);
|
|
180
|
+
for (const c of colorGroups.text.slice(0, 10)) lines.push(`- ${formatColor(c)}`);
|
|
181
|
+
lines.push('');
|
|
182
|
+
}
|
|
183
|
+
if (colorGroups.accents.length) {
|
|
184
|
+
lines.push(`### Accents (${colorGroups.accents.length})`);
|
|
185
|
+
for (const c of colorGroups.accents.slice(0, 10)) lines.push(`- ${formatColor(c)}`);
|
|
186
|
+
lines.push('');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// ── Typography ──
|
|
190
|
+
lines.push('## Typography');
|
|
191
|
+
lines.push(`### Font Families (${data.allFontFamilies.length})`);
|
|
192
|
+
for (const f of data.allFontFamilies.slice(0, 10)) {
|
|
193
|
+
lines.push(`- ${f.split(',')[0].trim()}`);
|
|
194
|
+
}
|
|
195
|
+
lines.push('');
|
|
196
|
+
lines.push(`### Font Sizes (${data.allFontSizes.length})`);
|
|
197
|
+
const sortedSizes = [...data.allFontSizes].sort((a, b) => parsePixels(a) - parsePixels(b));
|
|
198
|
+
for (const s of sortedSizes) lines.push(`- ${s}`);
|
|
199
|
+
lines.push('');
|
|
200
|
+
|
|
201
|
+
// ── Border Radii ──
|
|
202
|
+
lines.push('## Border Radii');
|
|
203
|
+
for (const r of data.allBorderRadii.slice(0, 10)) lines.push(`- ${r}`);
|
|
204
|
+
lines.push('');
|
|
205
|
+
|
|
206
|
+
// ── Shadows ──
|
|
207
|
+
lines.push('## Shadows');
|
|
208
|
+
for (const s of data.allShadows.slice(0, 10)) lines.push(`- ${s}`);
|
|
209
|
+
lines.push('');
|
|
210
|
+
|
|
211
|
+
// ── Transitions ──
|
|
212
|
+
lines.push('## Transitions & Animations');
|
|
213
|
+
for (const t of data.allTransitions.slice(0, 10)) lines.push(`- ${t}`);
|
|
214
|
+
lines.push('');
|
|
215
|
+
|
|
216
|
+
// ── CSS Custom Properties ──
|
|
217
|
+
const varsCount = Object.keys(data.cssCustomProperties).length;
|
|
218
|
+
if (varsCount > 0) {
|
|
219
|
+
lines.push(`## CSS Custom Properties (${varsCount})`);
|
|
220
|
+
const entries = Object.entries(data.cssCustomProperties).slice(0, 50);
|
|
221
|
+
for (const [prop, val] of entries) {
|
|
222
|
+
lines.push(`- \`${prop}\`: ${val}`);
|
|
223
|
+
}
|
|
224
|
+
lines.push('');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ── Images ──
|
|
228
|
+
if (data.images.length > 0) {
|
|
229
|
+
lines.push(`## Images (${data.images.length})`);
|
|
230
|
+
for (const img of data.images.slice(0, 15)) {
|
|
231
|
+
lines.push(`- ${img.width}x${img.height} — ${img.alt || 'no alt'} — ${img.src.slice(0, 80)}`);
|
|
232
|
+
}
|
|
233
|
+
lines.push('');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return lines.join('\n');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// ── CLI ──────────────────────────────────────────────────────────────
|
|
240
|
+
|
|
241
|
+
const domain = process.argv[2];
|
|
242
|
+
|
|
243
|
+
if (!domain) {
|
|
244
|
+
console.error('Usage: npm run analyze -- <domain>');
|
|
245
|
+
console.error('Example: npm run analyze -- linear.app');
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const baseDir = join(process.cwd(), 'extractions', domain);
|
|
250
|
+
|
|
251
|
+
async function main() {
|
|
252
|
+
console.log(`\n📊 Analyzing layout for ${domain}...`);
|
|
253
|
+
|
|
254
|
+
const rawPath = join(baseDir, 'raw-css.json');
|
|
255
|
+
const raw = JSON.parse(await readFile(rawPath, 'utf-8'));
|
|
256
|
+
|
|
257
|
+
// Analyze desktop viewport
|
|
258
|
+
const desktopData = raw.desktop as ExtractionResult;
|
|
259
|
+
if (!desktopData) {
|
|
260
|
+
console.error('No desktop data found in raw-css.json');
|
|
261
|
+
process.exit(1);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const analysis = generateAnalysis(desktopData);
|
|
265
|
+
|
|
266
|
+
// Also generate mobile analysis if present
|
|
267
|
+
let mobileAnalysis = '';
|
|
268
|
+
if (raw.mobile) {
|
|
269
|
+
mobileAnalysis = '\n\n---\n\n' + generateAnalysis(raw.mobile as ExtractionResult);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const outputPath = join(baseDir, 'layout-analysis.md');
|
|
273
|
+
await writeFile(outputPath, analysis + mobileAnalysis);
|
|
274
|
+
|
|
275
|
+
console.log(`✅ Layout analysis saved to ${outputPath}`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
main().catch(err => {
|
|
279
|
+
console.error('Error:', err);
|
|
280
|
+
process.exit(1);
|
|
281
|
+
});
|