
Ideogram4
- 175 installs
- 1.9k repo stars
- Updated July 6, 2026
- digitalsamba/claude-code-video-toolkit
Generate title cards and thumbnails with legible on-image text and exact brand colors using Ideogram 4 JSON captions.
About
Generates images with legible on-image text and precise color/layout control via Ideogram 4's structured JSON caption format. A developer uses it to make title cards, thumbnails, and signage with baked-in text.
- Builds structured JSON captions for Ideogram 4 to render legible in-image text and exact brand hex palettes
- Thin Python wrapper posts the caption to Ideogram's hosted v4 API for title cards, thumbnails, and quote cards
Ideogram4 by the numbers
- 175 all-time installs (skills.sh)
- Ranked #652 of 1,335 Generative Media skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/digitalsamba/claude-code-video-toolkit --skill ideogram4Add your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 175 |
|---|---|
| repo stars | ★ 1.9k |
| Last updated | July 6, 2026 |
| Repository | digitalsamba/claude-code-video-toolkit ↗ |
What it does
Generate title cards and thumbnails with legible on-image text and exact brand colors using Ideogram 4 JSON captions.
Files
Ideogram 4 Skill
Text-to-image generation with Ideogram 4 (9.3B, open-weight, released June 2026). Its superpower is best-in-class in-image text rendering — it beats much larger models (FLUX.2 dev 32B, Qwen-Image 20B, Hunyuan 80B) at rendering legible signage, logos, captions, and multi-line text — plus exact color-palette and bounding-box control.
That advantage is locked behind a structured JSON caption format. A plain-text prompt gets you FLUX-level results and misses the entire point of using this model. This skill teaches Claude to act as the "magic prompt" expander — turning a user's casual request into the JSON caption Ideogram 4 was trained on.
Backend: The toolkit uses Ideogram's hosted v4 API (not self-hosted weights). The API
accepts a structured json_prompt, so everything this skill teaches applies directly — Claudebuilds the caption, the tool posts it as json_prompt. Paid API plans include a **commerciallicense**, which the self-hostable weights (non-commercial) do not — that's why we use the API.
Cost is ~$0.03/image (turbo) to ~$0.09/image (quality).
When to Use This Skill
Reach for Ideogram 4 (over FLUX.2) when the image needs:
- Legible on-image text — title cards, thumbnails, lower-thirds backgrounds, signage, logos,
quote cards, CTAs with a headline baked in
- Exact brand colors — hex color-palette conditioning, per-element
- Controlled layout — bounding boxes place text/objects in specific regions
- Multilingual text in the image
Use FLUX.2 instead when: the image has no critical text, you need commercial-licensed output, or you just want a fast atmospheric background. FLUX takes plain natural-language prompts; Ideogram wants JSON. See tools/flux2.py.
The One Thing to Get Right
Always emit a structured JSON caption, not a plain sentence. The model is trained exclusively on JSON captions that name every element explicitly. Claude is a better expander than Ideogram's free hosted magic-prompt (their own docs note the shipped one "is not the same used in production"), so build the caption yourself using this skill rather than passing raw text.
Minimal valid caption:
{"high_level_description":"A sailboat at sunset on calm water.","style_description":{"aesthetics":"serene, warm, golden hour","lighting":"golden hour backlighting","photo":"wide angle, f/8","medium":"photograph","color_palette":["#FF6B35","#F7C59F","#004E89"]},"compositional_deconstruction":{"background":"Calm ocean at low horizon with orange-pink sky.","elements":[{"type":"obj","desc":"White triangular sail silhouetted against the setting sun."}]}}Full schema, strict key-ordering rules, and the bbox coordinate system are in `prompting.md`. Worked title-card / thumbnail / quote-card examples are in `examples.md`.
Quick Reference — tools/ideogram4.py
Thin wrapper over Ideogram's hosted v4 API. NeedsIDEOGRAM_API_KEYin.env
(key from developer.ideogram.ai).--jsonposts the caption as the API'sjson_prompt
field (no server-side magic prompt — Claude is the expander);--promptpoststext_prompt.
# Hand-authored JSON caption (the recommended path for text/layout) — Claude writes caption.json
python3 tools/ideogram4.py --json caption.json --output title.png
# Caption from stdin (Claude can pipe it directly)
cat caption.json | python3 tools/ideogram4.py --json - --output title.png
# Plain prompt — Ideogram's server-side magic prompt expands it (weaker; prefer --json)
python3 tools/ideogram4.py --prompt "Title card: 'AI ENGINEERING REVIEW' bold white on dark" --output title.png
# Inject brand hex colors into the caption's palette (JSON mode)
python3 tools/ideogram4.py --json caption.json --brand digital-samba --output cta.png
# Quality tier + resolution
python3 tools/ideogram4.py --json caption.json --speed QUALITY --resolution 2048x2048 --output slide.pngKey Files
prompting.md— full JSON schema, strict key ordering, bbox coordinate system, palette rulesexamples.md— worked captions for title cards, thumbnails, quote cards, brand CTAs
Video Production Fit
Ideogram 4's niche in the toolkit is slides and thumbnails with baked-in text, where FLUX and LTX-2 fail (both render garbled text). Natural pairings:
| Use case | Why Ideogram 4 |
|---|---|
| Title-card / CTA background with headline text | Legible text + exact brand hex colors in one pass |
| YouTube/social thumbnail with a punchy phrase | Big readable text is its strongest suit |
| Quote card / stat card | Multi-line text + layout control via bboxes |
| Signage/logos inside a product-demo scene | In-image text other models can't render |
Then feed the still into Remotion (<OffthreadVideo>/Img) or animate it with tools/ltx2.py --input.
Ideogram 4 — Worked Examples
Real caption examples for the toolkit's bread-and-butter use cases. Each shows the user's casual ask and the JSON caption Claude should produce (this is the magic-prompt expansion). JSON is shown pretty-printed for readability — serialize compact (separators=(",",":")) when passing.
---
1. Title card with headline text (the flagship use case)
User: "Title card for the AI Engineering Review video — big bold 'AI ENGINEERING REVIEW' on a dark techy background."
{
"high_level_description": "A dark modern tech title card with a large bold headline reading 'AI ENGINEERING REVIEW' centered in the upper-middle.",
"style_description": {
"aesthetics": "bold, modern, high-contrast corporate tech, generous negative space",
"lighting": "soft cyan rim glow from below, deep shadows",
"medium": "flat vector graphic design with subtle gradient backdrop",
"art_style": "minimalist tech poster, clean geometric",
"color_palette": ["#0B0B1A", "#00E0C6", "#1B2A4A", "#FFFFFF"]
},
"compositional_deconstruction": {
"background": "Deep near-black navy gradient with a faint geometric grid and a soft cyan glow rising from the lower edge.",
"elements": [
{
"type": "text",
"bbox": [340, 120, 540, 880],
"text": "AI ENGINEERING REVIEW",
"desc": "Bold heavy sans-serif headline, all caps, crisp white, tight letter spacing, centered.",
"color_palette": ["#FFFFFF"]
},
{
"type": "obj",
"bbox": [580, 380, 620, 620],
"desc": "A thin glowing cyan horizontal accent rule beneath the headline.",
"color_palette": ["#00E0C6"]
}
]
}
}Why it works: the headline is a text element with the literal string (legible-text strength), the brand cyan is pinned via per-element palette on the accent rule, and the bbox keeps the title in the upper-middle band.
---
2. Thumbnail with a punchy phrase
User: "YouTube thumbnail, the words 'SHIP FASTER' huge on the left, a rocket on the right."
{
"high_level_description": "A high-energy thumbnail with the huge two-line phrase 'SHIP FASTER' on the left and a stylized rocket launching on the right.",
"style_description": {
"aesthetics": "loud, saturated, high-energy, big-text thumbnail style",
"lighting": "bright punchy lighting with strong contrast",
"medium": "bold flat illustration",
"art_style": "modern poster illustration, thick outlines",
"color_palette": ["#FF3B30", "#FFD60A", "#0B0B1A", "#FFFFFF"]
},
"compositional_deconstruction": {
"background": "Bold diagonal split background, deep navy on the right, warm yellow burst on the left.",
"elements": [
{
"type": "text",
"bbox": [250, 40, 750, 520],
"text": "SHIP FASTER",
"desc": "Massive heavy condensed sans-serif, two lines, all caps, white with a thick dark outline, left-aligned.",
"color_palette": ["#FFFFFF", "#0B0B1A"]
},
{
"type": "obj",
"bbox": [200, 560, 850, 960],
"desc": "A stylized cartoon rocket launching upward with a bright flame trail, slight tilt.",
"color_palette": ["#FF3B30", "#FFD60A", "#FFFFFF"]
}
]
}
}Keep thumbnail phrases to 1–3 words — that's where the text rendering is strongest.
---
3. Brand CTA with exact colors
User: "End-card CTA for Digital Samba: 'Start your free trial' button, on-brand colors."
When the user names a brand, read brands/<brand>/brand.json for the real hex values and placethem in the palettes. The placeholders below stand in for those.
{
"high_level_description": "A clean end-card with the headline 'Start your free trial' and a rounded call-to-action button, in Digital Samba brand colors.",
"style_description": {
"aesthetics": "clean, trustworthy, modern SaaS",
"lighting": "even soft lighting, airy",
"medium": "flat UI-style vector graphic",
"art_style": "minimal product marketing card, lots of whitespace",
"color_palette": ["#FFFFFF", "#1456F0", "#0B1B3A"]
},
"compositional_deconstruction": {
"background": "Soft white-to-pale-blue gradient, very clean.",
"elements": [
{
"type": "text",
"bbox": [300, 150, 460, 850],
"text": "Start your free trial",
"desc": "Friendly bold sans-serif headline, dark navy, centered.",
"color_palette": ["#0B1B3A"]
},
{
"type": "obj",
"bbox": [560, 340, 680, 660],
"desc": "A rounded rectangular button with subtle shadow.",
"color_palette": ["#1456F0"]
},
{
"type": "text",
"bbox": [585, 360, 655, 640],
"text": "Get started free",
"desc": "Button label, medium-weight white sans-serif, centered on the button.",
"color_palette": ["#FFFFFF"]
}
]
}
}Note the layered text-over-object: the button is an obj, its label is a separate text element with a tighter bbox sitting inside the button's bbox.
---
4. Quote / stat card (multi-line text + layout)
User: "Stat card: big '94%' with 'of teams shipped faster' underneath."
{
"high_level_description": "A minimal stat card with a giant '94%' figure and the supporting line 'of teams shipped faster' beneath it.",
"style_description": {
"aesthetics": "confident, minimal, data-forward",
"lighting": "flat even studio light",
"medium": "flat vector graphic design",
"art_style": "clean infographic card",
"color_palette": ["#0B0B1A", "#00E0C6", "#FFFFFF"]
},
"compositional_deconstruction": {
"background": "Solid deep navy with a faint radial glow behind the figure.",
"elements": [
{
"type": "text",
"bbox": [220, 250, 560, 750],
"text": "94%",
"desc": "Enormous bold sans-serif figure, bright cyan, centered.",
"color_palette": ["#00E0C6"]
},
{
"type": "text",
"bbox": [600, 200, 700, 800],
"text": "of teams shipped faster",
"desc": "Medium-weight white sans-serif subline, centered beneath the figure.",
"color_palette": ["#FFFFFF"]
}
]
}
}---
5. Photographic scene (when to use photo)
User: "A photo of a modern office at golden hour for a background, no text."
{
"high_level_description": "A warm, modern open-plan office bathed in golden-hour light, no text.",
"style_description": {
"aesthetics": "warm, aspirational, editorial",
"lighting": "golden hour sunlight streaming through floor-to-ceiling windows, long soft shadows",
"photo": "35mm, f/2.8, shallow depth of field, eye-level",
"medium": "photograph",
"color_palette": ["#F4C77E", "#3A2E25", "#D9C8B4"]
},
"compositional_deconstruction": {
"background": "Open-plan office with wood desks and plants, large windows with sun flare at the far end.",
"elements": [
{
"type": "obj",
"bbox": [350, 100, 800, 500],
"desc": "A wooden desk with an open laptop and a steaming coffee mug, foreground left.",
"color_palette": ["#6B4E2E", "#1B1B1B"]
},
{
"type": "obj",
"bbox": [300, 600, 750, 780],
"desc": "A leafy potted plant catching warm backlight.",
"color_palette": ["#3E5C2E"]
}
]
}
}Note the key order flips for photos: aesthetics → lighting → photo → medium → color_palette.
---
Good vs. bad at a glance
| Bad (plain text) | Good (JSON caption) |
|---|---|
"Title card saying AI Engineering Review" | Example 1 — headline as a text element, bbox, brand palette |
Text described inside desc | Literal string in the text field of a text element |
color: blue | "color_palette": ["#1456F0"] (uppercase hex, per element) |
| Paragraph of body copy in one text element | 1–3 word headline + short subline, each its own element |
Lowercase hex #1456f0 | Uppercase #1456F0 |
Ideogram 4 — JSON Caption Prompting
Ideogram 4 is trained exclusively on structured JSON captions where every element is named explicitly. This file is the reference for building those captions. The whole prompt-adherence and text-rendering advantage flows from following this schema precisely — including its quirks (strict key ordering, an unusual bbox axis order).
Top-Level Structure
A caption is a JSON object with three top-level fields:
| Field | Required | Purpose |
|---|---|---|
high_level_description | Optional but strongly recommended | 1–2 sentence summary of the whole image |
style_description | Optional object | Visual aesthetics, medium, global color palette |
compositional_deconstruction | Required object | Spatial layout: background + every element |
style_description
Must contain exactly one of photo or art_style:
photo— for photographic imagesart_style— for illustrations, paintings, 3D renders, vector/graphic design
Required keys when the block is present: aesthetics, lighting, medium. Optional: color_palette.
Strict key ordering (this matters)
"The model was trained on JSON with a consistent key order, so maintaining it improves
generation quality." Deviating is allowed but samples outside the training distribution.
- Photos:
aesthetics→lighting→photo→medium→color_palette - Non-photos:
aesthetics→lighting→medium→art_style→color_palette
"style_description": {
"aesthetics": "bold, modern, high-contrast corporate",
"lighting": "flat even studio lighting, no harsh shadows",
"medium": "flat vector graphic design, clean geometric",
"art_style": "minimalist tech poster, generous negative space",
"color_palette": ["#0B0B1A", "#00E0C6", "#FFFFFF"]
}compositional_deconstruction
Two required fields:
background— string describing the environment / backdropelements— array of objects and text, each with a fixed key order
Element: object (type: "obj")
Key order: type → bbox → desc → color_palette
{ "type": "obj", "bbox": [200, 100, 800, 450], "desc": "A sleek silver laptop, three-quarter view, screen glowing.", "color_palette": ["#C0C0C0", "#1B1B2F"] }Element: text (type: "text")
Key order: type → bbox → text → desc → color_palette
The text field holds the literal string to render; desc describes how it looks (font weight, style, placement feel).
{ "type": "text", "bbox": [120, 80, 300, 920], "text": "AI ENGINEERING REVIEW", "desc": "Bold heavy sans-serif headline, all caps, crisp white, centered.", "color_palette": ["#FFFFFF"] }Bounding Boxes (bbox)
- Format: `[y_min, x_min, y_max, x_max]` — note the y-first axis order (row before column).
- Coordinates are normalized 0–1000, where
0is top/left and1000is bottom/right. - Optional per element. Omit when you don't care where something lands; include for precise layout.
Quick mental map (full frame is 0–1000 on each axis):
x: 0 ............... 500 ............... 1000
y=0 ┌───────────────────────────────────┐
│ top band [0,0, 250,1000] │ ← headline / title text here
│ │
y=500 │ center [350,150, 650,850] │ ← hero subject
│ │
y=1000│ bottom [800,0, 1000,1000] │ ← CTA / footer text
└───────────────────────────────────┘So a centered headline across the top third is [80, 100, 280, 900] (y_min=80, x_min=100, y_max=280, x_max=900).
Color Palette Rules
- Up to 16 colors in
style_description.color_palette; up to 5 per element. - Must be uppercase hex:
#RRGGBB(e.g.#1B1B2F, not#1b1b2forrgb(...)). - Include both background and contrast/accent colors for controlled lighting.
- Per-element palettes override/steer that element specifically — ideal for forcing exact brand
colors on a logo or headline.
Serialization Quirks
When emitting the JSON string the model consumes:
- Use compact separators:
separators=(",", ":")(no spaces) — the--jsonpath in the tool
handles this; if hand-passing, compact JSON is safest.
ensure_ascii=Falseso non-ASCII / multilingual text passes through literally.- Preserve key order exactly as above.
Magic Prompt vs. Claude
Ideogram ships an LLM "magic prompt" that expands plain text → JSON. Three configs exist: ideogram-4-v1 (free hosted default), claude-opus-v1, claude-sonnet-v1 (both via OpenRouter). Their docs warn the shipped expander "is not the same used in production — results will differ."
Claude Code runs on Opus. So the highest-quality path is: Claude builds the caption directly using this skill, rather than round-tripping through the weaker free expander or adding an OpenRouter dependency. Treat yourself as the magic-prompt LLM.
Prompting Principles
1. Name every element explicitly. The model rewards exhaustive captions. Don't write "a busy office" — list the desk, the monitor, the plant, the window light. 2. Put literal on-image text in a `text` element, never bury it in a description. This is what unlocks the legible-text advantage. 3. Keep rendered strings reasonable. A headline + subhead + CTA is fine (its strength); a paragraph of body copy still degrades. 4. Use bboxes for layout-critical images (title cards, thumbnails). Skip them for loose scenes. 5. Use per-element palettes to pin brand colors on logos/headlines; global palette for mood. 6. Match the style block to intent — photo for realism, art_style for design/graphic work. Most title cards and thumbnails are art_style.
Common Pitfalls
| Pitfall | Fix |
|---|---|
| Plain-text prompt, generic result | Build the JSON caption — that's the whole point |
| Text rendered garbled/misspelled | Put it in a text element with the literal string in text, keep it short |
| Wrong colors | Uppercase hex, per-element color_palette on the headline/logo |
| Text in wrong spot | Add a bbox (remember y-first: [y_min,x_min,y_max,x_max], 0–1000) |
| Mediocre adherence | Add high_level_description; name more elements; keep key order |
lowercase hex ignored | Always #RRGGBB uppercase |