pixr-cli
v0.3.0
Published
Installable image-generation CLI for Gemini, OpenAI-compatible APIs, OpenRouter, and fal, with reusable local defaults.
Maintainers
Readme
pixr
pixr is an installable image-generation CLI for Node.js. It works with Gemini, OpenAI and OpenAI-compatible APIs (Together, Qwen via DashScope, LiteLLM, local servers), OpenRouter, and fal. Today it is focused on generation workflows with reusable local defaults. The brand is intentionally broader so the tool can grow into a more agentic image editor later.
The npm package name is pixr-cli.
The installed command is pixr.
Features
- installable CLI with
pixr genalias for fast prompt-based generationeditfor text-guided image editsvaryfor one or more image variations- multiple providers with custom base URLs:
gemini,openai,openrouter,fal - reusable home-directory defaults in
~/.pixr/ - named profiles under
~/.pixr/profiles/<name>/ - per-profile model and save-directory defaults
- live image-model listing (Gemini and OpenRouter)
- interactive model picker
- saved default model and output directory
- live model search and per-model capability info,
--paramfor any provider parameter - masked edits, plus local
info,resize,crop,extend,mask, andgridcommands - command-aware prompt and reference discovery from
~/.pixr/ - interactive and flag-driven profile creation
- width and height resizing
- output conversion to
png,jpg, orwebp - REPL mode when no prompt is passed
- JSON output for scripting
- fallback to the Gemini Files API when inline refs are too large (Gemini only)
Requirements
- Node.js
>=20.10 - an API key for your provider in
PIXR_API_KEY(or the env var named by--api-key-env)
Legacy env vars still work:
NANO_IMAGE_API_KEYNANO_IMAGE_MODELNANO_IMAGE_CLIENT_MODULE
Install
Install from npm:
npm install -g pixr-cliInstall from this repo:
npm install
npm linkQuick Start
Set your API key:
export PIXR_API_KEY=your_gemini_api_keyList image-capable models (Gemini and OpenRouter only):
pixr modelsSave your preferred default model:
pixr model gemini-3.1-flash-image-previewScaffold your local ~/.pixr workspace:
pixr config --init
pixr profile init social
pixr profile init social --model gemini-3.1-flash-image-preview \
--save-dir "~/Pictures/pixr/social" --format webp --width 1600 --height 900 \
--prefix social --default-profileSave a default output directory:
pixr save-dir --set "~/Pictures/pixr"Generate an image:
pixr generate "a clean product poster for a white mechanical keyboard"Use the shorter alias:
pixr gen "a clean product poster for a white mechanical keyboard"Edit an existing image:
pixr edit ./hero.png "turn this into a premium skincare ad with softer lighting"Generate two variations:
pixr vary ./hero.png --count 2Generate and save into a folder:
pixr generate --save-to ./renders "a studio portrait of a citrus soda can"Generate with exact output size and format:
pixr generate -w 1600 -h 840 -f webp --save-to ./renders \
"a minimal editorial thumbnail about digital creativity"Use the prompt directly without the generate subcommand:
pixr "a retro sci-fi postcard of tokyo in rain"Open the REPL:
pixrProviders
Pick a provider with --provider (or PIXR_PROVIDER, or provider in a profile). --base-url (or PIXR_BASE_URL) overrides its API URL, and --api-key-env names the env var that holds the key. The default is gemini with PIXR_API_KEY. No model is built in: pick one with pixr models, then pass --model or save it with pixr model <name>.
| Provider | Default base URL | Notes |
| --- | --- | --- |
| gemini | Google's | --base-url points the Gemini SDK at a proxy. |
| openai | https://api.openai.com/v1 | Calls /images/generations, and /images/edits when references or an input are given. Works with any compatible API; include the /v1 (or equivalent) in --base-url. |
| openrouter | https://openrouter.ai/api/v1 | Calls /images. Model ids look like vendor/model. |
| fal | https://queue.fal.run | Model is the endpoint id, e.g. fal-ai/flux/dev. Uses the queue API. |
export OPENROUTER_API_KEY=sk-or-...
pixr profile init router --provider openrouter --api-key-env OPENROUTER_API_KEY \
--model google/gemini-2.5-flash-image --default-profile
pixr generate "a lighthouse at dusk"
export TOGETHER_API_KEY=...
pixr generate --provider openai --base-url https://api.together.ai/v1 \
--api-key-env TOGETHER_API_KEY -m black-forest-labs/FLUX.1-schnell "a paper boat"
export FAL_KEY=...
pixr generate --provider fal --api-key-env FAL_KEY -m fal-ai/flux/dev "a neon fox"Provider notes:
- Models are never hardcoded.
pixr modelslists them live,--search <text>filters, and--categoryfilters fal's catalog (text-to-image,image-to-image, ...).pixr models --info <model>shows what a model accepts: its parameters, how many input images, and any mask field. OpenRouter and fal publish this; Gemini and OpenAI-compatible APIs do not, so for them requests are sent as asked and the provider's own error is shown. - You choose the provider and model for every task. Per-command defaults work in
~/.pixr/config.json, for example{ "commands": { "edit": { "provider": "openrouter", "model": "vendor/model" } } }. --param name=value(repeatable) sets any provider parameter. Values are JSON when they parse (--param seed=7,--param 'imageConfig={"aspectRatio":"16:9"}') and@file.pngbecomes an image data URL (--param [email protected]). They merge overproviderOptionsfrom config. Parameters a model's live schema does not list produce a warning, not an error.- Gemini has no schema, so give it aspect ratio and size yourself, for example
--param 'imageConfig={"aspectRatio":"16:9","imageSize":"2K"}'. - Exact
--width/--heightand--formatare always applied locally after generation. Giving both-wand-hforces that exact size, so an image of a different shape is stretched (pixr warns); give one of them to keep the shape. For OpenRouter, an aspect ratio is also sent when the model's live schema lists one that matches. - Instruction and style files are prepended to the prompt for non-Gemini providers.
- On fal, the input image and mask go in the fields the model's own schema names (
image_url,image_urls,mask_url, ...). Name a field yourself with--param <field>[email protected]when a model needs it. --paramvalues for Gemini are merged into the requestconfiglast, so they can override pixr's own defaults (responseModalities,systemInstruction).- The key is read from the environment only, never stored in config files.
- Precedence: CLI flags, then the profile/config file, then
PIXR_PROVIDER/PIXR_BASE_URL. Passing a different--providerthan the profile uses ignores that profile's base URL, key env, model, andproviderOptions.
Editing images
pixr edit <image> [prompt] works with any image-to-image model; the prompt is optional for models that take none (for example background removal on fal: pixr edit photo.png --provider fal -m <model from pixr models --category image-to-image --search background>).
Masks use one convention: white = change, black = keep. --mask <png> must be the same size as the input.
pixr mask photo.png --rect 200,120,300,300 # or --ellipse x,y,w,h; writes a mask the size of photo.png
pixr edit photo.png "replace it with a vase of tulips" --mask pixr-mask-photo-*.pngWith --mask-mode auto (default) the model's own mask field is used when its live schema has one. Otherwise the edited result is merged over the original through the mask, so pixels outside the mask never change (verified exactly). Models that do not keep the scene's geometry can leave a visible seam at the mask edge; use a model with a native mask for those edits. --mask-mode native forces a native mask (OpenAI-style mask on openai), --mask-mode composite always merges locally.
Local tools (no provider, no API key):
| Command | What it does |
| --- | --- |
| pixr info <image> | width, height, format, alpha, bytes |
| pixr resize <image> -w 800 -f webp | resize and/or convert |
| pixr crop <image> --rect x,y,w,h | crop |
| pixr extend <image> --pad 0,200,0,0 | add canvas (--color) and write a mask of the new area, for outpainting |
| pixr mask <image> --rect/--ellipse x,y,w,h | draw a mask |
| pixr grid a.png b.png --columns 2 | one contact sheet, to compare candidates |
For scripts and agents: pass --json for machine-readable output on stdout, --no-stdin so a missing prompt never waits on stdin, and expect errors as {"error":{"code","message"}} on stderr with exit code 1 (2 for bad command-line usage).
Commands
The words info, resize, crop, extend, mask, and grid (like edit, model, and config) are commands when they come first. To generate from a prompt that starts with one, write pixr generate "mask the sky...".
Every command supports help:
pixr --help
pixr help edit
pixr help vary
pixr help generate
pixr generate --help
pixr edit --help
pixr vary --help
pixr profile --help
pixr models --help
pixr model --help
pixr save-dir --help
pixr config --help
pixr refs --helpMain commands:
pixr generate [options] <prompt>pixr gen [options] <prompt>pixr edit [options] <input> <prompt>pixr vary [options] <input> [prompt]pixr modelspixr model [<name>] [--clear-model]pixr profile [list|show|init] [name]pixr save-dir [<path>] [--set <path>] [--clear-save-dir]pixr refspixr config [--init]
Examples:
pixr generate --model gemini-2.5-flash-image "a soft editorial portrait"
pixr generate --ref ./extra.png --no-default-refs "a bottle shot with hard rim light"
pixr generate -w 1600 "a wide editorial thumbnail with auto height"
pixr edit ./hero.png --ref ./logo.png "replace the product label with this logo"
pixr vary ./hero.png --count 3 "keep the same product, explore bolder compositions"
pixr profile list
pixr profile show social
pixr profile init social --model gemini-3.1-flash-image-preview --save-dir ./renders/social
pixr config --init
pixr models --json
pixr refs --json
pixr config --jsonDevelopment
Run directly from the repo:
npm run dev -- --help
npm run dev -- models
npm run dev -- generate "a chrome camera on velvet"
npm run dev -- save-dir --set "~/Pictures/pixr"If you want the branded npm script:
npm run pixr -- models
npm run pixr -- config --json
npm run pixr -- help generateDefaults
pixr automatically uses these files if they exist:
~/.pixr/
├── config.json
├── INSTRUCTION.md
├── STYLE.md
├── prompts/
│ ├── generate.md
│ ├── edit.md
│ └── vary.md
├── assets/
│ ├── common/
│ ├── generate/
│ ├── edit/
│ └── vary/
└── profiles/
└── social/
├── INSTRUCTION.md
├── STYLE.md
└── assets/Profile fallback:
--profile <name>uses~/.pixr/profiles/<name>/INSTRUCTION.md,STYLE.md, andassets/when present- profiles can also save their own
model,outputDir,format,width,height,prefix,count, andpromptFilein~/.pixr/config.json - if a profile file is missing,
pixrfalls back to the global~/.pixrfile or asset folders assets/common/and command folders likeassets/edit/are auto-discovered- if more than three default asset images exist,
pixruses the latest three by modified time and prints a warning
Legacy local setup is still read when present:
~/.nano-img/config.json~/.nano-img/assets/~/.nano-img/INSTRUCTION.md~/.nano-image/STYLE.md
Precedence:
- CLI flags
- selected profile overrides
- environment variables
- saved config
- auto-discovered home-directory files
Notes
editandvarysend the input image (plus any references) to the provider's edit flow.--save-toand--outputare identical.pixr profile init <name>opens an interactive setup flow in a real terminal unless you pass flags or--no-interactive.-walone preserves aspect ratio.-halone preserves aspect ratio.-wand-htogether force exact final dimensions.- a text file is saved if the model returns text alongside the image (Gemini).
Testing
See TEST.md.
License
ISC
