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

  1. 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 setup to configure." and stop.
  2. Identify the command from the user's input (see Command Routing below).
  3. Always read references/MODEL_MATRIX.md first (needed for step 4). Then read the command-specific reference file(s) per the Command Routing table below.
  4. Announce: model selected + reason + cost estimate. Wait for confirmation on expensive ops.
  5. Execute the workflow. Save output to assets/generated/<command>/YYYY-MM-DD/.
  6. Write a sidecar .json manifest for every generated file.
  7. 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_KEY or GOOGLE_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:9 or 9: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 .json sidecar 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 workflowRead reference(s)
"generate", "create image", "make a picture", "logo", "illustration"→ generatePROMPT_FRAMEWORKS.md
"edit", "modify", "change this image"→ editPROMPT_FRAMEWORKS.md
"icon", "favicon", "app icon", "logo icon"→ iconPLATFORM_RECIPES.md
"social", "instagram", "twitter", "linkedin", "tiktok", "social pack"→ socialPLATFORM_RECIPES.md, PROMPT_FRAMEWORKS.md
"web assets", "hero", "OG image", "website", "banner", "landing page"→ webPLATFORM_RECIPES.md
"from content", "from README", "from blog post", "read this file"→ contentPROMPT_FRAMEWORKS.md
"translate", "localize", "in Spanish/French/etc."→ translatePROMPT_FRAMEWORKS.md
"animate", "make a video from this image"→ animatePROMPT_FRAMEWORKS.md, CINEMATOGRAPHY.md
"video", "reel", "tiktok video", "youtube video"→ videoPROMPT_FRAMEWORKS.md, CINEMATOGRAPHY.md
"batch", "variations", "multiple versions"→ batchPROMPT_FRAMEWORKS.md
"brand kit", "brand register", "brand list"→ brand(none — brand kit logic is self-contained)
"setup", "configure", "API key"→ setupTROUBLESHOOTING.md

If unclear, ask: "Which command? (generate / edit / icon / social / web / content / translate / animate / video / batch / brand / setup)"

Workflows

generate — Text-to-Image

  1. Read references/PROMPT_FRAMEWORKS.md (Framework 1 and 4 if reference images provided).
  2. 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.
  3. Show the enhanced prompt to the user: "Enhanced prompt: [prompt]. Model: [model] ([reason]). Estimated cost: [cost]. Proceed?"
  4. Wait for confirmation, then generate.
  5. Save to assets/generated/generate/YYYY-MM-DD/output.png + output.json manifest.
  6. Display the image and offer: "Want to edit it? Or generate a variation?"

edit — Image Editing

  1. Ask for the image path if not provided.
  2. Read references/PROMPT_FRAMEWORKS.md (Framework 2).
  3. Track edit count for this session. Display current count: "Edit #N".
  4. Construct edit prompt using preservation language: append "Keep everything else exactly the same." to the user's instruction.
  5. Show enhanced prompt + model + cost. Wait for confirmation.
  6. Generate. Save to assets/generated/edit/YYYY-MM-DD/edit-N.png + edit-N.json.
  7. If edit count reaches 5: warn — "You're at edit #5. Quality can degrade after 7 edits. Consider saving a checkpoint."
  8. 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

  1. Read references/PLATFORM_RECIPES.md (Favicon & PWA Icon Set section).
  2. Ask if not clear: "What's the icon concept? (logo, symbol, initial letter, abstract)"
  3. Auto-detect framework by checking for: next.config.* (Next.js), astro.config.* (Astro), svelte.config.* (SvelteKit), vite.config.* (Vite).
  4. Model: NB Pro. Request transparent background: add "transparent background, no background, isolated on transparency" to prompt.
  5. Show prompt + model + cost. Confirm.
  6. Generate at 512×512 (1:1). Save as icon-512.png.
  7. Use Bash to resize to all required sizes:
    mkdir -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.png
    
    If sips not available (Linux), use convert from ImageMagick.
  8. Write manifest.json with icon entries.
  9. Place files in the correct framework public directory (from PLATFORM_RECIPES.md Framework Asset Placement table).
  10. Report: "Generated 6 icon sizes + manifest.json. Placed in [directory]."

social — Multi-Platform Social Asset Pack

  1. Read references/PLATFORM_RECIPES.md (Social Media Platforms section).
  2. Ask which platforms if not specified: "Which platforms? (instagram / tiktok / linkedin / twitter / pinterest / youtube / facebook / all)"
  3. Apply NB image formula to the user's brief. Model: NB2 default, NB Pro for LinkedIn and YouTube thumbnail.
  4. Show enhanced prompt + platforms + model + total cost estimate. Confirm.
  5. 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)
  6. Save each with the exact file name from PLATFORM_RECIPES.md to assets/generated/social/YYYY-MM-DD/.
  7. Write one social-pack.json manifest listing all files.
  8. Report: "Generated [N] assets for [platforms]. Saved to assets/generated/social/YYYY-MM-DD/."

web — Website Asset Pack

  1. Read references/PLATFORM_RECIPES.md (Website Assets section).
  2. Auto-detect framework (same check as icon command).
  3. 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."
  4. Model: NB Pro for all (hero assets seen by many people).
  5. Show enhanced prompt + asset list + cost. Confirm.
  6. 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 as hero-dark.png. c. OG image: 1200×630 (16:9). Same concept, adjust composition for the wider format. Save as og.png. d. Favicon set: same as icon workflow (reuse icon command logic for the 6 sizes + manifest.json).
  7. Place assets in correct framework directories.
  8. Write web-pack.json manifest.
  9. Report: "Generated full website asset pack. Hero, dark hero, OG image, and [N] favicon sizes. Placed in [directories]."

content — Content-to-Visual Asset Set

  1. Ask for the file path if not provided: "What file should I read? (README.md, blog post, landing page, etc.)"
  2. Read the file using the Read tool.
  3. 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?
  4. Construct a visual brief: "This content is about [themes]. Tone: [tone]. Suggested visual: [brief]."
  5. Show the brief to the user: "Here's what I extracted: [brief]. Does this capture the right direction? (yes / adjust)"
  6. If adjusted, incorporate feedback. If yes, proceed.
  7. Model: NB Pro for hero (hero asset). NB2 for social and supporting illustration.
  8. 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 as content-illustration.png.
  9. Save all to assets/generated/content/YYYY-MM-DD/. Write content-pack.json manifest.
  10. Report the asset set and the extracted brief used.

translate — Multilingual Visual Localization

  1. Ask for inputs if not provided:
    • Source image path
    • Target languages (e.g., "French, Spanish, Arabic")
  2. Read the source image. Identify the text visible in it (ask the user if unclear).
  3. 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?"
  4. Model: NB Pro (text rendering quality).
  5. 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).
  6. Write translate-pack.json manifest listing all localized files.
  7. 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]:

  1. 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
  2. Create .visual-factory/memory/brands/ directory if it doesn't exist:
    mkdir -p .visual-factory/memory/brands
    
  3. 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"
    }
    
  4. Confirm: "Brand kit '[name]' registered. Use --brand [name] with any command to apply it."

brand list:

  1. Check if .visual-factory/memory/brands/ exists.
  2. List all *.json files in that directory.
  3. For each, show: name, style description, color palette, creation date.
  4. 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:

  1. Read .visual-factory/memory/brands/<name>.json.
  2. 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
  3. Announce: "Using brand kit '[name]': [style description]."

animate — Image-to-Video (NB→Veo Pipeline)

  1. Read references/PROMPT_FRAMEWORKS.md (Veo Framework 4: Image-to-Video).
  2. Read references/MODEL_MATRIX.md (Video Models section).
  3. 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)
  4. 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.
  5. 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.
  6. Select model: Veo Lite (default). Veo Fast if --extend requested. Veo Full if 4K requested.
  7. Construct motion prompt: "[Cinematography movement] as [what moves]. [Audio direction if enabled]." Show to user.
  8. Announce: "Submitting to Veo. This is async — I'll poll every 10 seconds. Expect 30 seconds to a few minutes."
  9. Submit video generation. Poll every 10 seconds until operation.done == true.
  10. Download video. Save to assets/generated/animate/YYYY-MM-DD/output.mp4.
  11. Save output.json manifest.
  12. Report: "Animation complete. Static frame: [path]. Video: [path]. Duration: [N]s."

video — Text-to-Video

  1. Read references/PROMPT_FRAMEWORKS.md (Veo Frameworks 1–3).
  2. Read references/CINEMATOGRAPHY.md.
  3. 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)
  4. Apply the 5-part Veo formula: [Cinematography] + [Subject] + [Action] + [Context] + [Style & Ambiance].
  5. 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.
  6. 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
  7. Select model per MODEL_MATRIX.md. Enforce aspect ratio before API call.
  8. Show full enhanced prompt + model + estimated cost. Confirm.
  9. Announce async: "Submitting to Veo. Polling every 10 seconds. Expect 30s to a few minutes."
  10. Poll until done. Download. Save to assets/generated/video/YYYY-MM-DD/output.mp4 + manifest.
  11. If --extend requested: poll for completion, then submit extension with a continuation prompt.
  12. Report: "Video complete. Saved to [path]. Duration: [N]s."

batch — N Variations of a Concept

  1. 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")
  2. Read references/PROMPT_FRAMEWORKS.md (Framework 1).
  3. 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
  4. Show the variation matrix to the user. Confirm.
  5. Model selection: NB2 default. NB Pro if campaign assets.
  6. Show total cost estimate (N × per-image cost). Confirm.
  7. For N < 20: Fan out parallel generation — generate all N images in a single turn, announcing each as it completes.
  8. 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.
  9. Save all to assets/generated/batch/<concept-slug>/YYYY-MM-DD/ as variant-01.png, variant-02.png, etc.
  10. Write batch.json manifest listing all files with their variation axis values.
  11. Report: "Generated [N] variations. Saved to assets/generated/batch/[slug]/[date]/."

setup — Auth Wizard

  1. Check current environment:
    echo "GOOGLE_API_KEY: ${GOOGLE_API_KEY:+set (hidden)}"
    echo "GOOGLE_APPLICATION_CREDENTIALS: ${GOOGLE_APPLICATION_CREDENTIALS:-not set}"
    
  2. If GOOGLE_API_KEY is 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.
  3. 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.
  4. 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.
  5. 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.
  6. Report: "Auth configured. Model access: [NB2 ✓ / NB Pro ✓ / Veo ✓]."