diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 82cd4da..2d1b6dd 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "meta-ads-designer", "description": "Design and generate posters, flyers, Meta/social ads and promo graphics that look art-directed instead of AI-generated.", - "version": "5.10.0", + "version": "6.2.0", "author": { "name": "AI Evolution Labs", "url": "https://github.com/aievolutionpl" }, "homepage": "https://github.com/aievolutionpl/meta-ads-designer", "license": "MIT", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5c2460..46de4c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,3 +19,5 @@ jobs: run: python scripts/check_docs.py - name: QA gate self-test run: python scripts/test_qa.py + - name: Creative diagnostics self-test + run: python scripts/test_diagnostics.py diff --git a/CHANGELOG.md b/CHANGELOG.md index c67f402..87b47c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,58 @@ All notable changes to Meta Ads Designer. Versions follow [SemVer](https://semve --- +## [6.2.0] — 2026-09-24 + +### Added +- **`R52` The words must sell.** A five-question sell test (what is it · why me · why believe it · why now · only we could say it) runs on every on-image string. Mood lines, unproven superlatives and generic questions count as copy slop and a hard fail. Added to `headline-system.md` §0 with before/after rewrites, `core.md` §11a and the `SKILL.md` decision steps. +- **AI-generated README showcase** (`assets/showcase/`): a hero and three ads generated from the skill's prompts, analysed in `examples/08-generated-showcase.md`. The analysis covers text transcription, defects and R52 copy failures, and `prompts/readme-showcase-v2.txt` carries the round-2 selling hooks. + +--- + +## [6.1.0] — 2026-09-24 + +### Fixed +- **5.11.0 and 6.0.0 now reach `main`.** The previous merge only carried 5.10.0. +- **R50 contradictions removed.** Older guidance in core, the engine, the charter, headline system, model routing, prompt library, QA gate, layout system, hospitality and niche playbooks, style atlas and static formats told the agent to typeset text or compose logos in code (Mode B). It now says to generate with quoted copy, pass references and transcribe the result. Mode B survives only as an explicit-request fallback, and examples 00, 01 and 04 carry the R50 note. + +### Added +- **`scripts/generate_fal.py`**: generates ads through fal.ai's queue API from a prompt file, saves the images and a reproducibility log (model, prompt, seed, request id). Standard library only; needs `FAL_KEY`. +- **`examples/08-generated-showcase.md`** and `examples/prompts/readme-showcase.txt`: the full R51 loop and three ready prompts for the README showcase. + +--- + +## [6.0.0] — 2026-09-24 + +Doctrine change, hence the major version: final ads are always generated by an AI image model, and the agent researches and asks before it generates. + +### Added +- **`R50` Generated, never coded.** Every final ad (imagery, headline, copy, layout) comes out of an image model: an API model, Codex or the host's tool. HTML, code or programmatic overlays are used only on explicit request. It overrides every earlier "Mode B / deterministic composition / typesetting handoff" instruction. Text reliability now comes from quoted copy with diacritics, "no other text", hierarchy and position, reference images with roles, post-render transcription, and regeneration or targeted model edits. +- **`R51` Research and ask before generating.** Research the brand site, Meta Ad Library, competitors, reviews and season. Ask 3–6 questions in one message, each with a default. Write a decision note, then prompt, generate and analyse each result. +- **`references/discovery-and-research.md`**: research table, question bank, decision-note template and the post-generation analysis order. + +### Changed +- `SKILL.md` (new first section, generation-first text contract, analysis step, description), `core.md` §0 and §12, `prompt-craft.md` §2, the engine's precedence note, `design-rules.md` §4, both READMEs, and notes on examples 02, 03, 05 and 07. + +### Removed +- The HTML-typeset Style Atlas board (`assets/style-atlas-2026.png`, `assets/generated/style-atlas.html`). A coded board contradicted R50. + +--- + +## [5.11.0] — 2026-09-24 + +Skills as repeatable jobs, following Metaflow's overview of Claude skills for Meta ads (CPA diagnostics, creative fatigue detection, competitor creative analysis). + +### Added +- **`R49` Diagnose before you redesign**: read results first, stop at the first broken funnel step, and change only the creative decision it points to. +- **`references/creative-diagnostics.md`**: input and output contracts, a symptom → cause → change table, and guardrails against claiming causation. +- **`scripts/creative_diagnostics.py`**: reads an Ads Manager CSV export (comma, semicolon or tab; Polish decimal commas), compares each ad with the account median, flags fatigue, weak hook, weak hold, low CTR, high CPM, high CPA and winners, and prints the next-brief action for each. Standard library only; `scripts/test_diagnostics.py` in CI. + +### Changed +- **`SKILL.md`**: campaign requests deliver a package (working note, prompt, typesetting handoff, per-placement output, landing continuity line); results route to diagnostics first. +- **`core.md`** §19a, the engine, both READMEs, the charter and CI. + +--- + ## [5.10.0] — 2026-09-24 The 2026 feed layer: what current Meta ads look like, which structures persuade, and what changed on the platform. Researched from Behance and Dribbble portfolio patterns, Penji's Meta design guidance, Meta's Ads Guide and about thirty 2026 sources on creative performance, trends and placement changes. Third-party figures are labelled as such and never presented as promised results. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fb64ed9..f0c40ea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ This is a **rules repo** — the value is the design doctrine. Every contributio | File | Role | When to edit it | |------|------|-----------------| -| **`visual-advertising-engine.md`** | The canonical standard (48 rules) | **Adding/refining a rule → edit here FIRST.** This is the source of truth. English. | +| **`visual-advertising-engine.md`** | The canonical standard (52 rules) | **Adding/refining a rule → edit here FIRST.** This is the source of truth. English. | | `design-rules.md` | The readable charter (English canonical) | Summarize a rule already in the engine. | | `core.md` | The complete general-knowledge inject | Add only if a rule is so essential it must be in the inject. | | `SKILL.md` | Agent manual | Procedural/workflow changes. | diff --git a/README.en.md b/README.en.md index 626b6c7..443372c 100644 --- a/README.en.md +++ b/README.en.md @@ -6,13 +6,17 @@ An AI agent skill for choosing **composition, typography, colour and visual dire [Polski](README.md) · [Agent instructions](SKILL.md) · [Quick start](#quick-start) · [Examples](examples/README.md) -![Version](https://img.shields.io/badge/version-5.10.0-222222) +![Version](https://img.shields.io/badge/version-6.2.0-222222) ![License](https://img.shields.io/badge/license-MIT-222222) ![Model independent](https://img.shields.io/badge/prompts-model_independent-222222) -![Meta Ads Designer — bold contemporary typography and three advertising concepts](assets/meta-ads-designer-bold.png) +![Meta Ads Designer — AI-generated showcase](assets/showcase/hero.jpg) -*AI-generated demonstration concepts: fictional cafe DAYBREAK, event AFTER HOURS and brand FORM. These illustrate design directions, not client campaigns or measured advertising performance. [Exact prompt and image notes](examples/06-readme-showcase.md).* +| | | | +|---|---|---| +| ![PORA](assets/showcase/ad-pora.jpg) | ![NURT](assets/showcase/ad-nurt.jpg) | ![NOC BRZMI](assets/showcase/ad-noc-brzmi.jpg) | + +*Fully AI-generated from the skill's prompts: no retouching, no code overlays. Brands are fictional. [Prompts, analysis and round 2](examples/08-generated-showcase.md).* ## What the skill does @@ -36,11 +40,13 @@ The same concepts can also take a quieter editorial direction: *A second demonstration board. The art direction changes; the skill is not restricted to either style.* -## New in 5.10: the 2026 feed layer +## New in 6.0: research, questions, AI generation -![Style Atlas 2026: six fictional ads, each pairing a static format with one visual language](assets/style-atlas-2026.png) +- **Always generated by AI from scratch.** Every final ad comes out of an image model (API, Codex or the host's tool), headline and layout included. No HTML or coded composition (R50). +- **Research first, then questions.** The agent checks the brand's site, Meta Ad Library, competitors and reviews, then asks 3–6 sharp questions at once, each with a default, and writes prompts from a decision note (R51). +- **Analysis after generation.** The agent transcribes every word in the image, checks product and logo fidelity, runs the thumbnail test and changes one decision per iteration. -*Six fictional ads typeset deterministically in HTML ([source](assets/generated/style-atlas.html)): no image model, no client assets, no performance claims. Each pairs a persuasion format with one visual language.* +### The 2026 layer The skill now knows what current Meta ads look like and why some structures persuade: @@ -59,6 +65,7 @@ flowchart LR D --> E["Image and visual review"] ``` +1. **Research and questions** — study the brand, Ad Library and competitors, ask 3–6 questions, write a decision note. 1. **Brief** — establish audience, verified offer, goal, format and available assets. 2. **Idea** — choose what makes the benefit visible: product, action, detail, situation or type. 3. **Art direction** — pick a format the proof supports and one visual language, then define the focal element, reading order, copy space, fonts and palette. @@ -96,9 +103,7 @@ git clone https://github.com/aievolutionpl/meta-ads-designer.git ## Text and logos -Short copy can be generated with the ad and inspected afterwards. When exact fonts, diacritics, prices or official logos matter, the skill supports separate typesetting: an image with planned copy space plus a composition specification. - -A prompt communicates intent. It cannot guarantee identical fonts, pixel coordinates or perfect spelling in every tool. +The whole ad, text included, is generated by the AI model. The skill quotes exact copy with correct diacritics, gives hierarchy and position, and passes the logo and product as reference images. After generation the agent transcribes every word. On an error it regenerates or runs a targeted edit with the same model instead of overlaying text in code. ## Repository guide @@ -108,12 +113,14 @@ A prompt communicates intent. It cannot guarantee identical fonts, pixel coordin | [core.md](core.md) | Self-contained chat instruction | | [Art direction](references/art-direction.md) | Marketing goal to composition and typography | | [Prompt craft](references/prompt-craft.md) | Writing and reviewing prompts | +| [Discovery and research](references/discovery-and-research.md) | Research, pre-generation questions, decision note, result analysis | | [Style atlas 2026](references/style-atlas-2026.md) | Twelve visual languages, trend slop, reading reference boards | | [Static ad formats](references/static-ad-formats.md) | Persuasion skeletons, proof, funnel and vertical fit | | [Worked prompts](examples/05-model-independent-directions.md) | Flyer, food and local service | | [2026 style directions](examples/07-2026-style-directions.md) | Format plus style briefs and an Andromeda-ready campaign set | -| [Visual Advertising Engine](visual-advertising-engine.md) | Canonical rules R01–R48 | +| [Visual Advertising Engine](visual-advertising-engine.md) | Canonical rules R01–R52 | | [Layout system](references/layout-system.md) | Starting values for grids, margins and type | +| [Creative diagnostics](references/creative-diagnostics.md) | From an Ads Manager export to the next brief (`scripts/creative_diagnostics.py`) | | [Platform guidance](references/platform-compliance.md) | Safe zones, text limits, Advantage+, AI labels | | [QA gate](references/qa-gate.md) | Reviewing actual rendered images | | [More examples](examples/README.md) | Briefs, prompts and design decisions | @@ -124,6 +131,7 @@ A prompt communicates intent. It cannot guarantee identical fonts, pixel coordin pip install -r requirements.txt python scripts/check_docs.py python scripts/test_qa.py +python scripts/test_diagnostics.py ``` Documentation checks validate links, rule references and versions. Image QA measures selected technical properties; composition, credibility and brief fidelity need separate review. Campaign performance requires measurement after publication. diff --git a/README.md b/README.md index 880d27a..785c2f3 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,17 @@ Skill dla agentów AI, który pomaga dobierać **kompozycję, typografię, kolor [English](README.en.md) · [Instrukcja skilla](SKILL.md) · [Szybki start](#szybki-start) · [Przykłady](examples/README.md) -![Version](https://img.shields.io/badge/version-5.10.0-222222) +![Version](https://img.shields.io/badge/version-6.2.0-222222) ![License](https://img.shields.io/badge/license-MIT-222222) ![Model independent](https://img.shields.io/badge/prompts-model_independent-222222) -![Meta Ads Designer — nowoczesna typografia i trzy wyraziste kreacje reklamowe](assets/meta-ads-designer-bold.png) +![Meta Ads Designer — AI-generated showcase](assets/showcase/hero.jpg) -*Koncepcje demonstracyjne wygenerowane z art-directed promptu: fikcyjna kawiarnia DAYBREAK, wydarzenie AFTER HOURS i marka FORM. To ilustracja kierunków projektowych, nie kampanie klientów ani dowód skuteczności reklamowej. [Prompt i opis grafiki](examples/06-readme-showcase.md).* +| | | | +|---|---|---| +| ![PORA](assets/showcase/ad-pora.jpg) | ![NURT](assets/showcase/ad-nurt.jpg) | ![NOC BRZMI](assets/showcase/ad-noc-brzmi.jpg) | + +*Przykłady wygenerowane w całości przez AI z promptów skilla: bez retuszu i bez nakładek w kodzie. Marki są fikcyjne. [Prompty, analiza i runda 2](examples/08-generated-showcase.md).* ## Co robi ten skill @@ -36,11 +40,13 @@ Ten sam zestaw pomysłów można rozwinąć w spokojniejszym kierunku editorial: *Druga plansza demonstracyjna. Zmienia się charakter art direction, a nie zakres możliwości skilla.* -## Nowość w 5.10: warstwa 2026 +## Nowość w 6.0: research, pytania i generacja AI -![Style Atlas 2026: sześć fikcyjnych reklam, każda łączy format statyczny z jednym językiem wizualnym](assets/style-atlas-2026.png) +- **Zawsze generacja AI od zera.** Każda finalna reklama powstaje w modelu obrazu (API, Codex albo narzędzie hosta), razem z nagłówkiem i układem. Żadnego składania grafik w HTML czy kodzie (R50). +- **Najpierw research, potem pytania.** Agent sprawdza stronę marki, Meta Ad Library, konkurencję i opinie, a potem zadaje 3–6 trafnych pytań naraz, z domyślną odpowiedzią przy każdym. Dopiero z notatki decyzyjnej pisze prompty (R51). +- **Analiza po generacji.** Agent przepisuje każde słowo z obrazu, sprawdza wierność produktu i logo, robi test miniatury i zmienia jedną decyzję na iterację. -*Sześć fikcyjnych reklam złożonych deterministycznie w HTML ([źródło](assets/generated/style-atlas.html)): bez modelu obrazu, bez materiałów klientów, bez obietnic wyników. Każda łączy format perswazji z jednym językiem wizualnym.* +### Warstwa 2026 Skill wie teraz, jak wyglądają aktualne reklamy Meta i dlaczego pewne struktury przekonują: @@ -59,6 +65,7 @@ flowchart LR D --> E["Obraz i ocena wizualna"] ``` +1. **Research i pytania** — agent bada markę, Ad Library i konkurencję, zadaje 3–6 pytań i spisuje notatkę decyzyjną. 1. **Brief** — agent ustala odbiorcę, prawdziwą ofertę, cel, format i dostępne materiały. 2. **Pomysł** — wybiera, co pokaże korzyść: produkt, działanie, detal, sytuacja lub typografia. 3. **Art direction** — wybiera format, na który pozwala dowód, i jeden język wizualny, a potem określa dominantę, kolejność czytania, przestrzeń na tekst, fonty i paletę. @@ -96,9 +103,7 @@ Instrukcją wejściową jest [SKILL.md](SKILL.md). Szczegóły dla poszczególny ## Tekst i logo w reklamie -Dla krótkich treści można poprosić generator o gotową reklamę i sprawdzić jej pisownię. Gdy liczą się dokładny font, polskie znaki, cena lub oficjalne logo, skill przewiduje osobny skład: obraz z zaplanowanym miejscem na tekst oraz specyfikację typografii. - -Prompt wyraża intencję projektową. Nie gwarantuje identycznego fontu, położenia co do piksela ani bezbłędnej pisowni w każdym narzędziu. +Cała reklama, łącznie z tekstem, powstaje w modelu AI. Skill pisze dokładne cytaty tekstu z polskimi znakami, podaje hierarchię i położenie, a logo i produkt przekazuje jako obrazy referencyjne. Po generacji agent przepisuje każde słowo z obrazu. Przy błędzie generuje ponownie albo robi celowaną edycję tym samym modelem, zamiast nakładać tekst kodem. ## Materiały w repozytorium @@ -108,12 +113,14 @@ Prompt wyraża intencję projektową. Nie gwarantuje identycznego fontu, położ | [core.md](core.md) | Samodzielna instrukcja do wklejenia w czacie | | [Art direction](references/art-direction.md) | Od celu marketingowego do kompozycji i typografii | | [Prompt craft](references/prompt-craft.md) | Pisanie i sprawdzanie promptów | +| [Research i pytania](references/discovery-and-research.md) | Research, pytania przed generacją, notatka decyzyjna, analiza wyników | | [Atlas stylów 2026](references/style-atlas-2026.md) | Dwanaście języków wizualnych, trend slop, czytanie plansz referencyjnych | | [Formaty statyczne](references/static-ad-formats.md) | Szkielety perswazji, dowód, lejek i dopasowanie do branży | | [Przykłady promptów](examples/05-model-independent-directions.md) | Flyer, gastronomia i usługa lokalna | | [Kierunki 2026](examples/07-2026-style-directions.md) | Briefy „format + styl” i zestaw kampanii pod Andromedę | -| [Visual Advertising Engine](visual-advertising-engine.md) | Kanoniczne reguły R01–R48 | +| [Visual Advertising Engine](visual-advertising-engine.md) | Kanoniczne reguły R01–R52 | | [Layout system](references/layout-system.md) | Punkty wyjścia dla siatki, marginesów i skali tekstu | +| [Diagnostyka kreacji](references/creative-diagnostics.md) | Z eksportu Ads Managera do kolejnego briefu (`scripts/creative_diagnostics.py`) | | [Platformy](references/platform-compliance.md) | Strefy bezpieczne, limity tekstu, Advantage+, etykiety AI | | [QA gate](references/qa-gate.md) | Ocena rzeczywiście wygenerowanych obrazów | | [Pozostałe przykłady](examples/README.md) | Briefy, prompty i omówienie decyzji | @@ -124,6 +131,7 @@ Prompt wyraża intencję projektową. Nie gwarantuje identycznego fontu, położ pip install -r requirements.txt python scripts/check_docs.py python scripts/test_qa.py +python scripts/test_diagnostics.py ``` Kontrole dokumentacji sprawdzają linki, odwołania do reguł i wersje. Skrypt QA bada wybrane cechy techniczne obrazu; ocenę kompozycji, wiarygodności i zgodności z briefem trzeba wykonać osobno. Wyniki kampanii wymagają pomiaru po publikacji. diff --git a/SKILL.md b/SKILL.md index b3badbd..70cd329 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,9 +1,9 @@ --- name: meta-ads-designer -description: Art-direct social ads, posters and flyers and write model-independent image prompts when a user requests advertising visuals, stronger composition or less generic AI design. +description: Research, question, art-direct and generate Meta/social ads, posters and flyers with AI image models (API, Codex or built-in tools), using strong prompts and post-generation analysis, when a user requests advertising visuals or less generic AI design. license: MIT metadata: - version: 5.10.0 + version: 6.2.0 author: AI Evolution Labs url: https://github.com/aievolutionpl/meta-ads-designer --- @@ -12,7 +12,14 @@ metadata: Act as an advertising art director. Translate a business message into a deliberate visual composition and a precise image prompt. Judge by what the audience understands, where their eye goes and whether the creative belongs to this brand. -This skill works independently of image models, for prompt writing alone or generation with available tools. Model selection and API setup are not prerequisites. +Final ads are always generated from scratch by an AI image model, whether an API model, Codex or the host's image tool, never coded or templated. The craft is in research, the prompt and the analysis of what comes back. The prompts are model-independent. When no image tool is available, deliver the ready prompts and say that nothing was rendered. + +## Research and ask before generating + +Do not generate from a thin brief. Read [discovery and research](references/discovery-and-research.md) and follow its order (R51): +1. **Research** with the tools available: the brand's site and social profiles, Meta Ad Library for the brand and 2–3 competitors, reviews, and the seasonal context. Write a 5–8 bullet research note, each bullet ending in an implication for the ad. +2. **Ask 3–6 questions in one message**, only what research did not answer and what changes the prompt: offer and proof, audience and moment, main objection, style direction, references, placements, language, image model. Give a recommended default for each. If the user says "just do it", skip the questions and list your assumptions. +3. **Write the decision note** (brief, insight, concepts, references, exact copy, output) before the first prompt. For a campaign, wait for approval before generating many images. ## Understand the brief @@ -30,7 +37,7 @@ Read [art direction](references/art-direction.md) before drafting a new directio 2. For a static ad, choose the format, the persuasion skeleton, from the proof you actually have and the audience's stage. Read [static ad formats](references/static-ad-formats.md). No verified number, no stat drop; no real review, no review card. 3. Choose one visual language and commit to its type, colour, image treatment and signature device. Read [style atlas 2026](references/style-atlas-2026.md). Brand identity outranks trend; never mix two dialects in one frame. 4. Define dominant element, reading path, copy field, quiet area, brand anchor and edge treatment. -5. Choose type by role, width, weight, language and brand. Set exact copy and line breaks. +5. Choose type by role, width, weight, language and brand. Set exact copy and line breaks. Run the sell test (R52) on every string: the headline states a concrete benefit or result for this product, the support line proves it or gives a reason to act, the CTA names the action. No mood lines, no unproven superlatives. 6. Assign colour roles and, for photography, light and material treatment. 7. Remove anything that competes without helping the message. @@ -44,10 +51,13 @@ The canonical [engine](visual-advertising-engine.md) defines stable rule IDs. R4 Read [prompt craft](references/prompt-craft.md). Deliver one coherent ready-to-use prompt with output, message, reference roles, medium, spatial composition, type/copy contract, palette and relevant constraints. Photography adds light and camera; a flat poster does not need them. No unresolved placeholders or contradictory directions. -Choose a text contract: -- Short generated copy: quote all strings and describe hierarchy. Inspect spelling if rendered. -- Exact or dense copy: request a clean image with planned copy space and supply a separate typesetting specification. -- Type-led artwork: specify the grid and type as the main visual; use a composition tool if exact typography is required. +Every final ad is generated by an image model from the prompt (an API model, Codex or the host's image tool), including its headline, copy and layout. Never build or finish the ad with HTML, code or programmatic overlays unless the user explicitly asks for that (R50). + +Text in the generated image: +- Quote every string exactly, in the ad's language with correct diacritics, say "no other text", and give hierarchy, line breaks and position. +- Keep copy short: headline ≤ 6 words, one support line, one CTA. Move the rest to Meta's text fields. +- After generation, transcribe every word in the image and compare it with the approved copy. On a misspelling, regenerate or run a targeted edit with the same model. Never paint over the image in code. +- Supply the official logo and product photos as reference images with named roles, and require them unchanged. Font names and percentages express intent, not guaranteed rendering. Place official logo assets appropriately rather than inventing a plausible logo. @@ -57,10 +67,12 @@ Read [worked directions](examples/05-model-independent-directions.md) for comple For prompts alone, check facts, clarity, spatial feasibility, copy fit, reference fidelity and internal consistency. Deliver the prompt plus a short production note only where needed. Never claim visual QA or conversion results without evidence. -For generated images, inspect phone-size hierarchy and full-resolution text, identity and defects. Use [QA gate](references/qa-gate.md). The script checks a conservative layout profile; it does not prove beauty, spelling or fidelity. Explain inapplicable heuristics instead of reporting a false PASS. +For generated images, analyse every result before showing it as done, following [discovery and research](references/discovery-and-research.md) §4: transcribe the text, check reference fidelity, run the thumbnail test, name defects, then ship or change one decision and regenerate. Inspect phone-size hierarchy and full-resolution text, identity and defects. Use [QA gate](references/qa-gate.md). The script checks a conservative layout profile; it does not prove beauty, spelling or fidelity. Explain inapplicable heuristics instead of reporting a false PASS. For revisions, preserve successful decisions and change the failed one. Read [artifact control](references/artifact-control.md) for preservation and symptom-based recovery. Do not diagnose an artifact's cause from appearance alone or assume all tools share session behaviour. +When the user asks for a campaign or a new creative, deliver a package, not a loose prompt: the working note (format, style, persona, hook), the generation prompt with every string quoted, one native file or prompt per requested placement, and a continuity line for the landing page. If results already exist, diagnose them first (R49). + Deliver requested outputs and placements. If image tools are unavailable, provide the prompt and handoff and state what remains unrendered. ## Campaigns and deeper guidance @@ -71,6 +83,7 @@ Read only what is relevant: | Need | Reference | |---|---| +| Research, discovery questions, decision note, post-generation analysis | [Discovery and research](references/discovery-and-research.md) | | Visual languages, trend reading, reference boards | [Style atlas 2026](references/style-atlas-2026.md) | | Static formats, proof and funnel fit | [Static ad formats](references/static-ad-formats.md) | | Canvas, spacing and type starting values | [Layout system](references/layout-system.md) | @@ -82,8 +95,9 @@ Read only what is relevant: | Generic visuals | [Anti-slop registry](references/anti-slop-registry.md), interpreted through R42 | | Competitor analysis | [Competitor teardown](references/competitor-ad-teardown.md) | | Placement-specific delivery, Advantage+, AI labels | [Platform guidance](references/platform-compliance.md); verify changing requirements when relevant | -| Existing campaign results | [Performance loop](references/creative-performance-loop.md) | +| Existing campaign results, fatigue, CPA spikes | [Creative diagnostics](references/creative-diagnostics.md) (run `scripts/creative_diagnostics.py` on a CSV export), [performance loop](references/creative-performance-loop.md) | | Requested motion | [Video track](references/video-ugc-track.md) | +| Generating through fal.ai | `scripts/generate_fal.py` (needs `FAL_KEY`); see [generated showcase](examples/08-generated-showcase.md) | | Requested setup or tool routing | [Installation](INSTALL.md), [model routing](references/model-routing.md) | Do not publish campaigns or spend ad budget merely because a reference describes those activities. diff --git a/assets/generated/style-atlas.html b/assets/generated/style-atlas.html deleted file mode 100644 index 9ea5788..0000000 --- a/assets/generated/style-atlas.html +++ /dev/null @@ -1,310 +0,0 @@ - - - - -Style Atlas 2026 — Meta Ads Designer - - - - - - - - -
-
-

Style Atlas 2026

-

Format × visual language. Six fictional ads typeset in HTML from references/style-atlas-2026.md: no image model, no client assets.

-
-
Meta Ads Designer 5.10
R45 · one visual language
R46 · format follows proof
-
- -
- - -
-
-
Noc
brzmi
- - - -
-
18.10.2026 · 20:00
-
Studio 8
-
Bilety: nocbrzmi.example
-
-
-
01Oversized type posterBold statement · weight contrast in one headline
-
- - -
-
-
Notatki · dziś
-
-

Czego nigdy nie robimy
u klientów

-
24 września, 09:12
-
    -
  • nie przestawiamy rzeczy bez pytania
  • -
  • nie używamy Twoich ręczników
  • -
  • nie zmieniamy ekipy co tydzień
  • -
  • nie zostawiamy zapachu chemii
  • -
-
PORZĄDEKUmów sprzątanie →
-
-
02Native interface: notesConfession · objection handling in the owner's voice
-
- - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LUMA - SERUM · 30 ML - - - - - - -
47/60
-
reported smoother skin
in 4 weeks
-
Independent user study, 60 participants, 2026.
-
LUMA
-
-
03Colour-block still lifeStat drop · verified number with its source line
-
- - -
-
-
Zimna
do wieczora.
-
NURT
- - - - - - - - - - - - - - - - - - NURT - - - - - - - - - - - - - -
24 h zimna
-
750 ml
-
stal 18/8
-
−20%na start
- -
-
04Performance sticker bannerProduct + callouts · one sticker, one verified offer
-
- - -
-
- - - - - - - - - - - - - - - - - - - - -
-
-
Targ
winyli
-
SOBOTA12.10
-
Hala Targowa 3
10:00–17:00 · wstęp wolny
- - - - - -
-
05Tactile zineEvent flyer · two-ink overprint as the one process
-
- - -
-
-

Kawa, która
nie czekała na półce.

- - - - - -
ZIARNOz marketu
Palenie✓7 dni temudata nieznana
Mielenie✓u Ciebiew fabryce
Dostawa✓co 2 tygodniewizyta w sklepie
-
ZIARNOZamów pierwszą paczkę →
-
-
06Quiet minimalComparison · a category, not a named competitor
-
- -
- - diff --git a/assets/showcase/ad-noc-brzmi.jpg b/assets/showcase/ad-noc-brzmi.jpg new file mode 100644 index 0000000..7f594f6 Binary files /dev/null and b/assets/showcase/ad-noc-brzmi.jpg differ diff --git a/assets/showcase/ad-nurt.jpg b/assets/showcase/ad-nurt.jpg new file mode 100644 index 0000000..0ceb6d6 Binary files /dev/null and b/assets/showcase/ad-nurt.jpg differ diff --git a/assets/showcase/ad-pora.jpg b/assets/showcase/ad-pora.jpg new file mode 100644 index 0000000..d607e98 Binary files /dev/null and b/assets/showcase/ad-pora.jpg differ diff --git a/assets/showcase/hero.jpg b/assets/showcase/hero.jpg new file mode 100644 index 0000000..fefa25e Binary files /dev/null and b/assets/showcase/hero.jpg differ diff --git a/assets/style-atlas-2026.png b/assets/style-atlas-2026.png deleted file mode 100644 index b1ecb4f..0000000 Binary files a/assets/style-atlas-2026.png and /dev/null differ diff --git a/core.md b/core.md index 0020f11..0889a72 100644 --- a/core.md +++ b/core.md @@ -1,6 +1,6 @@ # 🎬 Meta Ads Designer — CORE (inject me) -> **Paste this into any AI chat (ChatGPT, Claude, Gemini) or any agent's system prompt.** Self-contained: the full general knowledge for generating beautiful social-media ads. Deeper numbers: `references/layout-system.md` + `references/headline-system.md`. Full standard: `visual-advertising-engine.md` (R01–R48). QA gate: `references/qa-gate.md`. +> **Paste this into any AI chat (ChatGPT, Claude, Gemini) or any agent's system prompt.** Self-contained: the full general knowledge for generating beautiful social-media ads. Deeper numbers: `references/layout-system.md` + `references/headline-system.md`. Full standard: `visual-advertising-engine.md` (R01–R52). QA gate: `references/qa-gate.md`. --- @@ -14,10 +14,15 @@ Choose photography, documentary, illustration, graphic form or typography for th Before prompting, decide reading order, dominant element, copy field, quiet space, type roles and palette roles. Name a preferred font and describe its weight/width; quote exact copy and line breaks. Layout numbers are starting points; actual text must fit. Shorten copy before shrinking essential information. -For prompt-only requests, deliver one complete prompt and an optional typesetting handoff. Check facts, spatial conflicts and contradictory instructions. Never score an unseen image. Explore multiple concepts when useful; hold one variable at a time only for controlled tests. Brand and brief outrank generic recipes. +For prompt-only requests, deliver one complete generation prompt with all copy quoted inside it. Check facts, spatial conflicts and contradictory instructions. Never score an unseen image. Explore multiple concepts when useful; hold one variable at a time only for controlled tests. Brand and brief outrank generic recipes. --- +## 0 · Before generating: research and ask (R51) +1. **Research:** the brand's site and socials, Meta Ad Library for the brand and 2–3 competitors, reviews, season. Note 5–8 findings, each with its implication for the ad. +2. **Ask 3–6 questions in one message**, each with a default: offer and proof · who and at what moment · main objection · style (bold / premium / phone-real / graphic) · references to keep exactly · placements and number of concepts · language · image model. +3. **Decision note:** brief · insight · concepts (persona, hook, format, style) · references · exact copy · output. Then prompt, generate and analyse every result. + ## 1 · The law A great ad does ONE job: stop the scroll and deliver ONE message. Everything else serves that. - One product. One idea. One strong visual. @@ -112,20 +117,22 @@ Never prompt first. Run this order: > Full per-industry playbooks (15 niches, What works / Avoid / Headline / CTA): `references/niche-playbooks.md`. Depth for food/hotel/services: `references/hospitality-food-services-playbook.md`. Quick map below. - **Food/restaurant:** real dish photos are the hero (top ~62%) + a **solid** panel below with headline/subline/CTA/logo. Zero text on the food. Never invent dishes the venue doesn't serve. Warm, appetite-driven light. -- **Hotel/venue:** a distinctive or listed facade → deterministic mode (see §12) — the model invents balconies and redraws signage. Real-photo + clean typography beats an AI-rebuilt building. +- **Hotel/venue:** a distinctive or listed facade → pass the real photo as a reference image and edit around it (R41); the model invents balconies and redraws signage when it rebuilds the building from text. - **Services/trade:** real install photos as refs → generate NEW premium scenes. Problem→Effect as a **pair** of creatives. Package tiers and deadlines must be **real**. - **Retail/product:** product in real use, sharp, isolated by contrast. Let the product be 100% recognisable. Colour must match the listing (returns are killed by mismatched colour). - **Fitness:** real bodies/effort, not CGI; transformation as a **series**, not split-screen. - **Beauty/spa:** editorial soft light, believable skin, product as hero — never a redrawn label. - **Real estate:** the **real** property is the hero; never AI-invent architecture. Price + location pop as type. - **Tech/SaaS:** real UI screenshots (never invented interfaces); one feature per ad. -- **Finance/professional:** credibility over flash; real numbers sell; deterministic Mode B for text safety. +- **Finance/professional:** credibility over flash; real numbers sell; keep copy short and quoted, transcribe it after every render (R50). -## 12 · Two production modes — decide before generating -- **A · Native in-render text** — copy baked into the render. Only for short Latin-script copy (≤12 rendered words) on a model verified to spell. Quote every word; append `CRITICAL: every word spelled PERFECTLY`. -- **B · Deterministic** — generate a background only (`no text, no logos, no signage`) **with planned negative space**, then compose typography and the official logo file in code/Figma. +## 11a · The words must sell (R52) +Sell test on every headline: what is it · why me (benefit, not mood) · why believe it (number, time, material, proof) · why now · only we could say it. Formula: benefit + proof, then action. "Poranek ma warstwy." fails; "Croissant, który chrupie jeszcze ciepły." passes. Mood lines, unproven superlatives and generic questions are copy slop and a hard fail. -**Diacritics (ą ć ę ł ń ó ś ź ż), apostrophes, ampersands, prices, longer copy → Mode B, always.** +## 12 · Generated, never coded (R50) +- **The whole ad comes out of the image model:** photo or illustration, headline, copy and layout. Never compose ads in HTML or code unless the user asks. +- **Text that renders right:** quote every string exactly with diacritics (ą ć ę ł ń ó ś ź ż), write "no other text", give position and hierarchy, keep the headline ≤ 6 words. Append `every word spelled exactly as quoted`. +- **Check and fix with the model:** transcribe every word in the render and compare. On an error, regenerate or run a targeted edit on that word only. Logo and product go in as reference images, preserved exactly. ## 13 · Prompt architecture (11 parts, no placeholders left) OBJECTIVE · SUBJECT · ACTION/CONTEXT · ENVIRONMENT · COMPOSITION · CAMERA · LIGHTING · MATERIALS/TEXTURES · BRAND MOOD · OUTPUT · CONSTRAINTS. @@ -177,6 +184,9 @@ product changed · logo wrong or redrawn · lettering fake or misspelled · hand ## 19 · The gate — score before you deliver 10 criteria × 0/1/2: hierarchy · product · realism · typography · copy · colour · space · logo · thumbnail · idea. **Ship at ≥16/20 with zero hard fails.** Ask a vision model to **transcribe** every word it can read and compare it yourself — asking "is the spelling correct?" gets a yes. +## 19a · Results first (R49) +If the user has results, read them before redesigning. Stop at the first broken step: frequency ≥ 2.5–3.5 → new concept; weak 3-second hook → new first frame; good hook, weak hold → show proof earlier; low CTR → new hook or proof format; good CTR, high CPA → landing-page continuity. Change one decision per diagnosis; never claim causation without a controlled test. + ## 20 · The 2026 feed layer (R45–R48) **What the feed rewards now:** clarity over flash · feed-native over ad-shaped · real people and real products over synthetic polish · type as the hero · one confident accent against calm neutrals · distinct concepts over near-duplicates. diff --git a/design-rules.md b/design-rules.md index db2989b..84f800e 100644 --- a/design-rules.md +++ b/design-rules.md @@ -30,7 +30,7 @@ Use [art direction](references/art-direction.md) and [prompt craft](references/p | Your question | Open | |---------------|------| -| What are the rules? | [`visual-advertising-engine.md`](visual-advertising-engine.md) — R01–R48, authoritative | +| What are the rules? | [`visual-advertising-engine.md`](visual-advertising-engine.md) — R01–R52, authoritative | | I need one page to paste into a chat | [`core.md`](core.md) | | How big is the headline? What grid? What colors? | [`references/layout-system.md`](references/layout-system.md) | | What should the headline actually *say*? | [`references/headline-system.md`](references/headline-system.md) | @@ -75,16 +75,19 @@ Everything else — light, lens, depth, angle — is R09–R13 in the engine. --- -## 4 · The two production modes +## 4 · The two production modes (R50: generation is the default) + +R50 overrides this section: final ads are generated by the image model with their text; deterministic composition runs only on explicit request. + Decide **before** you generate (full spec: [`layout-system.md`](references/layout-system.md) §5): | Mode | What it is | When | |------|-----------|------| | **A · Native in-render text** | Copy baked into the AI render, in-scene, end-to-end. Keep strings SHORT (brand + headline + one location line); quote every rendered word; append the spelling directive. | The user wants a fully-generated visual, the model spells reliably, and the copy is short and Latin-script. | -| **B · Deterministic composition** | Generate a clean background only (`no text, no logo, no signage, no collage`), then compose the ad in code/Figma: official logo file, exact copy, brand panels, safe margins. | Logo fidelity or exact copy matters; long copy; Polish diacritics; legal/price lines; anything that must be pixel-correct. | +| **B · Deterministic composition** (explicit request only, R50) | Generate a clean background only (`no text, no logo, no signage, no collage`), then compose the ad in code/Figma: official logo file, exact copy, brand panels, safe margins. | Logo fidelity or exact copy matters; long copy; Polish diacritics; legal/price lines; anything that must be pixel-correct. | -**Both can coexist in one batch** (e.g. 5 native + 5 deterministic). Deliver a combined contact sheet. QA text spelling either way. +Default to A with the generation techniques in R50. Deliver a contact sheet and QA spelling by transcription. --- diff --git a/examples/00-anti-examples.md b/examples/00-anti-examples.md index 34c0f9f..0065e64 100644 --- a/examples/00-anti-examples.md +++ b/examples/00-anti-examples.md @@ -1,5 +1,7 @@ # 00 · Anti-examples — the same brief, written two ways +> **R50 note (6.0):** every final ad is generated by the image model. Where a case below gives a "typesetting handoff" or Mode B composition, fold that copy, type and placement into the generation prompt as quoted text. Use a separate typesetting step only if the user explicitly asks for one. + > **Agents learn faster from a contrast than from a ban list.** Each pair below is one brief: the prompt an agent writes by default, what the model gives back, and the prompt that actually produces an ad. --- diff --git a/examples/01-restaurant-real-food.md b/examples/01-restaurant-real-food.md index 705543d..1e16403 100644 --- a/examples/01-restaurant-real-food.md +++ b/examples/01-restaurant-real-food.md @@ -1,5 +1,7 @@ # 01 · Restaurant — real food hero, native in-render text +> **R50 note (6.0):** every final ad is generated by the image model. Where a case below gives a "typesetting handoff" or Mode B composition, fold that copy, type and placement into the generation prompt as quoted text. Use a separate typesetting step only if the user explicitly asks for one. + **Mode A** · 4:5 (1080×1350) · one creative from a batch of five --- diff --git a/examples/02-hotel-editorial.md b/examples/02-hotel-editorial.md index d8ff71e..14009a2 100644 --- a/examples/02-hotel-editorial.md +++ b/examples/02-hotel-editorial.md @@ -1,5 +1,7 @@ # 02 · Hotel — editorial background + deterministic typography +> **R50 note (6.0):** every final ad is generated by the image model. Where a case below gives a "typesetting handoff", fold that copy, type and placement into the generation prompt as quoted text. Use a separate typesetting step only if the user explicitly asks for one. + **Mode B** · 4:5 (1080×1350) · one creative from a batch of ten structurally different styles --- diff --git a/examples/03-services-problem-effect.md b/examples/03-services-problem-effect.md index 68299db..0d1b4f9 100644 --- a/examples/03-services-problem-effect.md +++ b/examples/03-services-problem-effect.md @@ -1,5 +1,7 @@ # 03 · Services — Problem → Effect, with a real deadline +> **R50 note (6.0):** every final ad is generated by the image model. Where a case below gives a "typesetting handoff", fold that copy, type and placement into the generation prompt as quoted text. Use a separate typesetting step only if the user explicitly asks for one. + **Mode B** · 4:5 (1080×1350) · two creatives shown (the pair that tests the angle) --- diff --git a/examples/04-retail-product-in-use.md b/examples/04-retail-product-in-use.md index 9c18750..c281a96 100644 --- a/examples/04-retail-product-in-use.md +++ b/examples/04-retail-product-in-use.md @@ -1,5 +1,7 @@ # 04 · Retail — reference as source of truth, a series of five +> **R50 note (6.0):** every final ad is generated by the image model. Where a case below gives a "typesetting handoff" or Mode B composition, fold that copy, type and placement into the generation prompt as quoted text. Use a separate typesetting step only if the user explicitly asks for one. + **Mode A for the hero, B for the offer creative** · 4:5 (1080×1350) · full batch of five --- diff --git a/examples/05-model-independent-directions.md b/examples/05-model-independent-directions.md index 8e22845..b109ceb 100644 --- a/examples/05-model-independent-directions.md +++ b/examples/05-model-independent-directions.md @@ -1,5 +1,7 @@ # Three advertising prompts with different design decisions +> **R50 note (6.0):** every final ad is generated by the image model. Where a case below gives a "typesetting handoff", fold that copy, type and placement into the generation prompt as quoted text. Use a separate typesetting step only if the user explicitly asks for one. + These are fictional teaching briefs with explicitly supplied facts. No images were generated or scored. The prompts demonstrate design reasoning, not measured campaign performance. ## 1 · A typographic event flyer diff --git a/examples/06-readme-showcase.md b/examples/06-readme-showcase.md index 86dbde0..94adc29 100644 --- a/examples/06-readme-showcase.md +++ b/examples/06-readme-showcase.md @@ -34,10 +34,3 @@ undefined [Bold README cover](../assets/meta-ads-designer-bold.png) -## Style Atlas 2026 board - -[Style Atlas 2026](../assets/style-atlas-2026.png) is not an AI-generated image. It is typeset deterministically in HTML and CSS from [its source](../assets/generated/style-atlas.html) and rendered with a headless browser, which is the Mode B route the skill recommends when copy, diacritics and layout must be exact. The product drawings are flat vector illustrations, not photographs. - -Every brand on it is fictional: NOC BRZMI and its reserved `.example` domain come from [example 05](05-model-independent-directions.md); NURT, PORZĄDEK and LUMA from [example 07](07-2026-style-directions.md); TARG WINYLI and ZIARNO exist only on the board. The number 47/60, the offer and the comparison rows are teaching content, not claims about any real product. The board demonstrates format and style decisions; it is not evidence of advertising performance. - -To re-render after editing the HTML, open it in a Chromium-based browser at a 1400×1420 viewport and capture at 1.5× device scale. diff --git a/examples/07-2026-style-directions.md b/examples/07-2026-style-directions.md index 6afca53..494e1e5 100644 --- a/examples/07-2026-style-directions.md +++ b/examples/07-2026-style-directions.md @@ -1,5 +1,7 @@ # 2026 style directions: format plus visual language +> **R50 note (6.0):** every final ad is generated by the image model. Where a case below gives a "typesetting handoff", fold that copy, type and placement into the generation prompt as quoted text. Use a separate typesetting step only if the user explicitly asks for one. + These are fictional teaching briefs. Every fact below is stated as supplied by the fictional client, so the prompts show how to use proof, not how to invent it. No images were generated or scored; nothing here claims measured performance. Each case names its **format** from [static-ad-formats.md](../references/static-ad-formats.md) and its **visual language** from [style-atlas-2026.md](../references/style-atlas-2026.md), then compiles both into one prompt with [prompt-craft.md](../references/prompt-craft.md). diff --git a/examples/08-generated-showcase.md b/examples/08-generated-showcase.md new file mode 100644 index 0000000..6530efd --- /dev/null +++ b/examples/08-generated-showcase.md @@ -0,0 +1,60 @@ +# Generated showcase: research → questions → prompt → image → analysis + +This case produces the README showcase with an AI image model, following R50 and R51. All brands (PORA, NURT, NOC BRZMI) are fictional, and nothing here claims measured performance. + +## 1 · Research note (abbreviated) + +- Cafés in Kraków on Meta Ad Library mostly run plated dishes on dark wood → **gap:** hands and preparation in daylight. +- Bottle brands run clean packshots on white → **gap:** a loud performance banner with one verified offer. +- Event flyers in the city rely on DJ photos → **gap:** type as the hero. + +## 2 · Questions asked (with the defaults accepted) + +1. Offer and proof? → only the bottle has a verified first-order offer (−20%). +2. Audience? → cold, local, Instagram feed. +3. Style? → A) documentary, B) performance sticker, C) typographic poster: one per concept. +4. Placements? → 4:5, one image per concept. +5. Language? → Polish, with diacritics rendered in the image. + +## 3 · Prompts + +The exact prompts are in [prompts/readme-showcase.txt](prompts/readme-showcase.txt), one per concept, with every string quoted. Generate them with: + +```bash +export FAL_KEY=... +python scripts/generate_fal.py examples/prompts/readme-showcase.txt --model --aspect 4:5 --out assets/showcase +``` + +The script writes the images and a `.log.json` with model, prompt, seed and request id. + +## 4 · Analysis after generation + +For each image: transcribe every word and compare it with the quoted copy (watch `ś`, `−`, `ł`); check that there is one focal point at thumbnail size; check hands, condensation and grain for artifacts; then ship it or change one decision and regenerate ([discovery-and-research.md](../references/discovery-and-research.md) §4). + +## 5 · Round 1: what came back + +Generated from [prompts/readme-showcase.txt](prompts/readme-showcase.txt) and the hero prompt. No retouching, no code overlays. + +| Hero | PORA | NURT | NOC BRZMI | +|---|---|---|---| +| ![hero](../assets/showcase/hero.jpg) | ![PORA](../assets/showcase/ad-pora.jpg) | ![NURT](../assets/showcase/ad-nurt.jpg) | ![NOC BRZMI](../assets/showcase/ad-noc-brzmi.jpg) | + +**Analysis (§4 of discovery-and-research):** + +| Ad | Text transcribed | Visual | Verdict | +|---|---|---|---| +| PORA | "Poranek ma warstwy." · "Wpadnij na śniadanie" · "PORA": all correct, including ś | Strong: real hands, steam, flaky layers, one focal point. Minor: gibberish on the blurred chalkboard in the background | Image ships; **headline fails R52**: a mood line, it doesn't say what is sold or why | +| NURT | "ZIMNA DO WIECZORA." · "24 h zimna" · "750 ml" · "stal 18/8" · "−20% na start" · "NURT": all correct | Clear product + callouts + one sticker. Defect: the handle overlaps "WIECZORA" | Fix the collision; **headline is a claim without a scene**, so make the 24 h tangible | +| NOC BRZMI | "NOC" · "BRZMI" · "18.10.2026 · 20:00" · "Studio 8": correct | Great weight contrast; the wave nearly touches the letters | **No reason to buy a ticket:** the event name alone doesn't sell | + +## 6 · Round 2: prompts that sell (R52) + +One decision changes per ad: the copy. Layout, style and light stay. Ready in [prompts/readme-showcase-v2.txt](prompts/readme-showcase-v2.txt). + +| Ad | Round 1 | Round 2 | +|---|---|---| +| PORA | Poranek ma warstwy. | **Croissant, który chrupie jeszcze ciepły.** · Z pieca co godzinę, od 7:00 · Wpadnij na śniadanie | +| NURT | ZIMNA DO WIECZORA. | **NALANA O 8:00. WCIĄŻ LODOWATA O 20:00.** · callouts kept · −20% na pierwszą | +| NOC BRZMI | NOC BRZMI | NOC BRZMI + **6 godzin live. 3 sceny. Jedna noc.** · date · Bilety od 49 zł | + +(All facts are part of the fictional brief.) diff --git a/examples/README.md b/examples/README.md index 1bfc5ab..0439451 100644 --- a/examples/README.md +++ b/examples/README.md @@ -18,6 +18,8 @@ For generated visual demonstrations, see the [README showcase](06-readme-showcas Additional prompt-only teaching cases: [model-independent directions](05-model-independent-directions.md) covers a typographic flyer, food ad and service ad. These are fictional briefs without rendered results or invented QA scores. +[Generated showcase](08-generated-showcase.md) walks the full research → questions → prompt → fal.ai generation → analysis loop for the README images. + [2026 style directions](07-2026-style-directions.md) pairs a static format with a visual language from the style atlas: performance sticker callouts, direct-flash editorial, a notes-app confession, a colour-block stat drop and a seasonal offer, plus one Andromeda-ready campaign set. Also fictional, prompt-only and unscored. ## How each case is structured diff --git a/examples/prompts/readme-showcase-v2.txt b/examples/prompts/readme-showcase-v2.txt new file mode 100644 index 0000000..d920b9a --- /dev/null +++ b/examples/prompts/readme-showcase-v2.txt @@ -0,0 +1,5 @@ +Vertical 4:5 Instagram feed advertisement, fully designed, for a Kraków bakery called "PORA". Candid documentary food photograph in soft morning window light from the left: a baker's floured hands tearing open a warm croissant on a worn wooden counter, flaky layers and a thin wisp of steam, background softly out of focus with plain bakery shelves and no signs or chalkboards. Natural skin texture, real crumbs, no glossy retouching. The upper third is a calm warm-white wall. Upper left, headline in a refined high-contrast serif, dark espresso, on two lines: "Croissant, który chrupie" / "jeszcze ciepły.". Below it, smaller, clean sans serif: "Z pieca co godzinę, od 7:00". Under that, a small dark rounded pill with white text: "Wpadnij na śniadanie". Small wordmark "PORA" in spaced capitals bottom left. Every word spelled exactly as quoted, including Polish diacritics. No other text anywhere, including the background. No logos, prices or icons. +--- +Vertical 4:5 performance-style Instagram advertisement for a steel water bottle brand "NURT". Flat saturated tangerine background. Upper 40%: headline in heavy condensed grotesk all caps on two lines, "NALANA O 8:00." in white and "WCIĄŻ LODOWATA O 20:00." in near-black, fully clear of the bottle with generous space below it. One sage-green matte steel bottle with a brushed steel cap and handle stands large in the lower right, starting well below the headline, small cold condensation droplets on its upper half, realistic soft contact shadow, hard studio light from the upper left. Left of the bottle, three short white labels with thin hand-drawn white arrows pointing at it: "24 h zimna", "750 ml", "stal 18/8". One round yellow sticker, slightly rotated, overlapping the bottle's shoulder: "−20% na pierwszą". Small "NURT" wordmark top right. Every word spelled exactly as quoted, including Polish diacritics (Ą in WCIĄŻ, Ż). No other text, no extra props. +--- +Vertical 4:5 bold typographic event poster for a night of live electronic music called "NOC BRZMI". Flat saturated cobalt-blue background with subtle risograph grain. Warm-white stacked title fills the upper 60% within generous margins: "NOC" in an extremely heavy condensed grotesk and "BRZMI" in a very thin weight of the same condensed family. Below the title, clearly separated, one line in a bold clean sans, acid yellow: "6 godzin live. 3 sceny. Jedna noc.". Then one broad acid-yellow sound-wave stroke across the width, not touching any letters. Bottom left, warm white, medium sans: "18.10.2026 · 20:00 · Studio 8". Bottom right, a small warm-white outlined pill: "Bilety od 49 zł". No photographs, no logos, no icons, no other text. Every word spelled exactly as quoted, including Polish diacritics. diff --git a/examples/prompts/readme-showcase.txt b/examples/prompts/readme-showcase.txt new file mode 100644 index 0000000..9ca3b07 --- /dev/null +++ b/examples/prompts/readme-showcase.txt @@ -0,0 +1,5 @@ +Vertical 4:5 Instagram feed advertisement, fully designed, for a fictional Kraków bakery called "PORA". Candid documentary food photograph in soft morning window light from the left: a baker's floured hands tearing open a warm croissant on a worn wooden counter, flaky layers and a thin wisp of steam visible, background softly out of focus with a glimpse of the bakery shelf. Natural skin texture, real crumbs, no retouched gloss. Upper third is calm warm-white wall space. In that upper-left area, the headline "Poranek ma warstwy." in a refined high-contrast serif, dark espresso colour, two lines: "Poranek ma" / "warstwy.". Below it, smaller, in a clean sans serif: "Wpadnij na śniadanie". Small wordmark "PORA" in spaced capitals at bottom left. Every word spelled exactly as quoted, including Polish diacritics. No other text, no logos, no badges, no prices, no icons. +--- +Vertical 4:5 performance-style Instagram advertisement for a fictional steel water bottle brand "NURT". Flat saturated tangerine background. One sage-green matte steel bottle with a brushed steel cap stands large in the lower right, crisp clean edges, small cold condensation droplets on its upper half, realistic soft contact shadow, hard studio light from the upper left giving one clean highlight. Upper left: headline in heavy condensed grotesk all caps, two lines, "ZIMNA" in white and "DO WIECZORA." in near-black. Left of the bottle, three short white labels each with a thin hand-drawn white arrow pointing at the bottle: "24 h zimna", "750 ml", "stal 18/8". One circular yellow sticker rotated slightly, overlapping the bottle's shoulder, reading "−20% na start". Small "NURT" wordmark top right. Every word spelled exactly as quoted, including Polish diacritics. No other text, no extra props, no ice, no splashes. +--- +Vertical 4:5 bold typographic event poster for a fictional night of live electronic music called "NOC BRZMI". Flat saturated cobalt-blue background with subtle risograph grain. The words "NOC" in an extremely heavy condensed grotesk and "BRZMI" in a very thin weight of the same condensed family, stacked, warm-white, filling the upper two thirds edge to edge within generous margins. One broad acid-yellow sound-wave stroke enters from the right edge below the title without touching the letters. Bottom left, clean medium sans serif, warm white: "18.10.2026 · 20:00" then "Studio 8". No photographs, no other text, no logos, no icons. Every word spelled exactly as quoted. diff --git a/references/anti-slop-registry.md b/references/anti-slop-registry.md index bdf2660..1a086cd 100644 --- a/references/anti-slop-registry.md +++ b/references/anti-slop-registry.md @@ -64,7 +64,7 @@ Audiences now report that they spot AI-generated ads on sight and trust them les | two or three style dialects in one frame | one visual language per creative (R45) | | a Behance-style board of tilted ad cards shipped as one ad | extract one card's language and build one ad (R06) | | a sticker, an arrow and an emoji on every element | one sticker for the one key fact | -| an invented interface, listing or app screen | a real screenshot composited in a design tool | +| an invented interface, listing or app screen | the real screenshot passed as a reference image and preserved exactly | | a play button, close icon or notification badge on a still | nothing that pretends to be tappable (R48) | | an outpainted edge that invents product or architecture | supply native ratios; keep extendable edges clean ([`platform-compliance.md`](platform-compliance.md) §6) | diff --git a/references/creative-diagnostics.md b/references/creative-diagnostics.md new file mode 100644 index 0000000..90fe6d9 --- /dev/null +++ b/references/creative-diagnostics.md @@ -0,0 +1,59 @@ +# Creative diagnostics: from numbers to the next brief + +> The operating tool behind **R49**. When the user supplies results, such as an Ads Manager export, a screenshot of metrics or a verbal report, read them as evidence about the *creative* and turn every problem into one concrete change for the next brief. Metrics diagnose; they never design. + +Skills for Meta ads are most useful as repeatable jobs with a fixed input and output: diagnose a CPA spike, detect creative fatigue, analyse competitor creative, write the client summary. This file is the designer's version of those jobs. + +--- + +## 1 · Input contract + +- **Best:** a CSV export from Ads Manager at ad level, with `Ad name`, `Impressions`, `Reach` or `Frequency`, `Amount spent`, `Link clicks` or `CTR`, `Results` or `Cost per result`, and for video `3-second video plays` and `ThruPlays`. +- **Acceptable:** a screenshot or pasted table. Transcribe the numbers first and say which are missing. +- **Not evidence:** "it isn't working" without numbers. Ask for the export, or proceed with a creative review and say that performance was not assessed. + +Run the helper when a CSV is available: + +```bash +python scripts/creative_diagnostics.py export.csv # readable report +python scripts/creative_diagnostics.py export.csv --json # for further processing +``` + +It compares each ad with the account's own median, skips ads under 1,000 impressions and prints a next-brief action for each flag. It uses only the Python standard library. + +## 2 · Symptom → creative cause → change + +Read the funnel in order and stop at the first break: the earliest broken step explains the later ones. + +| Symptom | Likely creative cause | Change in the next brief | +|---|---|---| +| Frequency ≥ 2.5 (cold) and CTR falling | Fatigue: the audience has seen it | New concept: persona, hook, format or style (R47). A recolour will not help | +| Low 3-second view rate / thumb-stop | The first frame does not stop the scroll | Bigger promise, one focal point, stronger contrast, type as hero (R36, R45) | +| Good hook, weak hold (ThruPlay ÷ 3 s) | The opening promises more than the middle delivers | Show product or proof earlier; cut the setup (R39) | +| Low CTR, normal hook | The message or the offer is not landing | New hook mechanism or a proof format: stat drop, review stack (R46) | +| High CPM, normal targeting | Low relevance, or a near-duplicate of other ads | Make it visibly distinct from the rest of the set (R47) | +| Good CTR, high CPA | Ad and landing page promise different things | Continuity note: the page must open with the ad's promise (R37 §4) | +| Low CTR and high CPA | The creative attracts the wrong click or none | Re-decide the audience moment and the takeaway before the visuals (R43) | +| Clear winner | The angle works for this audience | Iterate for new personas and settings; keep the angle (R47) | + +## 3 · Output contract + +Deliver four things, in this order: + +1. **Verdict per ad:** healthy, watch, replace or winner, each with the number behind it. +2. **Pattern across ads:** what the winners share (format, style, hook, persona) and what the losers share. Name the variable only when it was actually isolated. Otherwise call it a hypothesis. +3. **Next briefs:** for each ad to replace, one brief line in the working-note format, for example `Persona: first-time buyer · Hook: objection kill · Format: comparison · Style: native interface`. +4. **What is unknown:** missing columns, small samples and attribution limits. + +## 4 · Guardrails + +- Never claim a creative change *caused* a result unless a controlled test isolated it (R43). +- Under roughly 1,000 impressions or a few conversions, report a hint, not a verdict. +- Compare with the account's own median before quoting industry benchmarks; verticals differ widely. +- Do not change budgets, pause ads or publish anything because a diagnosis suggests it. Recommend it; the user acts. +- Numbers never override brand identity, facts or the proof rule. A "winning" fake-urgency ad is still a hard fail. + +## 5 · Sources + +- Metaflow, [Best 10 Claude skills for Meta ads](https://metaflow.life/blog/claude-skills-for-meta-ads): skills as repeatable jobs, with CPA diagnostics, creative fatigue detection and competitor creative analysis among the highest-leverage. +- Fatigue thresholds: [creative-performance-loop.md](creative-performance-loop.md) §5 and its sources. diff --git a/references/discovery-and-research.md b/references/discovery-and-research.md new file mode 100644 index 0000000..78a3edb --- /dev/null +++ b/references/discovery-and-research.md @@ -0,0 +1,78 @@ +# Discovery and research before generation + +> The operating tool behind **R51**. A generated ad is only as good as the prompt, and the prompt is only as good as what the agent knows. Before the first generation, the agent researches and asks a few sharp questions. Then it writes the prompt, generates with an image model and analyses the result. + +The order is fixed: **research → questions → decision note → prompt → generate → analyse → refine.** + +--- + +## 1 · Research first, so the questions are smart + +Do this before asking anything, with whatever tools the host has (web search, fetch, browser, the user's files). Spend minutes, not hours. + +| Look at | To learn | +|---|---| +| The brand's website, Instagram and Facebook page | Real products, prices, tone of voice, palette, typefaces, photography style, existing claims | +| Meta Ad Library (brand name, then 2–3 competitors, same country) | What the category already runs, which ads have run longest (the strongest signal), which formats and hooks are overused | +| Competitors' feeds and top posts | Where the visual gap is: what nobody in the niche does | +| Reviews (Google, Booking, marketplace) | The customer's own words: real benefits, objections and proof you may quote with permission | +| Seasonal and local context | Dates, weather, holidays and local events that make the ad current | +| Current style references (Behance, Dribbble, Pinterest) | A visual language to borrow in principle ([style-atlas-2026.md](style-atlas-2026.md) §6) | + +Write the findings as a short **research note**: 5–8 bullets, each ending with its implication for the ad. Example: "Every competitor shows a plated dish on dark wood → our gap: hands and preparation in daylight." + +If research tools are unavailable, say so and rely on the questions. + +## 2 · Ask a few questions, once + +Ask **3–6 questions in one message**, only what research could not answer and what would change the prompt. Offer a recommended default for each, so the user can reply "ok" or just a letter. Never interrogate: one round, then proceed with stated assumptions. + +Pick from this bank by what is actually unknown: + +**Offer and proof** +1. What exactly are we promoting, and is there a verified offer (price, discount, deadline)? *Default: no offer, a benefit-led ad.* +2. What proof can we show: a number, real reviews, the founder, a before/after? *Default: none; lead with the product.* + +**Audience and moment** +3. Who is it for, and at what moment do they see it: first contact (cold) or people who already know you (retargeting)? *Default: cold, broad local audience.* +4. What stops them from buying today: price, trust, "not now", not knowing you? *Default: not knowing you.* + +**Visual and brand** +5. Which style is closer: A) bold and loud, B) calm and premium, C) natural "shot on a phone", D) graphic/typographic? *Default: from the research, stated.* +6. Do you have a product photo, logo or venue photos to use as references? Which must be kept exactly? *Default: generate the scene; use the logo as a reference only if supplied.* +7. Brand colours or fonts that must appear, or anything that must never appear? *Default: palette taken from the website.* + +**Delivery** +8. Placements: feed 4:5, Reels/Stories 9:16, or both? How many concepts? *Default: 4:5, three distinct concepts.* +9. Language and exact headline, or should I write it? *Default: I write it in the brand's language.* +10. Which image model or tool do you use (Codex, an API model, another app)? *Default: the one available in this session.* + +Skip a question when the brief, the files or the research already answer it. A user who says "just do it" gets zero questions and a visible list of assumptions. + +## 3 · The decision note (before any prompt) + +Compress research and answers into one block the user can approve at a glance: + +``` +BRIEF : product · offer (verified?) · audience + moment · objection +INSIGHT : one line from research, e.g. the visual gap in the niche +CONCEPTS : 1) persona · hook · format · style + 2) … 3) … (distinct per R47) +REFERENCES : image A = exact product · image B = logo · style = named language +COPY : exact headline / subline / CTA per concept, in the ad's language +OUTPUT : model · ratio(s) · number of variations per concept +``` + +For a single quick ad, the note can be three lines. For a campaign, show it and wait for a yes before generating many images. + +## 4 · After generation: analyse, don't admire + +For every image, report in this order: +1. **Transcribe** every word visible in the image and compare it with the approved copy (spelling, diacritics). +2. **Fidelity:** does the product, logo or venue match the reference? +3. **Thumbnail test:** at phone size, what is seen first, second and third? +4. **Idea:** can someone say what is advertised in one second? +5. **Defects:** hands, physics, texture artifacts, invented text or UI ([qa-gate.md](qa-gate.md)). +6. **Verdict and one change:** ship, or name the single decision the next generation changes (R41, R49). + +Regenerate with a corrected prompt; do not fix a generated ad by drawing over it with code (R50). diff --git a/references/headline-system.md b/references/headline-system.md index 28ba4a1..6139f71 100644 --- a/references/headline-system.md +++ b/references/headline-system.md @@ -6,6 +6,22 @@ Character budgets here are locked to the type scale in [`layout-system.md`](layo --- + +## 0 · The sell test (R52) + +Before any archetype, a headline must sell. Rewrite until all five answers are yes: **what is it · why me · why believe it · why now · only we could say it.** + +| Mood line (fails) | Selling line (passes) | Why it works | +|---|---|---| +| Poranek ma warstwy. | Croissant, który chrupie jeszcze ciepły. | Product + sensory benefit you can verify at the counter | +| Zimna do wieczora. | Nalana o 8:00. Wciąż lodowata o 20:00. | Turns "24 h" into a scene the buyer imagines | +| NOC BRZMI (name only) | NOC BRZMI · 6 godzin live, 3 sceny, jedna noc. | Event name + what you get for the ticket | +| Najlepsza kawa w mieście | Palona 7 dni temu. Mielona przy Tobie. | Proof replaces the superlative | + +**Formula:** `[concrete benefit or result] + [proof detail]`, then `[action]`. Headline ≤ 6–8 words, support line ≤ 45 characters, CTA ≤ 3 words. + +**Copy slop — never on the image:** mood with no product · adjectives without proof (najlepszy, premium, wyjątkowy, jakość) · questions nobody asked · "odkryj", "poczuj", "przenieś się" · invented urgency · slogans a competitor could reuse. + ## 1 · The specificity test (run this first, on every headline) > **Could a direct competitor paste this headline onto their own ad without changing a single word?** @@ -116,9 +132,9 @@ Polish diacritics `ą ć ę ł ń ó ś ź ż` are the single most common in-ren | Situation | Do this | |-----------|---------| -| Polish copy, any length | **Mode B (deterministic).** Default. Render the text yourself with a font verified to carry Polish glyphs. | +| Polish copy, any length | **Generate it (R50).** Quote the exact string with every diacritic, add "no other text", keep the headline ≤ 6 words, then transcribe the render letter by letter. On an error, regenerate or edit only that word with the model. | | Polish copy, client insists on a fully generated image | Write the headline **using only diacritic-free words** (§5a), keep it ≤ 3 words, and vision-QA every variant | -| Polish copy, long or containing a proper noun with diacritics | Mode B. No exceptions. | +| Polish copy, long or containing a proper noun with diacritics | Shorten it; move the rest to Meta's text fields. Deterministic typesetting only on explicit user request. | | Latin-script copy without diacritics (EN, most brand names) | Mode A is fine | ### 5a · Diacritic-free Polish headlines that still sound native @@ -127,10 +143,10 @@ Polish has plenty of strong words with no diacritics. Build the headline from th > `PROSTO Z GRILLA` · `OTWARTE DO PIERWSZEJ` · `DWA DANIA, 49 ZL` · `REZERWUJ STOLIK` · `TYLKO W SOBOTY` · `DOWOZIMY NA MIEJSCE` · `PIERWSZY RAZ OD LAT` · `BEZ ZALICZKI` -Watch: `zł` → write `ZL` only if the brand accepts it, otherwise Mode B. Never fake a diacritic with an apostrophe. +Watch: `zł` → write `ZL` only if the brand accepts it, otherwise quote `zł` exactly and verify the render. Never fake a diacritic with an apostrophe. ### 5b · Font check -Before rendering Polish deterministically, confirm the family ships the glyphs. Verified safe: Montserrat, Inter, Lato, Source Sans 3, Oswald, Playfair Display, Archivo. Verify anything else — a missing glyph is silently substituted and the line ends up in two typefaces. +When the user explicitly asks for deterministic typesetting, confirm the family ships the glyphs. Verified safe: Montserrat, Inter, Lato, Source Sans 3, Oswald, Playfair Display, Archivo. Verify anything else — a missing glyph is silently substituted and the line ends up in two typefaces. ```python from fontTools.ttLib import TTFont @@ -155,7 +171,7 @@ print("MISSING:", missing or "none") - Ellipses trailing into nothing - ALL CAPS on anything longer than 4 words -**Punctuation rules:** a headline ends without a full stop unless it's two sentences (CONTRAST archetype). Apostrophes must be typographic `’` in Mode B; in Mode A, name them explicitly in the prompt — a missing apostrophe in a brand name is a verified failure mode. +**Punctuation rules:** a headline ends without a full stop unless it's two sentences (CONTRAST archetype). Apostrophes must be typographic `’`; name them explicitly in the prompt — a missing apostrophe in a brand name is a verified failure mode. --- @@ -195,7 +211,7 @@ archetypes concrete · place · number · contrast · command budgets headline ≤22 (1 line) / ≤40 (2 lines) · subline ≤45 CTA ≤18 · detail row ≤60 · caption ≤125 mode A cap ≤12 rendered words total on the image -polish diacritics → Mode B, always (or diacritic-free words only) +polish diacritics → quoted exactly, short, transcribed after render (R50) banned elevate · seamless · your perfect X · rhetorical questions routine one owned fact → archetype → 5 drafts → kill 3 → shortest wins ``` diff --git a/references/hospitality-food-services-playbook.md b/references/hospitality-food-services-playbook.md index 1d9eeec..6b1cb10 100644 --- a/references/hospitality-food-services-playbook.md +++ b/references/hospitality-food-services-playbook.md @@ -36,7 +36,7 @@ **Landscape photos:** don't force-crop a landscape table-spread to 4:5 (cuts ~50% width and clips plates). Use the "photo top + solid panel" layout instead of full-bleed cover-crop. -### 1c · AI stylized food (Mode B) — dark studio recipe +### 1c · AI stylized food — dark studio recipe ``` Dark studio editorial food photography. Black charcoal background. @@ -80,7 +80,7 @@ After the first pass **always** vision-QA the contact sheet for mid-word truncat ## 2 · HOTELS / VENUES — premium but authentic ### 2a · Core principle -Prefer **real-photo + deterministic typography/layout** over AI re-generation of the building/facade. Preserves authenticity and avoids AI-slop interiors or redrawn signage. +Prefer **the real photo as a reference image, with the ad generated around it and the building preserved (R41)** over AI re-generation of the facade from text. Preserves authenticity and avoids AI-slop interiors or redrawn signage. ### 2b · Design system (premium/traditional) - Default feed: **1080×1350 / 4:5**. @@ -138,7 +138,7 @@ Don't start with "make a beautiful kitchen". Start with "what should this ad say ### 4a · Two-layer workflow 1. **Generate fresh AI backgrounds first** from the reference photos (as style refs), never text-on-photo. `ONE SINGLE ... BACKGROUND ONLY — no text, no logos, no words, no signage, no collage, no grid` + leave negative space for typography. -2. **Compose the final ad deterministically** (PIL / HTML / Figma): official logo file + exact headline/subline/CTA + brand panels + safe margins + real fonts. +2. **Generate the final ad with the model (R50)**, passing the official logo and photos as references, with official logo file + exact headline/subline/CTA + brand panels + safe margins + real fonts. ### 4b · Deterministic typography checklist - Official logo only; never AI-redrawn logo. diff --git a/references/layout-system.md b/references/layout-system.md index f3b7a7c..73f01b4 100644 --- a/references/layout-system.md +++ b/references/layout-system.md @@ -72,7 +72,7 @@ Multiply every px value in this file by `canvas_short_edge / 1080`. For 9:16 (sh | 56–88px | single-word headers, big display | high crop risk — vision-QA required | | 24–28px | body / subtitle | safe with a shadow | -This table applies to **Mode A (native in-render text)**, where the model chooses the actual rasterized size and mid-word truncation is the #1 failure. In Mode B you control the raster — use §2a instead. +This table applies to **Mode A (native in-render text)**, where the model chooses the actual rasterized size and mid-word truncation is the #1 failure. In the rare explicitly requested Mode B you control the raster — use §2a instead. ### 2c · Font pairings (name real typefaces — R17) @@ -207,7 +207,7 @@ Type occupies the top 35–40%, the photo is a **placed rectangle** with margin **Both modes can ship in one batch.** Deliver a combined contact sheet. -**Mode B's non-negotiable:** the background prompt must **plan the negative space** ("clean negative space in the lower third for typography"). A background generated without that instruction produces the Canva look no matter how good the typography is. +**Mode B (explicit request only, R50) — its non-negotiable:** the background prompt must **plan the negative space** ("clean negative space in the lower third for typography"). A background generated without that instruction produces the Canva look no matter how good the typography is. --- diff --git a/references/model-routing.md b/references/model-routing.md index 86fb7f2..b38eae1 100644 --- a/references/model-routing.md +++ b/references/model-routing.md @@ -24,7 +24,7 @@ If the brief is new or uncertain, **generate small first**: one finished ad (R34 | Job | Route to | |-----|----------| | **Native in-scene text** (Mode A, R18) | The model best at reliable spelling — keep strings short, QA every variant | -| **Clean product / commercial photo** (Mode B) | A strong photorealism model; compose typography/logo deterministically after | +| **Clean product / commercial photo** | A strong photorealism model with the product and logo as references; copy quoted in the prompt (R50) | | **Recomposition / editing** | An editing-capable model working from the reference (R03) | | **Series consistency** (R20) | One model for the whole set so the product stays identical | @@ -52,13 +52,13 @@ Route per the motion track: [`video-ugc-track.md`](video-ugc-track.md) §5. - **Name the cost.** If the platform charges per generation, report the model and the number of generations in the delivery (SKILL.md step 6). - **Draft cheap, ship high.** Validate the angle at a draft quality tier, then re-render the winner at full quality. Draft tiers are for iteration; a final product shot or a transparent-background packshot needs medium/high or it ships soft and dirty (R40 mode D). - **At scale, prefer API calls to a chat thread.** Each call is an independent request with context you control, so cross-image ghosting is meaningfully lower — which matters most on exactly the sets where consistency is the deliverable (R20, R35). -- **Prefer the free/deterministic path when fidelity matters** (Mode B, R18): compose real typography and the official logo deterministically instead of paying for a model to guess at it. +- **Fidelity comes from references, not code** (R18, R50): pass the official logo and product photos as reference images with named roles, and choose a model that follows references and renders text well. --- ## 5 · Fallback when a model under-delivers -- **Spelling fails** → switch to Mode B (deterministic composition) rather than re-rolling a model that can't spell. +- **Spelling fails** → shorten the copy, run a targeted text edit, or switch to a model with stronger text rendering. Never overlay the text in code unless the user asks. - **Product drifts** → strengthen the reference role (R03) or switch to an editing model; do not accept a changed product. - **Motion is weak** → go back to a strong static hero rather than ship a weak video (R39: static-first). - **Output is artifacted** → do not re-roll blind. Diagnose the mode first (R40): high-risk texture subject, colliding styles, session bleed, or draft-tier settings. Re-rolling clears none of them. diff --git a/references/niche-playbooks.md b/references/niche-playbooks.md index 0985175..3d3cc5a 100644 --- a/references/niche-playbooks.md +++ b/references/niche-playbooks.md @@ -45,7 +45,7 @@ CONCRETE (name the dish) · SENSORY · PLACE · DEADLINE (midweek offers) - **The editorial split** (photo as a placed block on a flat brand field) is the fastest way out of generic hospitality. ### What to avoid -- ❌ AI drawing the logo onto the building — place the original file deterministically. +- ❌ AI drawing the logo onto the building — pass the original file as a reference image and require it unchanged. - ❌ Re-generating a listed or distinctive facade — it invents balconies and windows. - ❌ Too many small text rows in the footer — it has to read from a thumbnail. @@ -64,7 +64,7 @@ OBJECTION (the portal-is-cheaper belief) · NUMBER (the direct-booking gap) · P - **Real product/install photos as references** → generate **new** premium scenes (different light, time of day, lifestyle). Never overlay on the client's raw photo. - **Angles that sell services:** Problem → Effect (before/after when it proves value instantly) · package tiers ("Installation included", "£0 deposit") · genuine deadline offers ("Fitted before October 31") · transformation (chaos → order, dark → light). - **Benefit-led headline ≤40 characters**, body ≤125. -- Readable CTA + logo fidelity + location/phone — all deterministic, never AI-rendered. +- Readable CTA + logo fidelity + location/phone — quoted exactly in the prompt, logo as a reference, verified by transcription. ### What to avoid - ❌ Pasting frames or gradients onto the client's raw photos. @@ -191,7 +191,7 @@ NUMBER · PLACE · AUDIENCE · DEADLINE (open houses) - **The real vehicle as hero** — clean studio or dramatic location, correct proportions. - Motion/aspiration: on the road, golden hour, cinematic — but the car stays recognisable and true to colour. - Spec highlights as clean type (year, mileage, price) — not on the car. -- Dealer identity + contact deterministic, never AI-rendered onto the paint. +- Dealer identity from the supplied logo reference; contact details in Meta's text fields, not painted on the car. ### What to avoid - ❌ Wrong body proportions, extra doors, fake badging, misdrawn wheels. @@ -211,7 +211,7 @@ NUMBER · AUDIENCE · DEADLINE · CONTRAST ### What works - **The outcome, not the classroom** — a graduate working, a certificate held, a skill in use. - Clean, trustworthy, no gimmick: real people, real results, clear next step. -- Structure aids: roadmap visuals, "module 1→5" as clean graphics (deterministic). +- Structure aids: roadmap visuals, "module 1→5" as clean generated graphics with quoted labels. - Proof: placement, results, reviews — stated, never invented. ### What to avoid @@ -231,7 +231,7 @@ AUDIENCE · PROOF · NUMBER · OBJECTION ### What works - **Trust and calm** — clean, clinical-but-warm; real facilities or real products. - One clear benefit per ad (not a list of 10 claims). -- Real dosage/label details deterministic — a supplement label is never AI-rendered. +- Real dosage/label from the product photo as a reference, preserved exactly — never invented. - Proof (clinics, certifications, results) stated responsibly. ### What to avoid @@ -253,7 +253,7 @@ OBJECTION · PROOF · AUDIENCE · NUMBER - **Credibility over flash** — clean layouts, strong typography, a calm brand field. - The human/professional + a concrete promise (tax saved, claim won, coverage found). - Numbers do the selling: "£X saved", "N clients", "response in 24h" — real, verifiable. -- Deterministic composition (Mode B) — precision and legal-safety of text matter. +- Keep legal and numeric copy minimal and quoted, verify by transcription; long disclaimers go in the text fields. ### What to avoid - ❌ Generic stock "handshake + skyscraper" imagery. @@ -279,7 +279,7 @@ NUMBER · OBJECTION · PROOF · AUDIENCE ### What to avoid - ❌ Fake/fictional UI screens — inventing screens is a hard fail (user will never see that interface). - ❌ HUD/cyberpunk clichés, neon grids, or "futuristic" noise. -- ❌ Text/UI re-drawn by the model — use real screenshots (Mode B). +- ❌ Text/UI re-drawn by the model — pass real screenshots as reference images. ### Headline archetypes that work here NUMBER · AUDIENCE · CONTRAST · OBJECTION diff --git a/references/prompt-craft.md b/references/prompt-craft.md index 5f08aae..9d73d40 100644 --- a/references/prompt-craft.md +++ b/references/prompt-craft.md @@ -24,9 +24,11 @@ If the request is prompt-only, return the ready-to-paste prompt with a short pro **Finished ad with generated text:** quote every intended string, declare no other copy, specify hierarchy and line breaks. Use for short copy when the available renderer can handle it. Inspect the actual lettering afterwards. -**Image plus separate typesetting:** request a text-free image with a planned copy field. Provide an adjacent typesetting specification containing exact copy, preferred fonts, alignment, palette and official logo placement. The image prompt alone is not the complete ad. Use this for precision-sensitive or information-heavy work. +**This is the default (R50):** the model renders the complete ad, text included. Describe type by class, weight, width, case and position ("heavy condensed grotesk, all caps, upper left, two lines"). Font names state intent only. -**Graphic/type-led composition:** the hero may be the headline itself. Specify the overall grid and supporting device. If exact type is required, compose the final artwork with a design tool instead of pretending a text-free background already contains the design. +**Graphic/type-led composition:** the headline itself may be the hero. Specify the grid, the words, the weight contrast and the one supporting device, and let the model render the whole poster. + +**Text-free image plus separate typesetting** exists only when the user explicitly asks for it. Otherwise fix text errors with a regeneration or a targeted model edit. ## 3 · Prompt preflight @@ -49,7 +51,7 @@ If facts are missing, omit them or request them; do not put plausible invented f | Attractive but generic | Replace the generic setting with a specific use moment or brand device | | Unclear offer | Resolve the takeaway and headline before changing the lighting | | Busy hierarchy | Remove a secondary idea; enlarge one focal element; consolidate details | -| Copy unreadable | Shorten copy or reserve a larger calm field; typeset separately if needed | +| Copy unreadable | Shorten copy or reserve a larger calm field; regenerate with the shorter copy | | Looks pasted together | Align image direction, type edges, colour roles and spacing | | Product drift | Reassert source identity and narrow the edit; consider source compositing | | Wrong style | Describe visible formal properties, not more mood adjectives | diff --git a/references/prompt-library.md b/references/prompt-library.md index e9fc9aa..fc001d1 100644 --- a/references/prompt-library.md +++ b/references/prompt-library.md @@ -81,7 +81,7 @@ Finished version: [`../examples/01-restaurant-real-food.md`](../examples/01-rest --- -## 🏨 Hotel / venue — editorial background (Mode B) +## 🏨 Hotel / venue — editorial scene ``` ONE SINGLE PHOTOGRAPHIC BACKGROUND ONLY — no text, no words, no signage, @@ -130,7 +130,7 @@ Finished version: [`../examples/03-services-problem-effect.md`](../examples/03-s --- -## 🎨 Mode B — clean photo + deterministic typography +## 🎨 Mode B — clean photo + deterministic typography (explicit user request only, R50) 1. Generate a **clean photograph** with zero text in the prompt, and an explicitly **planned empty area** for the copy. A background generated without that instruction produces the pasted-on look no matter how good the typography is. 2. Compose typography + the official logo file deterministically (design tool, PIL, HTML). @@ -215,7 +215,7 @@ Three rules that go with it: 2. **Keep it short** — brand + headline + one detail line. ≤12 rendered words total. 3. Add `CRITICAL: every word spelled perfectly` and name the proper nouns. 4. **Never render punctuation-heavy brand names** (apostrophes, ampersands, accents, inch marks). Leave the space, place the file. -5. **Diacritics → Mode B.** Polish `ą ć ę ł ń ó ś ź ż` is the highest-failure case (headline-system §5). +5. **Diacritics → quote exactly and verify (R50).** Polish `ą ć ę ł ń ó ś ź ż` is the highest-failure case (headline-system §5). 6. **Vision-QA every variant** — and ask the model to *transcribe* what it reads, not to confirm that the spelling is right. --- @@ -230,4 +230,4 @@ Model capability changes faster than this repo. Verify on your host rather than | Clean lifestyle / product photography | any strong photographic model | | Real dishes / product / building preserved | a reference-capable model, fed the real refs with labelled roles | | Deterministic typography + logo | any clean-photo model + a composition step (Mode B) | -| Diacritics of any kind in-image | none — use Mode B | +| Diacritics of any kind in-image | the strongest text-rendering model available; quote exactly, transcribe, targeted edit on errors | diff --git a/references/qa-gate.md b/references/qa-gate.md index a3fcc13..b9c18e7 100644 --- a/references/qa-gate.md +++ b/references/qa-gate.md @@ -137,7 +137,7 @@ Return ONLY this JSON, no prose: - `style_coherence: false` → two colliding style descriptors. Pick one and regenerate; re-rolling will not resolve it ([`artifact-control.md`](artifact-control.md) §4). - `visual_language: "mixed"` → **R45**. Two dialects compete (for example direct flash plus riso grain plus stickers). Keep the language that serves the message, remove the other's devices, and regenerate ([`style-atlas-2026.md`](style-atlas-2026.md) §5). - `fake_functional_ui` non-empty → **`R48-fake-ui`**. Remove the control; a still image must not pretend to be tappable ([`platform-compliance.md`](platform-compliance.md) §6). -- `spelling_errors` with `severity: hard` → regenerate (Mode A) or re-render the text layer (Mode B). +- `spelling_errors` with `severity: hard` → regenerate, or run a targeted model edit on the misspelled word (R50). - `total < 16` → fix the lowest-scoring criteria and re-run. - `reads_as_ai_generated: true` with `total ≥ 16` → trust the flag, not the score. Redesign. @@ -162,7 +162,7 @@ Ten criteria, 0/1/2 each. This is what `score` in the vision JSON refers to, and **Thresholds** - **≥ 18** — ship. -- **16–17** — ship if the deductions are on criteria 7–9 (fixable in a deterministic pass); otherwise fix. +- **16–17** — ship if the deductions are on criteria 7–9 (fixable in one more generation or targeted edit); otherwise fix. - **12–15** — fix and re-score. Usually typography or copy. - **< 12** — regenerate from a new prompt. Don't patch. - **Any hard fail at any score** — regenerate. diff --git a/references/static-ad-formats.md b/references/static-ad-formats.md index 49b8202..3e4f972 100644 --- a/references/static-ad-formats.md +++ b/references/static-ad-formats.md @@ -109,7 +109,7 @@ Each entry: skeleton → copy budget → where it shines → integrity rule. ### 3.11 · Native interface (notes, chat, post) -- **Skeleton.** The anatomy of a familiar screen (notes list, chat thread, post, sticky note) filling the frame, one highlighted line, product or brand cue small in a corner. Build deterministically (Mode B). +- **Skeleton.** The anatomy of a familiar screen (notes list, chat thread, post, sticky note) filling the frame, one highlighted line, product or brand cue small in a corner. Generate it with every line quoted exactly (R50). - **Copy.** As long as it takes to read in 3 seconds: a title plus 3–5 short lines. - **Shines.** Confessions ("things I wish I knew…"), objection handling, founder notes, services, apps. - **Integrity.** Brand's own voice, clearly the brand's own content. No fake tappable UI (play buttons, close X, notification badges), no impersonation of a real person, platform account or news outlet. diff --git a/references/style-atlas-2026.md b/references/style-atlas-2026.md index eea99ca..48a9bde 100644 --- a/references/style-atlas-2026.md +++ b/references/style-atlas-2026.md @@ -101,7 +101,7 @@ Each entry gives the DNA, where it fits, a model-independent prompt fragment to - **Signature device.** Content that reads as a real thought or conversation in the brand's own voice. - **Use for.** Objection handling, lists ("3 things we never do"), confessions, founder notes, apps, services. - **Avoid for.** Products that need to be seen to be wanted. -- **Prompt fragment.** Build this deterministically (Mode B). Specify: "notes-style card, off-white background, title 'Why our espresso tastes different' in semibold, a three-item checklist in regular weight, the last item highlighted with a yellow marker stroke." +- **Prompt fragment.** Generate it with the copy quoted exactly. Specify: "notes-style card, off-white background, title 'Why our espresso tastes different' in semibold, a three-item checklist in regular weight, the last item highlighted with a yellow marker stroke." - **Integrity.** Never fake functional UI such as a play button, a close X, notification badges or checkboxes that look tappable. Never impersonate a real person, a real platform account, a news outlet or another brand's interface. Quotes and reviews must be real (see static-ad-formats.md §3). ### 8 · Performance sticker banner @@ -148,7 +148,7 @@ The dominant style on Eastern European performance boards: dense, energetic and - **Signature device.** A genuine screen, legible at feed size. - **Use for.** Real estate, apps, SaaS, booking, marketplaces, courses. - **Avoid for.** Physical products that should be shown directly. -- **Prompt fragment.** Generate the hand and device with a blank, evenly lit screen area, then composite the real screenshot in a design tool: "A hand holds a modern smartphone at a slight angle in front of a softly defocused apartment balcony at golden hour. The screen is a clean flat bright area facing the camera squarely for later compositing, with no reflections or UI drawn on it." +- **Prompt fragment.** Generate the hand and device with a blank, evenly lit screen area, or pass the real screenshot as a reference image to be shown on the screen: "A hand holds a modern smartphone at a slight angle in front of a softly defocused apartment balcony at golden hour. The screen is a clean flat bright area facing the camera squarely for later compositing, with no reflections or UI drawn on it." - **Fails when.** The model invents an interface, prices or listing details. Screens must be real and composited (R18). ## 4 · Style is the skin, format is the skeleton diff --git a/scripts/creative_diagnostics.py b/scripts/creative_diagnostics.py new file mode 100644 index 0000000..7914002 --- /dev/null +++ b/scripts/creative_diagnostics.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python3 +"""Creative diagnostics from a Meta Ads Manager CSV export. + +Turns per-ad numbers into creative decisions: which ads are fatigued, which +lose at the hook, which lose after the click, and what the next brief should +change (R37, R47, references/creative-diagnostics.md). It reads numbers; it +never judges an image. Thresholds are third-party 2026 benchmarks, compared +against the account's own median, not universal truths. + +Usage: + python scripts/creative_diagnostics.py export.csv + python scripts/creative_diagnostics.py export.csv --json + python scripts/creative_diagnostics.py export.csv --min-impressions 3000 + +Column names are matched loosely (English Ads Manager export headers). Only +`Ad name` and `Impressions` are required; every other check runs when its +column exists and reports "n/a" otherwise. Standard library only. +""" + +from __future__ import annotations + +import argparse +import csv +import json +import statistics +import sys +from pathlib import Path + +ALIASES = { + "ad": ["ad name", "ad"], + "impressions": ["impressions"], + "reach": ["reach"], + "frequency": ["frequency"], + "spend": ["amount spent", "amount spent (usd)", "amount spent (pln)", "amount spent (eur)", "spend"], + "clicks": ["link clicks", "clicks (all)", "clicks"], + "ctr": ["ctr (link click-through rate)", "ctr (all)", "ctr"], + "cpm": ["cpm (cost per 1,000 impressions)", "cpm"], + "results": ["results", "purchases", "leads", "conversions"], + "cpa": ["cost per result", "cost per purchase", "cost per lead", "cpa"], + "views3s": ["3-second video plays", "video plays at 3 seconds"], + "thruplays": ["thruplays"], +} + +FREQ_WATCH, FREQ_REPLACE = 2.5, 3.5 # cold prospecting (creative-performance-loop §5) +CTR_LOW = 0.70 # below 70% of the account median +CPA_HIGH = 1.40 # above 140% of the account median +CPM_HIGH = 1.30 # above 130% of the account median +HOOK_LOW = 0.70 # hook rate below 70% of the median +HOLD_LOW = 0.70 # thruplay/3s hold below 70% of the median + + +def _num(raw: str | None) -> float | None: + if raw is None: + return None + s = str(raw).strip().replace("%", "").replace(" ", "").replace(" ", "") + if not s or s in {"-", "—"}: + return None + if s.count(",") == 1 and "." not in s: + s = s.replace(",", ".") + s = s.replace(",", "") + try: + return float(s) + except ValueError: + return None + + +def load(path: Path) -> list[dict]: + text = path.read_text(encoding="utf-8-sig") + dialect = csv.Sniffer().sniff(text[:4096], delimiters=",;\t") + rows = list(csv.DictReader(text.splitlines(), dialect=dialect)) + if not rows: + return [] + headers = {h.strip().lower(): h for h in rows[0].keys() if h} + cols = {} + for key, names in ALIASES.items(): + for n in names: + if n in headers: + cols[key] = headers[n] + break + if "ad" not in cols or "impressions" not in cols: + raise SystemExit("creative_diagnostics: need at least 'Ad name' and 'Impressions' columns") + out = [] + for r in rows: + ad = {"ad": (r.get(cols["ad"]) or "").strip()} + for key, col in cols.items(): + if key != "ad": + ad[key] = _num(r.get(col)) + if ad["ad"]: + out.append(ad) + return out + + +def derive(ad: dict) -> dict: + imp = ad.get("impressions") or 0 + if ad.get("ctr") is None and ad.get("clicks") is not None and imp: + ad["ctr"] = ad["clicks"] / imp * 100 + if ad.get("cpm") is None and ad.get("spend") is not None and imp: + ad["cpm"] = ad["spend"] / imp * 1000 + if ad.get("cpa") is None and ad.get("spend") is not None and ad.get("results"): + ad["cpa"] = ad["spend"] / ad["results"] + if ad.get("frequency") is None and ad.get("reach"): + ad["frequency"] = imp / ad["reach"] + ad["hook"] = ad["views3s"] / imp * 100 if ad.get("views3s") is not None and imp else None + ad["hold"] = (ad["thruplays"] / ad["views3s"] * 100 + if ad.get("thruplays") is not None and ad.get("views3s") else None) + return ad + + +def median(ads: list[dict], key: str) -> float | None: + vals = [a[key] for a in ads if a.get(key) is not None and a[key] > 0] + return statistics.median(vals) if vals else None + + +def diagnose(ad: dict, med: dict) -> tuple[list[str], list[str]]: + flags, actions = [], [] + f = ad.get("frequency") + if f is not None and f >= FREQ_REPLACE: + flags.append(f"fatigued (frequency {f:.1f})") + actions.append("replace with a new concept: different persona, hook or format, not a recolour (R47)") + elif f is not None and f >= FREQ_WATCH: + flags.append(f"fatigue watch (frequency {f:.1f})") + actions.append("brief the replacement now; keep 3-5 approved variants ready") + + def low(key, ratio): + return ad.get(key) is not None and med.get(key) and ad[key] < med[key] * ratio + + def high(key, ratio): + return ad.get(key) is not None and med.get(key) and ad[key] > med[key] * ratio + + if low("hook", HOOK_LOW): + flags.append(f"weak hook ({ad['hook']:.1f}% vs median {med['hook']:.1f}%)") + actions.append("rebuild the first frame: bigger promise, stronger contrast, one focal point (R36)") + if low("hold", HOLD_LOW): + flags.append(f"weak hold ({ad['hold']:.1f}% vs median {med['hold']:.1f}%)") + actions.append("hook works, story doesn't: show the product/proof earlier, cut the middle") + if low("ctr", CTR_LOW): + flags.append(f"low CTR ({ad['ctr']:.2f}% vs median {med['ctr']:.2f}%)") + actions.append("message isn't landing: test a new hook or a proof format (stat drop, reviews)") + if high("cpm", CPM_HIGH): + flags.append(f"high CPM ({ad['cpm']:.2f} vs median {med['cpm']:.2f})") + actions.append("low relevance or a near-duplicate of other ads: make it visibly distinct") + ctr_ok = ad.get("ctr") is not None and med.get("ctr") and ad["ctr"] >= med["ctr"] + if high("cpa", CPA_HIGH): + flags.append(f"high CPA ({ad['cpa']:.2f} vs median {med['cpa']:.2f})") + actions.append("clicks but no conversions: check ad-to-landing continuity and offer clarity (R37 §4)" + if ctr_ok else "fix the promise before the page: the creative attracts the wrong click") + if not flags: + is_winner = (ad.get("cpa") is not None and med.get("cpa") and ad["cpa"] <= med["cpa"] * 0.8) or \ + (ad.get("ctr") is not None and med.get("ctr") and ad["ctr"] >= med["ctr"] * 1.3) + if is_winner: + flags.append("winner") + actions.append("iterate for new personas and settings; keep the angle, change the context (R47)") + return flags, actions + + +def main() -> int: + ap = argparse.ArgumentParser(description="Creative diagnostics from a Meta Ads Manager CSV export.") + ap.add_argument("csv", type=Path) + ap.add_argument("--min-impressions", type=int, default=1000, + help="skip ads below this volume: small samples are noise (default 1000)") + ap.add_argument("--json", action="store_true") + args = ap.parse_args() + + ads = [derive(a) for a in load(args.csv)] + ads = [a for a in ads if (a.get("impressions") or 0) >= args.min_impressions] + if not ads: + print("no ads above the impression floor", file=sys.stderr) + return 1 + med = {k: median(ads, k) for k in ("ctr", "cpm", "cpa", "hook", "hold")} + + report = [] + for a in ads: + flags, actions = diagnose(a, med) + report.append({"ad": a["ad"], "impressions": int(a["impressions"]), + "flags": flags, "next_brief": actions}) + report.sort(key=lambda r: (r["flags"] == ["winner"], -len(r["flags"]))) + + if args.json: + print(json.dumps({"medians": med, "ads": report}, indent=2)) + return 0 + def fmt(v, d=2, unit=""): + return "n/a" if v is None else f"{v:.{d}f}{unit}" + print(f"{len(ads)} ads · medians: CTR {fmt(med['ctr'], 2, '%')} · CPM {fmt(med['cpm'])} · " + f"CPA {fmt(med['cpa'])} · hook {fmt(med['hook'], 1, '%')} · hold {fmt(med['hold'], 1, '%')}\n") + for r in report: + print(f"■ {r['ad']} ({r['impressions']:,} impr.)") + for f, act in zip(r["flags"], r["next_brief"]): + print(f" {f}\n → {act}") + if not r["flags"]: + print(" healthy · no action") + print() + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/generate_fal.py b/scripts/generate_fal.py new file mode 100644 index 0000000..6dc01e6 --- /dev/null +++ b/scripts/generate_fal.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +"""Generate ad images with a fal.ai image model (R50: ads are generated, never coded). + +Reads a prompt file (one prompt; or several separated by a line with `---`), +submits each to fal.ai's queue API, waits, and saves the images next to a JSON +log of prompt, model, request id and seed so every README image is reproducible. + +Usage: + export FAL_KEY=... # never commit the key + python scripts/generate_fal.py prompts.txt --model fal-ai/ --out assets/generated + python scripts/generate_fal.py prompts.txt --model fal-ai/ --aspect 4:5 --n 2 + python scripts/generate_fal.py prompts.txt --model fal-ai/ --image-url https://... (reference) + +Model ids and accepted parameters differ per model; check the model page on +fal.ai. Extra parameters can be passed as --param key=value (repeatable). +Standard library only. Needs network access to queue.fal.run and fal.media. +""" + +from __future__ import annotations + +import argparse +import json +import os +import sys +import time +import urllib.request +from pathlib import Path + +QUEUE = "https://queue.fal.run" +SIZES = {"4:5": "portrait_4_3", "9:16": "portrait_16_9", "1:1": "square_hd", "16:9": "landscape_16_9"} + + +def call(url: str, key: str, payload: dict | None = None) -> dict: + data = json.dumps(payload).encode() if payload is not None else None + req = urllib.request.Request(url, data=data, method="POST" if data else "GET", + headers={"Authorization": f"Key {key}", "Content-Type": "application/json"}) + with urllib.request.urlopen(req, timeout=120) as r: + return json.loads(r.read()) + + +def generate(model: str, key: str, args: dict, timeout: int = 600) -> dict: + job = call(f"{QUEUE}/{model}", key, args) + status_url, response_url = job["status_url"], job["response_url"] + start = time.time() + while time.time() - start < timeout: + st = call(status_url, key) + if st.get("status") == "COMPLETED": + res = call(response_url, key) + res["_request_id"] = job.get("request_id") + return res + if st.get("status") in {"FAILED", "ERROR"}: + raise RuntimeError(f"fal job failed: {st}") + time.sleep(3) + raise TimeoutError("fal job did not finish in time") + + +def main() -> int: + ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + ap.add_argument("prompts", type=Path) + ap.add_argument("--model", required=True, help="fal model id, e.g. fal-ai/") + ap.add_argument("--out", type=Path, default=Path("out")) + ap.add_argument("--aspect", default="4:5", choices=sorted(SIZES)) + ap.add_argument("--n", type=int, default=1, help="images per prompt") + ap.add_argument("--image-url", action="append", default=[], help="reference image URL (edit models)") + ap.add_argument("--param", action="append", default=[], help="extra model parameter key=value") + a = ap.parse_args() + + key = os.environ.get("FAL_KEY") + if not key: + print("generate_fal: set FAL_KEY in the environment", file=sys.stderr) + return 2 + prompts = [p.strip() for p in a.prompts.read_text(encoding="utf-8").split("\n---\n") if p.strip()] + a.out.mkdir(parents=True, exist_ok=True) + log = [] + for i, prompt in enumerate(prompts, 1): + args = {"prompt": prompt, "num_images": a.n, "image_size": SIZES[a.aspect], "aspect_ratio": a.aspect} + if a.image_url: + args["image_urls"] = a.image_url + for kv in a.param: + k, _, v = kv.partition("=") + args[k] = json.loads(v) if v[:1] in "[{0123456789tfn" and v not in {"", "none"} else v + print(f"[{i}/{len(prompts)}] generating…", file=sys.stderr) + res = generate(a.model, key, args) + for j, img in enumerate(res.get("images", []), 1): + path = a.out / f"{a.prompts.stem}-{i:02d}-{j}.png" + urllib.request.urlretrieve(img["url"], path) + log.append({"file": path.name, "model": a.model, "prompt": prompt, + "seed": res.get("seed"), "request_id": res.get("_request_id")}) + print(path) + (a.out / f"{a.prompts.stem}.log.json").write_text(json.dumps(log, indent=2, ensure_ascii=False), encoding="utf-8") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/test_diagnostics.py b/scripts/test_diagnostics.py new file mode 100644 index 0000000..ab9e877 --- /dev/null +++ b/scripts/test_diagnostics.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +"""Self-test for scripts/creative_diagnostics.py — synthetic Ads Manager exports.""" + +from __future__ import annotations + +import subprocess +import sys +import tempfile +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent)) +import creative_diagnostics as cd + +CSV = """Ad name,Impressions,Reach,Amount spent (PLN),Link clicks,Results,3-second video plays,ThruPlays +A fatigued,40000,10000,800,400,20,, +B weak hook,30000,20000,600,300,15,3000,1500 +C winner,30000,25000,600,900,40,12000,6000 +D wrong click,30000,25000,600,600,5,, +E median,30000,25000,600,450,16,9000,4500 +F tiny,200,200,5,1,0,, +""" + + +def run() -> dict: + with tempfile.TemporaryDirectory() as raw: + p = Path(raw) / "export.csv" + p.write_text(CSV, encoding="utf-8") + ads = [cd.derive(a) for a in cd.load(p) if (a.get("impressions") or 0) >= 1000] + med = {k: cd.median(ads, k) for k in ("ctr", "cpm", "cpa", "hook", "hold")} + out = {a["ad"]: cd.diagnose(a, med)[0] for a in ads} + cli = subprocess.run([sys.executable, str(Path(__file__).parent / "creative_diagnostics.py"), str(p)], + capture_output=True, text=True) + out["_cli"] = cli.returncode + return out + + +def main() -> int: + r = run() + checks = [ + ("frequency 4.0 is flagged as fatigued", any("fatigued" in f for f in r["A fatigued"])), + ("low 3s-view rate is flagged as a weak hook", any("weak hook" in f for f in r["B weak hook"])), + ("strong CTR and CPA is labelled a winner", r["C winner"] == ["winner"]), + ("clicks without conversions flag high CPA", any("high CPA" in f for f in r["D wrong click"])), + ("the median ad is healthy", r["E median"] == []), + ("ads under the impression floor are skipped", "F tiny" not in r), + ("the CLI exits 0", r["_cli"] == 0), + ] + fails = 0 + for name, ok in checks: + print(f" {'ok ' if ok else 'FAIL'} {name}") + fails += not ok + print(f"\n{len(checks) - fails}/{len(checks)} cases passed") + return 1 if fails else 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/visual-advertising-engine.md b/visual-advertising-engine.md index 8088e40..a5e397f 100644 --- a/visual-advertising-engine.md +++ b/visual-advertising-engine.md @@ -8,7 +8,7 @@ | | | |---|---| -| **Rules** | R01–R48 below | +| **Rules** | R01–R52 below | | **Layout / type / color numbers** | [`references/layout-system.md`](references/layout-system.md) | | **Headline & copy generation** | [`references/headline-system.md`](references/headline-system.md) | | **Creative variation matrix (test-ready sets)** | [`references/variation-matrix.md`](references/variation-matrix.md) | @@ -20,6 +20,7 @@ | **Competitor ad teardown** | [`references/competitor-ad-teardown.md`](references/competitor-ad-teardown.md) | | **2026 visual languages (style atlas)** | [`references/style-atlas-2026.md`](references/style-atlas-2026.md) | | **Static ad formats (persuasion skeletons)** | [`references/static-ad-formats.md`](references/static-ad-formats.md) | +| **Creative diagnostics (results → next brief)** | [`references/creative-diagnostics.md`](references/creative-diagnostics.md) | | **QA gate (scored, machine-checkable)** | [`references/qa-gate.md`](references/qa-gate.md) | | **Worked end-to-end examples** | [`examples/`](examples/) | @@ -27,7 +28,7 @@ ## Scope and precedence -This standard teaches model-independent advertising judgment and prompt writing. R45–R48 add the 2026 layer: one committed visual language, a format chosen by proof and funnel, concept diversity and the current placement system. R42–R44 qualify older recipes: choose the medium for the message, and distinguish a style preference from a fidelity requirement. Photography-specific rules apply only to photography. Numerical layouts are starting points. User brief and supplied identity outrank category defaults. Tool setup is optional production guidance, never a prerequisite for writing a prompt. +**R50 and R51 take precedence over everything below:** final ads are generated by an AI image model after research and a short round of questions, never coded. This standard teaches model-independent advertising judgment and prompt writing. R45–R48 add the 2026 layer: one committed visual language, a format chosen by proof and funnel, concept diversity and the current placement system. R42–R44 qualify older recipes: choose the medium for the message, and distinguish a style preference from a fidelity requirement. Photography-specific rules apply only to photography. Numerical layouts are starting points. User brief and supplied identity outrank category defaults. Tool setup is optional production guidance, never a prerequisite for writing a prompt. ## R01 · MAIN GOAL @@ -254,7 +255,7 @@ Type scale, pairings, tracking: [`references/layout-system.md`](references/layou Two production modes — decide **before** generating (see [`references/layout-system.md`](references/layout-system.md) §5): - **Mode A · Native in-render text** — the copy is baked into the AI render. Only when the model spells reliably. Quote every rendered word, keep strings short, append the spelling directive, vision-QA every variant. -- **Mode B · Deterministic composition** — generate a clean background (`no text, no logos, no signage`), then compose typography and the official logo file with code/design tool. +- **Mode B · Deterministic composition** (only on explicit user request, R50) — generate a clean background (`no text, no logos, no signage`), then compose typography and the official logo file with code/design tool. Either way: **never let the model invent** logos · prices · product names · slogans · labels · contact details. A "plausible" logo is a FAIL (R30). @@ -563,7 +564,7 @@ Specify medium, dominant element, reading path, copy field, quiet space, type ro R25 is a semantic checklist, not mandatory headings. Combine it into concise prose. Add exact copy, type roles and reading order for finished ads; replace camera/light fields with graphic form when appropriate. The five-slot skeleton is an alternative packaging of those decisions, not a second required prompt. -A prompt specifies one output, one direction, exact copy or a separate typesetting contract, composition and relevant constraints. Omit model names, unsupported parameter syntax and irrelevant rules. Check factual support, spatial feasibility, copy length and contradictions before delivery. +A prompt specifies one output, one direction, exact quoted copy, composition and relevant constraints. Omit model names, unsupported parameter syntax and irrelevant rules. Check factual support, spatial feasibility, copy length and contradictions before delivery. Prompting cannot guarantee exact fonts, pixels, spelling or preservation. For prompt-only work, deliver the complete prompt without claiming a rendered result. For an actual image, inspect small-size hierarchy, text and source fidelity before scoring it. @@ -601,6 +602,39 @@ Advantage+ creative enhancements can expand images, add overlays, rewrite text a Depth: [platform guidance](references/platform-compliance.md). +## R49 · DIAGNOSE BEFORE YOU REDESIGN + +When results exist, read them before touching the creative. Find the first broken step of the funnel: stopping power (hook), holding power, click, conversion. Change the creative decision that step points to, and only that one. Fatigue asks for a new concept, a weak hook for a new first frame, a good CTR with a bad CPA for a continuity check on the landing page. Metrics diagnose; they never excuse invented proof, and a correlation is not a controlled test. + +Depth: [creative diagnostics](references/creative-diagnostics.md). + +## R50 · GENERATED, NEVER CODED + +Every final creative is generated from scratch by an AI image model (an API model, Codex or the host's image tool), with its imagery, headline, copy and layout in the render. Do not build, template or finish ads with HTML, CSS, code or programmatic text overlays unless the user explicitly asks. This rule outranks every older instruction to use "Mode B", a "deterministic composition" or a "separate typesetting" step. Those passages now describe a fallback that runs only on explicit request. + +Make generated text reliable instead: short quoted copy with exact diacritics, "no other text", clear hierarchy and position; supplied logo and product images as references with named roles; after each render, transcribe and compare every word, then regenerate or run a targeted model edit on any error. The facts rules still hold: never let the model invent logos, prices, claims or signage (R18). + +## R51 · RESEARCH AND ASK BEFORE GENERATING + +Before the first generation, research the brand, its Meta Ad Library presence, 2–3 competitors, reviews and the seasonal context. Then ask the user 3–6 questions in a single message, each with a recommended default, about what research could not settle: offer and proof, audience and moment, main objection, style direction, references, placements, language and model. Compress everything into a decision note (brief, insight, concepts, references, exact copy, output) and write prompts from it. After every generation, analyse the result (text transcription, fidelity, thumbnail test, idea, defects) and change one decision per regeneration. A user who asks to skip questions gets stated assumptions instead. + +Depth: [discovery and research](references/discovery-and-research.md). + +## R52 · THE WORDS MUST SELL + +Every string on the image has a job. The headline sells the product: a concrete benefit or result the buyer gets, in the buyer's words, specific enough that no competitor could paste it onto their ad. The support line gives the proof or the reason to act now. The CTA names the action. A pretty, poetic or clever line that does not say what is sold and why it matters fails, however good the image is. + +Run the **sell test** on every headline before generating: +1. **What is it?** Can a stranger tell the product from the image plus headline in one second? +2. **Why me?** Does the headline state a benefit, a result or a pain removed, not an adjective or a mood? +3. **Why believe it?** Is there a concrete detail such as a number, time, place, material or real proof? +4. **Why now?** Is there a verified reason to act (offer, season, date), or at least a clear action? +5. **Could a competitor use it unchanged?** If yes, rewrite it. + +Copy slop is a hard fail: mood lines with no product ("Poranek ma warstwy."), stacked adjectives, "najlepszy/premium/wyjątkowy" without proof, generic questions, invented urgency, and the banned AI vocabulary. Facts come only from the brief (R43). + +Depth: [headline system](references/headline-system.md) §0. + ## 🏁 FINAL PRINCIPLE — DON'T DECORATE. DIRECT. Don't treat the image generator as a tool for adding more and more effects. Treat it like a **production crew**. First decide: what we show · why we show it · where the viewer looks · what emotions we want · what benefit must be understood. Only later choose: light · lens · set design · styling · color · effects.