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.
- package/.vercel/README.txt +11 -0
- package/.vercel/project.json +1 -0
- package/CHANGELOG.md +15 -0
- package/CONTRIBUTING.md +25 -0
- package/README.md +9 -7
- package/bin/design-extract.js +18 -1
- 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/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 +1 -1
- package/src/config.js +3 -0
- package/src/crawler.js +20 -2
- package/src/utils-cookies.js +73 -0
- package/tests/cookies.test.js +98 -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,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
|
-
<
|
|
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=
|
|
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://
|
|
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
|
-
**[
|
|
458
|
+
**[design-extract-beta.vercel.app](https://design-extract-beta.vercel.app)** — the brutalist product page.
|
|
457
459
|
|
|
458
460
|
## Contributing
|
|
459
461
|
|
package/bin/design-extract.js
CHANGED
|
@@ -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
|
|
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>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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 <url></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.
|