# /reference-ads

> Generate ad creatives using the client's OWN existing designs from Google Drive as style references for Krea.ai.


# /reference-ads

Generate production-ready ad creatives by cloning the visual style of the client's existing designs. Instead of building from templates (like `/static-ad-generator`), this skill browses the client's Google Drive folder, uses vision to pick the best 2-3 existing designs as references, and passes them to Krea.ai so the output matches the actual brand identity — colors, typography, composition, mood.

**vs `/static-ad-generator`:** static-ad-generator uses 40 pre-built prompt templates and writes everything from scratch. Good for clients with no design history. reference-ads uses the client's OWN designs as the creative template — good for clients where the design team has already established a visual language.

**vs `/krea-create-images`:** krea-create-images requires the user to manually provide a reference URL. reference-ads automates the entire reference discovery flow — browse Drive, evaluate candidates, pick the best, upload as public URLs, build the prompts.

**With `/copywrite`:** Pass `--with-copywriter` to delegate copy generation to the copywriter agent (self-test loop, HR/BS/DE/EN). Without the flag, the skill writes copy inline.

---

## Triggers

- `/reference-ads "ACME Agency"` — full pipeline with 3 concepts (default)
- `/reference-ads "ACME Agency" --concepts 5` — 5 different ad concepts
- `/reference-ads "ACME Agency" --refresh` — force fresh reference selection (ignore cache)
- `/reference-ads "ACME Agency" --ratio 1:1 --batch 2` — square format, 2 variants per concept
- `/reference-ads "ACME Agency" --with-copywriter` — delegate copy to the copywriter agent

---

## Preflight

Run ALL checks before any expensive operations. If ANY check fails, abort with the specific failure.

1. **Client exists** in `ACME Agency/clients/clients.json`. Resolve the canonical key (case-insensitive).
2. **`drive_folder_id` is present and reachable.** Test with a `listFiles()` call. If missing or unreachable → abort: "This skill requires a client with designs in Drive. Use `/static-ad-generator` for template-based generation instead."
3. **`CLIENT.md` exists** at `ACME Agency/clients/<Client>/CLIENT.md`. If missing → warn but continue (reference images provide visual context, and the skill can still work without it).
4. **Krea API key set** in `.env` (`KREA_API_KEY`). If missing → abort.
5. **concepts x batch stays sane**: `concepts * batch <= 16`. If higher → require explicit confirmation.
6. **Slack channel resolves** via `getClientChannel()`. Skip Slack cleanly if bot not invited.
7. **Disk space**: at least 200 MB free in the local client folder.

If all checks pass, log: "preflight: OK (<client>, <concepts> concepts x <batch> batch = <total> images, ratio <ratio>)"

---

## Phase 1 — Reference Discovery & Selection

**Goal:** Find the client's best 2-3 existing designs in Drive and prepare them as Krea reference images.

### Step 1.1 — Check cache

Look for `ACME Agency/clients/<Client>/reference_selection.json`. If it exists:
- Parse it. Check `selected_at` timestamp.
- If same calendar month AND `--refresh` was NOT passed → skip to Step 1.6 (reuse cached references).
- If different month OR `--refresh` was passed → continue to Step 1.2 (fresh selection).

### Step 1.2 — Browse Drive folder

Use `google_drive.mjs` to recursively discover design images:

```javascript
node --input-type=module <<'EOF'
import { listFiles, downloadFile } from './ACME Agency/scripts/lib/google_drive.mjs';
import { mkdir } from 'fs/promises';

const FOLDER_ID = '<drive_folder_id>';
const CLIENT = '<ClientName>';

// List top-level contents
const topLevel = await listFiles(FOLDER_ID);
console.log(`Top-level: ${topLevel.length} items`);

// Find design-related subfolders (max depth 2)
const DESIGN_NAMES = /social.?media|dizajn|design|kreativ|galerij|gallery|oglas|ads|vizual/i;
const designFolders = topLevel.filter(f =>
  f.mimeType.includes('folder') && DESIGN_NAMES.test(f.name)
);

// Collect image files from design folders + root
let allImages = [];

// Root-level images
const rootImages = (await listFiles(FOLDER_ID, { mimeType: 'image' }))
  .filter(f => !f.name.startsWith('.'));
allImages.push(...rootImages);

// Subfolder images (up to depth 2)
for (const folder of designFolders) {
  const subItems = await listFiles(folder.id);
  // Direct images in this folder
  const images = subItems.filter(f => f.mimeType.startsWith('image/'));
  allImages.push(...images);

  // Go one level deeper (e.g. Social media design/Croatia/2026/)
  const subFolders = subItems.filter(f => f.mimeType.includes('folder'));
  for (const sf of subFolders.slice(0, 5)) {
    const deepImages = await listFiles(sf.id, { mimeType: 'image' });
    allImages.push(...deepImages.slice(0, 10));
  }
}

// Deduplicate by ID, sort by modifiedTime desc
const seen = new Set();
allImages = allImages.filter(f => {
  if (seen.has(f.id)) return false;
  seen.add(f.id);
  return true;
}).sort((a, b) => new Date(b.modifiedTime) - new Date(a.modifiedTime));

// Filter to last 60 days
const cutoff = Date.now() - 60 * 24 * 60 * 60 * 1000;
const recent = allImages.filter(f => new Date(f.modifiedTime).getTime() > cutoff);

console.log(`Found ${recent.length} images from the last 60 days`);

// Take top 10 candidates
const candidates = recent.slice(0, 10);

// Download to ref-candidates/
await mkdir(`ACME Agency/clients/${CLIENT}/ref-candidates`, { recursive: true });
for (const img of candidates) {
  const ext = img.name.split('.').pop() || 'png';
  const dest = `ACME Agency/clients/${CLIENT}/ref-candidates/${img.id}.${ext}`;
  await downloadFile(img.id, dest);
  console.log(`Downloaded: ${img.name} (${img.modifiedTime})`);
}
EOF
```

**If zero images found:** Abort with: "No recent designs found in <Client>'s Drive folder (last 60 days). Use `/static-ad-generator` for template-based generation instead."

**If fewer than 3 images found:** Continue with what's available — even 1 reference is better than none.

### Step 1.3 — Vision evaluation

Read each downloaded candidate image with Claude vision. For each, evaluate on a 1-10 scale:

| Criterion | What to look for |
|-----------|------------------|
| **Production quality** | Professional finish, not a rough draft, screenshot, or meme. Clean edges, proper resolution. |
| **Brand consistency** | Uses consistent colors, typography, logo placement. Looks like it belongs to the same brand. |
| **Composition** | Well-structured for an ad format. Clear visual hierarchy, not cluttered. |
| **Style clarity** | Has a clear, replicable visual style that Krea can clone. Not a generic stock photo. |
| **Brief relevance** | (Only if campaign brief provided) Relates to the product/service/concept being advertised. |

**Scoring:**
- Score each criterion 1-10
- Compute average
- Rank all candidates by average score
- **Penalize heavily:** images with lots of overlaid text (Krea will try to clone the text layout, which breaks), screenshots of other platforms, low-resolution images, images that are clearly logos/icons (not full ad designs)

### Step 1.4 — Select top references

Pick the top 2-3 images. Log the selection with reasoning:

```
Reference selection for <Client>:
1. <filename> (modified <date>) — score 9.2 — clean layout, strong brand colors, professional product shot
2. <filename> (modified <date>) — score 8.8 — good typography, relevant to campaign brief
3. <filename> (modified <date>) — score 8.5 — consistent brand style, good composition
```

### Step 1.5 — Upload as public URLs

For each selected reference, upload to Drive with public access:

```javascript
node --input-type=module <<'EOF'
import { uploadPublic } from './ACME Agency/scripts/lib/google_drive.mjs';
import { readFile, writeFile } from 'fs/promises';

const CLIENT = '<ClientName>';
const FOLDER_ID = '<drive_folder_id>';

const refs = [
  { local: 'ACME Agency/clients/<Client>/ref-candidates/<id1>.png', tag: 'ref-style-1' },
  { local: 'ACME Agency/clients/<Client>/ref-candidates/<id2>.png', tag: 'ref-style-2' },
  { local: 'ACME Agency/clients/<Client>/ref-candidates/<id3>.png', tag: 'ref-style-3' },
];

const urls = {};
for (const r of refs) {
  const url = await uploadPublic(r.local, FOLDER_ID, `${r.tag}.png`);
  urls[r.tag] = url;
  console.log(`${r.tag}: ${url}`);
}

// Update clients.json reference_assets
const registryPath = 'ACME Agency/clients/clients.json';
const registry = JSON.parse(await readFile(registryPath, 'utf8'));
const clientKey = Object.keys(registry.clients).find(k => k.toLowerCase() === CLIENT.toLowerCase());
if (!registry.clients[clientKey].reference_assets) registry.clients[clientKey].reference_assets = {};
Object.assign(registry.clients[clientKey].reference_assets, urls);
await writeFile(registryPath, JSON.stringify(registry, null, 2));
console.log('Updated clients.json reference_assets');
EOF
```

### Step 1.6 — Cache selection

Save `ACME Agency/clients/<Client>/reference_selection.json`:

```json
{
  "selected_at": "2026-04-13T10:30:00Z",
  "client": "ClientName",
  "method": "vision-scored",
  "references": [
    {
      "drive_file_id": "...",
      "name": "original-filename.png",
      "score": 9.2,
      "score_breakdown": { "quality": 9, "brand": 10, "composition": 9, "style": 9, "relevance": 9 },
      "public_url": "https://drive.google.com/uc?id=...",
      "local_path": "ACME Agency/clients/<Client>/ref-candidates/<id>.png",
      "tag": "ref-style-1"
    }
  ]
}
```

---

## Phase 2 — Prompt + Copy Construction

**Goal:** Build Krea prompts that describe each ad concept while instructing Krea to clone the reference style. Write the ad copy for each concept.

### Step 2.1 — Deep reference analysis

Read the selected reference images again with vision and extract a detailed style profile:

- **Color palette:** Dominant colors, accent colors, background treatment (gradient/solid/textured)
- **Typography style:** Weight (bold/light), case (uppercase/mixed), placement (top/center/bottom), approximate size relative to image
- **Layout pattern:** Where's the product/hero shot? Where's the text? How much whitespace?
- **Mood:** Professional/warm/energetic/minimal/luxurious/clinical
- **Brand elements:** Logo placement and size, any recurring visual motifs

Compile this into a **style brief** — a 3-5 sentence summary that can be prepended to every Krea prompt. Example:

> "Deep purple gradient background with gold accent text. Bold white uppercase headlines at top, product mockup centered. Clean professional composition with ample breathing room. Logo bottom-right, small. Mood: confident, premium but approachable."

### Step 2.2 — Build concepts

For each concept (default 3, configurable via `--concepts`):

1. **Define the concept angle** based on the campaign brief:
   - What product/service/offer is being advertised?
   - What's the unique angle for this specific concept? (testimonial, direct pitch, problem-solution, stat/authority, lifestyle, event/deadline)
   - What should the image SHOW? (product, person, environment, abstract)

2. **Write the ad copy** for this concept:
   - **Headline** for the image overlay (max 8 words, punchy, benefit-driven)
   - **Accent word** (1-2 words in a contrasting color for emphasis, usually the key benefit)
   - **CTA text** (button or bottom text: "Saznajte vise", "Kontaktirajte nas", etc.)
   - **Primary text** (the text that goes below the image in Meta — 2-3 paragraphs, conversational, follows Croatian/Bosnian copywriting rules from CLAUDE.md)
   - **Description** (one-liner for Meta link description field)

   If `--with-copywriter` was passed, delegate to the copywriter agent (Task tool, subagent_type: "copywriter") with the concept details and CLIENT.md context.

3. **Build the Krea prompt** by combining:
   - The style brief from Step 2.1 (prepended to every prompt)
   - The concept description (what should be in the image)
   - Image overlay text placement instructions (from the copy)
   - CLIENT.md brand details if available (exact hex colors, logo description)
   - Client market cue ("Croatian market", "Bosnian market", "German market")

   **Prompt structure:**
   ```
   [STYLE BRIEF from Step 2.1]

   Modern [aspect_ratio] advertisement for [client business description].
   [Concept description: what's in the image, the scene, the subject, the mood].

   Text overlay: bold [uppercase/mixed] headline at [position] reading "[HEADLINE TEXT]"
   with the word "[ACCENT WORD]" in [accent color].
   [CTA placement]: "[CTA TEXT]" in [style].
   Logo [position], [size].

   Style: match the visual style, color palette, typography weight, and composition of the reference images.
   Clean, professional, high-quality advertising creative.
   ```

### Step 2.3 — Save prompts JSON

Save to `ACME Agency/clients/<ClientName>/static_ads_prompts.json` in the standard format that `static_ads_generate.mjs` reads:

```json
{
  "client": "ClientName",
  "generated_at": "2026-04-13T10:45:00Z",
  "brand_dna_version": "reference-ads",
  "input_mode": "reference",
  "campaign": "Campaign description from brief",
  "prompts": [
    {
      "template_number": 1,
      "template_name": "direct-pitch",
      "prompt": "Deep purple gradient background matching reference style...",
      "aspect_ratio": "4:5",
      "reference_tags": ["ref-style-1", "ref-style-2", "ref-style-3"],
      "notes": "Copy: Headline='BRENDIRANJE ZA VAS PORTAL', CTA='POSALJITE UPIT'"
    },
    {
      "template_number": 2,
      "template_name": "testimonial",
      "prompt": "...",
      "aspect_ratio": "4:5",
      "reference_tags": ["ref-style-1", "ref-style-2", "ref-style-3"],
      "notes": "..."
    }
  ]
}
```

**Key:** Every prompt uses the SAME `reference_tags` — all point to the selected reference designs. This is what makes every generated image match the client's existing style.

Show the user a summary table before Phase 3:

```
Concepts for <Client>:
| # | Name           | Headline                      | Ratio | Refs |
|---|----------------|-------------------------------|-------|------|
| 1 | direct-pitch   | BRENDIRANJE ZA VAS PORTAL     | 4:5   | 3    |
| 2 | testimonial    | ZADOVOLJNI KLIJENTI           | 4:5   | 3    |
| 3 | problem-solve  | ZASTO NAM VJERUJU             | 4:5   | 3    |

Total: 3 images (3 concepts x 1 batch). Ready to generate?
```

---

## Phase 3 — Generation

**Goal:** Run batch generation via the existing pipeline.

### Step 3.1 — Verify reference_assets

Before generating, confirm `clients.json > reference_assets` has all the `ref-style-*` keys that the prompts reference:

```javascript
node --input-type=module <<'EOF'
import { readFile } from 'fs/promises';
const reg = JSON.parse(await readFile('ACME Agency/clients/clients.json', 'utf8'));
const client = reg.clients['<ClientName>'];
const assets = client.reference_assets || {};
for (const tag of ['ref-style-1', 'ref-style-2', 'ref-style-3']) {
  console.log(`${tag}: ${assets[tag] || 'MISSING'}`);
}
EOF
```

If any are missing → abort. Something went wrong in Phase 1.

### Step 3.2 — Run static_ads_generate.mjs

```bash
node ACME Agency/scripts/static_ads_generate.mjs "<ClientName>" --batch <batch>
```

The script:
1. Reads `static_ads_prompts.json`
2. For each prompt, maps `reference_tags` to `reference_assets` URLs
3. **Auto-prepends the client logo** (via `ensureClientLogo()`) as the first reference and augments the prompt with a "logo is canonical" instruction. The logo is added on top of your selected `ref-style-*` references, not in place of them.
4. Calls `generateAndDownload()` with the reference URLs as `imageUrls`
5. Uploads all generated images to Drive (nested folder structure)
6. Posts ONE consolidated Slack report
7. Saves manifest to `static_ads_manifest.json`

**Do NOT call `krea_create_images.mjs` in a loop.** The whole point of this skill is to use the batch pipeline for consolidated output.

---

## Phase 4 — Delivery & Verification

### Step 4.1 — Verify output

Check:
- [ ] Total images generated = concepts x batch (no silent skips)
- [ ] Every local file exists and is > 10KB
- [ ] Drive URLs match local count
- [ ] `static_ads_manifest.json` has a new entry with today's timestamp
- [ ] Reference images were actually passed to Krea (check manifest for `imageUrls` or look at script logs)
- [ ] Slack report was posted successfully (if `--no-slack` was not passed)

### Step 4.2 — Post copy to Slack thread

If ad copy was generated in Phase 2, post it as a threaded reply to the Slack report:

```
*Ad Copy — <Client> — <Campaign>*

*Concept 1: direct-pitch*
Headline: BRENDIRANJE ZA VAS PORTAL
Primary text: [full primary text]
CTA: POSALJITE UPIT

*Concept 2: testimonial*
...
```

---

## Phase 5 — Iteration

If the user wants changes:

- **Different references:** Run with `--refresh` to re-browse Drive and pick new references
- **More/fewer concepts:** Run with `--concepts N`
- **Different copy:** Edit `static_ads_prompts.json` directly, then re-run Phase 3 only with `node ACME Agency/scripts/static_ads_generate.mjs "<Client>" --batch 1`
- **Different ratio:** Run with `--ratio 1:1` (or `9:16`, `16:9`)
- **Higher quality:** Run with `--resolution 4K` and `--batch 2` for more variants

---

## Key Files

| File | Purpose |
|------|---------|
| `ACME Agency/clients/clients.json` | Client registry — `drive_folder_id`, `reference_assets`, `slack_channel` |
| `ACME Agency/clients/<Client>/CLIENT.md` | Brand context (optional but improves quality) |
| `ACME Agency/clients/<Client>/reference_selection.json` | Cached reference selection (vision scores, URLs) |
| `ACME Agency/clients/<Client>/static_ads_prompts.json` | Prompts JSON consumed by `static_ads_generate.mjs` |
| `ACME Agency/clients/<Client>/static_ads_manifest.json` | Generation manifest (written by `static_ads_generate.mjs`) |
| `ACME Agency/clients/<Client>/ref-candidates/` | Downloaded reference candidate images |
| `ACME Agency/scripts/static_ads_generate.mjs` | Batch generation engine (Phase 3) |
| `ACME Agency/scripts/lib/google_drive.mjs` | `listFiles`, `downloadFile`, `uploadPublic`, `findOrCreateFolder` |
| `ACME Agency/scripts/lib/krea.mjs` | `generateAndDownload` (via static_ads_generate.mjs) |
| `ACME Agency/scripts/lib/slack.mjs` | `getClientChannel`, `postMessage` |

---

## Tips for Better Output

1. **Fewer text overlays = better results.** Krea is bad at rendering non-Latin text (Croatian diacritics). Keep overlay text minimal (1 headline + 1 CTA) and plan to add text in post-production if needed.
2. **Reference quality matters more than quantity.** 2 excellent references beat 5 mediocre ones. Prefer clean, professional designs over busy social media posts.
3. **Same ratio as references.** If the reference designs are 1:1 squares, generate 1:1. Krea clones composition better when the aspect ratio matches.
4. **Run with `--batch 2`** on first attempts — gives you 2 variants per concept so you can pick the better one.
5. **The style brief is critical.** Spend time on Step 2.1 — a precise style description (exact colors, exact typography weight, exact layout) produces dramatically better Krea output than a vague "match the style."
