| name | assets-not-mockups |
| description | Generate discrete image assets with Google's Gemini image models (Nano Banana Pro, Nano Banana 2), and refuse to generate design mockups. Use when asked for product shots, stock or marketing photography, mascots, illustrations, textures, logos, OG and social cards, or image-to-image edits that hold a face, product or style steady. Also use when someone asks an image model to show what a page, screen, app or UI could look like, because that is the refusal case. Bundles a stdlib-only script and the prompting that actually moves the output. |
Assets, Not Mockups
An image model produces finished, hand-collaged artwork. It does not produce designs you can build. Point it at a product shot, a mascot, a texture or an OG card and it saves you a photographer and an afternoon. Point it at "show me what the settings page could look like" and it hands you a beautiful picture that no HTML will ever reproduce, and you will burn a day building a worse, hand-drawn copy of it before admitting the picture was never a design.
Those are two different tools wearing the same API. This skill is the first one, and a refusal to be the second.
The refusal
Never generate website, app, UI, page-layout, dashboard, email-template or "what could this look like" mockups, comps or design explorations. Not as a starting point, not as inspiration, not just to see.
The reason is mechanical, not aesthetic. A generated mockup has no structure: no box model, no type scale, no grid, no states, no reuse. Every pixel is a one-off decision made by something that has never shipped CSS. The gap between the picture and the buildable version is invisible until you are in it, and then it is the whole job. You end up reverse-engineering an illustration instead of designing, and the result is worse than if you had never seen the picture, because now you are anchored to it.
The line: an asset drops into a slot in a design. A mockup is the design. If the deliverable would be a picture of an interface, stop.
When you catch the request, say so in one sentence and offer what does work:
- Build it in code. Real markup can be iterated, reviewed in a browser, made responsive and kept. A rough coded layout beats a gorgeous render every time, because it is the actual artefact.
- Bring in a human designer when the visual direction genuinely is not settled. That is a design problem, not a generation problem.
- Generate the assets the design needs. Often the real ask hiding inside "mock up the landing page" is a hero image, an illustration and three product shots. Those are legitimate. Offer them.
If the human hears this and still wants the mockup, that is their call and their money. Say plainly that it will not be reproducible in code, then do it. The crime is generating one silently and letting the picture set expectations nobody can build to.
What it is for
Discrete assets that ship as-is:
- product photography and hero shots
- stock and marketing photography
- mascots, characters, illustrations, icons
- textures, patterns, backgrounds
- logos and wordmarks
- OG cards, social cards, thumbnails
- image-to-image edits: restyle a photo, swap a background, hold a face or product steady across a set
Run it
python3 skills/assets-not-mockups/scripts/generate_image.py \
--prompt "<a vivid paragraph, see prompting below>" \
--out path/to/image.png --aspect 1:1 --size 2K
Drive the script. Do not hand-roll the HTTP call: the request shape (reference images before the instruction, responseModalities, imageConfig) is fiddly and the script already has it right. Stdlib only, no dependencies.
The key
The script needs a Google AI Studio API key. It looks in three places, first hit wins:
GEMINI_API_KEY, GOOGLE_AI_API_KEY or GOOGLE_API_KEY in the environment.
- The file at
GEMINI_ENV_FILE, if set, read for a GEMINI_API_KEY= or GOOGLE_AI_API_KEY= line. Use this to point at an env file you already keep a key in, rather than making a second copy of the secret.
- Nothing, in which case it exits and tells you to get one.
If there is no key, stop and tell the human where to get one: https://ai.google.dev/gemini-api/docs/image-generation. There is a free tier. Do not stub the image, do not substitute a placeholder, do not go looking for some other image API to use instead. No key means blocked, and blocked is a fine thing to report.
For a permanent setup, put the key (or a GEMINI_ENV_FILE path pointing at it) in your shell profile or in the env block of ~/.claude/settings.json, so every session has it. Never commit a key to a repo.
Generating spends the human's money. Every call is billed to their key, and image models are not cheap. Generate deliberately. For a set of more than a few, say what you are about to make and how many, and get a yes before you spend it. Never loop over a list of prompts unattended.
Output is PNG. Convert and resize for the target slot afterwards, for example cwebp -q 82 image.png -o image.webp.
Models
| Model | Use for | Notes |
|---|
gemini-3-pro-image (Nano Banana Pro, default) | final product, hero and brand shots | highest quality and control, 1K/2K/4K, best text rendering |
gemini-3.1-flash-image (Nano Banana 2) | fast iteration, everyday edits | quicker and cheaper, 4K, up to 14 reference images |
gemini-3.1-flash-lite-image (Nano Banana 2 Lite) | bulk and cheap drafts | cheapest tier |
That table is a dated snapshot, not the truth. Verified live on 30 July 2026. Google ships new image models faster than anyone updates documentation, and every id above will eventually 404 or be superseded by something better and cheaper. So check, rather than trusting the table:
python3 skills/assets-not-mockups/scripts/generate_image.py --list-models
That is a free GET against the models endpoint, printing what this key can actually reach, newest first, stable before preview. Run it when:
- the verified date above is more than a month or two old
- a model id returns 404, which usually means it moved in or out of
-preview
- you are about to generate a large or expensive set and want the current best model rather than last quarter's
Then pick the highest-numbered member of the family you want and prefer the stable id over -preview. Do not probe before every single call; it is an extra round trip and the default is usually right. Probe when the snapshot is old or something breaks.
Pass --model to switch. Default to Pro for anything that ships.
--aspect: 1:1 3:2 2:3 4:5 16:9 9:16 21:9. --size: 1K 2K 4K. Match the slot the asset lands in, so square product cards get 1:1 and OG cards get 16:9. Generating a shape you then crop wastes most of the pixels you paid for.
Prompting
- Write a narrative paragraph, not keywords. These models understand language, so prose beats comma-soup. Describe a scene the way you would to a photographer who cannot see it.
- Think like a photographer for anything photoreal: name the shot, the lens, the light and the depth. "Low-angle 35mm shot, soft natural window light, shallow depth of field, gentle film grain, true-to-life colour."
- Text rendering is a headline feature. Put the exact words in quotes and describe weight, colour and placement:
bold coral-red text reading "AGENTS WELCOME" across the top. It renders legible text reliably, which is what makes OG cards and thumbnails viable.
- State composition and negative space when something will overlay the image: "generous negative space on the left for a title".
- Use explicit negatives to kill the known failure modes. "A single real photograph, never a collage, grid or split image. No text, no logos, no watermarks." For photoreal add "never a 3D render, CGI or illustration, no plastic sheen." The collage failure mode in particular will bite you unless you name it.
- Loose structure: subject, composition, action, location, style, edits.
One visual language for a set
When several images have to feel like one shoot, write a single visual-language preamble and prepend it to every per-image prompt. Tune the shared language once; vary only the scene. This is the biggest single lever on whether a set looks intentional or AI-scattered, and it is the step people skip.
VISUAL LANGUAGE (prepend to every prompt in this set):
Shot on a 50mm lens, soft overcast daylight from the left, shallow depth of
field. Muted palette of warm off-white, sage and dark walnut. Matte surfaces,
no gloss. Quiet, unstyled, lived-in. A single real photograph, never a collage
or split image. No text, no logos, no watermarks. Never a 3D render or
illustration.
PER IMAGE: a stoneware mug on a bare kitchen counter, steam just visible, ...
Keep the preamble in a file or a config constant next to whatever consumes the images, so a later regeneration matches the originals instead of starting a new look. Allow a per-image override for the one shot that genuinely needs different light.
Reference images
Pass --ref <path>, repeatable. Pro takes a few, Nano Banana 2 up to about 14. References go before the instruction, which the script handles. Use them to:
- restyle a real photo into a brand look while keeping a face or product recognisable
- hold a character or product consistent across a whole set
- lock colour and lighting from a mood board
Refer to the inputs explicitly in the prompt: "Using the supplied product photo, place it on a warm off-white seamless background...". A reference the prompt never mentions gets treated as a vague suggestion.
Before you call it done
- Look at it. Read the image back. Do not report success on the basis that the script exited zero.
- Check the text letter by letter if there is any. Near-miss spelling is the most common defect and the easiest to miss when you know what it is supposed to say.
- Check the negatives held. No accidental collage, no phantom watermark, no extra fingers.
- Convert and size for the slot before handing it over.
If it is wrong, change the prompt and regenerate rather than accepting it. But count the attempts out loud, because each one is billed.