Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when generating or editing images via `blockrun_image` — especially with GPT Image 2, Nano Banana, or Grok Imagine for posters, UI mockups, marketing assets, product shots, or anything with on-image text. Turns vague user requests ("make me a cool poster") into structured, text-accurate prompts that actually render what you asked for.
.claude/skills/blockrunai-image-prompting/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 481% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 328% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 795% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 147% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 164% | 0% |
Most image failures are prompt failures. This skill gives the MCP agent a repeatable structure for turning any user request into a prompt that renders clean typography, preserves layout on edits, and avoids AI slop. Defaults are tuned for GPT Image 2 (best legible text), with fallbacks for Nano Banana, Grok Imagine, and CogView.
Costs are what you are actually CHARGED, verified live. Size is the biggest lever: any dimension above 1024 moves GPT Image 2 to the large tier and roughly doubles the price ($0.064 → $0.127). Ask for 1536x1024 only when you need it.
| User wants... | Model | Mode | Size | Cost | |---|---|---|---|---| | Poster / typography-heavy asset | openai/gpt-image-2 | generate | 1536x1024 or 1024x1536 | $0.127 | | Clean product / UI mockup | openai/gpt-image-2 | generate | 1024x1024 | $0.064 | | Photoreal / fashion / editorial | openai/gpt-image-2 or google/nano-banana-pro | generate | 1024x1024 | $0.064–0.106 | | Pro-level photoreal at Flash speed | google/nano-banana-2 | generate | 1024x1024 (only size) | $0.0955 | | Artistic / stylized / fast | google/nano-banana | generate | 1024x1024 | $0.0535 | | Cheapest usable draft | zai/cogview-4 | generate | 1024x1024 | $0.01675 | | Widescreen / banner on a budget | bytedance/seedream-5-pro | generate | 2048x1024 or 1280x720 | $0.04825 ($0.0955 when both sides >1024) | | Edit an existing image (localized change) | openai/gpt-image-2 | edit | match source | $0.064 at 1024x1024, $0.127 above | | Composite from multiple refs | openai/gpt-image-2 | edit (multi-ref) | match target | $0.064 at 1024x1024, $0.127 above |
Valid GPT Image 2 sizes: 1024x1024 (square), 1536x1024 (landscape ~3:2), 1024x1536 (portrait ~2:3).
Write prompts as five short blocks separated by blank lines. This is the single biggest quality lever.
SCENE: where/when/background/environment, one or two lines.
SUBJECT: the main focus (who/what), described concretely.
DETAILS: materials, texture, lighting, camera angle, composition, mood,
lens feel, depth of field, surface condition. Stack concrete nouns.
USE CASE: editorial photo / product mockup / poster / UI screen / infographic / concept frame.
(This single line tells the model what kind of image to produce.)
CONSTRAINTS: what must not drift. "No extra text." "No duplicate elements."
"Preserve face." "Legible typography." Repeat these on every edit.> The fifth slot is where most mediocre prompts fail silently. Describe the idea without bounding it and the model gets inventive in directions you will regret.
Headline (EXACT TEXT): "Fresh and clean."No extra words. No duplicate text. No watermarks.HERO:, SUB:, BOTTOM-LEFT TAG:, TOP BANNER:.| Bad (vague / praise-loaded) | Good (concrete visual fact) | |---|---| | "stunning, epic, masterpiece" | "overcast daylight, brushed aluminum, 50mm feel" | | "minimalist brutalist luxury editorial" | "cream background, heavy black condensed sans-serif, asymmetric type block, one hero object, studio tabletop light" | | "it should contain a boarding pass feel" | "a boarding pass lies on the tray, barcode visible, creased corner" | | "beautiful lighting" | "incandescent work lamp spilling warm light onto wet concrete" |
Rules:
pythonimport os from pathlib import Path chain_file = Path.home() / ".blockrun" / ".chain" chain = chain_file.read_text().strip() if chain_file.exists() else "base" if chain == "solana": from blockrun_llm import setup_agent_solana_wallet, ImageClient setup_agent_solana_wallet() else: from blockrun_llm import setup_agent_wallet, ImageClient setup_agent_wallet() image = ImageClient()
pythonprompt = """ SCENE: A realistic roadside billboard at sunset, empty two-lane highway, soft gradient sky from peach to lavender, a few utility poles. SUBJECT: A product billboard for a bottled water brand. Bottle on the right third of the frame, catching warm rim light. DETAILS: 35mm photo feel, shallow depth of field, matte-painted billboard, clean kerning, precise print finish. USE CASE: Product mockup for a marketing deck, landscape 3:2. CONSTRAINTS: - Headline (EXACT TEXT): "Fresh and clean." - Bold sans-serif, high contrast, centered vertically in the left half. - No extra words. No duplicate text. No watermark. """ result = image.generate( prompt, model="openai/gpt-image-2", size="1536x1024", n=1, ) print(result.data[0].url) # URL or data URL
The golden pattern for iterative editing — one small change per turn. Repeat the preserve list every turn.
pythonprompt = """ CHANGE: Make the light warmer — shift the sunset toward a deeper orange. Remove the extra chair on the left. PRESERVE: Keep the bottle position, label text, and billboard layout exactly as in the source image. Keep the headline text verbatim. CONSTRAINTS: No extra text. No duplicate elements. Same aspect ratio. """ # `image` arg accepts a public URL OR a data URL (data:image/png;base64,...) result = image.edit( prompt, image="https://example.com/source.png", model="openai/gpt-image-2", size="1536x1024", ) print(result.data[0].url)
Why this works: small atomic edits compound reliably. Giant rewrites ("redo this but nicer") drift everything.
Pass multiple reference images (up to ~16) via the edit endpoint. Label each reference's role in the prompt so the model knows how to use it.
pythonprompt = """ COMPOSITE: Combine the three reference images as follows. - REF 1 is the SUBJECT (the wristwatch): preserve exact dial, hands, and crown. - REF 2 is the ENVIRONMENT (marble tabletop + window light): use as background. - REF 3 is the STYLE REFERENCE: match its color grade and contrast. USE CASE: E-commerce hero shot, square. CONSTRAINTS: No extra objects. No text. Preserve watch proportions exactly. """ # SDK: pass primary via `image=`; additional refs via a multipart request # (check the MCP's `blockrun_image` tool for the multi-image payload shape)
This is the real prompt that produced the image below — a vague, one-line user ask turned into a structured prompt that rendered every copy line correctly on the first shot.
!100 Trillion Tokens poster generated with openai/gpt-image-2
User asked for: "generate 1 cool poster showing we hit 100 Trillion Token LLM consumption on blockrun.ai"
Clarifying questions worth asking before prompting:
Final prompt passed to openai/gpt-image-2 at size="1536x1024":
SCENE: A retro-futuristic synthwave scene, 80s vaporwave aesthetic, cinematic
16:9 composition. Deep purple-to-magenta sunset sky with a giant glowing
pink-and-orange setting sun cut by thin horizontal neon lines. Palm tree
silhouettes on both sides. Faint city skyline in the distance. An infinite
chrome grid floor vanishing at the horizon with pink and cyan perspective lines.
SUBJECT: A milestone announcement poster with the hero text
"100 TRILLION TOKENS" dominating the center of the frame.
DETAILS: Hero text in huge glossy chrome letters with a pink-to-cyan gradient
and neon rim light, bold condensed sans-serif, CRT glow, slight scanline
texture across the letters. Faint CRT scanlines overlay the entire frame.
Subtle film grain. Chromatic aberration on edges. High contrast, symmetrical,
cinematic poster composition.
USE CASE: Social media announcement poster for X/Twitter, 16:9 landscape.
CONSTRAINTS:
- HERO (EXACT TEXT, centered): "100 TRILLION TOKENS"
- SUB under the hero (clean neon cyan, wide letter-spacing, EXACT TEXT):
"The world's largest pay-per-call LLM gateway"
- TOP-CENTER BANNER inside a thin neon outline (EXACT TEXT):
"NOW WITH SEEDANCE + GPT IMAGE 2"
- BOTTOM-LEFT TAG (monospace, magenta, EXACT TEXT):
"> Served on blockrun.ai"
- BOTTOM-RIGHT TAG (monospace, magenta, EXACT TEXT):
"> Powered by x402 micropayments"
- Legible crisp typography. No extra words. No duplicate text. No watermark.Why this worked:
(EXACT TEXT) and wrapped in quotes.No duplicate text. No extra words. was in the CONSTRAINTS block — GPT Image 2 loves to duplicate headlines if you don't forbid it.1536x1024) rather than asking for "16:9" and hoping.Use 1536x1024 for X/Twitter, 1024x1024 for IG grid, 1024x1536 for IG story. Put every copy element on its own labeled line in the CONSTRAINTS block. Always include No duplicate text. No extra words.
State the device, status bar, app name, screen title, each visible element with position and state (checked, active, disabled), palette (hex-ish is fine: "deep navy accent"), typography scale, corner radius, spacing feel.
Surface + light source + lens + depth of field + one hero object. Name the material of everything in frame. Avoid "beautiful" — describe what you'd see.
Generate 3–4 variants with the same 5-section skeleton but swap only the DETAILS block (palette, lens, material). Keep SCENE/SUBJECT/USE CASE/CONSTRAINTS identical so you're actually comparing one variable.
SCENE: <where/when/background>
SUBJECT: <main focus, concrete nouns>
DETAILS: <materials, texture, lighting (source + quality + color),
camera angle, lens feel, depth of field, composition, mood>
USE CASE: <poster | UI screen | product shot | editorial photo | concept frame>
CONSTRAINTS:
- HERO (EXACT TEXT): "<verbatim copy>"
- SUB: "<verbatim copy>"
- <other copy with role labels>
- <typography rules: font style, weight, spacing, hierarchy>
- No extra words. No duplicate text. No watermark.
- <anything that must not drift: face, layout, aspect ratio>| Mode | When | Endpoint | Pattern | |---|---|---|---| | Generate | From scratch | /v1/images/generations | 5-section framework | | Edit | One image, localized change | /v1/images/image2image | Change / Preserve / Constraints | | Combine | Multi-image composition | /v1/images/image2image (multi-ref) | Labeled refs (SUBJECT / ENV / STYLE) |
result.data[0].url is either an HTTPS URL or a data:image/...;base64,... string. Save via urllib.request.urlretrieve for URLs or base64.b64decode(item.b64_json) for b64 payloads.1536x1024 — it reads as landscape on X/Twitter without cropping.CONSTRAINTS line marked (EXACT TEXT).pip install blockrun-llmImageClient().get_wallet_address(); setup_agent_wallet().get_balance())edit / multi-ref: source images must be reachable by a public URL or passed as a data URLBlockRun image models: openai/gpt-image-2, openai/gpt-image-1, google/nano-banana, google/nano-banana-2, google/nano-banana-pro, zai/cogview-4, xai/grok-imagine-image, xai/grok-imagine-image-pro, bytedance/seedream-5-pro
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 16,062 | 14,961 | -7% | 1 | 1 | 0% | 988 | 5,743 | +481% | 0 | 0 | — |
case-02 | fail→pass | 10,463 | 5,603 | -46% | 1 | 1 | 0% | 1,162 | 4,976 | +328% | 0 | 0 | — |
case-03 | fail→pass | 10,208 | 13,811 | +35% | 1 | 1 | 0% | 719 | 6,432 | +795% | 0 | 0 | — |
case-04 | fail→pass | 10,739 | 5,282 | -51% | 1 | 1 | 0% | 1,955 | 4,821 | +147% | 0 | 0 | — |
case-05 | fail→pass | 9,745 | 2,393 | -75% | 1 | 1 | 0% | 1,600 | 4,223 | +164% | 0 | 0 | — |
case-06 | fail→pass | 13,148 | 4,733 | -64% | 1 | 1 | 0% | 2,204 | 4,704 | +113% | 0 | 0 | — |
case-07 | fail→pass | 12,674 | 7,596 | -40% | 1 | 1 | 0% | 2,339 | 5,418 | +132% | 0 | 0 | — |
case-08 | fail→pass | 9,475 | 7,842 | -17% | 1 | 1 | 0% | 1,551 | 5,205 | +236% | 0 | 0 | — |
case-09 | pass→pass | 10,920 | 5,941 | -46% | 1 | 1 | 0% | 1,703 | 4,846 | +185% | 0 | 0 | — |
case-10 | fail→pass | 9,416 | 3,868 | -59% | 1 | 1 | 0% | 1,402 | 4,504 | +221% | 0 | 0 | — |
case-11 | pass→pass | 4,648 | 3,071 | -34% | 1 | 1 | 0% | 858 | 4,447 | +418% | 0 | 0 | — |
case-12 | fail→pass | 5,425 | 2,617 | -52% | 1 | 1 | 0% | 945 | 4,314 | +357% | 0 | 0 | — |
case-13 | pass→pass | 10,176 | 6,886 | -32% | 1 | 1 | 0% | 1,891 | 5,191 | +175% | 0 | 0 | — |
case-14 | pass→pass | 12,201 | 10,669 | -13% | 1 | 1 | 0% | 1,901 | 5,843 | +207% | 0 | 0 | — |
case-15 | fail→pass | 15,387 | 11,164 | -27% | 1 | 1 | 0% | 2,429 | 5,817 | +139% | 0 | 0 | — |
case-16 | fail→pass | 14,737 | 8,366 | -43% | 1 | 1 | 0% | 2,164 | 5,208 | +141% | 0 | 0 | — |
case-17 | fail→pass | 13,191 | 8,832 | -33% | 1 | 1 | 0% | 2,390 | 5,523 | +131% | 0 | 0 | — |
case-18 | pass→pass | 19,220 | 15,958 | -17% | 1 | 1 | 0% | 2,829 | 6,394 | +126% | 0 | 0 | — |
case-19 | pass→pass | 8,741 | 7,685 | -12% | 1 | 1 | 0% | 1,554 | 5,233 | +237% | 0 | 0 | — |
case-20 | pass→pass | 9,124 | 10,639 | +17% | 1 | 1 | 0% | 1,332 | 5,416 | +307% | 0 | 0 | — |
case-21 | fail→pass | 11,216 | 9,712 | -13% | 1 | 1 | 0% | 1,816 | 5,602 | +208% | 0 | 0 | — |
case-22 | fail→pass | 8,255 | 3,134 | -62% | 1 | 1 | 0% | 1,499 | 4,304 | +187% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +68 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.