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.
Files changed (92) hide show
  1. package/.github/FUNDING.yml +1 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.yml +62 -0
  3. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.yml +28 -0
  5. package/.vercel/README.txt +11 -0
  6. package/.vercel/project.json +1 -0
  7. package/CHANGELOG.md +58 -0
  8. package/CONTRIBUTING.md +25 -0
  9. package/README.md +120 -8
  10. package/bin/design-extract.js +106 -3
  11. package/chrome-extension/README.md +41 -0
  12. package/chrome-extension/icons/favicon.svg +7 -0
  13. package/chrome-extension/icons/icon-128.png +0 -0
  14. package/chrome-extension/icons/icon-16.png +0 -0
  15. package/chrome-extension/icons/icon-32.png +0 -0
  16. package/chrome-extension/icons/icon-48.png +0 -0
  17. package/chrome-extension/manifest.json +26 -0
  18. package/chrome-extension/popup.html +167 -0
  19. package/chrome-extension/popup.js +59 -0
  20. package/docs/superpowers/plans/2026-04-18-designlang-v7.md +1121 -0
  21. package/docs/superpowers/specs/2026-04-18-designlang-v7-design.md +150 -0
  22. package/docs/superpowers/specs/2026-04-18-website-redesign-design.md +120 -0
  23. package/docs/superpowers/specs/2026-04-19-designlang-v7-1-design.md +111 -0
  24. package/package.json +5 -4
  25. package/src/config.js +26 -0
  26. package/src/crawler.js +136 -2
  27. package/src/extractors/a11y-remediation.js +47 -0
  28. package/src/extractors/component-clusters.js +39 -0
  29. package/src/extractors/css-health.js +151 -0
  30. package/src/extractors/scoring.js +20 -1
  31. package/src/extractors/semantic-regions.js +44 -0
  32. package/src/extractors/stack-fingerprint.js +88 -0
  33. package/src/formatters/_token-ref.js +44 -0
  34. package/src/formatters/agent-rules.js +116 -0
  35. package/src/formatters/android-compose.js +164 -0
  36. package/src/formatters/dtcg-tokens.js +175 -0
  37. package/src/formatters/flutter-dart.js +130 -0
  38. package/src/formatters/ios-swiftui.js +161 -0
  39. package/src/formatters/markdown.js +25 -0
  40. package/src/formatters/wordpress.js +183 -0
  41. package/src/index.js +30 -0
  42. package/src/mcp/resources.js +64 -0
  43. package/src/mcp/server.js +110 -0
  44. package/src/mcp/tools.js +149 -0
  45. package/src/utils-cookies.js +73 -0
  46. package/tests/cli.test.js +50 -0
  47. package/tests/cookies.test.js +98 -0
  48. package/tests/extractors.test.js +131 -0
  49. package/tests/formatters.test.js +232 -0
  50. package/tests/mcp.test.js +68 -0
  51. package/website/app/api/extract/route.js +216 -56
  52. package/website/app/components/A11ySlider.js +369 -0
  53. package/website/app/components/Comparison.js +286 -0
  54. package/website/app/components/CssHealth.js +243 -0
  55. package/website/app/components/HeroExtractor.js +455 -0
  56. package/website/app/components/Marginalia.js +3 -0
  57. package/website/app/components/McpSection.js +223 -0
  58. package/website/app/components/PlatformTabs.js +250 -0
  59. package/website/app/components/RegionsComponents.js +429 -0
  60. package/website/app/components/Rule.js +13 -0
  61. package/website/app/components/Specimens.js +237 -0
  62. package/website/app/components/StructuredData.js +144 -0
  63. package/website/app/components/TokenBrowser.js +344 -0
  64. package/website/app/components/token-browser-sample.js +65 -0
  65. package/website/app/globals.css +415 -633
  66. package/website/app/icon.svg +7 -0
  67. package/website/app/layout.js +113 -6
  68. package/website/app/opengraph-image.js +170 -0
  69. package/website/app/page.js +325 -148
  70. package/website/app/robots.js +15 -0
  71. package/website/app/seo-config.js +82 -0
  72. package/website/app/sitemap.js +18 -0
  73. package/website/lib/cache.js +73 -0
  74. package/website/lib/rate-limit.js +30 -0
  75. package/website/lib/rate-limit.test.js +55 -0
  76. package/website/lib/specimens.json +86 -0
  77. package/website/lib/token-helpers.js +70 -0
  78. package/website/lib/url-safety.js +103 -0
  79. package/website/lib/url-safety.test.js +116 -0
  80. package/website/lib/zip-files.js +15 -0
  81. package/website/package-lock.json +85 -0
  82. package/website/package.json +1 -0
  83. package/website/public/favicon.svg +7 -0
  84. package/website/public/logo-specimen.svg +76 -0
  85. package/website/public/mark.svg +12 -0
  86. package/website/public/site.webmanifest +13 -0
  87. package/website/app/favicon.ico +0 -0
  88. package/website/public/file.svg +0 -1
  89. package/website/public/globe.svg +0 -1
  90. package/website/public/next.svg +0 -1
  91. package/website/public/vercel.svg +0 -1
  92. package/website/public/window.svg +0 -1
@@ -0,0 +1,7 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" role="img" aria-label="designlang">
2
+ <title>designlang</title>
3
+ <rect width="32" height="32" fill="#F3F1EA"/>
4
+ <circle cx="13" cy="20" r="7.5" fill="none" stroke="#0A0908" stroke-width="4.5"/>
5
+ <rect x="19" y="4" width="4.5" height="25" fill="#0A0908"/>
6
+ <rect x="25" y="25" width="4" height="4" fill="#FF4800"/>
7
+ </svg>
@@ -1,17 +1,124 @@
1
- import "./globals.css";
1
+ import { Fraunces, Instrument_Sans, JetBrains_Mono } from 'next/font/google';
2
+ import StructuredData from './components/StructuredData';
3
+ import {
4
+ SITE_URL,
5
+ SITE_NAME,
6
+ SITE_TITLE,
7
+ SITE_DESCRIPTION,
8
+ SITE_KEYWORDS,
9
+ } from './seo-config';
10
+ import './globals.css';
11
+
12
+ const fraunces = Fraunces({
13
+ subsets: ['latin'],
14
+ variable: '--font-display',
15
+ display: 'swap',
16
+ });
17
+
18
+ const instrumentSans = Instrument_Sans({
19
+ subsets: ['latin'],
20
+ variable: '--font-body',
21
+ display: 'swap',
22
+ });
23
+
24
+ const mono = JetBrains_Mono({
25
+ subsets: ['latin'],
26
+ variable: '--font-mono',
27
+ display: 'swap',
28
+ });
2
29
 
3
30
  export const metadata = {
4
- title: "DESIGNLANG — Reverse-Engineer Any Website's Design System",
5
- description: "One command. 8 output files. Colors, typography, spacing, layout, accessibility, interactions, and more. npx designlang",
31
+ metadataBase: new URL(SITE_URL),
32
+ title: {
33
+ default: SITE_TITLE,
34
+ template: '%s \u2014 designlang',
35
+ },
36
+ description: SITE_DESCRIPTION,
37
+ keywords: SITE_KEYWORDS,
38
+ authors: [{ name: 'Manav Arya Singh', url: 'https://manavaryasingh.com' }],
39
+ creator: 'Manav Arya Singh',
40
+ publisher: 'Manav Arya Singh',
41
+ applicationName: SITE_NAME,
42
+ category: 'developer tools',
43
+ classification:
44
+ 'design system extractor, design tokens, design-to-code, AI coding agents, MCP server',
45
+ generator: 'Next.js',
46
+ alternates: {
47
+ canonical: SITE_URL,
48
+ },
49
+ openGraph: {
50
+ type: 'website',
51
+ url: SITE_URL,
52
+ siteName: SITE_NAME,
53
+ title: SITE_TITLE,
54
+ description: SITE_DESCRIPTION,
55
+ locale: 'en_US',
56
+ images: [
57
+ {
58
+ url: '/opengraph-image',
59
+ width: 1200,
60
+ height: 630,
61
+ alt:
62
+ 'designlang specimen card \u2014 a lowercase d mark with one extracted orange token, the wordmark designlang in Fraunces, and a five-swatch palette strip.',
63
+ type: 'image/png',
64
+ },
65
+ ],
66
+ },
67
+ twitter: {
68
+ card: 'summary_large_image',
69
+ title: SITE_TITLE,
70
+ description: SITE_DESCRIPTION,
71
+ images: ['/opengraph-image'],
72
+ creator: '@manavaryasingh',
73
+ site: '@manavaryasingh',
74
+ },
75
+ robots: {
76
+ index: true,
77
+ follow: true,
78
+ nocache: false,
79
+ googleBot: {
80
+ index: true,
81
+ follow: true,
82
+ 'max-image-preview': 'large',
83
+ 'max-snippet': -1,
84
+ 'max-video-preview': -1,
85
+ },
86
+ },
87
+ icons: {
88
+ icon: [
89
+ { url: '/icon.svg', type: 'image/svg+xml' },
90
+ { url: '/favicon.svg', type: 'image/svg+xml' },
91
+ ],
92
+ shortcut: '/icon.svg',
93
+ apple: '/icon.svg',
94
+ },
95
+ manifest: '/site.webmanifest',
96
+ formatDetection: {
97
+ email: false,
98
+ address: false,
99
+ telephone: false,
100
+ },
101
+ };
102
+
103
+ export const viewport = {
104
+ themeColor: '#F3F1EA',
105
+ width: 'device-width',
106
+ initialScale: 1,
107
+ colorScheme: 'light',
6
108
  };
7
109
 
8
110
  export default function RootLayout({ children }) {
9
111
  return (
10
- <html lang="en">
112
+ <html
113
+ lang="en"
114
+ className={`${fraunces.variable} ${instrumentSans.variable} ${mono.variable}`}
115
+ >
11
116
  <head>
12
117
  <link rel="preconnect" href="https://fonts.googleapis.com" />
13
- <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
14
- <link href="https://fonts.googleapis.com/css2?family=Unbounded:wght@400;700;900&family=JetBrains+Mono:wght@400;700&family=Inter:wght@400;500;600&display=swap" rel="stylesheet" />
118
+ <link rel="dns-prefetch" href="https://fonts.gstatic.com" />
119
+ <link rel="author" href="https://manavaryasingh.com" />
120
+ <link rel="me" href="https://github.com/Manavarya09" />
121
+ <StructuredData />
15
122
  </head>
16
123
  <body>{children}</body>
17
124
  </html>
@@ -0,0 +1,170 @@
1
+ import { ImageResponse } from 'next/og';
2
+
3
+ export const runtime = 'nodejs';
4
+ export const alt =
5
+ 'designlang specimen card. A lowercase d built from a ring, a stem, and one extracted orange token, next to the wordmark designlang in Fraunces with a molten-orange period, and a five-swatch palette strip.';
6
+ export const size = { width: 1200, height: 630 };
7
+ export const contentType = 'image/png';
8
+
9
+ const PAPER = '#F3F1EA';
10
+ const INK = '#0A0908';
11
+ const INK_2 = '#403C34';
12
+ const INK_3 = '#8B8778';
13
+ const ACCENT = '#FF4800';
14
+
15
+ export default async function OpengraphImage() {
16
+ return new ImageResponse(
17
+ (
18
+ <div
19
+ style={{
20
+ width: '100%',
21
+ height: '100%',
22
+ background: PAPER,
23
+ color: INK,
24
+ display: 'flex',
25
+ flexDirection: 'column',
26
+ justifyContent: 'space-between',
27
+ padding: 56,
28
+ fontFamily: 'Georgia, serif',
29
+ border: `2px solid ${INK}`,
30
+ }}
31
+ >
32
+ {/* top caption strip */}
33
+ <div
34
+ style={{
35
+ display: 'flex',
36
+ justifyContent: 'space-between',
37
+ fontFamily: 'ui-monospace, Menlo, monospace',
38
+ fontSize: 16,
39
+ color: INK_2,
40
+ letterSpacing: 2,
41
+ textTransform: 'uppercase',
42
+ }}
43
+ >
44
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
45
+ <span>SPECIMEN / 01</span>
46
+ <span>EXTRACTED 2026</span>
47
+ </div>
48
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 4, textAlign: 'right' }}>
49
+ <span>v7.0</span>
50
+ <span>W3C DTCG</span>
51
+ </div>
52
+ </div>
53
+
54
+ {/* wordmark row */}
55
+ <div style={{ display: 'flex', alignItems: 'center', gap: 48 }}>
56
+ {/* mark */}
57
+ <div
58
+ style={{
59
+ position: 'relative',
60
+ width: 150,
61
+ height: 180,
62
+ display: 'flex',
63
+ }}
64
+ >
65
+ {/* counter ring */}
66
+ <div
67
+ style={{
68
+ position: 'absolute',
69
+ left: 0,
70
+ bottom: 0,
71
+ width: 116,
72
+ height: 116,
73
+ border: `24px solid ${INK}`,
74
+ borderRadius: '50%',
75
+ }}
76
+ />
77
+ {/* stem */}
78
+ <div
79
+ style={{
80
+ position: 'absolute',
81
+ left: 92,
82
+ top: 0,
83
+ width: 26,
84
+ height: 180,
85
+ background: INK,
86
+ }}
87
+ />
88
+ {/* extracted token */}
89
+ <div
90
+ style={{
91
+ position: 'absolute',
92
+ left: 122,
93
+ top: 150,
94
+ width: 30,
95
+ height: 30,
96
+ background: ACCENT,
97
+ }}
98
+ />
99
+ </div>
100
+
101
+ {/* word + tagline */}
102
+ <div style={{ display: 'flex', flexDirection: 'column' }}>
103
+ <div
104
+ style={{
105
+ fontSize: 128,
106
+ lineHeight: 1,
107
+ letterSpacing: -4,
108
+ display: 'flex',
109
+ alignItems: 'baseline',
110
+ }}
111
+ >
112
+ <span style={{ color: INK }}>designlang</span>
113
+ <span style={{ color: ACCENT }}>.</span>
114
+ </div>
115
+ <div
116
+ style={{
117
+ marginTop: 14,
118
+ fontSize: 22,
119
+ fontStyle: 'italic',
120
+ color: INK_2,
121
+ fontFamily: 'Helvetica, Arial, sans-serif',
122
+ }}
123
+ >
124
+ reads a website the way a developer reads a stylesheet.
125
+ </div>
126
+ </div>
127
+ </div>
128
+
129
+ {/* bottom: palette + command */}
130
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end' }}>
131
+ <div style={{ display: 'flex', gap: 14 }}>
132
+ {[INK, INK_2, INK_3, '#D8D3C5', ACCENT].map((c) => (
133
+ <div key={c} style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
134
+ <div style={{ width: 56, height: 56, background: c }} />
135
+ <span
136
+ style={{
137
+ fontFamily: 'ui-monospace, Menlo, monospace',
138
+ fontSize: 12,
139
+ color: INK_2,
140
+ letterSpacing: 1,
141
+ }}
142
+ >
143
+ {c}
144
+ </span>
145
+ </div>
146
+ ))}
147
+ </div>
148
+ <div
149
+ style={{
150
+ display: 'flex',
151
+ flexDirection: 'column',
152
+ gap: 6,
153
+ textAlign: 'right',
154
+ fontFamily: 'ui-monospace, Menlo, monospace',
155
+ fontSize: 16,
156
+ letterSpacing: 1.2,
157
+ color: INK_2,
158
+ }}
159
+ >
160
+ <span>$ npx designlang &lt;url&gt;</span>
161
+ <span style={{ color: INK_3 }}>MIT · Node ≥ 20 · Playwright</span>
162
+ </div>
163
+ </div>
164
+ </div>
165
+ ),
166
+ {
167
+ ...size,
168
+ }
169
+ );
170
+ }