Recreate a static graphic ad (Pinterest pin, IG/FB feed image, poster) from a reference image, swapping in a new brand's product and new copy while keeping the reference's layout, composition, and visual energy. ALWAYS generated with GPT Image 2 in edit-the-reference mode (fal-ai/gpt-image-1/edit-image, a billed FAL generation); the HTML/goose-graphics overlay is only an optional text-finishing step, never the generator. The static-graphics counterpart to the video remix-ad skill; this is what the app calls when a user picks a reference ad and wants it for their own product.
npx gooseworks install --claude # Then in your agent: /gooseworks <prompt> --skill remix-graphic-ad-from-reference
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:
fal-ai/gpt-image-1/edit-image.| 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). |
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.
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).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.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.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).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.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.
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.
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.
scripts/cutout_product.py (handles palette-transparency
renders and white/solid backgrounds via edge flood-fill — preserves interior white logos).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.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.--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.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.
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.
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.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.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:
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.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.
At ~$1 = 21 Higgsfield credits:
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/.
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.
template (default):* keep the reference ad's colours/theme; the brand contributes only itsbrand (only on explicit user request):* recolour the layout to the brand kit's colorsQC gate for a generated static ad image — verify the file opens, matches the requested dimensions, shows the correct product/subject (right shape, colour, label, logo), and has no garbled text or severe artifacts. Records pass/fail/needs-human in verification.md. Used as the final check in the static ad remix flow before shipping.
Given the path to a finished content-goose ad-run folder, extract everything that defines that ad — recipe shot list, VO script, characters, voices, world, atom-skills, master mp4 — and emit a `source-sample.json` in the exact shape the `upload-ad-sample` skill writes to the Goose Ads library. Also links every character and voice to the central character library at `/Users/akhil/projects/content-goose/assets/character-library/`, and if a character isn't in the library yet, adds it first then links. Use when the user wants to remix one of their existing ads — this skill produces the source JSON that the script-rewriting step and `remix-ad` consume.
Generate a single photoreal or designed image with OpenAI gpt-image via fal.ai. Supports gpt-image-1 (default, fixed sizes — the FAL fallback for Higgsfield's `gpt_image_2`) and gpt-image-2 (`openai/gpt-image-2`, custom output sizes up to 3840px). Routes to text-to-image or the edit variant depending on whether a reference image is provided. Use for photoreal character anchors, scene keyframes, and designed sheets (e.g. storyboards) where precise layout and legible text matter.