Minimal Editorial Poster
A minimal zine poster says one thing, quietly, with almost the whole frame
left empty around it. That works the same way regardless of which of
aria-code's domains the subject comes from — FINANCIAL_SCHEME's "AAPL beat
on margins", REALTY_SCHEME's "this listing's cash flow is genuine", a
sports recap, or a subject with no domain scheme at all. This skill is the
domain-agnostic prompt compiler: it turns a theme into a disciplined image
prompt, the same way a magazine art director turns a headline into a cover
brief — one attention geometry, one anchor, one color, real restraint.
aria-code can execute the compiled prompt directly when an image backend is
configured (see Execution below) — the compiled prompt is still the primary
artifact, but "compile and hand it off" is now the fallback path, not the
only path.
When this matters
- A standalone poster-style asset for a theme, headline, or brief — from
any domain, not just finance
- The user explicitly asks for "minimal", "zine", "editorial", or "poster"
styling for a piece of content, distinct from a data export
- Never for styling aria-code's own report covers/PPTX/Canva exports — that
is
minimal-editorial-exports's job, and the two skills should not both
fire for the same request
First-principles compiler — answer these in order
Answering out of order produces a prompt that looks assembled rather than
composed — each answer constrains the next.
- Canvas — aspect ratio and surface (tall poster, square card, wide
banner) and ground material (aged paper, plain matte, raw canvas).
- Attention geometry — what fraction of the frame is empty (70-90% is
the zine default) and where the one occupied region sits.
- Anchor — the single subject that fills that occupied region: a
photo-like image, a cut-paper silhouette, a solid color block, a small
illustration, a specimen-style object, a short line of type standing
alone. Pick ONE — never a scene with multiple competing subjects.
- Anchor treatment — how that one anchor is rendered: full color,
duotone, line art, halftone, high-contrast silhouette.
- Typography — serif, typewriter, or monospace; how much of the frame
type occupies (usually very little — a title and maybe one line, never a
paragraph).
- Color logic — one high-saturation anchor color against a
desaturated/neutral ground. See Color Engine below.
- Texture — the print-defect layer: xerox grain, risograph
misregistration, halftone dots, letterpress impression, scanner noise.
Pick one, applied subtly — texture is atmosphere, not the subject.
- Emotional temperature — quiet, wistful, plain, deadpan, tender. Not
loud, not commercial, not dramatic — this is an editorial/indie register,
not an ad.
- Hard avoids — see Negative Constraints; name explicitly in the
compiled prompt what this is NOT, since image models default toward the
commercial-poster look this style rejects.
Color Engine
- Exactly one saturated anchor color. Everything else is paper-neutral,
aged-white, muted grey, or ink-black.
- The anchor color should come from something real about the subject when
one exists (a domain signal's real color, a detail mentioned in the
brief) — not an arbitrary pretty color, the same principle
minimal-editorial-exports applies to report covers.
- Never two saturated colors fighting for attention.
Variation axes — don't compile the same poster every time
Running this compiler repeatedly for a batch (a week of stories, a set of
listings) with one fixed recipe becomes its own template. Vary, driven by
the actual subject each time, not at random:
- Attention geometry — center-fragment, lower-third float, upper
corner block, dual-panel split, type-led (no image anchor at all)
- Anchor type — photo/illustration/silhouette/block/specimen/type-only
- Texture — rotate across xerox/riso/halftone/letterpress/scan-noise
- Temperature — quiet vs. plain vs. wistful vs. deadpan
Execution — turning the compiled prompt into a real image
aria-code has two image backends, both MCP-exposed (packages/aria_mcp/server.py),
mirroring the local-vs-cloud choice local_llm_provider.py/openai_image_client.py
already make for chat:
- Local, self-hosted (
local_image_provider.py, default stabilityai/sdxl-turbo
fp16) — aria.report.generate_image_local for a from-scratch anchor,
aria.report.edit_image_local for an anchor that's an existing user photo.
No API key, no per-call cost. Needs the optional image_gen extra
installed and (once) ~4GB of fp16 weights downloaded — first call is slow,
later calls fast (confirmed on M1 Pro/MPS: ~10s for a 4-step from-scratch
generation once weights are cached).
- OpenAI-backed (
openai_image_client.py, gpt-image-1) —
aria.report.generate_image / aria.report.edit_image. Needs an OpenAI
key (/apikey set openai sk-...); real per-call cost.
Which tool to call is decided by the Anchor field (step 3): an anchor
that's the user's own existing photo → the edit tool with that file's path;
any other anchor type (illustration, silhouette, block, specimen, type-only)
→ the generate tool with no input image.
strength (edit tools only, 0–1) is the one parameter this skill has real
tuned guidance for — it controls how much the output is allowed to diverge
from the input photo:
- 0.35–0.45: conservative — keeps the original composition/likeness close,
treatment (duotone, texture) reads as a filter over the real photo
- 0.5–0.6: the default starting point — real restyling while the original
subject and composition stay recognizable (confirmed on a real portrait:
duotone + simplified background + texture all came through at 0.55)
- 0.65–0.75: aggressive — the anchor treatment dominates, useful when field 4
(anchor treatment) calls for something far from a straight photo (e.g.
full silhouette/line-art)
Steps: 4 is sdxl-turbo's trained regime (guidance_scale=0.0 to match) —
raising steps on a turbo-distilled model doesn't reliably improve quality,
it just costs more time; only raise it if you switch model to a
non-turbo checkpoint that expects real classifier-free guidance.
If neither backend is configured (extra not installed, no OpenAI key), say
so explicitly and fall back to the compiled-prompt-only output below — never
silently skip presenting anything.
Workflow
- Gather the theme/sentence/mood/brief from the user — ask if genuinely
ambiguous, don't invent a subject from nothing.
- Answer the nine first-principles fields in order for this specific
subject.
- Pick variation-axis values driven by what's actually different about
this subject versus the last one compiled in the same session/batch.
- Compile into the Output Format below.
- Run the Quality Gate before presenting it — prefer the bundled script
(
scripts/poster_gate.py, see Automated Quality Gate below) over eyeballing
the checklist; it catches the exact class of mistake that reads fine in
isolation (two saturated colors, a hard-avoid term that leaked into the
anchor treatment, "70%+ empty" that's actually 15%).
- If an image backend is configured (see Execution), actually call it —
local first (no cost) unless the user asked for OpenAI specifically —
using the Anchor field to choose generate vs. edit and, for edit, a
strength from the tuned ranges above. Otherwise present the compiled
prompt plus the non-image fallback brief and say plainly that no backend
is configured, rather than silently doing nothing with it.
Negative Constraints
Never: full-bleed busy scenes, commercial/advertising headline layouts,
product-ad composition, logos or brand marks, glossy 3D renders, cinematic
lighting, neon, cartoon style, dense scrapbook collage, long text blocks,
stock-photo realism, multiple competing focal subjects.
Output Format
POSTER PROMPT
Canvas: <aspect ratio + surface>
Attention geometry: <negative-space % + occupied region position>
Anchor: <the one subject> — <treatment>
Typography: <face + how little of the frame it uses>
Color: <one anchor color> on <neutral ground>
Texture: <one texture, applied subtly>
Temperature: <one register>
Avoid: <hard avoids relevant to this brief>
FALLBACK BRIEF (no image-gen backend configured)
A one-paragraph plain-language description of the same composition, for a
human designer or a non-image export path (e.g. handing to
minimal-editorial-exports for a text/chart-only equivalent) to work from.
When a backend is configured, the actual tool call follows immediately
after this block — anchor = existing photo → aria.report.edit_image_local
(or _image for OpenAI) with that file's path and a strength from the
tuned ranges above; any other anchor → aria.report.generate_image_local
(or _image) with the compiled prompt text.
Automated Quality Gate
scripts/poster_gate.py turns the checklist below into code — a spec that
"reads fine" can still fail it, which is the point (a hard-avoid term hiding
inside anchor_treatment, two role: "anchor" colors, negative_space_pct
that's real but under 70). Build the spec as a JSON object with the nine
compiled fields (see compile_prompt's field names — canvas,
negative_space_pct, anchor, anchor_is_photo, anchor_treatment,
typography, colors (list of {role, name, hex, source}, exactly one
role: "anchor"), texture, temperature, avoids, subject_keywords),
then:
python scripts/poster_gate.py --spec spec.json # compiled prompt + verdict + findings
python scripts/poster_gate.py --demo # no input needed — see below
--demo reproduces a real instance: the commercial travel-poster prompt this
skill's own author actually sent to an image tool for a London skyline photo
before this gate existed (full-bleed, two saturated colors, "dramatic
cinematic lighting" — several Negative Constraints violations at once) next
to the corrected minimal-editorial compile for the same source photo — one
FAILs with named codes (multiple_saturated_colors, forbidden_term_leak,
insufficient_negative_space, …), the other PASSes. subject_keywords
drives the genericness check (field 3's "would this same prompt work for a
different subject?") — declare the words that make this brief specific, and
the gate flags an anchor that doesn't actually use any of them.
When anchor_is_photo is true, the result also carries a
strength_recommendation (range + rationale) from the tuned guidance in
Execution below, keyed off keywords in anchor_treatment — so the edit-tool
call doesn't default blindly to 0.55 regardless of what field 4 actually asked
for.
Verdict is FAIL if any check hard-fails (missing/insufficient field,
forbidden-term leak, multiple anchor colors, generic anchor), WARN for
softer signals (borderline negative-space, ungrounded anchor color, no
subject_keywords declared), PASS otherwise. Treat FAIL as blocking —
recompile the offending field — and WARN as a prompt to double-check, not
an automatic block.
Cross-Runtime Execution
The compiler and gate above (SKILL.md body + poster_gate.py) are pure
Python and pure prose — no aria-code-specific tool calls — so they carry
unchanged into any runtime that can load a SKILL.md-shaped instruction set
and run a script or read its output. What differs per runtime is only which
image backend actually renders the compiled prompt:
- Aria Code — the Execution section below: local SDXL-Turbo
(
generate_image_local/edit_image_local) or OpenAI gpt-image-1
(generate_image/edit_image), auto-selected by this skill.
- Claude (Claude Code / claude.ai) — install this catalog as a plugin
(
.claude-plugin/marketplace.json → app-engineering-skills) or symlink
this skill folder into a project's .claude/skills/; run poster_gate.py
the same way, then hand the compiled prompt to whatever image tool is
connected (e.g. a Canva MCP connector) — note that most connector-based
image tools don't expose a raw img2img strength parameter the way
edit_image_local does, so an existing-photo anchor will read as
"regenerated in this style" rather than "this photo, restyled."
- ChatGPT — no native
SKILL.md loader; paste this file's body into a
Custom GPT's instructions or a project's custom instructions. Execution is
actually the closest match of any non-Aria runtime: ChatGPT's built-in image
tool is gpt-image-1, the same backend this skill already targets for
the OpenAI-backed path, so the compiled prompt carries over with no
backend-mapping step.
- Kimi / others with function-calling but no skill loader — same paste-as-
instructions approach; wire the compiled prompt to whatever image-generation
function the platform exposes, no tuned guidance carries over automatically.
Quality Gate
1---2name: minimal-editorial-poster3description: Compile a minimal editorial/zine-poster prompt for a theme, sentence, mood, or brief from ANY domain aria-code touches — a financial story, a real-estate listing highlight, a sports recap, a general subject — not tied to financial-report styling. Trigger for "做一张极简海报", "zine风格的海报", "minimal poster for [subject]", "给这个故事配一张海报", or when the user wants a standalone poster-style creative asset rather than a data export. Produces a ready-to-use image-generation prompt and, when an image backend is configured, actually executes it via aria.report.generate_image_local / edit_image_local (self-hosted, no API key) or the OpenAI-backed equivalents — falls back to prompt-only + a non-image brief when neither is available. Do NOT trigger for styling aria-code's own report/PPTX/Canva exports (use `minimal-editorial-exports` for that — this skill is for a standalone poster from a theme, not a data-export cover).4---56# Minimal Editorial Poster78A minimal zine poster says one thing, quietly, with almost the whole frame9left empty around it. That works the same way regardless of which of10aria-code's domains the subject comes from — `FINANCIAL_SCHEME`'s "AAPL beat11on margins", `REALTY_SCHEME`'s "this listing's cash flow is genuine", a12sports recap, or a subject with no domain scheme at all. This skill is the13domain-agnostic prompt compiler: it turns a theme into a disciplined image14prompt, the same way a magazine art director turns a headline into a cover15brief — one attention geometry, one anchor, one color, real restraint.1617aria-code can execute the compiled prompt directly when an image backend is18configured (see Execution below) — the compiled prompt is still the primary19artifact, but "compile and hand it off" is now the fallback path, not the20only path.2122## When this matters2324- A standalone poster-style asset for a theme, headline, or brief — from25 any domain, not just finance26- The user explicitly asks for "minimal", "zine", "editorial", or "poster"27 styling for a piece of content, distinct from a data export28- Never for styling aria-code's own report covers/PPTX/Canva exports — that29 is `minimal-editorial-exports`'s job, and the two skills should not both30 fire for the same request3132## First-principles compiler — answer these in order3334Answering out of order produces a prompt that looks assembled rather than35composed — each answer constrains the next.36371. **Canvas** — aspect ratio and surface (tall poster, square card, wide38 banner) and ground material (aged paper, plain matte, raw canvas).392. **Attention geometry** — what fraction of the frame is empty (70-90% is40 the zine default) and where the one occupied region sits.413. **Anchor** — the single subject that fills that occupied region: a42 photo-like image, a cut-paper silhouette, a solid color block, a small43 illustration, a specimen-style object, a short line of type standing44 alone. Pick ONE — never a scene with multiple competing subjects.454. **Anchor treatment** — how that one anchor is rendered: full color,46 duotone, line art, halftone, high-contrast silhouette.475. **Typography** — serif, typewriter, or monospace; how much of the frame48 type occupies (usually very little — a title and maybe one line, never a49 paragraph).506. **Color logic** — one high-saturation anchor color against a51 desaturated/neutral ground. See Color Engine below.527. **Texture** — the print-defect layer: xerox grain, risograph53 misregistration, halftone dots, letterpress impression, scanner noise.54 Pick one, applied subtly — texture is atmosphere, not the subject.558. **Emotional temperature** — quiet, wistful, plain, deadpan, tender. Not56 loud, not commercial, not dramatic — this is an editorial/indie register,57 not an ad.589. **Hard avoids** — see Negative Constraints; name explicitly in the59 compiled prompt what this is NOT, since image models default toward the60 commercial-poster look this style rejects.6162## Color Engine6364- Exactly one saturated anchor color. Everything else is paper-neutral,65 aged-white, muted grey, or ink-black.66- The anchor color should come from something real about the subject when67 one exists (a domain signal's real color, a detail mentioned in the68 brief) — not an arbitrary pretty color, the same principle69 `minimal-editorial-exports` applies to report covers.70- Never two saturated colors fighting for attention.7172## Variation axes — don't compile the same poster every time7374Running this compiler repeatedly for a batch (a week of stories, a set of75listings) with one fixed recipe becomes its own template. Vary, driven by76the actual subject each time, not at random:7778- **Attention geometry** — center-fragment, lower-third float, upper79 corner block, dual-panel split, type-led (no image anchor at all)80- **Anchor type** — photo/illustration/silhouette/block/specimen/type-only81- **Texture** — rotate across xerox/riso/halftone/letterpress/scan-noise82- **Temperature** — quiet vs. plain vs. wistful vs. deadpan8384## Execution — turning the compiled prompt into a real image8586aria-code has two image backends, both MCP-exposed (`packages/aria_mcp/server.py`),87mirroring the local-vs-cloud choice `local_llm_provider.py`/`openai_image_client.py`88already make for chat:8990- **Local, self-hosted** (`local_image_provider.py`, default `stabilityai/sdxl-turbo`91 fp16) — `aria.report.generate_image_local` for a from-scratch anchor,92 `aria.report.edit_image_local` for an anchor that's an existing user photo.93 No API key, no per-call cost. Needs the optional `image_gen` extra94 installed and (once) ~4GB of fp16 weights downloaded — first call is slow,95 later calls fast (confirmed on M1 Pro/MPS: ~10s for a 4-step from-scratch96 generation once weights are cached).97- **OpenAI-backed** (`openai_image_client.py`, `gpt-image-1`) —98 `aria.report.generate_image` / `aria.report.edit_image`. Needs an OpenAI99 key (`/apikey set openai sk-...`); real per-call cost.100101**Which tool to call is decided by the Anchor field (step 3):** an anchor102that's the user's own existing photo → the *edit* tool with that file's path;103any other anchor type (illustration, silhouette, block, specimen, type-only)104→ the *generate* tool with no input image.105106**`strength` (edit tools only, 0–1) is the one parameter this skill has real107tuned guidance for** — it controls how much the output is allowed to diverge108from the input photo:109- 0.35–0.45: conservative — keeps the original composition/likeness close,110 treatment (duotone, texture) reads as a filter over the real photo111- 0.5–0.6: the default starting point — real restyling while the original112 subject and composition stay recognizable (confirmed on a real portrait:113 duotone + simplified background + texture all came through at 0.55)114- 0.65–0.75: aggressive — the anchor treatment dominates, useful when field 4115 (anchor treatment) calls for something far from a straight photo (e.g.116 full silhouette/line-art)117118Steps: 4 is `sdxl-turbo`'s trained regime (`guidance_scale=0.0` to match) —119raising steps on a turbo-distilled model doesn't reliably improve quality,120it just costs more time; only raise it if you switch `model` to a121non-turbo checkpoint that expects real classifier-free guidance.122123If neither backend is configured (extra not installed, no OpenAI key), say124so explicitly and fall back to the compiled-prompt-only output below — never125silently skip presenting anything.126127## Workflow1281291. Gather the theme/sentence/mood/brief from the user — ask if genuinely130 ambiguous, don't invent a subject from nothing.1312. Answer the nine first-principles fields in order for this specific132 subject.1333. Pick variation-axis values driven by what's actually different about134 this subject versus the last one compiled in the same session/batch.1354. Compile into the Output Format below.1365. Run the Quality Gate before presenting it — prefer the bundled script137 (`scripts/poster_gate.py`, see Automated Quality Gate below) over eyeballing138 the checklist; it catches the exact class of mistake that reads fine in139 isolation (two saturated colors, a hard-avoid term that leaked into the140 anchor treatment, "70%+ empty" that's actually 15%).1416. If an image backend is configured (see Execution), actually call it —142 local first (no cost) unless the user asked for OpenAI specifically —143 using the Anchor field to choose generate vs. edit and, for edit, a144 `strength` from the tuned ranges above. Otherwise present the compiled145 prompt plus the non-image fallback brief and say plainly that no backend146 is configured, rather than silently doing nothing with it.147148## Negative Constraints149150Never: full-bleed busy scenes, commercial/advertising headline layouts,151product-ad composition, logos or brand marks, glossy 3D renders, cinematic152lighting, neon, cartoon style, dense scrapbook collage, long text blocks,153stock-photo realism, multiple competing focal subjects.154155## Output Format156157```158POSTER PROMPT159Canvas: <aspect ratio + surface>160Attention geometry: <negative-space % + occupied region position>161Anchor: <the one subject> — <treatment>162Typography: <face + how little of the frame it uses>163Color: <one anchor color> on <neutral ground>164Texture: <one texture, applied subtly>165Temperature: <one register>166Avoid: <hard avoids relevant to this brief>167168FALLBACK BRIEF (no image-gen backend configured)169A one-paragraph plain-language description of the same composition, for a170human designer or a non-image export path (e.g. handing to171minimal-editorial-exports for a text/chart-only equivalent) to work from.172```173174When a backend is configured, the actual tool call follows immediately175after this block — anchor = existing photo → `aria.report.edit_image_local`176(or `_image` for OpenAI) with that file's path and a `strength` from the177tuned ranges above; any other anchor → `aria.report.generate_image_local`178(or `_image`) with the compiled prompt text.179180## Automated Quality Gate181182`scripts/poster_gate.py` turns the checklist below into code — a spec that183"reads fine" can still fail it, which is the point (a hard-avoid term hiding184inside `anchor_treatment`, two `role: "anchor"` colors, `negative_space_pct`185that's real but under 70). Build the spec as a JSON object with the nine186compiled fields (see `compile_prompt`'s field names — `canvas`,187`negative_space_pct`, `anchor`, `anchor_is_photo`, `anchor_treatment`,188`typography`, `colors` (list of `{role, name, hex, source}`, exactly one189`role: "anchor"`), `texture`, `temperature`, `avoids`, `subject_keywords`),190then:191192```bash193python scripts/poster_gate.py --spec spec.json # compiled prompt + verdict + findings194python scripts/poster_gate.py --demo # no input needed — see below195```196197`--demo` reproduces a real instance: the commercial travel-poster prompt this198skill's own author actually sent to an image tool for a London skyline photo199before this gate existed (full-bleed, two saturated colors, "dramatic200cinematic lighting" — several Negative Constraints violations at once) next201to the corrected minimal-editorial compile for the *same source photo* — one202FAILs with named codes (`multiple_saturated_colors`, `forbidden_term_leak`,203`insufficient_negative_space`, …), the other PASSes. `subject_keywords`204drives the genericness check (field 3's "would this same prompt work for a205different subject?") — declare the words that make this brief specific, and206the gate flags an `anchor` that doesn't actually use any of them.207208When `anchor_is_photo` is true, the result also carries a209`strength_recommendation` (range + rationale) from the tuned guidance in210Execution below, keyed off keywords in `anchor_treatment` — so the edit-tool211call doesn't default blindly to 0.55 regardless of what field 4 actually asked212for.213214Verdict is `FAIL` if any check hard-fails (missing/insufficient field,215forbidden-term leak, multiple anchor colors, generic anchor), `WARN` for216softer signals (borderline negative-space, ungrounded anchor color, no217`subject_keywords` declared), `PASS` otherwise. Treat `FAIL` as blocking —218recompile the offending field — and `WARN` as a prompt to double-check, not219an automatic block.220221## Cross-Runtime Execution222223The compiler and gate above (`SKILL.md` body + `poster_gate.py`) are pure224Python and pure prose — no aria-code-specific tool calls — so they carry225unchanged into any runtime that can load a `SKILL.md`-shaped instruction set226and run a script or read its output. What differs per runtime is only which227image backend actually renders the compiled prompt:228229- **Aria Code** — the Execution section below: local SDXL-Turbo230 (`generate_image_local`/`edit_image_local`) or OpenAI `gpt-image-1`231 (`generate_image`/`edit_image`), auto-selected by this skill.232- **Claude (Claude Code / claude.ai)** — install this catalog as a plugin233 (`.claude-plugin/marketplace.json` → `app-engineering-skills`) or symlink234 this skill folder into a project's `.claude/skills/`; run `poster_gate.py`235 the same way, then hand the compiled prompt to whatever image tool is236 connected (e.g. a Canva MCP connector) — note that most connector-based237 image tools don't expose a raw img2img `strength` parameter the way238 `edit_image_local` does, so an existing-photo anchor will read as239 "regenerated in this style" rather than "this photo, restyled."240- **ChatGPT** — no native `SKILL.md` loader; paste this file's body into a241 Custom GPT's instructions or a project's custom instructions. Execution is242 actually the closest match of any non-Aria runtime: ChatGPT's built-in image243 tool *is* `gpt-image-1`, the same backend this skill already targets for244 the OpenAI-backed path, so the compiled prompt carries over with no245 backend-mapping step.246- **Kimi / others with function-calling but no skill loader** — same paste-as-247 instructions approach; wire the compiled prompt to whatever image-generation248 function the platform exposes, no tuned guidance carries over automatically.249250## Quality Gate251252- [ ] Exactly one anchor, one saturated color, one texture — none doubled up?253- [ ] Is the anchor color tied to something real about the subject, not254 arbitrary?255- [ ] Does attention geometry genuinely leave 70%+ empty, not just "less256 full than a normal poster"?257- [ ] Would this same compiled prompt work equally well for a completely258 different subject? If yes, it's too generic — revise field 3 (anchor)259 and field 6 (color) to be specific to this brief.260- [ ] If a backend is configured: chose edit vs. generate correctly from the261 Anchor field, and for edit, picked `strength` from the tuned ranges262 rather than defaulting blindly to 0.55 regardless of how far field 4263 (anchor treatment) actually wants to diverge from the source photo?264- [ ] If no backend is configured: said so explicitly and presented the265 fallback brief, not just a prompt nobody can act on?266- [ ] Confirmed this is a standalone poster request, not actually a request267 to style one of aria-code's own report/PPTX/Canva exports (that's268 `minimal-editorial-exports`)?