---
name: image-gen
description: >
  Acquire images as files — generate them with an AI image model (14 providers:
  OpenAI/gpt-image, Gemini, Qwen, Zhipu, Volcengine, Stability, FLUX, Ideogram,
  MiniMax, and more), search openly-licensed stock (Openverse/Pexels/Pixabay/
  Wikimedia), or slice one generated sheet into elements. Drive it one-off with a
  single prompt, or in batch from an image_prompts.json manifest with a written-
  back status/audit trail. Use when the user wants to generate/create/make an
  image or illustration, source a photo, or when another skill (e.g. ppt-master)
  needs images produced to disk.
license: MIT (adapted from hugohe3/ppt-master; complete terms in LICENSE.txt)
---

# Image Generation & Sourcing

Produce image files on disk through one of three acquisition paths. This skill
is the single home for image acquisition — other skills delegate to it rather
than embedding their own copy.

| Path | Script | Output status | What it does |
|---|---|---|---|
| **AI generation** | `scripts/image_gen.py` | `Generated` | Text prompt → rendered image via a configured provider backend |
| **Web search** | `scripts/image_search.py` | `Sourced` | Query → best openly-licensed match downloaded, with attribution recorded |
| **Slice** | `scripts/slice_images.py` | `Generated` | One generated grid "sheet" → N individual element files |

All `<skill-dir>/...` paths below are relative to **this skill's own directory**
(its absolute path is in the location header injected when the skill loads), not
the user's working directory. There is no persistent CWD across terminal calls —
pass absolute paths for `--output` and inputs.

## Preflight

1. **Run scripts with `uv run`** — every script carries [PEP 723](https://peps.python.org/pep-0723/)
   inline dependency metadata, so `uv run <skill-dir>/scripts/<name>.py …`
   auto-installs exactly what that script needs into an ephemeral, cached
   environment. No `pip install`, no venv, nothing left behind. `uv` ships with
   the octo installer; if it's somehow missing, the fallback is `pip install -r
   <skill-dir>/requirements.txt` once, then run the scripts with `python3`.
2. **Configure a backend** for AI generation. Set `IMAGE_BACKEND` and the
   provider's own key (e.g. `OPENAI_API_KEY`) in the process environment, or in a
   `.env` file — see `<skill-dir>/.env.example` for every provider's variables
   and the `.env` lookup order. `uv run <skill-dir>/scripts/image_gen.py
   --list-backends` prints what's available. Web search (`image_search.py`) needs
   no key for CC0/public-domain providers; Pexels/Pixabay use their own keys if
   you want those sources.

### First AI-generation run — backend setup gate (do NOT skip)

Before the **first** AI generation of a session (a positional `image_gen.py` call
or `image_gen.py --manifest`), check whether an AI backend is configured, and if
not, **guide the user proactively instead of running the script and dumping its
error**:

1. **Detect config.** Is `IMAGE_BACKEND` set in the environment, or present in a
   `.env` on the lookup path (`./.env`, `<skill-dir>/.env`, `<repo>/.env`,
   `~/.ppt-master/.env`)? If yes — and its provider key is present — **proceed
   silently**, ask nothing.
2. **If no backend is configured, stop and ask the user** (in the TUI/web use a
   question prompt; in an IM channel ask in plain language) to pick one of:
   - **Configure an AI backend now** — recommend a **CORE** backend
     (`openai` / `gemini` / `qwen` / `volcengine` / `zhipu`). Tell them exactly
     which env vars that backend needs (from `--list-backends` / `.env.example`),
     take the key, and **write it for them** to `./.env` (project-local) or
     `~/.ppt-master/.env` (user-level) — e.g. `IMAGE_BACKEND=openai` +
     `OPENAI_API_KEY=…`. Never echo the key back in chat, and never commit `.env`.
   - **Skip AI, use keyless web search instead** — run `image_search.py`
     (Openverse / Wikimedia are CC0 / public-domain, no key needed). Good when the
     user just wants real photos or has no API key.
   - **Use the host's native image tool (Path B)** — if the host (Claude Code /
     Codex / etc.) has its own image-generation tool, generate directly from the
     prompts in `image_prompts.json` and save to `images/<filename>`, skipping
     this script entirely. See `references/image-generator.md` §7 Path B.
3. **When invoked by another skill** that already confirmed the image source:
   honor it — if the caller confirmed `web` or host-native, do **not** prompt for
   an AI backend; only run this gate when AI generation is actually about to run
   with nothing configured.

Once a backend is configured this gate never fires again for the session.

## Two ways to drive it

### One-off — a single image right now

```bash
# AI generation
uv run <skill-dir>/scripts/image_gen.py "a serene alpine lake at dawn, soft mist, painterly" \
  --aspect_ratio 16:9 --image_size 2K --output /abs/out/dir --filename hero

# Web search (openly-licensed, downloads one best match + records the source)
uv run <skill-dir>/scripts/image_search.py "diverse engineering team in a modern office" \
  --orientation landscape --output /abs/out/team.jpg
```

The positional-prompt form skips the manifest and leaves no audit trail — reserve
it for quick fixups and standalone requests. **After it finishes, present the file
to the user** — see [Show the result](#show-the-result-to-the-user).

### Batch — an `image_prompts.json` manifest (audit trail)

The manifest is the shared contract when a caller has many images and wants a
written-back status per item. Write it, then run generation; the CLI runs every
`Pending`/`Failed` item and writes `Generated` / `Failed` / `Needs-Manual` back
into the same file as each completes.

```jsonc
{
  "project": "my-deck",
  "deck_rendering": "vector-illustration",   // one rendering shared by all items
  "deck_palette": "cool-corporate",          // one palette shared by all items
  "color_scheme": { "primary": "#1E3A5F", "secondary": "#F8F9FA", "accent": "#D4AF37" },
  "items": [
    { "filename": "cover.png", "prompt": "...", "aspect_ratio": "16:9",
      "image_size": "2K", "page_role": "hero_page", "text_policy": "none",
      "status": "Pending" }
  ]
}
```

```bash
# Render the read-only Markdown sidecar for review (no network):
uv run <skill-dir>/scripts/image_gen.py --render-md /abs/images/image_prompts.json
# Generate every Pending/Failed item in parallel, writing status back:
uv run <skill-dir>/scripts/image_gen.py --manifest /abs/images/image_prompts.json
```

Full field reference (`page_role`, `text_policy`, `type`, `slice_grid`/
`slice_names`, back-compat) is in `references/image-generator.md` §6.

### Slice a generated sheet into elements

When several small spot illustrations should share one coherent style, generate
one grid sheet (a single AI item), then cut it:

```bash
uv run <skill-dir>/scripts/slice_images.py /abs/images/spot_sheet.png \
  --grid 2x3 --names icon_a icon_b icon_c icon_d icon_e icon_f --trim --alpha
```

`--trim` tight-crops each cell to its content; `--alpha` knocks out the flat
background to transparency. Geometry rules: `references/image-generator.md` §4.3.

## Show the result to the user

These files are produced by a **script**, so — unlike `write_file` output — they
are **not surfaced automatically**. After producing an image the user wants to
see, call the **`show_artifact`** tool with the file's **absolute path** (one call
per file). It adapts to the interface: in the **web UI** the image previews inline
in the Artifacts panel; in the **TUI** the path becomes a click-to-open link;
headless / IM just reports the path. (`show_artifact` only accepts a path that
already exists and a previewable type — `.png/.jpg/.jpeg/.gif/.webp/.svg` all
qualify.)

**When to show:**

- **One-off / standalone requests** — "generate an image of …", "find a photo of
  …", a single fixup: **show every file you produce.** Seeing it is the point.
- **Batch manifest, or when invoked by another skill** (e.g. `ppt-master` building
  a deck): **do not `show_artifact` each item.** Those images are consumed into
  the deck and the calling skill presents the finished artifact; per-image
  previews would just spam the panel. Show one only on an explicit request to
  review a specific generated image.

## Prompt quality — consult the craft library before writing an AI prompt

The quality of an AI-generated image is set almost entirely by the prompt. Before
authoring or repairing any `ai` prompt, **read the prompt-craft library** — a
distilled checklist plus a 160-prompt exemplar atlas (adapted from the MIT-licensed
[GPT-Image2-Skill](https://github.com/wuyoscar/GPT-Image2-Skill), tuned for
`gpt-image-2` but the principles carry across backends):

1. **`references/prompt-craft/craft.md`** — the 18-point checklist: put exact text in
   quotes, declare canvas/aspect/layout before subject, JSON/config-style prompts,
   fixed-region schemas for infographics, diagram grammar for data figures, UI-as-spec,
   multi-panel consistency, camera context for photorealism, scene density over
   adjectives, bounded style anchors, material/lighting/palette as separate controls,
   edit-endpoint invariants, dense Chinese/multilingual layouts. Load it whenever a
   prompt involves readable text, diagrams/data, UI, multi-panel layouts, or is weak.
2. **`references/prompt-craft/gallery.md`** — routing index to per-category exemplar
   prompts (`gallery-*.md`). Find the closest category, read 3–8 nearby `**Prompt**`
   entries, and remix rather than writing from scratch. (Preview PNGs aren't bundled;
   the prompt text is what matters.)
3. **`references/prompt-craft/openai-cookbook.md`** — official `gpt-image` API/model
   parameter semantics; load for capability or parameter questions.

This lifts output quality across every backend; it is not gpt-image-only.

## References — load on demand

| Need | Read |
|---|---|
| **Prompt-craft checklist (read before writing any AI prompt)** | `references/prompt-craft/craft.md` |
| **Exemplar prompt atlas by category** | `references/prompt-craft/gallery.md` → `gallery-<category>.md` |
| Common framework: resource-list format, path dispatch, status enum | `references/image-base.md` |
| AI path: prompt assembly, page roles, sheet/slice geometry, manifest schema, path selection | `references/image-generator.md` |
| Web path: license tiers, provider selection, attribution, `--strict-no-attribution` | `references/image-searcher.md` |
| Palette vocabulary (color behavior for generated images) | `references/image-palettes/_index.md` |
| Rendering styles (flat, watercolor, 3d-isometric, …) | `references/image-renderings/_index.md` |
| Composition types (infographic, flowchart, framework, …) | `references/image-type-templates/_index.md` |

Lazy-load only what the job needs: an all-search job never opens
`image-generator.md`, and an all-generate job never opens `image-searcher.md`.

## Being invoked by another skill

A caller (such as `ppt-master`) hands off by writing an `image_prompts.json`
manifest into its own project and asking this skill to run it. Read the manifest,
run the path each item declares (`image_gen.py --manifest` for `ai`,
`image_search.py` for `web`, `slice_images.py` for `slice`), and the status
written back into the manifest is the caller's signal that the files are ready.
Honor a caller's confirmed generation path — a manifest existing does **not** by
itself mean `--manifest` should run (it is the AI-API path only); see
`references/image-generator.md` §7.
