designlang 7.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 (64) hide show
  1. package/.vercel/README.txt +11 -0
  2. package/.vercel/project.json +1 -0
  3. package/CHANGELOG.md +15 -0
  4. package/CONTRIBUTING.md +25 -0
  5. package/README.md +9 -7
  6. package/bin/design-extract.js +18 -1
  7. package/chrome-extension/README.md +41 -0
  8. package/chrome-extension/icons/favicon.svg +7 -0
  9. package/chrome-extension/icons/icon-128.png +0 -0
  10. package/chrome-extension/icons/icon-16.png +0 -0
  11. package/chrome-extension/icons/icon-32.png +0 -0
  12. package/chrome-extension/icons/icon-48.png +0 -0
  13. package/chrome-extension/manifest.json +26 -0
  14. package/chrome-extension/popup.html +167 -0
  15. package/chrome-extension/popup.js +59 -0
  16. package/docs/superpowers/specs/2026-04-18-website-redesign-design.md +120 -0
  17. package/docs/superpowers/specs/2026-04-19-designlang-v7-1-design.md +111 -0
  18. package/package.json +1 -1
  19. package/src/config.js +3 -0
  20. package/src/crawler.js +20 -2
  21. package/src/utils-cookies.js +73 -0
  22. package/tests/cookies.test.js +98 -0
  23. package/website/app/api/extract/route.js +216 -56
  24. package/website/app/components/A11ySlider.js +369 -0
  25. package/website/app/components/Comparison.js +286 -0
  26. package/website/app/components/CssHealth.js +243 -0
  27. package/website/app/components/HeroExtractor.js +455 -0
  28. package/website/app/components/Marginalia.js +3 -0
  29. package/website/app/components/McpSection.js +223 -0
  30. package/website/app/components/PlatformTabs.js +250 -0
  31. package/website/app/components/RegionsComponents.js +429 -0
  32. package/website/app/components/Rule.js +13 -0
  33. package/website/app/components/Specimens.js +237 -0
  34. package/website/app/components/StructuredData.js +144 -0
  35. package/website/app/components/TokenBrowser.js +344 -0
  36. package/website/app/components/token-browser-sample.js +65 -0
  37. package/website/app/globals.css +415 -633
  38. package/website/app/icon.svg +7 -0
  39. package/website/app/layout.js +113 -6
  40. package/website/app/opengraph-image.js +170 -0
  41. package/website/app/page.js +325 -148
  42. package/website/app/robots.js +15 -0
  43. package/website/app/seo-config.js +82 -0
  44. package/website/app/sitemap.js +18 -0
  45. package/website/lib/cache.js +73 -0
  46. package/website/lib/rate-limit.js +30 -0
  47. package/website/lib/rate-limit.test.js +55 -0
  48. package/website/lib/specimens.json +86 -0
  49. package/website/lib/token-helpers.js +70 -0
  50. package/website/lib/url-safety.js +103 -0
  51. package/website/lib/url-safety.test.js +116 -0
  52. package/website/lib/zip-files.js +15 -0
  53. package/website/package-lock.json +85 -0
  54. package/website/package.json +1 -0
  55. package/website/public/favicon.svg +7 -0
  56. package/website/public/logo-specimen.svg +76 -0
  57. package/website/public/mark.svg +12 -0
  58. package/website/public/site.webmanifest +13 -0
  59. package/website/app/favicon.ico +0 -0
  60. package/website/public/file.svg +0 -1
  61. package/website/public/globe.svg +0 -1
  62. package/website/public/next.svg +0 -1
  63. package/website/public/vercel.svg +0 -1
  64. package/website/public/window.svg +0 -1
@@ -0,0 +1,11 @@
1
+ > Why do I have a folder named ".vercel" in my project?
2
+ The ".vercel" folder is created when you link a directory to a Vercel project.
3
+
4
+ > What does the "project.json" file contain?
5
+ The "project.json" file contains:
6
+ - The ID of the Vercel project that you linked ("projectId")
7
+ - The ID of the user or team your Vercel project is owned by ("orgId")
8
+
9
+ > Should I commit the ".vercel" folder?
10
+ No, you should not share the ".vercel" folder with anyone.
11
+ Upon creation, it will be automatically added to your ".gitignore" file.
@@ -0,0 +1 @@
1
+ {"projectId":"prj_g6gBbA5TU1e3vLtU6w8FHJhy9Wmk","orgId":"team_NOd0BEOy4vNKC9vTwIRo0qdF","projectName":"website"}
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [7.1.0] — 2026-04-19
4
+
5
+ ### Added
6
+
7
+ - **Cookie file support** — `--cookie-file <path>` loads cookies from a JSON array, a Playwright `storageState.json`, or a Netscape `cookies.txt` (browser extensions, curl exports). The new loader lives in `src/utils-cookies.js` and merges cleanly with the existing `--cookie name=value` flag.
8
+ - **`--insecure`** — ignores HTTPS/SSL certificate errors. Useful for self-signed dev servers, internal staging environments behind corporate proxies, and local extraction through MITM tools. Passes `ignoreHTTPSErrors: true` to the Playwright context plus the matching Chromium launch flags.
9
+ - **`--user-agent <ua>`** — override the browser User-Agent string for extraction.
10
+ - **Chrome extension** — `chrome-extension/` ships a Manifest v3 popup that hands the current tab off to [designlang.manavaryasingh.com](https://designlang.manavaryasingh.com) with the URL prefilled. Also emits a "Copy CLI" button that drops `npx designlang <url>` into the clipboard. Developer-mode install for now; Chrome Web Store listing pending.
11
+ - **Website URL query parameter** — the extractor input on the hosted site now honours `?url=<encoded>` so the Chrome extension (and any deep link) can prefill.
12
+ - **CONTRIBUTING**: "Good first issues" and "Credits" sections.
13
+
14
+ ### Thanks
15
+
16
+ - A developer from China opened a conversation proposing cookie-file handling, SSL bypass, and a Chrome packaging story — this release ships all three.
17
+
3
18
  ## [7.0.0] — 2026-04-18
4
19
 
5
20
  ### Breaking
package/CONTRIBUTING.md CHANGED
@@ -61,3 +61,28 @@ When filing a bug, please include:
61
61
  - One feature/fix per PR
62
62
  - Keep PRs focused and small when possible
63
63
  - Add a brief description of what changed and why
64
+
65
+ ## Good first issues
66
+
67
+ Some work that's already scoped and ready for someone to pick up:
68
+
69
+ - **Extra cookie formats** — add support for browser-specific exports (EditThisCookie, Cookie-Editor) on top of the existing JSON / Playwright / Netscape loaders in `src/utils-cookies.js`.
70
+ - **Proxy support** — add `--proxy <url>` that passes through to Playwright's `proxy` launch option, paired with the existing `--insecure` flag for corporate networks.
71
+ - **Chrome extension: DevTools panel** — extend `chrome-extension/` with a DevTools panel that shows tokens for the current tab without leaving the browser. See the roadmap in `chrome-extension/README.md`.
72
+ - **Firefox + Edge packaging** — the manifest v3 extension already works in both; we just need store listings and icons.
73
+ - **Additional CSS-in-JS emitters** — Emotion, Stitches, Vanilla Extract, Panda, styled-components. Each is a thin formatter module under `src/formatters/`.
74
+
75
+ ## Credits
76
+
77
+ Shipped thanks to a few specific contributors — PRs welcome for the list:
78
+
79
+ - [@Manavarya09](https://github.com/Manavarya09) — author, maintainer.
80
+ - Community suggestions that landed as features: cookie-file loading, `--insecure` SSL bypass, and the first Chrome extension popup came from an external developer's proposal in mid-April 2026.
81
+
82
+ If you open a PR or file an issue that materially shapes a release, we'll add you here.
83
+
84
+ ## Code of conduct
85
+
86
+ Be decent. Disagreements about design, code, or approach are welcome — personal
87
+ attacks are not. Maintainer reserves the right to close issues and PRs that
88
+ don't engage in good faith.
package/README.md CHANGED
@@ -1,13 +1,12 @@
1
1
  <p align="center">
2
- <h1 align="center">DESIGNLANG</h1>
3
- <p align="center">Reverse-engineer any website's complete design system in one command.</p>
2
+ <img src="website/public/logo-specimen.svg" alt="designlang — reads a website the way a developer reads a stylesheet" width="900">
4
3
  </p>
5
4
 
6
5
  <p align="center">
7
- <a href="https://www.npmjs.com/package/designlang"><img src="https://img.shields.io/npm/v/designlang?color=blue&label=npm" alt="npm version"></a>
8
- <a href="https://github.com/Manavarya09/design-extract/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Manavarya09/design-extract" alt="license"></a>
9
- <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/designlang" alt="node version"></a>
10
- <a href="https://website-five-lime-65.vercel.app"><img src="https://img.shields.io/badge/website-live-red" alt="website"></a>
6
+ <a href="https://www.npmjs.com/package/designlang"><img src="https://img.shields.io/npm/v/designlang?color=0A0908&labelColor=F3F1EA&label=npm" alt="npm version"></a>
7
+ <a href="https://github.com/Manavarya09/design-extract/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Manavarya09/design-extract?color=0A0908&labelColor=F3F1EA" alt="license"></a>
8
+ <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/designlang?color=0A0908&labelColor=F3F1EA" alt="node version"></a>
9
+ <a href="https://designlang.manavaryasingh.com/"><img src="https://img.shields.io/badge/website-live-FF4800?labelColor=F3F1EA" alt="website"></a>
11
10
  </p>
12
11
 
13
12
  ---
@@ -368,7 +367,10 @@ Options:
368
367
  --interactions Capture hover/focus/active states
369
368
  --full Enable all captures
370
369
  --cookie <cookies...> Cookies for authenticated pages (name=value)
370
+ --cookie-file <path> Load cookies from JSON / storageState / Netscape cookies.txt
371
371
  --header <headers...> Custom headers (name:value)
372
+ --user-agent <ua> Override the browser User-Agent string
373
+ --insecure Ignore HTTPS/SSL certificate errors (self-signed, dev, proxies)
372
374
  --framework <type> Only generate specific theme (react, shadcn)
373
375
  --platforms <csv> Additional platforms: web,ios,android,flutter,wordpress,all (additive)
374
376
  --emit-agent-rules Emit Cursor / Claude Code / CLAUDE.md / agents.md rule files
@@ -453,7 +455,7 @@ In Claude Code, use `/extract-design <url>`.
453
455
 
454
456
  ## Website
455
457
 
456
- **[website-five-lime-65.vercel.app](https://website-five-lime-65.vercel.app)** — the brutalist product page.
458
+ **[design-extract-beta.vercel.app](https://design-extract-beta.vercel.app)** — the brutalist product page.
457
459
 
458
460
  ## Contributing
459
461
 
@@ -65,7 +65,10 @@ program
65
65
  .option('--interactions', 'capture hover/focus/active states')
66
66
  .option('--full', 'enable all extra captures (screenshots, responsive, interactions)')
67
67
  .option('--cookie <cookies...>', 'cookies for authenticated pages (name=value)')
68
+ .option('--cookie-file <path>', 'load cookies from JSON, Playwright storageState, or Netscape cookies.txt')
68
69
  .option('--header <headers...>', 'custom headers (name:value)')
70
+ .option('--user-agent <ua>', 'override the browser User-Agent string')
71
+ .option('--insecure', 'ignore HTTPS/SSL certificate errors (self-signed, dev, proxies)')
69
72
  .option('--ignore <selectors...>', 'CSS selectors to remove before extraction')
70
73
  .option('--tokens-legacy', 'Emit pre-v7 flat token JSON (backward compat)')
71
74
  .option('--platforms <csv>', 'Additional platforms: web,ios,android,flutter,wordpress,all (web is always emitted)', 'web')
@@ -115,7 +118,19 @@ program
115
118
  try {
116
119
  spinner.text = `Crawling${merged.depth > 0 ? ` (depth: ${merged.depth})` : ''}...`;
117
120
  // Parse auth options
118
- const cookies = merged.cookie || [];
121
+ const cliCookies = merged.cookie || [];
122
+ const fileCookies = [];
123
+ if (merged.cookieFile) {
124
+ try {
125
+ const { loadCookiesFromFile } = await import('../src/utils-cookies.js');
126
+ fileCookies.push(...loadCookiesFromFile(resolve(merged.cookieFile), url));
127
+ } catch (e) {
128
+ console.error(chalk.red(`\n cookie-file load failed: ${e.message}\n`));
129
+ process.exit(1);
130
+ }
131
+ }
132
+ const { mergeCookies } = await import('../src/utils-cookies.js');
133
+ const cookies = mergeCookies(cliCookies, fileCookies, url);
119
134
  const headers = {};
120
135
  if (merged.header) {
121
136
  for (const h of merged.header) {
@@ -135,6 +150,8 @@ program
135
150
  ignore: merged.ignore,
136
151
  cookies: cookies.length > 0 ? cookies : undefined,
137
152
  headers: Object.keys(headers).length > 0 ? headers : undefined,
153
+ insecure: merged.insecure || false,
154
+ userAgent: merged.userAgent,
138
155
  });
139
156
 
140
157
  // Responsive capture
@@ -0,0 +1,41 @@
1
+ # designlang — Chrome extension
2
+
3
+ Right-click → Extract design on any page. The extension opens
4
+ [designlang.manavaryasingh.com](https://designlang.manavaryasingh.com) with the
5
+ current tab's URL prefilled, so extraction starts with one click instead of
6
+ switching windows and pasting.
7
+
8
+ ## Features
9
+
10
+ - One-click handoff from any `http(s)://` page to the hosted extractor
11
+ - "Copy CLI" button — drops `npx designlang <url>` straight into your clipboard
12
+ - Zero tracking, zero analytics, zero permissions beyond `activeTab`
13
+
14
+ ## Install (developer mode, pending Chrome Web Store publish)
15
+
16
+ 1. Clone this repo.
17
+ 2. Open `chrome://extensions` in Chromium / Chrome / Edge / Arc / Brave.
18
+ 3. Toggle **Developer mode** (top right).
19
+ 4. Click **Load unpacked** and pick the `chrome-extension/` folder in this repo.
20
+ 5. Pin the extension from the puzzle-piece menu.
21
+
22
+ ## Permissions
23
+
24
+ - `activeTab` — to read the URL of the tab you triggered the popup on.
25
+ - `host_permissions` scoped to `https://designlang.manavaryasingh.com/*` for the
26
+ handoff.
27
+
28
+ No content scripts, no remote code, no background service worker. The whole
29
+ extension is ~3 KB of static HTML/JS/CSS.
30
+
31
+ ## Roadmap
32
+
33
+ - Chrome Web Store listing.
34
+ - Optional right-click context menu on links: *"Extract design from this link"*.
35
+ - DevTools panel that shows the extracted tokens for the current tab alongside
36
+ the real DOM selector that produced them.
37
+ - Firefox + Edge listings (the same MV3 manifest works for both).
38
+
39
+ ## Contributing
40
+
41
+ PRs welcome. See the root [`CONTRIBUTING.md`](../CONTRIBUTING.md).
@@ -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>
@@ -0,0 +1,26 @@
1
+ {
2
+ "manifest_version": 3,
3
+ "name": "designlang",
4
+ "version": "1.0.0",
5
+ "description": "Extract any website's complete design system — DTCG tokens, Tailwind, Figma variables, MCP server context, iOS/Android/Flutter/WordPress emitters.",
6
+ "author": "Manav Arya Singh",
7
+ "homepage_url": "https://designlang.manavaryasingh.com",
8
+ "action": {
9
+ "default_title": "Extract design system with designlang",
10
+ "default_popup": "popup.html",
11
+ "default_icon": {
12
+ "16": "icons/icon-16.png",
13
+ "32": "icons/icon-32.png",
14
+ "48": "icons/icon-48.png",
15
+ "128": "icons/icon-128.png"
16
+ }
17
+ },
18
+ "icons": {
19
+ "16": "icons/icon-16.png",
20
+ "32": "icons/icon-32.png",
21
+ "48": "icons/icon-48.png",
22
+ "128": "icons/icon-128.png"
23
+ },
24
+ "permissions": ["activeTab"],
25
+ "host_permissions": ["https://designlang.manavaryasingh.com/*"]
26
+ }
@@ -0,0 +1,167 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=360" />
6
+ <title>designlang</title>
7
+ <link rel="icon" href="icons/favicon.svg" type="image/svg+xml" />
8
+ <style>
9
+ :root {
10
+ --paper: #f3f1ea;
11
+ --ink: #0a0908;
12
+ --ink-2: #403c34;
13
+ --ink-3: #8b8778;
14
+ --accent: #ff4800;
15
+ }
16
+ *, *::before, *::after { box-sizing: border-box; }
17
+ html, body { margin: 0; padding: 0; }
18
+ body {
19
+ width: 360px;
20
+ background: var(--paper);
21
+ color: var(--ink);
22
+ font-family: -apple-system, 'Segoe UI', system-ui, sans-serif;
23
+ font-size: 14px;
24
+ line-height: 1.4;
25
+ }
26
+ .pad { padding: 18px 18px 20px; }
27
+ .bar {
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: space-between;
31
+ padding: 12px 18px 10px;
32
+ border-bottom: 1px solid var(--ink);
33
+ }
34
+ .mono {
35
+ font-family: ui-monospace, 'SF Mono', Menlo, monospace;
36
+ font-size: 11px;
37
+ letter-spacing: 0.12em;
38
+ text-transform: uppercase;
39
+ color: var(--ink-2);
40
+ }
41
+ .mark {
42
+ display: inline-flex;
43
+ align-items: center;
44
+ gap: 8px;
45
+ font-family: ui-monospace, Menlo, monospace;
46
+ font-weight: 600;
47
+ }
48
+ .mark svg { width: 16px; height: 16px; }
49
+ h1 {
50
+ margin: 16px 0 10px;
51
+ font-family: 'Iowan Old Style', Georgia, serif;
52
+ font-size: 22px;
53
+ font-weight: 400;
54
+ line-height: 1.1;
55
+ letter-spacing: -0.02em;
56
+ }
57
+ h1 em { color: var(--accent); font-style: italic; }
58
+ p { margin: 0 0 14px; color: var(--ink-2); }
59
+ .url {
60
+ display: block;
61
+ background: #fff;
62
+ border: 1px solid var(--ink);
63
+ padding: 10px 12px;
64
+ font: 12px ui-monospace, Menlo, monospace;
65
+ color: var(--ink);
66
+ word-break: break-all;
67
+ white-space: pre-wrap;
68
+ margin-bottom: 12px;
69
+ }
70
+ button, a.button {
71
+ display: inline-flex;
72
+ align-items: center;
73
+ justify-content: space-between;
74
+ gap: 10px;
75
+ width: 100%;
76
+ padding: 12px 14px;
77
+ font: 13px ui-monospace, Menlo, monospace;
78
+ letter-spacing: 0.03em;
79
+ background: var(--ink);
80
+ color: var(--paper);
81
+ border: 1px solid var(--ink);
82
+ box-shadow: 4px 4px 0 var(--accent);
83
+ cursor: pointer;
84
+ text-decoration: none;
85
+ transition: transform 120ms, box-shadow 120ms;
86
+ }
87
+ button:hover, a.button:hover {
88
+ transform: translate(-1px, -1px);
89
+ box-shadow: 5px 5px 0 var(--accent);
90
+ }
91
+ button:active, a.button:active {
92
+ transform: translate(3px, 3px);
93
+ box-shadow: 1px 1px 0 var(--accent);
94
+ }
95
+ .row {
96
+ display: grid;
97
+ grid-template-columns: 1fr 1fr;
98
+ gap: 8px;
99
+ margin-top: 10px;
100
+ }
101
+ .secondary {
102
+ display: inline-flex;
103
+ justify-content: center;
104
+ padding: 9px 10px;
105
+ border: 1px solid var(--ink);
106
+ background: transparent;
107
+ color: var(--ink);
108
+ font: 11px ui-monospace, Menlo, monospace;
109
+ letter-spacing: 0.06em;
110
+ text-transform: uppercase;
111
+ text-decoration: none;
112
+ box-shadow: none;
113
+ }
114
+ .secondary:hover {
115
+ background: var(--ink);
116
+ color: var(--paper);
117
+ transform: none;
118
+ box-shadow: none;
119
+ }
120
+ .hint {
121
+ margin-top: 12px;
122
+ font: 11px ui-monospace, Menlo, monospace;
123
+ color: var(--ink-3);
124
+ line-height: 1.5;
125
+ }
126
+ .hint code { color: var(--ink); }
127
+ </style>
128
+ </head>
129
+ <body>
130
+ <div class="bar">
131
+ <span class="mark">
132
+ <svg viewBox="0 0 32 32" aria-hidden="true">
133
+ <rect width="32" height="32" fill="#F3F1EA"/>
134
+ <circle cx="13" cy="20" r="7.5" fill="none" stroke="#0A0908" stroke-width="4.5"/>
135
+ <rect x="19" y="4" width="4.5" height="25" fill="#0A0908"/>
136
+ <rect x="25" y="25" width="4" height="4" fill="#FF4800"/>
137
+ </svg>
138
+ designlang
139
+ </span>
140
+ <span class="mono">v7.0</span>
141
+ </div>
142
+
143
+ <div class="pad">
144
+ <h1>Read this page as a <em>design system</em>.</h1>
145
+ <p>Extracts DTCG tokens, Tailwind config, Figma variables, an MCP companion, and native iOS / Android / Flutter / WordPress outputs.</p>
146
+
147
+ <span class="url" id="url-display">—</span>
148
+
149
+ <button id="extract-btn">
150
+ Extract on designlang
151
+ <span>↗</span>
152
+ </button>
153
+
154
+ <div class="row">
155
+ <a class="secondary" id="copy-cli" href="#">Copy CLI</a>
156
+ <a class="secondary" href="https://github.com/Manavarya09/design-extract" target="_blank" rel="noopener">GitHub</a>
157
+ </div>
158
+
159
+ <div class="hint">
160
+ Prefer the CLI? <code>npx designlang &lt;url&gt;</code>. MCP server:
161
+ <code>designlang mcp</code>.
162
+ </div>
163
+ </div>
164
+
165
+ <script src="popup.js"></script>
166
+ </body>
167
+ </html>
@@ -0,0 +1,59 @@
1
+ // designlang Chrome extension popup script.
2
+ // On open, reads the active tab's URL, shows it, and wires the Extract button
3
+ // to hand off to designlang.manavaryasingh.com with the URL prefilled.
4
+
5
+ const SITE = 'https://designlang.manavaryasingh.com/';
6
+
7
+ function isExtractable(url) {
8
+ if (!url) return false;
9
+ try {
10
+ const u = new URL(url);
11
+ return u.protocol === 'http:' || u.protocol === 'https:';
12
+ } catch {
13
+ return false;
14
+ }
15
+ }
16
+
17
+ async function getActiveTabUrl() {
18
+ const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
19
+ return tabs[0]?.url || '';
20
+ }
21
+
22
+ function render(tabUrl) {
23
+ const display = document.getElementById('url-display');
24
+ const btn = document.getElementById('extract-btn');
25
+ const copy = document.getElementById('copy-cli');
26
+
27
+ if (!isExtractable(tabUrl)) {
28
+ display.textContent = '(open a regular https:// page to extract)';
29
+ btn.disabled = true;
30
+ btn.style.opacity = '0.55';
31
+ btn.style.cursor = 'not-allowed';
32
+ copy.setAttribute('aria-disabled', 'true');
33
+ copy.style.pointerEvents = 'none';
34
+ copy.style.opacity = '0.55';
35
+ return;
36
+ }
37
+
38
+ display.textContent = tabUrl;
39
+
40
+ btn.addEventListener('click', () => {
41
+ const target = `${SITE}?url=${encodeURIComponent(tabUrl)}&source=chrome`;
42
+ chrome.tabs.create({ url: target });
43
+ window.close();
44
+ });
45
+
46
+ copy.addEventListener('click', async (e) => {
47
+ e.preventDefault();
48
+ const line = `npx designlang ${tabUrl}`;
49
+ try {
50
+ await navigator.clipboard.writeText(line);
51
+ copy.textContent = 'Copied';
52
+ setTimeout(() => { copy.textContent = 'Copy CLI'; }, 1200);
53
+ } catch {
54
+ copy.textContent = 'Clipboard denied';
55
+ }
56
+ });
57
+ }
58
+
59
+ getActiveTabUrl().then(render);
@@ -0,0 +1,120 @@
1
+ # designlang website redesign — Wave 2
2
+
3
+ **Date:** 2026-04-18
4
+ **Status:** Approved for implementation
5
+ **Direction:** Live Design DNA — the site embodies what designlang does.
6
+
7
+ ## Non-negotiables (from user)
8
+
9
+ - No "AI slop" aesthetic. No purple/blue gradients. No glassmorphism. No floating hero cards.
10
+ - **No emoji. No icon libraries** (Lucide, Heroicons, Phosphor). Iconography only as intent-drawn inline SVG, numerals, or letterforms.
11
+ - No Framer Motion bloat, no fade-up-on-every-element scroll theatrics.
12
+ - Copy must be earned, not templated.
13
+ - Designer voice visible — marginalia, footnotes, document-feel.
14
+
15
+ ## Visual system
16
+
17
+ **Base:** warm paper `#F3F1EA`, ink `#0A0908`, accent `#FF4800` (used once per screen, maximum).
18
+ **Grays (warm):** `#D8D3C5`, `#8B8778`, `#403C34`.
19
+ **Type:** Fraunces (display, optical 9pt, massive sizes), Instrument Sans (body), JetBrains Mono (mono/tokens).
20
+ **Grid:** 12-col, 24px gutters, deliberately broken by marginalia and side notes.
21
+ **Rules:** 1px solid ink hairlines everywhere (document feel), no soft dividers.
22
+ **Shadow:** one hard offset shadow (`6px 6px 0 #FF4800`) on the primary CTA only.
23
+ **Dark mode:** deferred. Paper-first matches design-system/archival feel.
24
+ **Motion:** prefers-reduced-motion strict. All motion is content-matched (see §Signature Interactions).
25
+
26
+ ## Page structure
27
+
28
+ Single-page scroll. Numbered sections like a monograph: `§00`…`§09`.
29
+
30
+ - §00 `HERO` — URL input + live extraction stream; tokens paint on screen as they compute.
31
+ - §01 `DTCG BROWSER` — interactive alias resolver. Click a semantic token, the line flies to its primitive.
32
+ - §02 `MCP` — split: Cursor/Claude Code rule panel on left, real terminal transcript on right.
33
+ - §03 `MULTI-PLATFORM` — tabs Web / iOS / Android / Flutter / WordPress; same token in 5 languages.
34
+ - §04 `CSS HEALTH` — big numerals (unused %, `!important` count, duplicates) set against real specificity plot.
35
+ - §05 `A11Y REMEDIATION` — before/after contrast slider with live ratio.
36
+ - §06 `REGIONS + COMPONENTS` — annotated screenshot; button cluster animates into variants.
37
+ - §07 `FEATURED SPECIMENS` — stripe / vercel / linear / github / figma / apple; each extracted and displayed like a museum specimen. Page accent shifts as you scroll between them.
38
+ - §08 `COMPARISON` — transparent, opinionated table vs. v0, Builder.io, Style Dictionary, Subframe, Project Wallace.
39
+ - §09 `INSTALL & FOOTER` — `npx designlang`, MCP config, Cursor rule install, GitHub/npm/Discussions/sponsor.
40
+
41
+ ## Signature interactions (motion only where content-matched)
42
+
43
+ 1. **Hero stream** — user submits URL, server streams back tokens in extraction order; swatches paint from left to right as server events arrive.
44
+ 2. **DTCG alias flight** — click `{primitive.color.brand.primary}` string, an SVG line animates from the semantic token to the primitive, primitive highlights, hex resolves inline.
45
+ 3. **Accent shift scroll** — as the Featured Specimens section scrolls, page accent CSS var transitions to each specimen's extracted primary.
46
+ 4. **A11y slider** — handle drag shows contrast ratio updating live above the color pair.
47
+ 5. **MCP terminal transcript** — real JSON-RPC lines, typed at realistic speed, showing `search_tokens` → result.
48
+ 6. **Component cluster unfold** — a single button card unfolds into its detected variants on scroll-into-view.
49
+
50
+ No other motion.
51
+
52
+ ## Backend
53
+
54
+ **Existing:** `/api/extract` route using `@sparticuz/chromium` + `playwright-core` + designlang `extractDesignLanguage`.
55
+
56
+ **Changes required:**
57
+
58
+ 1. **v7.0 output parity** — currently the API returns v6 shape. Add DTCG tokens, agent rules, MCP companion JSON, multi-platform outputs.
59
+ 2. **Streaming response** — the extraction produces tokens progressively; stream them over an HTTP stream (Next.js 16 streaming response) so the hero demo paints live. If extraction is atomic today (single `page.evaluate`), we stream the *stages*: crawl → colors → typography → spacing → components → a11y → done.
60
+ 3. **Rate limiting** — Vercel Edge Config or in-memory map keyed by IP. 3 extractions per IP per day for anonymous, soft 429 with helpful copy. No login.
61
+ 4. **URL validation** — reject `localhost`, `127.x`, `169.254.x`, `10.x`, `172.16–31.x`, `192.168.x`, `file://`, non-http(s). Reject URLs whose DNS resolves to private ranges.
62
+ 5. **Timeout cap** — hard 45s; abort Playwright if exceeded.
63
+ 6. **Caching** — cache extraction result by URL in Vercel Blob for 24h. Collision: same URL within 24h returns cached zip + a small "cached" annotation.
64
+ 7. **Bot detection** — Vercel BotID (free, platform-native).
65
+ 8. **Output:** downloadable `.zip` of all generated files (same set the CLI would produce for `--platforms all --emit-agent-rules`) plus a JSON summary for the on-screen preview.
66
+
67
+ **New/changed files:**
68
+ - `website/app/api/extract/route.js` — streaming + rate limit + caching + v7.0 outputs
69
+ - `website/lib/rate-limit.js` (new)
70
+ - `website/lib/url-safety.js` (new)
71
+ - `website/lib/cache.js` (new, Vercel Blob-backed)
72
+
73
+ ## Frontend components (new)
74
+
75
+ Kept flat in `website/app/components/`. Each is a self-contained section:
76
+
77
+ - `Hero.js` — URL input + live stream renderer
78
+ - `TokenBrowser.js` — DTCG alias resolver
79
+ - `McpSection.js` — split editor + terminal
80
+ - `PlatformTabs.js` — multi-platform code viewer
81
+ - `CssHealth.js` — numerals + specificity plot (hand-drawn SVG scatter)
82
+ - `A11ySlider.js` — contrast before/after
83
+ - `RegionsComponents.js` — annotated image + cluster unfold
84
+ - `Specimens.js` — featured site grid; orchestrates accent shift
85
+ - `Comparison.js` — opinionated feature matrix
86
+ - `InstallFooter.js` — closing section
87
+ - `Marginalia.js` — shared side-column component for footnotes and command labels
88
+ - `Rule.js` — 1px hairline divider with section label
89
+
90
+ New lib:
91
+ - `website/lib/token-helpers.js` — DTCG alias resolution shared with components
92
+ - `website/lib/specimens.json` — pre-extracted data for the featured section (generated at build time from the CLI so specimens are real)
93
+
94
+ ## Deferred (explicit non-goals for Wave 2)
95
+
96
+ - Login / user accounts / saved extractions
97
+ - Paid tiers
98
+ - Dark mode
99
+ - Blog / changelog page
100
+ - i18n
101
+ - Sharable `/x/<slug>` permalinks (nice-to-have but not Wave 2)
102
+
103
+ ## Test / verification plan
104
+
105
+ - Lighthouse: LCP ≤ 2.0s on the hero at 3G-Fast, CLS 0, accessibility ≥ 95.
106
+ - `prefers-reduced-motion: reduce` — verify all motion stops or substitutes with non-motion reveal.
107
+ - Keyboard navigation through every interactive element.
108
+ - Extractor end-to-end: submit real URL, receive streamed tokens, download zip, verify zip contains v7.0 shape.
109
+ - Rate limit: 4th request from same IP returns 429 with copy.
110
+ - URL safety: localhost, private IPs, `file://` all rejected with 400.
111
+
112
+ ## Implementation chunks (PR per chunk)
113
+
114
+ Each chunk is one PR. Merge before starting the next, same pattern as v7.0 release.
115
+
116
+ - **PR A: Foundation** — fonts, base CSS, grid primitives, `Rule`, `Marginalia`, new `globals.css`, `layout.js`, clean `page.js` scaffold.
117
+ - **PR B: Hero + streaming extraction API** — hero component, API streaming, URL safety, rate limit, basic Blob cache.
118
+ - **PR C: Core showcase sections** — DTCG browser, MCP section, multi-platform tabs.
119
+ - **PR D: Analytics sections** — CSS health, a11y slider, regions + components.
120
+ - **PR E: Specimens + comparison + install + footer + deploy** — pre-extract data at build time, accent-shift scroll, comparison table, final polish, Vercel deploy.