Brand visual language
Quick answer
- 01What is it?
- Visual shape communicates personality. A rounded corner says something different to the user than a sharp one, and that message arrives before they read a single word. The value is a focused slice of brand and messaging judgment, useful when several similar skills cover the same ground.
- 02Inputs
- Context for brand and messaging: your goals, audience, constraints, and any source material the skill asks for.
- 03Output
- A ready-to-use result for brand and messaging: the analysis, copy, or recommendations the agent produces.
Add this skill
Install as a package
Installs this one skill package for your coding agent, including any supporting files that skill ships with — not every skill in the repository. Read the tutorial.
$ npx skills add dembrandt/dembrandt-skills --skill brand-visual-languageSkill instructions
The instruction file for this skill. The skill also includes other files you need to install to use it.
Brand Visual Language
Visual shape communicates personality. A rounded corner says something different to the user than a sharp one — and that message arrives before they read a single word. The shapes in typography, border-radius, and iconography should tell a consistent story.
Shape Language
| Shape | Tone | Associated with |
|---|---|---|
| Rounded, pill-shaped | Friendly, approachable, playful, modern | Consumer apps, health, kids, lifestyle, social |
| Softly rounded (8–12px) | Professional, warm, accessible | SaaS, productivity, general B2B |
| Lightly rounded (2–4px) | Precise, structured, efficient | Enterprise tools, finance, data platforms |
| Sharp / no radius | Technical, serious, authoritative | Developer tools, security, industrial |
Every component — cards, inputs, modals, badges — should follow the same radius logic.
Radius for Large Surfaces
The perceived "roundedness" of an element changes with its scale. A radius that looks soft on a button may look sharp on a large container.
- Large Cards & Modals: Typically use a larger radius than buttons (e.g., if buttons are 4px, large cards might be 8px or 12px) to maintain a consistent visual tone.
- Wells and Background Sections: For large background areas or "wells," a smaller radius (2px–8px) is often used to provide structure and define the region without making it feel like a "floating" component. This keeps the focus on the content within, rather than the container itself.
Reading Shape from an Existing Brand
Before choosing a radius, look at the brand's existing materials:
- Logo: Is it rounded, geometric, or angular? The logo's shapes are intentional brand decisions.
- Product photography or illustration style: Rounded, bubbly illustrations signal a different personality than sharp, technical diagrams.
- Typography: A geometric sans-serif (Circular, Futura) reads differently than a humanist sans (Inter, Söhne) or a sharp editorial serif.
- Competitor landscape: Sometimes being the slightly softer option in a sharp market, or the more structured option in a playful market, is the differentiator.
Read the real shape language, don't infer it (dembrandt engine, optional). For a brand that already ships a product, extract its actual radius, type, and tone from the live site rather than guessing from the logo:
get_brand_identityandget_design_tokensreturn computed values off the DOM. Seeextract-design.
Typography and Shape
Typeface shapes carry the same tonal signals:
| Type style | Tone |
|---|---|
| Geometric sans (circular letterforms) | Modern, clean, slightly playful |
| Humanist sans (varied stroke widths) | Warm, readable, professional |
| Grotesque sans (neutral, utilitarian) | Serious, efficient, no-frills |
| Serif | Authoritative, established, editorial |
| Rounded sans | Friendly, approachable, informal |
| Monospace | Technical, developer-facing, precise |
The typeface and the border-radius should not contradict each other. A rounded, friendly typeface paired with sharp 0px corners creates visual dissonance.
Extending Brand Typography
Brand books often specify a display or heading font but leave body text underdefined — a single weight, no reading size, no fallback. This is common with luxury, fashion, or legacy brands where the brand identity was built for print, not screen.
When the brand book is insufficient for UI purposes, extend it deliberately:
When extension is justified:
- Brand font has poor legibility at small sizes (display fonts, decorative typefaces)
- Brand font lacks the weights needed for UI hierarchy (no regular, no medium)
- Brand font has no body or reading variant defined
- Brand font loads poorly (performance, licensing, web rendering)
How to extend:
- Keep the brand font for headings and display — this is where brand identity lives
- Add a secondary typeface for body text that is complementary in tone, not competing
- Match shape language: a geometric brand font pairs with a geometric body font; a humanist display pairs with a humanist body
Brand heading font (display, h1–h3): maintains identity
↓
Secondary body font (body, labels, UI copy): legibility and completeness
Pairing principles:
- Contrast in role, not in personality — the two fonts should feel like they belong to the same product
- Avoid two display fonts or two highly characterful fonts together
- A neutral, high-quality sans (Inter, DM Sans, Söhne) pairs safely with most brand fonts
- If the brand font is a serif, a clean sans body is the natural complement — and vice versa
Do this sparingly. Two typefaces is a deliberate extension. Three typefaces is almost always too many. Document the decision and the rationale so future designers do not add a third.
Iconography
Icon style must match the brand's shape language. Mixing icon styles — some thin, some bold, some filled, some outlined — breaks visual cohesion even when individual icons are correct.
| Icon style | Tone | Use when |
|---|---|---|
| Thin / outline (1–1.5px stroke) | Minimal, elegant, refined | Luxury, editorial, premium SaaS |
| Regular outline (2px stroke) | Balanced, professional | General SaaS, productivity tools |
| Bold / thick (2.5–3px stroke) | Strong, clear, accessible | Consumer apps, mobile-first, accessibility focus |
| Filled | Solid, confident, clear at small sizes | Dashboard indicators, status icons, mobile nav |
| Rounded corners on icon paths | Friendly, approachable | Consumer, lifestyle, health |
| Sharp corners on icon paths | Technical, precise | Developer tools, finance, data |
Rule: Use one icon library and one weight throughout. If mixing is unavoidable (e.g. a specialised icon not available in the chosen library), match stroke width and corner style manually.
Use the standard icon; never invent one for a solved concept
Gear = settings, person = profile, magnifier = search, house = home, trash = delete, bell = notifications. Inventing an alternative here costs decoding for zero benefit. Search "icon [concept]" to check the convention before committing. Save design freedom for concepts with no established icon.
Icons let the eye skip the word — but only unambiguous ones, and only where scanning pays off (nav, status, row types). A vague or decorative icon adds work instead of saving it; an icon on every label is noise. Right icon, relevant place. See [[ui-density]] on reading as time.
Consistency Across Elements
All shape-bearing elements should follow the same visual logic:
| Element | Applies shape language via |
|---|---|
| Buttons | --radius-button |
| Cards | --radius-card (same or slightly larger than button) |
| Inputs | --radius-input (typically same as button) |
| Badges / tags | Can be more rounded than buttons — pill shape is common |
| Modals / drawers | --radius-modal (often larger, 12–16px) |
| Avatars | Always fully round (--radius-full) |
| Icons | Stroke weight and corner style match brand |
| Illustrations | Shape style consistent with icon style |
Review Checklist
- Does the border-radius token match the brand's shape language (logo, illustrations, photography)?
- Is the same radius logic applied to buttons, inputs, and cards?
- Does the typeface tone match the overall brand personality?
- Is a single icon library used consistently throughout?
- Do icons match the brand in stroke weight (thin for refined, bold for accessible)?
- Are rounded icon corners used for friendly brands and sharp corners for technical brands?
- Are standard concepts (settings, profile, search, delete, notifications) using the conventional icon rather than an invented one?
- Are icons used only where recognition pays off — not sprinkled on every label as decoration?
- Is the border-radius adjusted for surface size (e.g., larger for modals, tighter 2-8px for wells/backgrounds)?
- Is there no visual contradiction between typeface style and shape choices (e.g. rounded type + sharp cards)?
Supporting file: skills/extract-design/SKILL.md
Extract Design — Dembrandt
Dembrandt runs a headless Chromium browser against any URL, walks up to thousands of DOM elements, reads computed CSS, and returns a structured design system: colors with confidence scoring, typography styles, spacing scale, border radius, borders, shadows, and interactive component styles.
How to Run
# Zero-install — npx fetches the package on first run (lowest friction)
npx -y dembrandt https://stripe.com
# Or install once (global), then call `dembrandt` directly
npm i -g dembrandt
# Basic extraction — outputs to terminal
dembrandt https://stripe.com
# JSON output — pipe into files or other tools
dembrandt https://stripe.com --json-only > stripe-tokens.json
# W3C DTCG format (design-tokens.org standard)
dembrandt https://stripe.com --dtcg --save-output
# Generate DESIGN.md (human + AI readable brand doc)
dembrandt https://stripe.com --design-md
# Multi-page crawl (follows internal links)
dembrandt https://stripe.com --crawl 5
# Dark mode colors
dembrandt https://stripe.com --dark-mode
# Mobile viewport
dembrandt https://stripe.com --mobile
# Everything saved to output/
dembrandt https://stripe.com --save-output
# Self-contained HTML report — open offline or attach as a CI artifact [dembrandt 0.19+]
dembrandt https://stripe.com --html report.html
# Drift gate — compare against a saved baseline; exits 1 on drift [dembrandt 0.19+]
dembrandt https://app.example.com --compare baseline.json --html report.html
MCP Usage (async by default)
To expose Dembrandt as MCP tools, add this server to the agent's MCP config (no install — npx fetches it on first run):
{ "mcpServers": { "dembrandt": { "command": "npx", "args": ["-y", "--package", "dembrandt", "dembrandt-mcp"] } } }
When using the Dembrandt MCP server, all extraction tools return a job_id immediately rather than blocking. Poll get_job_status until status is "completed":
1. get_design_tokens({ url: "stripe.com" })
→ { job_id: "job_123_abc", status: "queued" }
2. get_job_status({ job_id: "job_123_abc" })
→ { status: "running" } // poll again
3. get_job_status({ job_id: "job_123_abc" })
→ { status: "completed", result: { ... } }
Pass sync: true to any extraction tool to block and return the result directly (useful on fast networks, risks timeout on slow sites).
Extraction tools: get_design_tokens (everything), get_color_palette, get_typography, get_component_styles, get_surfaces, get_spacing, get_brand_identity. All accept slow, mobile (mobile viewport), and cookie (cookie string for authenticated pages); get_design_tokens and get_color_palette also accept darkMode and wcag (contrast analysis). [dembrandt 0.23.1+ for mobile/cookie/wcag]
Pure tools (no browser, synchronous, take an extraction object): compute_drift (0-100 drift score between two extractions), get_findings (design-system lint: contrast, consistency, duplication), export_dtcg (W3C Design Tokens format), generate_design_md (DESIGN.md brand guide), render_report (self-contained HTML report). Job control: get_job_status, list_jobs, cancel_job. [dembrandt 0.23.1+ for get_findings/export_dtcg/generate_design_md/list_jobs]
Note: dembrandt <=0.23.0 fails to start via the npx one-liner above (McpDepsMissingError) — the MCP SDK was an optional peer dependency. Fixed in 0.23.1; require it.
Output Structure
Dembrandt returns a structured object. The key sections:
colors.palette — Deduplicated colors with confidence (high/medium/low)
colors.semantic — Primary, secondary, background, text, and accent detection
colors.cssVariables — Named CSS custom properties with LCH + OKLCH values
typography.styles — Font family, size, weight, line-height per context
typography.sources — Google Fonts, Adobe Fonts, variable font detection
spacing.commonValues — Margin/padding scale with rem equivalents
spacing.scaleType — 4px, 8px, or custom grid
borderRadius.values — Border radius tokens with element context
borders.combinations — Width + style + color combinations
shadows — Box shadow elevation system
components.buttons — Button variants with hover/active/focus states
components.inputs — Input styles with focus states
components.links — Link colors and hover states
components.badges — Badge/tag/chip variants
breakpoints — Responsive breakpoints from CSS media queries
frameworks — Detected CSS framework (Tailwind, shadcn, MUI, etc.)
iconSystem — Detected icon library (Heroicons, FA, Material, etc.)
Working with Extracted Tokens
Seeding a Tailwind config
After extraction, map the output to tailwind.config.js:
// tailwind.config.js
export default {
theme: {
colors: {
primary: '#hex-from-colors.palette[0]',
// ...
},
fontFamily: {
sans: ['Family from typography.styles', 'system-ui'],
},
spacing: {
// Map spacing.commonValues px → rem
},
borderRadius: {
// Map borderRadius.values
},
boxShadow: {
// Map shadows
},
}
}
Seeding a shadcn/ui theme
Map semantic colors to shadcn CSS variables in HSL:
:root {
--background: /* from colors.semantic.background (0.22.0+), else colors.palette — lightest neutral */;
--foreground: /* from colors.semantic.text (0.22.0+), else colors.palette — darkest neutral */;
--primary: /* from colors.semantic.primary */;
--primary-foreground: /* contrasting color */;
--muted: /* mid-tone neutral */;
--border: /* from borders.combinations[0].color */;
--radius: /* from borderRadius.values[0].value */;
}
Reading confidence levels
Dembrandt scores every color by semantic context:
| Confidence | Meaning |
|---|---|
| high | Appears on semantically labeled elements (buttons, CTAs, headers with brand classes). Almost certainly a brand color. |
| medium | Moderate frequency or moderate context. Likely a brand color. |
| low | Rare, low semantic context. May be a one-off or component-specific color. |
Start with high confidence colors when building a palette. Include medium for full coverage. Treat low as reference only.
Flags Reference
| Flag | What it does |
|---|---|
--json-only | Clean JSON to stdout — pipe into files or tools |
--save-output | Save JSON to output/<domain>/<timestamp>.json |
--dtcg | W3C Design Tokens Community Group format |
--design-md | Generate DESIGN.md — prose-first brand doc |
--html [path] | Self-contained HTML report (inline CSS, embedded JSON). Open offline or attach as a CI artifact. (0.19+) |
--compare <baseline.json> | Diff against a saved extraction; prints a drift verdict and exits 1 on drift. CI gate. (0.19+) |
--brand-guide | Generate a PDF brand guide |
--dark-mode | Extract dark color scheme and merge into palette |
--mobile | Extract at 390px mobile viewport |
--crawl <n> | Crawl up to N pages and merge tokens |
--sitemap | Discover pages from sitemap.xml |
--slow | 3× timeouts — use on slow-loading or JS-heavy sites |
--screenshot <path> | Save a full-page screenshot |
--raw-colors | Include pre-filter raw colors in JSON output |
--browser firefox | Use Firefox instead of Chromium |
--stealth | Opt-in anti-detection: navigator spoofing + human mouse simulation. Use only when authorized. |
--user-agent <string> | Custom user agent string |
--locale <string> | Browser locale, e.g. fi-FI, en-GB (default: en-US) |
--timezone <string> | Browser timezone, e.g. Europe/Helsinki (default: America/New_York) |
--accept-language <string> | Custom Accept-Language header value |
--screen-size <WxH> | Physical screen resolution to report, e.g. 1920x1080 |
Drift Detection & CI (dembrandt 0.19+)
--compare turns extraction into a gate. Save a known-good baseline, then compare later extractions against it:
# 1. capture a baseline (in the SAME environment you will check against)
dembrandt https://app.example.com --json-only > baseline.json
# 2. later — compare; exits 0 if stable, 1 if drifted
dembrandt https://app.example.com --compare baseline.json --html report.html
- Runs the canonical drift engine over structured tokens — deterministic, not a pixel/render diff.
- Exit code:
0stable,1drift. Gates a pipeline directly. --htmlwrites a self-contained report; with--compareit includes a drift banner (added/removed/changed tokens). Attach it as a CI artifact.
Determinism: capture the baseline in the same environment you check it in (both production, or both the same preview). A baseline from one environment compared against another shows false drift.
In CI: run --compare <baseline> --html report.html against a preview/deployed URL, fail the job on exit 1, upload the HTML artifact. Programmatic: import computeDrift from dembrandt/drift and generateHtmlReport from dembrandt/report to diff and render server-side without the CLI.
Anti-Bot and SPA Handling
Dembrandt handles common extraction challenges automatically:
- SPA hydration — waits 8s for React/Vue/Svelte to render before extracting
- Lazy content — scrolls the full page to trigger lazy-loaded components
- Cloudflare / bot walls — auto-retries with a visible browser if headless is blocked
- Slow sites — use
--slowfor 3× timeouts on heavy JS bundles - Cookie banners — dismisses common CMP dialogs (OneTrust, cookielaw, GDPR patterns) automatically
- Bot detection bypass — use
--stealthto opt in to navigator spoofing and human mouse simulation; off by default so the tool identifies itself honestly
Checklist After Extraction
- Identify the 3–5 high-confidence colors — these are the core brand palette
- Check
colors.semantic.primary— is it correct? - Look at
typography.styles— what are the heading and body fonts? - Check
spacing.scaleType— 4px or 8px grid? - Review
components.buttons— how many variants exist? - Check
frameworks— is Tailwind, shadcn, or MUI detected? This shapes how you apply the tokens. - Use
--dark-modeif the site has a dark theme - Use
--crawl 3if the site has a multi-section design system spread across routes
Common questions
How do I install Brand visual language in Cursor, Claude Code, or Codex?
Run npx skills add dembrandt/dembrandt-skills --skill brand-visual-language in the project where you want it, then ask your agent for the skill by name. The --skill flag installs only Brand visual language, not every skill in the repository.
Where does Brand visual language come from and what license is it under?
Brand visual language comes from the dembrandt/dembrandt-skills repository on GitHub. That repository has 22 GitHub stars. The skill is published under the MIT license.
Prefer plain text? Read the Brand visual language guide as markdown.
Related skills
More from dembrandt