Learn-skills.dev ads-dna

install
source · Clone the upstream repo
git clone https://github.com/NeverSight/learn-skills.dev
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/NeverSight/learn-skills.dev "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/skills-md/agricidaniel/claude-ads/ads-dna" ~/.claude/skills/neversight-learn-skills-dev-ads-dna && rm -rf "$T"
manifest: data/skills-md/agricidaniel/claude-ads/ads-dna/SKILL.md
source content

Ads DNA — Brand DNA Extractor

Extracts brand identity from a website and saves it as

brand-profile.json
for use by
/ads create
,
/ads generate
, and
/ads photoshoot
.

Quick Reference

CommandWhat it does
/ads dna <url>
Full brand extraction →
brand-profile.json
/ads dna https://acme.com --quick
Fast extraction (homepage only)

Process

Step 1: Collect URL

If the user hasn't provided a URL, ask:

"What website URL should I analyze for brand DNA? (e.g. https://yoursite.com)"

Step 2: Fetch Pages

Use the WebFetch tool to retrieve each page. For each URL, use this fetch prompt:

"Return all visible text content, the full contents of any

<style>
blocks, inline
style=
attributes,
<meta>
tags, Google Fonts
@import
URLs, and any
og:image
values found on this page."

Fetch in this order:

  1. Homepage (
    <url>
    )
  2. About page — try
    <url>/about
    , then
    <url>/about-us
    , then
    <url>/our-story
  3. Product/Services page — try
    <url>/product
    , then
    <url>/products
    , then
    <url>/services

If

--quick
flag was provided: fetch the homepage only — skip steps 2 and 3.

If a secondary page returns a 404 or redirect error, continue with fewer pages and note: "Secondary pages unavailable — extraction based on homepage only. Confidence may be lower."

Step 2b: Capture Brand Screenshots

After fetching pages, capture desktop screenshots of the website. These serve as visual style references during

/ads generate
— the same approach Pomelli uses to anchor ad images to the actual brand aesthetic.

Run for the homepage:

python ~/.claude/skills/ads/scripts/capture_screenshot.py [url]

This saves

./brand-screenshots/[domain]_desktop.png
(default naming from the script).

Also attempt one secondary page (pricing or product page, whichever was accessible):

python ~/.claude/skills/ads/scripts/capture_screenshot.py [url]/pricing

If

--quick
flag was provided: skip screenshot capture entirely.

If capture fails (Playwright not installed, network error, JS-heavy SPA that times out):

  • Log:
    "Screenshot capture skipped — run: python3 -m playwright install chromium"
  • Continue without screenshots
  • Do NOT set the
    screenshots
    field in brand-profile.json

Step 3: Extract Brand Elements

From the fetched HTML, extract:

Colors:

  • og:image
    meta tag → analyze dominant colors (note 2-3 prominent hex values)
  • CSS
    background-color
    on
    body
    ,
    header
    ,
    .hero
    ,
    .btn-primary
  • CSS
    color
    on
    h1
    ,
    h2
    ,
    .btn
  • CSS
    border-color
    or
    background
    on
    .cta
    ,
    .button
  • Identify: primary (most prominent brand color), secondary (supporting colors), background, text

Typography:

  • @import url(https://fonts.googleapis.com/...)
    → extract font names from URL path
  • CSS
    font-family
    on
    h1
    ,
    h2
    ,
    body
    ,
    .headline
  • If Google Fonts URL contains
    family=Inter:wght@...
    , heading_font = "Inter"

Voice: Analyze hero headline, subheadline, About page intro, and CTA button text. Score each axis 1-10 using these heuristics:

SignalScore direction
Uses "you/your" frequentlyformal_casual → casual (+2)
Uses technical jargonexpert_accessible → expert (-2)
Short punchy sentences (≤8 words)bold_subtle → bold (+2)
Data/stats in herorational_emotional → rational (-2)
"Transform", "revolutionize", "disrupt"traditional_innovative → innovative (+2)
Customer testimonials leadrational_emotional → emotional (+2)
Industry awards, "trusted by X"traditional_innovative → traditional (-1)

Imagery style (from og:image and any visible hero image descriptions):

  • Photography vs. illustration vs. flat design
  • Subject matter (people, product, abstract, data)
  • Composition style (clean/minimal vs. busy/editorial)

Forbidden elements (infer from brand positioning):

  • Enterprise/B2B brands → add "cheesy stock photos", "consumer lifestyle imagery"
  • Healthcare → add "unqualified medical claims", "before/after imagery"
  • Finance → add "get rich quick imagery", "unrealistic wealth displays"
  • Consumer brands → usually no forbidden elements

Step 4: Build brand-profile.json

Read

~/.claude/skills/ads/references/brand-dna-template.md
for the exact schema.

Construct the JSON object following the schema precisely. Use

null
for any field that cannot be confidently extracted — do not guess.

Example of a low-confidence field:

"typography": {
  "heading_font": null,
  "body_font": "system-ui",
  "pairing_descriptor": "system default (Google Fonts not detected)"
}

Step 5: Write brand-profile.json

Write the JSON to

./brand-profile.json
in the current working directory (where the user is running Claude Code).

If screenshots were captured successfully in Step 2b, include a

screenshots
field:

"screenshots": {
  "homepage": "./brand-screenshots/[domain]_desktop.png",
  "secondary": ["./brand-screenshots/[domain]_pricing_desktop.png"]
}

Omit the

screenshots
field entirely if Step 2b was skipped or failed.

Step 6: Confirm and Summarize

Show the user:

✓ brand-profile.json saved to ./brand-profile.json

Brand DNA Summary:
  Brand: [brand_name]
  Voice: [descriptor 1], [descriptor 2], [descriptor 3]
  Primary Color: [hex]
  Typography: [heading_font] / [body_font]
  Target: [age_range] [profession]
  Screenshots: [N captured → ./brand-screenshots/] OR [skipped]

Run `/ads create` to generate campaign concepts from this profile.

Limitations

  • Sparse content: Sites with <200 words of body text produce lower-confidence profiles. Note: "Low confidence extraction — limited content available for analysis."
  • Dynamic sites: JavaScript-rendered content may not be captured. Playwright is not used by default. If the site appears to be SPA/React with no static HTML, note this.
  • Multi-brand enterprises: This tool creates one profile per URL. Run separately for each brand/product line.
  • Dark mode sites: If body background is #333 or darker, swap background/text values.
  • CSS-in-JS: Modern React sites may not have extractable CSS. Use og:image colors as fallback.

brand-profile.json Schema

{
  "schema_version": "1.0",
  "brand_name": "string",
  "website_url": "string",
  "extracted_at": "ISO-8601",
  "voice": {
    "formal_casual": 1-10,
    "rational_emotional": 1-10,
    "playful_serious": 1-10,
    "bold_subtle": 1-10,
    "traditional_innovative": 1-10,
    "expert_accessible": 1-10,
    "descriptors": ["adjective1", "adjective2", "adjective3"]
  },
  "colors": {
    "primary": "#hexcode or null",
    "secondary": ["#hex1", "#hex2"],
    "forbidden": ["#hex or color name"],
    "background": "#hexcode",
    "text": "#hexcode"
  },
  "typography": {
    "heading_font": "Font Name or null",
    "body_font": "Font Name or system-ui",
    "pairing_descriptor": "brief description"
  },
  "imagery": {
    "style": "professional photography | illustration | flat design | mixed",
    "subjects": ["subject1", "subject2"],
    "composition": "brief description",
    "forbidden": ["element1", "element2"]
  },
  "aesthetic": {
    "mood_keywords": ["keyword1", "keyword2", "keyword3"],
    "texture": "minimal | textured | mixed",
    "negative_space": "generous | moderate | dense"
  },
  "brand_values": ["value1", "value2", "value3"],
  "target_audience": {
    "age_range": "e.g. 25-45",
    "profession": "brief description",
    "pain_points": ["pain1", "pain2"],
    "aspirations": ["aspiration1", "aspiration2"]
  }
}