# Nano Banana

> Google Gemini image generation skill. Triggers on: 'generate image', 'draw', 'create character', 'illustration', 'nano banana', 'image gen', etc.

- Skill: `aldegad/nano-banana` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add aldegad/nano-banana`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aldegad/nano-banana/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Design & Media
- Author: aldegad (https://skillmd.com/u/aldegad)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/aldegad/nano-banana

---


## Nano Banana — Gemini Image Generation

Image generation skill using Google Gemini API. Supports 4K, character consistency mode, and native text-in-image.

### API Key Setup

Set the `GEMINI_API_KEY` environment variable before using this skill:

```bash
export GEMINI_API_KEY="your-api-key-here"
```

You can add this to your shell profile (`~/.zshrc`, `~/.bashrc`) or use a `.env` file.

### Image Generation

```bash
curl -s "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent?key=$GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [{"parts": [{"text": "Your prompt here"}]}],
    "generationConfig": {
      "responseModalities": ["TEXT", "IMAGE"]
    }
  }' | python3 -c "
import sys, json, base64, datetime, os
data = json.load(sys.stdin)
if 'error' in data:
    print(f'Error: {data[\"error\"][\"message\"]}', file=sys.stderr)
    sys.exit(1)
saved = False
for candidate in data.get('candidates', []):
    for part in candidate.get('content', {}).get('parts', []):
        if 'inlineData' in part:
            mime = part['inlineData'].get('mimeType', 'image/png')
            ext = 'png' if 'png' in mime else 'jpg' if 'jpeg' in mime or 'jpg' in mime else 'webp'
            out_dir = os.environ.get('NANO_BANANA_OUTPUT', '/tmp')
            filename = os.path.join(out_dir, f'nano-banana-{datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\")}.{ext}')
            with open(filename, 'wb') as f:
                f.write(base64.b64decode(part['inlineData']['data']))
            print(f'Saved: {filename}')
            saved = True
        elif 'text' in part:
            print(part['text'])
    if candidate.get('finishReason') not in (None, 'STOP'):
        print(f'Warning: finishReason={candidate[\"finishReason\"]}', file=sys.stderr)
if not saved:
    print('Error: no image returned (empty response, safety block, or text-only reply)', file=sys.stderr)
    sys.exit(1)
"
```

### Size / Aspect Ratio

Specify directly in your prompt:
- Square: "generate a square 1024x1024 image of ..."
- Landscape: "generate a wide landscape 1536x1024 image of ..."
- Portrait: "generate a tall portrait 1024x1536 image of ..."
- 4K: "generate a high-resolution 4K image of ..."

### Character Consistency Mode

To maintain the same character across multiple images, keep a fixed character description in every prompt:
```
"A cute bear character named Kuma, brown fur, round ears, wearing a blue scarf.
[Include this exact description in every image prompt]
In this image, Kuma is sitting at a desk coding."
```

### Image Editing (Partial Modification)

Read an existing image as base64 and send it alongside the edit instruction:
```bash
IMAGE_B64=$(base64 -i /path/to/existing-image.png) && curl -s "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent?key=$GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"contents\": [{\"parts\": [
      {\"text\": \"Edit this image: describe your edits here\"},
      {\"inlineData\": {\"mimeType\": \"image/png\", \"data\": \"$IMAGE_B64\"}}
    ]}],
    \"generationConfig\": {
      \"responseModalities\": [\"TEXT\", \"IMAGE\"]
    }
  }" | python3 -c "
import sys, json, base64, datetime, os
data = json.load(sys.stdin)
if 'error' in data:
    print(f'Error: {data[\"error\"][\"message\"]}', file=sys.stderr)
    sys.exit(1)
saved = False
for candidate in data.get('candidates', []):
    for part in candidate.get('content', {}).get('parts', []):
        if 'inlineData' in part:
            mime = part['inlineData'].get('mimeType', 'image/png')
            ext = 'png' if 'png' in mime else 'jpg' if 'jpeg' in mime or 'jpg' in mime else 'webp'
            out_dir = os.environ.get('NANO_BANANA_OUTPUT', '/tmp')
            filename = os.path.join(out_dir, f'nano-banana-edit-{datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\")}.{ext}')
            with open(filename, 'wb') as f:
                f.write(base64.b64decode(part['inlineData']['data']))
            print(f'Saved: {filename}')
            saved = True
        elif 'text' in part:
            print(part['text'])
    if candidate.get('finishReason') not in (None, 'STOP'):
        print(f'Warning: finishReason={candidate[\"finishReason\"]}', file=sys.stderr)
if not saved:
    print('Error: no image returned (empty response, safety block, or text-only reply)', file=sys.stderr)
    sys.exit(1)
"
```

### Usage Guide

1. Convert the user's request into an English prompt (English yields better quality)
2. Be specific with descriptions (style, colors, composition, background)
3. Generated images are saved to `$NANO_BANANA_OUTPUT` (defaults to `/tmp/`)
4. View the result with the Read tool and share with the user
5. For consistent character style, use: "cute forest animal, chibi style, warm colors, studio ghibli inspired"

### Model Reference

| Model | Notes |
|---|---|
| `gemini-3.1-flash-image-preview` | Default. 4K support, best quality |
| `gemini-2.5-flash-image` | Stable fallback |
| `gemini-3-pro-image-preview` | Pro quality |

Change the model name in the URL to try different models.

### Environment Variables

| Variable | Default | Description |
|---|---|---|
| `GEMINI_API_KEY` | (required) | Your Google Gemini API key |
| `NANO_BANANA_OUTPUT` | `/tmp` | Output directory for generated images |

