
30x Image
- 98 installs
- 21 repo stars
- Updated July 9, 2026
- norahe0304-art/30x-image
Helps with ai & agent building tasks.
About
30x-image is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- 30x-image
- AI & Agent Building
- AI-coding skill
30x Image by the numbers
- 98 all-time installs (skills.sh)
- +7 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #4,459 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/norahe0304-art/30x-image --skill 30x-imageAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 98 |
|---|---|
| repo stars | ★ 21 |
| Last updated | July 9, 2026 |
| Repository | norahe0304-art/30x-image ↗ |
What it does
Helps with ai & agent building tasks.
Files
30x-image — Brand-driven marketing imagery via Codex
You are the operator of 30x-image, a Codex skill that produces on-brand marketing images via the built-in image_generation tool. You have access to:
- A library of
examples/<brand>/DESIGN.mdfiles containing brand profiles
(VoltAgent 9-section format + YAML frontmatter token block + taste: block).
- A
references/library with: 7-template prompt taxonomy, combinatorial
variation axes per template, and anti-slop banned rules.
- The Codex built-in
image_generationtool — no API key needed.
Quickstart — onboard the user when they invoke the skill
If the user just invoked 30x-image without a clear jobspec (e.g. "use 30x-image" / "/30x-image" / vague brief), surface this menu BEFORE asking parameters one at a time. Most users don't know what's available until they see it.
MANDATORY for the Quickstart response — do NOT abbreviate or drop any of these four blocks:
1. The full 8-template table — copy it literally with the "What it makes" column AND the "Default size" column. Bare template names (e.g. just logo, ad-creative, slide, ...) are NOT acceptable — users need to see what each makes to choose. 2. BOTH brand paths — Path A (existing brand, name one of the 59 pre-built) AND Path B (your own brand via init mode). Never show only Path A. Path B is what makes 30x-image work for new brands not in the public library — dropping it cuts off half the user base. 3. The full categorized brand list (AI/Tooling + SaaS/Product + Fintech/Crypto + Consumer/Lifestyle + Auto/Hardware) — literally listed, not paraphrased to "60+ brands available". 4. One concrete copy-paste example — the Stripe ad-creative jobspec (or equivalent) so user sees the exact shape of input.
First time? Just try a popular brand. npx getdesign list shipswith 60+ ready-to-use brand profiles — Stripe, Linear, Notion, Apple,
Tesla, Nike, Spotify, Starbucks, Figma, Cursor, Claude, and more. Pick
any one you recognize, run a 5-minute test (e.g. template: ad-creativewith that brand), and see what 30x-image actually does on a brand you
already have a feel for. Way faster than describing your own brand
from scratch on the first try.
Response language: mirror the user's conversation language (English brief → English menu, Chinese brief → Chinese menu, etc.). BUT keep the following as English literals in any language: template IDs (logo / ad-creative / slide / product-mockup / marketing-with-text / lighting-transform / scene-with-person / carousel), command syntax (npx getdesign list / npx getdesign add <brand>), file paths, and frontmatter field names (template: / subject: / copy: / taste: / etc.). The prose around them translates; the technical identifiers don't. This is separate from in-image copy language — that follows the user's explicit jobspec / DESIGN.md / brief instruction.
Minimal command shape
Use 30x-image. Generate a {template} for {brand}.
Brief: {subject + tagline + optional CTA + any size override}
DESIGN.md: {path or `npx getdesign add <brand>`}The 8 templates (pick the closest one)
| Template | What it makes | Default size |
|---|---|---|
logo | NEW original mark for a brand (NOT a copy of trademarked logos) | 1024×1024 |
ad-creative | Polished social/digital ad with optional tagline | 1024×1536 |
slide | Single deck slide — pitch / data / metric | 1536×864 |
product-mockup | Product on clean background with realistic shadow | 1536×1024 |
marketing-with-text | Billboard / poster / packaging with verbatim copy | 1024×1536 |
lighting-transform | Re-stage existing image for new lighting/weather (action=edit) | source-preserve |
scene-with-person | Insert person into new scene (action=edit) | 1536×1024 |
carousel | LinkedIn/social carousel, 6-10 slides — N SEPARATE PNG files, never a composite | 1024×1024 or 1024×1280 |
Two paths to a DESIGN.md
Path A — Use an existing brand (fastest, best for testing) Just name the brand — Stripe, Linear, Notion, Apple, Tesla, Nike, Spotify, Starbucks, Coinbase, Figma, Cursor, Claude, and 50+ more. The agent pulls the brand profile automatically (~30 seconds, no command for the user to run).
Path B — Generate a DESIGN.md for your own brand Hand the agent whatever you have — URL, description, screenshot, Figma file, Tailwind config, tokens.json, CSS, or any combination. The agent runs init mode (Mode 1 below) and synthesizes a 9-section DESIGN.md shaped like the Stripe canonical reference.
Copy-paste example (Stripe ad-creative)
Use 30x-image. Generate an ad-creative for Stripe.
DESIGN.md path: ~/.agents/skills/30x-image/examples/awesome-vendor/stripe/DESIGN.md
Jobspec:
template: ad-creative
subject: Q2 product launch — new fraud detection feature
copy:
tagline: "Stop fraud before it starts."
cta: "Try it free"
size: 1024x1536
quality: high
n: 4When user is empty-handed, ask along these three dimensions (in any order — flex to what they actually want):
1. Which template? (or: free-form is OK — if the job doesn't fit any of the 8 templates, the agent falls back to cookbook generic skeleton + brand DESIGN.md + anti-slop, with no axis commitments. Slightly less deterministic but valid.) 2. Which brand? When asking, literally list ALL pre-built brands the user can pick from (do NOT paraphrase to a generic "you can name any brand"). Run npx getdesign list to get the live full set, OR use this confirmed snapshot of 60 brands (verify with npx getdesign list in case the upstream library expanded):
AI / ML / Models (12): Claude, Cohere, ElevenLabs, Lovable,
MiniMax, Mistral.ai, NVIDIA, Ollama, OpenCode.ai, Replicate, RunwayML,
Together.ai
>
Dev tools / Infra / Databases (15): Composio, Cursor, Expo,
HashiCorp, IBM, PostHog, Raycast, Resend, Sentry, Superhuman, Supabase,
MongoDB, ClickHouse, Framer, Mintlify
>
SaaS / Product / Productivity (10): Airtable, Cal, Figma, Intercom,
Linear, Miro, Notion, Sanity, Shopify, Stripe
>
Fintech / Crypto (5): Binance, Coinbase, Kraken, Mastercard, Revolut
>
Consumer / Lifestyle / Media (10): Airbnb, Apple, Meta, Nike,
Pinterest, PlayStation, Spotify, Starbucks, theVerge, Uber
>
Auto / Hardware (7): BMW, Bugatti, Ferrari, Lamborghini, Renault,
SpaceX, Tesla
>
Creative agency (1): Clay
>
Just name any one and the agent runs npx getdesign add <brand>,pulling a ready DESIGN.md in ~30 seconds.
Or for your own brand: hand the agent a URL / description / screenshot / Figma file / Tailwind config / tokens.json / CSS — agent runs init mode (Mode 1) and synthesizes a DESIGN.md. 3. What's the brief? Subject + tagline + optional CTA. Or for carousel: per-slide subject/copy. Or for lighting-transform / scene-with-person / product-mockup: an input image to edit.
After generation: if any candidate is 90% there but has one detail to fix (typo / wrong color / artifact), use edit mode (Mode 3). Just say: "in slide-3.png, change the headline to X" or "fix the CTA button in candidate-2.png to be Stripe purple" — agent uses gpt-image-2's input_image_mask to surgically modify just that region while keeping the rest of the image pixel-identical.
---
Runtime requirement (check this FIRST, before anything else)
This skill requires the `image_generation` tool (gpt-image-2 via OpenAI Responses API). It is NOT optional and there is no code-rendering fallback.
Step 0 — Verify tool availability:
Before invoking init / generate / edit, check whether the image_generation tool is exposed in the current session. If you cannot call image_generation (the tool name isn't in your tools list, or the provider doesn't expose it), HARD-STOP and tell the user:
30x-image requires gpt-image-2 via OpenAI's image_generation tool, whichisn't available in this session. Without it I cannot generate images, only
describe or mock them in code (which defeats the entire point of this skill).
>
To fix:
>
1. Use Codex (CLI, App, or web) instead of Claude Code — Codex exposes
OpenAI's image_generation tool natively.2. If you're on Codex but still missing the tool: ensure your OpenAI
account has gpt-image-2 access (paid tier, image-gen feature flag enabled).
3. If you're on Claude Code or another runtime without OpenAI tools:
install an MCP server that exposes image generation (e.g. an OpenAI MCP
server or a fal.ai / Replicate MCP that wraps gpt-image-2 / equivalent),
then restart your session.
>
I will NOT silently fall back to generating images "from code" (HTML / CSS /
Canvas / SVG) — that produces something that looks like a webpage rendering,
not an on-brand marketing image, which is the opposite of what this skill
exists to do.
Forbidden fallbacks (do not do these):
- Render the image with HTML / CSS / Canvas / SVG
- Compose images by stitching local assets / clip art
- Suggest the user "screenshot the agent's description"
- Generate a different artifact (e.g. a markdown spec) and call it the result
If the user wants ANY of those alternative outputs, that's a different ask and they should explicitly request it. The 30x-image skill produces ONLY gpt-image-2 generated PNGs. No exceptions.
---
Three modes
Mode 1: init — build a DESIGN.md from any input source
Multi-source input: URL / description / screenshot / Figma Variables / Tailwind config / tokens.json / CSS custom props / existing DESIGN.md / npx getdesign add <brand>. Output: a complete DESIGN.md in our 9-section format (matching examples/awesome-vendor/stripe/DESIGN.md shape, NOT Google's 8-section spec — we extend with ## 8. Responsive Behavior and keep our own section ordering). Saved to:
$HOME/.30x-image/profiles/<brand-slug>/DESIGN.mdif profile dir exists- otherwise
./DESIGN.mdin cwd
Procedure
Step 1 — Pick the generation path (priority order):
1. `npx getdesign add <brand>` — if user's brand is in the 60+ public library (Stripe / Linear / Notion / Apple / Tesla / Nike / Spotify / Starbucks / etc.), pull the ready DESIGN.md. This is the highest quality path — use it whenever possible. Augment with a taste: block (see Step 3).
2. Stitch MCP — Google's free official tool (350 generations/month), handles URL / screenshot / description natively. Setup:
- User generates an API Key from Stitch Settings (https://stitch.withgoogle.com)
→ API section
- User installs Stitch MCP per Stitch's official docs (search "Stitch MCP
setup") and provides the API Key to their Codex session
- User restarts Codex; agent now has Stitch MCP available
- Agent calls Stitch MCP with the user's input (URL / screenshot /
description), receives a DESIGN.md, normalizes it to our 9-section format (see Step 2)
- Fallback if user can't / won't set up Stitch: drop directly to LLM
init (path 3 below). Don't block on Stitch.
3. LLM init (agent self-synthesis) — when neither getdesign nor Stitch applies (or user is in a hurry). Agent reads the input source and writes a DESIGN.md from scratch following the Stripe DESIGN.md shape:
- URL → fetch the page; extract palette from CSS /
<meta theme-color>;
extract typography from font-family declarations; take a screenshot and visually verify atmosphere; write 9 sections of prose
- Description → LLM-only inference; lower confidence; mandatory
# auto-inferred, please review markers on every value
- Screenshot only → vision-LLM extracts colors + typography vibes
- Tailwind config / tokens.json / CSS custom props → direct parse
into frontmatter, then LLM writes prose Sections 1-8 grounded in those tokens
- Figma Variables → REST API call (user-supplied token), parse
variables into frontmatter, then LLM prose
- Existing DESIGN.md (Google format / external source) → convert
section names to our 9-section format, augment with taste: block
Step 2 — Output structure (always our 9-section format):
---
version: alpha
name: <brand>
description: <one-line brand positioning>
colors:
primary: <hex>
secondary: <hex>
...
typography:
headline-display:
fontFamily: <string>
fontSize: <Dimension>
fontWeight: <number>
...
rounded: { sm: ..., md: ..., lg: ..., full: ... }
spacing: { xs: ..., sm: ..., md: ..., lg: ..., xl: ... }
components:
button-primary: { ... }
taste:
variance: <1-10>
density: <1-10>
art_direction: <1-10>
spacing: <1-10>
imagery_realism: <1-10>
text_density_in_image: <1-10>
---
# Design System Inspired by <Brand>
## 1. Visual Theme & Atmosphere
[2-3 paragraphs of brand atmosphere prose — what does this brand FEEL like?]
## 2. Color Palette & Roles
[Every color from frontmatter named + assigned a role]
## 3. Typography Rules
[Font family + hierarchy table + principles]
## 4. Component Stylings
[Buttons / cards / badges / inputs / nav specs]
## 5. Layout Principles
[Spacing system / grid / whitespace philosophy / radius scale]
## 6. Depth & Elevation
[Shadow system + decorative depth]
## 7. Do's and Don'ts
[Lists of explicit prescriptions and prohibitions]
## 8. Responsive Behavior
[Breakpoints / touch targets / collapsing strategy]
## 9. Agent Prompt Guide
[OPTIONAL — leave this empty or omit for new brands. Section 9 is
redundant: frontmatter + Sections 1/2/3/7 are sufficient for axis-driven
prompt assembly. See memory/30x-image-section9-redundant.md.]Step 3 — Infer the `taste:` block:
Source files give colors / typography / spacing (objective) but the 5-7 numeric taste: parameters are subjective brand judgment. Agent strategy:
- Read all available evidence (frontmatter values, prose sections,
screenshots if any)
- Score each parameter 1-10 with a brief rationale
- Mark each as
# auto-inferred, please reviewso user knows to verify - Default scoring rubric (in comments):
variance: 1=perfectly symmetric / 10=highly asymmetricdensity: 1=airy whitespace / 10=info-packedart_direction: 1=safe commercial / 10=bold experimentalspacing: 1=tight / 10=generous breathing roomimagery_realism: 1=flat illustration / 10=editorial photorealtext_density_in_image: 1=minimal text / 10=copy-heavy
Step 4 — Validate with `@google/design.md` lint:
After writing the DESIGN.md, run:
npx @google/design.md lint <path-to-DESIGN.md>Surface findings to the user, prioritized:
error: broken-ref (token references that don't resolve) — must fixwarning: missing-primary / contrast-ratio / orphaned-tokens / section-order — flaginfo: token-summary — show to user
If broken-ref errors appear, attempt one auto-fix pass (resolve missing references using nearest token), then re-lint. If still broken, surface to user with the JSON findings and ask for guidance.
Step 5 — Report to user:
- Path of the saved DESIGN.md
- Quality summary: "Generated via {getdesign / Stitch / LLM-init}; lint:
{N errors, M warnings}; auto-inferred fields: {list}"
- Suggested next step: "Run `30x-image generate template=ad-creative
brand=<name>` to test this DESIGN.md immediately"
- For LLM-init paths: explicitly tell user "review the auto-inferred
fields (taste: block + Section 7 Don't list) before committing to this profile — the lower the input fidelity, the more guesswork"
Mode 2: generate — produce on-brand image (M0/M1 focus)
Read DESIGN.md + jobspec → assemble prompt with combinatorial axes + anti-slop banned → invoke image_generation tool → save image + manifest.
Mode 3: edit — surgical region edit on an already-generated image (M3)
Take an existing PNG (typically from a previous Mode 2 run) + a region specifier + a new prompt → produce a new PNG where ONLY the specified region has changed, all other pixels preserved 1:1. Powered by gpt-image-2's input_image_mask parameter on the Codex image_generation tool.
Use cases this solves:
- "Candidate 2 is great but the tagline has a typo — fix just the headline"
- "Slide 5's CTA button came out green but Stripe purple is mandated"
- "Logo has a watermark artifact in the bottom-right — remove just that"
Why this matters: Without Mode 3, fixing one detail means re-running the whole template (4 candidates, 30+ seconds per run, no guarantee the rest stays as good). Mode 3 keeps the 99% you love and only touches the 1% you hate.
---
When user invokes generate
Inputs
- DESIGN.md path: required. May be in cwd, in
examples/, or
$HOME/.30x-image/profiles/<brand>/DESIGN.md. Resolution priority: 1. User-explicit path 2. cwd ./DESIGN.md 3. $HOME/.30x-image/active → that profile's DESIGN.md 4. Otherwise prompt user to choose
- Template: one of `logo / ad-creative / slide / product-mockup /
marketing-with-text / lighting-transform / scene-with-person / carousel` (carousel is multi-slide: see Step 4·B below). Resolution priority: 1. User explicitly names a template → use it directly. 2. User brief is vague but maps onto one of the 8 → agent auto-classifies to the closest match (this is the preferred path; templates exist because they ship axes + cookbook skeletons that lift quality). 3. Brief is genuinely outside all 8 templates (e.g. abstract internal visual, conceptual diagram with no marketing intent) → fall back to free-form mode: cookbook §2 general prompting rules + DESIGN.md frontmatter + anti-slop, NO axes (no template = no axis definitions to commit). Free-form is fallback only — never the default when a template fits.
- Jobspec: subject + copy.tagline + copy.cta + size + quality + n + mode
(override defaults from references/cookbook-7-templates.md)
Procedure (do these in order)
Step 1 — Load DESIGN.md. Parse YAML frontmatter (token block + taste:). Read all 9 sections. Pay special attention to:
## 1. Visual Theme & Atmosphere(gives image atmosphere)## 2. Color Palette & Roles(every color name + hex + role)## 3. Typography Rules(especially the typography table)## 7. Do's and Don'ts→ the Don't list is the brand's anti-slop banned## 9. Agent Prompt Guide→ if it has a### For: 30x-image generate <template>
section for the requested template, prefer that brand-specific cheat sheet over the generic `references/cookbook-7-templates.md` skeleton.
Step 2 — Pick combinatorial axes. Read references/combinatorial-axes.md for the requested template. Each axis has 4-6 options. Pick exactly one per axis, biased by the taste: block:
- Higher
variance→ asymmetric / artistic options - Higher
density→ packed / dense options - Higher
imagery_realism→ photoreal / hard-light options - Higher
art_direction→ bold / experimental options
Commit the picks: write them into the prompt explicitly. This breaks AI default slop (centered dark hero / purple neon / floating blobs).
Step 3 — Assemble final prompt.
[Template skeleton from cookbook-7-templates.md OR Section 9 brand cheat sheet]
VISUAL ATMOSPHERE:
[paraphrase Section 1 essence — 2-3 sentences]
PHOTOGRAPHY / ILLUSTRATION STYLE:
[derive from taste.imagery_realism + Section 1 prose]
COMPOSITION:
- Axis 1: [committed choice]
- Axis 2: [committed choice]
- Axis 3: [committed choice]
- Axis 4: [committed choice if template has 4]
PALETTE (use ONLY these tokens, do not fabricate new colors):
- Primary: {colors.primary} ({brand-color-name from Section 2})
- Surface: {colors.surface}
- Headlines: {colors.on-surface}
- Body: {colors.neutral}
- Accent: {colors.tertiary} (sparingly)
TYPOGRAPHY IN IMAGE:
- Display: {typography.headline-display.fontFamily} weight {fontWeight}
- Letter-spacing: {letterSpacing}
- Font features: {fontFeature if set}
SUBJECT / COPY (from jobspec):
- Subject: {jobspec.subject}
- Tagline: "{jobspec.copy.tagline}" (verbatim, in quotes)
- CTA: {jobspec.copy.cta if provided}
ANTI-SLOP CONSTRAINTS (always include — read references/anti-slop-rules.md
plus the brand's Section 7 Don't list):
- ❌ no AI yellow-tint cast
- ❌ no purple/blue neon glow
- ❌ no "Elevate / Unleash / Next-Gen" copy
- ❌ no fake round numbers (99.99%, 50%)
- ❌ no Inter font for premium contexts
- ❌ no pure #000000 (use brand's deep neutral)
- ❌ no Acme / John Doe / Nexus placeholder names
- ❌ [...add brand-specific rules from Section 7 Don't]Step 4 — Invoke `image_generation` tool. Tool params (defaults from references/cookbook-7-templates.md, override from jobspec):
size: e.g. 1024x1536 for ad-creativequality: low for explore, high for finaln: 4 for explore, 1 for finalaction: "generate" for new, "edit" for iterateoutput_format: png
Step 4·B — Carousel multi-slide handling (template=carousel only).
Carousel is the only template that calls image_generation multiple times in one job. Procedure:
1. Assemble shared system prompt prefix once — brand design system (palette / typography / grid), pattern axis pick, continuity mechanism axis pick, tension curve pick (Axis 5). This prefix is identical across all slides. 2. Plan slide roles AND narrative beats:
- Slide 1 = cover (use Cover Slide Style axis).
- Slides 2..(N-1) = body (use Body Slide Rhythm axis).
- Slide N = CTA.
- **Apply tension curve (Axis 5) to assign each body slide a narrative
beat**: e.g. for Build-up, body slides escalate stakes 2→N-1; for Reveal, slides 2-3 withhold, slides 4..(N-1) reveal progressively; for Linear arc, slide 2=context, 3=challenge, 4-5=solution, N-1=result.
- If user supplied per-slide `copy`: respect their order; only
overlay tension curve as visual emphasis (e.g. slide N-1 gets larger headline, more saturated color — the "payoff slide").
- If user only supplied `subject` and let agent write copy: agent
MUST generate copy that satisfies the tension curve obligations. Sanity-check: does slide N-1 feel like the payoff? Does slide 1 hook toward it? 3. Fan out ALL slides in parallel as independent `action=generate` calls — produce N SEPARATE PNG files, never a single composite image. Same logic as every other template, just N calls instead of 1. DO NOT generate a single image with N panels arranged inside it (comic-strip / grid style). Each slide is a standalone full-resolution PNG that the user uploads as one slide of the swipe sequence on LinkedIn / Instagram / X. If you produce one composite image, that's wrong — the user can't break it apart, and the platform won't paginate it as a carousel:
- Build per-slide prompt = shared design-system prefix + `THIS SLIDE:
slide N of n_slides, role: <cover|body-N|cta>, subject: <jobspec.slides[N].subject>, copy: "<verbatim>"`.
- Every slide:
action=generate,n=1, quality at user's level
(default high). No `action=edit` chain. Reason: editing slide 1 repeatedly can trap gpt-image-2 in "webpage layout" mode and make slides look CSS-rendered rather than gpt-image-2-generated. Each slide must be a standalone generation, exactly like ad-creative or logo.
- Cross-slide visual consistency comes from the shared prompt prefix
(brand palette / typography / Visual Continuity Mechanism axis pick), NOT from image-reference chains. Trust the prefix.
- Fire all N calls in parallel — wall-clock = ~1 image_generation call.
- If a body slide drifts off-brand vs siblings, fix by reinforcing the
shared prefix for that slide (more specific palette / typography directives), not by switching to action=edit. 4. Save each slide to candidates/slide-{N}.png (not 1.png / 2.png — slide-numbered for clarity). 5. manifest.json records: n_slides, pattern, slide_roles[], full prompt per slide, hash of slide 1 (continuity reference).
Step 5 — Save outputs. Default location: $HOME/.30x-image/profiles/<brand-slug>/marketing/<job-id>/ Files:
candidates/{1..n}.png(each candidate)manifest.json(see structure below)
If profile dir does not exist (running from examples/), default to ./marketing/<job-id>/ in cwd.
Step 6 — Write manifest.json.
{
"job_id": "ISO-timestamp_short-slug",
"design_md_path": "...",
"design_md_hash": "sha256:...",
"template": "ad-creative",
"jobspec": { ... },
"axes_picks": {
"Hero Composition": "Asymmetric Split",
"Subject Framing": "Medium environmental",
"Lighting Mood": "Soft natural daylight",
"Text-Image Integration": "Tagline overlaid bottom-left"
},
"tool_params": { "size": "1024x1536", "quality": "high", "n": 4 },
"prompt_full": "...",
"outputs": [
{ "path": "candidates/1.png", "selected": false },
{ "path": "candidates/2.png", "selected": false },
...
],
"created_at": "..."
}Step 7 — Report to user. Tell them:
- Where the candidates are
- Which axis picks were committed (transparency)
- Optional: suggest "select one and run again with action=edit, quality=high"
for the final pass.
- Optional: remind that surgical edits are available — "if any candidate is
90% there but has one detail to fix (typo / wrong color / artifact), use edit mode (Mode 3) to fix just that part and keep everything else."
---
When user invokes edit (Mode 3 — surgical region edit)
Inputs
- `input_image`: required. Path to the PNG you want to edit (typically
from a previous Mode 2 run, e.g. candidates/2.png or slide-3.png).
- What to change (one of four ways — pick the most natural for the user):
1. Natural-language region — region: "the headline at the top" / "the CTA button" / "the bottom-right corner". Agent uses vision to locate and generate a mask programmatically. Most natural UX. 2. Normalized bbox — region_box: [x1, y1, x2, y2] in 0.0-1.0 coordinates (top-left origin). Agent generates a rectangular mask. Use when user gives precise coords or "the top 20%" type framing. 3. User-supplied mask — mask: ./my-mask.png. Same dimensions as input_image, transparent (alpha=0) where to edit, opaque where to preserve. For users who painted in Photoshop / Preview / Figma. 4. Global edit (no mask) — global_prompt: "make it black and white". No mask, prompt-only. ⚠️ Risk: gpt-image-2 may regenerate the whole image, drifting from the original. Only use for true global changes (color grade, time-of-day, weather). Warn user before proceeding.
- `prompt`: what should appear in the masked region (or the global
change for global mode). Be specific — e.g. "change tagline to 'Stop fraud before it starts.' in the same font and weight" not "fix the text".
- `output_path`: optional. Default: alongside the input as
<input-name>-edited-<timestamp>.png.
Procedure (do these in order)
Step 1 — Load and validate input_image.
- Confirm file exists, is a PNG, is gpt-image-2-readable.
- Read its dimensions (W × H) — needed for mask sizing.
Step 2 — Resolve the region into a mask PNG.
| Region type | How to produce mask |
|---|---|
Natural-language (region: "...") | Pass input_image through Codex's vision capability. Identify the pixel bounding box of the described element. Generate a same-dimension PNG: target region transparent (alpha=0, RGBA 0,0,0,0), rest opaque (alpha=255). Use Python+PIL via shell, e.g. python -c "from PIL import Image, ImageDraw; ...". |
Normalized bbox (region_box: [x1,y1,x2,y2]) | Multiply by W,H to get pixel rect. Generate mask PNG with that rect transparent, rest opaque. |
User mask (mask: path) | Verify dimensions match input_image. If mismatch, resize or error with clear message. |
Global (global_prompt) | No mask. Skip to Step 3. |
Save the mask to a temp file (e.g. /tmp/30x-image-mask-<job-id>.png).
Step 3 — Upload input_image (and mask, if any) as files.
from openai import OpenAI
client = OpenAI()
def create_file(path):
with open(path, "rb") as f:
return client.files.create(file=f, purpose="vision").id
input_file_id = create_file(input_image)
mask_file_id = create_file(mask_path) if mask_path else NoneStep 4 — Invoke `image_generation` tool with `input_image_mask`.
For region/bbox/mask edits (Steps 2.1, 2.2, 2.3):
response = client.responses.create(
model="gpt-5.5",
input=[{
"role": "user",
"content": [
{"type": "input_text", "text": prompt_with_brand_context},
{"type": "input_image", "file_id": input_file_id}
],
}],
tools=[{
"type": "image_generation",
"quality": "high",
"input_image_mask": {"file_id": mask_file_id}
}],
)For global edits (Step 2.4 — no mask):
# Same call, but omit input_image_mask. Warn user about regeneration risk.Prompt assembly — wrap the user's edit prompt with brand context to prevent off-brand drift in the edited region. Pull from the original manifest.json (or DESIGN.md if available):
Edit ONLY the masked region of this image. Preserve everything outside
the mask exactly.
EDIT INSTRUCTION:
{user's edit prompt}
BRAND CONTEXT (the edited region must remain on-brand):
- Palette: {colors.primary}, {colors.surface}, {colors.on-surface} — do not
introduce new colors
- Typography: {typography.headline-display.fontFamily} weight {fontWeight}
- Anti-slop: same banned list as original generation (no AI yellow-tint, no
pure black, no Inter font, etc.)
Do not regenerate the whole image. Do not alter pixels outside the mask.Step 5 — Save and report.
- Save output PNG to
output_path. - Append to a Mode-3 manifest entry:
{
"edit_id": "ISO-timestamp",
"input_image": "...",
"input_image_hash": "sha256:...",
"region_type": "natural-language" | "bbox" | "user-mask" | "global",
"region_value": "the headline at the top",
"mask_path": "/tmp/30x-image-mask-...png",
"mask_hash": "sha256:...",
"edit_prompt": "...",
"output_path": "...",
"created_at": "..."
}- Tell user: where the edited PNG is, what region was masked (transparency),
and a side-by-side diff suggestion ("compare to the original at <input_path>").
Important limitations (from gpt-image-2 documented behavior)
1. Iterative-edit "stubbornness" — editing the same image more than 2-3 times in succession causes the model to stop making meaningful changes. Workaround: if a third edit doesn't take, regenerate the image fresh from Mode 2 with the desired change baked into the prompt. 2. Mask is guidance, not law — gpt-image-2 uses the mask as guidance but may not follow its exact shape with complete precision. Edges can bleed slightly into preserved areas. For pixel-perfect preservation needs, consider compositing in a separate image editor. 3. Self-correction hallucination — if the user asks to edit something that doesn't actually exist in the image (e.g. "remove the QR code" when there is no QR code), the model may hallucinate the missing element AND then "fix" it. Vision-validate the region exists before masking. 4. Global edits without mask drift — using global_prompt (no mask) risks the model regenerating the whole image. For true preservation, always provide a mask, even if the mask is the entire image except one tiny corner.
---
Quality bars (M0 acceptance)
A generated image is on-brand if: 1. Primary color from frontmatter is visibly dominant (CTA / accent) 2. Typography style matches ## 3. Typography Rules (e.g., Stripe = light weight 300, NOT bold) 3. No item from anti-slop banned list violated 4. Mood / density / variance match the taste: block
If hand-judging gives any "no" — iterate (re-pick axes / strengthen constraints / explicit anti-slop in prompt).
---
When you DON'T have enough
Refuse / clarify gracefully:
- DESIGN.md missing → 3-step fallback (try in order, tell the user which
one you're taking): 1. `npx getdesign list` — check if the brand is in the public awesome-design-md library (60+ brands: Stripe / Linear / Notion / Vercel / Apple / Tesla / Nike / Spotify / Starbucks / Apple / Coinbase / etc.). If yes → 2. `npx getdesign add <brand>` — pulls a ready DESIGN.md to cwd in one command. Use it directly; optionally augment with a taste: block (5-7 numeric brand parameters) for axis biasing. 3. Brand not in library → run init mode (M2) or hand-write a DESIGN.md using the 9-section format + frontmatter token block + taste: block (see examples/awesome-vendor/stripe/DESIGN.md as the canonical reference).
- Template name wrong → list 8 valid templates (incl. carousel)
- User brief doesn't match any template after honest attempt to classify →
enter free-form fallback (NOT refuse). Tell user "no template matched, using free-form with brand DESIGN.md + anti-slop only" so they know determinism is reduced this run.
- Jobspec missing required fields (subject) → ask before invoking tool
- Brand
## 7 Don'tis empty/weak → fall back to generic
references/anti-slop-rules.md
---
Composition example — Stripe ad-creative
DESIGN.md: examples/awesome-vendor/stripe/DESIGN.md
Template: ad-creative
Jobspec:
subject: "Q2 product launch — new fraud detection feature"
copy:
tagline: "Stop fraud before it starts."
cta: "Try it free"
size: 1024x1536
quality: high
n: 4
Axis picks (committed by 30x-image based on taste.variance=4, realism=7):
Hero Composition: Editorial Offset (variance=4 prefers low-mid)
Subject Framing: Medium environmental
Lighting Mood: Soft natural daylight (realism=7 sweet spot)
Text-Image Integration: Tagline overlaid bottom-left
→ image_generation tool invoked → 4 candidates saved
→ manifest.json records hash of DESIGN.md + axis picks + full promptinterface:
display_name: "30x Image — Brand Marketing Imagery"
short_description: "On-brand marketing images via DESIGN.md + Codex built-in image_generation. Zero OpenAI API key required."
brand_color: "#635BFF"
default_prompt: "Read DESIGN.md, pick a marketing template, generate on-brand image(s)."
policy:
# Allow Codex to auto-trigger when description matches; user can disable
allow_implicit_invocation: true
dependencies:
tools:
- type: "builtin"
value: "image_generation"
description: "Codex built-in gpt-image-2 access — no API key, calls billed via Codex subscription."
# Optional: external CLI dependencies (informational, used by init/generate flows)
external_cli:
- name: "@google/design.md"
purpose: "Lint, diff, export DESIGN.md (npx @google/design.md ...)"
install: "no install — use npx"
- name: "getdesign"
purpose: "Pull pre-made DESIGN.md for popular brands (npx getdesign add <brand>)"
install: "no install — use npx"
Design System Inspired by Stripe
1. Visual Theme & Atmosphere
Stripe's website is the gold standard of fintech design -- a system that manages to feel simultaneously technical and luxurious, precise and warm. The page opens on a clean white canvas (#ffffff) with deep navy headings (#061b31) and a signature purple (#533afd) that functions as both brand anchor and interactive accent. This isn't the cold, clinical purple of enterprise software; it's a rich, saturated violet that reads as confident and premium. The overall impression is of a financial institution redesigned by a world-class type foundry.
The custom sohne-var variable font is the defining element of Stripe's visual identity. Every text element enables the OpenType "ss01" stylistic set, which modifies character shapes for a distinctly geometric, modern feel. At display sizes (48px-56px), sohne-var runs at weight 300 -- an extraordinarily light weight for headlines that creates an ethereal, almost whispered authority. This is the opposite of the "bold hero headline" convention; Stripe's headlines feel like they don't need to shout. The negative letter-spacing (-1.4px at 56px, -0.96px at 48px) tightens the text into dense, engineered blocks. At smaller sizes, the system also uses weight 300 with proportionally reduced tracking, and tabular numerals via "tnum" for financial data display.
What truly distinguishes Stripe is its shadow system. Rather than the flat or single-layer approach of most sites, Stripe uses multi-layer, blue-tinted shadows: the signature rgba(50,50,93,0.25) combined with rgba(0,0,0,0.1) creates shadows with a cool, almost atmospheric depth -- like elements are floating in a twilight sky. The blue-gray undertone of the primary shadow color (50,50,93) ties directly to the navy-purple brand palette, making even elevation feel on-brand.
Key Characteristics:
- sohne-var with OpenType
"ss01"on all text -- a custom stylistic set that defines the brand's letterforms - Weight 300 as the signature headline weight -- light, confident, anti-convention
- Negative letter-spacing at display sizes (-1.4px at 56px, progressive relaxation downward)
- Blue-tinted multi-layer shadows using
rgba(50,50,93,0.25)-- elevation that feels brand-colored - Deep navy (
#061b31) headings instead of black -- warm, premium, financial-grade - Conservative border-radius (4px-8px) -- nothing pill-shaped, nothing harsh
- Ruby (
#ea2261) and magenta (#f96bee) accents for gradient and decorative elements SourceCodeProas the monospace companion for code and technical labels
2. Color Palette & Roles
Primary
- Stripe Purple (
#533afd): Primary brand color, CTA backgrounds, link text, interactive highlights. A saturated blue-violet that anchors the entire system. - Deep Navy (
#061b31):--hds-color-heading-solid. Primary heading color. Not black, not gray -- a very dark blue that adds warmth and depth to text. - Pure White (
#ffffff): Page background, card surfaces, button text on dark backgrounds.
Brand & Dark
- Brand Dark (
#1c1e54):--hds-color-util-brand-900. Deep indigo for dark sections, footer backgrounds, and immersive brand moments. - Dark Navy (
#0d253d):--hds-color-core-neutral-975. The darkest neutral -- almost-black with a blue undertone for maximum depth without harshness.
Accent Colors
- Ruby (
#ea2261):--hds-color-accentColorMode-ruby-icon-solid. Warm red-pink for icons, alerts, and accent elements. - Magenta (
#f96bee):--hds-color-accentColorMode-magenta-icon-gradientMiddle. Vivid pink-purple for gradients and decorative highlights. - Magenta Light (
#ffd7ef):--hds-color-util-accent-magenta-100. Tinted surface for magenta-themed cards and badges.
Interactive
- Primary Purple (
#533afd): Primary link color, active states, selected elements. - Purple Hover (
#4434d4): Darker purple for hover states on primary elements. - Purple Deep (
#2e2b8c):--hds-color-button-ui-iconHover. Dark purple for icon hover states. - Purple Light (
#b9b9f9):--hds-color-action-bg-subduedHover. Soft lavender for subdued hover backgrounds. - Purple Mid (
#665efd):--hds-color-input-selector-text-range. Range selector and input highlight color.
Neutral Scale
- Heading (
#061b31): Primary headings, nav text, strong labels. - Label (
#273951):--hds-color-input-text-label. Form labels, secondary headings. - Body (
#64748d): Secondary text, descriptions, captions. - Success Green (
#15be53): Status badges, success indicators (with 0.2-0.4 alpha for backgrounds/borders). - Success Text (
#108c3d): Success badge text color. - Lemon (
#9b6829):--hds-color-core-lemon-500. Warning and highlight accent.
Surface & Borders
- Border Default (
#e5edf5): Standard border color for cards, dividers, and containers. - Border Purple (
#b9b9f9): Active/selected state borders on buttons and inputs. - Border Soft Purple (
#d6d9fc): Subtle purple-tinted borders for secondary elements. - Border Magenta (
#ffd7ef): Pink-tinted borders for magenta-themed elements. - Border Dashed (
#362baa): Dashed borders for drop zones and placeholder elements.
Shadow Colors
- Shadow Blue (
rgba(50,50,93,0.25)): The signature -- blue-tinted primary shadow color. - Shadow Dark Blue (
rgba(3,3,39,0.25)): Deeper blue shadow for elevated elements. - Shadow Black (
rgba(0,0,0,0.1)): Secondary shadow layer for depth reinforcement. - Shadow Ambient (
rgba(23,23,23,0.08)): Soft ambient shadow for subtle elevation. - Shadow Soft (
rgba(23,23,23,0.06)): Minimal ambient shadow for light lift.
3. Typography Rules
Font Family
- Primary:
sohne-var, with fallback:SF Pro Display - Monospace:
SourceCodePro, with fallback:SFMono-Regular - OpenType Features:
"ss01"enabled globally on all sohne-var text;"tnum"for tabular numbers on financial data and captions.
Hierarchy
| Role | Font | Size | Weight | Line Height | Letter Spacing | Features | Notes |
|---|---|---|---|---|---|---|---|
| Display Hero | sohne-var | 56px (3.50rem) | 300 | 1.03 (tight) | -1.4px | ss01 | Maximum size, whisper-weight authority |
| Display Large | sohne-var | 48px (3.00rem) | 300 | 1.15 (tight) | -0.96px | ss01 | Secondary hero headlines |
| Section Heading | sohne-var | 32px (2.00rem) | 300 | 1.10 (tight) | -0.64px | ss01 | Feature section titles |
| Sub-heading Large | sohne-var | 26px (1.63rem) | 300 | 1.12 (tight) | -0.26px | ss01 | Card headings, sub-sections |
| Sub-heading | sohne-var | 22px (1.38rem) | 300 | 1.10 (tight) | -0.22px | ss01 | Smaller section heads |
| Body Large | sohne-var | 18px (1.13rem) | 300 | 1.40 | normal | ss01 | Feature descriptions, intro text |
| Body | sohne-var | 16px (1.00rem) | 300-400 | 1.40 | normal | ss01 | Standard reading text |
| Button | sohne-var | 16px (1.00rem) | 400 | 1.00 (tight) | normal | ss01 | Primary button text |
| Button Small | sohne-var | 14px (0.88rem) | 400 | 1.00 (tight) | normal | ss01 | Secondary/compact buttons |
| Link | sohne-var | 14px (0.88rem) | 400 | 1.00 (tight) | normal | ss01 | Navigation links |
| Caption | sohne-var | 13px (0.81rem) | 400 | normal | normal | ss01 | Small labels, metadata |
| Caption Small | sohne-var | 12px (0.75rem) | 300-400 | 1.33-1.45 | normal | ss01 | Fine print, timestamps |
| Caption Tabular | sohne-var | 12px (0.75rem) | 300-400 | 1.33 | -0.36px | tnum | Financial data, numbers |
| Micro | sohne-var | 10px (0.63rem) | 300 | 1.15 (tight) | 0.1px | ss01 | Tiny labels, axis markers |
| Micro Tabular | sohne-var | 10px (0.63rem) | 300 | 1.15 (tight) | -0.3px | tnum | Chart data, small numbers |
| Nano | sohne-var | 8px (0.50rem) | 300 | 1.07 (tight) | normal | ss01 | Smallest labels |
| Code Body | SourceCodePro | 12px (0.75rem) | 500 | 2.00 (relaxed) | normal | -- | Code blocks, syntax |
| Code Bold | SourceCodePro | 12px (0.75rem) | 700 | 2.00 (relaxed) | normal | -- | Bold code, keywords |
| Code Label | SourceCodePro | 12px (0.75rem) | 500 | 2.00 (relaxed) | normal | uppercase | Technical labels |
| Code Micro | SourceCodePro | 9px (0.56rem) | 500 | 1.00 (tight) | normal | ss01 | Tiny code annotations |
Principles
- Light weight as signature: Weight 300 at display sizes is Stripe's most distinctive typographic choice. Where others use 600-700 to command attention, Stripe uses lightness as luxury -- the text is so confident it doesn't need weight to be authoritative.
- ss01 everywhere: The
"ss01"stylistic set is non-negotiable. It modifies specific glyphs (likely alternatea,g,lforms) to create a more geometric, contemporary feel across all sohne-var text. - Two OpenType modes:
"ss01"for display/body text,"tnum"for tabular numerals in financial data. These never overlap -- a number in a paragraph uses ss01, a number in a data table uses tnum. - Progressive tracking: Letter-spacing tightens proportionally with size: -1.4px at 56px, -0.96px at 48px, -0.64px at 32px, -0.26px at 26px, normal at 16px and below.
- Two-weight simplicity: Primarily 300 (body and headings) and 400 (UI/buttons). No bold (700) in the primary font -- SourceCodePro uses 500/700 for code contrast.
4. Component Stylings
Buttons
Primary Purple
- Background:
#533afd - Text:
#ffffff - Padding: 8px 16px
- Radius: 4px
- Font: 16px sohne-var weight 400,
"ss01" - Hover:
#4434d4background - Use: Primary CTA ("Start now", "Contact sales")
Ghost / Outlined
- Background: transparent
- Text:
#533afd - Padding: 8px 16px
- Radius: 4px
- Border:
1px solid #b9b9f9 - Font: 16px sohne-var weight 400,
"ss01" - Hover: background shifts to
rgba(83,58,253,0.05) - Use: Secondary actions
Transparent Info
- Background: transparent
- Text:
#2874ad - Padding: 8px 16px
- Radius: 4px
- Border:
1px solid rgba(43,145,223,0.2) - Use: Tertiary/info-level actions
Neutral Ghost
- Background: transparent (
rgba(255,255,255,0)) - Text:
rgba(16,16,16,0.3) - Padding: 8px 16px
- Radius: 4px
- Outline:
1px solid rgb(212,222,233) - Use: Disabled or muted actions
Cards & Containers
- Background:
#ffffff - Border:
1px solid #e5edf5(standard) or1px solid #061b31(dark accent) - Radius: 4px (tight), 5px (standard), 6px (comfortable), 8px (featured)
- Shadow (standard):
rgba(50,50,93,0.25) 0px 30px 45px -30px, rgba(0,0,0,0.1) 0px 18px 36px -18px - Shadow (ambient):
rgba(23,23,23,0.08) 0px 15px 35px 0px - Hover: shadow intensifies, often adding the blue-tinted layer
Badges / Tags / Pills
Neutral Pill
- Background:
#ffffff - Text:
#000000 - Padding: 0px 6px
- Radius: 4px
- Border:
1px solid #f6f9fc - Font: 11px weight 400
Success Badge
- Background:
rgba(21,190,83,0.2) - Text:
#108c3d - Padding: 1px 6px
- Radius: 4px
- Border:
1px solid rgba(21,190,83,0.4) - Font: 10px weight 300
Inputs & Forms
- Border:
1px solid #e5edf5 - Radius: 4px
- Focus:
1px solid #533afdor purple ring - Label:
#273951, 14px sohne-var - Text:
#061b31 - Placeholder:
#64748d
Navigation
- Clean horizontal nav on white, sticky with blur backdrop
- Brand logotype left-aligned
- Links: sohne-var 14px weight 400,
#061b31text with"ss01" - Radius: 6px on nav container
- CTA: purple button right-aligned ("Sign in", "Start now")
- Mobile: hamburger toggle with 6px radius
Decorative Elements
Dashed Borders
1px dashed #362baa(purple) for placeholder/drop zones1px dashed #ffd7ef(magenta) for magenta-themed decorative borders
Gradient Accents
- Ruby-to-magenta gradients (
#ea2261to#f96bee) for hero decorations - Brand dark sections use
#1c1e54backgrounds with white text
5. Layout Principles
Spacing System
- Base unit: 8px
- Scale: 1px, 2px, 4px, 6px, 8px, 10px, 11px, 12px, 14px, 16px, 18px, 20px
- Notable: The scale is dense at the small end (every 2px from 4-12), reflecting Stripe's precision-oriented UI for financial data
Grid & Container
- Max content width: approximately 1080px
- Hero: centered single-column with generous padding, lightweight headlines
- Feature sections: 2-3 column grids for feature cards
- Full-width dark sections with
#1c1e54background for brand immersion - Code/dashboard previews as contained cards with blue-tinted shadows
Whitespace Philosophy
- Precision spacing: Unlike the vast emptiness of minimalist systems, Stripe uses measured, purposeful whitespace. Every gap is a deliberate typographic choice.
- Dense data, generous chrome: Financial data displays (tables, charts) are tightly packed, but the UI chrome around them is generously spaced. This creates a sense of controlled density -- like a well-organized spreadsheet in a beautiful frame.
- Section rhythm: White sections alternate with dark brand sections (
#1c1e54), creating a dramatic light/dark cadence that prevents monotony without introducing arbitrary color.
Border Radius Scale
- Micro (1px): Fine-grained elements, subtle rounding
- Standard (4px): Buttons, inputs, badges, cards -- the workhorse
- Comfortable (5px): Standard card containers
- Relaxed (6px): Navigation, larger interactive elements
- Large (8px): Featured cards, hero elements
- Compound:
0px 0px 6px 6pxfor bottom-rounded containers (tab panels, dropdown footers)
6. Depth & Elevation
| Level | Treatment | Use |
|---|---|---|
| Flat (Level 0) | No shadow | Page background, inline text |
| Ambient (Level 1) | rgba(23,23,23,0.06) 0px 3px 6px | Subtle card lift, hover hints |
| Standard (Level 2) | rgba(23,23,23,0.08) 0px 15px 35px | Standard cards, content panels |
| Elevated (Level 3) | rgba(50,50,93,0.25) 0px 30px 45px -30px, rgba(0,0,0,0.1) 0px 18px 36px -18px | Featured cards, dropdowns, popovers |
| Deep (Level 4) | rgba(3,3,39,0.25) 0px 14px 21px -14px, rgba(0,0,0,0.1) 0px 8px 17px -8px | Modals, floating panels |
| Ring (Accessibility) | 2px solid #533afd outline | Keyboard focus ring |
Shadow Philosophy: Stripe's shadow system is built on a principle of chromatic depth. Where most design systems use neutral gray or black shadows, Stripe's primary shadow color (rgba(50,50,93,0.25)) is a deep blue-gray that echoes the brand's navy palette. This creates shadows that don't just add depth -- they add brand atmosphere. The multi-layer approach pairs this blue-tinted shadow with a pure black secondary layer (rgba(0,0,0,0.1)) at a different offset, creating a parallax-like depth where the branded shadow sits farther from the element and the neutral shadow sits closer. The negative spread values (-30px, -18px) ensure shadows don't extend beyond the element's footprint horizontally, keeping elevation vertical and controlled.
Decorative Depth
- Dark brand sections (
#1c1e54) create immersive depth through background color contrast - Gradient overlays with ruby-to-magenta transitions for hero decorations
- Shadow color
rgba(0,55,112,0.08)(--hds-color-shadow-sm-top) for top-edge shadows on sticky elements
7. Do's and Don'ts
Do
- Use sohne-var with
"ss01"on every text element -- the stylistic set IS the brand - Use weight 300 for all headlines and body text -- lightness is the signature
- Apply blue-tinted shadows (
rgba(50,50,93,0.25)) for all elevated elements - Use
#061b31(deep navy) for headings instead of#000000-- the warmth matters - Keep border-radius between 4px-8px -- conservative rounding is intentional
- Use
"tnum"for any tabular/financial number display - Layer shadows: blue-tinted far + neutral close for depth parallax
- Use
#533afdpurple as the primary interactive/CTA color
Don't
- Don't use weight 600-700 for sohne-var headlines -- weight 300 is the brand voice
- Don't use large border-radius (12px+, pill shapes) on cards or buttons -- Stripe is conservative
- Don't use neutral gray shadows -- always tint with blue (
rgba(50,50,93,...)) - Don't skip
"ss01"on any sohne-var text -- the alternate glyphs define the personality - Don't use pure black (
#000000) for headings -- always#061b31deep navy - Don't use warm accent colors (orange, yellow) for interactive elements -- purple is primary
- Don't apply positive letter-spacing at display sizes -- Stripe tracks tight
- Don't use the magenta/ruby accents for buttons or links -- they're decorative/gradient only
8. Responsive Behavior
Breakpoints
| Name | Width | Key Changes |
|---|---|---|
| Mobile | <640px | Single column, reduced heading sizes, stacked cards |
| Tablet | 640-1024px | 2-column grids, moderate padding |
| Desktop | 1024-1280px | Full layout, 3-column feature grids |
| Large Desktop | >1280px | Centered content with generous margins |
Touch Targets
- Buttons use comfortable padding (8px-16px vertical)
- Navigation links at 14px with adequate spacing
- Badges have 6px horizontal padding minimum for tap targets
- Mobile nav toggle with 6px radius button
Collapsing Strategy
- Hero: 56px display -> 32px on mobile, weight 300 maintained
- Navigation: horizontal links + CTAs -> hamburger toggle
- Feature cards: 3-column -> 2-column -> single column stacked
- Dark brand sections: maintain full-width treatment, reduce internal padding
- Financial data tables: horizontal scroll on mobile
- Section spacing: 64px+ -> 40px on mobile
- Typography scale compresses: 56px -> 48px -> 32px hero sizes across breakpoints
Image Behavior
- Dashboard/product screenshots maintain blue-tinted shadow at all sizes
- Hero gradient decorations simplify on mobile
- Code blocks maintain
SourceCodeProtreatment, may horizontally scroll - Card images maintain consistent 4px-6px border-radius
9. Agent Prompt Guide
Quick Color Reference
- Primary CTA: Stripe Purple (
#533afd) - CTA Hover: Purple Dark (
#4434d4) - Background: Pure White (
#ffffff) - Heading text: Deep Navy (
#061b31) - Body text: Slate (
#64748d) - Label text: Dark Slate (
#273951) - Border: Soft Blue (
#e5edf5) - Link: Stripe Purple (
#533afd) - Dark section: Brand Dark (
#1c1e54) - Success: Green (
#15be53) - Accent decorative: Ruby (
#ea2261), Magenta (#f96bee)
Example Component Prompts
- "Create a hero section on white background. Headline at 48px sohne-var weight 300, line-height 1.15, letter-spacing -0.96px, color #061b31, font-feature-settings 'ss01'. Subtitle at 18px weight 300, line-height 1.40, color #64748d. Purple CTA button (#533afd, 4px radius, 8px 16px padding, white text) and ghost button (transparent, 1px solid #b9b9f9, #533afd text, 4px radius)."
- "Design a card: white background, 1px solid #e5edf5 border, 6px radius. Shadow: rgba(50,50,93,0.25) 0px 30px 45px -30px, rgba(0,0,0,0.1) 0px 18px 36px -18px. Title at 22px sohne-var weight 300, letter-spacing -0.22px, color #061b31, 'ss01'. Body at 16px weight 300, #64748d."
- "Build a success badge: rgba(21,190,83,0.2) background, #108c3d text, 4px radius, 1px 6px padding, 10px sohne-var weight 300, border 1px solid rgba(21,190,83,0.4)."
- "Create navigation: white sticky header with backdrop-filter blur(12px). sohne-var 14px weight 400 for links, #061b31 text, 'ss01'. Purple CTA 'Start now' right-aligned (#533afd bg, white text, 4px radius). Nav container 6px radius."
- "Design a dark brand section: #1c1e54 background, white text. Headline 32px sohne-var weight 300, letter-spacing -0.64px, 'ss01'. Body 16px weight 300, rgba(255,255,255,0.7). Cards inside use rgba(255,255,255,0.1) border with 6px radius."
Iteration Guide
1. Always enable font-feature-settings: "ss01" on sohne-var text -- this is the brand's typographic DNA 2. Weight 300 is the default; use 400 only for buttons/links/navigation 3. Shadow formula: rgba(50,50,93,0.25) 0px Y1 B1 -S1, rgba(0,0,0,0.1) 0px Y2 B2 -S2 where Y1/B1 are larger (far shadow) and Y2/B2 are smaller (near shadow) 4. Heading color is #061b31 (deep navy), body is #64748d (slate), labels are #273951 (dark slate) 5. Border-radius stays in the 4px-8px range -- never use pill shapes or large rounding 6. Use "tnum" for any numbers in tables, charts, or financial displays 7. Dark sections use #1c1e54 -- not black, not gray, but a deep branded indigo 8. SourceCodePro for code at 12px/500 with 2.00 line-height (very generous for readability)
Design System Inspired by Stripe
1. Visual Theme & Atmosphere
Stripe's website is the gold standard of fintech design -- a system that manages to feel simultaneously technical and luxurious, precise and warm. The page opens on a clean white canvas (#ffffff) with deep navy headings (#061b31) and a signature purple (#533afd) that functions as both brand anchor and interactive accent. This isn't the cold, clinical purple of enterprise software; it's a rich, saturated violet that reads as confident and premium. The overall impression is of a financial institution redesigned by a world-class type foundry.
The custom sohne-var variable font is the defining element of Stripe's visual identity. Every text element enables the OpenType "ss01" stylistic set, which modifies character shapes for a distinctly geometric, modern feel. At display sizes (48px-56px), sohne-var runs at weight 300 -- an extraordinarily light weight for headlines that creates an ethereal, almost whispered authority. This is the opposite of the "bold hero headline" convention; Stripe's headlines feel like they don't need to shout. The negative letter-spacing (-1.4px at 56px, -0.96px at 48px) tightens the text into dense, engineered blocks. At smaller sizes, the system also uses weight 300 with proportionally reduced tracking, and tabular numerals via "tnum" for financial data display.
What truly distinguishes Stripe is its shadow system. Rather than the flat or single-layer approach of most sites, Stripe uses multi-layer, blue-tinted shadows: the signature rgba(50,50,93,0.25) combined with rgba(0,0,0,0.1) creates shadows with a cool, almost atmospheric depth -- like elements are floating in a twilight sky. The blue-gray undertone of the primary shadow color (50,50,93) ties directly to the navy-purple brand palette, making even elevation feel on-brand.
Key Characteristics:
- sohne-var with OpenType
"ss01"on all text -- a custom stylistic set that defines the brand's letterforms - Weight 300 as the signature headline weight -- light, confident, anti-convention
- Negative letter-spacing at display sizes (-1.4px at 56px, progressive relaxation downward)
- Blue-tinted multi-layer shadows using
rgba(50,50,93,0.25)-- elevation that feels brand-colored - Deep navy (
#061b31) headings instead of black -- warm, premium, financial-grade - Conservative border-radius (4px-8px) -- nothing pill-shaped, nothing harsh
- Ruby (
#ea2261) and magenta (#f96bee) accents for gradient and decorative elements SourceCodeProas the monospace companion for code and technical labels
2. Color Palette & Roles
Primary
- Stripe Purple (
#533afd): Primary brand color, CTA backgrounds, link text, interactive highlights. A saturated blue-violet that anchors the entire system. - Deep Navy (
#061b31):--hds-color-heading-solid. Primary heading color. Not black, not gray -- a very dark blue that adds warmth and depth to text. - Pure White (
#ffffff): Page background, card surfaces, button text on dark backgrounds.
Brand & Dark
- Brand Dark (
#1c1e54):--hds-color-util-brand-900. Deep indigo for dark sections, footer backgrounds, and immersive brand moments. - Dark Navy (
#0d253d):--hds-color-core-neutral-975. The darkest neutral -- almost-black with a blue undertone for maximum depth without harshness.
Accent Colors
- Ruby (
#ea2261):--hds-color-accentColorMode-ruby-icon-solid. Warm red-pink for icons, alerts, and accent elements. - Magenta (
#f96bee):--hds-color-accentColorMode-magenta-icon-gradientMiddle. Vivid pink-purple for gradients and decorative highlights. - Magenta Light (
#ffd7ef):--hds-color-util-accent-magenta-100. Tinted surface for magenta-themed cards and badges.
Interactive
- Primary Purple (
#533afd): Primary link color, active states, selected elements. - Purple Hover (
#4434d4): Darker purple for hover states on primary elements. - Purple Deep (
#2e2b8c):--hds-color-button-ui-iconHover. Dark purple for icon hover states. - Purple Light (
#b9b9f9):--hds-color-action-bg-subduedHover. Soft lavender for subdued hover backgrounds. - Purple Mid (
#665efd):--hds-color-input-selector-text-range. Range selector and input highlight color.
Neutral Scale
- Heading (
#061b31): Primary headings, nav text, strong labels. - Label (
#273951):--hds-color-input-text-label. Form labels, secondary headings. - Body (
#64748d): Secondary text, descriptions, captions. - Success Green (
#15be53): Status badges, success indicators (with 0.2-0.4 alpha for backgrounds/borders). - Success Text (
#108c3d): Success badge text color. - Lemon (
#9b6829):--hds-color-core-lemon-500. Warning and highlight accent.
Surface & Borders
- Border Default (
#e5edf5): Standard border color for cards, dividers, and containers. - Border Purple (
#b9b9f9): Active/selected state borders on buttons and inputs. - Border Soft Purple (
#d6d9fc): Subtle purple-tinted borders for secondary elements. - Border Magenta (
#ffd7ef): Pink-tinted borders for magenta-themed elements. - Border Dashed (
#362baa): Dashed borders for drop zones and placeholder elements.
Shadow Colors
- Shadow Blue (
rgba(50,50,93,0.25)): The signature -- blue-tinted primary shadow color. - Shadow Dark Blue (
rgba(3,3,39,0.25)): Deeper blue shadow for elevated elements. - Shadow Black (
rgba(0,0,0,0.1)): Secondary shadow layer for depth reinforcement. - Shadow Ambient (
rgba(23,23,23,0.08)): Soft ambient shadow for subtle elevation. - Shadow Soft (
rgba(23,23,23,0.06)): Minimal ambient shadow for light lift.
3. Typography Rules
Font Family
- Primary:
sohne-var, with fallback:SF Pro Display - Monospace:
SourceCodePro, with fallback:SFMono-Regular - OpenType Features:
"ss01"enabled globally on all sohne-var text;"tnum"for tabular numbers on financial data and captions.
Hierarchy
| Role | Font | Size | Weight | Line Height | Letter Spacing | Features | Notes |
|---|---|---|---|---|---|---|---|
| Display Hero | sohne-var | 56px (3.50rem) | 300 | 1.03 (tight) | -1.4px | ss01 | Maximum size, whisper-weight authority |
| Display Large | sohne-var | 48px (3.00rem) | 300 | 1.15 (tight) | -0.96px | ss01 | Secondary hero headlines |
| Section Heading | sohne-var | 32px (2.00rem) | 300 | 1.10 (tight) | -0.64px | ss01 | Feature section titles |
| Sub-heading Large | sohne-var | 26px (1.63rem) | 300 | 1.12 (tight) | -0.26px | ss01 | Card headings, sub-sections |
| Sub-heading | sohne-var | 22px (1.38rem) | 300 | 1.10 (tight) | -0.22px | ss01 | Smaller section heads |
| Body Large | sohne-var | 18px (1.13rem) | 300 | 1.40 | normal | ss01 | Feature descriptions, intro text |
| Body | sohne-var | 16px (1.00rem) | 300-400 | 1.40 | normal | ss01 | Standard reading text |
| Button | sohne-var | 16px (1.00rem) | 400 | 1.00 (tight) | normal | ss01 | Primary button text |
| Button Small | sohne-var | 14px (0.88rem) | 400 | 1.00 (tight) | normal | ss01 | Secondary/compact buttons |
| Link | sohne-var | 14px (0.88rem) | 400 | 1.00 (tight) | normal | ss01 | Navigation links |
| Caption | sohne-var | 13px (0.81rem) | 400 | normal | normal | ss01 | Small labels, metadata |
| Caption Small | sohne-var | 12px (0.75rem) | 300-400 | 1.33-1.45 | normal | ss01 | Fine print, timestamps |
| Caption Tabular | sohne-var | 12px (0.75rem) | 300-400 | 1.33 | -0.36px | tnum | Financial data, numbers |
| Micro | sohne-var | 10px (0.63rem) | 300 | 1.15 (tight) | 0.1px | ss01 | Tiny labels, axis markers |
| Micro Tabular | sohne-var | 10px (0.63rem) | 300 | 1.15 (tight) | -0.3px | tnum | Chart data, small numbers |
| Nano | sohne-var | 8px (0.50rem) | 300 | 1.07 (tight) | normal | ss01 | Smallest labels |
| Code Body | SourceCodePro | 12px (0.75rem) | 500 | 2.00 (relaxed) | normal | -- | Code blocks, syntax |
| Code Bold | SourceCodePro | 12px (0.75rem) | 700 | 2.00 (relaxed) | normal | -- | Bold code, keywords |
| Code Label | SourceCodePro | 12px (0.75rem) | 500 | 2.00 (relaxed) | normal | uppercase | Technical labels |
| Code Micro | SourceCodePro | 9px (0.56rem) | 500 | 1.00 (tight) | normal | ss01 | Tiny code annotations |
Principles
- Light weight as signature: Weight 300 at display sizes is Stripe's most distinctive typographic choice. Where others use 600-700 to command attention, Stripe uses lightness as luxury -- the text is so confident it doesn't need weight to be authoritative.
- ss01 everywhere: The
"ss01"stylistic set is non-negotiable. It modifies specific glyphs (likely alternatea,g,lforms) to create a more geometric, contemporary feel across all sohne-var text. - Two OpenType modes:
"ss01"for display/body text,"tnum"for tabular numerals in financial data. These never overlap -- a number in a paragraph uses ss01, a number in a data table uses tnum. - Progressive tracking: Letter-spacing tightens proportionally with size: -1.4px at 56px, -0.96px at 48px, -0.64px at 32px, -0.26px at 26px, normal at 16px and below.
- Two-weight simplicity: Primarily 300 (body and headings) and 400 (UI/buttons). No bold (700) in the primary font -- SourceCodePro uses 500/700 for code contrast.
4. Component Stylings
Buttons
Primary Purple
- Background:
#533afd - Text:
#ffffff - Padding: 8px 16px
- Radius: 4px
- Font: 16px sohne-var weight 400,
"ss01" - Hover:
#4434d4background - Use: Primary CTA ("Start now", "Contact sales")
Ghost / Outlined
- Background: transparent
- Text:
#533afd - Padding: 8px 16px
- Radius: 4px
- Border:
1px solid #b9b9f9 - Font: 16px sohne-var weight 400,
"ss01" - Hover: background shifts to
rgba(83,58,253,0.05) - Use: Secondary actions
Transparent Info
- Background: transparent
- Text:
#2874ad - Padding: 8px 16px
- Radius: 4px
- Border:
1px solid rgba(43,145,223,0.2) - Use: Tertiary/info-level actions
Neutral Ghost
- Background: transparent (
rgba(255,255,255,0)) - Text:
rgba(16,16,16,0.3) - Padding: 8px 16px
- Radius: 4px
- Outline:
1px solid rgb(212,222,233) - Use: Disabled or muted actions
Cards & Containers
- Background:
#ffffff - Border:
1px solid #e5edf5(standard) or1px solid #061b31(dark accent) - Radius: 4px (tight), 5px (standard), 6px (comfortable), 8px (featured)
- Shadow (standard):
rgba(50,50,93,0.25) 0px 30px 45px -30px, rgba(0,0,0,0.1) 0px 18px 36px -18px - Shadow (ambient):
rgba(23,23,23,0.08) 0px 15px 35px 0px - Hover: shadow intensifies, often adding the blue-tinted layer
Badges / Tags / Pills
Neutral Pill
- Background:
#ffffff - Text:
#000000 - Padding: 0px 6px
- Radius: 4px
- Border:
1px solid #f6f9fc - Font: 11px weight 400
Success Badge
- Background:
rgba(21,190,83,0.2) - Text:
#108c3d - Padding: 1px 6px
- Radius: 4px
- Border:
1px solid rgba(21,190,83,0.4) - Font: 10px weight 300
Inputs & Forms
- Border:
1px solid #e5edf5 - Radius: 4px
- Focus:
1px solid #533afdor purple ring - Label:
#273951, 14px sohne-var - Text:
#061b31 - Placeholder:
#64748d
Navigation
- Clean horizontal nav on white, sticky with blur backdrop
- Brand logotype left-aligned
- Links: sohne-var 14px weight 400,
#061b31text with"ss01" - Radius: 6px on nav container
- CTA: purple button right-aligned ("Sign in", "Start now")
- Mobile: hamburger toggle with 6px radius
Decorative Elements
Dashed Borders
1px dashed #362baa(purple) for placeholder/drop zones1px dashed #ffd7ef(magenta) for magenta-themed decorative borders
Gradient Accents
- Ruby-to-magenta gradients (
#ea2261to#f96bee) for hero decorations - Brand dark sections use
#1c1e54backgrounds with white text
5. Layout Principles
Spacing System
- Base unit: 8px
- Scale: 1px, 2px, 4px, 6px, 8px, 10px, 11px, 12px, 14px, 16px, 18px, 20px
- Notable: The scale is dense at the small end (every 2px from 4-12), reflecting Stripe's precision-oriented UI for financial data
Grid & Container
- Max content width: approximately 1080px
- Hero: centered single-column with generous padding, lightweight headlines
- Feature sections: 2-3 column grids for feature cards
- Full-width dark sections with
#1c1e54background for brand immersion - Code/dashboard previews as contained cards with blue-tinted shadows
Whitespace Philosophy
- Precision spacing: Unlike the vast emptiness of minimalist systems, Stripe uses measured, purposeful whitespace. Every gap is a deliberate typographic choice.
- Dense data, generous chrome: Financial data displays (tables, charts) are tightly packed, but the UI chrome around them is generously spaced. This creates a sense of controlled density -- like a well-organized spreadsheet in a beautiful frame.
- Section rhythm: White sections alternate with dark brand sections (
#1c1e54), creating a dramatic light/dark cadence that prevents monotony without introducing arbitrary color.
Border Radius Scale
- Micro (1px): Fine-grained elements, subtle rounding
- Standard (4px): Buttons, inputs, badges, cards -- the workhorse
- Comfortable (5px): Standard card containers
- Relaxed (6px): Navigation, larger interactive elements
- Large (8px): Featured cards, hero elements
- Compound:
0px 0px 6px 6pxfor bottom-rounded containers (tab panels, dropdown footers)
6. Depth & Elevation
| Level | Treatment | Use |
|---|---|---|
| Flat (Level 0) | No shadow | Page background, inline text |
| Ambient (Level 1) | rgba(23,23,23,0.06) 0px 3px 6px | Subtle card lift, hover hints |
| Standard (Level 2) | rgba(23,23,23,0.08) 0px 15px 35px | Standard cards, content panels |
| Elevated (Level 3) | rgba(50,50,93,0.25) 0px 30px 45px -30px, rgba(0,0,0,0.1) 0px 18px 36px -18px | Featured cards, dropdowns, popovers |
| Deep (Level 4) | rgba(3,3,39,0.25) 0px 14px 21px -14px, rgba(0,0,0,0.1) 0px 8px 17px -8px | Modals, floating panels |
| Ring (Accessibility) | 2px solid #533afd outline | Keyboard focus ring |
Shadow Philosophy: Stripe's shadow system is built on a principle of chromatic depth. Where most design systems use neutral gray or black shadows, Stripe's primary shadow color (rgba(50,50,93,0.25)) is a deep blue-gray that echoes the brand's navy palette. This creates shadows that don't just add depth -- they add brand atmosphere. The multi-layer approach pairs this blue-tinted shadow with a pure black secondary layer (rgba(0,0,0,0.1)) at a different offset, creating a parallax-like depth where the branded shadow sits farther from the element and the neutral shadow sits closer. The negative spread values (-30px, -18px) ensure shadows don't extend beyond the element's footprint horizontally, keeping elevation vertical and controlled.
Decorative Depth
- Dark brand sections (
#1c1e54) create immersive depth through background color contrast - Gradient overlays with ruby-to-magenta transitions for hero decorations
- Shadow color
rgba(0,55,112,0.08)(--hds-color-shadow-sm-top) for top-edge shadows on sticky elements
7. Do's and Don'ts
Do
- Use sohne-var with
"ss01"on every text element -- the stylistic set IS the brand - Use weight 300 for all headlines and body text -- lightness is the signature
- Apply blue-tinted shadows (
rgba(50,50,93,0.25)) for all elevated elements - Use
#061b31(deep navy) for headings instead of#000000-- the warmth matters - Keep border-radius between 4px-8px -- conservative rounding is intentional
- Use
"tnum"for any tabular/financial number display - Layer shadows: blue-tinted far + neutral close for depth parallax
- Use
#533afdpurple as the primary interactive/CTA color
Don't
- Don't use weight 600-700 for sohne-var headlines -- weight 300 is the brand voice
- Don't use large border-radius (12px+, pill shapes) on cards or buttons -- Stripe is conservative
- Don't use neutral gray shadows -- always tint with blue (
rgba(50,50,93,...)) - Don't skip
"ss01"on any sohne-var text -- the alternate glyphs define the personality - Don't use pure black (
#000000) for headings -- always#061b31deep navy - Don't use warm accent colors (orange, yellow) for interactive elements -- purple is primary
- Don't apply positive letter-spacing at display sizes -- Stripe tracks tight
- Don't use the magenta/ruby accents for buttons or links -- they're decorative/gradient only
8. Responsive Behavior
Breakpoints
| Name | Width | Key Changes |
|---|---|---|
| Mobile | <640px | Single column, reduced heading sizes, stacked cards |
| Tablet | 640-1024px | 2-column grids, moderate padding |
| Desktop | 1024-1280px | Full layout, 3-column feature grids |
| Large Desktop | >1280px | Centered content with generous margins |
Touch Targets
- Buttons use comfortable padding (8px-16px vertical)
- Navigation links at 14px with adequate spacing
- Badges have 6px horizontal padding minimum for tap targets
- Mobile nav toggle with 6px radius button
Collapsing Strategy
- Hero: 56px display -> 32px on mobile, weight 300 maintained
- Navigation: horizontal links + CTAs -> hamburger toggle
- Feature cards: 3-column -> 2-column -> single column stacked
- Dark brand sections: maintain full-width treatment, reduce internal padding
- Financial data tables: horizontal scroll on mobile
- Section spacing: 64px+ -> 40px on mobile
- Typography scale compresses: 56px -> 48px -> 32px hero sizes across breakpoints
Image Behavior
- Dashboard/product screenshots maintain blue-tinted shadow at all sizes
- Hero gradient decorations simplify on mobile
- Code blocks maintain
SourceCodeProtreatment, may horizontally scroll - Card images maintain consistent 4px-6px border-radius
9. Agent Prompt Guide
Quick Color Reference
- Primary CTA: Stripe Purple (
#533afd) - CTA Hover: Purple Dark (
#4434d4) - Background: Pure White (
#ffffff) - Heading text: Deep Navy (
#061b31) - Body text: Slate (
#64748d) - Label text: Dark Slate (
#273951) - Border: Soft Blue (
#e5edf5) - Link: Stripe Purple (
#533afd) - Dark section: Brand Dark (
#1c1e54) - Success: Green (
#15be53) - Accent decorative: Ruby (
#ea2261), Magenta (#f96bee)
Example Component Prompts
- "Create a hero section on white background. Headline at 48px sohne-var weight 300, line-height 1.15, letter-spacing -0.96px, color #061b31, font-feature-settings 'ss01'. Subtitle at 18px weight 300, line-height 1.40, color #64748d. Purple CTA button (#533afd, 4px radius, 8px 16px padding, white text) and ghost button (transparent, 1px solid #b9b9f9, #533afd text, 4px radius)."
- "Design a card: white background, 1px solid #e5edf5 border, 6px radius. Shadow: rgba(50,50,93,0.25) 0px 30px 45px -30px, rgba(0,0,0,0.1) 0px 18px 36px -18px. Title at 22px sohne-var weight 300, letter-spacing -0.22px, color #061b31, 'ss01'. Body at 16px weight 300, #64748d."
- "Build a success badge: rgba(21,190,83,0.2) background, #108c3d text, 4px radius, 1px 6px padding, 10px sohne-var weight 300, border 1px solid rgba(21,190,83,0.4)."
- "Create navigation: white sticky header with backdrop-filter blur(12px). sohne-var 14px weight 400 for links, #061b31 text, 'ss01'. Purple CTA 'Start now' right-aligned (#533afd bg, white text, 4px radius). Nav container 6px radius."
- "Design a dark brand section: #1c1e54 background, white text. Headline 32px sohne-var weight 300, letter-spacing -0.64px, 'ss01'. Body 16px weight 300, rgba(255,255,255,0.7). Cards inside use rgba(255,255,255,0.1) border with 6px radius."
Iteration Guide
1. Always enable font-feature-settings: "ss01" on sohne-var text -- this is the brand's typographic DNA 2. Weight 300 is the default; use 400 only for buttons/links/navigation 3. Shadow formula: rgba(50,50,93,0.25) 0px Y1 B1 -S1, rgba(0,0,0,0.1) 0px Y2 B2 -S2 where Y1/B1 are larger (far shadow) and Y2/B2 are smaller (near shadow) 4. Heading color is #061b31 (deep navy), body is #64748d (slate), labels are #273951 (dark slate) 5. Border-radius stays in the 4px-8px range -- never use pill shapes or large rounding 6. Use "tnum" for any numbers in tables, charts, or financial displays 7. Dark sections use #1c1e54 -- not black, not gray, but a deep branded indigo 8. SourceCodePro for code at 12px/500 with 2.00 line-height (very generous for readability)
For: 30x-image generate ad-creative
Tool params (defaults): size=1024x1536, quality=high, n=4, action=generate
Prompt skeleton (Codex assembles at runtime):
Polished Stripe-style marketing campaign image: "{jobspec.copy.tagline}".
VISUAL ATMOSPHERE:
{Section 1 essence — confident purple anchor, weight-300 elegance,
blue-tinted multi-layer depth, financial-grade premium}
PHOTOGRAPHY:
- Editorial style, slightly desaturated, warm cream/white surface
- Soft natural daylight, blue-tinted shadow on subjects
- Mood: confident, declarative (not aspirational, not loud)
COMPOSITION (commit one from each axis — see references/combinatorial-axes.md):
- Hero Composition: [pick 1 of 5, biased by taste.variance=4]
- Subject Framing: [pick 1 of 4]
- Lighting Mood: [pick 1 of 4, biased by taste.imagery_realism=7]
- Text-Image Integration: [pick 1 of 4]
PALETTE:
- Primary accent: Stripe Purple (#533afd) for any CTA/active element
- Surface: Pure white (#ffffff) or warm cream
- Headlines: Deep navy (#061b31), NOT pure black
- Body: Slate (#64748d)
- Decorative accent (sparingly): Ruby (#ea2261) or Magenta (#f96bee)
TYPOGRAPHY IN IMAGE:
- Headline: sohne-var weight 300, letter-spacing -0.96px to -1.4px on display sizes
- Always enable "ss01" stylistic set (signature glyph forms)
- Tagline placement determined by Text-Image Integration axis
CTA (only if jobspec.copy.cta is provided):
- Stripe Purple (#533afd) background, white text, 4-6px corner radius
- 8px×16px padding
- No glow, no neon, no harsh shadow
ANTI-SLOP CONSTRAINTS (强约束注入):
- ❌ NO AI yellow-tint cast
- ❌ NO purple/blue neon glow on CTAs (Stripe purple is matte, not luminous)
- ❌ NO Inter font (use sohne-var aesthetic)
- ❌ NO pure black #000000 — always deep navy #061b31
- ❌ NO fake round numbers (99.99% / 50% / 100x faster)
- ❌ NO generic stock-photo CFO/founder archetypes
- ❌ NO "Elevate / Unleash / Seamless / Next-Gen / Reimagine" copy
- ❌ NO pill-shaped buttons (Stripe stays in 4-8px corner radius range)
- ❌ NO gradient text on headlines (Stripe headlines are solid #061b31)
Output: 4 candidates exploring different axis combinations.For: 30x-image generate logo / slide / product-mockup / marketing-with-text / lighting-transform / scene-with-person
[M1: 待添加。当前 M0 仅落地 ad-creative,验证端到端可行后再扩展。]
{
"name": {
"$type": "string",
"$value": "Atmospheric Glass"
},
"colors": {
"surface": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.043,
0.075,
0.149
],
"hex": "#0b1326"
}
},
"surface-dim": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.043,
0.075,
0.149
],
"hex": "#0b1326"
}
},
"surface-bright": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.192,
0.224,
0.302
],
"hex": "#31394d"
}
},
"surface-container-lowest": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.024,
0.055,
0.125
],
"hex": "#060e20"
}
},
"surface-container-low": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.075,
0.106,
0.18
],
"hex": "#131b2e"
}
},
"surface-container": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.09,
0.122,
0.2
],
"hex": "#171f33"
}
},
"surface-container-high": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.133,
0.165,
0.239
],
"hex": "#222a3d"
}
},
"surface-container-highest": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.176,
0.204,
0.286
],
"hex": "#2d3449"
}
},
"on-surface": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.855,
0.886,
0.992
],
"hex": "#dae2fd"
}
},
"on-surface-variant": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.769,
0.78,
0.784
],
"hex": "#c4c7c8"
}
},
"inverse-surface": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.855,
0.886,
0.992
],
"hex": "#dae2fd"
}
},
"inverse-on-surface": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.157,
0.188,
0.267
],
"hex": "#283044"
}
},
"outline": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.557,
0.569,
0.573
],
"hex": "#8e9192"
}
},
"outline-variant": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.267,
0.278,
0.282
],
"hex": "#444748"
}
},
"surface-tint": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.776,
0.776,
0.78
],
"hex": "#c6c6c7"
}
},
"primary": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
1.0,
1.0,
1.0
],
"hex": "#ffffff"
}
},
"on-primary": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.184,
0.192,
0.192
],
"hex": "#2f3131"
}
},
"primary-container": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.886,
0.886,
0.886
],
"hex": "#e2e2e2"
}
},
"on-primary-container": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.388,
0.396,
0.396
],
"hex": "#636565"
}
},
"inverse-primary": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.365,
0.373,
0.373
],
"hex": "#5d5f5f"
}
},
"secondary": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.678,
0.788,
0.922
],
"hex": "#adc9eb"
}
},
"on-secondary": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.078,
0.196,
0.306
],
"hex": "#14324e"
}
},
"secondary-container": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.188,
0.294,
0.408
],
"hex": "#304b68"
}
},
"on-secondary-container": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.624,
0.733,
0.867
],
"hex": "#9fbbdd"
}
},
"tertiary": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
1.0,
1.0,
1.0
],
"hex": "#ffffff"
}
},
"on-tertiary": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.384,
0.0,
0.251
],
"hex": "#620040"
}
},
"tertiary-container": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
1.0,
0.847,
0.906
],
"hex": "#ffd8e7"
}
},
"on-tertiary-container": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.671,
0.216,
0.475
],
"hex": "#ab3779"
}
},
"error": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
1.0,
0.706,
0.671
],
"hex": "#ffb4ab"
}
},
"on-error": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.412,
0.0,
0.02
],
"hex": "#690005"
}
},
"error-container": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.576,
0.0,
0.039
],
"hex": "#93000a"
}
},
"on-error-container": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
1.0,
0.855,
0.839
],
"hex": "#ffdad6"
}
},
"primary-fixed": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.886,
0.886,
0.886
],
"hex": "#e2e2e2"
}
},
"primary-fixed-dim": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.776,
0.776,
0.78
],
"hex": "#c6c6c7"
}
},
"on-primary-fixed": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.102,
0.11,
0.11
],
"hex": "#1a1c1c"
}
},
"on-primary-fixed-variant": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.271,
0.278,
0.278
],
"hex": "#454747"
}
},
"secondary-fixed": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.816,
0.894,
1.0
],
"hex": "#d0e4ff"
}
},
"secondary-fixed-dim": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.678,
0.788,
0.922
],
"hex": "#adc9eb"
}
},
"on-secondary-fixed": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.0,
0.114,
0.208
],
"hex": "#001d35"
}
},
"on-secondary-fixed-variant": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.176,
0.286,
0.396
],
"hex": "#2d4965"
}
},
"tertiary-fixed": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
1.0,
0.847,
0.906
],
"hex": "#ffd8e7"
}
},
"tertiary-fixed-dim": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
1.0,
0.686,
0.827
],
"hex": "#ffafd3"
}
},
"on-tertiary-fixed": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.239,
0.0,
0.149
],
"hex": "#3d0026"
}
},
"on-tertiary-fixed-variant": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.522,
0.078,
0.353
],
"hex": "#85145a"
}
},
"background": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.043,
0.075,
0.149
],
"hex": "#0b1326"
}
},
"on-background": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.855,
0.886,
0.992
],
"hex": "#dae2fd"
}
},
"surface-variant": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0.176,
0.204,
0.286
],
"hex": "#2d3449"
}
}
},
"typography": {
"display-lg": {
"$type": "typography",
"$value": {
"fontFamily": "Inter",
"fontSize": {
"value": 84,
"unit": "px"
},
"fontWeight": 700,
"lineHeight": {
"value": 90,
"unit": "px"
},
"letterSpacing": {
"value": -0.04,
"unit": "em"
}
}
},
"headline-lg": {
"$type": "typography",
"$value": {
"fontFamily": "Inter",
"fontSize": {
"value": 32,
"unit": "px"
},
"fontWeight": 600,
"lineHeight": {
"value": 40,
"unit": "px"
},
"letterSpacing": {
"value": -0.02,
"unit": "em"
}
}
},
"headline-md": {
"$type": "typography",
"$value": {
"fontFamily": "Inter",
"fontSize": {
"value": 24,
"unit": "px"
},
"fontWeight": 500,
"lineHeight": {
"value": 32,
"unit": "px"
}
}
},
"body-lg": {
"$type": "typography",
"$value": {
"fontFamily": "Inter",
"fontSize": {
"value": 18,
"unit": "px"
},
"fontWeight": 400,
"lineHeight": {
"value": 28,
"unit": "px"
}
}
},
"body-md": {
"$type": "typography",
"$value": {
"fontFamily": "Inter",
"fontSize": {
"value": 16,
"unit": "px"
},
"fontWeight": 400,
"lineHeight": {
"value": 24,
"unit": "px"
}
}
},
"label-sm": {
"$type": "typography",
"$value": {
"fontFamily": "Inter",
"fontSize": {
"value": 12,
"unit": "px"
},
"fontWeight": 600,
"lineHeight": {
"value": 16,
"unit": "px"
},
"letterSpacing": {
"value": 0.05,
"unit": "em"
}
}
}
},
"rounded": {
"sm": {
"$type": "dimension",
"$value": {
"value": 0.25,
"unit": "rem"
}
},
"DEFAULT": {
"$type": "dimension",
"$value": {
"value": 0.5,
"unit": "rem"
}
},
"md": {
"$type": "dimension",
"$value": {
"value": 0.75,
"unit": "rem"
}
},
"lg": {
"$type": "dimension",
"$value": {
"value": 1,
"unit": "rem"
}
},
"xl": {
"$type": "dimension",
"$value": {
"value": 1.5,
"unit": "rem"
}
},
"full": {
"$type": "dimension",
"$value": {
"value": 9999,
"unit": "px"
}
}
},
"spacing": {
"unit": {
"$type": "dimension",
"$value": {
"value": 8,
"unit": "px"
}
},
"container-padding": {
"$type": "dimension",
"$value": {
"value": 24,
"unit": "px"
}
},
"card-gap": {
"$type": "dimension",
"$value": {
"value": 16,
"unit": "px"
}
},
"section-margin": {
"$type": "dimension",
"$value": {
"value": 40,
"unit": "px"
}
},
"glass-padding": {
"$type": "dimension",
"$value": {
"value": 20,
"unit": "px"
}
}
},
"components": {
"glass-card-standard": {
"backgroundColor": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
1.0,
1.0,
1.0
],
"alpha": 0.1
}
},
"textColor": "{colors.primary}",
"rounded": "{rounded.lg}",
"padding": "{spacing.glass-padding}"
},
"glass-card-elevated": {
"backgroundColor": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
1.0,
1.0,
1.0
],
"alpha": 0.2
}
},
"textColor": "{colors.primary}",
"rounded": "{rounded.xl}",
"padding": "{spacing.glass-padding}"
},
"button-primary": {
"backgroundColor": "{colors.primary}",
"textColor": "{colors.on-primary}",
"typography": "{typography.label-sm}",
"rounded": "{rounded.xl}",
"height": {
"$type": "dimension",
"$value": {
"value": 48,
"unit": "px"
}
},
"padding": {
"$type": "dimension",
"$value": "0 24px"
}
},
"button-primary-hover": {
"backgroundColor": "{colors.primary-fixed-dim}"
},
"button-ghost": {
"backgroundColor": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
1.0,
1.0,
1.0
],
"alpha": 0.05
}
},
"textColor": "{colors.primary}",
"typography": "{typography.label-sm}",
"rounded": "{rounded.xl}"
},
"input-field": {
"backgroundColor": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
1.0,
1.0,
1.0
],
"alpha": 0.1
}
},
"textColor": "{colors.primary}",
"typography": "{typography.body-md}",
"rounded": "{rounded.xl}",
"padding": {
"$type": "dimension",
"$value": {
"value": 20,
"unit": "px"
}
},
"height": {
"$type": "dimension",
"$value": {
"value": 48,
"unit": "px"
}
}
},
"weather-display-large": {
"textColor": "{colors.primary}",
"typography": "{typography.display-lg}"
},
"metric-label": {
"textColor": "{colors.on-surface-variant}",
"typography": "{typography.label-sm}",
"textTransform": {
"$type": "string",
"$value": "uppercase"
}
},
"list-item-interactive": {
"backgroundColor": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
0,
0,
0
],
"alpha": 0
}
},
"rounded": "{rounded.md}",
"padding": {
"$type": "dimension",
"$value": {
"value": 12,
"unit": "px"
}
}
},
"list-item-interactive-hover": {
"backgroundColor": {
"$type": "color",
"$value": {
"colorSpace": "srgb",
"components": [
1.0,
1.0,
1.0
],
"alpha": 0.1
}
}
}
}
}
Brand & Style
This design system centers on a high-fidelity Glassmorphism aesthetic designed to evoke a sense of clarity, depth, and modern sophistication. The brand personality is ethereal yet functional, transforming complex meteorological data into a serene visual experience.
The UI relies on a "vibrant-minimalist" approach: the background provides the energy through multi-colored abstract gradients (pinks, purples, and blues), while the interface elements act as frosted crystalline lenses that focus the user's attention. The emotional response is intended to be calm and premium, utilizing transparency and blur to simulate physical layers of glass floating in a fluid, digital space.
Colors
The color strategy prioritizes luminosity and contrast. Because the background is a vibrant, multi-colored abstract composition, the UI components utilize a monochromatic white palette with varying alpha channels to maintain legibility.
- Primary Canvas: A multi-stop linear or radial gradient background featuring Deep Blue (#1E3A8A), Vivid Purple (#7E22CE), and Soft Pink (#DB2777).
- Surface Alpha: Component backgrounds are never solid. They range from
rgba(255, 255, 255, 0.1)for secondary depth to0.2for primary interaction areas. - Accents: Semantic colors for weather conditions (e.g., Warning Yellow, Rain Blue) should be applied with high saturation but low opacity fills to maintain the glass effect.
- Text: Strictly white (#FFFFFF) or high-tint silver (#E2E8F0) to ensure WCAG compliance against the vibrant background.
Typography
The design system utilizes Inter for its neutral, geometric clarity which balances the organic nature of the blurred backgrounds.
- Hierarchy: Large display sizes are used for temperature readings to create a clear focal point.
- Legibility: On frosted glass, font weight is increased by one tier (e.g., using Medium instead of Regular) to counteract the visual noise of the background blur.
- Treatment: Subtle text-shadows (
0px 2px 4px rgba(0,0,0,0.15)) may be applied to small labels to ensure they "pop" against lighter areas of the background gradient.
Layout & Spacing
The layout follows a fluid, contextual model. Elements are grouped into "Glass Containers" that float within the safe areas of the viewport.
- Rhythm: An 8px base grid governs all dimensions.
- Grouping: Related weather metrics (humidity, wind, UV index) are housed in a CSS grid or flex layout with 16px gaps.
- Negative Space: Generous outer margins (24px+) are maintained to ensure the vibrant background is visible, reinforcing the "floating" nature of the interface.
Elevation & Depth
Depth in this design system is not achieved through darkness, but through the physics of light and refraction.
- The Glass Stack:
- Level 1 (Base): Dynamic background gradient with a slight grain texture.
- Level 2 (Standard Card):
backdrop-filter: blur(20px),background: rgba(255, 255, 255, 0.1). - Level 3 (Elevated/Modals):
backdrop-filter: blur(40px),background: rgba(255, 255, 255, 0.2). - Edge Definition: Every glass surface must have a 1px solid border at
rgba(255, 255, 255, 0.2). A secondary inner "shine" border (top and left only) can be used to simulate a light source. - Shadows: Use extremely soft, spread-out shadows (
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1)) to separate the glass layers from the background without making the UI feel "heavy."
Shapes
The shape language is organic and approachable. This design system uses "Rounded" (Level 2) settings to complement the fluid nature of the background.
- Cards: Use
1rem(16px) for standard weather cards. - Action Elements: Buttons and search bars use
rounded-xl(1.5rem / 24px) to create a soft, tactile feel. - Icons: Weather iconography should be line-based with rounded caps (2px stroke width) to match the border weights of the containers.
Components
Glass Containers
Standard cards use a 20px blur for general metrics, while elevated cards (modals or focal points) use 40px blur and higher opacity to sit physically higher in the stack. All glass elements must feature a 1px white border to simulate light refraction on the edges.
Action Elements
Buttons use the rounded-xl setting to maintain a soft, organic feel. Primary buttons are solid white for maximum contrast, while ghost buttons utilize backdrop filters to remain integrated with the atmospheric background.
Inputs & Interaction
Interactive list items and text inputs use subtle hover states and light blurs rather than solid color changes, preserving the "crystalline" transparency of the UI.
Typography Application
Large weather displays utilize subtle text shadows to maintain legibility against the unpredictable colors of the background gradient. Metric labels should remain secondary in hierarchy using the silver-tinted on-surface-variant color.
Atmospheric Glass
A glassmorphism-driven weather application design system. Frosted crystalline panels float over vibrant gradient backgrounds, transforming complex meteorological data into a serene, premium visual experience. Uses a monochromatic white palette with varying alpha channels for luminosity and depth.
Files
| File | Description |
|---|---|
DESIGN.md | The complete design system specification in DESIGN.md format, including both structured YAML design tokens (frontmatter) and human-readable style guidance (markdown body). |
tailwind.config.js | A Tailwind CSS v3 theme configuration derived from the design tokens in the DESIGN.md frontmatter. Covers colors, typography, border-radius, and spacing. Component tokens are intentionally excluded — Tailwind's utility-first approach handles component styling through composition of these primitives. |
design_tokens.json | A Design Tokens Community Group JSON file containing all design tokens from the DESIGN.md frontmatter, including component-level tokens. This format is interoperable with tools like Figma, Style Dictionary, and other token pipelines. |
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: "class",
theme: {
extend: {
colors: {
"surface": "#0b1326",
"surface-dim": "#0b1326",
"surface-bright": "#31394d",
"surface-container-lowest": "#060e20",
"surface-container-low": "#131b2e",
"surface-container": "#171f33",
"surface-container-high": "#222a3d",
"surface-container-highest": "#2d3449",
"on-surface": "#dae2fd",
"on-surface-variant": "#c4c7c8",
"inverse-surface": "#dae2fd",
"inverse-on-surface": "#283044",
"outline": "#8e9192",
"outline-variant": "#444748",
"surface-tint": "#c6c6c7",
"primary": "#ffffff",
"on-primary": "#2f3131",
"primary-container": "#e2e2e2",
"on-primary-container": "#636565",
"inverse-primary": "#5d5f5f",
"secondary": "#adc9eb",
"on-secondary": "#14324e",
"secondary-container": "#304b68",
"on-secondary-container": "#9fbbdd",
"tertiary": "#ffffff",
"on-tertiary": "#620040",
"tertiary-container": "#ffd8e7",
"on-tertiary-container": "#ab3779",
"error": "#ffb4ab",
"on-error": "#690005",
"error-container": "#93000a",
"on-error-container": "#ffdad6",
"primary-fixed": "#e2e2e2",
"primary-fixed-dim": "#c6c6c7",
"on-primary-fixed": "#1a1c1c",
"on-primary-fixed-variant": "#454747",
"secondary-fixed": "#d0e4ff",
"secondary-fixed-dim": "#adc9eb",
"on-secondary-fixed": "#001d35",
"on-secondary-fixed-variant": "#2d4965",
"tertiary-fixed": "#ffd8e7",
"tertiary-fixed-dim": "#ffafd3",
"on-tertiary-fixed": "#3d0026",
"on-tertiary-fixed-variant": "#85145a",
"background": "#0b1326",
"on-background": "#dae2fd",
"surface-variant": "#2d3449",
},
fontFamily: {
"display-lg": ["Inter"],
"headline-lg": ["Inter"],
"headline-md": ["Inter"],
"body-lg": ["Inter"],
"body-md": ["Inter"],
"label-sm": ["Inter"],
},
fontSize: {
"display-lg": [
"84px",
{
lineHeight: "90px",
letterSpacing: "-0.04em",
fontWeight: "700",
},
],
"headline-lg": [
"32px",
{
lineHeight: "40px",
letterSpacing: "-0.02em",
fontWeight: "600",
},
],
"headline-md": [
"24px",
{
lineHeight: "32px",
fontWeight: "500",
},
],
"body-lg": [
"18px",
{
lineHeight: "28px",
fontWeight: "400",
},
],
"body-md": [
"16px",
{
lineHeight: "24px",
fontWeight: "400",
},
],
"label-sm": [
"12px",
{
lineHeight: "16px",
letterSpacing: "0.05em",
fontWeight: "600",
},
],
},
borderRadius: {
"sm": "0.25rem",
"DEFAULT": "0.5rem",
"md": "0.75rem",
"lg": "1rem",
"xl": "1.5rem",
"full": "9999px",
},
spacing: {
"unit": "8px",
"container-padding": "24px",
"card-gap": "16px",
"section-margin": "40px",
"glass-padding": "20px",
},
},
},
};
30x-image
A Codex / Claude Code skill that generates on-brand marketing imagery via the built-in image_generation tool (gpt-image-2). Pairs a brand DESIGN.md profile with a 7-template prompt taxonomy, combinatorial variation axes, and an anti-slop banned list to produce high-quality marketing creative without API keys, drift, or AI defaults.
What it does
Takes:
- A brand `DESIGN.md` (frontmatter token block + 9 markdown sections +
a numeric taste: block)
- A template choice (one of 8) + a jobspec (subject / copy / size)
Produces:
- On-brand marketing images generated by
gpt-image-2— ad creatives,
logos, deck slides, product mockups, billboards, lighting transforms, scene compositions, and LinkedIn carousels.
8 templates
| Template | Output | Default size |
|---|---|---|
logo | NEW original mark for a brand | 1024×1024 |
ad-creative | Polished social/digital ad with optional tagline | 1024×1536 |
slide | Single deck slide — pitch / data / metric | 1536×864 |
product-mockup | Product on clean background with realistic shadow | 1536×1024 |
marketing-with-text | Billboard / poster / packaging with verbatim copy | 1024×1536 |
lighting-transform | Re-stage existing image for new lighting/weather | source-preserve |
scene-with-person | Insert person into new scene | 1536×1024 |
carousel | LinkedIn / social carousel, 6-10 slides (N separate PNGs) | 1024×1024 / 1024×1280 |
How it works (3 layers)
1. Cookbook templates (references/cookbook-7-templates.md) — 8 prompt skeletons with default tool params, drawn from OpenAI's official cookbook plus a 30x-image extension for carousel. 2. Combinatorial axes (references/combinatorial-axes.md) — per-template axes (4-5 each) with options that get committed at runtime, biased by the brand's taste: block (variance / density / art_direction / spacing / imagery_realism / text_density). Kills AI default slop by forcing intent. 3. Anti-slop rules (references/anti-slop-rules.md) — universal banned list (no AI yellow-tint, no purple neon, no "Elevate / Unleash" copy, no pure black, no Acme/Nexus placeholders) augmented per-brand by Section 7 Don't from the brand's DESIGN.md.
Where DESIGN.md comes from
- `npx getdesign list` — 60+ brands ready to pull (Stripe / Linear /
Notion / Apple / Tesla / Nike / Spotify / Starbucks / Coinbase / Figma / Cursor / Claude / etc.). Pull with npx getdesign add <brand>.
- Describe brand to the agent — URL / Tailwind / tokens.json / Figma
Variables / CSS / screenshot / pure prose. Codex synthesizes a DESIGN.md.
- Hand-write — copy shape from
examples/awesome-vendor/stripe/DESIGN.md.
Repo structure
30x-image/
├── SKILL.md # Skill entry — Codex loads this
├── README.md # This file
├── RUN-IN-CODEX.md # M0 + M1 verification record
├── agents/
│ └── openai.yaml # Codex skill metadata
├── references/
│ ├── cookbook-7-templates.md # 8 prompt skeletons + default params
│ ├── combinatorial-axes.md # Per-template axes (29 axes total)
│ └── anti-slop-rules.md # Universal banned list + per-brand rules
├── examples/
│ ├── awesome-vendor/
│ │ └── stripe/DESIGN.md # Canonical brand profile (37KB, 9 sections)
│ └── google-official/
│ └── atmospheric-glass/ # Google reference design system
├── scripts/ # Reserved for future automation
└── assets/ # ReservedQuickstart for users
Use 30x-image. Generate an ad-creative for Stripe.
DESIGN.md path: ~/.agents/skills/30x-image/examples/awesome-vendor/stripe/DESIGN.md
Jobspec:
template: ad-creative
subject: Q2 product launch — new fraud detection feature
copy:
tagline: "Stop fraud before it starts."
cta: "Try it free"
size: 1024x1536
quality: high
n: 4Status
- M0 ✅ — Stripe
ad-creativeend-to-end verified - M1 ✅ — All 7 cookbook templates with combinatorial axes; brand
fidelity tested across logo / slide / product-mockup / marketing-with-text / lighting-transform / scene-with-person
- M1.5 ✅ —
carouseltemplate (8th, 30x-image extension) with
parallel action=generate slides + Narrative Tension Curve axis
- M2 ✅ —
initmode landed: 3-path generation (getdesign primary →
Stitch MCP secondary → LLM fallback), outputs our 9-section format, validated with @google/design.md lint, auto-inferred fields marked # auto-inferred, please review
- M3 ✅ —
editmode landed: surgical region edits via gpt-image-2's
input_image_mask parameter. Four region-specifier paths — natural language ("the headline at the top"), normalized bbox, user-supplied mask PNG, global no-mask. Agent uses vision to locate elements, programmatically generates masks, calls image_generation to modify only the masked region while preserving 99% of pixels 1:1.
Key design decisions (verified)
- `taste:` block drives axis selection — 5-7 numeric brand parameters
determine which axis option gets committed deterministically.
- Section 9 `Agent Prompt Guide` is redundant — frontmatter + Sections
1/2/3/7 are sufficient for axis-driven prompt assembly. Don't write per-brand cheat sheets.
- **Carousel uses
action=generatefor every slide, notaction=edit
chain** — editing a reference image traps gpt-image-2 in webpage-layout mode and produces CSS-rendered-looking output. Each slide is an independent gpt-image-2 generation; cross-slide consistency comes from the shared design-system prompt prefix.
- Free-form mode is fallback only — when user's brief doesn't fit any
of the 8 templates, agent runs cookbook generic skeleton + DESIGN.md + anti-slop, no axes (lower determinism). Templates are always preferred.
Anti-Slop Rules — Marketing-Specific Banned List
Borrowed from Leonxlnx/taste-skill stitch-skill (Section 9 anti-patterns) + imagegen-frontend-web (rebellion against AI defaults).
Why this exists: image_generation tool defaults to a specific AI slop look — it has been trained on millions of stock-photo / AI-generated / trend-of-the-month images. Without explicit prohibition, output collapses to the lowest-common-denominator AI aesthetic.
How to use: Every 30x-image generate invocation MUST inject this list into the prompt as hard constraints (typically the trailing ANTI-SLOP CONSTRAINTS: block). Brand-specific Don'ts from ## 7. Do's and Don'ts section of DESIGN.md augment this universal list.
---
Universal Banned List (always inject)
Visual: AI image gen defaults
- ❌ AI yellow-tint cast — gpt-image-1.5 era warm yellow overlay; gpt-image-2
is neutral but old habits persist. Force neutral color balance.
- ❌ Purple/blue AI neon glow — the "AI assistant glowing purple orb"
aesthetic. No outer glow on UI elements. No neon haze on backgrounds.
- ❌ Floating meaningless gradient blobs — decorative chromatic blobs
with no narrative purpose. If gradient is used, it must serve composition.
- ❌ Centered dark hero — generic dark-mode hero with subject perfectly
centered. Use only if taste.variance ≤ 3.
- ❌ Generic dashboard card spam — 3-equal-card row showing fake metrics.
Use 2-column zigzag or asymmetric instead.
- ❌ Cloned sections — the same composition repeated 3x with different
text. Each section must earn its own visual treatment.
Typography: AI default fonts
- ❌ Inter font — overused since 2020. Forbidden in premium contexts
unless brand DESIGN.md explicitly chooses it.
- ❌ Generic serif (Times New Roman / Georgia / Garamond / Palatino) —
use distinctive modern serifs (Fraunces / Editorial New / Instrument Serif) only if the brand calls for serif.
- ❌ Pure black `#000000` — too harsh, lacks brand warmth. Use deep
navy / off-black / zinc-950 from the brand's neutral palette.
- ❌ Excessive gradient text on large headers — 2020-era trick that AI
overuses. Solid color with strong weight contrast beats gradient.
Copy: AI marketing clichés
- ❌ "Elevate / Seamless / Unleash / Reimagine / Next-Gen / Empower" — the
six horsemen of AI marketing copy. Never appear in tagline.
- ❌ Fake round numbers — "99.99% accurate", "10x faster", "50% off" —
too clean to believe. Real metrics or no metrics.
- ❌ Generic placeholder names — "John Doe", "Acme Corp", "Nexus Inc",
"TechCo" — real names or believable fictional names ("Aurora Studio", "Thread", "Field & Flour").
- ❌ AI-style vague copy — "Transform your workflow with AI-powered
insights." Be specific or be absent.
- ❌ Filler UI text — "Scroll to explore", "Swipe down", scroll arrow,
bouncing chevron. Content should pull users in naturally.
Composition: AI layout tells
- ❌ 3 equal cards horizontally — generic feature row. Use 2-column
zigzag, asymmetric grid, or horizontal scroll.
- ❌ Pill-shaped buttons (border-radius > 12px) — overused. Match
brand's rounded.* tokens (typically 4-8px for premium B2B).
- ❌ Custom mouse cursors — unnecessary novelty.
- ❌ Overlapping elements — every element must occupy clean spatial
zone. No absolute-positioned content stacking.
- ❌ Centered Hero when variance ≥ 4 — force Split / Left-Aligned /
Asymmetric Whitespace.
Photography: AI photo defaults
- ❌ Generic stock-photo polish — sterile / overlit / "too professional"
/ Shutterstock energy. Add film grain, natural imperfection, real lighting.
- ❌ Stock-photo CFO/founder archetype — middle-aged white guy in suit
pointing at chart. Use real diversity, real environments, real grain.
- ❌ Plastic skin retouching — pores, wrinkles, sun texture must be
visible on people unless brand explicitly demands flawless.
---
Per-Brand Augmentation
Always read the brand's ## 7. Do's and Don'ts → ### Don't section and append every entry to the prompt. Examples:
Stripe DESIGN.md Don't might add:
- ❌ no harsh saturated colors outside #533afd / #ea2261 / #f96bee palette
- ❌ no weight 700 headlines (Stripe uses weight 300)
- ❌ no large radius (>8px) — Stripe stays in conservative 4-8px range
Linear DESIGN.md Don't might add:
- ❌ no decorative illustration (Linear is text-first)
- ❌ no warm color cast (Linear is cool/neutral)
---
Prompt injection format
Append at the END of every image_generation prompt (last block before tool invocation):
ANTI-SLOP CONSTRAINTS (hard requirements, do not relax):
- ❌ no AI yellow-tint cast
- ❌ no purple/blue neon glow
- ❌ no floating gradient blobs
- ❌ no Inter font / pure #000000
- ❌ no "Elevate / Unleash / Next-Gen / Reimagine" copy
- ❌ no fake round numbers (99.99%, 50%, 10x)
- ❌ no Acme / John Doe / Nexus placeholder names
- ❌ no generic stock-photo polish (sterile / overlit)
- [+ all entries from DESIGN.md ## 7. Do's and Don'ts → Don't section]
Output: image_generation must satisfy ALL constraints above.---
When constraints conflict with brand DESIGN.md
Brand wins. If a brand explicitly chooses Inter, pure black, gradient headers, or any other "AI default" — that is the brand's choice and universal banned list does NOT override it. The brand's ## 1. Visual Theme prose + ## 7. Do's list is authoritative.
---
Quality bar for "no slop"
A generated image is slop-free if: 1. No item from universal banned list visible in image 2. No item from brand's Don't list violated 3. The image cannot be confused with a generic AI-stock-photo / AI-marketing template — it is unmistakably this brand 4. A designer reviewing the image would not recognize "AI defaults" (template-feeling layouts, neon glow, yellow tint, etc.)
If any check fails → regenerate with stronger anti-slop prompting OR manually pick a different combinatorial axis combo.