Extracting Exact Design Tokens Using getComputedStyle() in the AI Website Cloner

The AI Website Cloner extracts pixel-perfect design tokens by injecting a JavaScript payload that calls window.getComputedStyle() on every DOM element, capturing colors, typography, and spacing values across multiple UI states before translating them into CSS custom properties.

The JCodesMore/ai-website-cloner-template repository automates the conversion of live websites into Next.js applications by programmatically reading browser-computed CSS values. This extraction process relies on getComputedStyle() to capture the exact, final-rendered design specifications that power the reconstruction workflow.

How the Extraction Pipeline Works

The cloner’s extraction pipeline operates across the Reconnaissance and Foundation phases, utilizing browser automation tools like Chrome MCP or Playwright to execute JavaScript inside the target page context.

Phase 1: Browser Initialization and Navigation

The skill first ensures a MCP browser session is available and navigates to the target URL. This setup occurs in the workflow definition at .windsurf/workflows/clone-website.md (lines 19-21), establishing the environment for DOM traversal.

Phase 2: Global Style Extraction

A JavaScript payload is injected via executeScript that walks the entire DOM, calling window.getComputedStyle() on each element. The script filters for 23 specific CSS properties—including fontSize, fontWeight, color, backgroundColor, padding, margin, borderRadius, and transition—while discarding empty or default values like 'none', 'auto', and '0px'. This logic is documented in the extraction script section (lines 38-80) of the workflow file.

Phase 3: Multi-State Capture

To record behavioral specifications, the script executes twice or more:

  1. State A: Capture the default computed styles at the initial scroll position (0 px)
  2. State B: Trigger UI changes via scroll, hover, or click events, then re-run the extraction

The before/after JSON diff becomes the behavioral spec written under the States & Behaviors section of component documentation. This process is detailed in the workflow (lines 82-89) and enables the cloner to recreate interactive effects like sticky headers or hover transitions.

Phase 4: Token Persistence and Translation

The raw JSON dump is written to specification files under docs/research/components/. A helper utility then translates these values into the codebase by updating src/app/globals.css with :root CSS custom properties and modifying src/app/layout.tsx for font configurations (workflow lines 79-81).

Core Implementation Code

The Base Extraction Script

This minimal runnable snippet demonstrates the core logic injected into the browser:

/* Run inside the browser (e.g., via Chrome MCP `executeScript`) */
(function selectorExtract(selector) {
  const el = document.querySelector(selector);
  if (!el) return JSON.stringify({ error: `Missing ${selector}` });

  const props = [
    'fontSize','fontWeight','fontFamily','lineHeight','letterSpacing','color',
    'backgroundColor','padding','margin','width','height','display',
    'justifyContent','alignItems','gap','borderRadius','boxShadow',
    'opacity','transform','transition','zIndex','position','top','right',
    'bottom','left','cursor'
  ];

  const cs = getComputedStyle(el);
  const styles = {};
  props.forEach(p => {
    const v = cs[p];
    if (v && v !== 'none' && v !== 'auto' && v !== '0px') styles[p] = v;
  });

  // Simple shallow dump – recursion is added later for full trees.
  return JSON.stringify({ selector, tag: el.tagName, styles }, null, 2);
})('SELECTOR');

The full production version includes recursive child traversal with configurable depth limits and is located in .windsurf/workflows/clone-website.md (lines 38-78).

Capturing Interactive States

To record scroll-triggered animations or hover effects, the cloner executes sequential extractions:

// 1️⃣ Capture default (scrollTop = 0)
const defaultState = await browser.executeScript(extractScript, '.header');

// 2️⃣ Scroll past the trigger
await page.evaluate(() => window.scrollTo(0, 120));   // example trigger point
await page.waitForTimeout(300);                       // let transitions settle

// 3️⃣ Capture scrolled state
const scrolledState = await browser.executeScript(extractScript, '.header');

// 4️⃣ Diff (simplified)
function diff(a, b) {
  const diffObj = {};
  for (const k in a.styles) {
    if (a.styles[k] !== b.styles[k]) diffObj[k] = [a.styles[k], b.styles[k]];
  }
  return diffObj;
}
const changes = diff(defaultState, scrolledState);
console.log('Header changes on scroll:', changes);

The resulting changes object is persisted to the component spec markdown template (lines 34-41) to document the behavioral specification.

Translating to CSS Variables

Extracted values are converted into Tailwind-compatible CSS custom properties:

/* docs/research/components/header.spec.md → generated tokens */
:root {
  --color-primary: #1e3a8a;   /* extracted from .header */
  --color-background: #fafafa;
}

/* dark mode block */
.dark {
  --color-background: #111827;
}

A Node.js helper reads the JSON token dump and injects these definitions into src/app/globals.css, establishing the design token foundation for the reconstructed site.

Key Source Files and Their Roles

  • .windsurf/workflows/clone-website.md: Master workflow describing the five-phase cloning pipeline, including the exact getComputedStyle() extraction implementation (lines 38-89).
  • .opencode/commands/clone-website.md: Command-line interface version of the workflow that mirrors the same extraction logic for Opencode agent compatibility.
  • docs/research/components/*.spec.md: Generated specification files that embed the exact getComputedStyle() output and state diffs for each UI component.
  • src/app/globals.css: Destination file for extracted color and spacing tokens as CSS custom properties.
  • src/app/layout.tsx: Target file for injecting extracted fontFamily configurations.

Summary

  • The extraction engine injects JavaScript that calls getComputedStyle() to read final cascaded values directly from the browser render tree.
  • Multi-state capture records behavioral changes—such as scroll effects and hover states—by diffing computed values before and after user interactions.
  • Raw JSON token dumps are stored in component specification files under docs/research/components/ for architectural reference.
  • Extracted tokens are translated into :root CSS custom properties in src/app/globals.css and font configurations in src/app/layout.tsx.

Frequently Asked Questions

Why does the cloner use getComputedStyle() instead of parsing static CSS files?

getComputedStyle() captures the final cascaded values after all stylesheet rules, inline styles, and JavaScript modifications have been applied by the browser engine. Static parsing cannot resolve specificity conflicts, computed inheritance, or runtime style injections that live sites frequently employ.

How does the cloner handle responsive or interactive design tokens?

The pipeline captures State A (default viewport) and State B (after triggering responsive breakpoints or hover events), then computes the JSON diff between these states. This diff reveals the exact property values that change during interactions, which are documented in the component spec's States & Behaviors section.

Which CSS properties are extracted during the process?

The extraction targets 23 specific properties: fontSize, fontWeight, fontFamily, lineHeight, letterSpacing, color, backgroundColor, padding, margin, width, height, display, justifyContent, alignItems, gap, borderRadius, boxShadow, opacity, transform, transition, zIndex, position, and cursor coordinates. Values equal to 'none', 'auto', or '0px' are filtered out to reduce noise.

Where are the extracted design tokens stored in the repository?

Raw extraction data lives in docs/research/components/*.spec.md files as JSON dumps. Processed design tokens are injected into src/app/globals.css as CSS custom properties (e.g., --color-primary), while font family declarations update src/app/layout.tsx to ensure proper Next.js font optimization.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →