Skip to content

v12.4: designlang pack — one polished design-system bundle#71

Merged
Manavarya09 merged 1 commit intomainfrom
feat/v12.4-pack
May 5, 2026
Merged

v12.4: designlang pack — one polished design-system bundle#71
Manavarya09 merged 1 commit intomainfrom
feat/v12.4-pack

Conversation

@Manavarya09
Copy link
Copy Markdown
Owner

Summary

Closes #59.

`designlang pack ` runs the full extraction once and writes every emitter output into a single, signed, layered directory. One artifact a designer or dev can clone, drop into a project, or zip up and send to a client.

```bash
npx designlang pack stripe.com

→ ./stripe-com-design-system/ (40 files, 232KB)

```

Layout

```
-design-system/
├── README.md bespoke, references source + grade + at-a-glance
├── LICENSE.txt provenance + usage guidance
├── tokens/ DTCG + Tailwind + CSS vars + Figma vars + motion + theme.js
├── components/ typed React stubs (anatomy.tsx)
├── storybook/ runnable Storybook project
├── starter/ minimal HTML starter wired to tokens/variables.css
├── prompts/ v0 / Lovable / Cursor / Claude Artifacts + named recipes/*.md
└── extras/ voice.json + prompt-pack.md rollup
```

What's in the change

  • New module `src/pack.js` exporting `buildPack(design, opts)`
  • New CLI command `pack [-o ] [--with-clone] [--open]`
  • `toText()` normaliser handles the inconsistent return shapes across formatters (some return objects, some return JSON strings already) — fixes a double-stringify bug for figma/motion/flat-tokens that emerged in first integration
  • Recipes now write as `.md` files, not array indices
  • 7 new tests covering directory shape, valid JSON outputs, README content, starter wiring, recipe filenames, and the double-stringify regression

Test plan

  • `npm test` — 357/357 passing (7 new)
  • Live: `node bin/design-extract.js pack stripe.com` → 40 files, 232KB, all token JSON parses with `json.load`
  • All top-level dirs present: README, LICENSE, tokens/, components/, storybook/, starter/, prompts/, extras/
  • Storybook `package.json` valid; `tailwind.config.js` syntactically correct
  • Recipes named (`button.md`, `card.md`) — no longer raw indices
  • Module syntax checks pass

Why this exists

The 17+ loose files designlang already emits are the right pieces, but asking a user to zip them themselves is friction. `pack` is the same artifacts as one polished, downloadable, cite-able bundle. Closes the gap between "extract" and "I can hand this to a teammate."

🤖 Generated with Claude Code

Closes #59.

`designlang pack <url>` runs the full extraction once and writes every
emitter output into a single, signed, layered directory. One artifact a
designer or dev can clone, drop into a project, or zip up and send to a
client.

Layout:

  <host>-design-system/
  ├── README.md           bespoke, references source + grade + at-a-glance
  ├── LICENSE.txt         provenance + usage guidance
  ├── tokens/             DTCG + Tailwind + CSS vars + Figma vars + motion + theme.js
  ├── components/         typed React stubs (anatomy.tsx)
  ├── storybook/          runnable Storybook project
  ├── starter/            minimal HTML starter wired to tokens/variables.css
  ├── prompts/            v0 / Lovable / Cursor / Claude Artifacts + named recipes/*.md
  └── extras/             voice.json + prompt-pack.md rollup

Pure composition — zero new deps, zero new analysis. Reuses formatDtcg,
formatTokens, formatTailwind, formatCssVars, formatFigma, formatMotionTokens,
formatReactTheme, formatAnatomyStubs, formatStorybook, buildPromptPack,
generateClone (opt-in via --with-clone).

Internals:
- `toText()` normaliser handles the inconsistent return shapes across
  formatters (some return objects, some return JSON strings already).
- Recipes now write as `<name>.md` files, not array indices.
- 7 new tests cover directory shape, valid JSON token outputs, README
  content, starter wiring, recipe filenames, and a regression test for
  the double-stringify bug.

357/357 tests pass.

Verified live on stripe.com: 40 files, 232KB, all token JSON parses
cleanly.
Copilot AI review requested due to automatic review settings May 5, 2026 20:00
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
website Ready Ready Preview, Comment May 5, 2026 8:00pm

@Manavarya09 Manavarya09 merged commit 5fb8493 into main May 5, 2026
3 of 4 checks passed
@Manavarya09 Manavarya09 deleted the feat/v12.4-pack branch May 5, 2026 20:00
Comment thread src/pack.js
try { return new URL(url).hostname; } catch { return String(url || ''); }
}

function exists(p) {
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new “pack” workflow to produce a single on-disk design-system bundle (tokens + components + Storybook + starter + prompts) from one extraction, and wires it into the CLI and docs for the v12.4.0 release.

Changes:

  • Introduces src/pack.js with buildPack(design, opts) to write a standardized pack directory structure.
  • Adds designlang pack <url> CLI command to run extraction then build the pack (with optional --with-clone and --open).
  • Updates docs/changelog/version and adds tests covering pack output shape and key file contents.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tests/formatters.test.js Adds test coverage for buildPack() output layout, token JSON validity, README/starter content, and regression behavior.
src/pack.js New pack builder that writes README/LICENSE, tokens, components, storybook project, starter, prompts, and extras.
README.md Documents the new pack command in quick-start + command list.
package.json Bumps package version to 12.4.0.
CHANGELOG.md Adds 12.4.0 release notes describing the new pack feature.
bin/design-extract.js Adds pack subcommand implementation and output messaging (including --open).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/pack.js
* @param {boolean} [opts.withClone=true] — include the Next.js starter
* @returns {object} { dir, files: string[] }
*/
export function buildPack(design, opts = {}) {
Comment thread src/pack.js
Comment on lines +322 to +333
// starter/ — minimal HTML by default; full Next.js when --with-clone
const starterDir = join(outDir, 'starter');
if (opts.withClone) {
try {
generateClone(design, starterDir);
written.push(starterDir);
} catch (err) {
// Clone is best-effort — fall back to HTML starter if it errors.
mkdirSync(starterDir, { recursive: true });
writeFile(join(starterDir, 'index.html'), buildStarter(design));
written.push(join(starterDir, 'index.html'));
}
Comment thread src/pack.js
Comment on lines +185 to +227
const hostName = host(design.meta?.url);
const families = (design.typography?.families || []).map(f => (typeof f === 'string' ? f : f.name)).filter(Boolean);
const display = families[0] || 'system-ui';
const heading = (design.voice?.sampleHeadings || [])[0] || `Built from ${hostName}`;
return `<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>${hostName} starter</title>
<link rel="stylesheet" href="../tokens/variables.css">
<style>
body {
margin: 0;
font-family: ${JSON.stringify(display)}, -apple-system, BlinkMacSystemFont, sans-serif;
background: var(--color-background, #fff);
color: var(--color-text, #111);
line-height: 1.5;
}
main { max-width: 840px; margin: 0 auto; padding: 64px 32px; }
h1 { font-size: clamp(40px, 6vw, 72px); line-height: 1.05; margin: 0 0 18px; }
p { font-size: 18px; max-width: 56ch; color: var(--color-text-secondary, #555); }
.cta {
display: inline-block;
padding: 14px 28px;
margin-top: 28px;
background: var(--color-primary, #0a0a0a);
color: var(--color-on-primary, #fff);
border-radius: var(--radius-md, 8px);
text-decoration: none;
font-weight: 600;
}
.cta:hover { opacity: 0.9; }
.meta { margin-top: 64px; font-size: 12px; color: #888; }
.meta a { color: inherit; }
</style>
</head>
<body>
<main>
<h1>${heading}</h1>
<p>This starter is wired to the tokens in <code>tokens/variables.css</code>. Edit the variables and watch this page change. Drop in your own components and use the same tokens to keep the visual language consistent.</p>
<a class="cta" href="#">Get started</a>
<p class="meta">Generated by <a href="https://designlang.app">designlang</a>. Re-pack with <code>npx designlang pack ${hostName}</code>.</p>
</main>
Comment thread src/pack.js
Comment on lines +354 to +360
for (const recipe of pack.recipes) {
// Each recipe = { name, content }; sanitise name to a safe filename.
const safeName = String(recipe.name || 'recipe').replace(/[^a-z0-9-_]+/gi, '-').toLowerCase();
const p = join(recipesDir, `${safeName}.md`);
writeFile(p, recipe.content);
written.push(p);
}
Comment thread src/pack.js
Comment on lines +45 to +54

function nameFromUrl(url) {
try {
const u = new URL(url);
return u.hostname.replace(/[^a-z0-9]+/gi, '-').replace(/^-|-$/g, '').toLowerCase();
} catch {
return 'design-system';
}
}

Comment thread src/pack.js
Comment on lines +59 to +61
function exists(p) {
try { statSync(p); return true; } catch { return false; }
}
Comment thread CHANGELOG.md
**Pack — one command, one polished design-system bundle.**

\`designlang pack <url>\` runs the full extraction once and writes every
emitter output into a single, signed, layered directory. One artifact a
Comment thread CHANGELOG.md
Comment on lines +9 to +10
designer or dev can clone, drop into a project, or zip up and send to a
client. Closes [#59](https://github.com/Manavarya09/design-extract/issues/59).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: component recognition v1 — DOM clusters → typed components

3 participants