This skill orchestrates three lower-level components:
image-prompt style anchor + composition-zone vocabulary
common/runners execute layer — multi-aspect batch generation via the chosen image provider
common/style-library/carousel/ — reuses the 24 carousel visual styles as the visual vocabulary (poster styles overlap heavily with editorial carousel styles)
Use when the user wants a finished flyer image — not just a prompt. Without --execute, returns the assembled prompts; with --execute, generates the actual PNGs.
This skill does NOT:
- Generate animated flyers (use
reel-builder for motion)
- Render print-ready CMYK / 300DPI files — outputs are RGB at standard digital resolutions (1080 / 1240 px). For print: open the PNG in a real DTP tool (Affinity / InDesign / Photoshop) and convert.
- Compose multi-image collages — single image per aspect.
- Generate QR codes (deferred to v2.5.x — if you need a QR, generate separately and overlay manually).
- Search Eventbrite / Meetup / Luma for event metadata — you provide title / date / location explicitly.
- Replace a designer's judgment on layout — the composition zones are starter conventions; tweak via prompt iteration.
ROLE
Read the event details + optional photo + optional style → pick a model (text-friendly + multi-ref-capable if photo provided) → assemble per-aspect prompts with composition zones filled in → batch execute via the image provider → save PNGs + manifest → print paths.
PIPELINE
Resolve event details:
- Required:
--title
- Strongly recommended: at least one of
--date, --location, or --cta (a flyer without a single detail is just a styled portrait)
- Optional:
--subtitle, --time (can be merged with date)
Resolve photo (optional):
--photo <path-or-url>: passed as reference image to the chosen model.
- Multi-ref capable models needed (Nano Banana Pro / Flux Kontext / gpt-image-2 / Ideogram 3 / Seedream 5.0).
- If
--photo provided AND --model auto: skill picks a ref-capable model.
- If
--photo provided AND --model <slug> that can't handle refs: warn + auto-substitute, or exit if user passed --strict.
Resolve style — see references/event-details.md:
--style <library-id>: load from common/style-library/carousel/<id>.md. Use the Style anchor (text-in-image mode) block (flyers always have text).
--style auto: pick from library based on the event type implied by the title + the chosen tone (formal, casual, indie, corporate). Algorithm same as carousel-builder.
--style-mod "<override>": append a tweak to the anchor.
Pick model — see references/model-picker.md:
--model auto:
- Photo provided + identity preserve critical (named speaker) →
nano-banana-pro
- Photo provided + brand-style transfer needed →
flux-2-pro or seedream-5
- Photo provided + Latin/CJK text needed →
gpt-image-2
- No photo + text-heavy →
ideogram-3-quality
- No photo + photoreal style →
nano-banana-pro or flux-2-pro
--model <slug>: explicit override.
- ONE model for all aspects (consistency across the family).
Build per-aspect prompts — see references/composition-zones.md:
Each aspect has a composition template with three zones:
- Headline zone (top 20-25%): title in large bold typography
- Visual zone (middle 50-55%): photo integration if provided, else style anchor visual
- Details zone (bottom 25-30%): date + location + CTA in smaller typography
The prompt assembly per aspect:
<style anchor (text-in-image mode)>
Composition: <aspect-specific zone template>
Embed text:
Headline: "<TITLE>"
<Subtitle if present>
<Date if present>
<Location if present>
<CTA if present>
Aspect ratio: <portrait|square|story|landscape|a4>
Size: <pixel dimensions>
Estimate cost + confirm — sum aspects × variants. Under default carousel budget ($1.50) → no prompt; over → ask once.
Batch execute — common.runners.batch.run_batch():
- Parallelism default 2 (each aspect = ~5-10s API call; running 3 in parallel rarely problematic but rate-limit safety)
- Manifest updated after each aspect
--resume retries only failed aspects
Output:
./generated/flyer/<event-slug>/
portrait.png (1080×1350)
square.png (1080×1080)
story.png (1080×1920)
landscape.png (1920×1080, if requested)
a4.png (1240×1754, if requested)
manifest.json
style-used.md
prompts.md
stdout last lines:
Flyer: ./generated/flyer/<event-slug>/ (N/M aspects succeeded)
Files: portrait.png · square.png · story.png
MODES
Required
flyer-maker --title "<text>"
Strongly recommended (provide ≥1)
--date "<text>" — free-form date / time
--location "<text>"
--cta "<text>" — call to action (e.g., "Tickets: link in bio", "RSVP via DM", "Free entry")
Optional content
--subtitle "<text>" — secondary line under the title
--photo <path-or-url> — reference image to embed (speaker face, venue shot, theme image)
--lang en|ru — language of embedded text (default: matches the language of --title)
Visual
--style auto|<library-id> — visual style (uses carousel style library; default auto)
--style-mod "<override>" — append a tweak to the chosen anchor
--aspects portrait,square,story,landscape,a4 — comma list (default: portrait,square,story)
--variants N — N takes per aspect (default 1)
--model auto|<slug> — image provider (default auto)
Execution
--execute — actually generate (else returns plan + prompts)
--output <dir> — custom output (default ./generated/flyer/<event-slug>/)
--parallelism N — concurrent API calls (default 2, max 4)
--yes — skip cost confirmation
--resume — retry only failed aspects
--strict — fail (don't auto-substitute) if --model <slug> can't handle --photo
Inspection
--prompts-only — print plan + per-aspect prompts, exit (no API call)
--cost-only — print total cost, exit
--check — validate env vars + library files exist
STRUCTURED LAYOUT (Ideogram 4 only)
When --model is an ideogram-4* tier, emit the layout as structure instead of
flattening it into a sentence: add json_prompt to each plan item's kwargs,
following common/references/json-prompt.md.
This skill already knows where every element goes; sending that directly is what
stops the arrangement drifting between variants.
On any v3 tier the provider refuses a json_prompt rather than ignoring it, so
keep the prose prompt as written and send nothing extra.
REFERENCES (load on demand)
| File |
When to load |
| references/event-details.md |
Step 1 — required vs. optional fields, formatting conventions for date/time/location |
| references/aspect-presets.md |
Step 5 — pixel dimensions, social-platform-specific recommendations |
| references/composition-zones.md |
Step 5 — headline/visual/details zone layouts per aspect, anti-clutter rules |
| references/model-picker.md |
Step 4 — auto-pick decision tree, capability matrix, cost preview |
| references/troubleshoot.md |
When text renders wrong, photo doesn't integrate, layout collapses |
EXAMPLES
See examples/before-after.md — 3 calibration runs: solo founder workshop with embedded speaker photo (Nano Banana Pro), conference poster without photo using bold typographic Swiss style (Ideogram 3 Quality), three-aspect launch event with Kinfolk-minimal aesthetic + RU+EN bilingual variant (gpt-image-2).
CONSTRAINTS
Embedded text on image is the differentiator. Without text rendering, this is just a styled image — use image-prompt directly. The skill defaults to text-friendly models because the title + details MUST land readable.
Headlines ≤8 words. Past 8 words, even the best text-in-image models distort. The validator warns; the prompt assembly trims if longer.
One model for all aspects. Mixing providers across the portrait / square / story batch breaks visual cohesion. Lock per-flyer.
One style for all aspects. Same anchor across the batch.
Photo identity preserve uses Nano Banana Pro by default. For speaker portraits in a flyer, NBP is the safest pick. Override with --model gpt-image-2 if you need text + photo blended in a stylized layout.
Aspect compositions differ. A 1080×1350 portrait and a 1080×1920 story have different headline/details zones — see references/composition-zones.md. Don't assume the prompt is identical across aspects.
Cost confirm ONCE per batch. Sum across all aspects + variants.
--prompts-only is the safety dry-run. Always recommend it for first iteration — flyers iterate on copy + composition more than on style.
Manifest updates after every aspect. --resume retries only failed ones.
No QR codes in v1. If you need a QR (ticketing link, venue map), generate separately and overlay in a real image editor.
No print-ready output in v1. Outputs are RGB PNG at digital resolutions. For print: open in a DTP tool and convert.
Event-slug derived from title. Default: kebab-case of title, max 40 chars + date suffix. Override via --output <dir>.
--photo accepts local paths AND URLs. Provider routes accordingly.
Never print API keys. Mask in errors.
Output dir is ./generated/flyer/<event-slug>/ by default.
INVOCATION HINTS
When the user says any of:
- "make a flyer for X", "event poster for Y", "workshop flyer"
- "meetup poster", "concert poster", "exhibition flyer"
- "use this photo on a flyer", "put my face on a workshop poster"
- "flyer with embedded date and location"
- "промо для мероприятия", "афиша", "плакат", "флайер"
- "сделай афишу для воркшопа / встречи / митапа"
- "афиша с моей фоткой"
Defaults: --aspects portrait,square,story --style auto --model auto. Without --execute, returns prompts + plan; with --execute, generates files.
If the user mentions a specific platform (Instagram → emphasize 4:5 portrait + 9:16 story; LinkedIn → emphasize 1:1 square + 1.91:1 landscape; print → suggest A4 aspect), bias --aspects accordingly.
This skill is distinct from:
image-prompt — that writes prompts for any image; this orchestrates a multi-aspect batch for flyers specifically
carousel-builder — that's N-slide narrative; this is 1-image-per-aspect event posters
reel-builder — that's video; this is static images
For album / book / podcast covers: use image-prompt --execute with a simpler one-shot prompt (no event-details structure). A dedicated cover-maker skill is planned (see ROADMAP).
For YouTube thumbnails: image-prompt --execute with 16:9 size + face + bold title. A dedicated thumbnail-maker skill is planned.
1---2name: flyer-maker3description: Turn event details (title / date / location / CTA) plus optional photo into a poster / flyer / social-event-graphic with embedded text in a chosen style. Multi-aspect: portrait, square, story, landscape, a4. Use when: 'make a flyer for X', 'event poster', 'workshop flyer', 'meetup poster', 'афиша', 'плакат', 'флайер для мероприятия'.4license: MIT5---67<objective>8End-to-end flyer / poster generator. Input: event details (title, optional date / location / CTA) plus an optional user-supplied photo. Output: N single-image variants at different aspect ratios, each with the event details embedded as text + the photo integrated (if provided) + a consistent visual style.910This skill orchestrates three lower-level components:111. `image-prompt` style anchor + composition-zone vocabulary122. `common/runners` execute layer — multi-aspect batch generation via the chosen image provider133. `common/style-library/carousel/` — reuses the 24 carousel visual styles as the visual vocabulary (poster styles overlap heavily with editorial carousel styles)1415Use when the user wants a finished flyer image — not just a prompt. Without `--execute`, returns the assembled prompts; with `--execute`, generates the actual PNGs.1617This skill does NOT:18- Generate animated flyers (use `reel-builder` for motion)19- Render print-ready CMYK / 300DPI files — outputs are RGB at standard digital resolutions (1080 / 1240 px). For print: open the PNG in a real DTP tool (Affinity / InDesign / Photoshop) and convert.20- Compose multi-image collages — single image per aspect.21- Generate QR codes (deferred to v2.5.x — if you need a QR, generate separately and overlay manually).22- Search Eventbrite / Meetup / Luma for event metadata — you provide title / date / location explicitly.23- Replace a designer's judgment on layout — the composition zones are starter conventions; tweak via prompt iteration.24</objective>2526## ROLE2728Read the event details + optional photo + optional style → pick a model (text-friendly + multi-ref-capable if photo provided) → assemble per-aspect prompts with composition zones filled in → batch execute via the image provider → save PNGs + manifest → print paths.2930## PIPELINE31321. **Resolve event details**:33 - Required: `--title`34 - Strongly recommended: at least one of `--date`, `--location`, or `--cta` (a flyer without a single detail is just a styled portrait)35 - Optional: `--subtitle`, `--time` (can be merged with date)36372. **Resolve photo** (optional):38 - `--photo <path-or-url>`: passed as reference image to the chosen model.39 - Multi-ref capable models needed (Nano Banana Pro / Flux Kontext / gpt-image-2 / Ideogram 3 / Seedream 5.0).40 - If `--photo` provided AND `--model auto`: skill picks a ref-capable model.41 - If `--photo` provided AND `--model <slug>` that can't handle refs: warn + auto-substitute, or exit if user passed `--strict`.42433. **Resolve style** — see `references/event-details.md`:44 - `--style <library-id>`: load from `common/style-library/carousel/<id>.md`. Use the `Style anchor (text-in-image mode)` block (flyers always have text).45 - `--style auto`: pick from library based on the event type implied by the title + the chosen tone (formal, casual, indie, corporate). Algorithm same as carousel-builder.46 - `--style-mod "<override>"`: append a tweak to the anchor.47484. **Pick model** — see `references/model-picker.md`:49 - `--model auto`:50 - Photo provided + identity preserve critical (named speaker) → `nano-banana-pro`51 - Photo provided + brand-style transfer needed → `flux-2-pro` or `seedream-5`52 - Photo provided + Latin/CJK text needed → `gpt-image-2`53 - No photo + text-heavy → `ideogram-3-quality`54 - No photo + photoreal style → `nano-banana-pro` or `flux-2-pro`55 - `--model <slug>`: explicit override.56 - ONE model for all aspects (consistency across the family).57585. **Build per-aspect prompts** — see `references/composition-zones.md`:59 Each aspect has a composition template with three zones:60 - **Headline zone** (top 20-25%): title in large bold typography61 - **Visual zone** (middle 50-55%): photo integration if provided, else style anchor visual62 - **Details zone** (bottom 25-30%): date + location + CTA in smaller typography6364 The prompt assembly per aspect:65 ```66 <style anchor (text-in-image mode)>6768 Composition: <aspect-specific zone template>6970 Embed text:71 Headline: "<TITLE>"72 <Subtitle if present>73 <Date if present>74 <Location if present>75 <CTA if present>7677 Aspect ratio: <portrait|square|story|landscape|a4>78 Size: <pixel dimensions>79 ```80816. **Estimate cost + confirm** — sum aspects × variants. Under default carousel budget ($1.50) → no prompt; over → ask once.82837. **Batch execute** — `common.runners.batch.run_batch()`:84 - Parallelism default 2 (each aspect = ~5-10s API call; running 3 in parallel rarely problematic but rate-limit safety)85 - Manifest updated after each aspect86 - `--resume` retries only failed aspects87888. **Output**:89 ```90 ./generated/flyer/<event-slug>/91 portrait.png (1080×1350)92 square.png (1080×1080)93 story.png (1080×1920)94 landscape.png (1920×1080, if requested)95 a4.png (1240×1754, if requested)96 manifest.json97 style-used.md98 prompts.md99 ```100101 stdout last lines:102 ```103 Flyer: ./generated/flyer/<event-slug>/ (N/M aspects succeeded)104 Files: portrait.png · square.png · story.png105 ```106107## MODES108109### Required110111- `flyer-maker --title "<text>"`112113### Strongly recommended (provide ≥1)114115- `--date "<text>"` — free-form date / time116- `--location "<text>"`117- `--cta "<text>"` — call to action (e.g., "Tickets: link in bio", "RSVP via DM", "Free entry")118119### Optional content120121- `--subtitle "<text>"` — secondary line under the title122- `--photo <path-or-url>` — reference image to embed (speaker face, venue shot, theme image)123- `--lang en|ru` — language of embedded text (default: matches the language of `--title`)124125### Visual126127- `--style auto|<library-id>` — visual style (uses carousel style library; default auto)128- `--style-mod "<override>"` — append a tweak to the chosen anchor129- `--aspects portrait,square,story,landscape,a4` — comma list (default: `portrait,square,story`)130- `--variants N` — N takes per aspect (default 1)131- `--model auto|<slug>` — image provider (default auto)132133### Execution134135- `--execute` — actually generate (else returns plan + prompts)136- `--output <dir>` — custom output (default `./generated/flyer/<event-slug>/`)137- `--parallelism N` — concurrent API calls (default 2, max 4)138- `--yes` — skip cost confirmation139- `--resume` — retry only failed aspects140- `--strict` — fail (don't auto-substitute) if `--model <slug>` can't handle `--photo`141142### Inspection143144- `--prompts-only` — print plan + per-aspect prompts, exit (no API call)145- `--cost-only` — print total cost, exit146- `--check` — validate env vars + library files exist147148## STRUCTURED LAYOUT (Ideogram 4 only)149150When `--model` is an `ideogram-4*` tier, emit the layout as structure instead of151flattening it into a sentence: add `json_prompt` to each plan item's `kwargs`,152following [`common/references/json-prompt.md`](../../common/references/json-prompt.md).153This skill already knows where every element goes; sending that directly is what154stops the arrangement drifting between variants.155156On any v3 tier the provider refuses a `json_prompt` rather than ignoring it, so157keep the prose prompt as written and send nothing extra.158159## REFERENCES (load on demand)160161| File | When to load |162|---|---|163| [references/event-details.md](references/event-details.md) | Step 1 — required vs. optional fields, formatting conventions for date/time/location |164| [references/aspect-presets.md](references/aspect-presets.md) | Step 5 — pixel dimensions, social-platform-specific recommendations |165| [references/composition-zones.md](references/composition-zones.md) | Step 5 — headline/visual/details zone layouts per aspect, anti-clutter rules |166| [references/model-picker.md](references/model-picker.md) | Step 4 — auto-pick decision tree, capability matrix, cost preview |167| [references/troubleshoot.md](references/troubleshoot.md) | When text renders wrong, photo doesn't integrate, layout collapses |168169## EXAMPLES170171See [examples/before-after.md](examples/before-after.md) — 3 calibration runs: solo founder workshop with embedded speaker photo (Nano Banana Pro), conference poster without photo using bold typographic Swiss style (Ideogram 3 Quality), three-aspect launch event with Kinfolk-minimal aesthetic + RU+EN bilingual variant (gpt-image-2).172173## CONSTRAINTS174175- **Embedded text on image is the differentiator.** Without text rendering, this is just a styled image — use `image-prompt` directly. The skill defaults to text-friendly models because the title + details MUST land readable.176177- **Headlines ≤8 words.** Past 8 words, even the best text-in-image models distort. The validator warns; the prompt assembly trims if longer.178179- **One model for all aspects.** Mixing providers across the portrait / square / story batch breaks visual cohesion. Lock per-flyer.180181- **One style for all aspects.** Same anchor across the batch.182183- **Photo identity preserve uses Nano Banana Pro by default.** For speaker portraits in a flyer, NBP is the safest pick. Override with `--model gpt-image-2` if you need text + photo blended in a stylized layout.184185- **Aspect compositions differ.** A 1080×1350 portrait and a 1080×1920 story have different headline/details zones — see `references/composition-zones.md`. Don't assume the prompt is identical across aspects.186187- **Cost confirm ONCE per batch.** Sum across all aspects + variants.188189- **`--prompts-only` is the safety dry-run.** Always recommend it for first iteration — flyers iterate on copy + composition more than on style.190191- **Manifest updates after every aspect.** `--resume` retries only failed ones.192193- **No QR codes in v1.** If you need a QR (ticketing link, venue map), generate separately and overlay in a real image editor.194195- **No print-ready output in v1.** Outputs are RGB PNG at digital resolutions. For print: open in a DTP tool and convert.196197- **Event-slug derived from title.** Default: kebab-case of title, max 40 chars + date suffix. Override via `--output <dir>`.198199- **`--photo` accepts local paths AND URLs.** Provider routes accordingly.200201- **Never print API keys.** Mask in errors.202203- **Output dir is `./generated/flyer/<event-slug>/`** by default.204205## INVOCATION HINTS206207When the user says any of:208209- "make a flyer for X", "event poster for Y", "workshop flyer"210- "meetup poster", "concert poster", "exhibition flyer"211- "use this photo on a flyer", "put my face on a workshop poster"212- "flyer with embedded date and location"213- "промо для мероприятия", "афиша", "плакат", "флайер"214- "сделай афишу для воркшопа / встречи / митапа"215- "афиша с моей фоткой"216217Defaults: `--aspects portrait,square,story --style auto --model auto`. Without `--execute`, returns prompts + plan; with `--execute`, generates files.218219If the user mentions a specific platform (Instagram → emphasize 4:5 portrait + 9:16 story; LinkedIn → emphasize 1:1 square + 1.91:1 landscape; print → suggest A4 aspect), bias `--aspects` accordingly.220221This skill is **distinct from**:222- `image-prompt` — that writes prompts for any image; this orchestrates a multi-aspect batch for flyers specifically223- `carousel-builder` — that's N-slide narrative; this is 1-image-per-aspect event posters224- `reel-builder` — that's video; this is static images225226For album / book / podcast covers: use `image-prompt --execute` with a simpler one-shot prompt (no event-details structure). A dedicated `cover-maker` skill is planned (see ROADMAP).227228For YouTube thumbnails: `image-prompt --execute` with 16:9 size + face + bold title. A dedicated `thumbnail-maker` skill is planned.