Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on:
pull_request:
push:
branches: [main]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: oven-sh/setup-bun@v2
- run: bun install
- name: Biome lint
run: bunx biome check .

typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: oven-sh/setup-bun@v2
- run: bun install
- name: Install skill dependencies
run: |
cd skills/openrouter-models/scripts && bun install && cd ../../..
cd skills/openrouter-images/scripts && bun install && cd ../../..
- name: Type check
run: bun run typecheck
81 changes: 81 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.0/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true,
"defaultBranch": "main"
},
"files": {
"includes": [
"**",
"!**/*.json",
"!!**/biome.json",
"!**/node_modules"
]
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100,
"expand": "always"
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": {
"useLiteralKeys": "off",
"noForEach": "off",
"noBannedTypes": "error"
},
"style": {
"noNonNullAssertion": "off",
"useNodejsImportProtocol": "error",
"useBlockStatements": "error",
"noParameterAssign": "error",
"useConst": "error",
"useImportType": {
"level": "on",
"options": {
"style": "separatedType"
}
},
"noInferrableTypes": "error",
"noUselessElse": "error"
},
"correctness": {
"noUnusedImports": "error"
},
"suspicious": {
"noExplicitAny": "error",
"noAssignInExpressions": "error",
"noConsole": "off",
"noDoubleEquals": {
"level": "error",
"options": {
"ignoreNull": false
}
}
},
"performance": {
"recommended": true,
"noAccumulatingSpread": "error"
},
"security": {
"recommended": true
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"trailingCommas": "all",
"semicolons": "always",
"arrowParentheses": "always",
"bracketSpacing": true,
"lineWidth": 100
}
}
}
31 changes: 31 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "openrouter-skills",
"private": true,
"scripts": {
"lint": "biome check .",
"lint:fix": "biome check --fix .",
"format": "biome format --fix .",
"typecheck": "bun run typecheck:models && bun run typecheck:images",
"typecheck:models": "cd skills/openrouter-models/scripts && bunx tsc --noEmit",
"typecheck:images": "cd skills/openrouter-images/scripts && bunx tsc --noEmit"
},
"devDependencies": {
"@biomejs/biome": "2.4.0"
}
}
68 changes: 49 additions & 19 deletions skills/openrouter-images/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
---
name: openrouter-images
description: Generate images from text prompts and edit existing images using OpenRouter's image generation models. Use when the user asks to create, generate, or make an image, picture, or illustration from a description, or wants to edit, modify, transform, or alter an existing image with a text prompt.
description: >
Generate images from text prompts and edit existing images using OpenRouter's image generation models.
Use this skill whenever the user wants to create visual content of any kind: generate an image, picture,
photo, artwork, illustration, logo, icon, banner, thumbnail, mockup, diagram, or sketch from a description.
Also use when the user wants to edit, modify, transform, or alter an existing image — changing colors,
adding or removing elements, converting style (watercolor, pixel art, oil painting, etc.), or fixing
something in a photo. Trigger on phrases like "make me a picture", "draw/sketch/paint this", "visualize
this concept", "create a logo", "generate a mockup", "change/fix/update this image", "add/remove something
from this photo", or any request that implies producing or modifying a visual. Even if the user doesn't
say "image generation" explicitly, use this skill whenever the output should be an image file.
---

# OpenRouter Images
Expand All @@ -9,12 +18,13 @@ Generate images from text prompts and edit existing images via OpenRouter's chat

## Prerequisites

The `OPENROUTER_API_KEY` environment variable must be set. Get a key at https://openrouter.ai/keys
- The `OPENROUTER_API_KEY` environment variable must be set. Get a key at https://openrouter.ai/keys
- `bun` must be installed

## First-Time Setup

```bash
cd <skill-path>/scripts && npm install
cd <skill-path>/scripts && bun install
```

## Decision Tree
Expand All @@ -34,10 +44,10 @@ Pick the right script based on what the user is asking:
Create a new image from a text prompt:

```bash
cd <skill-path>/scripts && npx tsx generate.ts "a red panda wearing sunglasses"
cd <skill-path>/scripts && npx tsx generate.ts "a futuristic cityscape at night" --aspect-ratio 16:9
cd <skill-path>/scripts && npx tsx generate.ts "pixel art of a dragon" --output dragon.png
cd <skill-path>/scripts && npx tsx generate.ts "a watercolor painting" --model google/gemini-2.5-flash-image
cd <skill-path>/scripts && bun run generate.ts "a red panda wearing sunglasses"
cd <skill-path>/scripts && bun run generate.ts "a futuristic cityscape at night" --aspect-ratio 16:9
cd <skill-path>/scripts && bun run generate.ts "pixel art of a dragon" --output dragon.png
cd <skill-path>/scripts && bun run generate.ts "a watercolor painting" --model google/gemini-2.5-flash-image
```

### Options
Expand All @@ -54,9 +64,9 @@ cd <skill-path>/scripts && npx tsx generate.ts "a watercolor painting" --model g
Modify an existing image with a text prompt:

```bash
cd <skill-path>/scripts && npx tsx edit.ts photo.png "make the sky purple"
cd <skill-path>/scripts && npx tsx edit.ts avatar.jpg "add a party hat" --output avatar-hat.png
cd <skill-path>/scripts && npx tsx edit.ts scene.png "convert to watercolor style" --model google/gemini-2.5-flash-image
cd <skill-path>/scripts && bun run edit.ts photo.png "make the sky purple"
cd <skill-path>/scripts && bun run edit.ts avatar.jpg "add a party hat" --output avatar-hat.png
cd <skill-path>/scripts && bun run edit.ts scene.png "convert to watercolor style" --model google/gemini-2.5-flash-image
```

### Options
Expand Down Expand Up @@ -95,20 +105,40 @@ Supported input formats: `.png`, `.jpg`, `.jpeg`, `.webp`, `.gif`
}
```

## Using a Different Model
## Prompt Tips

The default model is `google/gemini-3.1-flash-image-preview` (Nano Banana 2). To use a different model, pass `--model <id>` with any OpenRouter model ID that supports image output modalities.
Better prompts produce better images. A few specifics go a long way:

Use the `openrouter-models` skill to discover image-capable models:
- **State the medium** — "a watercolor painting", "a 35mm photograph", "pixel art", "3D render". This anchors the model's style.
- **Describe style and mood** — lighting, color palette, atmosphere ("warm golden-hour light", "moody noir shadows", "vibrant pop-art colors").
- **Be specific about composition** — what's in the foreground vs background, camera angle, framing ("close-up portrait", "wide aerial shot").
- **For edits, be precise** — say exactly what to change and what to preserve ("make the sky sunset-orange but keep the buildings unchanged").

## Model Selection

The default model is `google/gemini-3.1-flash-image-preview` (Nano Banana 2) — it's fast, free-tier eligible, and handles most requests well.

Pass `--model <id>` to use a different model. Choose based on what the user needs:

| Need | Recommended approach |
|---|---|
| Quick drafts, iteration | Default model — fast turnaround for exploring ideas |
| Highest quality / artistic style | Try a dedicated image model (e.g. DALL-E, Stable Diffusion variants) |
| Photo-realistic edits | Gemini models handle edit instructions well since they understand both text and images natively |
| Budget-conscious | Stick with the default or check pricing via the `openrouter-models` skill |

To discover all available image-generation models, use the `openrouter-models` skill:

```bash
cd <openrouter-models-skill-path>/scripts && npx tsx search-models.ts --modality image
cd <openrouter-models-skill-path>/scripts && bun run search-models.ts --modality image
```

## Presenting Results

- After generating or editing, display the saved image to the user
- Include the model used and any text response the model provided (printed to stderr)
- If multiple images are returned, show all of them
- When the user doesn't specify an output path, tell them where the file was saved
- For edit operations, mention the source image that was modified
- **Display the saved image** to the user immediately — they need to see the result to decide if it's good or needs another iteration.
- **Mention the model used** — so the user can switch models if the style doesn't match what they wanted.
- **Tell them the file path** — they'll need it for further edits, to include in other work, or to share.
- **Suggest refinements** — if the result isn't perfect, offer to tweak the prompt or try a different model. Image generation is inherently iterative.
- Include any text response the model provided (printed to stderr).
- If multiple images are returned, show all of them.
- For edit operations, mention the source image that was modified.
31 changes: 31 additions & 0 deletions skills/openrouter-images/scripts/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading