Skills · UGC niches

fb-creatives

/fb-creatives

How to make an N-creative FB / Meta / IG static ad pack for a real brand — generalized niche know-how, not one specific ad.

UGC nichesnicheuser
SKILL.md

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 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.
  • 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 artifacts/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 artifacts/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.
  • --ref artifacts/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

SetRegisterDefault conceptsModel
A — real peoplephotoreal candid portraits / testimonials with pull-quote4-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 pillopenai/gpt-5.4-image-2
B — graphic / typographywordmark posters, price-stack with strikethrough, data-viz bar chart, code-card4-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 / dashboardscreenshot-flavored proof shots: dashboard tile, code-card output, before-after4-6 receipts: "we tested all of them", "1 PDF → 1 API call → clean markdown"openai/gpt-5.4-image-2
D — memememe-header on a brand-tinted canvas, dunk-on-competitor, "POV: …"2-4; meme should ladder back to one product claim, not genericopenai/gpt-5.4-image-2
E — niche audiencetargeted 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 copyopenai/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 artifacts/refs/research.md (the digest), artifacts/refs/tokens.json (CSS hex), artifacts/refs/hero.png (Playwright screenshot), and an enumerated "Documented API surfaces" list (curl / Python / TS / GUI).
  2. Read artifacts/refs/research.md — never sketch brand-DNA from memory.
  3. Write brand-dna.md with REAL hex values from artifacts/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 artifacts/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 artifacts/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 + artifacts/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 artifacts/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 importmust 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 artifacts/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

# Site-grounding sub-agent (dispatched via Agent tool — see site-grounding.md
# for the full prompt template). Output lands at artifacts/refs/research.md + artifacts/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 artifacts/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 artifacts/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 — why this is a skill and not a template.
  • docs/playbooks/site-grounding.md — the Playwright sub-agent prompt template (mandatory T1 step).
  • docs/playbooks/intake.md — the creative-pack branch of intake.
  • 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: .ralphy/workspaces/<ws>/projects/sotaocr-fb-001/postmortem/ — the lessons + matrix this skill codifies.