How to make an N-creative FB / Meta / IG static ad pack for a real brand — generalized niche know-how, not one specific ad. A domain overlay on the standard pipeline: supplies the 5-set creative matrix (A real-people · B graphic / typography · C proof / data-viz · D meme · E niche-audience), the site-grounding pre-flight (curl CSS hex + Playwright hero screenshot used as `--ref` on every gen), the true-parallel batch shape on `openai/gpt-5.4-image-2`, the per-set prompt cookbook (testimonial ...
Scanned 6/1/2026
Install via CLI
openskills install alecs5am/ralphy---
name: fb-creatives
namespace: user
description: >-
How to make an N-creative FB / Meta / IG static ad pack for a real brand — generalized niche know-how, not one specific ad. A domain overlay on the standard pipeline: supplies the 5-set creative matrix (A real-people · B graphic / typography · C proof / data-viz · D meme · E niche-audience), the site-grounding pre-flight (curl CSS hex + Playwright hero screenshot used as `--ref` on every gen), the true-parallel batch shape on `openai/gpt-5.4-image-2`, the per-set prompt cookbook (testimonial portrait, code-card poster, strikethrough price stack, horizontal bar chart, meme header), and the deliverable folder layout (numbered PNGs + `ads-copy.md` + `README.md`). Works for ANY brand the user names — a SaaS dev tool, a DTC product, a B2B service — the skill supplies the matrix know-how, the user supplies the brand + URL.
USE WHEN the user asks for an "ad pack", "32 creatives", "FB / Meta / IG ads", "creative matrix", "set of static ads", "performance creatives for <brand>", with N ≥ 4 stills and a single concrete brand / site.
This is a niche SKILL (generalized), not a remix TEMPLATE. For "remix this exact ad but swap X", that is the remix path in docs/skills-vs-templates.md. For a single poster, use /poster.
---
## Trigger
**FIRES** on a generic N-creative ad-pack brief: "make 32 FB creatives for <brand>", "ad pack for <site>", "set of Meta ads", "creative matrix", "8-10 static ads for IG feed", "performance creatives for our cold-traffic campaign". Any brand, any vertical — the skill is brand-agnostic.
**DO NOT FIRE** when:
- The brief is for ONE still (poster, drop graphic, hero image) → use [`/poster`](../poster/SKILL.md) instead.
- The brief is for a moving video (UGC / unboxing / talking-head) → match the matching `/ralphy-ugc-*` skill.
- The user points at one specific ad to reproduce (`@template:<slug>`, "remix this exact ad") → that is the **remix path**. See [`docs/skills-vs-templates.md`](../../../docs/skills-vs-templates.md).
- The user pasted `@guideline:<slug>` for a register the pack sits in (photoreal humans, anti-AI-slop) → run `ralphy guideline show <slug>` first and fold its rules into the A-set portrait prompts.
## What this skill is
A generalized matrix overlay, not a finished ad pack. It does not name a brand, a hero, a price, or a number — it tells the art-director HOW a multi-register static ad pack is built so a strong one comes out for whatever the user is promoting. It runs **through** `ralphy generate image`; it does not bypass the reference-required gate or the site-grounding invariant.
## Hard invariants
- All generation routes through `ralphy generate image` (no raw API). Read `MODELS.md` before naming any model id — the stack below is a default, not a hardcode.
- **Real-brand pre-flight: site-grounding before ANY prompt.** When the brief names a real brand URL, **dispatch a Playwright sub-agent** to crawl home + `/docs` + `/pricing` + `/features` + `/examples` BEFORE drafting brand-DNA. Read `refs/research.md` (the sub-agent's digest), not a single `WebFetch` of the home page. Every palette hex in a prompt must trace to `refs/tokens.json`; every named API symbol in code-creative slots must trace to "Documented API surfaces" in `research.md`. Skipping this cost `sotaocr-fb-001` $1.20 (wrong-palette v1 burn) + 5/32 hallucinated-Python-SDK creatives. Full discipline: [`docs/playbooks/site-grounding.md`](../../../docs/playbooks/site-grounding.md).
- **`--ref refs/hero.png` on EVERY gen.** Once captured, pass the live-site hero screenshot as `--ref` on all N creatives. Brand-palette + type drift across the pack drops to near zero. Without it, each prompt re-interprets "blue CTA" slightly differently — at 32 concepts the drift compounds.
- **Verify SDK / API surface before any code-creative.** If the C / E sets render code on screen, the named API symbol (`import foo`, `foo.parse()`) must exist on the brand's docs. If the landing only documents curl, the ad shows curl — not an invented Python wrapper. Curl is the strictly-safe fallback for HTTP APIs.
- **Append-only on regen.** Re-rolling a slot writes `.v2.png`, never overwrites. Failed / dark-bg v1 generations stay on disk as A/B reference.
- The reference-required gate still fires for **named real persons / IPs** in the A or D set — refuse without a ref or logged `--no-ref-consent`.
- The quality gate refuses, not warns — two failed `scoreImage` in a row → stop and report options.
## The niche, in one paragraph
An N-creative FB pack lives or dies on **brand consistency across distinct registers**. Ads-Manager wants 8-32 visually-distinct creatives to feed its A/B engine, but every one must read as the same brand at thumb-stop speed. The 5-set matrix gives the campaign 5 register-buckets (real people, typography, proof / data-viz, meme, niche-audience), each with 2-8 concepts inside; site-grounding + a `--ref hero.png` glue holds the brand together across all of them. The pack ships as numbered PNGs + a `ads-copy.md` (primary text / headline / description / CTA per creative) + an Ads-Manager-grouping `README.md`.
## The 5-set creative matrix
| Set | Register | Default concepts | Model |
|---|---|---|---|
| **A — real people** | photoreal candid portraits / testimonials with pull-quote | 4-9 diverse personas (age / ethnicity / wardrobe / setting); each is a pull-quote card layout: photo block + slate-900 quote + blue accent + emerald supporting-stat + CTA pill | `openai/gpt-5.4-image-2` |
| **B — graphic / typography** | wordmark posters, price-stack with strikethrough, data-viz bar chart, code-card | 4-8 visual hooks anchored on a *specific number* from the lander ("$0.003", "5× cheaper", "13 points more accurate") | `openai/gpt-5.4-image-2` |
| **C — proof / dashboard** | screenshot-flavored proof shots: dashboard tile, code-card output, before-after | 4-6 receipts: "we tested all of them", "1 PDF → 1 API call → clean markdown" | `openai/gpt-5.4-image-2` |
| **D — meme** | meme-header on a brand-tinted canvas, dunk-on-competitor, "POV: …" | 2-4; meme should ladder back to one product claim, not generic | `openai/gpt-5.4-image-2` |
| **E — niche audience** | targeted to one persona segment (indie hacker, AI engineer, ops lead, finance ops) | 2-6 segment-specific concepts; can reuse A / B / C templates with niche copy | `openai/gpt-5.4-image-2` |
The matrix scales: 8-12 starter A/B pack → 24-32 full matrix → 40+ broad-spectrum. Default mix for a 32-pack: A=9, B=8, C=7, D=4, E=4.
## Site-grounding (the T1 step)
Before writing any prompt:
1. **Dispatch sub-agent** (via `Agent` tool, `subagent_type: "general-purpose"`) to crawl home + `/docs` + `/pricing` + `/features` + `/examples` + `/blog`. Sub-agent returns `refs/research.md` (the digest), `refs/tokens.json` (CSS hex), `refs/hero.png` (Playwright screenshot), and an enumerated "Documented API surfaces" list (curl / Python / TS / GUI).
2. **Read `refs/research.md`** — never sketch brand-DNA from memory.
3. **Write `brand-dna.md`** with REAL hex values from `refs/tokens.json`, the real type stack, the real CTA color, the real hero claims.
4. **Lock the voice register** at intake (dev-honest / marketing-punchy / mix). Anchor every prompt on a *specific number* from the lander.
## Workflow
1. **Intake.** Run the creative-pack branch of intake (aspect for placements: 4:5 FB feed / 1:1 IG feed / 9:16 Stories / mix; pack size; sets to cover; brand site URL — REQUIRED; voice register; hard no's).
2. **Site-grounding.** Dispatch the Playwright sub-agent (see above). Read `refs/research.md`. Write `brand-dna.md`.
3. **Concept matrix.** Draft the 5-set scaffold; pick the N concepts the user wants. Surface the matrix in chat; get explicit "go".
4. **Prompt scaffold.** One `prompts/<slot>.txt` per concept. Each cites brand-DNA hex verbatim, names a specific photographic spec (camera/lens/grain for A-set, syntax-color spec for code-cards in B/C), includes a ban-negative for known failure modes (beauty filter, plastic skin, missing strikethrough, dark background when site is light).
5. **Generate — TRUE PARALLEL via bash `&`.** `gpt-5.4-image-2` validated for 23-concurrent (sotaocr-fb-001, 2026-05-29). NOT `ralphy queue` — the daemon was idle on 13 jobs that session. Each gen passes `--ref refs/hero.png`.
6. **Review + iterate.** Read all PNGs inline. Re-roll only mis-rendered slots (not the whole batch). Auto-versioning preserves v1.
7. **Deliverable.** `final/` with numbered prefix, `ads-copy.md` (primary text · headline · description · CTA × N), `README.md` with the concept-by-concept table + Ads-Manager ad-set grouping (real-people / diverse-personas / numbers / editorial-graphic / proof-dashboard / code / meme).
8. **Hand off** to `/evaluator` if the user wants a quality gate before delivery.
## Default model stack (verify against MODELS.md)
- **Default — `openai/gpt-5.4-image-2`.** Production-grade parallel (validated 23-concurrent at $0.20/img). Crisp typography (the wordmarks, price stacks, code-cards, syntax coloring). Use for all 5 sets. Aspect via `--size` (FB feed `--size 1080x1350`, IG feed `--size 1080x1080`, Stories `--size 1080x1920`).
- **Fallback — `google/gemini-3-pro-image-preview`.** Faster, cheaper, tolerates ≥4 concurrent, but smudges small embedded typography. Use ONLY for fast palette/composition exploration; finalize on gpt-image.
## Failure modes
- **Brand-DNA invented from memory** (dark-bg + orange when site is white + blue). Cost on sotaocr-fb-001: $1.20 + 12 min. Prevention: site-grounding sub-agent + `refs/hero.png` on T1.
- **Believing stale "cap=1 concurrent" memory on gpt-image** → 25 min wasted on a serial loop. Prevention: 2× parallel probe before architecting any batch shape; gpt-5.4-image-2 is production-grade parallel as of 2026-05-29.
- **`ralphy queue` daemon idle on pending jobs.** Use bash `&` fan-out, not `--queue`, for ad-hoc N-image batches until the daemon is reliable.
- **Hallucinated SDK in code-creatives.** Model auto-completes Python ergonomics from training prior even when brand only ships curl. Verify every named symbol against `refs/research.md` "Documented API surfaces"; fall back to curl when SDK unverified.
- **Generic "Better X for Y" copy.** Cold-traffic FB copy lands when anchored on a specific lander number. Always anchor each headline on one verifiable claim from `brand-dna.md`.
- **A-set portraits going beauty-filter editorial.** Without "naturalistic, NOT glossy" + camera/lens spec + named imperfection in the body, gpt-image defaults to fashion-magazine glaze. See the A-set cookbook below.
- **Missing strikethrough policy in price stack.** Without an explicit anti-token, gpt-image sometimes applies the strikethrough uniformly across rows. Always state row-by-row policy + negative "strikethrough on the brand row".
## Aspect ratio
`--size` is honored by gpt-image as of `loud-kids-poster-001` (lands on nearest native bucket). Defaults:
- FB feed → `--size 1080x1350` (4:5)
- IG feed → `--size 1080x1080` (1:1)
- Stories → `--size 1080x1920` (9:16)
- Mix → fan out separately per placement, do not auto-crop.
## Cookbook
### A-set — real-people testimonial (validated on sotaocr-fb-001 A2/A6/A7/A9)
```
LAYOUT (top to bottom):
1. PHOTO BLOCK (52% height): Rounded 24px-radius photograph filling width with 5% margin.
CONTENTS: a photoreal candid portrait of <persona> — <2-3 specific features:
age, ethnicity, hair, wardrobe>. Natural skin texture with visible pores,
<named imperfection: mole / asymmetry / stubble>, slight facial asymmetry.
<Setting + lighting>. Sony A7 IV, Sigma 85mm at f/2.0, Kodak Portra 400 grain,
naturalistic, NOT glossy.
2. QUOTE CARD (30% height): Pure white panel, 88% width, thin border, soft shadow.
- Pull-quote slate-900 Inter Medium ~52pt, slight italic, blue <ACCENT> open-quote glyph
- Attribution slate-400 Inter Regular ~26pt
- Below, emerald #10B981 Inter SemiBold supporting stat
3. CTA + URL FOOTER (18%): Blue <ACCENT> pill + slate-400 sub-line.
Negative: dark background, orange accent, plastic skin, beauty filter, AI fingers,
perfect teeth, frozen expression, fashion-editorial pose.
```
Key tokens: **"naturalistic, NOT glossy"** + **camera + lens + grain spec** + **named imperfection in the body**.
### B-set — price-stack with strikethrough (validated on B4/B8)
```
PRICE STACK (50% height): Four large rows stacked vertically with generous spacing.
Each row: vendor name (left, slate-900 Inter Medium ~36pt), large price
(right, Inter Black ~64pt). Vendors with strikethrough have a 4px red #DC2626
line running cleanly through the ENTIRE row (label + price) horizontally at
vertical center. The <BRAND> row has NO strikethrough and uses emerald #10B981
for the price.
Row 1: "<Competitor 1>" — "<price>" (with red strikethrough through both)
...
Row 4: "<BRAND>" — "<price>" (NO strikethrough, emerald price, small "←" arrow)
Negative: strikethrough on the <BRAND> row, missing strikethrough on the
competitor rows, broken/wavy/dashed strikethrough lines.
```
Key tokens: explicit row-by-row spec + **explicit anti-token "strikethrough on the BRAND row"**.
### B / C / E — code-card (validated on B3/C7/E3)
```
CODE CARD: A floating window-chrome card centered, ~88% canvas width, 25px corner
radius, soft drop shadow. macOS-style window-chrome header with three small
circles (red/amber/emerald), centered title "<file>.py" in JetBrains Mono.
Card body deep navy #0F172A background. Inside, 3-4 lines of crisp monospace
code (JetBrains Mono ~30pt) with line numbers in muted #475569.
Syntax: keywords blue #60A5FA, strings emerald #34D399, comments slate-400 #94A3B8,
variables cream #F1F5F9.
Line 1 (comment): # <one-line value claim>
Line 2: <curl OR import — must match the brand's documented surface>
...
```
Key tokens: **macOS chrome description verbatim** + **explicit syntax-color-per-token mapping** + **line numbers gutter spec**. Verify the named API surface against `refs/research.md`.
### C-set — horizontal bar chart (validated on B2)
```
HORIZONTAL BAR CHART: Four horizontal bars stacked vertically.
Each row has three columns:
- LEFT: brand label, slate-900 Inter Medium ~32pt, left-aligned
- MIDDLE: bar — rounded ends, height ~64px, track #F3F4F6, fill in row color
- RIGHT: percentage, large Inter Bold ~48pt, right-aligned
Rows (top to bottom):
- "<BRAND>" · bar filled emerald #10B981, length 95% · "95%" in emerald
- "<Competitor>" · bar filled slate-400 #9CA3AF, length 82% · "82%" in slate-400
...
```
Key tokens: explicit three-column spec per row + named track + fill colors + named bar length as % of canvas.
## CLI cookbook
```bash
# Site-grounding sub-agent (dispatched via Agent tool — see site-grounding.md
# for the full prompt template). Output lands at refs/research.md + refs/hero.png.
# Per-creative generation — TRUE parallel via bash & fan-out
for slot in a1 a2 a3 b1 b2 b3 c1 c2 c3 d1 d2 e1 e2; do
ralphy generate image --project <id> --slot "$slot" \
--model openai/gpt-5.4-image-2 --size 1080x1350 \
--ref refs/hero.png \
--prompt "$(cat prompts/$slot.txt)" &
done
wait
# Re-roll a single mis-rendered slot (writes .v2.png — append-only)
ralphy generate image --project <id> --slot a5 \
--model openai/gpt-5.4-image-2 --size 1080x1350 \
--ref refs/hero.png \
--prompt "$(cat prompts/a5.txt)"
# Quality gate
ralphy project score <id> --strict
```
At ~$0.20/creative on gpt-image, a 32-pack ≈ **$6.40 / ~25 min** (with site-grounding done first); the sotaocr-fb-001 reference ran $8.00 / ~30 min because of the wrong-palette v1 burn.
## See also
- [`docs/skills-vs-templates.md`](../../../docs/skills-vs-templates.md) — why this is a skill and not a template.
- [`docs/playbooks/site-grounding.md`](../../../docs/playbooks/site-grounding.md) — the Playwright sub-agent prompt template (mandatory T1 step).
- [`docs/playbooks/intake.md`](../../../docs/playbooks/intake.md) — the creative-pack branch of intake.
- [`docs/playbooks/art-director.md`](../../../docs/playbooks/art-director.md) — model picks + ref-anchor flow.
- `MEMORY.md` — anti-ai-slop image prompts, OR parallel gpt-image OK, verify SDK before code-creative, site-grounding before brand-DNA.
- Reference postmortem: `workspace/projects/sotaocr-fb-001/postmortem/` — the lessons + matrix this skill codifies.
No comments yet. Be the first to comment!