---
name: image-ad-from-references
description: Makes an on-brand static image ad (the picture plus its headline, main text and button) for one product with Icarus. Reads the brand's website into a brand kit (logo, colours, fonts, tone, audience, the kind of people it shows), reads the product page for its facts, follows the layout of the brand's own designed ads from the Meta Ad Library, and pins the product so it stays exact. Use when someone gives a product link or product photos and asks for an image ad, a static ad, a Meta, Facebook or Instagram ad creative, a feed or story ad, or "an ad like their ads" as a picture. For a video ad, use video-ad-from-references.
---

# Image ad from references

## Overview

The new ad should look like the brand's own team made it. Three sources make that true, each for its own part:

| Source | Gives | From |
|---|---|---|
| Brand kit | logo, colours, fonts, tagline, tone of voice, audience, aesthetics, and the **cast**: the kind of people the brand shows | the brand's website (`scripts/brand_kit.py`) plus what you see in its photos |
| Product facts | name, price, old price, description, features, the chosen colour's photo | the product page (`scripts/product.py`) |
| Their designed ads | layout: where the product, the person and each word sit; the frame shape | the Meta Ad Library (`scripts/ad_library.cjs ... images`), when the brand runs any |

The ad comes out ready for Meta: one picture, plus the headline, main text, button and link to paste in.

**Their ads decide what is on the picture.** Copy only what their designed ads have: a logo only if theirs show one, a price only if theirs show one, their kind of title and caption in their kind of type, their light (flash at night, city daylight, studio colour), their poses and their energy. What their ads leave out stays out. A logo, price or tagline added because "ads have them" makes it look like a template, not their ad.

What they can send, and what each gives:

| They send | Product | Facts | Brand kit |
|---|---|---|---|
| A product page link | its photo, from `product.py` | name, price, old price, features | from the page's own website |
| Only a product photo (attached or a file) | that photo, saved as below | only what they tell you | from the brand's website: take its name from the logo on the product or ask for the site in the same message |
| Their website or ad images too | | | from those |

With only a photo, ask once, in one message, for what you cannot see: the brand's website if the photo doesn't show the name, and the name, price or offer they want on the ad. Without those, the ad shows the product and the logo, and no name or price.

**On brand or nothing.** Credits are spent only once you have a brand kit from the website or real designed ads of theirs. If you have neither, stop, spend nothing, and ask for their website or two or three of their ad images.

Asking for the ad is the go-ahead: run through without stopping for a yes. Make three ads unless they ask for a number: three versions to test against each other. Stop only for what you cannot decide: which of two pages is the real brand, a claim the product page does not make, a real person's face.

Every Icarus tool is written here as `Icarus:<tool>`. The scripts need Python 3 with Pillow; the Ad Library script also needs Node with Playwright. Where a script cannot reach the site (a sandbox with no outside network, as in the Claude app), read the website and the product page with your web fetch tool instead and fill the same fields, save the product from its public photo link with `Icarus:create_product`, and treat the Ad Library as blocked. If `node -e "require('playwright')"` fails, install it once:

```bash
npm i --prefix ~/.cache/ad-library playwright && npx --prefix ~/.cache/ad-library playwright install chromium
export PLAYWRIGHT_PATH=~/.cache/ad-library/node_modules/playwright
```

## Workflow

Copy this checklist and tick it off as you go:

```
Ad progress:
- [ ] 1. Brand kit built from the website
- [ ] 2. Product facts read and product saved
- [ ] 3. Their designed ads read (when there are any)
- [ ] 4. Ad written: picture plan and copy
- [ ] 5. Person cast and checked (when the ad shows one)
- [ ] 6. Picture made
- [ ] 7. Picture checked
- [ ] 8. Report written
```

**1. Build the brand kit.** Run `python3 scripts/brand_kit.py https://<brand site> brand-kit`. It writes `brand-kit/brand.json` (name, logo, colours from the logo and the site's styles, fonts, tagline, description, headings) and downloads the logo and the site's photos into `brand-kit/images/`. Look at the logo and every photo, then complete the kit in this table; the photos decide the last three rows:

| Field | What to write |
|---|---|
| Name, website, logo | from `brand.json` |
| Colours | six, main first: the logo's and the site's most used, without plain greys |
| Fonts | from `brand.json`; describe each in words too ("bold geometric sans") |
| Tagline, description | from `brand.json`, in their words |
| Selling points | three to five, only what the site says |
| Tone of voice | three to five words, from how the site and their ads write |
| Audience | one line: who the site speaks to |
| Aesthetics | settings, light, colour, camera angles the photos use |
| Cast | first, whether their ads and photos show people at all: many food, drink, beauty and other packaged-goods brands show only the product, a hand, or the product in a scene. If they show people, what their people share, read off their faces one by one: age band, the mix of looks they cast, face shape (slim oval with high cheekbones, round and soft, a defined jaw), skin tone range, makeup in exact small words (dewy skin, light flush, brushed brows, nude lips, no eyeliner; or a bare face; or full glam with winged liner), hair and grooming, build, expression (candid half smile, big laugh, cool and unsmiling), styling and clothes palette |

If the website cannot be read, build what you can from their ads and say what is missing.

**2. Read the product.** With a product page, run `python3 scripts/product.py <product page> product.json`. With only a photo, skip the script: a photo attached in the chat goes in through `Icarus:save_attached_files` when the app can pass it, otherwise `Icarus:upload_file` (the person picks it in the box); a photo you have as a file goes in through `Icarus:get_upload_link` and `scripts/upload.py`; then save it with `Icarus:create_product`, and the facts are only what they told you. It writes the name, price, old price, stock, description, options and photos from the store's own product data, with the chosen colour's photo first. Save that photo with `Icarus:create_product`. Every fact in the ad comes from `product.json` or from the user.

**3. Read their designed ads.** Take the page whose name matches the brand exactly (`node scripts/ad_library.cjs "Brand name"` lists them, exact name first; ask only if two could be it), then `node scripts/ad_library.cjs <page id> 20 ad-library images`. Look at every picture and set aside the catalog ones: the product alone on a plain background, often with `{{product.brand}}` in the copy. Meta builds those itself from the product feed, so they are only a guide to the copy voice. Group the designed ones by look (lifestyle with logo and price, campaign headline, sale banner) and take the longest-running ad (`startDate`) of the biggest group as the reference. A sale look fits only when `product.json` has an old price or the user gives an offer. Note where the product, the person and each word sit, how big and in what colour, and the frame shape.

Their designed ads are weak when there are none, only catalog ones, or none still running after two weeks: a brand stops paying for an ad that doesn't sell. Then take the layout from the best in their niche: search the web for the three or four leading brands in their category and market at a similar price, look each up the same way, and take the longest-running designed ad across them. From another brand's ad only the layout is borrowed (where the person, the product and each word sit, and the frame shape); the look, the person, the words and the colours still come from this brand's kit. Say in the report whose ad the layout came from.

The script is blocked (exit code 2, and always in the Claude app)? Their website's campaign banners are designed ads too: the homepage photos with words on them that `brand_kit.py` downloads (or that your web fetch lists). Take the reference from those. No banners either? Ask for two or three of their ad images or Instagram posts, in one message, before spending anything.

**4. Write the ads.** Three rows unless they asked for another number. The first follows the reference; each other one changes one thing so the three can be tested against each other: the layout of another of their top designed ads, a different scene from the kit's aesthetics, or a different headline angle (a feature, a use, the price). The product, the cast face and the brand kit stay the same in all of them. One row per ad:

| Picture | Person, or none | Words on the picture | Headline | Main text | Button | Link |

- Picture: the reference's layout with a setting like theirs, in concrete words (place, light, colours, materials, camera angle, pose), with this product. Use the light their ads use, whatever it is: on-camera flash at night, motion-blurred city, bright studio colour. Don't add a look they don't use (glow, sunbeams, fairy lights, candles, pampas, rattan): that makes a picture look generated. When the reference shows only the product, keep it that way: a pack on a colour backdrop, ingredients or splashes around it, a hand holding it, the product on a table: whichever their ads use.
- Person: only when the reference shows one, or the user asks for one; cast in step 5 to fit the kit's cast row. A hand alone needs no casting: describe it in words. Never the person in their photos or ads: that is a real model's face.
- Words on the picture: only the kinds the reference has, in its places, sizes and type styles (a big display title, a small caption in a typewriter font, a logo, a price: whichever it shows, nothing more). A title or caption in their voice from the product's facts; a price only when their ad shows one, from `product.json` (old price struck through only when there is one). Every word spelled exactly, in quotes. Their ads show no words? Then none.
- Headline, main text, button: in the kit's tone of voice, from the product's facts only. The button is one their ads use. The link is the product page.

**5. Cast the person.** Only when the ad shows a person; otherwise skip to step 6. When it does, cast them first, alone, so the face can be checked before it goes in the ad. Make three options in one `Icarus:create_generations` call, each with `model` `muse` (its people look real; check it in `Icarus:list_models`), frame 3:4 and no reference pictures. Muse brings its own look, so each prompt is one short plain line from the cast row, with no camera, lens or "realistic" words. Muse goes to extremes on makeup: no makeup words give a bare face and "glam" gives heavy glam, so write their makeup in the cast row's exact small words, never "glam" or "natural" alone. The three options differ in one thing the cast row allows (hair, skin tone, the mix of looks): for example "waist-up casting portrait of a young male model with a sharp jaw, light olive skin and tousled dark brown hair, candid half smile, open navy linen shirt, plain light grey studio wall". Take each option's link from the `output` that `Icarus:wait_generations` returns (not `Icarus:get_generations`, which puts every option on screen as if it were the ad), download them and put them on one sheet under crops of three or four of their faces (`Pillow` is enough), then pick from that sheet, never from memory, the one that would sit in their ads without standing out and is clearly not one of their models. If none fits, make one more set of three with the lines fixed; if none fits again, say so and stop before the ad.

Save the winner with `Icarus:create_character` (the casting photo of a made-up person is their original) and pin it in step 6 with `characterIds`. If it is refused (an older Icarus), pass the casting photo's link as a reference picture instead.

**6. Make the picture.** Use `model` `nano-banana-2` unless they name another. Check it with `Icarus:list_models` (`model` `nano-banana-2`) and take the reference's frame shape (or the one asked for: 1:1 or 4:5 for the feed, 9:16 for stories) from its list; if it is not listed, use the top pick of `Icarus:list_models` with the job in plain words. Then one `Icarus:create_generations` call with one request per ad, each with:

- `model`, `productIds` the saved product, `aspectRatio`, an `idempotencyKey`
- `characterIds` the saved cast face, when there is a person. Their ad goes in as a picture only when it shows no person; with a person in it, the model copies their model's face and pose, so describe its layout in words instead.
- `prompt` in this order: which picture is which ("the pinned suitcase is the product; the pinned man is the person, with his exact face, hair and skin"); the scene and layout in words (setting, light, where the person and the product stand, how much of the frame each fills, the camera height); the product, "exactly as in its photo"; the person's pose, expression and clothes; "Words on the picture, exactly these and nothing else:" with each word in quotes, where it sits and how it looks; last, no other words, logos or text anywhere

Then `Icarus:wait_generations` and `Icarus:get_generations`.

**7. Check the picture.** Look at it beside the product photo, the casting photo, their ad and the kit's photos. It passes when the product matches its photo (shape, colour, logo, details), the person is the cast one and not their model, every word is spelled exactly as planned and nothing else is written, and the layout, light, pose and words match theirs, with nothing their ads don't have (no extra logo, price or tagline). A failed picture is made once more with the prompt fixed for what was wrong; if it fails again, report it.

**8. Report.**
```markdown
## <Product> image ads: <done> of <planned>
**Brand kit:** colours <hex list>, fonts <names>, tone <words>, cast <one line>
**Modelled on:** <their ad id>, running since <date> (or: laid out from the brand kit)
**Cost:** <credits> credits (balance from Icarus:whoami before and after)

| Ad | Picture | What is different | Headline | Main text | Button |
Link for all: <product page>
```

## Examples

<example>
User: Make an image ad for https://mokobara.com/products/the-transit-check-in-luggage

`brand_kit.py https://mokobara.com` gives the logo, black, white and the brand yellow #FFC002, fonts NeurialGrotesk and Karla, and the tagline "Elevate the joy of travel". Its photos show people in their early 20s with mixed looks, laughing mid-stride on sunlit coasts under blue skies, in open linen shirts, oversized jackets and wide cream trousers. `product.py` gives Transit Luggage - Check-in, ₹5,999, old price ₹13,999. Their longest-running designed ad is a 9:16 shot of a man walking a check-in case along a seaside terrace, "mokobara" bold at the top centre, the name in two small lines on the left, the price below with the old price struck through. Their men share an editorial model's face with a defined jaw, light to olive skin, tousled hair with volume, a candid half smile looking off camera, and elevated casual clothes. So a man of that type is cast first with Muse on a grey studio wall and checked against them; then the ad follows their layout, described in words, with the white Transit pinned and the casting photo as the only reference picture. Their ad shows the logo, the name and the price, so this one does too: exactly "mokobara", "Transit Luggage -", "Check-in", "₹5999" and "₹13999" struck through. The copy is in their playful voice: "Meet the Transit Check-in 👋 65 litres, 8 super silent ninja wheels and a one-push TSA lock. Epic journeys begin here." with "Shop now".
</example>

<example>
User: Make an image ad for this NEWME top: <product page>

The Ad Library is blocked in the Claude app, so the reference comes from the homepage banners: full-bleed fashion photos, often at night with on-camera flash or a motion-blurred city behind, one or two models in confident editorial poses, a big display title at the bottom ("LIGHT & Layers", "READY FOR THE NIGHT") with one word in a script or outlined font, and a short caption in a small typewriter font beside the model. No logo on the photo, no price. So the ad has exactly that: a title in their style from the product's name, a small caption, a cast model in a flash-lit night street, and no logo or price.
</example>

<example>
User: Make a sale ad for this kurta. https://brand.in/products/kurta

`product.py` shows a price and no old price, so there is no sale to show: no discount goes on the picture or in the copy, and the report says a sale price would need to come from them. The ad follows their lifestyle look instead.
</example>

<example>
User: Make an ad for this roasted makhana pack: <product page of a snack brand>

The brand kit gives a bright red, deep browns and cream, and a warm, homely tone. Their longest-running designed ads show no people: one pack at the centre on a bright colour that matches its flavour, the snack spilling around it, the logo at the top and one short claim from the page at the bottom. So the ad has no person and skips casting: the pinned pack on that kind of backdrop with the snack around it, the logo and one claim taken word for word from the product page, in their places, made with `nano-banana-2`.
</example>

<example>
User: Make a Facebook ad for our new candle.

No website, no product page, no ads in the Ad Library and none sent. Stop: "Send your website or the candle's page, and two or three of your ad images if you have them, and I'll make it on brand. Nothing has been spent."
</example>

## Common mistakes

| Mistake | What happens | Fix |
|---|---|---|
| Writing the person from your own taste | a face that doesn't belong to the brand | read the cast row off their faces, cast first, check before the ad |
| Skipping makeup and face shape in the cast row | a bare or over-made-up face that looks like another brand's | write both in exact small words; pick from a side-by-side sheet |
| Their ad with a person as a reference picture | the model copies their model's face and pose: their ad, with a real person, copied | describe the layout in words; only the product and the casting photo go in as pictures |
| Adding a logo, price or tagline their ads don't have | a template ad that doesn't look like theirs | words on the picture are only the kinds their ad shows |
| Plain daylight when their ads use flash, night or city blur | a flat stock-photo look | copy their light, whatever it is |
| Copying a catalog ad | a plain product photo nobody needs: Meta makes those from the feed | follow their designed ads, or the brand kit |
| Following their ads when they are weak | a copy of an ad that doesn't sell | none still running after two weeks: take the layout from the niche's best |
| Their model in the new ad | a real person's face in an ad they did not agree to | a new person of the same cast |
| A price, discount or claim not in `product.json` | a false claim in their ad | only the page's facts or the user's |
| Describing the product in words | the words fight the photo and the product drifts | pin it and say "exactly as in its photo" |
| Their old product left in the picture | the ad sells the wrong product | say to replace it, and check before reporting |
| Words misspelled on the picture | the ad can't run | check every letter in step 6 and remake once |

---

Page: https://withicarus.com/skills/image-ad-from-references
Download: https://icarus.b-cdn.net/skills/image-ad-from-references/v1-55bfa578/image-ad-from-references.zip
Install guide for AI apps: https://withicarus.com/skills/image-ad-from-references/llms-install.md
This skill makes photos and videos with Icarus. Connect Icarus to your AI app: https://withicarus.com/mcp
