designlang 7.2.0 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +17 -0
  3. package/bin/design-extract.js +5 -1
  4. package/package.json +1 -1
  5. package/src/config.js +2 -0
  6. package/src/crawler.js +35 -6
  7. package/src/extractors/accessibility.js +44 -1
  8. package/src/extractors/colors.js +50 -12
  9. package/src/extractors/scoring.js +49 -30
  10. package/.github/FUNDING.yml +0 -1
  11. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -62
  12. package/.github/ISSUE_TEMPLATE/config.yml +0 -8
  13. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -28
  14. package/.github/og-preview.png +0 -0
  15. package/.github/workflows/manavarya-bot.yml +0 -17
  16. package/chrome-extension/README.md +0 -41
  17. package/chrome-extension/icons/favicon.svg +0 -7
  18. package/chrome-extension/icons/icon-128.png +0 -0
  19. package/chrome-extension/icons/icon-16.png +0 -0
  20. package/chrome-extension/icons/icon-32.png +0 -0
  21. package/chrome-extension/icons/icon-48.png +0 -0
  22. package/chrome-extension/manifest.json +0 -26
  23. package/chrome-extension/popup.html +0 -167
  24. package/chrome-extension/popup.js +0 -59
  25. package/docs/superpowers/plans/2026-04-18-designlang-v7.md +0 -1121
  26. package/docs/superpowers/specs/2026-04-18-designlang-v7-design.md +0 -150
  27. package/docs/superpowers/specs/2026-04-18-website-redesign-design.md +0 -120
  28. package/docs/superpowers/specs/2026-04-19-designlang-v7-1-design.md +0 -111
  29. package/tests/cli.test.js +0 -84
  30. package/tests/cookies.test.js +0 -98
  31. package/tests/extractors.test.js +0 -792
  32. package/tests/formatters.test.js +0 -709
  33. package/tests/interaction-states.test.js +0 -62
  34. package/tests/mcp.test.js +0 -68
  35. package/tests/modern-css.test.js +0 -104
  36. package/tests/routes-reconciliation.test.js +0 -120
  37. package/tests/utils.test.js +0 -413
  38. package/tests/wide-gamut.test.js +0 -90
  39. package/website/.claude/launch.json +0 -11
  40. package/website/AGENTS.md +0 -5
  41. package/website/CLAUDE.md +0 -1
  42. package/website/README.md +0 -36
  43. package/website/app/api/extract/route.js +0 -245
  44. package/website/app/components/A11ySlider.js +0 -369
  45. package/website/app/components/Comparison.js +0 -286
  46. package/website/app/components/CssHealth.js +0 -243
  47. package/website/app/components/Extractor.js +0 -184
  48. package/website/app/components/HeroExtractor.js +0 -455
  49. package/website/app/components/Marginalia.js +0 -3
  50. package/website/app/components/McpSection.js +0 -223
  51. package/website/app/components/PlatformTabs.js +0 -250
  52. package/website/app/components/RegionsComponents.js +0 -429
  53. package/website/app/components/Rule.js +0 -13
  54. package/website/app/components/Specimens.js +0 -237
  55. package/website/app/components/StructuredData.js +0 -144
  56. package/website/app/components/TokenBrowser.js +0 -344
  57. package/website/app/components/token-browser-sample.js +0 -65
  58. package/website/app/globals.css +0 -505
  59. package/website/app/icon.svg +0 -7
  60. package/website/app/layout.js +0 -126
  61. package/website/app/opengraph-image.js +0 -170
  62. package/website/app/page.js +0 -399
  63. package/website/app/robots.js +0 -15
  64. package/website/app/seo-config.js +0 -82
  65. package/website/app/sitemap.js +0 -18
  66. package/website/jsconfig.json +0 -7
  67. package/website/lib/cache.js +0 -73
  68. package/website/lib/rate-limit.js +0 -30
  69. package/website/lib/rate-limit.test.js +0 -55
  70. package/website/lib/specimens.json +0 -86
  71. package/website/lib/token-helpers.js +0 -70
  72. package/website/lib/url-safety.js +0 -103
  73. package/website/lib/url-safety.test.js +0 -116
  74. package/website/lib/zip-files.js +0 -15
  75. package/website/next.config.mjs +0 -15
  76. package/website/package-lock.json +0 -1353
  77. package/website/package.json +0 -19
  78. package/website/public/favicon.svg +0 -7
  79. package/website/public/logo-specimen.svg +0 -76
  80. package/website/public/mark.svg +0 -12
  81. package/website/public/site.webmanifest +0 -13
@@ -1,286 +0,0 @@
1
- import Marginalia from './Marginalia';
2
-
3
- const TOOLS = [
4
- 'designlang',
5
- 'v0',
6
- 'Builder.io Visual Copilot',
7
- 'Style Dictionary',
8
- 'Subframe',
9
- 'Project Wallace',
10
- ];
11
-
12
- // Y = yes, N = no, P = partial
13
- const ROWS = [
14
- {
15
- feature: 'Extracts from a live URL',
16
- cells: ['Y', 'N', 'Y', 'N', 'N', 'Y'],
17
- },
18
- {
19
- feature: 'Emits W3C DTCG tokens',
20
- cells: ['Y', 'N', 'N', 'Y', 'N', 'N'],
21
- },
22
- {
23
- feature: 'Semantic alias layer',
24
- cells: ['Y', 'N', 'N', 'Y', 'P', 'N'],
25
- },
26
- {
27
- feature: 'Multi-platform output (iOS, Android, Flutter)',
28
- cells: ['Y', 'N', 'N', 'Y', 'N', 'N'],
29
- },
30
- {
31
- feature: 'MCP server over stdio',
32
- cells: ['Y', 'N', 'N', 'N', 'N', 'N'],
33
- },
34
- {
35
- feature: 'CSS health audit',
36
- cells: ['Y', 'N', 'N', 'N', 'N', 'Y'],
37
- },
38
- {
39
- feature: 'A11y remediation suggestions',
40
- cells: ['P', 'N', 'P', 'N', 'N', 'P'],
41
- },
42
- {
43
- feature: 'Component cluster detection',
44
- cells: ['P', 'Y', 'Y', 'N', 'Y', 'N'],
45
- },
46
- {
47
- feature: 'Offline / local-only',
48
- cells: ['Y', 'N', 'N', 'Y', 'N', 'N'],
49
- },
50
- {
51
- feature: 'Open source / MIT',
52
- cells: ['Y', 'N', 'N', 'Y', 'N', 'P'],
53
- },
54
- ];
55
-
56
- function Mark({ kind }) {
57
- if (kind === 'Y') {
58
- return (
59
- <svg width="14" height="14" viewBox="0 0 14 14" aria-label="yes" role="img">
60
- <rect x="2" y="2" width="10" height="10" fill="var(--ink)" transform="rotate(45 7 7)" />
61
- </svg>
62
- );
63
- }
64
- if (kind === 'P') {
65
- return (
66
- <svg width="16" height="16" viewBox="0 0 16 16" aria-label="partial" role="img">
67
- <rect
68
- x="3"
69
- y="3"
70
- width="10"
71
- height="10"
72
- fill="var(--accent)"
73
- stroke="var(--ink)"
74
- strokeWidth="1"
75
- transform="rotate(45 8 8)"
76
- />
77
- </svg>
78
- );
79
- }
80
- return (
81
- <span className="mono" style={{ color: 'var(--ink-3)', fontSize: 14 }} aria-label="no">
82
-
83
- </span>
84
- );
85
- }
86
-
87
- export default function Comparison() {
88
- return (
89
- <div>
90
- <div className="with-margin" style={{ marginTop: 'var(--r5)', marginBottom: 'var(--r7)' }}>
91
- <div>
92
- <div className="section-label" style={{ marginBottom: 'var(--r5)' }}>
93
- <span>§08 — Compared</span>
94
- </div>
95
- <h2 className="display" style={{ marginBottom: 'var(--r4)' }}>
96
- Where designlang doesn&apos;t win,<br />
97
- <em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>it says so.</em>
98
- </h2>
99
- <p className="prose" style={{ fontSize: 18, lineHeight: 1.5, maxWidth: '62ch' }}>
100
- We picked five tools doing closely adjacent work. The matrix below is our honest
101
- assessment on 2026-04-18, written by someone who actually uses all six.
102
- </p>
103
- </div>
104
- <Marginalia>
105
- <div>legend</div>
106
- <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 8 }}>
107
- <Mark kind="Y" /> <span>supported</span>
108
- </div>
109
- <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 6 }}>
110
- <Mark kind="P" /> <span>partial</span>
111
- </div>
112
- <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 6 }}>
113
- <Mark kind="N" /> <span>not supported</span>
114
- </div>
115
- <hr style={{ margin: '12px 0', border: 0, borderTop: '1px solid var(--ink-3)' }} />
116
- <p className="foot">
117
- Open a PR if this matrix is wrong for your tool. We&apos;ll update it or explain
118
- our read.
119
- </p>
120
- </Marginalia>
121
- </div>
122
-
123
- <div style={{ overflowX: 'auto', marginBottom: 'var(--r7)' }}>
124
- <table
125
- style={{
126
- width: '100%',
127
- minWidth: 900,
128
- borderCollapse: 'collapse',
129
- tableLayout: 'fixed',
130
- }}
131
- >
132
- <thead>
133
- <tr>
134
- <th
135
- scope="col"
136
- className="mono"
137
- style={{
138
- textAlign: 'left',
139
- fontSize: 12,
140
- textTransform: 'uppercase',
141
- letterSpacing: '0.12em',
142
- color: 'var(--ink-2)',
143
- padding: '12px 20px 12px 0',
144
- borderBottom: '1px solid var(--ink)',
145
- fontWeight: 400,
146
- width: '28%',
147
- }}
148
- >
149
- Feature
150
- </th>
151
- {TOOLS.map((t, i) => (
152
- <th
153
- key={t}
154
- scope="col"
155
- className="mono"
156
- style={{
157
- textAlign: 'center',
158
- fontSize: 12,
159
- textTransform: 'uppercase',
160
- letterSpacing: '0.08em',
161
- color: i === 0 ? 'var(--ink)' : 'var(--ink-2)',
162
- padding: '12px 8px',
163
- borderBottom: '1px solid var(--ink)',
164
- fontWeight: 400,
165
- }}
166
- >
167
- {t}
168
- </th>
169
- ))}
170
- </tr>
171
- </thead>
172
- <tbody>
173
- {ROWS.map((row, rIdx) => (
174
- <tr key={row.feature}>
175
- <th
176
- scope="row"
177
- style={{
178
- textAlign: 'left',
179
- padding: '14px 20px 14px 0',
180
- fontWeight: 400,
181
- fontSize: 15,
182
- color: 'var(--ink)',
183
- borderBottom: rIdx === ROWS.length - 1 ? 0 : '1px solid var(--paper-3)',
184
- }}
185
- >
186
- {row.feature}
187
- </th>
188
- {row.cells.map((c, i) => (
189
- <td
190
- key={i}
191
- style={{
192
- textAlign: 'center',
193
- padding: '14px 8px',
194
- verticalAlign: 'middle',
195
- borderBottom: rIdx === ROWS.length - 1 ? 0 : '1px solid var(--paper-3)',
196
- }}
197
- >
198
- <span style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
199
- <Mark kind={c} />
200
- </span>
201
- </td>
202
- ))}
203
- </tr>
204
- ))}
205
- </tbody>
206
- </table>
207
- </div>
208
-
209
- <div className="with-margin">
210
- <div>
211
- <h3
212
- className="mono"
213
- style={{
214
- fontSize: 12,
215
- textTransform: 'uppercase',
216
- letterSpacing: '0.14em',
217
- color: 'var(--ink-2)',
218
- marginBottom: 'var(--r4)',
219
- }}
220
- >
221
- What designlang is not
222
- </h3>
223
- <ul
224
- style={{
225
- listStyle: 'none',
226
- padding: 0,
227
- display: 'grid',
228
- gap: 'var(--r3)',
229
- maxWidth: '72ch',
230
- }}
231
- >
232
- <li
233
- style={{
234
- borderLeft: '1px solid var(--ink)',
235
- paddingLeft: 'var(--r4)',
236
- fontSize: 16,
237
- lineHeight: 1.5,
238
- }}
239
- >
240
- <em style={{ fontFamily: 'var(--font-display)', fontStyle: 'italic' }}>
241
- It is not a design-to-code generator.
242
- </em>{' '}
243
- It extracts the <strong>system</strong>, not the components as JSX.
244
- </li>
245
- <li
246
- style={{
247
- borderLeft: '1px solid var(--ink)',
248
- paddingLeft: 'var(--r4)',
249
- fontSize: 16,
250
- lineHeight: 1.5,
251
- }}
252
- >
253
- <em style={{ fontFamily: 'var(--font-display)', fontStyle: 'italic' }}>
254
- It is not a hosted cloud service.
255
- </em>{' '}
256
- The free website extractor is rate-limited; production use should run the CLI or
257
- MCP server locally.
258
- </li>
259
- <li
260
- style={{
261
- borderLeft: '1px solid var(--ink)',
262
- paddingLeft: 'var(--r4)',
263
- fontSize: 16,
264
- lineHeight: 1.5,
265
- }}
266
- >
267
- <em style={{ fontFamily: 'var(--font-display)', fontStyle: 'italic' }}>
268
- It is not a Figma plugin.
269
- </em>{' '}
270
- designlang reads the <strong>rendered DOM</strong>, not the Figma file — the
271
- output is what your users actually see, not what a designer intended.
272
- </li>
273
- </ul>
274
- </div>
275
- <Marginalia>
276
- <div>honesty clause</div>
277
- <p className="foot" style={{ marginTop: 6 }}>
278
- Two partial cells for designlang on purpose — the a11y remediation engine
279
- suggests fixes but won&apos;t rewrite your markup, and component cluster
280
- detection is heuristic, not vision-based.
281
- </p>
282
- </Marginalia>
283
- </div>
284
- </div>
285
- );
286
- }
@@ -1,243 +0,0 @@
1
- // §04 CSS health — mostly static. Static SVG plot, no ResizeObserver needed
2
- // (responsive via 100% width + aspect-ratio). Numbers are the PR B smoke
3
- // sample taken from stripe.com: 14 sheets, 89% unused, 764 !important rules,
4
- // 9,041 duplicate declarations.
5
-
6
- // Synthetic sample shaped from the PR B smoke distribution: a mostly low
7
- // specificity body with a rising-ramp tail — the classic "!important wall"
8
- // silhouette. X = rule order (0..100), Y = collapsed specificity (a*100+b*10+c).
9
- const POINTS = [
10
- [2, 11], [4, 10], [6, 20], [8, 12], [10, 21], [12, 11], [14, 22],
11
- [16, 20], [18, 12], [20, 22], [22, 30], [24, 20], [26, 21], [28, 31],
12
- [30, 22], [32, 30], [34, 31], [36, 22], [38, 32], [40, 30], [42, 40],
13
- [44, 32], [46, 41], [48, 42], [50, 51], [52, 42], [54, 50], [56, 61],
14
- [58, 52], [60, 71], [62, 81], [64, 92], [66, 112], [68, 121], [70, 141],
15
- [72, 161], [74, 172], [76, 191], [78, 202], [80, 221], [82, 232],
16
- [84, 252], [86, 272], [88, 291], [90, 311], [92, 331], [94, 352],
17
- [96, 372], [98, 391], [100, 412],
18
- ];
19
-
20
- const VENDOR_CHIPS = [
21
- ['-webkit-', '183'],
22
- ['-moz-', '41'],
23
- ['-ms-', '7'],
24
- ['-o-', '2'],
25
- ['duplicates', '9,041'],
26
- ];
27
-
28
- const STATS = [
29
- ['89%', 'unused css'],
30
- ['764', '!important rules'],
31
- ['9,041', 'duplicate declarations'],
32
- ['14', 'stylesheets analyzed'],
33
- ];
34
-
35
- import Rule from './Rule';
36
- import Marginalia from './Marginalia';
37
-
38
- function SpecificityPlot() {
39
- // viewBox 100 x 100 (abstract units), axis gutters inside.
40
- const maxY = 500;
41
- const padL = 10;
42
- const padB = 12;
43
- const padT = 4;
44
- const padR = 4;
45
-
46
- return (
47
- <svg
48
- viewBox="0 0 200 125"
49
- preserveAspectRatio="none"
50
- role="img"
51
- aria-label="Specificity scatter plot — rule order vs specificity score"
52
- style={{
53
- width: '100%',
54
- aspectRatio: '16 / 10',
55
- border: '1px solid var(--ink)',
56
- background: 'var(--paper)',
57
- display: 'block',
58
- }}
59
- >
60
- {/* axis lines */}
61
- <line x1={padL} y1={125 - padB} x2={200 - padR} y2={125 - padB} stroke="var(--ink)" strokeWidth="0.5" />
62
- <line x1={padL} y1={padT} x2={padL} y2={125 - padB} stroke="var(--ink)" strokeWidth="0.5" />
63
-
64
- {/* axis labels (mono ~10px visually — SVG units scaled) */}
65
- <text x={padL} y={124} fontFamily="var(--font-mono)" fontSize="3.2" fill="var(--ink-2)" letterSpacing="0.1">
66
- rule order →
67
- </text>
68
- <text
69
- x={padL + 1}
70
- y={padT + 3}
71
- fontFamily="var(--font-mono)"
72
- fontSize="3.2"
73
- fill="var(--ink-2)"
74
- letterSpacing="0.1"
75
- >
76
- ↑ specificity
77
- </text>
78
- <text x={200 - padR - 14} y={124} fontFamily="var(--font-mono)" fontSize="3" fill="var(--ink-3)">
79
- n=50
80
- </text>
81
-
82
- {/* points */}
83
- {POINTS.map(([x, y], i) => {
84
- const px = padL + (x / 100) * (200 - padL - padR);
85
- const py = 125 - padB - (Math.min(y, maxY) / maxY) * (125 - padB - padT);
86
- const outlier = y > 200;
87
- return (
88
- <rect
89
- key={i}
90
- x={px - 1}
91
- y={py - 1}
92
- width="2"
93
- height="2"
94
- fill={outlier ? 'var(--accent)' : 'var(--ink)'}
95
- />
96
- );
97
- })}
98
- </svg>
99
- );
100
- }
101
-
102
- export default function CssHealth() {
103
- return (
104
- <>
105
- <Rule number="04" label="CSS health audit" />
106
- <div className="with-margin" style={{ marginTop: 'var(--r5)' }}>
107
- <div>
108
- <div className="eyebrow" style={{ marginBottom: 'var(--r3)' }}>§04 CSS health</div>
109
- <h2 className="display" style={{ marginBottom: 'var(--r4)' }}>
110
- The stylesheet is the problem.
111
- </h2>
112
- <p className="prose" style={{ fontSize: 18, maxWidth: '62ch', color: 'var(--ink-2)' }}>
113
- Most sites ship 40–90% unused CSS, long walls of <code>!important</code> escalations,
114
- and a specificity graph that rises forever. v7.0 surfaces all of it — not as a
115
- vanity score, but as exact declaration-level evidence.
116
- </p>
117
-
118
- <div
119
- className="grid-12"
120
- style={{
121
- marginTop: 'var(--r7)',
122
- gap: 'var(--col-gap)',
123
- alignItems: 'start',
124
- }}
125
- >
126
- {/* Big numerals — span 5 */}
127
- <div
128
- style={{
129
- gridColumn: 'span 5',
130
- display: 'grid',
131
- gridTemplateColumns: '1fr 1fr',
132
- gap: 'var(--r5) var(--r4)',
133
- }}
134
- >
135
- {STATS.map(([n, label]) => (
136
- <div key={label} style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
137
- <div
138
- className="display"
139
- style={{
140
- fontSize: 'clamp(64px, 7vw, 120px)',
141
- lineHeight: 0.95,
142
- fontVariantNumeric: 'tabular-nums',
143
- fontFeatureSettings: "'tnum' 1",
144
- letterSpacing: '-0.04em',
145
- }}
146
- >
147
- {n}
148
- </div>
149
- <div
150
- className="mono"
151
- style={{
152
- fontSize: 11,
153
- letterSpacing: '0.14em',
154
- textTransform: 'uppercase',
155
- color: 'var(--ink-2)',
156
- }}
157
- >
158
- {label}
159
- </div>
160
- </div>
161
- ))}
162
- </div>
163
-
164
- {/* Plot — span 7 */}
165
- <div style={{ gridColumn: 'span 7' }}>
166
- <div
167
- className="mono"
168
- style={{
169
- fontSize: 11,
170
- letterSpacing: '0.14em',
171
- textTransform: 'uppercase',
172
- color: 'var(--ink-2)',
173
- marginBottom: 'var(--r3)',
174
- display: 'flex',
175
- justifyContent: 'space-between',
176
- }}
177
- >
178
- <span>specificity distribution</span>
179
- <span style={{ color: 'var(--accent)' }}>outliers: specificity &gt; 200</span>
180
- </div>
181
- <SpecificityPlot />
182
- <div
183
- className="mono"
184
- style={{
185
- fontSize: 11,
186
- color: 'var(--ink-3)',
187
- marginTop: 'var(--r3)',
188
- }}
189
- >
190
- collapsed score: a×100 + b×10 + c. rising tail = accumulated !important wall.
191
- </div>
192
- </div>
193
- </div>
194
-
195
- {/* Caption strip — vendor prefix chips */}
196
- <div
197
- style={{
198
- marginTop: 'var(--r7)',
199
- display: 'flex',
200
- flexWrap: 'wrap',
201
- gap: 'var(--r3)',
202
- borderTop: 'var(--hair)',
203
- paddingTop: 'var(--r4)',
204
- }}
205
- >
206
- {VENDOR_CHIPS.map(([k, v]) => (
207
- <span
208
- key={k}
209
- className="mono"
210
- style={{
211
- display: 'inline-flex',
212
- alignItems: 'baseline',
213
- gap: 8,
214
- padding: '3px 8px',
215
- border: '1px solid var(--ink)',
216
- fontSize: 11,
217
- letterSpacing: '0.04em',
218
- }}
219
- >
220
- <span style={{ color: 'var(--ink-2)' }}>{k}</span>
221
- <span style={{ fontVariantNumeric: 'tabular-nums' }}>{v}</span>
222
- </span>
223
- ))}
224
- </div>
225
- </div>
226
-
227
- <Marginalia>
228
- <div>additive scoring</div>
229
- <p style={{ marginTop: 6 }}>
230
- Tracked additively: existing score fields kept for back-compat; CSS health joins as a new
231
- dimension.
232
- </p>
233
- <hr style={{ margin: '12px 0', border: 0, borderTop: '1px solid var(--ink-3)' }} />
234
- <div>works on any site</div>
235
- <p className="foot" style={{ marginTop: 6 }}>
236
- Flags rising specificity, zombie declarations, and abandoned <code>!important</code> walls —
237
- with exact selector provenance.
238
- </p>
239
- </Marginalia>
240
- </div>
241
- </>
242
- );
243
- }