Extract Design System From Existing Code
extract-design-systemReads a project's existing CSS, tokens, or live-site styles and distills its design tokens so new components match the app's current look.
Instructions
Distill the design tokens out of a project's EXISTING CSS so new components match the app the user already built.
Use this when the user says "match our existing style", "use our design system", "style this like the rest of the app", or you are adding UI to a codebase that already has its own look. This is the inverse of find-design-system / create-design-system: instead of giving the user one of our systems, it reads theirs.
How to use it: read the project's globals.css (or wherever the design tokens / CSS custom properties live, e.g. a Tailwind v4 @theme block) and pass its full contents as css. The MCP server cannot read your filesystem, so you must paste the text.
Returns: the semantic palette (primary, background, foreground, accent, border, ring, etc.), radius, fonts, and shadow scale, plus a pasteable token sheet with every color normalized to oklch(). Handles hex, rgb()/rgba(), hsl()/hsla(), named colors, bare Shopify "r,g,b" triplets, and existing oklch values, across :root, .dark, and @theme blocks.
Beyond pasted CSS, sources accepts any mix of inputs and merges them (later sources win):
kind "css": any stylesheet text, same as the
cssparam.kind "computed": a JSON sample of rendered styles read off the LIVE site, which beats variable-name guessing because it records what elements actually look like. Gather it by running this in the site's browser console and passing the printed JSON:
JSON.stringify((() => {
const pick = (el, props) => {
if (!el) return null;
const cs = getComputedStyle(el);
return Object.fromEntries(props.map((p) => [p, cs[p]]));
};
const clear = (c) => {
const flat = (c || "").split(" ").join("");
return !flat || flat === "transparent" || flat.endsWith(",0)") || flat.endsWith("/0)");
};
const aside = "dialog,[role=dialog],[aria-modal=true],[class*=cookie],[id*=cookie],[class*=consent],[id*=consent],[class*=cky-]";
const action = (selector, props) => {
const all = Array.from(document.querySelectorAll(selector)).slice(0, 200).filter((el) => !el.closest(aside));
const shown = all.filter((el) => {
const box = el.getBoundingClientRect();
return box.width > 0 && box.height > 0 && !clear(getComputedStyle(el).backgroundColor);
});
const isPrimaryClass = (t) => t === "primary" || ((t.startsWith("btn") || t.startsWith("button")) && t.endsWith("primary"));
const named = shown.find((el) => String(el.className).split(" ").some(isPrimaryClass));
const spread = (el) => {
const rgb = (getComputedStyle(el).backgroundColor.match(/[0-9.]+/g) || []).slice(0, 3).map(Number);
return rgb.length === 3 ? Math.max(...rgb) - Math.min(...rgb) : 0;
};
const colourful = shown.slice(0, 12).reduce((best, el) => (spread(el) > (best ? spread(best) : 39) ? el : best), null);
const sample = pick(named ?? colourful ?? shown[0] ?? all[0] ?? null, props);
return sample && { ...sample, namedPrimary: named ? "yes" : "" };
};
return {
body: pick(document.querySelector("body"), ["backgroundColor","color","fontFamily"]),
heading: pick(document.querySelector("h1,h2"), ["fontFamily"]),
link: pick(document.querySelector("a[href]"), ["color"]),
button: action("button,[role=button],.btn,input[type=submit],a[class*=button],a[class*=btn]", ["backgroundColor","color","borderRadius"]),
input: pick(document.querySelector("input:not([type=hidden]),textarea,select"), ["borderColor","borderRadius"]),
card: pick(document.querySelector("[class*=card]"), ["backgroundColor","color","borderRadius","boxShadow"]),
};
})())kind "tokens": a design-tokens JSON export ($value entries, W3C format or the Figma variables API shape with 0..1 rgb floats).
Common vendor names (Shopify's --color-button family) are mapped into empty semantic slots automatically and the mapping is reported in the output.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| css | No | Full contents of the project's globals.css (or any CSS holding the design tokens / CSS custom properties). Optional when `sources` is given. | |
| name | No | Optional label for the extracted system, e.g. the app or repo name. | |
| sources | No | Any mix of brand sources, merged in order (later sources win). See the tool description for how to gather each kind. | |
| maxTokens | No | Maximum tokens to return. Truncates the token sheet to fit. |