pixelkiln 0.92.1 → 0.92.3

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/docs/ENDPOINTS.md CHANGED
@@ -27,6 +27,181 @@ listed so it is obvious what exists.
27
27
 
28
28
  ---
29
29
 
30
+ ## Validation ledger
31
+
32
+ Which PixelLab endpoints PixelKiln calls, and how much is actually known about
33
+ each, so live spending can be chosen by risk. Audited 5 November 2026 from
34
+ `src/client.ts`, `src/pixellab-vfx.ts`, this file, the other docs, the skill
35
+ references, the benchmark and showcase lockfiles, and git history. No PixelLab
36
+ call was made for it. Each row is one endpoint (or one tightly coupled family
37
+ of paths: a `POST` and the `GET` that polls it). The Evidence is the section
38
+ named in the "What is known" cell.
39
+
40
+ **Status**
41
+
42
+ - **Measured live**: a real call was billed and the completed response shape
43
+ was seen. The cell says what was measured.
44
+ - **Run live, not measured**: it ran against the account, but the bill or a
45
+ variant was not recorded.
46
+ - **Mock only**: wrapped and unit-tested against mocked HTTP, with no live run
47
+ in the docs.
48
+ - **Schema only**: wrapped from PixelLab's OpenAPI or MCP schema, with no live
49
+ run, and the docs call the completed-job shape or the price a guess.
50
+ - **Not wrapped**: PixelLab has it and PixelKiln does not call it.
51
+ - **Unknown**: the repo does not establish a status. See [Needs a human
52
+ look](#needs-a-human-look).
53
+
54
+ **Money at risk** is how much a wrong estimate or an unreadable response could
55
+ cost in one call: **Low** up to 3 generations, **Medium** 4 to 15, **High**
56
+ over 15, or billed per direction or per batch. Failed requests are not billed,
57
+ so a rejected body costs nothing; the exposure is an accepted job that bills
58
+ more than planned or finishes in a shape PixelKiln cannot read.
59
+
60
+ `target_palette` is sent on 17 routes since 0.92.0. Only `imagePro`,
61
+ `imageProFlash` and `tiles` ran live with it (each matched the plan); the other
62
+ 14 are mock only (`objectPro` base, state and `pro` animation, `1dir`, Pro
63
+ `terrain`, `uiAsset`, `uiElement`, Pro and Pro Flash character bases, states,
64
+ portraits, outfit transfer, `interpolate`, `edit-animation`), and their rows
65
+ say so. Since then `objectPro` base, `uiElement`, `interpolate` and
66
+ `edit-animation` have each run live (November 2026), but without a palette, so
67
+ the palette claim on them is still mock only.
68
+
69
+ **Free acceptance probe** (November 2026): for 13 of those 14 routes, a request
70
+ carrying only a valid four-colour `target_palette` and none of the required
71
+ fields was answered with `422`s that named the missing fields and nothing about
72
+ `target_palette`, while the same request with an invalid palette (a non-hex
73
+ colour, `max_colors` 999) was answered with two `target_palette` errors. So
74
+ PixelLab's validator knows the field and its shape on those routes, which a
75
+ mocked test cannot show. The probe cannot show that the palette is obeyed or what
76
+ the call costs, and a failed validation bills nothing. The 14th route,
77
+ `/objects/{id}/animations` (the `objectPro` `pro` animation), has no required
78
+ fields, so a palette-only request could have been accepted and billed; it was
79
+ not probed.
80
+
81
+ | Endpoint | PixelKiln feature | Status | What is known (cost / sizes / shape) | Gaps (never seen) | Money at risk |
82
+ |---|---|---|---|---|---|
83
+ | `GET /balance` | `doctor`, `gen` balance reads, gallery | Measured live | Free. Count is at `subscription.generations` ([Reproducing these numbers](#reproducing-these-numbers)). | Only the subscription shape is documented; a credit-only account's reply is not recorded. | Low |
84
+ | `GET /pro-flash/cost` | Pro Flash estimates for `character` and `imageProFlash` | Measured live | Free quote. For `operation=character`: image 5 up to 96px, 6 to 208px, 9 above, plus rotations; two live jobs (7 and 2) billed exactly the quote ([Characters, measured](#characters-measured)). | Quotes for `create`, `edit` and `inpaint` are recorded from PixelLab's MCP `get_pro_flash_capabilities`, not from this route (roadmap, "Pro Flash for plain image create, edit, and inpaint"). | Low |
85
+ | `GET /background-jobs/{id}` | every job poll; where the billed amount is read | Measured live | `usage` at the top level and again at `last_response.billing_usage`; confirmed for a `map` object (1), a standard character base (1) and the skeleton jobs ([Limits and billing](#limits-and-billing)). | Jobs are deleted 8 hours after finishing, so a bill not read in time is lost (the v3 base bill was). | Low |
86
+ | `POST /create-image-pixflux` | `pixflux` | Measured live | 1 generation, PNG inline, about 10 s; `color_image` is a hard palette lock (130 badges, 65 of 65 in each set) ([Single-image generators, measured](#single-image-generators-measured)). Ran in `benchmarks/provider-environments/pixellab`. | None recorded. | Low |
87
+ | `POST /map-objects` (+ `GET /map-objects/{id}`, falling back to `GET /objects`) | `map` | Measured live | 1 generation, job about 30 s; the job record expires after 8 hours but the image survives ([Object lifecycle](#object-lifecycle)). `color_image` returns 500. | The `scene` field (`background_image` + inpainting): "Unverified until a real call is billed" ([GENERATORS.md](./GENERATORS.md), `map`). | Low |
88
+ | `POST /generate-image-v2` | `imagePro` | Measured live | A 64×64 call billed 10 (40 before the cut) and 10 again with `target_palette`; the completed job was read and a candidate downloaded through `gen` ([October 2026 Pro price cut](#october-2026-pro-price-cut), [Target palette](#target-palette-target_palette)). | Canvases above 65536px² (15 and 25 tiers) are priced from the shared Pro ladder, not measured here; `reference_images` and `style_image` are unmodeled. | High |
89
+ | `POST /create-image-pro-flash` | `imageProFlash` | Measured live | A 32×32 still with a four-colour `target_palette` billed 5, in only those colours (November 2026; [GENERATORS.md](./GENERATORS.md#target-palette)). | Larger canvases (quote 9 at 256px) and the style-image path were never billed. | Medium |
90
+ | `POST /edit-image-pro-flash` | revision `engine: "pro-flash"`, `image-to-image` | Mock only | Quote 5 at 64px, provisional, from MCP (roadmap, "Pro Flash for plain image create, edit, and inpaint"). | Never billed; completed-job shape never read live; the `reference` edit method is unmodeled. | Medium |
91
+ | `POST /inpaint-image-pro-flash` | revision `engine: "pro-flash"`, `inpaint` | Mock only | Quotes 5 at 64px and 6 at 128px, provisional, from MCP (same roadmap entry). | Never billed; completed-job shape never read live; `context_image` and `output_methods` unmodeled. | Medium |
92
+ | `POST /image-to-pixelart-pro-flash` | `pixelkiln pixelate` | Measured live | A 256×256 and a 384×384 render each billed 6; the image is `last_response.images[0]`; the result is opaque on a near-white field ([Image to Pixel Art Pro Flash, measured](#image-to-pixel-art-pro-flash-measured)). | Whether 6 is flat above 384px or with a larger source. | Medium |
93
+ | `POST /inpaint-v3` | revision `inpaint` | Measured live | Nine pre-cut points from 32×32 to 512×512 (20 / 25 / 40); after the cut 256, 288, 352 and 384px billed 10, 15, 25, 25. `last_response.image` is a single object ([Limits and billing](#limits-and-billing), [October 2026 Pro price cut](#october-2026-pro-price-cut)). | The 20-to-25 break sits in (65536px², 82944px²] and 25-to-40 in (102400px², 123904px²]; 32px to 128px and 512px were not re-measured after the cut. | High |
94
+ | `POST /edit-images-v2` | revision `image-to-image` | Measured live | One 32×32 call billed 20 (before the cut); `images` is an array of `{type, base64, width, height}` ([Limits and billing](#limits-and-billing)). | Nothing above 32×32 and nothing after the cut; the plan borrows `proTierCost`. | High |
95
+ | `POST /remove-background` | revision `remove-background` | Measured live | 1 generation, synchronous `{usage, image}`; keeps the palette ([Post-processing utilities, measured](#post-processing-utilities-measured)). Measured as a loose call in the July 2026 reference. | The `complex` task and the foreground text hint (roadmap, "Remove background"). | Low |
96
+ | `POST /reduce-colors` | revision `reduce-colors` | Measured live | 0.1 generations at 32×32, balance diff and `usage` agree ([Cleanup tier, measured](#cleanup-tier-measured), September 2026). | Larger canvases; the price of a multi-frame set call is unmeasured. | Low |
97
+ | `POST /correct-pixelart` | revision `correct-pixelart` | Measured live | 0.1 generations at 32×32 ([Cleanup tier, measured](#cleanup-tier-measured)). | Larger canvases and multi-frame sets, as above. | Low |
98
+ | `POST /unzoom` | `pixelkiln unzoom` | Unknown | "Cost unmeasured; PixelLab's MCP tool description claims 0.1" ([Cleanup tier, measured](#cleanup-tier-measured)). Nothing records a live run. | Everything. | Low |
99
+ | `POST /normal-map` | revision `normal-map`, `pixelkiln normal-map` | Measured live | An 8-frame 1304×26 strip and a 64×64 revision each billed 0.5; the map comes back the input's size with matching alpha ([Normal map](#normal-map-post-normal-map-measured-once), October 2026). | The `directx` convention; strips near the 32-frame limit. | Low |
100
+ | `POST /generate-ui-v2` | `uiElement` | Measured live | A 32×32 call billed 10 and the review page showed 64 candidates at 32×32 (November 2026, Tier 3; the plan said 1 candidate and now follows `uiElementCandidateCount`). Planned on the 10/15/25 ladder ([GENERATORS.md](./GENERATORS.md#uielement)). `target_palette` sent, mock only. | Other sizes (the 15 and 25 tiers and the other candidate bands, which come from PixelLab's published grid), and the concept-image path. | High |
101
+ | `POST /create-1-direction-object` (+ `GET /objects/{id}`) | `1dir` | Measured live | A 32px, 3-description `batch` billed 20 (the pre-cut floor) and `item_descriptions[0]` owned slot 0 ([Candidates](#candidates)); candidate counts follow size. `target_palette` sent, mock only. | No bill since the October 2026 cut (10 / 15 / 25 is PixelLab's published ladder); tiers above the floor under `item_descriptions`. | High |
102
+ | `POST /objects/{id}/select-frames` | `1dir` and `batch` pick | Run live, not measured | Promoted three candidates in the live batch run ([Candidates](#candidates)); `indices` is plural. | Its cost was not recorded. | Low |
103
+ | `GET /objects?limit=&offset=` | `adopt`, `salvage` | Measured live | Free; a March 2026 sprite still resolved four months on ([Object lifecycle](#object-lifecycle)). | None recorded. | Low |
104
+ | `POST /create-object-pro-flash` | `objectPro` base | Measured live | A 32px base billed 6 and returned 8 files at 32×32 (the rotations), matching the plan, which prices it like `character` pro-flash (November 2026, Tier 3; [GENERATORS.md](./GENERATORS.md#objectpro)). `target_palette` sent, mock only. | Other sizes and the 1-generation `reference` path. | Medium |
105
+ | `POST /objects/{id}/states` | `objectPro` state | Mock only | Assumed to price like `character` pro-flash; the base ran live, this route did not. `target_palette` sent, mock only. | Price and shape. | Medium |
106
+ | `POST /objects/{id}/animations` | `objectPro` animation (`v3`, `pro`) | Mock only | Same assumption as the state row; `pro` mode is documented 10 to 25 per direction. `target_palette` sent on `pro` only, mock only. | Price, shape, per-direction billing. | High |
107
+ | `PATCH /objects/{id}/tags`, `PATCH /characters/{id}/tags` | tagging in `fetch`, `adopt`, `salvage` | Unknown | Only the negative is documented: pixflux, pixen and bitforge results "cannot be tagged" ([Object lifecycle](#object-lifecycle)). | A recorded live call. | Low |
108
+ | `DELETE /objects/{id}`, `POST /objects/{id}/dismiss-review`, `DELETE /characters/{id}` | `salvage`, account cleanup | Unknown | Not discussed in the docs. | A recorded live call. | Low |
109
+ | `DELETE /characters/{id}/animations` | replacing a loop's direction | Unknown | "Deleting one direction of a shared group has not been run live" ([Skeleton-driven motion, measured](#skeleton-driven-motion-measured)). | Whether the rest of the group keeps its motion. | Low |
110
+ | `POST /create-tiles-pro` (+ `GET /tiles-pro/{id}`) | `tiles` | Measured live | One numbered description, 4 tiles at 16px, with a Game Boy `target_palette`, billed 10, every candidate in the palette (November 2026). `GET` has no `status`: 423 while drawing ([Tilesets: measured once per kind](#tilesets-measured-once-per-kind)). | `tile_feature` sets (`roads`, `tileset`, `building`) and `tile_rules`; large tile-size × variation canvases that reach the top tier. | High |
111
+ | `POST /create-tileset` (+ `GET /tilesets/{id}`) | `terrain`, top-down | Measured live | Pro 32px billed 15 (three sets, one connected through `lower_base_tile_id`, one with edge slope); Pro 64px billed 25 and returned 25 tiles at transition 0.5; standard sets billed 3 each (planned 4), one connected through `upper_base_tile_id` ([Tilesets: measured once per kind](#tilesets-measured-once-per-kind), October 2026). `target_palette` on Pro, mock only. | Pro below 32px; standard above 32px; a standard set cannot connect to a Pro set. | High |
112
+ | `POST /create-tileset-sidescroller` | `terrain`, `terrainOrientation: "sidescroller"` | Measured live | One 16px set at transition 0.25 billed 3; 16 tiles; `usage` is null on the `GET`, so the bill comes from the job ([Tilesets: measured once per kind](#tilesets-measured-once-per-kind)). | 32px tiles and other transition sizes (tile counts assumed 16); the call returned `metadata.transition_size: 0.0` for 0.25. | Low |
113
+ | `POST /create-isometric-tile` (+ `GET /isometric-tiles/{id}`) | `isometricTile` | Measured live | One 32px `block` billed 1 generation, not the schema's `usd: 0.02` example ([Standalone isometric tile](#standalone-isometric-tile-schema-documented-cost-measured-once)). | Other sizes and shapes; flat pricing across 16 to 64px is an assumption. | Low |
114
+ | `POST /create-ui-asset` (+ `GET /ui-assets/{id}`) | `uiAsset` | Measured live | One 256×192 call billed 20, the low end of the quoted 20 to 40; the plan prices 40 ([UI panels](#ui-panels-one-endpoint-schema-documented-cost-unverified), September 2026). | A second size; `pixelkiln plan` over-reads. | High |
115
+ | `POST /generate-font-pro` (+ `GET /generate-font-pro/{id}`) | `pixelkiln font` | Unknown | Documented at 15 since the cut; "its cost is not yet measured" ([Not yet explored](#not-yet-explored)). Nothing records a live run. | Price and the non-`{usage, image}` response shape. | Medium |
116
+ | `POST /create-character-with-8-directions`, `/create-character-with-4-directions` | `character` base, `mode: standard` | Measured live | 1 generation (read from the job's `usage`); canvas 28px larger than `image_size` ([Limits and billing](#limits-and-billing), [Characters, measured](#characters-measured), September 2026). | The 4-direction body and quadruped templates are not recorded. | Low |
117
+ | `POST /create-character-v3` | `character` base, `mode: v3` | Run live, not measured | A base once recorded `billed: {amount: 0, unit: "usd"}` against an estimate of 2 while the submit reported 1 generation; the job had expired, so the real bill is unseen ([Limits and billing](#limits-and-billing)). | The real bill at any size. | Low (Medium at 256px, 9) |
118
+ | `POST /create-character-pro` | `character` base, `mode: pro` | Unknown | Planned 10 to 25 by canvas ([GENERATORS.md](./GENERATORS.md)). No bill recorded in the docs. `target_palette` sent, mock only. | Everything. | High |
119
+ | `POST /create-character-pro-flash` | `character` base, `mode: pro-flash` | Measured live | Two live jobs (7 and 2, the second from a `reference`) billed exactly the estimate; returns exactly the requested canvas ([Characters, measured](#characters-measured), September 2026). `target_palette` sent, mock only. | Sizes beyond 96px; `source_image_id` and the style-image path. | High |
120
+ | `POST /create-character-state` | `character` state | Run live, not measured | A 64px state "moved the balance by about 22 against the 20 to 40 tier", with other jobs running ([Characters, measured](#characters-measured)). `target_palette` sent, mock only. | A clean bill, and any bill since the cut. | High |
121
+ | `POST /animate-character`, `mode` template or v3 | `character` loops without skeleton-v3 | Run live, not measured | A v3 text loop on a 96px pro-flash base came back 108×108; template loops need a skeleton template ([Characters, measured](#characters-measured)). Plan: template 1, v3 `ceil(size² × frames / 65536)`. | Billed amounts were not recorded; billed per direction. | High |
122
+ | `POST /animate-character`, `mode: pro` | `character` loops, `mode: pro` | Unknown | Planned 10 to 25 by canvas ([GENERATORS.md](./GENERATORS.md)). Nothing records a live run. | Everything. | High |
123
+ | `POST /characters/animations`, `mode: skeleton-v3` | `character` loops, `mode: "skeleton-v3"` (template or sentence) | Measured live | On a v3 character: a template loop billed 3; a sentence loop (no template) billed 3, 8 frames at 96×96 from a 64px character; `west` added with `animation_group_id` billed 3 and joined the group. A standard-engine character is refused with a 500 "no stored 3D skeleton" ([Skeleton-driven motion, measured](#skeleton-driven-motion-measured), October 2026). | `pro` and `pro-flash` bases; other frame counts; the price per direction across 8 directions is untested. | High |
124
+ | `POST /portrait-character-pro` (+ `GET /portrait-character-pro/{job_id}`) | `character` portrait | Measured live | A 16px `character_to_portrait` billed 20 (before the cut); the `GET` reports `usage: null`, so read the job ([Characters, measured](#characters-measured)). `target_palette` sent, mock only. | The price after the cut (10 to 25); larger sizes. | High |
125
+ | `POST /characters/{id}/portrait` | `character` portrait attach | Measured live | Free (`usage.generations: 0`); the reply holds the only copy of the stored URL ([Characters, measured](#characters-measured)). | None recorded. | Low |
126
+ | `POST /transfer-outfit-v2` | `character` outfit | Measured live | A 2-frame 92×92 job billed 20 (before the cut); frames return inline in `last_response.quantized_images` ([Characters, measured](#characters-measured)). `target_palette` sent, mock only. | Other frame counts (2 to 16) and canvases; the price after the cut. | High |
127
+ | `GET /characters/{id}`, `GET /characters?limit=&offset=` | `adopt`, `fetch --refresh`, `salvage` | Measured live | Free; carries no `usage`; image URLs carry `?t=<updated_at>` ([Object lifecycle](#object-lifecycle)). | None recorded. | Low |
128
+ | `POST /animate-with-text-v3` | revision `animate` | Measured live | A 64×64, 4-frame call billed 1 and returned 5 frames at 64×64 (the input frame plus 4); the plan, which borrows `character`'s v3 formula, said 1 (November 2026, Tier 3; [REVISIONS.md](./REVISIONS.md#animation-and-interpolation)). | Other sizes and frame counts (up to 16 frames at 256px reads 16 by the borrowed formula). | Medium |
129
+ | `POST /animate-pixminimax` | revision `animate-pixminimax` | Measured live | 64×64 at 8 frames billed 1 and returned 9 frames at 64×64 (the input frame plus 8); at 16 frames billed 2 and returned 17. The plan said 1 for the 16-frame call because its old placeholder under-read; it now follows PixelLab's published table (64×64 at 4 / 8 / 16 / 40 frames: 1 / 1 / 2 / 6), see `pixMiniMaxCost` (November 2026, Tier 3; [roadmap](../skills/pixelkiln/references/pixellab-roadmap.md), "Generated effects with PixMiniMax"). | 40 frames and other sizes are unbilled (the table is PixelLab's, not a bill); `enhance_prompt`'s 0.05 is the schema's number. | Medium |
130
+ | `POST /animate-with-skeleton-v3` | revision `animate-skeleton` | Measured live | 8 frames at 64×64 billed 3 and returned 8 frames at 64×64; `description` and `action` are both required, and sent with neither the endpoint returns 422 ([Skeleton-driven motion, measured](#skeleton-driven-motion-measured), October 2026). | Other frame counts (3 = 2 and 15 = 4 are PixelLab's anchors, unbilled). | Low |
131
+ | `POST /estimate-skeleton` | `pixelkiln estimate-skeleton`, gallery pose helper | Run live, not measured | Ran on a 64×64 sprite before the 8-frame revision ([REVISIONS.md](./REVISIONS.md#skeleton-driven-animation)). | Its cost; the reply's `usage` is typed `unknown`. | Low |
132
+ | `POST /interpolation-v2` | revision `interpolate` | Measured live | A 64×64 start sprite with a `lastFrame` keyframe and the default frame count billed 10 and returned 14 frames at 64×64 (November 2026, Tier 3; [REVISIONS.md](./REVISIONS.md#interpolate-between-two-keyframes)). The planner said 25, a 2.5× over-read, and now prices the canvas on the 10/15/25 ladder. `target_palette` sent, mock only. | Canvases above 65536px² (15 and 25 tiers, unbilled) and other frame counts. | High |
133
+ | `POST /edit-animation-v2` | revision `edit-animation` | Measured live | One text edit of a 9-frame 64×64 set billed 10 and the edited set was accepted into review (November 2026, Tier 3). The planner said 25 and now prices the packed grid (nine 64×64 frames: 192×192) on the same ladder. `target_palette` sent, mock only. | Larger sets and canvases, where the packed grid crosses 65536px² (unbilled, assumed to follow the ladder). | High |
134
+ | `POST /vfx`, lite artist, no sprite | `pixelkiln vfx --description`, `vfx` block `description` | Measured live | One effect billed 1 (balance 5104 to 5103); 163×26, 8 frames, sheet and atlas cut into 8 correct frames ([VFX artist](#vfx-artist-post-vfx-measured-once), October 2026). | The `files` shape (list or map) is undocumented; PixelKiln reads three. | Low |
135
+ | `POST /vfx`, sprite, pro artist, `effect_id` change or `game_pack` | same | Mock only | Quoted from the OpenAPI table: pro 6 (8 with a sprite), 14 and 28 for larger sprites; plans count twice the quote ([VFX artist](#vfx-artist-post-vfx-measured-once)). | Every variant above. | High |
136
+ | MCP `tools/call` `vfx_workbench` at `api.pixellab.ai/mcp` | `pixelkiln vfx`, `vfx` block `preset` or `recipe` | Measured live | Free on a subscription; same recipe re-rendered byte-identical; exports a sheet, GIF, atlas and optional game pack ([VFX workbench (MCP only), measured](#vfx-workbench-mcp-only-measured), October 2026). | "Busy, retry" is the only recorded error; sprites by asset are not wired. | Low |
137
+ | `POST /create-image-pixen`, `/create-image-bitforge` | none | Not wrapped | Each 1 generation; bitforge returned blobs for a simple prompt ([Single-image generators, measured](#single-image-generators-measured)). | n/a | n/a |
138
+ | `POST /rotate`, `/resize`, `/image-to-pixelart` | none | Not wrapped | Each 1 generation; all three break a locked palette ([Post-processing utilities, measured](#post-processing-utilities-measured)). | n/a | n/a |
139
+ | `POST /inpaint`, `/edit-image` (not v2 or v3) | none | Not wrapped | "Untouched by any of this" ([Not yet explored](#not-yet-explored)). | n/a | n/a |
140
+ | `POST /generate-with-style-v2`, `/image-to-pixelart-pro`, `/create-8-direction-object` | none | Not wrapped | Style transfer at 20 before the cut, not re-measured; `objectPro` covers the 8-direction object. | n/a | n/a |
141
+ | `POST /animate-with-text-v2`, `/generate-8-rotations-v2`, `/tilesets`, `/tilesets-sidescroller`, legacy `/animate-with-skeleton` | none | Not wrapped | PixelKiln calls the `/create-tileset*` aliases, not `/tilesets*`; the legacy skeleton route takes exactly 3 frames (roadmap, "The legacy `/animate-with-skeleton`"). | n/a | n/a |
142
+ | Character lip-sync, vocal animation, talking GIF, `portrait_to_character` | none | Not wrapped | Named out of scope in [PIXELLAB.md](./PIXELLAB.md). | n/a | n/a |
143
+
144
+ ### Where a wrong guess costs money
145
+
146
+ The High and Medium rows that are Mock only, Schema only or Run live, not
147
+ measured, most exposed first. A live run of the top ones also settles the most
148
+ uncertainty per generation.
149
+
150
+ 1. **`/objects/{id}/animations`, `/objects/{id}/states`** (Mock only).
151
+ `objectPro` assumes `character` pro-flash prices; the base ran live and
152
+ matched (6 at 32px), but its `pro` animations are 10 to 25 per direction.
153
+ 2. **`/animate-character` template and v3** (Run live, not measured). One job
154
+ per direction, so an 8-direction loop is eight bills no one has recorded.
155
+ 3. **`/create-character-state`** (Run live, not measured). One rough bill
156
+ (about 22) taken beside other jobs and before the cut.
157
+ 4. **`/vfx` with a sprite, the pro artist, a change or a game pack** (Mock
158
+ only). Up to 28 generations a call, and plans reserve twice the quote.
159
+ 5. **`/edit-image-pro-flash`, `/inpaint-image-pro-flash`** (Mock only). 5 to 6
160
+ per call on provisional quotes, no completed response seen.
161
+ 6. **`/create-character-v3`** (Run live, not measured). 2 at 64px, up to 9 at
162
+ 256px, and the one recorded bill was an unreadable zero.
163
+
164
+ Measured in November 2026 and no longer on this list: `/animate-pixminimax`,
165
+ `/animate-with-text-v3`, `/interpolation-v2`, `/edit-animation-v2`,
166
+ `/generate-ui-v2` and the `objectPro` base. Their remaining exposure is the
167
+ sizes and frame counts the row says were not billed. Two of the planners were
168
+ wrong: `interpolate` and `edit-animation` over-read 2.5× (25 planned, 10 billed)
169
+ and `animate-pixminimax` under-read a 16-frame clip (1 planned, 2 billed). Both
170
+ are now calibrated to those bills, and the PixMiniMax planner follows PixelLab's
171
+ published points at 4, 8, 16 and 40 frames, which the 40-frame point has not
172
+ been billed against.
173
+
174
+ Also worth a second look because they are measured on an old price list: the
175
+ `1dir`, `/portrait-character-pro`, `/transfer-outfit-v2` and `/edit-images-v2`
176
+ bills all predate the October 2026 cut, and `/inpaint-v3` was only re-measured
177
+ from 256px to 384px.
178
+
179
+ ### Needs a human look
180
+
181
+ The repo does not establish whether or how these ran live:
182
+
183
+ - `POST /create-character-pro` and `POST /animate-character` with
184
+ `mode: "pro"`: the docs plan 10 to 25 and record no bill.
185
+ - `POST /generate-font-pro`: documented price only (`pixelkiln font`).
186
+ - `POST /unzoom`: documented price only (`pixelkiln unzoom`).
187
+ - `PATCH` tags on objects and characters, `DELETE /objects/{id}`,
188
+ `DELETE /characters/{id}`, `POST /objects/{id}/dismiss-review`: used by
189
+ `fetch`, `adopt` and `salvage`, and no doc records a live call.
190
+ - `DELETE /characters/{id}/animations`: only the one-direction-of-a-shared-group
191
+ case is called out as not run.
192
+
193
+ ### Keeping the ledger current
194
+
195
+ Update the row in the same change that records a live call. When a call is
196
+ billed, take the amount from the finished job's `usage` (or
197
+ `last_response.billing_usage`), not from a balance diff taken straight after,
198
+ since billing lags; read it before the job record expires 8 hours later. Move
199
+ the row's status, write the measurement and its month into "What is known",
200
+ and remove the gap it closes. If a call ran but the bill was not captured,
201
+ set the row to Run live, not measured rather than leaving it Mock only.
202
+
203
+ ---
204
+
30
205
  ## Single-image generators, measured
31
206
 
32
207
  The endpoints that produce one standalone image. This is the decision that
@@ -54,10 +229,10 @@ canvas like the other Pro tools: a 64×64 call billed exactly 10.
54
229
  `generate-image-v2` is wrapped by pixelkiln's `imagePro` generator
55
230
  (skills/pixelkiln/references/pixellab.md): non-square and larger canvases
56
231
  than `pixflux` allows, at the 10–25 above. Its `reference_images` and
57
- `style_image` are not modeled, and its completed job's response shape is
58
- inferred from `edit-images-v2`'s (also unmeasured for this endpoint
59
- specifically) rather than confirmed live — see `pollImagePro` in
60
- `src/providers/pixellab.ts`. `generate-with-style-v2` is not wrapped at all.
232
+ `style_image` are not modeled. Its completed job was read live (a 64×64
233
+ call, October 2026, ran through `gen` and downloaded a picked candidate);
234
+ `pollImagePro` in `src/providers/pixellab.ts` still reads it defensively.
235
+ `generate-with-style-v2` is not wrapped at all.
61
236
 
62
237
  ### What the measurements actually showed
63
238
 
@@ -265,8 +440,10 @@ PixelLab 0.4.130 added a beta `target_palette` body field, then gave it to 27
265
440
  POST endpoints: `{ colors?: 2-256 hex, name?: string (≤100), max_colors?: 2-64,
266
441
  smart?: boolean }`. With `colors` every pixel is one of them; `max_colors` caps
267
442
  each image. The schema is documentation only so far: **cost with a palette is
268
- measured for `generate-image-v2` alone** (a 64×64 call billed 10, the same as
269
- without), and the rest are unmeasured. PixelKiln never sends `smart` (beta,
443
+ measured for three routes**: `generate-image-v2` (a 64×64 call billed 10, the
444
+ same as without), `create-image-pro-flash` (a 32×32 still billed 5) and
445
+ `create-tiles-pro` (4 tiles at 16px billed 10), each matching the plan. The
446
+ other 14 routes PixelKiln sends it to are mock only. PixelKiln never sends `smart` (beta,
270
447
  "single images only", needs `colors`, adds 15 to 60 s).
271
448
 
272
449
  | Endpoint | PixelKiln wrapper | Sent |
@@ -447,8 +624,8 @@ exactly its quote at 32px and 64px, and standard billed 3, under the plan.
447
624
 
448
625
  `POST /tilesets` (top-down) and `/tilesets-sidescroller` are the current
449
626
  versions; `/create-tileset*` are the older aliases with identical schemas.
450
- Both are wrapped by pixelkiln's `terrain` generator
451
- (skills/pixelkiln/references/pixellab.md), the sidescroller one with
627
+ pixelkiln's `terrain` generator
628
+ (skills/pixelkiln/references/pixellab.md) calls the aliases, the sidescroller one with
452
629
  `terrainOrientation: "sidescroller"`; the reference-image/`color_image`
453
630
  knobs below are not.
454
631
 
@@ -560,8 +737,9 @@ That is the only way to land new art on an existing sheet's ground plane.
560
737
 
561
738
  `GET /tiles-pro/{id}` carries no `status` field. It answers **423 while the set
562
739
  is still drawing** and 200 with `storage_urls` when it is done, so the HTTP code
563
- is the status. Cost is reported at submit time and lands on the same 20/25/40
564
- canvas tiers as `1dir`, but the canvas is tile size x variation count, not one
740
+ is the status. Cost is reported at submit time and lands on the same canvas
741
+ tiers as `1dir` (10/15/25 since the October 2026 cut, 20/25/40 before; a 4-tile
742
+ 16px set billed 10), but the canvas is tile size x variation count, not one
565
743
  sprite. A small tile in a large set still reaches the top tier.
566
744
 
567
745
  All response shapes used by the client are validated at runtime. The TypeScript
@@ -892,15 +1070,15 @@ Listed so the gaps are known rather than assumed away:
892
1070
  across every frame of a set) are wired the same way, as the `interpolate`
893
1071
  and `edit-animation` modes; see
894
1072
  [Interpolate between two keyframes](./REVISIONS.md#interpolate-between-two-keyframes).
895
- All four are schema-only for the *request* (live OpenAPI document, not an
896
- observed call); the *completed job* response shape is a genuine unknown —
897
- no usage example exists for either endpoint at all, only the generic
898
- background-job one — so `pollAnimateRevision` checks several plausible
899
- field names defensively rather than assume one. Cost borrows `character`'s
900
- own measured v3-loop formula as a placeholder, for the same reason
901
- `objectPro` borrowed `character` pro-flash's; `interpolate` and
902
- `edit-animation` borrow the 20/25/40 Pro canvas tiers instead, since
903
- neither schema carries a usage example.
1073
+ All four ran live in November 2026 (Tier 3): 64×64 PixMiniMax at 8 and 16
1074
+ frames billed 1 and 2, `animate-with-text-v3` at 4 frames billed 1,
1075
+ `interpolate` billed 10, and `edit-animation` of a 9-frame set billed 10.
1076
+ Every completed job was read correctly. PixMiniMax returned the frame count
1077
+ plus the input frame (9 and 17 frames); `interpolate` returned 14 frames at
1078
+ the default count. Cost: `animate` borrows `character`'s measured v3-loop
1079
+ formula; `animate-pixminimax` follows PixelLab's published table, which the
1080
+ borrowed formula under-read; `interpolate` and `edit-animation` price the
1081
+ canvas on the 10/15/25 Pro ladder (the planner had read them as 25).
904
1082
  - `/generate-font-pro` (+ `GET /generate-font-pro/{job_id}`) — an 80-glyph
905
1083
  atlas PNG plus a `.ttf` from a style description, `weight`
906
1084
  (`Bold`/`Regular`), and `glyph_px` (8/16/32/64). Documented at 15
@@ -918,14 +1096,11 @@ Listed so the gaps are known rather than assumed away:
918
1096
  - `image-to-pixelart-pro` takes only `image` + `description`, no size fields.
919
1097
  The non-Pro version is characterised above, and the Pro Flash version,
920
1098
  which pixelkiln wraps, [below](#image-to-pixel-art-pro-flash-measured).
921
- - the tileset family, with schema documented above and costs unmeasured
922
- (the standalone isometric tile endpoint alongside it now has one real
923
- measured data point — see above)
924
1099
  - `generate-font-pro`, job-based, with a response shape not in the simple
925
1100
  `{usage, image}` form (wrapped by `pixelkiln font`, but its cost is not
926
1101
  yet measured)
927
1102
  - the character family beyond what the `character` generator uses: lip-sync,
928
- skeleton animation, `portrait_to_character` (a full character from a bust),
1103
+ `portrait_to_character` (a full character from a bust),
929
1104
  and `source_image_id` on Pro Flash. The four creation engines, states,
930
1105
  `animate-character`, portraits, and outfit transfer are covered in full; see
931
1106
  the September 2026 measurements below.
@@ -942,6 +1117,9 @@ generations and finished in about two minutes:
942
1117
  error for each, and a failed request bills nothing. The completed job's
943
1118
  `last_response` carries `images` (base64, `width`, `height`), `flow_kind`,
944
1119
  and `billing_usage` beside the top-level `usage`.
1120
+ - **`POST /characters/animations`, `mode: "skeleton-v3"` with a
1121
+ `template_animation_id`** (a template `skeleton-v3` loop): one loop on a v3
1122
+ character billed 3, inside PixelLab's quoted 2 to 4.
945
1123
  - **`POST /characters/animations`, `mode: "skeleton-v3"` with no
946
1124
  `template_animation_id`** (PixelLab's new custom motion): a one-sentence
947
1125
  `action_description` and `frame_count` 8 returned 8 frames at **96×96**
@@ -19,9 +19,9 @@ account; [ENDPOINTS.md](./ENDPOINTS.md) contains the detailed experiments.
19
19
  | Controlled pose/expression sequence in ComfyUI | `frames` | 0 `free` provider units | one atomic ordered set |
20
20
  | Animated GIF or spritesheet from Retro Diffusion | `animation` | $0.07–$0.25 per animation (published price) | 1 GIF or PNG sheet |
21
21
  | A character facing 4 or 8 directions, its poses, and its animations | `character` | 1 per base (standard), 10–25 per pose or portrait, 1 per template loop (2–4 as `skeleton-v3`), 20 per outfit (measured once) | one set of directions, one ordered loop, or one portrait |
22
- | A prop, creature, or vehicle with rotations, states, or loops but no character rig | `objectPro` | about 6 per base at 64px (unmeasured) | one set of directions, or one ordered loop |
22
+ | A prop, creature, or vehicle with rotations, states, or loops but no character rig | `objectPro` | 6 per base (measured at 32px; about 6 at 64px) | one set of directions, or one ordered loop |
23
23
  | UI chrome — panels, buttons, health bars, toolbars | `uiAsset` | 20 generations (measured once, at 256x192) | 1 composited image |
24
- | One UI element from a description, 16px and up, optionally guided by a concept image | `uiElement` | 10–25 generations (unmeasured) | 1 image |
24
+ | One UI element from a description, 16px and up, optionally guided by a concept image | `uiElement` | 10–25 generations (a 32×32 call billed 10) | 1 image |
25
25
  | A styled still on the Pro Flash model, or the south sprite a Pro Flash character will rotate | `imageProFlash` | 5–9 generations (PixelLab's provisional quote) | 1 image |
26
26
  | An animated effect (spell, hit, explosion, aura), on its own or around a sprite | `vfx` | free from presets and parts; 1–28 when described to PixelLab's artist (lite measured at 1; plans at twice the quote) | one ordered frame set |
27
27
 
@@ -288,11 +288,13 @@ and regenerating the parent makes the child stale.
288
288
  | portrait | portrait-character-pro | 10–25 by `size` (16px billed exactly 20 live, before the October 2026 cut) |
289
289
  | outfit | transfer-outfit-v2 | 20 (a 2-frame, 92×92 job billed exactly this live; not yet measured at other frame counts or canvases) |
290
290
 
291
- The 20–40 tiers are PixelLab's; the tier is resolved from the canvas when
292
- the job runs and reserved against the floor, so `plan` reports the tier the
293
- canvas lands in. `plan` prices a 64px state at 40 (the 1dir tier for that
294
- many pixels); one live 64px state in September 2026 moved the balance by
295
- about 22, so the estimate reads high, which is the safe side for a budget.
291
+ The 10–25 tiers are PixelLab's (20–40 before its October 2026 cut); the tier
292
+ is resolved from the canvas when the job runs and reserved against the floor,
293
+ so `plan` reports the tier the canvas lands in. `plan` prices a 64px state at
294
+ 25 (the 1dir tier for that many pixels); one live 64px state in September
295
+ 2026, before the cut, moved the balance by about 22 against the then 20–40
296
+ tiers, so there is no bill on the new list, and the estimate is read as high,
297
+ which is the safe side for a budget.
296
298
  `poll` now reads what a job like this actually billed and records it
297
299
  alongside the estimate as `billed`; `pixelkiln history`, `plan --json`, and
298
300
  the gallery show both when they differ, though `gen`'s wave budget still
@@ -351,12 +353,13 @@ ignored, since none of them reach the API for an object.
351
353
  restricted to the fields above (no `template`/`subject`, since neither
352
354
  applies). See [Working with a cast](./CHARACTERS.md#working-with-a-cast).
353
355
 
354
- **Cost is not independently measured.** `objectProCost()` assumes
355
- `/create-object-pro-flash`/its state/its animation price identically to
356
+ **Cost: the base is measured, the rest is assumed.** `objectProCost()` prices
357
+ `/create-object-pro-flash`/its state/its animation identically to
356
358
  `character`'s own measured pro-flash formula (`proFlashCharacterCost`),
357
- since the request bodies are near-identical minus `template_id` — treat it
358
- as a working assumption, not a confirmed number, until checked against a
359
- live account.
359
+ since the request bodies are near-identical minus `template_id`. A 32px base
360
+ billed exactly 6 live (November 2026, Tier 3) and returned 8 files at 32×32,
361
+ matching the plan. The state route, the `pro` animation and other sizes
362
+ are still mock only; treat them as a working assumption.
360
363
 
361
364
  Adoption (`pixelkiln adopt`) has not been extended for `objectPro`'s own
362
365
  `<object id>#<animation group id>` remote-id scheme yet, unlike `character`'s
@@ -440,12 +443,13 @@ plain `revision` (image-to-image) of the base panel, which already carries
440
443
  this for every other generator.
441
444
 
442
445
  **Cost: confirmed live at one data point — 20 generations for a 256x192
443
- canvas**, the low end of the `create_ui_asset` MCP tool's "20–40
444
- generations" claim. PixelKiln still estimates with the same canvas-tier
445
- formula as `1dir`/`tiles`, which predicts the 40 ceiling for every valid
446
- `uiAsset` size (its 192px floor is already past that formula's top tier) —
447
- the measured call proves the formula wrong here, since it billed the floor
448
- price at an area well above where `1dir`/`tiles` would bill the ceiling.
446
+ canvas**, the low end of the `create_ui_asset` MCP tool's then "20–40
447
+ generations" claim (before PixelLab's October 2026 cut to 10–25). PixelKiln
448
+ still estimates with the same canvas-tier formula as `1dir`/`tiles`, which
449
+ predicts the 25 ceiling for every valid `uiAsset` size (its 192px floor is
450
+ already past that formula's top tier) — the measured call proves the
451
+ formula wrong here, since it billed the floor price at an area well above
452
+ where `1dir`/`tiles` would bill the ceiling.
449
453
  Left as an over-read for `--budget` until a second size is measured; see
450
454
  [ENDPOINTS.md](./ENDPOINTS.md) for the full writeup.
451
455
 
@@ -529,15 +533,20 @@ to 16×16, which suits icons and small widgets:
529
533
  - `uiColorPalette` is sent as `color_palette`, the same free-text hint
530
534
  `uiAsset` takes. PixelLab removes the background by default; set
531
535
  `noBackground: false` on the style to keep it.
532
- - One call is expected to return one image, recorded straight away. If the
533
- endpoint ever returns several, they go to candidate review like
534
- `imagePro`'s.
535
-
536
- **Unmeasured.** The schema carries no usage example and no call has been
537
- billed yet. The plan prices it on the same 10/15/25 canvas tiers as
538
- `1dir`/`tiles`, the safe over-read for a Pro endpoint, and the completed
539
- job's shape is read defensively (`pollUiElement` names the keys it got if
540
- the shape is not the documented `images` list).
536
+ - A small element returns many candidates (64 at 32×32, measured), which go
537
+ to candidate review like `imagePro`'s; a call that returns one image is
538
+ recorded straight away.
539
+
540
+ **Cost: measured once.** A 32×32 call billed 10 live (November 2026, Tier 3)
541
+ and the review page showed **64 candidates** at 32×32, which the plan said as
542
+ 1 until it followed the `/generate-image-v2` size tiers (`uiElementCandidateCount`:
543
+ 64 up to 32px, 49 at 33–35, 36 at 36–41, 25 at 42–50, 16 at 51–64, 9 at
544
+ 65–84, 16 at 85, 4 at 86–170, 1 above). Only the 32px point is a bill; the
545
+ other bands are PixelLab's published grid. A size with more than one candidate
546
+ goes to review. The plan prices the canvas on the 10/15/25 tiers as
547
+ `1dir`/`tiles` do; other sizes are unbilled, and the completed job's shape
548
+ is still read defensively (`pollUiElement` names the keys it got if the shape
549
+ is not the documented `images` list).
541
550
 
542
551
  ## `vfx`
543
552
 
package/docs/PIXELLAB.md CHANGED
@@ -77,9 +77,9 @@ unapproved files. See [Manifest quality profiles](./MANIFEST.md#quality-profiles
77
77
  | `imageProFlash` | You need a still on the Pro Flash model, optionally styled from one image, 16 to 256px | 5 to 9 generations (provisional quote) |
78
78
  | `vfx` | You need an animated effect (spell, hit, explosion, aura), on its own or around a sprite | free from presets and parts; 1 to 28 when described to PixelLab's artist (lite measured at 1) |
79
79
  | `character` | You need a character in 4 or 8 directions, with states, loops, portraits, or outfits | See [Characters](./CHARACTERS.md) |
80
- | `objectPro` | You need a prop or creature with rotations, states, or loops but no character rig | about 6 at 64px (unmeasured) |
80
+ | `objectPro` | You need a prop or creature with rotations, states, or loops but no character rig | 6 per base (measured at 32px) |
81
81
  | `uiAsset` | You need a UI panel composited from pieces and named elements, 192px and up | 20 generations (measured once) |
82
- | `uiElement` | You need one UI element from a description, 16px and up | 10 to 25 generations (unmeasured) |
82
+ | `uiElement` | You need one UI element from a description, 16px and up | 10 to 25 generations (a 32×32 call billed 10) |
83
83
 
84
84
  `map` accepts these values:
85
85
 
@@ -139,9 +139,10 @@ joints, and `skeleton-preview` draws them over the sprite before you spend:
139
139
  - Each billed exactly 3 generations for 8 frames, measured live. The sentence
140
140
  loop came back at 96×96 from a 64px character; the posed one stayed 64×64.
141
141
  [The home page](https://pixelkiln.griffen.codes/#updates) shows both.
142
- - Each direction of a sentence loop is its own request for now, so a loop with
143
- several directions can move a little differently in each. PixelLab can draw
144
- every direction from one motion, but PixelKiln does not send that yet.
142
+ - Each direction of a sentence loop is its own request, but the first
143
+ direction leads and every later one is sent into its animation group, so all
144
+ directions are drawn from one motion (a live append billed 3 and joined the
145
+ group).
145
146
 
146
147
  See [Loops from a sentence](./CHARACTERS.md#loops-from-a-sentence) and
147
148
  [Skeleton-driven animation](./REVISIONS.md#skeleton-driven-animation).
package/docs/REVISIONS.md CHANGED
@@ -400,17 +400,20 @@ review** first (`pixelkiln pick`), not straight to downloadable output; there
400
400
  is no per-candidate choice to make (it is one ordered set, previewed as a
401
401
  loop), just accept or reject the whole thing.
402
402
 
403
- **Neither endpoint's completed-job response shape has been exercised against
404
- a live account.** The request fields above come from PixelLab's live OpenAPI
405
- document; the shape of a *finished* job (which key holds the frame list, and
406
- whether it's hosted URLs or inline base64) is an informed guess checked
407
- against several plausible shapes (see `pollAnimateRevision` in
408
- `src/providers/pixellab.ts`), the same defensive posture `pollRevision`
409
- already takes for `image-to-image`/`inpaint`. Cost is likewise unmeasured:
410
- `estimate()` borrows `character`'s own measured v3-loop formula
403
+ **Both endpoints ran live in November 2026 (Tier 3), and every completed job
404
+ was read correctly.** A 64×64 `animate` of 4 frames billed 1 and returned 5
405
+ frames at 64×64; a 64×64 `animate-pixminimax` billed 1 at 8 frames (9 frames
406
+ back) and 2 at 16 frames (17 back). PixelLab includes the input frame in the
407
+ set, so a set holds the requested count plus one. `pollAnimateRevision` still
408
+ checks several plausible field names defensively rather than assume one.
409
+ Cost: `animate` borrows `character`'s measured v3-loop formula
411
410
  (`ceil(width × height × frames / 65536)`, since the request shapes are
412
- near-identical) as a placeholder, plus `enhancePrompt`'s own documented
413
- +0.05-generation surcharge, which is a real schema number rather than a guess.
411
+ near-identical), which matched the one bill; `animate-pixminimax` follows
412
+ PixelLab's published table (64×64 at 4 / 8 / 16 / 40 frames costs 1 / 1 / 2 /
413
+ 6), because that formula read the 16-frame clip as 1 against a bill of 2 (see
414
+ `pixMiniMaxCost`; 40 frames is the published number, not a bill). Both add
415
+ `enhancePrompt`'s documented +0.05-generation surcharge. Other sizes and
416
+ frame counts are unbilled.
414
417
 
415
418
  ### Interpolate between two keyframes
416
419
 
@@ -468,10 +471,12 @@ time.
468
471
 
469
472
  `interpolate` and `edit-animation` land in candidate review like `animate`,
470
473
  take `fps` (defaulting to the parent's own rate when it has one, else 8), and
471
- reject `strength`. Neither has been exercised against a live account: request
472
- fields come from PixelLab's live OpenAPI document, the completed job is read
473
- by the same defensive frame-list lookup `animate` uses, and cost is an
474
- estimate (see [PixelLab](#pixellab) below).
474
+ reject `strength`. Both ran live in November 2026 (Tier 3) and the completed
475
+ job was read correctly by the same frame-list lookup `animate` uses: a 64×64
476
+ `interpolate` with a `lastFrame` keyframe billed 10 and returned 14 frames at
477
+ 64×64, and an `edit-animation` of a 9-frame 64×64 set billed 10. The plan
478
+ now prices them at those 10 (it used to read 25). Larger canvases are
479
+ unbilled (see [PixelLab](#pixellab) below).
475
480
 
476
481
  ComfyUI supports none of the four frame-set modes: its revision path always
477
482
  writes a single output image, and an animation is a frame set — a structural
@@ -545,7 +550,7 @@ calls it directly, but nothing in `resolveSpecs`/`estimate()`/`submitRevision`
545
550
  ever calls it — planning stays offline by construction (the keypoints file is
546
551
  read like any other manifest input, never a network call), and the only
547
552
  PixelLab endpoint `animate-skeleton`'s submission composes is
548
- `animate-with-skeleton-v3` itself, not two never-tested-live calls chained
553
+ `animate-with-skeleton-v3` itself, not two endpoints chained
549
554
  together. A future pipeline stage that budgets and tracks `estimate-skeleton`
550
555
  calls the way `gen` does everything else is tracked separately, once this
551
556
  mode has shipped and seen real use.
@@ -698,33 +703,33 @@ further — there is nothing to ask.
698
703
  image; a whole member set is still one call, but whether its price stays
699
704
  flat is unmeasured.
700
705
  - `interpolate` (`/interpolation-v2`) and `edit-animation`
701
- (`/edit-animation-v2`) are both documented "Pro" endpoints with no usage
702
- example in the schema and no live measurement. `estimate()` borrows the
703
- same 10/15/25 canvas tiers the other unmeasured Pro edits use, sized on the
704
- keyframe for `interpolate` and on the packed frame grid for
705
- `edit-animation` (four 32×32 frames price as a 64×64 canvas, the 40 tier).
706
- Over-reading is the safe direction for `--budget`; expect a live bill at or
707
- below the plan.
706
+ (`/edit-animation-v2`) are "Pro" endpoints and bill on the 10/15/25 canvas
707
+ ladder (`proTierCost`: 10 up to 65536px², 15 up to 102400px², 25 above).
708
+ `estimate()` sizes the canvas on the keyframe for `interpolate` and on the
709
+ packed frame grid for `edit-animation` (nine 64×64 frames pack into
710
+ 192×192). Measured live in November 2026: a 64×64 `interpolate` and a
711
+ 9-frame 64×64 `edit-animation` each billed 10, where the plan used to say
712
+ 25. Larger canvases are unbilled and follow the same ladder; over-reading
713
+ is the safe direction for `--budget`.
708
714
  - `animate` calls `/animate-with-text-v3`, `animate-pixminimax` calls
709
715
  `/animate-pixminimax` — both real async background jobs, unlike the two
710
716
  Cleanup-tier modes above, since they generate new frames rather than
711
717
  transform the source. Both take at most 256 pixels per side; `animate`
712
718
  additionally caps at 16 frames (`animate-pixminimax` allows up to 40). See
713
719
  [Animation and interpolation](#animation-and-interpolation) above for the
714
- full field list, the frame-set output shape, and its own (still unmeasured)
715
- cost caveat — unlike the Cleanup tier above, neither `animate` nor
716
- `animate-pixminimax` has been exercised against a live account yet, and the
717
- request/response shapes come from PixelLab's live OpenAPI document, not an
718
- observed call. Treat the exact field names as provisional until a real
719
- call confirms them.
720
+ full field list, the frame-set output shape, and the live bills: both ran
721
+ live in November 2026 (64×64 `animate` at 4 frames billed 1; `animate-pixminimax`
722
+ at 8 and 16 frames billed 1 and 2), and the completed jobs were read
723
+ correctly.
720
724
  - `animate-skeleton` calls `/animate-with-skeleton-v3`, also a real async
721
725
  background job, at most 256 pixels per side and 3-15 frames (the frame
722
726
  count comes from `keypointsFile`, not a manifest field). See
723
727
  [Skeleton-driven animation](#skeleton-driven-animation) above for the full
724
728
  field list, the `keypointsFile` shape, and the `estimateSkeleton`
725
- CLI-only-and-never-in-the-submission-path decision. Same unverified-live
726
- caveat as `animate`/`animate-pixminimax`, sourced from the live
727
- `animate_with_skeleton_v3` MCP tool schema rather than an observed call.
729
+ CLI-only-and-never-in-the-submission-path decision. Unlike
730
+ `animate`/`animate-pixminimax`, it has run live: an 8-frame revision billed
731
+ exactly 3 generations (see that section); its field names came from the
732
+ `animate_with_skeleton_v3` MCP tool schema.
728
733
  - `normal-map` calls `/normal-map` (PixelLab 0.4.130), a background job whose
729
734
  map is `last_response.image`; a loop's frames go and come back as one
730
735
  horizontal strip, cut into per-frame files on poll. See
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixelkiln",
3
- "version": "0.92.1",
3
+ "version": "0.92.3",
4
4
  "description": "Manifest-driven pixel-art generation, review, recovery, and packaging with deterministic provenance.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -46,7 +46,8 @@ Two engine-specific data points worth the same treatment:
46
46
  pro engine at the same canvas ("even at 256×256, we can generate eight
47
47
  animation frames, which we didn't have before even with the pro tools") —
48
48
  consistent with pixelkiln's documented `character` cost model, where v3
49
- scales `ceil(size²×8/65536)` and pro sits in the flat 20–40 tier regardless.
49
+ scales `ceil(size²×8/65536)` and pro sits in the flat 10–25 tier regardless (20–40 before PixelLab's
50
+ October 2026 cut).
50
51
  Prefer v3 over pro for a loop unless pro's quality is specifically needed.
51
52
  - `portrait-character-pro` (not part of this adapter) renders sizes 128 and
52
53
  160 at "2K" internal resolution versus "1K" for 16–64, at a measured cost