visual-factory
Use when the user asks to generate images or videos with Google Nano Banana or Veo: social media content (Reels, TikTok, YouTube thumbnails), product photography, storyboard-to-video, ad creatives, multilingual campaign variants, website asset packs, app icons, favicon sets. NOT for editing raw local code files, NOT for Midjourney/DALL-E/Stable Diffusion, NOT for video trimming/ffmpeg editing.
Visual Factory
Generate images, icons, and videos using Google's Nano Banana (Gemini image models) and Veo — directly from Claude Code. One command for every visual production need.
On Activation
- Check for API credentials:
- Run:
echo $GOOGLE_API_KEY - If empty, run:
echo $GOOGLE_APPLICATION_CREDENTIALS - If both empty: tell the user "No Gemini API credentials found. Run
/visual-factory setupto configure." and stop.
- Run:
- Identify the command from the user's input (see Command Routing below).
- Always read
references/MODEL_MATRIX.mdfirst (needed for step 4). Then read the command-specific reference file(s) per the Command Routing table below. - Announce: model selected + reason + cost estimate. Wait for confirmation on expensive ops.
- Execute the workflow. Save output to
assets/generated/<command>/YYYY-MM-DD/. - Write a sidecar
.jsonmanifest for every generated file. - Inform user about SynthID + C2PA watermarks: "All Nano Banana and Veo output carries permanent SynthID + C2PA watermarks. These cannot be removed."
Model Selection
Before every generation, read references/MODEL_MATRIX.md and apply the decision tree.
Quick rules (memorize these):
- Image default:
gemini-3.1-flash-image-preview(Nano Banana 2) - Upgrade to
gemini-3-pro-image-preview(NB Pro) for: hero assets, text rendering, mockups, >3 refs, NB→Veo first frame, batch campaigns - Video default:
veo-3.1-lite-generate-preview - Upgrade to Veo Fast for extension or higher motion quality
- Upgrade to Veo Full for 4K or production hero video
Always tell the user which model you chose and why, before generating.
Hard Constraints
- Auth: API keys via env vars only (
GOOGLE_API_KEYorGOOGLE_APPLICATION_CREDENTIALS). Never hardcode. Never log. - Confirmation: Show cost estimate before generating. Require explicit confirmation for NB Pro + 4K or any Veo Full request.
- Veo async: Veo is ALWAYS asynchronous. Poll every 10 seconds. Never block. Minimum 30s wait.
- Veo aspect ratio: Enforce before API call — Veo ONLY accepts
16:9or9:16. - Rate limits: On 429, apply exponential backoff: 1s → 2s → 4s → 8s → 16s. After 5 retries, stop and inform the user.
- Edit sessions: Track edit count. Warn at edit #5. Offer checkpoint-and-reset at edit #7.
- Text in images: Enforce 25-character limit. Recommend ALL CAPS. Warn if user asks for longer.
- Output: Never commit generated assets to git without explicit user confirmation.
- Watermarks: Never promise watermark removal. SynthID + C2PA are permanent.
- Content policy: If blocked, explain and suggest rephrasing. Never retry the same prompt.
- Scope: Only generates. Never edits project code files unprompted.
- Manifests: Write a
.jsonsidecar for every generated file (prompt, model, cost, timestamp, output path).
Command Routing
Detect the command from the user's message and execute the matching workflow below.
| User says... | Run workflow | Read reference(s) |
|---|---|---|
| "generate", "create image", "make a picture", "logo", "illustration" | → generate | PROMPT_FRAMEWORKS.md |
| "edit", "modify", "change this image" | → edit | PROMPT_FRAMEWORKS.md |
| "icon", "favicon", "app icon", "logo icon" | → icon | PLATFORM_RECIPES.md |
| "social", "instagram", "twitter", "linkedin", "tiktok", "social pack" | → social | PLATFORM_RECIPES.md, PROMPT_FRAMEWORKS.md |
| "web assets", "hero", "OG image", "website", "banner", "landing page" | → web | PLATFORM_RECIPES.md |
| "from content", "from README", "from blog post", "read this file" | → content | PROMPT_FRAMEWORKS.md |
| "translate", "localize", "in Spanish/French/etc." | → translate | PROMPT_FRAMEWORKS.md |
| "animate", "make a video from this image" | → animate | PROMPT_FRAMEWORKS.md, CINEMATOGRAPHY.md |
| "video", "reel", "tiktok video", "youtube video" | → video | PROMPT_FRAMEWORKS.md, CINEMATOGRAPHY.md |
| "batch", "variations", "multiple versions" | → batch | PROMPT_FRAMEWORKS.md |
| "brand kit", "brand register", "brand list" | → brand | (none — brand kit logic is self-contained) |
| "setup", "configure", "API key" | → setup | TROUBLESHOOTING.md |
If unclear, ask: "Which command? (generate / edit / icon / social / web / content / translate / animate / video / batch / brand / setup)"
Workflows
generate — Text-to-Image
- Read
references/PROMPT_FRAMEWORKS.md(Framework 1 and 4 if reference images provided). - Apply the 5-component formula to enhance the user's prompt:
[Subject] + [Action] + [Location] + [Composition] + [Style]. Stack lighting, camera, color grading, materiality dimensions for quality. - Show the enhanced prompt to the user: "Enhanced prompt: [prompt]. Model: [model] ([reason]). Estimated cost: [cost]. Proceed?"
- Wait for confirmation, then generate.
- Save to
assets/generated/generate/YYYY-MM-DD/output.png+output.jsonmanifest. - Display the image and offer: "Want to edit it? Or generate a variation?"
edit — Image Editing
- Ask for the image path if not provided.
- Read
references/PROMPT_FRAMEWORKS.md(Framework 2). - Track edit count for this session. Display current count: "Edit #N".
- Construct edit prompt using preservation language: append "Keep everything else exactly the same." to the user's instruction.
- Show enhanced prompt + model + cost. Wait for confirmation.
- Generate. Save to
assets/generated/edit/YYYY-MM-DD/edit-N.png+edit-N.json. - If edit count reaches 5: warn — "You're at edit #5. Quality can degrade after 7 edits. Consider saving a checkpoint."
- If edit count reaches 7: offer checkpoint — "I recommend a checkpoint: I'll save this result, then you can restart the session with it as the new base reference."
icon — App Icon & Favicon Set
- Read
references/PLATFORM_RECIPES.md(Favicon & PWA Icon Set section). - Ask if not clear: "What's the icon concept? (logo, symbol, initial letter, abstract)"
- Auto-detect framework by checking for:
next.config.*(Next.js),astro.config.*(Astro),svelte.config.*(SvelteKit),vite.config.*(Vite). - Model: NB Pro. Request transparent background: add "transparent background, no background, isolated on transparency" to prompt.
- Show prompt + model + cost. Confirm.
- Generate at 512×512 (1:1). Save as
icon-512.png. - Use Bash to resize to all required sizes:
Ifmkdir -p assets/generated/icon/YYYY-MM-DD # After generating icon-512.png, resize using sips (macOS) or convert (ImageMagick) # sips is available on macOS without installation: sips -z 192 192 icon-512.png --out icon-192.png sips -z 180 180 icon-512.png --out icon-180.png sips -z 96 96 icon-512.png --out icon-96.png sips -z 32 32 icon-512.png --out icon-32.png sips -z 16 16 icon-512.png --out icon-16.pngsipsnot available (Linux), useconvertfrom ImageMagick. - Write
manifest.jsonwith icon entries. - Place files in the correct framework public directory (from PLATFORM_RECIPES.md Framework Asset Placement table).
- Report: "Generated 6 icon sizes + manifest.json. Placed in [directory]."
social — Multi-Platform Social Asset Pack
- Read
references/PLATFORM_RECIPES.md(Social Media Platforms section). - Ask which platforms if not specified: "Which platforms? (instagram / tiktok / linkedin / twitter / pinterest / youtube / facebook / all)"
- Apply NB image formula to the user's brief. Model: NB2 default, NB Pro for LinkedIn and YouTube thumbnail.
- Show enhanced prompt + platforms + model + total cost estimate. Confirm.
- For each selected platform, generate assets at the correct sizes:
- Instagram: 1080×1080 (1:1), 1080×1350 (4:5), 1080×1920 (9:16)
- TikTok: 1080×1920 (9:16)
- LinkedIn: 1200×628 (16:9) — NB Pro
- Twitter/X: 1600×900 (16:9)
- Pinterest: 1000×1500 (2:3)
- YouTube: 1280×720 (16:9) — NB Pro
- Facebook: 1200×630 (16:9)
- Save each with the exact file name from PLATFORM_RECIPES.md to
assets/generated/social/YYYY-MM-DD/. - Write one
social-pack.jsonmanifest listing all files. - Report: "Generated [N] assets for [platforms]. Saved to assets/generated/social/YYYY-MM-DD/."
web — Website Asset Pack
- Read
references/PLATFORM_RECIPES.md(Website Assets section). - Auto-detect framework (same check as icon command).
- Ask if not clear: "What's the hero concept/brief? I'll generate: hero image (1920×1080), dark mode hero, OG image (1200×630), and favicon set."
- Model: NB Pro for all (hero assets seen by many people).
- Show enhanced prompt + asset list + cost. Confirm.
- Generate in sequence:
a. Hero image: 1920×1080 (16:9). Save as
hero.png. b. Dark mode variant: same prompt + "dark mode color scheme, dark backgrounds, high contrast for dark UI". Save ashero-dark.png. c. OG image: 1200×630 (16:9). Same concept, adjust composition for the wider format. Save asog.png. d. Favicon set: same as icon workflow (reuse icon command logic for the 6 sizes + manifest.json). - Place assets in correct framework directories.
- Write
web-pack.jsonmanifest. - Report: "Generated full website asset pack. Hero, dark hero, OG image, and [N] favicon sizes. Placed in [directories]."
content — Content-to-Visual Asset Set
- Ask for the file path if not provided: "What file should I read? (README.md, blog post, landing page, etc.)"
- Read the file using the Read tool.
- Extract from the content:
- Key themes: What is this about in 3–5 words?
- Emotional tone: Professional / playful / urgent / inspiring / technical?
- Color palette cues: Any colors mentioned or implied?
- Subject matter: People / product / abstract / technology / nature?
- Construct a visual brief: "This content is about [themes]. Tone: [tone]. Suggested visual: [brief]."
- Show the brief to the user: "Here's what I extracted: [brief]. Does this capture the right direction? (yes / adjust)"
- If adjusted, incorporate feedback. If yes, proceed.
- Model: NB Pro for hero (hero asset). NB2 for social and supporting illustration.
- Generate the full asset set:
a. Hero image: 1920×1080. Save as
content-hero.png. b. Social pack: 1080×1080 (Instagram feed) + 1200×628 (LinkedIn) + 1200×630 (OG). Save with platform names. c. Supporting illustration: 1:1, more abstract/conceptual variation of the theme. Save ascontent-illustration.png. - Save all to
assets/generated/content/YYYY-MM-DD/. Writecontent-pack.jsonmanifest. - Report the asset set and the extracted brief used.
translate — Multilingual Visual Localization
- Ask for inputs if not provided:
- Source image path
- Target languages (e.g., "French, Spanish, Arabic")
- Read the source image. Identify the text visible in it (ask the user if unclear).
- Hard limits check: If any text block exceeds 25 characters, warn the user: "The text '[text]' is [N] chars — above the 25-char reliable limit. I recommend shortening it or using ALL CAPS. Continue anyway?"
- Model: NB Pro (text rendering quality).
- For each target language:
a. Translate the text (Claude translates directly).
b. Check translated text length. If >25 chars, suggest a shorter alternative.
c. Construct edit prompt: "Replace the [language] text in the image with '[translated text]' in ALL CAPS [font-style]. Keep everything else exactly the same."
d. Generate. Save as
<base-name>-<lang-code>.png(e.g.,hero-fr.png,hero-ar.png). - Write
translate-pack.jsonmanifest listing all localized files. - Note: For Arabic/Hebrew (RTL scripts) and CJK (Chinese/Japanese/Korean), use NB Pro and expect 2–3 iterations for correct rendering. Test all output carefully.
brand — Persistent Brand Kit Management
brand register [name]:
- Collect from user:
- Reference images (up to 6): ask user to provide paths or describe
- Color palette: primary hex, secondary hex, accent hex
- Style description: 2–3 sentences (e.g., "Minimalist, premium, dark backgrounds, gold accents")
- Tone: Professional / playful / bold / understated
- Create
.visual-factory/memory/brands/directory if it doesn't exist:mkdir -p .visual-factory/memory/brands - Write
.visual-factory/memory/brands/<name>.json:{ "name": "<name>", "reference_images": ["path/to/ref1.png", "path/to/ref2.png"], "colors": { "primary": "#1A1A2E", "secondary": "#E94560", "accent": "#FFD700" }, "style": "Minimalist, premium, dark backgrounds, gold accents", "tone": "Professional", "created": "YYYY-MM-DD" } - Confirm: "Brand kit '[name]' registered. Use
--brand [name]with any command to apply it."
brand list:
- Check if
.visual-factory/memory/brands/exists. - List all
*.jsonfiles in that directory. - For each, show: name, style description, color palette, creation date.
- If directory doesn't exist or is empty: "No brand kits registered yet. Run
/visual-factory brand register [name]to create one."
brand use [name] / --brand [name] flag:
- Read
.visual-factory/memory/brands/<name>.json. - Inject into the generation prompt:
- Append style description to every prompt
- Add color guidance: "Color palette: primary [hex], secondary [hex], accent [hex]"
- Reference images: prepend to any reference image set
- Announce: "Using brand kit '[name]': [style description]."
animate — Image-to-Video (NB→Veo Pipeline)
- Read
references/PROMPT_FRAMEWORKS.md(Veo Framework 4: Image-to-Video). - Read
references/MODEL_MATRIX.md(Video Models section). - Ask for inputs if not provided:
- Source image path (optional — will generate one if not provided)
- Motion description: "What should move in the video?" (NOT scene description)
- Aspect ratio: 16:9 or 9:16 (ONLY these two options)
- Audio: on or off? (default: off — Veo Lite has no audio)
- If no source image provided:
a. Ask for a scene brief.
b. Generate NB Pro first frame optimized for video: stable background, clear subject, motion headroom. Save as
animate-frame.png. c. Confirm with user before proceeding to video. - Enforce aspect ratio: if user requests anything other than 16:9 or 9:16, tell them "Veo only supports 16:9 and 9:16" and ask them to choose.
- Select model: Veo Lite (default). Veo Fast if
--extendrequested. Veo Full if 4K requested. - Construct motion prompt: "[Cinematography movement] as [what moves]. [Audio direction if enabled]." Show to user.
- Announce: "Submitting to Veo. This is async — I'll poll every 10 seconds. Expect 30 seconds to a few minutes."
- Submit video generation. Poll every 10 seconds until
operation.done == true. - Download video. Save to
assets/generated/animate/YYYY-MM-DD/output.mp4. - Save
output.jsonmanifest. - Report: "Animation complete. Static frame: [path]. Video: [path]. Duration: [N]s."
video — Text-to-Video
- Read
references/PROMPT_FRAMEWORKS.md(Veo Frameworks 1–3). - Read
references/CINEMATOGRAPHY.md. - Ask for inputs if not provided:
- Video brief / concept
- Aspect ratio: 16:9 or 9:16 (ONLY these two — enforce strictly)
- Duration: 4, 6, or 8 seconds (default: 8)
- Extend? (adds 7s segments via extension API — not available on Lite)
- Audio direction (dialogue, SFX, ambience, music)
- Apply the 5-part Veo formula:
[Cinematography] + [Subject] + [Action] + [Context] + [Style & Ambiance]. - For multi-beat clips (user wants 3+ scenes): use timestamp prompting:
[00:00-00:02] Shot 1. [00:02-00:05] Shot 2. [00:05-00:08] Shot 3. - Direct all four audio layers explicitly (if audio requested):
- Dialogue in single quotes
- SFX: with SFX: prefix
- Ambience as scene description
- Music with genre + instrument + timing
- Select model per MODEL_MATRIX.md. Enforce aspect ratio before API call.
- Show full enhanced prompt + model + estimated cost. Confirm.
- Announce async: "Submitting to Veo. Polling every 10 seconds. Expect 30s to a few minutes."
- Poll until done. Download. Save to
assets/generated/video/YYYY-MM-DD/output.mp4+ manifest. - If
--extendrequested: poll for completion, then submit extension with a continuation prompt. - Report: "Video complete. Saved to [path]. Duration: [N]s."
batch — N Variations of a Concept
- Ask for inputs if not provided:
- Concept description (the core subject)
- N: how many variations? (default: 5)
- Variation axes: what should vary? Options:
lighting,mood,style,setting,color(default: all) - Concept slug for folder naming (e.g., "summer-campaign")
- Read
references/PROMPT_FRAMEWORKS.md(Framework 1). - Build N prompt variations by systematically varying the requested axes. For each axis value:
- lighting: golden hour / studio / overcast / neon / candlelight
- mood: playful / professional / dramatic / minimal / energetic
- style: photorealistic / editorial / illustrated / cinematic / product
- setting: indoor / outdoor / studio / urban / natural
- color: warm / cool / monochrome / vibrant / muted
- Show the variation matrix to the user. Confirm.
- Model selection: NB2 default. NB Pro if campaign assets.
- Show total cost estimate (N × per-image cost). Confirm.
- For N < 20: Fan out parallel generation — generate all N images in a single turn, announcing each as it completes.
- For N ≥ 20: Inform user: "Using Gemini Batch API for 50% cost reduction. This is async — results ready in 10–30 minutes." Submit batch job. Poll for completion.
- Save all to
assets/generated/batch/<concept-slug>/YYYY-MM-DD/asvariant-01.png,variant-02.png, etc. - Write
batch.jsonmanifest listing all files with their variation axis values. - Report: "Generated [N] variations. Saved to assets/generated/batch/[slug]/[date]/."
setup — Auth Wizard
- Check current environment:
echo "GOOGLE_API_KEY: ${GOOGLE_API_KEY:+set (hidden)}" echo "GOOGLE_APPLICATION_CREDENTIALS: ${GOOGLE_APPLICATION_CREDENTIALS:-not set}" - If
GOOGLE_API_KEYis set: confirm "Found GOOGLE_API_KEY. Running a test generation to verify..."- Test: generate a 1×1 pixel NB2 image with prompt "a single red dot, minimal, 1x1"
- If succeeds: "Auth verified. You're ready to use visual-factory."
- If fails: show the error and continue to troubleshoot.
- If neither is set, ask 3 questions: a. "Personal or production use?" → Personal: Gemini API key path. Production: Vertex AI path. b. "Do you have a Google Cloud project?" → Yes: Vertex AI. No: Gemini API key (simpler). c. "Do you have a budget preference?" → Free tier: Gemini API free tier. Paid: either path.
- Gemini API key path:
- "Go to https://aistudio.google.com/apikey and create a key."
- "Then run:
export GOOGLE_API_KEY=your_key_here" - "Add to your shell profile (~/.zshrc or ~/.bashrc):
export GOOGLE_API_KEY=your_key_here" - Run test generation to confirm.
- Vertex AI path:
- "Go to console.cloud.google.com and enable the Vertex AI API for your project."
- "Create a service account with 'Vertex AI User' role. Download the JSON key."
- "Then run:
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json" - Run test generation to confirm.
- Report: "Auth configured. Model access: [NB2 ✓ / NB Pro ✓ / Veo ✓]."