# Brand Visual Discovery — Source Protocol

The canonical ordered list of every source to check when building a brand image set. Run these in order. Build a source list before downloading anything. Present source list to human for confirmation before capture phase.

## Rule: DISCOVER before CAPTURE
Never start downloading images until you have a source list. The discovery phase is searches and fetches only — no image downloads. Output: a table of URLs with agency attribution, content description, and estimated image count.

---

## TIER 1 — Agency Case Studies (highest quality, always check first)

### 1a. Search for the agency

```
web_search "[Brand] brand identity agency case study"
web_search "[Brand] rebrand agency"
web_search "[Brand] visual identity [year]"
web_search "[Brand] advertising agency campaign"
```

### 1b. Check every major agency portfolio directly

Search each portfolio for the brand name. Fetch the work page if found.

**Identity / brand design studios:**
- `behance.net/search/projects?search=[Brand]+brand+identity`
- `pentagram.com/work` — search for brand
- `wearecollins.com/work`
- `wolffolins.com/work`
- `portorocha.com/projects`
- `gretel.nyc/work`
- `koto.studio/work`
- `mucho.ws/work`
- `designstudio.co.uk/work`
- `studiodumbar.com/work`
- `character.is/work`
- `movethedialect.com/work`
- `TheodoreStudio.com`

**Campaign / advertising / motion:**
- `buck.co/work`
- `instrument.com/work`
- `droga5.com/work`
- `wiedenkennedy.com/work`
- `bbdo.com/work`
- `anomaly.com/work`
- `rpglan.com` (pgLang)
- `themill.com/work`

**How to extract images from agency sites:**
1. Try: `web_fetch [URL]` — extract `<img>` src attributes from the case study page
2. For Prismic-based sites (common for Porto Rocha, many studios): see `creative-visual-research` skill for Prismic API method
3. Use `scripts/images/extract-images.sh [URL] [output-dir] [limit]` for generic HTML extraction
4. If blocked: search for the case study on Behance instead (`web_search "[Agency] [Brand] behance"`)

---

## TIER 2 — Design Press Coverage

These outlets publish editorial-quality imagery with agency attribution. Hit all of them.

| Publication | Search method | Notes |
|-------------|--------------|-------|
| **It's Nice That** | `web_search "[Brand] site:itsnicethat.com"` | Editorial design coverage, high-res campaign imagery |
| **The Brand Identity** | `web_search "[Brand] site:the-brandidentity.com"` | Identity system deep-dives |
| **Brand New / UnderConsideration** | `web_search "[Brand] site:underconsideration.com"` | Brand identity changes, community commentary |
| **Creative Review** | `web_search "[Brand] site:creativereview.co.uk"` | Campaign and identity work |
| **Eye on Design (AIGA)** | `web_search "[Brand] site:eyeondesign.aiga.org"` | Design editorial coverage |
| **Communication Arts** | `web_search "[Brand] commarts.com"` | Award-winning creative |
| **Grafik** | `web_search "[Brand] site:grafik.net"` | UK design editorial |

For each result found: `web_fetch [URL]` — extract image src URLs from the article. Download the ones that are 1000px+ and on-brand.

---

## TIER 3 — Campaign Press

For campaign work specifically:

| Publication | Search | Notes |
|-------------|--------|-------|
| **LBB Online** | `web_search "[Brand] site:lbbonline.com"` | Campaign launches with agency credits |
| **Ads of the World** | `web_search "[Brand] adsoftheworld.com"` | Archived campaign creative |
| **The Drum** | `web_search "[Brand] campaign site:thedrum.com"` | Trade press |
| **Campaign** | `web_search "[Brand] campaign campaignlive.com"` | UK/US trade press |
| **Adweek** | `web_search "[Brand] adweek.com"` | US advertising trade press |
| **Cannes Lions** | `web_search "[Brand] Cannes Lions shortlist winner"` | Award-winning campaigns |
| **Clio Awards** | `web_search "[Brand] Clio Awards"` | Additional award source |
| **D&AD** | `web_search "[Brand] D&AD pencil"` | UK design/advertising awards |

---

## TIER 4 — Brand's Own Assets

| Source | URL pattern | What to find |
|--------|------------|-------------|
| **Press/Newsroom** | `[brand].com/press` · `[brand].com/newsroom` · `[brand].com/media` · `newsroom.[brand].com` · `press.[brand].com` | Downloadable press kits, brand assets, campaign imagery |
| **Brand blog** | `[brand].com/blog` (search for "brand" or "campaign") | Behind-the-scenes brand content |
| **About/Design** | `[brand].com/about` · `[brand].com/design` | Sometimes hosts design system info |
| **Figma Community** | `web_search "site:figma.com/community [brand]"` | Published brand kits, UI kits, design systems |
| **Brand guidelines PDF** | `web_search "[brand] brand guidelines filetype:pdf"` | Sometimes publicly available identity docs |

---

## TIER 5 — Social & Community

Run after Tiers 1-4. Social fills gaps, provides social-native content for §10.

| Platform | Method | Notes |
|----------|--------|-------|
| **Instagram** | Instagram API (mobile UA method in `creative-visual-research` skill) | 12 most recent posts + profile stats. No auth needed. |
| **YouTube** | `img.youtube.com/vi/{VIDEO_ID}/maxresdefault.jpg` | Public CDN thumbnails, no auth. Get IDs from channel page. |
| **X/Twitter** | Playwright screenshot of profile or post | Works. Profile grid + individual posts. |
| **TikTok** | Platform blocks all automated capture | Styled stats card only. Get follower count + content type from web_search. |
| **LinkedIn** | `web_search "[Brand] LinkedIn brand post"` | Limited public access; use for employer brand signals |
| **Dribbble** | `web_search "[Brand] site:dribbble.com"` | Community design work, UI exploration |
| **Pinterest** | `web_search "[Brand] brand identity site:pinterest.com"` | Aggregated brand imagery, style references |

---

## MOTION ASSETS — Extract Alongside Images

When fetching any agency case study or brand page, flag these in addition to images:

| Signal | What it means | Action |
|--------|--------------|--------|
| `<iframe src="*vimeo*">` in HTML | Vimeo embed — agency case study reel | Extract Vimeo ID → download with yt-dlp |
| `<iframe src="*youtube*">` in HTML | YouTube embed — brand film | Extract YouTube ID → download with yt-dlp |
| `.gif` in image src | Animated GIF — motion demo | Download like an image (no special handling) |
| `*.riv` in page source | Rive animation file | Note URL — can embed natively in HTML |
| `*.lottie` or `*.json` Lottie | Lottie animation | Note URL — can embed with Lottie player |
| `<video src="*">` in HTML | Direct video embed | Download with curl |

**Download tool:**
```bash
# YouTube or Vimeo (headless — works for most public videos)
yt-dlp --format "mp4[height<=720][ext=mp4]" [URL] -o "assets/motion/[name].mp4"

# If bot detection blocks yt-dlp (YouTube increasingly common):
yt-dlp --cookies-from-browser chrome [URL] -o "assets/motion/[name].mp4"
# Requires running on a machine with Chrome and a logged-in YouTube session.
# Cannot run headlessly in a sandboxed agent — flag to human if blocked.
```

**Known blockers:**
- **YouTube brand films**: Bot detection is increasingly common. `--cookies-from-browser chrome` works on a desktop machine with a logged-in session. Flag to human if headless download fails.
- **Mux video** (used by BUCK and many agency sites): Mux streams require browser tab capture — yt-dlp cannot download Mux without HLS manifest extraction. Flag to human: "requires browser screen capture."
- **Vimeo (unlisted)**: Agency case study videos are sometimes unlisted. `yt-dlp` handles these if the URL is known — extract Vimeo IDs from page source first.
- **JS-rendered carousels**: Some agency portfolio carousels (especially on BUCK, Instrument) use scroll-triggered loading. Standard Playwright screenshot captures only the visible state. Fix: `page.evaluate("window.scrollBy(0, 500)")` in a loop to trigger carousel frames.

**Process to loop:**
```bash
ffmpeg -i assets/motion/[name].mp4 -ss 00:00:03 -t 10 -vf "scale=800:-1" -c:v libvpx-vp9 -b:v 0 -crf 33 -an assets/motion/[name]-loop.webm
ffmpeg -i assets/motion/[name].mp4 -ss 00:00:03 -t 10 -vf "scale=800:-1" -c:v libx264 -crf 26 -an assets/motion/[name]-loop.mp4
```

**Brand YouTube channels** — always check for brand films:
```
yt-dlp --get-id "https://www.youtube.com/@[channel]/videos" --playlist-items 1-10
```
Then download thumbnails + flag the top 3–5 for potential loop extraction.

---

## Discovery Output Format

Write a `discovery-sources.md` in the working directory with this structure:

```markdown
# [Brand] — Discovery Source List
Date: YYYY-MM-DD

## TIER 1 — Agency Case Studies
| Agency | URL | Content | Est. Images | Status |
|--------|-----|---------|-------------|--------|
| BUCK | buck.co/work/... | Full campaign case study | 22 | DONE |
| Instrument | instrument.com/work/... | "For Your Life's Work" | ~15 | TO CAPTURE |
| ... | | | | |

## TIER 2 — Design Press
| Publication | URL | Content | Est. Images | Status |
|-------------|-----|---------|-------------|--------|
| It's Nice That | itsnicethat.com/... | Campaign coverage | 8 | TO CAPTURE |
| ... | | | | |

## TIER 3 — Campaign Press
[same format]

## TIER 4 — Brand Assets
| Source | URL | Content | Est. Images | Status |
|--------|-----|---------|-------------|--------|
| Notion Press | notion.com/press | Press kit | 6 | TO CAPTURE |
| ... | | | | |

## TIER 5 — Social
[same format]

## NOT FOUND / BLOCKED
- [Agency/Source]: No results found / Access blocked / Brand not in portfolio

## CAPTURE PLAN (present this to human before downloading)
Priority order for capture:
1. [Highest value source] — [why]
2. ...

Estimated total new images: X
```

---

## After Human Approval

Once the source list is reviewed and approved, run the CAPTURE phase:
- Download from each approved source in priority order
- Reject anything below 800px wide
- Reject baked-in rounded corners
- Name files with source prefix: `[agency]-*.jpg`, `press-*.jpg`, `web-ig-*.jpg`, `social-yt-*.jpg`
- Compress: `node scripts/images/compress-images.js [assets-dir]`
- Remove `.backup` files after compression
