designlang 6.0.0 → 7.1.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/.github/FUNDING.yml +1 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +62 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +28 -0
- package/.vercel/README.txt +11 -0
- package/.vercel/project.json +1 -0
- package/CHANGELOG.md +58 -0
- package/CONTRIBUTING.md +25 -0
- package/README.md +120 -8
- package/bin/design-extract.js +106 -3
- package/chrome-extension/README.md +41 -0
- package/chrome-extension/icons/favicon.svg +7 -0
- package/chrome-extension/icons/icon-128.png +0 -0
- package/chrome-extension/icons/icon-16.png +0 -0
- package/chrome-extension/icons/icon-32.png +0 -0
- package/chrome-extension/icons/icon-48.png +0 -0
- package/chrome-extension/manifest.json +26 -0
- package/chrome-extension/popup.html +167 -0
- package/chrome-extension/popup.js +59 -0
- package/docs/superpowers/plans/2026-04-18-designlang-v7.md +1121 -0
- package/docs/superpowers/specs/2026-04-18-designlang-v7-design.md +150 -0
- package/docs/superpowers/specs/2026-04-18-website-redesign-design.md +120 -0
- package/docs/superpowers/specs/2026-04-19-designlang-v7-1-design.md +111 -0
- package/package.json +5 -4
- package/src/config.js +26 -0
- package/src/crawler.js +136 -2
- package/src/extractors/a11y-remediation.js +47 -0
- package/src/extractors/component-clusters.js +39 -0
- package/src/extractors/css-health.js +151 -0
- package/src/extractors/scoring.js +20 -1
- package/src/extractors/semantic-regions.js +44 -0
- package/src/extractors/stack-fingerprint.js +88 -0
- package/src/formatters/_token-ref.js +44 -0
- package/src/formatters/agent-rules.js +116 -0
- package/src/formatters/android-compose.js +164 -0
- package/src/formatters/dtcg-tokens.js +175 -0
- package/src/formatters/flutter-dart.js +130 -0
- package/src/formatters/ios-swiftui.js +161 -0
- package/src/formatters/markdown.js +25 -0
- package/src/formatters/wordpress.js +183 -0
- package/src/index.js +30 -0
- package/src/mcp/resources.js +64 -0
- package/src/mcp/server.js +110 -0
- package/src/mcp/tools.js +149 -0
- package/src/utils-cookies.js +73 -0
- package/tests/cli.test.js +50 -0
- package/tests/cookies.test.js +98 -0
- package/tests/extractors.test.js +131 -0
- package/tests/formatters.test.js +232 -0
- package/tests/mcp.test.js +68 -0
- package/website/app/api/extract/route.js +216 -56
- package/website/app/components/A11ySlider.js +369 -0
- package/website/app/components/Comparison.js +286 -0
- package/website/app/components/CssHealth.js +243 -0
- package/website/app/components/HeroExtractor.js +455 -0
- package/website/app/components/Marginalia.js +3 -0
- package/website/app/components/McpSection.js +223 -0
- package/website/app/components/PlatformTabs.js +250 -0
- package/website/app/components/RegionsComponents.js +429 -0
- package/website/app/components/Rule.js +13 -0
- package/website/app/components/Specimens.js +237 -0
- package/website/app/components/StructuredData.js +144 -0
- package/website/app/components/TokenBrowser.js +344 -0
- package/website/app/components/token-browser-sample.js +65 -0
- package/website/app/globals.css +415 -633
- package/website/app/icon.svg +7 -0
- package/website/app/layout.js +113 -6
- package/website/app/opengraph-image.js +170 -0
- package/website/app/page.js +325 -148
- package/website/app/robots.js +15 -0
- package/website/app/seo-config.js +82 -0
- package/website/app/sitemap.js +18 -0
- package/website/lib/cache.js +73 -0
- package/website/lib/rate-limit.js +30 -0
- package/website/lib/rate-limit.test.js +55 -0
- package/website/lib/specimens.json +86 -0
- package/website/lib/token-helpers.js +70 -0
- package/website/lib/url-safety.js +103 -0
- package/website/lib/url-safety.test.js +116 -0
- package/website/lib/zip-files.js +15 -0
- package/website/package-lock.json +85 -0
- package/website/package.json +1 -0
- package/website/public/favicon.svg +7 -0
- package/website/public/logo-specimen.svg +76 -0
- package/website/public/mark.svg +12 -0
- package/website/public/site.webmanifest +13 -0
- package/website/app/favicon.ico +0 -0
- package/website/public/file.svg +0 -1
- package/website/public/globe.svg +0 -1
- package/website/public/next.svg +0 -1
- package/website/public/vercel.svg +0 -1
- package/website/public/window.svg +0 -1
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef } from 'react';
|
|
4
|
+
import specimens from '../../lib/specimens.json';
|
|
5
|
+
import Marginalia from './Marginalia';
|
|
6
|
+
|
|
7
|
+
// Quick relative-luminance check used to guard against accents that would fail
|
|
8
|
+
// 3:1 on paper. If they do, we fall back to ink.
|
|
9
|
+
function contrastsOnPaper(hex) {
|
|
10
|
+
const paper = [0xf3, 0xf1, 0xea];
|
|
11
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
12
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
13
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
14
|
+
const lum = (c) => {
|
|
15
|
+
const s = c / 255;
|
|
16
|
+
return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
|
|
17
|
+
};
|
|
18
|
+
const l1 = 0.2126 * lum(paper[0]) + 0.7152 * lum(paper[1]) + 0.0722 * lum(paper[2]);
|
|
19
|
+
const l2 = 0.2126 * lum(r) + 0.7152 * lum(g) + 0.0722 * lum(b);
|
|
20
|
+
const ratio = (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
|
|
21
|
+
return ratio >= 3;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default function Specimens() {
|
|
25
|
+
const stripRef = useRef(null);
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const el = stripRef.current;
|
|
29
|
+
if (!el) return;
|
|
30
|
+
|
|
31
|
+
const cards = Array.from(el.querySelectorAll('[data-specimen]'));
|
|
32
|
+
const root = document.documentElement;
|
|
33
|
+
const DEFAULT = '#FF4800';
|
|
34
|
+
|
|
35
|
+
const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
36
|
+
root.style.setProperty('--accent-transition', reduced ? '0s' : '400ms');
|
|
37
|
+
// Attach transition for --accent. Since CSS can't transition a custom
|
|
38
|
+
// property by default we apply it via a style tag scoped to documentElement.
|
|
39
|
+
const styleEl = document.createElement('style');
|
|
40
|
+
styleEl.textContent = `html { transition: --accent var(--accent-transition) ease; } @property --accent { syntax: '<color>'; inherits: true; initial-value: #FF4800; }`;
|
|
41
|
+
document.head.appendChild(styleEl);
|
|
42
|
+
|
|
43
|
+
const io = new IntersectionObserver(
|
|
44
|
+
(entries) => {
|
|
45
|
+
const visible = entries.filter((e) => e.isIntersecting);
|
|
46
|
+
if (visible.length === 0) {
|
|
47
|
+
root.style.setProperty('--accent', DEFAULT);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// Pick the one with the greatest visibility ratio.
|
|
51
|
+
const top = visible.sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
|
|
52
|
+
const accent = top.target.getAttribute('data-accent') || DEFAULT;
|
|
53
|
+
const safe = contrastsOnPaper(accent) ? accent : '#0A0908';
|
|
54
|
+
root.style.setProperty('--accent', safe);
|
|
55
|
+
},
|
|
56
|
+
{ root: el, threshold: [0.6] }
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
cards.forEach((c) => io.observe(c));
|
|
60
|
+
return () => {
|
|
61
|
+
io.disconnect();
|
|
62
|
+
root.style.setProperty('--accent', DEFAULT);
|
|
63
|
+
styleEl.remove();
|
|
64
|
+
};
|
|
65
|
+
}, []);
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<div>
|
|
69
|
+
<div className="with-margin" style={{ marginTop: 'var(--r5)', marginBottom: 'var(--r7)' }}>
|
|
70
|
+
<div>
|
|
71
|
+
<div className="section-label" style={{ marginBottom: 'var(--r5)' }}>
|
|
72
|
+
<span>§07 — Specimens</span>
|
|
73
|
+
</div>
|
|
74
|
+
<h2 className="display" style={{ marginBottom: 'var(--r5)' }}>
|
|
75
|
+
Six design systems,<br />
|
|
76
|
+
<em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>one format.</em>
|
|
77
|
+
</h2>
|
|
78
|
+
<p className="prose" style={{ fontSize: 18, lineHeight: 1.5, maxWidth: '62ch' }}>
|
|
79
|
+
Each specimen was crawled once and written to DTCG. The page accent below is
|
|
80
|
+
pulled from the specimen's own extracted primary — the same{' '}
|
|
81
|
+
<code className="mono" style={{ fontSize: 14 }}>semantic.color.action.primary</code>{' '}
|
|
82
|
+
your agent would get over MCP.
|
|
83
|
+
</p>
|
|
84
|
+
</div>
|
|
85
|
+
<Marginalia>
|
|
86
|
+
<div>accessibility</div>
|
|
87
|
+
<p className="foot" style={{ marginTop: 6 }}>
|
|
88
|
+
The live <code>--accent</code> is tested for ≥3:1 contrast with paper on scroll.
|
|
89
|
+
Specimens that fall below fall back to ink.
|
|
90
|
+
</p>
|
|
91
|
+
<hr style={{ margin: '12px 0', border: 0, borderTop: '1px solid var(--ink-3)' }} />
|
|
92
|
+
<p className="foot">
|
|
93
|
+
Specimens are point-in-time snapshots, re-rendered from on-disk DTCG files.
|
|
94
|
+
To update, re-run <code>designlang <url> --platforms web</code> and
|
|
95
|
+
replace the specimen entry.
|
|
96
|
+
</p>
|
|
97
|
+
</Marginalia>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div
|
|
101
|
+
ref={stripRef}
|
|
102
|
+
className="specimen-strip"
|
|
103
|
+
style={{
|
|
104
|
+
display: 'flex',
|
|
105
|
+
gap: 'var(--r5)',
|
|
106
|
+
overflowX: 'auto',
|
|
107
|
+
overflowY: 'hidden',
|
|
108
|
+
scrollSnapType: 'x mandatory',
|
|
109
|
+
paddingBottom: 'var(--r5)',
|
|
110
|
+
paddingInline: 'var(--page-pad-x)',
|
|
111
|
+
marginInline: 'calc(-1 * var(--page-pad-x))',
|
|
112
|
+
scrollbarWidth: 'thin',
|
|
113
|
+
}}
|
|
114
|
+
>
|
|
115
|
+
{specimens.map((s) => (
|
|
116
|
+
<SpecimenCard key={s.host} s={s} />
|
|
117
|
+
))}
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<style jsx>{`
|
|
121
|
+
.specimen-strip > :global([data-specimen]) {
|
|
122
|
+
flex: 0 0 640px;
|
|
123
|
+
height: 400px;
|
|
124
|
+
scroll-snap-align: start;
|
|
125
|
+
border: 1px solid var(--ink);
|
|
126
|
+
background: var(--paper-2);
|
|
127
|
+
padding: var(--r5);
|
|
128
|
+
display: grid;
|
|
129
|
+
grid-template-rows: auto auto 1fr auto auto;
|
|
130
|
+
gap: var(--r4);
|
|
131
|
+
}
|
|
132
|
+
@media (max-width: 860px) {
|
|
133
|
+
.specimen-strip {
|
|
134
|
+
flex-direction: column;
|
|
135
|
+
overflow-x: hidden;
|
|
136
|
+
scroll-snap-type: none;
|
|
137
|
+
}
|
|
138
|
+
.specimen-strip > :global([data-specimen]) {
|
|
139
|
+
flex: 0 0 auto;
|
|
140
|
+
width: 100%;
|
|
141
|
+
height: auto;
|
|
142
|
+
min-height: 420px;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
`}</style>
|
|
146
|
+
</div>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function SpecimenCard({ s }) {
|
|
151
|
+
return (
|
|
152
|
+
<article data-specimen data-accent={s.accent} aria-label={`${s.display} specimen`}>
|
|
153
|
+
<header style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
|
|
154
|
+
<span className="chip mono">{s.host}</span>
|
|
155
|
+
<span className="chip mono">{s.year}</span>
|
|
156
|
+
<span className="chip mono">{s.framework}</span>
|
|
157
|
+
</header>
|
|
158
|
+
|
|
159
|
+
<div style={{ display: 'flex', gap: 0 }}>
|
|
160
|
+
{s.palette.map((hex) => (
|
|
161
|
+
<div key={hex} style={{ flex: '0 0 auto', marginRight: 8 }}>
|
|
162
|
+
<div
|
|
163
|
+
aria-hidden="true"
|
|
164
|
+
style={{
|
|
165
|
+
width: 40,
|
|
166
|
+
height: 40,
|
|
167
|
+
background: hex,
|
|
168
|
+
border: '1px solid var(--ink)',
|
|
169
|
+
}}
|
|
170
|
+
/>
|
|
171
|
+
<div
|
|
172
|
+
className="mono"
|
|
173
|
+
style={{ fontSize: 10, marginTop: 4, color: 'var(--ink-2)', letterSpacing: '0.02em' }}
|
|
174
|
+
>
|
|
175
|
+
{hex.toUpperCase()}
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
))}
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
<div
|
|
182
|
+
className="display"
|
|
183
|
+
style={{
|
|
184
|
+
fontSize: 64,
|
|
185
|
+
lineHeight: 1,
|
|
186
|
+
letterSpacing: '-0.02em',
|
|
187
|
+
color: 'var(--ink)',
|
|
188
|
+
alignSelf: 'center',
|
|
189
|
+
whiteSpace: 'nowrap',
|
|
190
|
+
overflow: 'hidden',
|
|
191
|
+
textOverflow: 'ellipsis',
|
|
192
|
+
}}
|
|
193
|
+
>
|
|
194
|
+
<span style={{ color: s.accent }}>{s.display}.</span>{' '}
|
|
195
|
+
<span style={{ color: 'var(--ink-2)' }}>Design as a system.</span>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<div style={{ display: 'flex', gap: 'var(--r6)' }}>
|
|
199
|
+
<Metric label="a11y" value={s.a11y} />
|
|
200
|
+
<Metric label="score" value={s.designScore} />
|
|
201
|
+
<Metric label="radius" value={s.radius} />
|
|
202
|
+
</div>
|
|
203
|
+
|
|
204
|
+
<footer
|
|
205
|
+
style={{
|
|
206
|
+
fontFamily: 'var(--font-display)',
|
|
207
|
+
fontStyle: 'italic',
|
|
208
|
+
color: 'var(--ink-2)',
|
|
209
|
+
fontSize: 14,
|
|
210
|
+
borderTop: '1px solid var(--ink-3)',
|
|
211
|
+
paddingTop: 10,
|
|
212
|
+
}}
|
|
213
|
+
>
|
|
214
|
+
{s.note}
|
|
215
|
+
</footer>
|
|
216
|
+
</article>
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function Metric({ label, value }) {
|
|
221
|
+
return (
|
|
222
|
+
<div>
|
|
223
|
+
<div
|
|
224
|
+
className="display"
|
|
225
|
+
style={{ fontSize: 40, lineHeight: 1, letterSpacing: '-0.02em' }}
|
|
226
|
+
>
|
|
227
|
+
{value}
|
|
228
|
+
</div>
|
|
229
|
+
<div
|
|
230
|
+
className="mono"
|
|
231
|
+
style={{ fontSize: 10, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.12em', marginTop: 4 }}
|
|
232
|
+
>
|
|
233
|
+
{label}
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
);
|
|
237
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SITE_URL,
|
|
3
|
+
SITE_NAME,
|
|
4
|
+
SITE_DESCRIPTION,
|
|
5
|
+
SITE_KEYWORDS,
|
|
6
|
+
} from '../seo-config';
|
|
7
|
+
|
|
8
|
+
// JSON-LD structured data. All content is server-literal — no user input is
|
|
9
|
+
// interpolated into the JSON string. This matches the Next.js App Router
|
|
10
|
+
// metadata docs' recommended inline-script pattern.
|
|
11
|
+
// https://nextjs.org/docs/app/building-your-application/optimizing/metadata#json-ld
|
|
12
|
+
export default function StructuredData() {
|
|
13
|
+
const graph = {
|
|
14
|
+
'@context': 'https://schema.org',
|
|
15
|
+
'@graph': [
|
|
16
|
+
{
|
|
17
|
+
'@type': 'SoftwareApplication',
|
|
18
|
+
'@id': `${SITE_URL}/#software`,
|
|
19
|
+
name: 'designlang',
|
|
20
|
+
alternateName: ['design-extract', 'designlang CLI'],
|
|
21
|
+
description: SITE_DESCRIPTION,
|
|
22
|
+
applicationCategory: 'DeveloperApplication',
|
|
23
|
+
applicationSubCategory: 'Design System Extractor',
|
|
24
|
+
operatingSystem: 'macOS, Windows, Linux',
|
|
25
|
+
softwareVersion: '7.0.0',
|
|
26
|
+
downloadUrl: 'https://www.npmjs.com/package/designlang',
|
|
27
|
+
installUrl: 'https://www.npmjs.com/package/designlang',
|
|
28
|
+
url: SITE_URL,
|
|
29
|
+
offers: {
|
|
30
|
+
'@type': 'Offer',
|
|
31
|
+
price: '0',
|
|
32
|
+
priceCurrency: 'USD',
|
|
33
|
+
availability: 'https://schema.org/InStock',
|
|
34
|
+
},
|
|
35
|
+
license: 'https://opensource.org/licenses/MIT',
|
|
36
|
+
codeRepository: 'https://github.com/Manavarya09/design-extract',
|
|
37
|
+
programmingLanguage: ['JavaScript', 'TypeScript'],
|
|
38
|
+
runtimePlatform: 'Node.js 20+',
|
|
39
|
+
featureList: [
|
|
40
|
+
'Reverse-engineer any website into a W3C DTCG design system',
|
|
41
|
+
'Emits primitive, semantic, and composite tokens',
|
|
42
|
+
'Multi-platform output: Tailwind, CSS variables, Figma variables, shadcn/ui, React, Vue, Svelte, iOS SwiftUI, Android Compose, Flutter, WordPress block theme',
|
|
43
|
+
'Stdio MCP server exposing tokens, regions, components, CSS health, and remediation',
|
|
44
|
+
'Agent rule emitter for Cursor, Claude Code, Windsurf, AGENTS.md',
|
|
45
|
+
'CSS health audit: specificity graph, !important count, unused CSS via Coverage API, @keyframes catalog',
|
|
46
|
+
'WCAG accessibility remediation with nearest passing palette color',
|
|
47
|
+
'Semantic region classifier (nav, hero, pricing, testimonials, footer, and more)',
|
|
48
|
+
'Reusable component clustering with variant detection',
|
|
49
|
+
'Dark mode diff, authenticated page crawling, responsive breakpoint capture',
|
|
50
|
+
],
|
|
51
|
+
keywords: SITE_KEYWORDS.slice(0, 25).join(', '),
|
|
52
|
+
author: {
|
|
53
|
+
'@type': 'Person',
|
|
54
|
+
name: 'Manav Arya Singh',
|
|
55
|
+
url: 'https://manavaryasingh.com',
|
|
56
|
+
},
|
|
57
|
+
publisher: {
|
|
58
|
+
'@type': 'Person',
|
|
59
|
+
name: 'Manav Arya Singh',
|
|
60
|
+
url: 'https://manavaryasingh.com',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
'@type': 'WebSite',
|
|
65
|
+
'@id': `${SITE_URL}/#website`,
|
|
66
|
+
url: SITE_URL,
|
|
67
|
+
name: SITE_NAME,
|
|
68
|
+
description: SITE_DESCRIPTION,
|
|
69
|
+
publisher: { '@id': `${SITE_URL}/#person` },
|
|
70
|
+
inLanguage: 'en-US',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
'@type': 'Person',
|
|
74
|
+
'@id': `${SITE_URL}/#person`,
|
|
75
|
+
name: 'Manav Arya Singh',
|
|
76
|
+
url: 'https://manavaryasingh.com',
|
|
77
|
+
sameAs: [
|
|
78
|
+
'https://github.com/Manavarya09',
|
|
79
|
+
'https://www.npmjs.com/~manavarya0909',
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
'@type': 'BreadcrumbList',
|
|
84
|
+
'@id': `${SITE_URL}/#breadcrumbs`,
|
|
85
|
+
itemListElement: [
|
|
86
|
+
{ '@type': 'ListItem', position: 1, name: 'Home', item: SITE_URL },
|
|
87
|
+
{ '@type': 'ListItem', position: 2, name: 'Extract', item: `${SITE_URL}/#extract` },
|
|
88
|
+
{ '@type': 'ListItem', position: 3, name: 'Features', item: `${SITE_URL}/#features` },
|
|
89
|
+
{ '@type': 'ListItem', position: 4, name: 'Specimens', item: `${SITE_URL}/#specimens` },
|
|
90
|
+
{ '@type': 'ListItem', position: 5, name: 'Install', item: `${SITE_URL}/#install` },
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
'@type': 'FAQPage',
|
|
95
|
+
'@id': `${SITE_URL}/#faq`,
|
|
96
|
+
mainEntity: [
|
|
97
|
+
{
|
|
98
|
+
'@type': 'Question',
|
|
99
|
+
name: 'What is designlang?',
|
|
100
|
+
acceptedAnswer: {
|
|
101
|
+
'@type': 'Answer',
|
|
102
|
+
text: 'designlang is an open-source CLI tool that crawls any live website with Playwright and emits its complete design system in W3C DTCG token format, plus Tailwind, CSS variables, Figma variables, shadcn/ui theme, and native emitters for iOS SwiftUI, Android Compose, Flutter, and WordPress block themes.',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
'@type': 'Question',
|
|
107
|
+
name: 'Does designlang work with AI coding agents like Claude Code and Cursor?',
|
|
108
|
+
acceptedAnswer: {
|
|
109
|
+
'@type': 'Answer',
|
|
110
|
+
text: 'Yes. designlang ships a stdio MCP server (designlang mcp) that exposes extracted tokens, regions, components, CSS health, and accessibility remediation as MCP resources and tools, plus an --emit-agent-rules flag that writes .cursor/rules/designlang.mdc, .claude/skills/designlang/SKILL.md, CLAUDE.md.fragment, and agents.md.',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
'@type': 'Question',
|
|
115
|
+
name: 'How is designlang different from Style Dictionary, Subframe, v0, Builder.io, and Project Wallace?',
|
|
116
|
+
acceptedAnswer: {
|
|
117
|
+
'@type': 'Answer',
|
|
118
|
+
text: 'designlang extracts from a live rendered URL, not a Figma file or a manually-authored token source. It outputs strict DTCG with a semantic/primitive layering and composite tokens, ships multi-platform emitters (iOS, Android, Flutter, WordPress) from one extraction, runs a CSS health audit plus a11y remediation, classifies page regions, and detects reusable components automatically. It is open-source under MIT and runs locally as a CLI or MCP server.',
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
'@type': 'Question',
|
|
123
|
+
name: 'Is designlang free and open source?',
|
|
124
|
+
acceptedAnswer: {
|
|
125
|
+
'@type': 'Answer',
|
|
126
|
+
text: 'Yes. designlang is MIT-licensed, free, and fully open-source. The CLI installs with npx designlang <url> and requires only Node.js 20 or later. The website at designlang.manavaryasingh.com offers a free rate-limited extraction for quick demos.',
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
'@type': 'Question',
|
|
131
|
+
name: 'What output formats does designlang support?',
|
|
132
|
+
acceptedAnswer: {
|
|
133
|
+
'@type': 'Answer',
|
|
134
|
+
text: 'W3C DTCG JSON (primitive, semantic, composite layers), Tailwind CSS config, CSS custom properties, Figma Variables JSON, shadcn/ui theme, React / Vue / Svelte theme objects, iOS SwiftUI Color + CGFloat extensions, Android Jetpack Compose Theme.kt and colors.xml, Flutter ThemeData, and a WordPress block theme skeleton (theme.json, style.css, templates).',
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const json = JSON.stringify(graph).replace(/</g, '\\u003c');
|
|
143
|
+
return <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: json }} />;
|
|
144
|
+
}
|