Learn-skills.dev ads-dna
git clone https://github.com/NeverSight/learn-skills.dev
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"
data/skills-md/agricidaniel/claude-ads/ads-dna/SKILL.mdAds 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
| Command | What it does |
|---|---|
| Full brand extraction → |
| 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
blocks, inline<style>attributes,style=tags, Google Fonts<meta>URLs, and any@importvalues found on this page."og:image
Fetch in this order:
- Homepage (
)<url> - About page — try
, then<url>/about
, then<url>/about-us<url>/our-story - Product/Services page — try
, then<url>/product
, then<url>/products<url>/services
If
flag was provided: fetch the homepage only — skip steps 2 and 3.--quick
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
flag was provided: skip screenshot capture entirely.--quick
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
field in brand-profile.jsonscreenshots
Step 3: Extract Brand Elements
From the fetched HTML, extract:
Colors:
meta tag → analyze dominant colors (note 2-3 prominent hex values)og:image- CSS
onbackground-color
,body
,header
,.hero.btn-primary - CSS
oncolor
,h1
,h2.btn - CSS
orborder-color
onbackground
,.cta.button - Identify: primary (most prominent brand color), secondary (supporting colors), background, text
Typography:
→ extract font names from URL path@import url(https://fonts.googleapis.com/...)- CSS
onfont-family
,h1
,h2
,body.headline - If Google Fonts URL contains
, heading_font = "Inter"family=Inter:wght@...
Voice: Analyze hero headline, subheadline, About page intro, and CTA button text. Score each axis 1-10 using these heuristics:
| Signal | Score direction |
|---|---|
| Uses "you/your" frequently | formal_casual → casual (+2) |
| Uses technical jargon | expert_accessible → expert (-2) |
| Short punchy sentences (≤8 words) | bold_subtle → bold (+2) |
| Data/stats in hero | rational_emotional → rational (-2) |
| "Transform", "revolutionize", "disrupt" | traditional_innovative → innovative (+2) |
| Customer testimonials lead | rational_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"] } }