---
name: gooseworks-ai/remix-graphic-ad-from-reference
source: https://app.decimal.ai/s/gooseworks-ai-remix-graphic-ad-from-reference@1/SKILL.md
source_sha256: 8156bffc56c5
---

# remix-graphic-ad-from-reference

## Purpose

Given **one reference ad image** + a **target product** + **new copy**, produce a finished static ad
that keeps the reference's *layout and composition* but swaps the product and words for the new brand.
This powers the app's "pick a Pinterest ad you like → get the same ad for your product" flow.

It does **not** invent layouts and it does **not** regenerate the whole scene from scratch. It reads
the reference, then recreates it with GPT Image 2:

- **GPT Image 2 (edit the reference) — ALWAYS use this as the generator.** Run it in **image-edit
 mode on the reference itself** to preserve the layout/composition and swap in the new product +
 copy. This is the engine for EVERY remix (premium look). FAL slug `fal-ai/gpt-image-1/edit-image`.
- **HTML overlay (goose-graphics) — NOT a generation engine.** It is only an optional FINISHING
 step: if GPT bakes garbled/misspelled copy, overlay crisp text on top of the GPT output. Never use
 it as the primary generator — a remix must always be generated by GPT Image 2.


## Inputs

| Input | Required | Notes |
|---|---|---|
| `reference_image` | yes | The ad to recreate (local path or URL). One image. |
| `product` | yes | Target product: a clean product render/photo (PNG/webp). Pull the **real** brand asset; grounding/swapping on it is what keeps the label correct. **If the brand asset is a multi-product lineup, crop to the ONE relevant product first** — the remix grounds on a single clean product per `product_slot` (use `product_images_needed` from the slot map for how many distinct products the layout needs). |
| `copy_changes` | optional | If omitted, **the agent auto-writes it** from the brand pack mapped to the template's `slot_map` (see Phase 0.5). New headline, benefit callouts, social-proof line, discount/badge text. Keep the reference's *structure* (same zones), swap the words. |
| `brand` | recommended | Palette (hex), font, logo/wordmark, voice — from `get_brand_kit` / a `brand-research` pack. |
| `style_source` | optional | **`template` (DEFAULT)** keeps the reference ad's palette/theme; **`brand`** recolours to the brand kit's documented palette. See "Brand grounding" below. The caller sets it (e.g. the user asks to "match my brand colours" → `brand`); absent → `template`. |
| `route_hint` | optional | Engine override. Default is **always `gpt_image_2`**; `html` is only a text-overlay finishing step, never the generator. |
| `aspect` | optional | Inherit from the reference; map to the renderer canvas. Default 4:5 / 1080×1350. |
| `remix_spec` | optional | The precomputed spec from the template library (`slot_map` + `gen_prompt` + `remix_engine`). **If present, SKIP Phase 0 re-analysis** — the slots and prompt are already authored. This is the normal path when remixing a library template. |
| `remix_mode` | from template | `product` (swap a physical product) or `ui` (SaaS/app ad — swap the app screenshot/UI, NEVER insert a product). Tagged on the template. |
| `app_screenshot` | for `ui` mode | The brand's app/UI screenshot to drop into the device frame (used instead of `product` when `remix_mode:ui`). |

## Brand grounding — read the kit, never improvise (do this before generating)

The brand context comes from `get_brand_kit` (structured): `colors` (palette hex), `typography`,
`products[]` (with `imageUrls` + `name`/`description`), `screenshotUrls`, and `referenceImages[]`
(each tagged with `productName` + `kind: "product" | "website_screenshot"`). **Read the full kit, not
a preview.**

### Palette — by `style_source` (default `template`)
**Default to `template`. Use `brand` ONLY when the user explicitly asks** (e.g. "use/match my brand
colours", "make it on-brand"). Do NOT switch to `brand` on your own judgment — keeping the reference's
look is the expected default.
- **`template` (default):** keep the **reference ad's** colours/theme; the brand contributes only its
  product image, logo, and copy/voice — NOT its colours.
- **`brand` (only on explicit user request):** recolour the layout to the brand kit's `colors`
  (primary/accent/bg/text).
- **NEVER invent a colour.** Every colour in the output must come from EITHER the reference
  (`template`) OR the kit's documented `colors` (`brand`). Do **not** pull an accent off the logo, a
  mascot, a product, or "what looks nice." If `style_source: brand` but the kit has no palette, fall
  back to `template` (don't guess). This is the #1 off-brand failure.

### Which image to feature — select from the kit, send ONLY the relevant one(s)
- **Physical-product brand:** the hero is the brand's product. Pick from `referenceImages` where
  `productName` matches the slot's product and `kind` is `"product"` (hero = that product's
  `imageUrls[0]`). Send only that product's image(s) for the slot — **not** all reference images.
- **SaaS / software / app brand** (`brandType` ∈ saas/software/service/app/platform, or
  `remix_mode: ui`): the hero is the brand's **app UI** — use `referenceImages` with
  `kind: "website_screenshot"` (i.e. `screenshotUrls`). **NEVER insert a physical product or a
  mascot** for a SaaS ad. If there is no screenshot, rebrand the existing UI (recolor/logo/copy).
- Don't substitute a mascot/logo for the product unless the brand genuinely has no product/app image
  and the layout's product slot can't be filled — and if so, say so to the user, don't silently swap.

## Composed Atoms

- `goose-graphics` (`skills/design/composites/goose-graphics`) — renders the HTML-overlay path to PNG via the goose-graphics Playwright pipeline.
- `create-image-gpt-image-fal` (`skills/ads/capabilities/create-image-gpt-image-fal`) — GPT Image 2, run in **edit mode on the reference** for the photographic path.
- `create-product-images-higgsfield-product-photoshoot` — OPTIONAL: only when no clean product render exists and one must be generated first. Not bundled in goose-skills yet; if absent, require the caller to supply a clean product image.

## Workflow

### Phase 0 — Get the spec (use `remix_spec` if it exists; analyze only if it doesn't)
**If the template carries a `remix_spec` (every library template does), DO NOT re-analyze the image.**
Read it directly:
- `remix_spec.slot_map.text_slots` → the text fields to replace (each has `id`, `role`, and the
 reference's current text). Map the brand's `copy_changes` onto these slots by `id`/`role`.
- `remix_spec.slot_map.product_images_needed` + `product_slots` → how many brand product images to ask
 for and where each goes. Cut each out with `scripts/cutout_product.py`.
- `remix_spec.slot_map.logo_slots` / `decorations` → logo placement + arrows/badges to reproduce.
- `remix_spec.gen_prompt` → the ready, real-product-locked GPT prompt (fill its `{{placeholders}}`).
- `remix_spec.remix_engine` → the engine to use (skip Phase 1 routing).

**Only if there is no `remix_spec`** (a brand-new, un-tagged reference): view it at full res and write a
one-paragraph anatomy (background, product placement, every text zone, palette, font) — i.e. produce a
`remix_spec` on the fly. Prefer running the template through the triage tagger first so this is cached.

### Phase 0.5 — Author the copy (agent auto-writes; user can revise)
If `copy_changes` is supplied, use it. **Otherwise the agent writes it** — read the brand pack
(voice/tone, value-props, never-say) and map onto `remix_spec.slot_map.text_slots`: one on-brand line
per slot, matching each slot's `role` and keeping length close to the reference's current text so it
fits the layout. Respect never-say / no-competitor / no-unverifiable-claims. Write one line for **every text slot the reference has** (no more, no fewer) — these fill the `gen_prompt` `{{text_slots}}` block. **Add no text the reference doesn't have, drop none it does**; if an area has no text in the reference, add none. The output is an exact copy of the reference differing only in product, theme/colour, and the words.
**Versioning:** show the drafted copy; on user feedback, regenerate a **v2** (re-author the copy → re-render)
rather than editing pixels. Keep each version.

### Phase 1 — Engine (ALWAYS GPT Image 2)
**Always generate with GPT Image 2** (`fal-ai/gpt-image-1/edit-image`, edit-the-reference mode) — go straight to **Phase 2B**. Do NOT use the HTML-overlay path as the generator, and **ignore `remix_spec.remix_engine` even if it says `html`** — every remix is generated by GPT Image 2 (this is a billed FAL generation via the proxy). Phase 2A (HTML/goose-graphics) is ONLY an optional text-overlay finishing step if GPT bakes wrong copy.

### Phase 2A — HTML-overlay (OPTIONAL text-overlay finishing only — NOT the generator)
1. Cut the product out to a transparent PNG with `scripts/cutout_product.py` (handles palette-transparency
 renders *and* white/solid backgrounds via edge flood-fill — preserves interior white logos).
2. Build one `index.html` from `assets/overlay-template.html`: reproduce the reference's background,
 place the cutout, lay the new copy in the same zones. Arrows = inline SVG; scalloped seals = inline JS
 (template has both). Use the brand font (Google Fonts) + palette.
3. Render via `create-goose-graphics` / the goose-graphics screenshot pipeline:
 `node <goose-graphics>/screenshot/screenshot.js --format <canvas> --input index.html --output render.png --font-delay 1500`.
 Map aspect→canvas: 1080×1080→`carousel`, 1080×1350→`poster`, 1080×1920→`story`. **2:3 (1080×1620) has NO goose-graphics preset** → render at `poster` (1080×1350, nearest) or a standalone 2:3 Playwright canvas; don't hand-edit the vendored renderer.

### Phase 2B — GPT Image 2 path (EDIT the reference, do not regenerate)
1. **Run GPT Image 2 in image-edit mode with the reference ad as the base + the product render** —
 prompt it to *keep the reference's layout, background, camera, lighting, and signature element exactly*
 and only **(a)** replace the product with the attached one (match its label/logo exactly) and
 **(b)** clear the original text.
 ⚠️ **Never generate grounded on the product alone** — that invents a generic new scene and discards
 the reference's composition.
2. **Text:** either let GPT render the new SHORT copy, **or** have it leave clean space and add copy via
 the HTML overlay. **Never stack an HTML text layer on output that already has baked text** — one source.
3. `--aspect_ratio 3:4` (or nearest), `--quality high --resolution 2k`. **If the model returns a small
 image (long edge < ~1080px), upscale to ≥2k before shipping** — AI-path baked text softens at low res
 (a known tradeoff vs the HTML path, which is natively 2×/crisp). GPT edit slug: `fal-ai/gpt-image-1/edit-image` (`image_urls[]`); it caps ~1536px long edge, so upscale to ≥2k via `fal-ai/esrgan`.
4. **Fidelity gate (3 checks, all must pass):** (a) signature element/layout preserved; (b) **EVERY instance
 of the source product is replaced and NO source/competitor brand name, logo, or label survives anywhere**
 in frame (diff full-res output vs reference — a partial swap that leaves a competitor bottle is a brand/
 compliance hazard); (c) output is full-res (long edge ≥ ~2000px) and baked text is sharp. If any fails:
 re-roll GPT on the original reference, or (for text-only failures) overlay the text via goose-graphics
 on top of the GPT image. Reject only if GPT can't preserve the layout at all — never swap to HTML as
 the generator.

### Phase 3 — QC + deliver
Run Quality Checks. Save the master to `finals/`; keep HTML/cutout/prompt + a provenance note in
`working/`. If copy is wrong on a GPT output, switch that ad to the HTML path rather than re-rolling text.

## Decision Rules

**The engine is ALWAYS GPT Image 2 — there is no routing decision.** Generate every remix with
`fal-ai/gpt-image-1/edit-image` in edit-the-reference mode (Phase 2B). The rules below are about
how to run GPT well, not whether to use it.

- **GPT edits the reference, never regenerates from the product alone.** Keep the reference's
  layout, background, camera, and signature element; only swap the product + clear the old text.
- **SaaS/app/software ad → `remix_mode: ui`.** No physical product — swap the **app screenshot/UI**
  into the device frame and rebrand; **NEVER insert a physical product**. If no app screenshot,
  rebrand the existing UI (recolor/logo/copy). Use the UI `gen_prompt` on the template.
- **If GPT bakes garbled/misspelled copy or a wrong price/claim:** re-roll GPT with an explicit
  "render this exact text" prompt; if it still fails, keep the GPT image but **overlay the crisp
  text on top via goose-graphics (Phase 2A)** as a finishing step. Do NOT fall back to HTML as the
  generator — the base image is always GPT.
- **No fear / no competitor-bashing / no unverifiable claims**, even if the reference uses them. Re-skin the hook.
- **Bespoke cinematic / IP-bound references** (specific VFX device, celebrity, brand character) are not remixable — reject.

## Output

- `finals/<slug>_<WxH>.png` — the finished ad (2× device scale on the HTML path → e.g. 2160×2700).
- `working/index.html` + `working/<product>-cutout.png` (HTML path) — editable source for copy/price variants.
- `working/ai-gen/gpt-v1.png` + `working/ai-gen/PROVENANCE.md` (GPT path) — URL, model, prompt, credits.
- A one-line route + cost record.

## Quality Checks

**`Read` the real brand product asset next to the full-res generated output and compare them
directly** — most AI-path failures are product drift you can't catch without the side-by-side:

- **Product shape & size:** the same product at the right proportions and scale — not stretched,
  squashed, bent, oddly cropped, or resized out of proportion vs. the real asset.
- **Product colour:** colours match the real asset — body, cap, packaging, finish, AND any visible
  contents (pill/powder/liquid); no hue shift, wrong shade, or washed-out / oversaturated look. (See
  the "Product internals inherit the reference colour" failure mode.)
- **Text not garbled:** every word on the product label/packaging and in the ad copy is real,
  correctly spelled, and legible — not garbled, melted, doubled, or invented. Discount/price/claim ==
  the intended value.
- **Logo:** if any logo / wordmark appears in the frame, it must be the brand's CORRECT logo — right
  mark, right spelling, undistorted, correct colours. A wrong or mangled logo = fail.
- Layout matches the reference anatomy: same zones, reading order, energy. No colliding text; legible
  at thumbnail size.
- **Brand alignment (per `style_source`):** colours come from the right source — the **reference's**
  palette for `template`, the kit's documented **`colors`** for `brand`. **No invented / off-brand
  colour** (e.g. an accent pulled off a mascot or logo — the #1 failure). Typography = the kit's
  fonts. The featured asset is the brand's **real product** (or **app UI** for SaaS), selected from
  the kit — never a mascot/placeholder standing in for the product.
- View the **full-res** output, not a thumbnail — text errors hide at small sizes.

If any product / text / logo check fails, re-roll the same engine on the **original reference** with an
explicit prompt ("keep the product's exact shape, proportions and colours; render the label text and
logo exactly as in the attached product image; do not distort or restyle them"), or route text/logo-heavy
cards to the HTML path (crisp text + the real logo file placed directly). Don't ship a render whose
product is the wrong size or colour, has garbled text, or shows a wrong / distorted logo.

## Failure Modes

- **AI "changes everything" / drops the reference's signature element.** Cause: generating grounded on
 the product alone. Fix: GPT must **edit the reference**. If it still can't preserve the layout, use HTML
 or reject the reference.
- **Partial swap / residual competitor branding.** The AI replaced only one of several products and left a
 source/competitor bottle, dropper, logo, or label in frame — a brand/compliance hazard, not just a
 fidelity miss. The gen_prompt now says "replace EVERY instance, remove ALL source branding"; still
 verify it in the fidelity gate by diffing against the reference.
- **Product internals inherit the reference (wrong pill/powder/liquid colour).** GPT can keep the
  *reference* product's capsule/powder colour instead of the brand's. Fix: the gen_prompt says match the
  brand image's visible contents — so the brand product image must SHOW the real contents. If the brand's
  actual pill/powder/liquid colour isn't in the research pack or asset, **ASK the user — don't guess.**
- **Hand-held product → hallucinated hand.** Templates where a hand holds/grips the product hallucinate a malformed hand on GPT-edit (HTML can't render a hand either). Only replicable if a real product-in-hand photo is supplied; otherwise reject the template or pick a non-hand layout.
- **Stacking two text layers** (baked text + HTML overlay) = doubled/conflicting copy. Use ONE text source.
- **Bespoke/cinematic/IP references** aren't remixable by product+copy swap — reject, don't attempt.
- **GPT bakes wrong copy/discount.** Don't re-roll more than once for text — overlay the correct text via goose-graphics (Phase 2A) on top of the GPT image; keep GPT as the base.
- **Cutout eats the white logo.** Use edge flood-fill (the helper does this), never a global white→transparent threshold.
- **Product asset is the back of the pack / wrong SKU.** Verify the face before using it.

## Spend Reference

At ~$1 = 21 Higgsfield credits:
- GPT Image 2 (3:4, 2k high): **~7 cr ≈ $0.33** per image — this is the path EVERY remix uses.
- HTML-overlay (goose-graphics): **$0** — only the optional text-overlay finishing step, not a remix on its own.
Research/setup dominates the agent cost for the first ad of a new brand; variants are far cheaper.

## Tests

See `tests/`. Smoke = route + render a known reference→product pair end-to-end and confirm a non-empty
PNG at the right dimensions with correct copy. Verifier: `skills/ads/capabilities/verify-product-image/`.

## Skill Location & Related

`skills/ads/composites/remix-graphic-ad-from-reference/` (goose-skills). Related:
`skills/ads/composites/brand-research` (brand context), `skills/ads/capabilities/create-image-gpt-image-fal`
(GPT Image 2 edit engine), `skills/ads/capabilities/verify-product-image` (QC), and
`skills/design/composites/goose-graphics` (HTML→PNG renderer). The video analog `remix-ad` lives in the
separate ads-video repo.