@koda-sl/baker-cli 0.182.1-dev.c8185c1b5 → 0.185.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +153 -77
- package/dist/{chunk-UZ37VVP4.js → chunk-3TXZKSAR.js} +92 -28
- package/dist/chunk-3TXZKSAR.js.map +1 -0
- package/dist/cli.js +3581 -4909
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -2
- package/dist/chunk-UZ37VVP4.js.map +0 -1
package/README.md
CHANGED
|
@@ -1753,7 +1753,6 @@ Each external source is its own subcommand. Pick the verb that matches the sourc
|
|
|
1753
1753
|
| `baker images stock <q> [--type photo\|vector\|psd]` | Magnific (Freepik's dev API) — photos, vectors, illustrations, PSDs (~250M assets) | off |
|
|
1754
1754
|
| `baker images google <q>` | Google Images via the official Custom Search JSON API | off |
|
|
1755
1755
|
| `baker images pinterest <q>` | Pinterest reference imagery via ScrapeCreators (photo-real mood boards) | off |
|
|
1756
|
-
| `baker images generate <prompt>` | AI image generation via OpenRouter image models (cost-tracked) | **always on** (the bytes are the artifact) |
|
|
1757
1756
|
| `baker images logo <domain>` | Brand logo via Brandfetch CDN | **on** (top 1) |
|
|
1758
1757
|
| `baker images icon <name>` | Iconify (200+ icon sets, no API key) | off (CDN URL is stable) |
|
|
1759
1758
|
| `baker images gif <q>` | Reaction GIFs / memes via Giphy (paid-social creative) | off |
|
|
@@ -1854,7 +1853,7 @@ baker images stock "office reaction" --people only
|
|
|
1854
1853
|
|
|
1855
1854
|
Free tier exists but watermarks previews — pass `--license freemium` to filter to clean free assets explicitly.
|
|
1856
1855
|
|
|
1857
|
-
An empty result comes back with `hints` naming the filters that narrowed the search plus the fallbacks (`baker images find --sources …`, `baker
|
|
1856
|
+
An empty result comes back with `hints` naming the filters that narrowed the search plus the fallbacks (`baker images find --sources …`, `baker studio generate`); a provider failure returns an `error.fix` pointing at the same exits. `baker images google` does the same, minus the cross-provider fallback (it is the last-resort provider).
|
|
1858
1857
|
|
|
1859
1858
|
**Flags:**
|
|
1860
1859
|
|
|
@@ -1916,53 +1915,9 @@ baker images pinterest "cozy coffee shop interior" --auto-ingest 2 --context "Mo
|
|
|
1916
1915
|
|
|
1917
1916
|
Endpoint `api.scrapecreators.com/v1/pinterest/search` (`SCRAPE_CREATORS_API_KEY`), $0.00188/request, 1-day cache.
|
|
1918
1917
|
|
|
1919
|
-
###
|
|
1918
|
+
### AI image generation
|
|
1920
1919
|
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
```bash
|
|
1924
|
-
baker images generate "a friendly golden retriever in a bright modern living room" --aspect-ratio 16:9
|
|
1925
|
-
baker images generate "hero shot of a matte black water bottle on wet marble, studio light" \
|
|
1926
|
-
--model google/gemini-3-pro-image-preview --image-size 2K --aspect-ratio 4:5
|
|
1927
|
-
baker images generate "home office hero, warm minimalist, natural light, 35mm photo" \
|
|
1928
|
-
--reference "https://i.pinimg.com/…/pin1.jpg,https://…/brand-product.png"
|
|
1929
|
-
baker images generate "put this product on a marble countertop in soft daylight" \
|
|
1930
|
-
--reference "./src/brand/logos/product.png,./refs/kitchen-mood.jpg" # local sandbox files
|
|
1931
|
-
baker images generate "flat geometric mascot, brand palette" \
|
|
1932
|
-
--model recraft/recraft-v4.1-pro-vector --rgb-colors "[[10,10,10],[255,80,0]]" --bg-rgb "[255,255,255]"
|
|
1933
|
-
```
|
|
1934
|
-
|
|
1935
|
-
**Models** (`--model`, default `google/gemini-3.1-flash-image-preview`):
|
|
1936
|
-
|
|
1937
|
-
| Model | Best for | Aspect ratios | Sizes |
|
|
1938
|
-
|---|---|---|---|
|
|
1939
|
-
| `google/gemini-3.1-flash-image-preview` **(default)** | Fast iteration, reference editing, extreme aspect ratios (Nano Banana flash) | standard **+** `1:4` `4:1` `1:8` `8:1` | `0.5K`–`4K` |
|
|
1940
|
-
| `google/gemini-3.1-flash-lite-image` | Cheapest tier (Nano Banana 2 Lite) — half the flash price per output token. High-volume variants and any 1K-sufficient frame, portrait ad formats included | standard **+** `1:4` `4:1` `1:8` `8:1` | `1K` **only** |
|
|
1941
|
-
| `google/gemini-3-pro-image-preview` | Highest fidelity (Nano Banana Pro) — strong prompt adherence and reference grounding | standard set | `1K` `2K` `4K` |
|
|
1942
|
-
| `openai/gpt-image-2` | Photoreal + cleanest in-image text — ad/landing reproduction | standard set **minus** `4:5` `5:4` | *(none — derived from the ratio)* |
|
|
1943
|
-
| `openai/gpt-5.4-image-2` | **Legacy** — accepted so canvases authored before the gpt-image-2 switch still re-run. Don't pick it for new work. | standard set | `1K` `2K` `4K` (ignored upstream) |
|
|
1944
|
-
| `recraft/recraft-v4.1-pro-vector` | Vector/flat/SVG-style with palette control | standard set | `1K` `2K` `4K` |
|
|
1945
|
-
|
|
1946
|
-
Standard aspect ratios: `1:1` `2:3` `3:2` `3:4` `4:3` `4:5` `5:4` `9:16` `16:9` `21:9`.
|
|
1947
|
-
|
|
1948
|
-
`openai/gpt-image-2` accepts neither `image_size` nor the `4:5` / `5:4` portrait ratios — OpenAI picks the pixel dimensions from the ratio. To ship a 4:5 Meta feed ad from it, render the hero at `3:4` and adapt with `image_aspect_adapt`; the scaffolders do this for you.
|
|
1949
|
-
|
|
1950
|
-
`google/gemini-3.1-flash-lite-image` renders at `1K` and nothing else — `2K` / `4K` is a provider 400 (`resolution: not supported. Accepted: 1K`), not a soft clamp. It costs half of `google/gemini-3.1-flash-image-preview` per output image token ($0.00003 vs $0.00006), so it is the cheap-iteration tier for images. Keep hero stills and reference sheets that need `2K`+ on the flash or pro tier.
|
|
1951
|
-
|
|
1952
|
-
**Flags:**
|
|
1953
|
-
|
|
1954
|
-
| Flag | Description |
|
|
1955
|
-
|---|---|
|
|
1956
|
-
| `--model` | Model id (default `google/gemini-3.1-flash-image-preview`) |
|
|
1957
|
-
| `--aspect-ratio` | Output aspect ratio (default `1:1`) |
|
|
1958
|
-
| `--image-size` | Resolution: `1K` (default) `2K` `4K` (Gemini flash also `0.5K`; Gemini flash-lite is `1K` only) |
|
|
1959
|
-
| `--reference` | Comma-separated visual references, each either a **public image URL** (Pinterest / stock / library `imageUrl`) **or a local file path** (a sandbox image — brand logo, product shot, cropped photo, screenshot). Local files are downscaled (≤1536px) and inlined automatically — no manual upload. Applied in order; the biggest quality lever for photographed, on-brand output. Split is on `,`, so a URL containing a literal comma in its query string would be torn in two (rare for image CDNs — pass it alone if it occurs); a single `data:` URL is taken whole. |
|
|
1960
|
-
| `--strength` | Recraft only: vectorization strength 0–1 |
|
|
1961
|
-
| `--rgb-colors` | Recraft only: JSON palette `[[r,g,b],…]` |
|
|
1962
|
-
| `--bg-rgb` | Recraft only: JSON background `[r,g,b]` |
|
|
1963
|
-
| `--context` | Describe-hint override for the ingested row (defaults to the prompt) |
|
|
1964
|
-
|
|
1965
|
-
Returns `{ images: [{ imageId, imageUrl, deduped, width, height }], model, costUsd }`. `imageUrl` is library-owned and ready to place. Requires `OPENROUTER_API_KEY` on the Convex deployment. No `seed` (OpenRouter image_config has no seed slot). Identical re-generations dedup by content hash.
|
|
1920
|
+
Its own family — see [`baker studio`](#baker-studio--make-new-imagery) below. `baker images` sources what already exists; `baker studio` makes what doesn't.
|
|
1966
1921
|
|
|
1967
1922
|
### `baker images logo <domain>`
|
|
1968
1923
|
|
|
@@ -2920,6 +2875,155 @@ baker schema images.search # Get image search schema
|
|
|
2920
2875
|
|
|
2921
2876
|
Not every command registers a schema. On `NOT_FOUND` the error carries a structured `fix` pointing at `--help` and the family's agent doc (`__tooling__/docs/tools/baker/<family>.md` in sandboxes). Every top-level family's `--help` also ends with a `Full guide:` line pointing at that doc; `packages/cli/__tests__/doc-coverage.test.ts` fails CI if a mounted command is missing from its family doc.
|
|
2922
2877
|
|
|
2878
|
+
## `baker studio` — make new imagery
|
|
2879
|
+
|
|
2880
|
+
The generation lane. `baker images` **sources** what already exists; `baker studio` **makes** what doesn't. Every call opens a *batch* — one brief, 1-8 takes, rendered in parallel — recorded against the calling chat and shown in the dashboard Studio next to the batches the client ran themselves.
|
|
2881
|
+
|
|
2882
|
+
| Command | Purpose |
|
|
2883
|
+
|---|---|
|
|
2884
|
+
| `baker studio generate <prompt>` | Render 1-8 takes of one still. Each take is ingested into the media library as it lands |
|
|
2885
|
+
| `baker studio animate <prompt> --image <…>` | Turn a still into a clip. The prompt describes movement, not the look |
|
|
2886
|
+
| `baker studio get <generationId>` | Read one batch: takes, urls, library state, per-take failure reason |
|
|
2887
|
+
| `baker studio list` | Recent batches for the calling chat (`--all` widens to the company) |
|
|
2888
|
+
| `baker studio keep <generationId> --slot N` | Mark the keeper. Stars an image; **ingests** a clip into the video library |
|
|
2889
|
+
| `baker studio models` | Per model: shapes, resolutions, clip lengths, prompt cap, reference limit, every knob. `--kind image\|video`, `--model <id>` |
|
|
2890
|
+
| `baker studio skills` | Craft directions accepted by `generate --skill <id>` |
|
|
2891
|
+
| `baker studio improve <prompt>` | Sharpen a rough brief — the same rewrite the client's prompt-bar wand performs. Returns the rewrite and the original; generates nothing |
|
|
2892
|
+
|
|
2893
|
+
**Every per-model limit is enforced before anything is billed.** Prompt character caps (Kling 2,500 · Seedance 4,000 · Recraft 10,000 · gpt-image 32,000), reference-image counts (Recraft 1 · Gemini 14 · gpt-image 16 · Seedance 9 in reference mode), the uint32 seed range, RGB channel bounds, and `width:height` shapes are all checked against the chosen model up front — the request is refused with the number to fix rather than opening a batch that fails a take at a time. A knob the model does not have is refused too; only the *shape* snaps to the nearest it renders. `baker studio models` reads all of this from the same contract table the backend validates against, so it cannot drift.
|
|
2894
|
+
|
|
2895
|
+
Two of those checks run in the CLI itself, before the request is even sent. The **reference-image count** is one: `--reference` / `--image` accept file paths and URLs, which are uploaded to the media library first, so checking the count only at the backend means paying to ingest and describe every image in a set that was always going to be refused. The **first-frame rule** is the other — a clip started from one exact frame takes exactly one image whatever the model's reference slot allows, and reference mode is refused outright on Veo and Kling, which cannot read references at all.
|
|
2896
|
+
|
|
2897
|
+
**References must be JPG, PNG or WebP.** The models read nothing else, and the library legitimately holds SVGs because Recraft's vector model writes them — so "render the logo I just made, on a kitchen counter" is a shape the trap fits exactly. It is refused on the way in, naming the format.
|
|
2898
|
+
|
|
2899
|
+
Starting a batch returns 202 + a `generationId`; the CLI polls until the takes settle. `--wait false` / `--max-wait 0` returns the id immediately, and a wait that runs out is **not** a failure — the id comes back with `status: running` and a hint to collect it with `baker studio get`.
|
|
2900
|
+
|
|
2901
|
+
### `baker studio generate <prompt>`
|
|
2902
|
+
|
|
2903
|
+
```bash
|
|
2904
|
+
baker studio generate "a friendly golden retriever in a bright modern living room" --aspect-ratio 16:9
|
|
2905
|
+
baker studio generate "hero shot of a matte black water bottle on wet marble, studio light" \
|
|
2906
|
+
--model google/gemini-3-pro-image-preview --image-size 2K --aspect-ratio 4:5 --count 3
|
|
2907
|
+
baker studio generate "home office hero, warm minimalist, natural light, 35mm photo" \
|
|
2908
|
+
--reference "https://i.pinimg.com/…/pin1.jpg,./src/brand/logos/product.png,j57abc123def456ghi789"
|
|
2909
|
+
baker studio generate "founder-style selfie, kitchen background" --skill ugc-selfie-hook
|
|
2910
|
+
baker studio generate "flat geometric mascot, brand palette" \
|
|
2911
|
+
--model recraft/recraft-v4.1-pro-vector --rgb-colors "[[10,10,10],[255,80,0]]" --bg-rgb "[255,255,255]"
|
|
2912
|
+
```
|
|
2913
|
+
|
|
2914
|
+
**Models** (`--model`, default `google/gemini-3.1-flash-image-preview`):
|
|
2915
|
+
|
|
2916
|
+
| Model | Best for | Aspect ratios | Sizes |
|
|
2917
|
+
|---|---|---|---|
|
|
2918
|
+
| `google/gemini-3.1-flash-image-preview` **(default)** | Fast iteration, reference editing, extreme aspect ratios (Nano Banana flash) | standard **+** `1:4` `4:1` `1:8` `8:1` | `0.5K`–`4K` |
|
|
2919
|
+
| `google/gemini-3.1-flash-lite-image` | Cheapest tier (Nano Banana 2 Lite) — half the flash price per output token. High-volume variants and any 1K-sufficient frame, portrait ad formats included | standard **+** `1:4` `4:1` `1:8` `8:1` | `1K` **only** |
|
|
2920
|
+
| `google/gemini-3-pro-image-preview` | Highest fidelity (Nano Banana Pro) — strong prompt adherence and reference grounding | standard set | `1K` `2K` `4K` |
|
|
2921
|
+
| `openai/gpt-image-2` | Photoreal + cleanest in-image text — ad/landing reproduction | standard set **minus** `4:5` `5:4` | *(none — derived from the ratio)* |
|
|
2922
|
+
| `openai/gpt-5.4-image-2` | **Legacy** — accepted so canvases authored before the gpt-image-2 switch still re-run. Don't pick it for new work. | standard set | `1K` `2K` `4K` (ignored upstream) |
|
|
2923
|
+
| `recraft/recraft-v4.1-pro-vector` | Vector/flat/SVG-style with palette control. Writes **SVG**, so its output cannot be fed back as a reference | `1:1` `4:3` `3:4` `16:9` `9:16` **only** | *(none — refuses `image_size`)* |
|
|
2924
|
+
|
|
2925
|
+
Standard aspect ratios: `1:1` `2:3` `3:2` `3:4` `4:3` `4:5` `5:4` `9:16` `16:9` `21:9`.
|
|
2926
|
+
|
|
2927
|
+
`openai/gpt-image-2` accepts neither `image_size` nor the `4:5` / `5:4` portrait ratios — OpenAI picks the pixel dimensions from the ratio. To ship a 4:5 Meta feed ad from it, render the hero at `3:4` and adapt with `image_aspect_adapt`; the scaffolders do this for you.
|
|
2928
|
+
|
|
2929
|
+
`google/gemini-3.1-flash-lite-image` renders at `1K` and nothing else — `2K` / `4K` is a provider 400 (`resolution: not supported. Accepted: 1K`), not a soft clamp. It costs half of `google/gemini-3.1-flash-image-preview` per output image token ($0.00003 vs $0.00006), so it is the cheap-iteration tier for images. Keep hero stills and reference sheets that need `2K`+ on the flash or pro tier.
|
|
2930
|
+
|
|
2931
|
+
`recraft/recraft-v4.1-pro-vector` is the narrowest of the roster in three ways, all read off its live endpoint schema: it renders **five** ratios (no `4:5` / `5:4` / `2:3` / `3:2` / `21:9`, so a portrait ad shape snaps to `3:4`), it has **no `image_size`** — the provider accepts one and ignores it, which is why it is refused here — and it takes **exactly one** reference image against 14-16 elsewhere. Its output is an SVG, and the image models read only JPG, PNG and WebP, so a Recraft take cannot be used as a reference for the next render.
|
|
2932
|
+
|
|
2933
|
+
A knob the chosen model does not advertise is **refused, not silently dropped** — the error names the model and what it accepts, and carries an `error.fix` telling the agent to drop the flag rather than abandon the job.
|
|
2934
|
+
|
|
2935
|
+
**Flags:**
|
|
2936
|
+
|
|
2937
|
+
| Flag | Description |
|
|
2938
|
+
|---|---|
|
|
2939
|
+
| `--model` | Model id (default `google/gemini-3.1-flash-image-preview`) |
|
|
2940
|
+
| `--aspect-ratio` | Output aspect ratio (default `1:1`) |
|
|
2941
|
+
| `--count` | Takes to render, 1–8 (default 1) |
|
|
2942
|
+
| `--reference` | Comma-separated visual references, in order: **library image ids**, **local file paths**, and/or **image URLs**. Paths and URLs are added to the media library first and passed as ids — the studio takes library ids only, so the client can see what grounded the render and the reference stays reusable. The biggest quality lever there is. |
|
|
2943
|
+
| `--skill` | Craft direction id (`baker studio skills`) — art direction plus the model/shape/count it wants |
|
|
2944
|
+
| `--brand` | Append the company palette and visual style. **Off by default** for the agent (the dashboard defaults it on) |
|
|
2945
|
+
| `--image-size` | Resolution: `0.5K` (Gemini flash only) `1K` `2K` `4K`; Gemini flash-lite is `1K` only. **No default** — left unset the provider picks the pixels from the ratio. `gpt-image-2` has no resolution setting and **refuses** this flag |
|
|
2946
|
+
| `--quality` | `low` \| `medium` \| `high` \| `auto`. Only on models that honour it — OpenRouter lists it for gpt-image alone, so every Gemini model and Recraft **refuse** it |
|
|
2947
|
+
| `--strength` | Recraft only: vectorization strength 0–1 |
|
|
2948
|
+
| `--rgb-colors` | Recraft only: JSON palette `[[r,g,b],…]` |
|
|
2949
|
+
| `--bg-rgb` | Recraft only: JSON background `[r,g,b]` |
|
|
2950
|
+
| `--wait` / `--max-wait` | Wait for the takes (default on, 240000 ms). `--wait false` / `--max-wait 0` returns the batch id |
|
|
2951
|
+
| `--full` | Include settings, references, chat attribution, `createdAt` |
|
|
2952
|
+
|
|
2953
|
+
Requires `OPENROUTER_API_KEY` on the Convex deployment. Identical re-generations dedup by content hash.
|
|
2954
|
+
|
|
2955
|
+
### `baker studio improve <prompt>`
|
|
2956
|
+
|
|
2957
|
+
Sharpen a rough brief into directed art direction, using the same model and prompt as the wand in the dashboard's Studio bar.
|
|
2958
|
+
|
|
2959
|
+
```
|
|
2960
|
+
baker studio improve "make it look premium"
|
|
2961
|
+
baker studio improve "zoom in a bit" --kind video --has-reference
|
|
2962
|
+
```
|
|
2963
|
+
|
|
2964
|
+
| Flag | Notes |
|
|
2965
|
+
| --- | --- |
|
|
2966
|
+
| `--kind` | `image` (default) sharpens a still brief; `video` sharpens a **motion** brief |
|
|
2967
|
+
| `--skill` | Sharpen it for one craft direction (`baker studio skills`) |
|
|
2968
|
+
| `--has-reference` | Say a reference image is wired, so the rewrite describes the **change** rather than the whole scene |
|
|
2969
|
+
|
|
2970
|
+
Both `prompt` (the rewrite) and `original` come back, so you can show the client what changed instead of silently replacing their words. Nothing is generated — pass the result to `baker studio generate` yourself.
|
|
2971
|
+
|
|
2972
|
+
Reach for it when you are relaying the **client's** own words. When you are writing the art direction yourself, just write it: you will do a better job than a flash model rewriting you.
|
|
2973
|
+
|
|
2974
|
+
### `baker studio animate <prompt>`
|
|
2975
|
+
|
|
2976
|
+
```bash
|
|
2977
|
+
baker studio animate "slow push in, model turns to camera and smiles" --image j57abc123def456ghi789
|
|
2978
|
+
baker studio animate "handheld drift right, steam rising from the cup" \
|
|
2979
|
+
--image ./out/hero.png --duration 6 --quality 1080p
|
|
2980
|
+
baker studio animate "product rotates once on a turntable" --image j57abc…,j57def… --from references
|
|
2981
|
+
```
|
|
2982
|
+
|
|
2983
|
+
The image fixes the look, so the prompt describes **movement**. Models: `bytedance/seedance-2.0` (default), `google/veo-3.1`, `google/veo-3.1-fast`, `kwaivgi/kling-v3.0-pro`.
|
|
2984
|
+
|
|
2985
|
+
| Flag | Description |
|
|
2986
|
+
|---|---|
|
|
2987
|
+
| `--image` | **Required.** Comma-separated library image ids / local paths / image URLs; the first is the opening frame |
|
|
2988
|
+
| `--from` | `frame` (default — animate the first image) \| `references` (use the images as visual reference). Mutually exclusive at every provider |
|
|
2989
|
+
| `--model` | Video model id (default `bytedance/seedance-2.0`) |
|
|
2990
|
+
| `--aspect-ratio` | Default `9:16` |
|
|
2991
|
+
| `--duration` | Seconds; per-model set (default 5, snapped onto what the model renders) |
|
|
2992
|
+
| `--quality` | Resolution, e.g. `720p` (default) \| `1080p` |
|
|
2993
|
+
| `--count` | Takes, 1–3 (default 1). A clip costs ~45x an image |
|
|
2994
|
+
| `--sound` | Let the model generate audio. Off by default (billed on top) |
|
|
2995
|
+
| `--negative` / `--seed` / `--people` / `--enhance-prompt` / `--conditioning-scale` / `--cfg-scale` | Per-model knobs; refused when the chosen model doesn't advertise them |
|
|
2996
|
+
| `--wait` / `--max-wait` | Wait for the takes (default on, 600000 ms) |
|
|
2997
|
+
| `--full` | Include settings, references, chat attribution, `createdAt` |
|
|
2998
|
+
|
|
2999
|
+
**A rendered clip is not usable anywhere until it is kept** — `keep` is what ingests it into the video library. Unkept takes are never ingested, which is what makes a rejected batch cheap.
|
|
3000
|
+
|
|
3001
|
+
### `baker studio get` / `list` / `keep` / `skills`
|
|
3002
|
+
|
|
3003
|
+
```bash
|
|
3004
|
+
baker studio get j57abc123def456ghi789 --full
|
|
3005
|
+
baker studio list --kind video --limit 5 # this chat's batches
|
|
3006
|
+
baker studio list --all # every batch for the company
|
|
3007
|
+
baker studio keep j57abc123def456ghi789 --slot 2
|
|
3008
|
+
baker studio keep j57abc123def456ghi789 --slot 2 --undo
|
|
3009
|
+
baker studio skills
|
|
3010
|
+
```
|
|
3011
|
+
|
|
3012
|
+
Compact output per take is `{ slot, status, imageId | videoId, url, inLibrary, error }` alongside the batch's prompt, model, aspect ratio and status; `--full` adds the settings echo, the reference ids, the chat id and `createdAt`. `keep` stars an image (it was already in the library) and **ingests** a clip; `--undo` reverses either.
|
|
3013
|
+
|
|
3014
|
+
**Craft presets.** `--skill <id>` appends ready-written art direction to your brief — camera, lens, light, plus a clean-plate rule (no text, logos or overlays in the picture; type is composited afterwards) and a preference for physical cause over adjective.
|
|
3015
|
+
|
|
3016
|
+
| `--skill` | Model it picks | Shape | Takes | Wants a reference |
|
|
3017
|
+
|---|---|---|---|---|
|
|
3018
|
+
| `product-pack-shot` | `openai/gpt-image-2` | `1:1` | 3 | **yes** |
|
|
3019
|
+
| `ugc-selfie-hook` | `openai/gpt-image-2` | `9:16` | 3 | **yes** |
|
|
3020
|
+
| `lifestyle-scene` | `openai/gpt-image-2` | `4:5` | 3 | **yes** |
|
|
3021
|
+
| `cinematic-still` | `google/gemini-3-pro-image-preview` | `16:9` | 3 | no |
|
|
3022
|
+
| `brand-icon` | `recraft/recraft-v4.1-pro-vector` | `1:1` | 4 | no |
|
|
3023
|
+
| `background-plate` | `google/gemini-3.1-flash-image-preview` | `4:5` | 3 | no |
|
|
3024
|
+
|
|
3025
|
+
A skill fills only what you did **not** pin — `--model`, `--aspect-ratio` and `--count` always win. Which means a skill can change the model, and the model decides what the rest of the flags may be: `--skill brand-icon` lands on Recraft, so it takes one reference image rather than fourteen, refuses `--image-size`, and writes SVG that cannot be fed back in as a reference. The CLI resolves the skill's model before checking the reference count, so an over-long `--reference` list is refused before anything is uploaded.
|
|
3026
|
+
|
|
2923
3027
|
## Creative Canvas
|
|
2924
3028
|
|
|
2925
3029
|
The creative canvas runs declarative JSON pipelines. You author a graph of nodes (text, image, video, audio, composition, control-flow), `baker canvas run` it, and every node's output drops to disk under `canvas/<run_id>/` so you can watch progress and consume the artifacts.
|
|
@@ -4976,32 +5080,6 @@ Without `--slug` the command behaves as before (one creative record per publishe
|
|
|
4976
5080
|
|
|
4977
5081
|
## Landing Quality (`baker landing`)
|
|
4978
5082
|
|
|
4979
|
-
Two tools that bracket a landing build: **`inspiration`** before you design (what does good look like here?) and **`critique`** after you build (did this settle into generic defaults?).
|
|
4980
|
-
|
|
4981
|
-
### `baker landing inspiration`
|
|
4982
|
-
|
|
4983
|
-
A searchable library of real landing-page sections. Each entry is one section of a real page: a screenshot, a standalone HTML+CSS reproduction with a measured fidelity score, a description of how it moves, and the transferable idea behind it — classified in the same vocabulary the landing skill teaches, so a hit is directly buildable.
|
|
4984
|
-
|
|
4985
|
-
```bash
|
|
4986
|
-
baker landing inspiration search "pricing with a monthly/annual toggle" --scope all
|
|
4987
|
-
baker landing inspiration view <section id> # full DNA + screenshots + motion filmstrip
|
|
4988
|
-
baker landing inspiration code <section id> # the standalone bundle
|
|
4989
|
-
baker landing inspiration page <source id> # a whole page as a section sequence
|
|
4990
|
-
baker landing inspiration add https://linear.app --note "client likes this density"
|
|
4991
|
-
baker landing inspiration favorites # what this company has saved
|
|
4992
|
-
baker landing inspiration scrape <url> --out <dir> # capture any page now, synchronously
|
|
4993
|
-
```
|
|
4994
|
-
|
|
4995
|
-
- **Hybrid search over three signals** — keywords, meaning, and *appearance* (the screenshot is embedded, so a query like "dark developer hero with a terminal" can match a section whose text never says "terminal"). Filters: `--type --composition --register --interaction --motion --media --device --theme --max-rank --min-craft --min-fidelity --domain --similar-to --scope --limit`.
|
|
4996
|
-
- **Screenshots are downloaded to `.baker/inspiration/`** so an agent can actually look at a result rather than read a description of it.
|
|
4997
|
-
- **`fidelity` says how much to trust the code.** A measured 0–1 match between the live section and our standalone re-render, always reported. Above ~0.95 the markup renders like the original; below ~0.75 the section is scroll- or JS-driven and it does not.
|
|
4998
|
-
- **`used_on_pages`** appears when a section shows up on more than one of that site's pages — a nav or footer they ship everywhere, which is a stronger reference than a one-off.
|
|
4999
|
-
- **The corpus is shared across companies; favorites are per-company**, and search defaults to this company's saved sections.
|
|
5000
|
-
- **`add` studies in the background; `scrape` returns with the page on disk.** `add` grows the shared library and takes minutes, so it can never answer "build our page like this one" within the same turn. `scrape` runs the identical capture locally and blocks until it finishes, writing section screenshots, standalone markup, a whole-page reproduction and `report.html`. `--no-motion` roughly halves the runtime; `--no-mobile`, `--no-code` and `--no-report` skip further passes.
|
|
5001
|
-
- **Inspiration, never a clipboard.** Both `code` and `scrape` record what was consulted, and `critique`'s `originality` family blocks a publish that reuses a reference's copy verbatim.
|
|
5002
|
-
|
|
5003
|
-
### `baker landing critique`
|
|
5004
|
-
|
|
5005
5083
|
Deterministic design-quality critic for landing pages — an offline, no-LLM detector for the well-known "AI slop" tells (gradient text, overused fonts like Inter, side-tab colored borders, cream/parchment grounds, purple-on-heading palettes, buzzword copy, broken images, and more). It scores a landing's `.astro` source and returns findings tiered **block / warn / advisory**.
|
|
5006
5084
|
|
|
5007
5085
|
```bash
|
|
@@ -5019,9 +5097,7 @@ baker landing critique spring-offer summer-offer claude # score three landings
|
|
|
5019
5097
|
|
|
5020
5098
|
- **Agent washing is a copy tell.** A page that claims autonomy ("fully autonomous", "while you sleep", "no human intervention") and never says anywhere what the buyer approves, overrides, or audits scores an `agent-washing` warn. One signal about oversight of the agent's actions — approval, review, override, undo/rollback, audit log, escalation — anywhere on the page clears it; the rule is page-scope precisely because the hero can defer the trust story to a section below it. Generic privacy boilerplate ("GDPR", "encrypted", "your data") deliberately does **not** clear it, since it appears in most footers and says nothing about who is in charge of the agent.
|
|
5021
5099
|
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
Output is the standard envelope `{ ok, data, hints }` with `data = { advisory, slug, overall, counts, dimensions, findings }`. `dimensions` scores eight design families (typography, color, borders_depth, motion, spacing, copy, integrity, originality) 0–1 (higher is better); `counts` is the block/warn/advisory tally.
|
|
5100
|
+
Output is the standard envelope `{ ok, data, hints }` with `data = { advisory, slug, overall, counts, dimensions, findings }`. `dimensions` scores seven design families (typography, color, borders_depth, motion, spacing, copy, integrity) 0–1 (higher is better); `counts` is the block/warn/advisory tally.
|
|
5025
5101
|
|
|
5026
5102
|
## Brand Fonts (`baker brand fonts`)
|
|
5027
5103
|
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
__toESM
|
|
8
8
|
} from "./chunk-YL3HDEIJ.js";
|
|
9
9
|
|
|
10
|
-
//
|
|
10
|
+
// ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js
|
|
11
11
|
var require_safe_stable_stringify = __commonJS({
|
|
12
|
-
"
|
|
12
|
+
"../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js"(exports, module) {
|
|
13
13
|
"use strict";
|
|
14
14
|
var { hasOwnProperty } = Object.prototype;
|
|
15
15
|
var stringify = configure2();
|
|
@@ -1075,7 +1075,7 @@ function resolveAdaptFormats(params) {
|
|
|
1075
1075
|
return params.formats ?? [];
|
|
1076
1076
|
}
|
|
1077
1077
|
|
|
1078
|
-
//
|
|
1078
|
+
// ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/esm/wrapper.js
|
|
1079
1079
|
var import__ = __toESM(require_safe_stable_stringify(), 1);
|
|
1080
1080
|
var configure = import__.default.configure;
|
|
1081
1081
|
var wrapper_default = import__.default;
|
|
@@ -1120,11 +1120,22 @@ function normalizeForCanonical(value) {
|
|
|
1120
1120
|
var OPENROUTER_IMAGE_AR = ["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"];
|
|
1121
1121
|
var OPENROUTER_IMAGE_AR_EXTREME = [...OPENROUTER_IMAGE_AR, "1:4", "4:1", "1:8", "8:1"];
|
|
1122
1122
|
var OPENROUTER_IMAGE_AR_GPT = ["1:1", "2:3", "3:2", "3:4", "4:3", "9:16", "16:9", "21:9"];
|
|
1123
|
+
var GPT_IMAGE_PROMPT_MAX = 32e3;
|
|
1124
|
+
var RECRAFT_PROMPT_MAX = 1e4;
|
|
1125
|
+
var SEEDANCE_PROMPT_MAX = 4e3;
|
|
1126
|
+
var KLING_PROMPT_MAX = 2500;
|
|
1127
|
+
var VEO_SEED_MAX = 4294967295;
|
|
1128
|
+
var GPT_IMAGE_MAX_REFERENCES = 16;
|
|
1129
|
+
var GEMINI_IMAGE_MAX_REFERENCES = 14;
|
|
1130
|
+
var RECRAFT_MAX_REFERENCES = 1;
|
|
1131
|
+
var SEEDANCE_MAX_REFERENCES = 9;
|
|
1123
1132
|
var OPENROUTER_IMAGE_SIZE = ["1K", "2K", "4K"];
|
|
1124
|
-
var
|
|
1133
|
+
var OPENROUTER_IMAGE_SIZES = ["0.5K", ...OPENROUTER_IMAGE_SIZE];
|
|
1134
|
+
var OPENROUTER_IMAGE_SIZE_EXTENDED = OPENROUTER_IMAGE_SIZES;
|
|
1125
1135
|
var GEMINI_LITE_IMAGE_SIZE = ["1K"];
|
|
1126
1136
|
var OPENROUTER_IMAGE_QUALITY = ["auto", "low", "medium", "high"];
|
|
1127
|
-
var
|
|
1137
|
+
var RECRAFT_IMAGE_AR = ["1:1", "4:3", "3:4", "16:9", "9:16"];
|
|
1138
|
+
var SEEDANCE_DURATIONS = [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
|
1128
1139
|
var KLING_DURATIONS = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
|
1129
1140
|
var GEMINI_OMNI_DURATIONS = [3, 4, 5, 6, 7, 8, 9, 10];
|
|
1130
1141
|
var GEMINI_OMNI_DEFAULT_SECONDS = 10;
|
|
@@ -1153,6 +1164,7 @@ var IMAGE_GENERATE_MODELS = [
|
|
|
1153
1164
|
"google/gemini-3-pro-image-preview",
|
|
1154
1165
|
"recraft/recraft-v4.1-pro-vector"
|
|
1155
1166
|
];
|
|
1167
|
+
var DEFAULT_IMAGE_GENERATE_MODEL = "google/gemini-3.1-flash-image-preview";
|
|
1156
1168
|
var VIDEO_GENERATE_MODELS = [
|
|
1157
1169
|
"bytedance/seedance-2.0",
|
|
1158
1170
|
"google/gemini-omni-flash",
|
|
@@ -1161,6 +1173,10 @@ var VIDEO_GENERATE_MODELS = [
|
|
|
1161
1173
|
"kwaivgi/kling-v3.0-pro"
|
|
1162
1174
|
];
|
|
1163
1175
|
var DEFAULT_VIDEO_GENERATE_MODEL = "google/gemini-omni-flash";
|
|
1176
|
+
var REFERENCE_TO_VIDEO_MODELS = ["bytedance/seedance-2.0", "google/gemini-omni-flash"];
|
|
1177
|
+
function supportsReferenceToVideo(model) {
|
|
1178
|
+
return REFERENCE_TO_VIDEO_MODELS.includes(model);
|
|
1179
|
+
}
|
|
1164
1180
|
function isGeminiOmniModel(model) {
|
|
1165
1181
|
return model.startsWith("google/gemini-omni");
|
|
1166
1182
|
}
|
|
@@ -1265,12 +1281,18 @@ var MODEL_REGISTRY = {
|
|
|
1265
1281
|
// no `image_size` (OpenAI picks the pixel dimensions from the ratio, and a
|
|
1266
1282
|
// `resolution` is silently ignored) and the narrower `..._AR_GPT` ratio set.
|
|
1267
1283
|
"openai/gpt-image-2": {
|
|
1284
|
+
// Its live endpoint also advertises `background` (auto|opaque) and
|
|
1285
|
+
// `output_compression` (0-100), which we deliberately do not declare. Not an
|
|
1286
|
+
// oversight: a registry param is a promise the whole system keeps — the
|
|
1287
|
+
// canvas node schema, the dashboard control, the CLI flag and the cost model
|
|
1288
|
+
// all have to carry it — and neither knob changes what the picture IS.
|
|
1289
|
+
// Declaring them would widen four surfaces to expose a file-size dial.
|
|
1268
1290
|
label: "OpenAI GPT Image 2",
|
|
1269
1291
|
inputs: [],
|
|
1270
|
-
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES }],
|
|
1292
|
+
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES, max: GPT_IMAGE_MAX_REFERENCES }],
|
|
1271
1293
|
required: ["prompt"],
|
|
1272
1294
|
params: {
|
|
1273
|
-
prompt: { kind: "string" },
|
|
1295
|
+
prompt: { kind: "string", maxLength: GPT_IMAGE_PROMPT_MAX },
|
|
1274
1296
|
aspect_ratio: { kind: "string", enum: OPENROUTER_IMAGE_AR_GPT },
|
|
1275
1297
|
quality: { kind: "string", enum: OPENROUTER_IMAGE_QUALITY }
|
|
1276
1298
|
}
|
|
@@ -1285,10 +1307,10 @@ var MODEL_REGISTRY = {
|
|
|
1285
1307
|
"openai/gpt-5.4-image-2": {
|
|
1286
1308
|
label: "OpenAI GPT-5.4 Image 2 (legacy)",
|
|
1287
1309
|
inputs: [],
|
|
1288
|
-
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES }],
|
|
1310
|
+
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES, max: GPT_IMAGE_MAX_REFERENCES }],
|
|
1289
1311
|
required: ["prompt"],
|
|
1290
1312
|
params: {
|
|
1291
|
-
prompt: { kind: "string" },
|
|
1313
|
+
prompt: { kind: "string", maxLength: GPT_IMAGE_PROMPT_MAX },
|
|
1292
1314
|
aspect_ratio: { kind: "string", enum: OPENROUTER_IMAGE_AR },
|
|
1293
1315
|
image_size: { kind: "string", enum: OPENROUTER_IMAGE_SIZE },
|
|
1294
1316
|
quality: { kind: "string", enum: OPENROUTER_IMAGE_QUALITY }
|
|
@@ -1297,7 +1319,7 @@ var MODEL_REGISTRY = {
|
|
|
1297
1319
|
"google/gemini-3.1-flash-image-preview": {
|
|
1298
1320
|
label: "Google Gemini 3.1 Flash Image (Preview)",
|
|
1299
1321
|
inputs: [],
|
|
1300
|
-
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES }],
|
|
1322
|
+
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES, max: GEMINI_IMAGE_MAX_REFERENCES }],
|
|
1301
1323
|
required: ["prompt"],
|
|
1302
1324
|
params: {
|
|
1303
1325
|
prompt: { kind: "string" },
|
|
@@ -1322,7 +1344,7 @@ var MODEL_REGISTRY = {
|
|
|
1322
1344
|
// Source: GET /api/v1/images/models/google/gemini-3.1-flash-lite-image/endpoints.
|
|
1323
1345
|
label: "Google Gemini 3.1 Flash Lite Image",
|
|
1324
1346
|
inputs: [],
|
|
1325
|
-
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES }],
|
|
1347
|
+
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES, max: GEMINI_IMAGE_MAX_REFERENCES }],
|
|
1326
1348
|
required: ["prompt"],
|
|
1327
1349
|
params: {
|
|
1328
1350
|
prompt: { kind: "string" },
|
|
@@ -1333,7 +1355,7 @@ var MODEL_REGISTRY = {
|
|
|
1333
1355
|
"google/gemini-3-pro-image-preview": {
|
|
1334
1356
|
label: "Google Gemini 3 Pro Image (Nano Banana Pro)",
|
|
1335
1357
|
inputs: [],
|
|
1336
|
-
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES }],
|
|
1358
|
+
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES, max: GEMINI_IMAGE_MAX_REFERENCES }],
|
|
1337
1359
|
required: ["prompt"],
|
|
1338
1360
|
params: {
|
|
1339
1361
|
prompt: { kind: "string" },
|
|
@@ -1345,14 +1367,24 @@ var MODEL_REGISTRY = {
|
|
|
1345
1367
|
}
|
|
1346
1368
|
},
|
|
1347
1369
|
"recraft/recraft-v4.1-pro-vector": {
|
|
1370
|
+
// The vector/logo tier, and the odd one out of this roster in three ways.
|
|
1371
|
+
// All three are read off its live endpoint schema, and all three are the
|
|
1372
|
+
// kind of fact that only shows up as a billed 400 if it is guessed:
|
|
1373
|
+
// - it renders FIVE ratios (no 4:5 / 5:4 / 2:3 / 3:2 / 21:9), so portrait
|
|
1374
|
+
// ad shapes snap to 3:4 rather than being sent as-is;
|
|
1375
|
+
// - it has NO resolution knob (`supported_parameters` lists none), so
|
|
1376
|
+
// `image_size` is refused here instead of accepted and ignored;
|
|
1377
|
+
// - it takes exactly ONE reference image, against 14-16 everywhere else.
|
|
1378
|
+
// Its palette levers are real but arrive as provider passthrough
|
|
1379
|
+
// (`controls`), which is why they are `json` rather than typed enums; the
|
|
1380
|
+
// backend adapter builds that block in `buildImageGenBody`.
|
|
1348
1381
|
label: "Recraft v4.1 Pro Vector",
|
|
1349
1382
|
inputs: [],
|
|
1350
|
-
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES }],
|
|
1383
|
+
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES, max: RECRAFT_MAX_REFERENCES }],
|
|
1351
1384
|
required: ["prompt"],
|
|
1352
1385
|
params: {
|
|
1353
|
-
prompt: { kind: "string" },
|
|
1354
|
-
aspect_ratio: { kind: "string", enum:
|
|
1355
|
-
image_size: { kind: "string", enum: OPENROUTER_IMAGE_SIZE },
|
|
1386
|
+
prompt: { kind: "string", maxLength: RECRAFT_PROMPT_MAX },
|
|
1387
|
+
aspect_ratio: { kind: "string", enum: RECRAFT_IMAGE_AR },
|
|
1356
1388
|
strength: { kind: "number", min: 0, max: 1 },
|
|
1357
1389
|
rgb_colors: { kind: "json" },
|
|
1358
1390
|
background_rgb_color: { kind: "json" }
|
|
@@ -1437,19 +1469,22 @@ var MODEL_REGISTRY = {
|
|
|
1437
1469
|
// wrongly recommended and which sends you round the same loop.
|
|
1438
1470
|
label: "ByteDance Seedance 2.0",
|
|
1439
1471
|
inputs: [],
|
|
1440
|
-
optional_inputs: [{ kind: "image", mimes: REPLICATE_IMAGE_MIMES }],
|
|
1472
|
+
optional_inputs: [{ kind: "image", mimes: REPLICATE_IMAGE_MIMES, max: SEEDANCE_MAX_REFERENCES }],
|
|
1441
1473
|
required: ["prompt"],
|
|
1442
1474
|
params: {
|
|
1443
1475
|
// Replicate's Seedance wrapper hard-caps the prompt at 4000 chars; gate
|
|
1444
1476
|
// it here so an over-length prompt fails validate (free) not the billed call.
|
|
1445
|
-
prompt: { kind: "string", maxLength:
|
|
1477
|
+
prompt: { kind: "string", maxLength: SEEDANCE_PROMPT_MAX },
|
|
1446
1478
|
aspect_ratio: {
|
|
1447
1479
|
kind: "string",
|
|
1448
1480
|
enum: ["1:1", "3:4", "9:16", "4:3", "16:9", "21:9", "9:21"]
|
|
1449
1481
|
},
|
|
1450
1482
|
resolution: { kind: "string", enum: ["480p", "720p", "1080p", "4k"] },
|
|
1451
1483
|
duration: { kind: "number", enum: SEEDANCE_DURATIONS },
|
|
1452
|
-
seed
|
|
1484
|
+
// Replicate types this `integer`, and a fractional seed is a schema
|
|
1485
|
+
// rejection rather than a rounded one. No range is advertised, so none is
|
|
1486
|
+
// invented — see `InputSpec.max` on why absent must stay ungated.
|
|
1487
|
+
seed: { kind: "number", integer: true },
|
|
1453
1488
|
generate_audio: { kind: "boolean" }
|
|
1454
1489
|
}
|
|
1455
1490
|
},
|
|
@@ -1505,7 +1540,8 @@ var MODEL_REGISTRY = {
|
|
|
1505
1540
|
aspect_ratio: { kind: "string", enum: ["16:9", "9:16"] },
|
|
1506
1541
|
resolution: { kind: "string", enum: ["720p", "1080p", "4K"] },
|
|
1507
1542
|
duration: { kind: "number", enum: [4, 6, 8] },
|
|
1508
|
-
seed
|
|
1543
|
+
// Vertex declares `seed` a uint32: "accepted range 0-4294967295".
|
|
1544
|
+
seed: { kind: "number", integer: true, min: 0, max: VEO_SEED_MAX },
|
|
1509
1545
|
generate_audio: { kind: "boolean" },
|
|
1510
1546
|
person_generation: { kind: "string", enum: ["allow_all", "allow_adult"] },
|
|
1511
1547
|
enhance_prompt: { kind: "boolean" },
|
|
@@ -1529,9 +1565,10 @@ var MODEL_REGISTRY = {
|
|
|
1529
1565
|
required: ["prompt"],
|
|
1530
1566
|
params: {
|
|
1531
1567
|
// Kling caps the prompt shorter than Seedance; gate it here so an
|
|
1532
|
-
// over-length prompt fails validate (free) not the billed call.
|
|
1533
|
-
prompt
|
|
1534
|
-
|
|
1568
|
+
// over-length prompt fails validate (free) not the billed call. Its
|
|
1569
|
+
// negative prompt is a SEPARATE 2,500 budget, not a shared one.
|
|
1570
|
+
prompt: { kind: "string", maxLength: KLING_PROMPT_MAX },
|
|
1571
|
+
negative_prompt: { kind: "string", maxLength: KLING_PROMPT_MAX },
|
|
1535
1572
|
aspect_ratio: { kind: "string", enum: ["16:9", "9:16", "1:1"] },
|
|
1536
1573
|
resolution: { kind: "string", enum: ["720p"] },
|
|
1537
1574
|
duration: { kind: "number", enum: KLING_DURATIONS },
|
|
@@ -1552,7 +1589,7 @@ var MODEL_REGISTRY = {
|
|
|
1552
1589
|
aspect_ratio: { kind: "string", enum: ["16:9", "9:16"] },
|
|
1553
1590
|
resolution: { kind: "string", enum: ["720p", "1080p", "4K"] },
|
|
1554
1591
|
duration: { kind: "number", enum: [4, 6, 8] },
|
|
1555
|
-
seed: { kind: "number" },
|
|
1592
|
+
seed: { kind: "number", integer: true, min: 0, max: VEO_SEED_MAX },
|
|
1556
1593
|
generate_audio: { kind: "boolean" },
|
|
1557
1594
|
// Image-to-video and EU/UK/CH/MENA regions cap this at `allow_adult`;
|
|
1558
1595
|
// `allow_all` is text-to-video only. Allow both so an image-conditioned
|
|
@@ -1715,6 +1752,22 @@ var MODEL_REGISTRY = {
|
|
|
1715
1752
|
function supportsParam(kind, model, param) {
|
|
1716
1753
|
return MODEL_REGISTRY[kind]?.[model]?.params[param] !== void 0;
|
|
1717
1754
|
}
|
|
1755
|
+
var DEFAULT_CLIP_DURATION_S = 5;
|
|
1756
|
+
function nearestClipDuration(model, preferred) {
|
|
1757
|
+
const schema = MODEL_REGISTRY.video_generate[model]?.params.duration;
|
|
1758
|
+
const allowed = schema?.kind === "number" ? schema.enum : void 0;
|
|
1759
|
+
if (!allowed?.length || allowed.includes(preferred)) return preferred;
|
|
1760
|
+
return [...allowed].sort((a, b) => Math.abs(a - preferred) - Math.abs(b - preferred) || a - b)[0];
|
|
1761
|
+
}
|
|
1762
|
+
function promptMaxLength(kind, model) {
|
|
1763
|
+
const schema = MODEL_REGISTRY[kind]?.[model]?.params.prompt;
|
|
1764
|
+
return schema?.kind === "string" ? schema.maxLength : void 0;
|
|
1765
|
+
}
|
|
1766
|
+
function maxInputReferences(kind, model) {
|
|
1767
|
+
const spec = MODEL_REGISTRY[kind]?.[model];
|
|
1768
|
+
const slot = spec?.optional_inputs?.find((input) => input.kind === "image") ?? spec?.inputs.find((input) => input.kind === "image");
|
|
1769
|
+
return slot?.max;
|
|
1770
|
+
}
|
|
1718
1771
|
function supportedAspectRatios(kind, model) {
|
|
1719
1772
|
const schema = MODEL_REGISTRY[kind]?.[model]?.params.aspect_ratio;
|
|
1720
1773
|
return schema?.kind === "string" ? schema.enum : void 0;
|
|
@@ -1859,6 +1912,9 @@ function validateNumberValue(key, value, schema, model) {
|
|
|
1859
1912
|
message: `${key}: ${value} not allowed by "${model}" (allowed: ${schema.enum.join(", ")})`
|
|
1860
1913
|
};
|
|
1861
1914
|
}
|
|
1915
|
+
if (schema.integer && !Number.isInteger(value)) {
|
|
1916
|
+
return { code: "invalid_value", param: key, message: `${key}: ${value} must be a whole number` };
|
|
1917
|
+
}
|
|
1862
1918
|
if (schema.min !== void 0 && value < schema.min) {
|
|
1863
1919
|
return { code: "invalid_value", param: key, message: `${key}: ${value} below min ${schema.min}` };
|
|
1864
1920
|
}
|
|
@@ -7258,7 +7314,7 @@ var ImageGenerateParams = z17.object({
|
|
|
7258
7314
|
model: imageModelEnum,
|
|
7259
7315
|
prompt: z17.string().min(1),
|
|
7260
7316
|
aspect_ratio: z17.enum(["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "4:5", "5:4", "21:9", "1:4", "4:1", "1:8", "8:1"]).optional(),
|
|
7261
|
-
image_size: z17.enum(
|
|
7317
|
+
image_size: z17.enum(OPENROUTER_IMAGE_SIZES).optional(),
|
|
7262
7318
|
// Rendering quality. OpenRouter models without a quality knob ignore it; the
|
|
7263
7319
|
// registry gates which models accept it (gpt-image, Gemini).
|
|
7264
7320
|
quality: z17.enum(["auto", "low", "medium", "high"]).optional(),
|
|
@@ -7292,7 +7348,7 @@ var ImageAspectAdaptParams = z18.object({
|
|
|
7292
7348
|
formats: z18.array(z18.enum(ASPECT_ADAPT_FORMATS)).min(1).max(6).refine((formats) => new Set(formats).size === formats.length, { message: "formats must be unique" }).optional(),
|
|
7293
7349
|
platform: z18.enum(AD_FORMAT_PLATFORMS).optional(),
|
|
7294
7350
|
guidance: z18.string().min(1).optional(),
|
|
7295
|
-
image_size: z18.enum(
|
|
7351
|
+
image_size: z18.enum(OPENROUTER_IMAGE_SIZES).optional()
|
|
7296
7352
|
}).strict().refine((p) => p.formats === void 0 !== (p.platform === void 0), {
|
|
7297
7353
|
message: "provide exactly one of `formats` (explicit ratios) or `platform` (a placement preset)",
|
|
7298
7354
|
path: ["formats"]
|
|
@@ -7378,7 +7434,7 @@ var ImageReferenceSheetParams = z21.object({
|
|
|
7378
7434
|
style: z21.string().optional(),
|
|
7379
7435
|
prompt_override: z21.string().min(1).optional(),
|
|
7380
7436
|
aspect_ratio: z21.enum(["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "4:5", "5:4", "21:9", "1:4", "4:1", "1:8", "8:1"]).optional(),
|
|
7381
|
-
image_size: z21.enum(
|
|
7437
|
+
image_size: z21.enum(OPENROUTER_IMAGE_SIZES).optional()
|
|
7382
7438
|
}).strict();
|
|
7383
7439
|
var imageReferenceSheetNode = delegated({
|
|
7384
7440
|
id: "image_reference_sheet",
|
|
@@ -8148,12 +8204,20 @@ export {
|
|
|
8148
8204
|
SEEDANCE_DURATIONS,
|
|
8149
8205
|
ELEVENLABS_MAX_MUSIC_LENGTH_MS,
|
|
8150
8206
|
IMAGE_GENERATE_MODELS,
|
|
8207
|
+
DEFAULT_IMAGE_GENERATE_MODEL,
|
|
8208
|
+
VIDEO_GENERATE_MODELS,
|
|
8151
8209
|
DEFAULT_VIDEO_GENERATE_MODEL,
|
|
8210
|
+
supportsReferenceToVideo,
|
|
8152
8211
|
supportsLastFrame,
|
|
8153
8212
|
MODEL_REGISTRY,
|
|
8154
8213
|
supportsParam,
|
|
8214
|
+
DEFAULT_CLIP_DURATION_S,
|
|
8215
|
+
nearestClipDuration,
|
|
8216
|
+
promptMaxLength,
|
|
8217
|
+
maxInputReferences,
|
|
8155
8218
|
nearestSupportedAspectRatio,
|
|
8156
8219
|
nearestSupportedImageSize,
|
|
8220
|
+
estimateVideoCredits,
|
|
8157
8221
|
resolveConcurrency,
|
|
8158
8222
|
ulid,
|
|
8159
8223
|
isPersistedAssetRef,
|
|
@@ -8180,4 +8244,4 @@ export {
|
|
|
8180
8244
|
defaultRegistry,
|
|
8181
8245
|
createEngineFromEnv
|
|
8182
8246
|
};
|
|
8183
|
-
//# sourceMappingURL=chunk-
|
|
8247
|
+
//# sourceMappingURL=chunk-3TXZKSAR.js.map
|