# How the Brand Onboarding Process Extracts Colors from a Website for Diagram Design

> Learn how brand onboarding extracts website colors for diagram design. Discover how we parse CSS, rank colors by prominence, and map them to design tokens.

- Repository: [Cathryn Lavery/diagram-design](https://github.com/cathrynlavery/diagram-design)
- Tags: deep-dive
- Published: 2026-08-18

---

**The brand onboarding process fetches a website's HTML, parses its CSS to extract all color values, ranks them by frequency and visual prominence, then maps the top five colors to semantic design tokens.**

This automated pipeline—implemented in the `cathrynlavery/diagram-design` repository—eliminates manual color entry by transforming any public website into a reusable brand palette. The entire workflow completes in approximately 60 seconds and writes directly to the skill's style guide.

## The 10-Step Color Extraction Pipeline

The **brand onboarding process** follows a deterministic, self-contained workflow defined in [`skills/diagram-design/references/onboarding.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/onboarding.md):

### 1. User URL Input

The skill prompts for a publicly accessible website address. Example: `https://mybrand.com`.

### 2. HTML Retrieval

The system issues an HTTP GET request using Python's `httpx` or `urllib.request` to download the page markup.

### 3. Stylesheet Discovery

**BeautifulSoup** parses the HTML to locate:
- `<link rel="stylesheet">` tags for external CSS
- Inline `<style>` blocks embedded in the document

### 4. CSS Aggregation

External stylesheets are fetched and concatenated with inline styles. The combined CSS is **normalized**—comments, whitespace, and media-query wrappers are stripped.

### 5. Color Parsing

A regular expression scan extracts every CSS color literal:
- Hex codes: `#rrggbb`, `#rgb`
- Functions: `rgb()`, `hsl()`
- Named colors: `aliceblue`, `antiquewhite`, `aqua`, etc.

The parser prioritizes properties associated with brand visibility: `background-color`, `color`, `border-color`, and `fill`.

### 6. Frequency Scoring

Each color occurrence is tallied. **Heuristics boost weights** for colors applied to high-visibility selectors like `a`, `button`, and `h1`.

### 7. Top-N Selection

By default, the pipeline selects the **five most common colors** and assigns them to semantic roles:
- `paper` — background/base color
- `ink` — primary text color
- `accent` — highlight/CTA color
- `muted` — secondary/subdued color
- `link` — hyperlink color

### 8. Font Family Extraction

A parallel scan extracts `font-family` declarations from `body` and heading selectors to identify the primary typeface.

### 9. Style Guide Generation

The extracted tokens replace defaults in [`skills/diagram-design/references/style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/style-guide.md). A **fidelity receipt** records the source URL and extracted values.

### 10. Profile Persistence (Optional)

Users may save results as a named profile to `~/.diagram-design/profiles/<slug>.md` for automatic application to future diagrams.

## Implementation: Core Code Components

The following Python snippets mirror the internal logic used by the diagram-design skill.

### Fetch and Parse HTML

```python
import httpx
from bs4 import BeautifulSoup

def fetch_html(url: str) -> str:
    """Download the page HTML."""
    resp = httpx.get(url, timeout=10.0)
    resp.raise_for_status()
    return resp.text

```

### Collect CSS from All Sources

```python
def collect_css(html: str, base_url: str) -> str:
    """Gather inline <style> blocks and external CSS files."""
    soup = BeautifulSoup(html, "html.parser")
    css_parts = []

    # Inline styles

    for style_tag in soup.find_all("style"):
        css_parts.append(style_tag.string or "")

    # External stylesheets

    for link in soup.select('link[rel="stylesheet"]'):
        href = link.get("href")
        if not href:
            continue
        css_url = httpx.URL(href, base_url=base_url)
        css_parts.append(httpx.get(str(css_url)).text)

    return "\n".join(css_parts)

```

### Extract and Rank Colors

```python
import re
from collections import Counter

COLOR_RE = re.compile(
    r"""(?i)
    \#([0-9a-f]{3}|[0-9a-f]{6})|
    rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)|
    hsl\(\s*\d+\s*,\s*\d+%?,\s*\d+%?\)|
    (aliceblue|antiquewhite|aqua|...|yellow)  # abbreviated list

    """, re.VERBOSE)

def extract_colors(css: str) -> list[str]:
    """Return a list of all colour literals found in the CSS."""
    return COLOR_RE.findall(css)

def rank_colors(colors: list[str]) -> list[tuple[str, int]]:
    """Count occurrences and return colours sorted by frequency."""
    return Counter(colors).most_common()

def map_to_tokens(top_colors: list[tuple[str, int]]) -> dict:
    """Map the five most common colours to semantic tokens."""
    tokens = ["paper", "ink", "accent", "muted", "link"]
    return {token: color for token, color in zip(tokens, [c for c, _ in top_colors])}

```

## Command-Line Usage

Execute the full pipeline via the skill's built-in command:

```bash
diagram-design onboard https://example.com

```

This prints a summary report and updates [`style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/style-guide.md) with extracted tokens.

To preserve results for reuse:

```bash
diagram-design onboard https://example.com --save my-brand

```

The saved profile enables automatic brand application without re-running extraction.

## Key Source Files

| File | Purpose |
|------|---------|
| [`skills/diagram-design/references/onboarding.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/onboarding.md) | Complete specification of URL-to-tokens flow, color-extraction heuristics, and ranking algorithm |
| [`skills/diagram-design/references/style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/style-guide.md) | Semantic token definitions (`paper`, `ink`, `accent`, `muted`, `link`) populated by onboarding |
| [`skills/diagram-design/SKILL.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/SKILL.md) | High-level capability description linking to onboarding functionality |

## Summary

- The **brand onboarding process** extracts colors from websites through automated CSS parsing and frequency analysis
- **Five semantic tokens** (`paper`, `ink`, `accent`, `muted`, `link`) receive the most prominent colors
- The pipeline completes in **~60 seconds** and writes directly to [`style-guide.md`](https://github.com/cathrynlavery/diagram-design/blob/main/style-guide.md)
- **Profiles** enable persistent brand reuse via `~/.diagram-design/profiles/`
- Implementation relies on **BeautifulSoup**, **httpx**, and regex-based color parsing

## Frequently Asked Questions

### What color formats does the brand onboarding process support?

The parser recognizes hex shorthand (`#rgb`), hex standard (`#rrggbb`), `rgb()` functions, `hsl()` functions, and CSS named colors. All values are extracted as strings and ranked by occurrence count before token assignment.

### How does the system decide which colors are "brand" colors?

Frequency is the primary signal—colors appearing most often in the CSS are assumed primary. **Heuristic weights** boost scores for colors applied to navigation elements (`a`), buttons (`button`), and headings (`h1`), under the assumption that these receive deliberate brand treatment.

### Can I modify the number of extracted colors?

The default selects **five colors** mapped to fixed semantic tokens. To customize, edit the `tokens` list in `map_to_tokens()` and adjust the slice operation on `top_colors` before the `zip()` call.

### Where are extracted brand profiles stored?

Named profiles persist to `~/.diagram-design/profiles/<slug>.md` when using the `--save` flag. These Markdown files contain the full token set and fidelity receipt, enabling version-controlled brand management and team sharing.