pixelkiln 0.63.0 → 0.65.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.
@@ -57,18 +57,23 @@ Tiles and provider-native animation remain outside this contract.
57
57
 
58
58
  ## Dependency graph
59
59
 
60
- Four kinds of asset draw from another asset's generated bytes, and all four
60
+ Six kinds of asset draw from another asset's generated bytes, and all six
61
61
  are edges from a child spec to a parent spec in the same style: a
62
- `revision` (image-to-image or inpaint from a still), a character `state` or
63
- `animation` (drawn by PixelLab from the character it holds, so the edge is
64
- to the parent's south-facing file), a `mirror` (a local left-to-right flip
65
- of the parent's files), and a pro base's `styleCharacter` (the look it
66
- follows). Manifest loading rejects missing parents, self-references, and
67
- cycles. Resolution includes transitive parents even when `--only` selects
68
- just the child, chooses the parent's approved quality output when one
69
- exists, and hashes the parent's bytes (and a revision's optional mask) into
70
- the child identity, so a regenerated parent makes its children stale rather
71
- than silently mismatched.
62
+ `revision` (image-to-image or inpaint from a still), a character `state`,
63
+ `animation`, or `portrait` (drawn by PixelLab from the character it holds
64
+ or its south-facing file, so the edge is to that one file), a `mirror` (a
65
+ local left-to-right flip of the parent's files), an `outfit` (PixelLab
66
+ re-clothing a loop's whole frame set from a reference image, so the edge
67
+ is to every one of the parent's files, not one), and a pro base's
68
+ `styleCharacter` (the look it follows). Manifest loading rejects missing
69
+ parents, self-references, and cycles. Resolution includes transitive
70
+ parents even when `--only` selects just the child, chooses the parent's
71
+ approved quality output when one exists, and hashes the parent's bytes
72
+ (and a revision's optional mask) into the child identity for the
73
+ single-file edges, so a regenerated parent makes its children stale rather
74
+ than silently mismatched. A mirror and an outfit depend on the parent's
75
+ *whole* output set instead, tracked outside `specHash` (see below), since
76
+ there is no one file to hash at resolve time.
72
77
 
73
78
  Planning walks the graph from the child and reports `blocked` unless each
74
79
  parent is committed source, an intact current download, or a current approved
@@ -78,7 +83,10 @@ runs the plan in waves until nothing new becomes actionable. The submit
78
83
  boundary repeats the walk after queue and rate-limit waits, closing the gap
79
84
  between a printed plan and provider work. A mirror is the one edge with no
80
85
  provider on the far side: submit flips the files itself and records the
81
- parent's output hashes, and the plan compares those directly.
86
+ parent's output hashes, and the plan compares those directly. An outfit
87
+ records the same kind of hash over the parent's output set, but does call
88
+ a provider (`transfer-outfit-v2`) and costs generations; `billed` and the
89
+ usual lock lifecycle apply to it exactly as they do to a state or loop.
82
90
 
83
91
  Providers opt into revision modes through `supportsRevision`. The first
84
92
  implementation is ComfyUI: it uploads content-addressed inputs, binds only the
@@ -340,6 +340,67 @@ Engines that flip sprites at draw time (Godot's `flip_h`, Unity's
340
340
  you generate and flip in the engine; mirrors are for pipelines that want
341
341
  every direction on disk.
342
342
 
343
+ ## Portraits
344
+
345
+ A `portrait` asset is a bust made from a base or state's south sprite, and
346
+ attached to that character's own PixelLab record:
347
+
348
+ ```json
349
+ "mira.bust": { "portrait": { "of": "mira", "size": 64 } }
350
+ ```
351
+
352
+ `of` names the base or state to portray; `size` is one of PixelLab's fixed
353
+ result sizes (16, 32, 48, 64, 128, or 160 — 128 and 160 render at 2K and cost
354
+ more), independent of the style's own `size`. A portrait takes no prompt: it
355
+ is drawn from the parent's pixels, not text, so it is priced and generated
356
+ like a state, 20 to 40 generations by the size tier (a 16px portrait billed
357
+ exactly 20, the floor, in a live test; see [`docs/ENDPOINTS.md`](ENDPOINTS.md)).
358
+ It lands as `<asset>.png`, one file like a single-direction generator, and
359
+ `pixelkiln fetch` also attaches it to the parent's character record upstream
360
+ (a separate, free call PixelLab does not make on its own) — useful for
361
+ PixelLab's own tools, since the API otherwise has no way to read a
362
+ character's portrait back once set.
363
+
364
+ A portrait blocks until its parent is downloaded and current, and goes
365
+ `stale` when the parent is regenerated, exactly like a state. It takes no
366
+ `reference` or `concept` (those belong on a base) and no `state` or
367
+ `animation` (a portrait is not one of those, and the three are mutually
368
+ exclusive). Its view comes from the style, but only `low top-down`, `high
369
+ top-down`, or `side` are valid — narrower than a `standard` base's own
370
+ options, since the underlying endpoint takes a smaller set.
371
+
372
+ The reverse tool, drawing a full character from a portrait image, is not
373
+ implemented; see the open items in [`docs/ENDPOINTS.md`](ENDPOINTS.md).
374
+
375
+ ## Outfit transfer
376
+
377
+ An `outfit` asset re-clothes an existing loop's frames with a reference
378
+ outfit image, PixelLab's `transfer-outfit-v2`:
379
+
380
+ ```json
381
+ "mira.walk.armored": {
382
+ "outfit": { "of": "mira.walk", "reference": "refs/armor.png" }
383
+ }
384
+ ```
385
+
386
+ `of` names the loop (an `animation` asset) to re-clothe; `reference` is a
387
+ manifest-relative image of the outfit, 32 to 256px per side. An outfit takes
388
+ no prompt (drawn from pixels, not text) and reads its source loop's own
389
+ downloaded frames — 2 to 16 of them, PixelLab's own limit — rather than the
390
+ character record, so it works even once the source's PixelLab job record
391
+ has expired. It shares its source's width, height, and directions, and is
392
+ priced and generated like a state or loop, not for free like a `mirror`:
393
+ measured live at 20 generations for a 2-frame, 92×92 job (see
394
+ [`docs/ENDPOINTS.md`](ENDPOINTS.md)), the floor of the same tier a state
395
+ uses, not yet confirmed at other frame counts or canvases.
396
+
397
+ An outfit blocks until its source loop is downloaded and current — the
398
+ same rule a mirror's source follows, since both depend on a whole frame
399
+ set rather than one file — and goes `stale` when the source is
400
+ regenerated. It takes no `state`, `animation`, `portrait`, `reference`, or
401
+ `concept` (those describe a different shape or belong on a base); a
402
+ reference image change alone also makes it stale.
403
+
343
404
  ## Working with a cast
344
405
 
345
406
  - `pixelkiln plan` shows a state or loop as `blocked` until its parent is
package/docs/CLI.md CHANGED
@@ -304,12 +304,15 @@ Review remote objects that no supplied lockfile claims. On shared accounts, pass
304
304
  every other project lock via repeatable `--claims`; sibling manifests are used
305
305
  to exclude objects matching another project's styles. `--dry-run --json`
306
306
  provides a scriptable inventory. Import, keep, and discard are review decisions;
307
- discard only tags an object. Pass `--provider` when the manifest uses more than
308
- one provider.
307
+ discard only tags an object. Unclaimed characters are reviewed too, one card per
308
+ base and its states, in the manifest's `character` styles; importing one writes
309
+ its base, states, and loops and adopts them (see
310
+ [Recovery](./RECOVERY.md#characters)). Pass `--provider` when the manifest uses
311
+ more than one provider.
309
312
 
310
313
  ### `purge`
311
314
 
312
- Delete provider objects previously tagged `pixelkiln:discard`. It is separate
315
+ Delete provider objects and characters previously tagged `pixelkiln:discard`. It is separate
313
316
  from salvage, lists targets, asks for confirmation, and refuses non-interactive
314
317
  deletion without `--yes`. Use `--dry-run` first. Pass `--provider` when the
315
318
  manifest uses more than one provider.
package/docs/ENDPOINTS.md CHANGED
@@ -582,12 +582,11 @@ Listed so the gaps are known rather than assumed away:
582
582
  - `generate-font-pro`, job-based, with a response shape not in the simple
583
583
  `{usage, image}` form (wrapped by `pixelkiln font`, but its cost is not
584
584
  yet measured)
585
- - the character family beyond what the `character` generator uses: portraits
586
- (`portrait-character-pro` both ways, `/characters/{id}/portrait`), outfit
587
- transfer (`transfer-outfit-v2`), lip-sync, skeleton animation, and
588
- `source_image_id` on Pro Flash. The four creation engines, states, and
589
- `animate-character` are covered in full; see the September 2026 measurements
590
- below.
585
+ - the character family beyond what the `character` generator uses: lip-sync,
586
+ skeleton animation, `portrait_to_character` (a full character from a bust),
587
+ and `source_image_id` on Pro Flash. The four creation engines, states,
588
+ `animate-character`, portraits, and outfit transfer are covered in full; see
589
+ the September 2026 measurements below.
591
590
 
592
591
  ## Characters, measured
593
592
 
@@ -615,6 +614,27 @@ Listed so the gaps are known rather than assumed away:
615
614
  that is not a biped or one of the four quadrupeds, animate from text.
616
615
  - Request validation is strict: an unknown body field is a 422 listing every
617
616
  problem at once, which is a free way to check a body's shape.
617
+ - **`portrait-character-pro`** (`direction: character_to_portrait`, a full-body
618
+ sprite in, a bust out) is job-based: `POST` returns `background_job_id`,
619
+ `GET /portrait-character-pro/{job_id}` answers 423 while drawing and, once
620
+ `status: "completed"`, a `download_url` (its own `usage` is always `null`;
621
+ read the billed amount from `GET /background-jobs/{background_job_id}`
622
+ instead, same as every other job here). Not the couple-generations
623
+ "conversion" the name suggests: the smallest `result_size` (16px) billed
624
+ **20 generations**, the same order of magnitude as a state or `1dir`.
625
+ `POST /characters/{id}/portrait` (attaching a portrait image to a character
626
+ record) is a separate, synchronous, **free** call (`usage.generations: 0`);
627
+ its response is the only place the stored portrait's URL appears; the
628
+ character's own `GET /characters/{id}` never gains a portrait field, so
629
+ PixelKiln has to remember the URL itself. `character_to_portrait` and
630
+ `SetPortrait` are two independent calls with no automatic link between them.
631
+ - **`transfer-outfit-v2`** (a reference outfit image plus 2–16 existing
632
+ frames back wearing it) is job-based the same way, polled through
633
+ `GET /background-jobs/{id}` only (no dedicated status endpoint). A 2-frame,
634
+ 92×92 job billed **20 generations** — again a real generation cost, not a
635
+ cheap frame edit. The completed job returns the result frames inline as
636
+ base64 in `last_response.quantized_images`, not as storage URLs like every
637
+ other multi-frame result here.
618
638
 
619
639
  ---
620
640
 
@@ -221,12 +221,14 @@ system requests reduced motion and stops while it is offscreen. After approval,
221
221
 
222
222
  `character` is PixelLab's character family as managed assets: a base drawn
223
223
  facing 4 or 8 directions (from a prompt, or from your own south-facing
224
- sprite with `reference`), states (a pose, an outfit) that PixelLab applies
225
- to every direction of an existing character, and animations, one loop of
226
- one character in one direction. The three share one PixelLab character. A state
227
- or animation depends on its parent the way a revision does: the parent must
228
- be downloaded and current before the child can be submitted, and
229
- regenerating the parent makes the child stale.
224
+ sprite with `reference`), states (a pose or a text-edited outfit) that
225
+ PixelLab applies to every direction of an existing character, animations,
226
+ one loop of one character in one direction, portraits, a bust made from
227
+ the south sprite, and outfit transfers, an existing loop's frames
228
+ re-clothed from a reference image instead of text. A state, animation,
229
+ portrait, or outfit depends on its parent the way a revision does: the
230
+ parent must be downloaded and current before the child can be submitted,
231
+ and regenerating the parent makes the child stale.
230
232
 
231
233
  | Asset | PixelLab call | Cost |
232
234
  |---|---:|---:|
@@ -238,6 +240,8 @@ regenerating the parent makes the child stale.
238
240
  | animation with a `template` | animate-character | 1 |
239
241
  | animation from text (v3) | animate-character | ceil(size² × frames / 65536): 1 at 64px, 2 at 128px |
240
242
  | animation, `mode: pro` | animate-character | 20–40 by canvas |
243
+ | portrait | portrait-character-pro | 20–40 by `size` (16px billed exactly 20 live) |
244
+ | outfit | transfer-outfit-v2 | 20 (a 2-frame, 92×92 job billed exactly this live; not yet measured at other frame counts or canvases) |
241
245
 
242
246
  The 20–40 tiers are PixelLab's; the tier is resolved from the canvas when
243
247
  the job runs and reserved against the floor, so `plan` reports the tier the
package/docs/MANIFEST.md CHANGED
@@ -436,7 +436,9 @@ their own page: [Characters](./CHARACTERS.md) and
436
436
  "prompt": "walking in place, short legs stepping",
437
437
  "animation": { "of": "bot", "direction": "west", "frames": 12, "fps": 12 }
438
438
  },
439
- "bot.walk.east": { "mirror": "bot.walk.west" } // flipped locally, 0 generations
439
+ "bot.walk.east": { "mirror": "bot.walk.west" }, // flipped locally, 0 generations
440
+ "bot.bust": { "portrait": { "of": "bot", "size": 64 } }, // no prompt; drawn from bot's pixels
441
+ "bot.walk.west.armored": { "outfit": { "of": "bot.walk.west", "reference": "refs/armor.png" } }
440
442
  }
441
443
  }
442
444
  ```
package/docs/PIXELLAB.md CHANGED
@@ -156,10 +156,11 @@ comparing notes with someone using a different one:
156
156
 
157
157
  ## What is outside this adapter
158
158
 
159
- PixelLab offers more than PixelKiln currently exposes. Portraits, outfit
160
- transfer, lip-sync, and skeleton-driven animation are not part of this
161
- adapter. Characters, their states, and their animations are the `character`
162
- generator, with all four creation engines (standard, v3, pro, pro-flash),
159
+ PixelLab offers more than PixelKiln currently exposes. Lip-sync and
160
+ skeleton-driven animation are not part of this adapter. Characters, their
161
+ states, their animations, their portraits, and outfit transfer onto their
162
+ loops are the `character` generator, with all four creation engines
163
+ (standard, v3, pro, pro-flash),
163
164
  reference sprites, concept images, style anchors, mirrors, and every
164
165
  `animate-character` control; see [Characters](./CHARACTERS.md). Masked
165
166
  inpainting and whole-image editing are the `revision` asset shape, not the
package/docs/RECOVERY.md CHANGED
@@ -128,6 +128,37 @@ array to stdout and human diagnostics to stderr for piping into `jq`.
128
128
  Imported ids are derived from prompts and land under `_salvaged/`; review and
129
129
  rename them before treating them as stable application ids.
130
130
 
131
+ ### Characters
132
+
133
+ Characters are account records of their own, outside the object listing, and
134
+ salvage reviews them too. A base and the states made from it share a group
135
+ upstream, so each unclaimed group is one card: the base's south rotation, with
136
+ a line counting its directions, states, and loops. A group is unclaimed when
137
+ none of its characters is in any supplied lockfile. A group with some members
138
+ claimed (a project uses the base, say, but not a state) is left out and
139
+ reported, since discarding the rest would delete states of a character in use;
140
+ declare those states and run `pixelkiln adopt` instead.
141
+
142
+ Groups go to the manifest's `character` styles, never to other styles: the
143
+ only character style when there is one, otherwise the style whose prompt
144
+ prefix or suffix the base's prompt carries. `--style <character style>` takes
145
+ every unclaimed group. A manifest with no character style reports the groups
146
+ and triages none of them. Account objects likewise never route to a character
147
+ style, where an import would become a character base with nothing upstream.
148
+
149
+ | Verdict | Effect on a character group |
150
+ |---|---|
151
+ | import | Add a base asset, one asset per state, and one loop asset per animation direction to the manifest, each with a `remoteId`, then adopt them: every rotation and frame is downloaded and gets a lock entry. |
152
+ | keep | Add `pixelkiln:keep` to the base and every state. |
153
+ | discard | Add `pixelkiln:discard` to the base and every state; does not delete. |
154
+
155
+ An imported base is named from the character's name, its states
156
+ `<base>_<state name>`, and its loops `<parent>.<animation>.<direction>`. A loop
157
+ PixelLab recorded without an animation group id cannot be adopted by
158
+ `remoteId` and is left out, with a line saying so. A base whose size differs
159
+ from the style's gets its own `size`; a 4-direction character imported into an
160
+ 8-direction style keeps its four rotations.
161
+
131
162
  ## Shared workspace catalog
132
163
 
133
164
  For a single project, its own lockfile is the whole claim set. On a shared
@@ -190,9 +221,11 @@ pixelkiln purge
190
221
  pixelkiln purge --yes
191
222
  ```
192
223
 
193
- Only objects already tagged `pixelkiln:discard` are eligible. The command lists
194
- targets, asks interactively, and refuses non-interactive deletion without
195
- `--yes`. A shared account should be fully adopted/salvaged before purge.
224
+ Only objects and characters already tagged `pixelkiln:discard` are eligible.
225
+ The command lists targets, asks interactively, and refuses non-interactive
226
+ deletion without `--yes`. A shared account should be fully adopted/salvaged
227
+ before purge. A deleted character takes its animations with it; each state is
228
+ its own record upstream, tagged and deleted on its own.
196
229
 
197
230
  ## Accept intentional spec prose changes
198
231
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixelkiln",
3
- "version": "0.63.0",
3
+ "version": "0.65.0",
4
4
  "description": "Manifest-driven pixel-art generation, review, recovery, and packaging with deterministic provenance.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -1388,6 +1388,53 @@
1388
1388
  },
1389
1389
  "minItems": 1
1390
1390
  },
1391
+ "portrait": {
1392
+ "type": "object",
1393
+ "properties": {
1394
+ "of": {
1395
+ "type": "string",
1396
+ "minLength": 1
1397
+ },
1398
+ "size": {
1399
+ "type": "number",
1400
+ "enum": [
1401
+ 16,
1402
+ 32,
1403
+ 48,
1404
+ 64,
1405
+ 128,
1406
+ 160
1407
+ ],
1408
+ "default": 64
1409
+ }
1410
+ },
1411
+ "required": [
1412
+ "of"
1413
+ ],
1414
+ "additionalProperties": false
1415
+ },
1416
+ "outfit": {
1417
+ "type": "object",
1418
+ "properties": {
1419
+ "of": {
1420
+ "type": "string",
1421
+ "minLength": 1
1422
+ },
1423
+ "reference": {
1424
+ "type": "string",
1425
+ "minLength": 1
1426
+ },
1427
+ "additionalInstructions": {
1428
+ "type": "string",
1429
+ "maxLength": 2000
1430
+ }
1431
+ },
1432
+ "required": [
1433
+ "of",
1434
+ "reference"
1435
+ ],
1436
+ "additionalProperties": false
1437
+ },
1391
1438
  "proportions": {
1392
1439
  "anyOf": [
1393
1440
  {
@@ -94,7 +94,8 @@ ceilings copied from each plan group.
94
94
  Use the staged `submit` → `poll` → `pick` → `fetch` commands when resuming or
95
95
  debugging one phase. Use the plan's printed stage for paid work and `restore`
96
96
  for missing downloaded bytes, `adopt` for exact matches
97
- already in the provider account, and `salvage` for reviewed unclaimed objects.
97
+ already in the provider account, and `salvage` for reviewed unclaimed objects
98
+ and characters.
98
99
  Use `pack`, `mount`, or `export` only for the artifact format the project needs.
99
100
  Prefer a manifest quality profile when a whole style shares the final-art rule.
100
101
  Use `refine --from` only for a one-off candidate outside that contract, after
@@ -388,7 +388,8 @@ previously catalogued anywhere.
388
388
  `agent_inspect`/`agent_feedback`/`agent_help`) manage a *separate* PixelLab
389
389
  product — "deploy your own agent," confirmed directly from the live tool
390
390
  schemas — unrelated to game-asset generation. Nothing to build here.
391
- - Portraits, outfit transfer, and lip-sync/vocal-animation/talking-gif are
392
- already named as out of scope in docs/PIXELLAB.md. Portrait and
393
- outfit-transfer support exist on an internal branch stack not yet merged;
394
- lip-sync and vocal animation have no in-flight work.
391
+ - Lip-sync/vocal-animation/talking-gif are named as out of scope in
392
+ docs/PIXELLAB.md, with no in-flight work. Portraits (`portrait`) and outfit
393
+ transfer (`outfit`) are character asset kinds; see docs/CHARACTERS.md. They
394
+ were built and live-measured in September 2026 on a stacked branch that
395
+ never reached `main`, and were ported onto it later.