pixelkiln 0.55.0 → 0.57.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/dist/cli.js +269 -18
- package/dist/cli.js.map +1 -1
- package/dist/client/gallery.js +152 -0
- package/dist/index.cjs +271 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +582 -54
- package/dist/index.d.ts +582 -54
- package/dist/index.js +270 -18
- package/dist/index.js.map +1 -1
- package/docs/CHARACTERS.md +6 -1
- package/docs/ENDPOINTS.md +11 -4
- package/docs/GENERATORS.md +5 -0
- package/docs/MANIFEST.md +6 -2
- package/docs/REVISIONS.md +99 -9
- package/package.json +1 -1
- package/schema/manifest.schema.json +26 -1
- package/skills/pixelkiln/references/pixellab-roadmap.md +21 -21
- package/skills/pixelkiln/references/pixellab.md +18 -5
- package/skills/pixelkiln/references/revisions.md +16 -3
package/dist/cli.js
CHANGED
|
@@ -708,7 +708,11 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
|
|
|
708
708
|
from: spec.revision.sourceAssetId,
|
|
709
709
|
sourceSha256: spec.revision.sourceSha256,
|
|
710
710
|
maskSha256: spec.revision.maskSha256,
|
|
711
|
-
strength: spec.revision.strength
|
|
711
|
+
strength: spec.revision.strength,
|
|
712
|
+
numColors: spec.revision.numColors,
|
|
713
|
+
paletteImageSha256: spec.revision.paletteImageSha256,
|
|
714
|
+
dithering: spec.revision.dithering,
|
|
715
|
+
ditheringStrength: spec.revision.ditheringStrength
|
|
712
716
|
} : void 0
|
|
713
717
|
})
|
|
714
718
|
);
|
|
@@ -728,7 +732,7 @@ import { z } from "zod";
|
|
|
728
732
|
var MediaTypeSchema = z.enum(["image/png", "image/gif"]);
|
|
729
733
|
var GeneratorSchema = z.enum(["1dir", "map", "pixflux", "tiles", "animation", "frames", "character", "terrain", "imagePro", "isometricTile", "objectPro"]);
|
|
730
734
|
var GridConfidenceSchema = z.enum(["low", "medium", "high"]);
|
|
731
|
-
var RevisionModeSchema = z.enum(["image-to-image", "inpaint", "outpaint"]);
|
|
735
|
+
var RevisionModeSchema = z.enum(["image-to-image", "inpaint", "outpaint", "reduce-colors", "correct-pixelart"]);
|
|
732
736
|
function tileVariationCount(descriptions) {
|
|
733
737
|
return Math.max(1, descriptions) * 4;
|
|
734
738
|
}
|
|
@@ -922,6 +926,7 @@ var CharacterAnimationSchema = z.object({
|
|
|
922
926
|
context.addIssue({ code: z.ZodIssueCode.custom, message: "template mode needs a template", path: ["template"] });
|
|
923
927
|
}
|
|
924
928
|
});
|
|
929
|
+
var RevisionDitheringSchema = z.enum(["none", "2x2", "4x4", "8x8"]);
|
|
925
930
|
var RevisionSchema = z.object({
|
|
926
931
|
/** What kind of controlled change the provider workflow performs. */
|
|
927
932
|
mode: RevisionModeSchema,
|
|
@@ -930,7 +935,15 @@ var RevisionSchema = z.object({
|
|
|
930
935
|
/** Manifest-relative black/white PNG. Required only for masked inpainting. */
|
|
931
936
|
mask: z.string().min(1).optional(),
|
|
932
937
|
/** Provider-neutral edit strength. The active adapter must bind it explicitly. */
|
|
933
|
-
strength: z.number().min(0).max(1).optional()
|
|
938
|
+
strength: z.number().min(0).max(1).optional(),
|
|
939
|
+
/** `reduce-colors` only: target color count. Mutually exclusive with `paletteImage`. */
|
|
940
|
+
numColors: z.number().int().min(2).max(256).optional(),
|
|
941
|
+
/** `reduce-colors` only: manifest-relative image whose colors become the palette. Mutually exclusive with `numColors`. */
|
|
942
|
+
paletteImage: z.string().min(1).optional(),
|
|
943
|
+
/** `reduce-colors` only: ordered dithering matrix size. */
|
|
944
|
+
dithering: RevisionDitheringSchema.optional(),
|
|
945
|
+
/** `reduce-colors` only: dithering intensity; ignored when `dithering` is "none" or unset. */
|
|
946
|
+
ditheringStrength: z.number().min(0).max(10).optional()
|
|
934
947
|
}).strict().superRefine((revision, context) => {
|
|
935
948
|
if (revision.mode === "inpaint" && !revision.mask) {
|
|
936
949
|
context.addIssue({
|
|
@@ -946,6 +959,29 @@ var RevisionSchema = z.object({
|
|
|
946
959
|
path: ["mask"]
|
|
947
960
|
});
|
|
948
961
|
}
|
|
962
|
+
if (revision.numColors !== void 0 && revision.paletteImage !== void 0) {
|
|
963
|
+
context.addIssue({
|
|
964
|
+
code: z.ZodIssueCode.custom,
|
|
965
|
+
message: "numColors and paletteImage are mutually exclusive",
|
|
966
|
+
path: ["numColors"]
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
for (const field of ["numColors", "paletteImage", "dithering", "ditheringStrength"]) {
|
|
970
|
+
if (revision[field] !== void 0 && revision.mode !== "reduce-colors") {
|
|
971
|
+
context.addIssue({
|
|
972
|
+
code: z.ZodIssueCode.custom,
|
|
973
|
+
message: `${field} applies to reduce-colors revisions only`,
|
|
974
|
+
path: [field]
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
if (revision.strength !== void 0 && revision.mode === "reduce-colors") {
|
|
979
|
+
context.addIssue({
|
|
980
|
+
code: z.ZodIssueCode.custom,
|
|
981
|
+
message: "reduce-colors revisions do not take a strength; use dithering/ditheringStrength",
|
|
982
|
+
path: ["strength"]
|
|
983
|
+
});
|
|
984
|
+
}
|
|
949
985
|
});
|
|
950
986
|
var StyleObjectSchema = z.object({
|
|
951
987
|
/** Generation backend for this style. Omit to inherit the manifest default. */
|
|
@@ -1552,7 +1588,11 @@ var LockEntrySchema = z.object({
|
|
|
1552
1588
|
sourceAssetId: z.string().min(1),
|
|
1553
1589
|
sourceSha256: z.string().regex(/^[0-9a-f]{64}$/),
|
|
1554
1590
|
maskSha256: z.string().regex(/^[0-9a-f]{64}$/).optional(),
|
|
1555
|
-
strength: z.number().min(0).max(1).optional()
|
|
1591
|
+
strength: z.number().min(0).max(1).optional(),
|
|
1592
|
+
numColors: z.number().int().min(2).max(256).optional(),
|
|
1593
|
+
paletteImageSha256: z.string().regex(/^[0-9a-f]{64}$/).optional(),
|
|
1594
|
+
dithering: RevisionDitheringSchema.optional(),
|
|
1595
|
+
ditheringStrength: z.number().min(0).max(10).optional()
|
|
1556
1596
|
}).strict().nullable().default(null),
|
|
1557
1597
|
/** For a mirror: the asset it flips and a hash over that asset's output hashes when this was made. */
|
|
1558
1598
|
mirror: z.object({
|
|
@@ -4690,6 +4730,11 @@ var ComfyUIProvider = class _ComfyUIProvider {
|
|
|
4690
4730
|
if (spec.revision.strength != null && !options.bindings.strength) {
|
|
4691
4731
|
throw new Error("ComfyUI revision strength requires bindings.strength");
|
|
4692
4732
|
}
|
|
4733
|
+
if (spec.revision.numColors != null || spec.revision.paletteImageFile || spec.revision.dithering) {
|
|
4734
|
+
throw new Error(
|
|
4735
|
+
"ComfyUI has no binding for numColors/paletteImage/dithering \u2014 those are PixelLab's /reduce-colors parameters. A reduce-colors revision on ComfyUI is whatever your own workflow does with bindings.sourceImage; write that behavior into the graph directly."
|
|
4736
|
+
);
|
|
4737
|
+
}
|
|
4693
4738
|
if ((!options.bindings.width || !options.bindings.height) && spec.revision.sourceWidth != null && spec.revision.sourceHeight != null && (spec.width !== spec.revision.sourceWidth || spec.height !== spec.revision.sourceHeight)) {
|
|
4694
4739
|
throw new Error(
|
|
4695
4740
|
"ComfyUI revisions without width/height bindings must keep the source dimensions"
|
|
@@ -5388,6 +5433,16 @@ var MapObjectSchema = z2.object({
|
|
|
5388
5433
|
}).passthrough();
|
|
5389
5434
|
var ObjectListSchema = z2.object({ objects: z2.array(PixelLabObjectSchema), total: z2.number().int().min(0) }).passthrough();
|
|
5390
5435
|
var PixfluxResponseSchema = z2.object({ image: z2.object({ base64: z2.string().min(1) }).passthrough(), usage: z2.unknown().optional() }).passthrough();
|
|
5436
|
+
var ReduceColorsResponseSchema = z2.object({
|
|
5437
|
+
images: z2.array(z2.object({ base64: z2.string().min(1) }).passthrough()).min(1),
|
|
5438
|
+
palette: z2.object({ base64: z2.string().min(1) }).passthrough(),
|
|
5439
|
+
n_colors: z2.number().int(),
|
|
5440
|
+
usage: z2.unknown().optional()
|
|
5441
|
+
}).passthrough();
|
|
5442
|
+
var CorrectPixelartResponseSchema = z2.object({
|
|
5443
|
+
images: z2.array(z2.object({ base64: z2.string().min(1) }).passthrough()).min(1),
|
|
5444
|
+
usage: z2.unknown().optional()
|
|
5445
|
+
}).passthrough();
|
|
5391
5446
|
var SelectFramesSchema = z2.object({ created_object_ids: z2.array(z2.string()) }).passthrough();
|
|
5392
5447
|
var CharacterSubmitSchema = z2.object({
|
|
5393
5448
|
background_job_id: z2.string().min(1),
|
|
@@ -6095,6 +6150,52 @@ var PixelLabClient = class {
|
|
|
6095
6150
|
"generate-image-v2"
|
|
6096
6151
|
);
|
|
6097
6152
|
}
|
|
6153
|
+
/**
|
|
6154
|
+
* `/reduce-colors`, PixelLab's "Cleanup" tier: quantize one image onto a
|
|
6155
|
+
* smaller palette, synchronously — no `background_job_id`, the result
|
|
6156
|
+
* comes back in this same response, like `createImagePixflux`. Verified
|
|
6157
|
+
* against the live OpenAPI schema, not exercised against a live account:
|
|
6158
|
+
* the schema's own response example is `usage: {type: "usd", usd: 0.02}`,
|
|
6159
|
+
* which — going by this codebase's own repeated experience with PixelLab's
|
|
6160
|
+
* documented-vs-billed cost mismatches (`isometricTile`, `objectPro`) —
|
|
6161
|
+
* should not be trusted over a real call. `numColors` and `paletteImage`
|
|
6162
|
+
* are mutually exclusive upstream; the manifest schema already enforces
|
|
6163
|
+
* that before this is ever called.
|
|
6164
|
+
*/
|
|
6165
|
+
async reduceColors(args) {
|
|
6166
|
+
const body = { images: [args.image] };
|
|
6167
|
+
if (args.numColors != null) body.num_colors = args.numColors;
|
|
6168
|
+
if (args.paletteImage) body.palette_image = args.paletteImage;
|
|
6169
|
+
if (args.dithering) body.dithering = args.dithering;
|
|
6170
|
+
if (args.ditheringStrength != null) body.dithering_strength = args.ditheringStrength;
|
|
6171
|
+
const res = validateResponse(
|
|
6172
|
+
ReduceColorsResponseSchema,
|
|
6173
|
+
await this.request("/reduce-colors", { method: "POST", body: JSON.stringify(body) }),
|
|
6174
|
+
"reduce-colors"
|
|
6175
|
+
);
|
|
6176
|
+
return {
|
|
6177
|
+
png: Buffer.from(res.images[0].base64, "base64"),
|
|
6178
|
+
paletteStripPng: Buffer.from(res.palette.base64, "base64"),
|
|
6179
|
+
nColors: res.n_colors,
|
|
6180
|
+
usage: res.usage
|
|
6181
|
+
};
|
|
6182
|
+
}
|
|
6183
|
+
/**
|
|
6184
|
+
* `/correct-pixelart`, PixelLab's "Cleanup" tier: sharpen edges and drop
|
|
6185
|
+
* stray pixels without resizing, synchronously — same shape as
|
|
6186
|
+
* `reduceColors` above, no background job. Cost is likewise unverified
|
|
6187
|
+
* against a live account (schema example: `usage: {type: "usd", usd: 0.02}`).
|
|
6188
|
+
*/
|
|
6189
|
+
async correctPixelart(args) {
|
|
6190
|
+
const body = { images: [args.image] };
|
|
6191
|
+
if (args.strength != null) body.strength = args.strength;
|
|
6192
|
+
const res = validateResponse(
|
|
6193
|
+
CorrectPixelartResponseSchema,
|
|
6194
|
+
await this.request("/correct-pixelart", { method: "POST", body: JSON.stringify(body) }),
|
|
6195
|
+
"correct-pixelart"
|
|
6196
|
+
);
|
|
6197
|
+
return { png: Buffer.from(res.images[0].base64, "base64"), usage: res.usage };
|
|
6198
|
+
}
|
|
6098
6199
|
async getBackgroundJob(jobId) {
|
|
6099
6200
|
const raw = await this.request(`/background-jobs/${encodeURIComponent(jobId)}`);
|
|
6100
6201
|
return validateResponse(BackgroundJobSchema, raw, "background-jobs/{id}");
|
|
@@ -6274,12 +6375,15 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6274
6375
|
}
|
|
6275
6376
|
/**
|
|
6276
6377
|
* `inpaint` (`/inpaint-v3`, a mask) and `image-to-image` (`/edit-images-v2`,
|
|
6277
|
-
* no mask) both exist on PixelLab
|
|
6378
|
+
* no mask) both exist on PixelLab, and so do `reduce-colors`
|
|
6379
|
+
* (`/reduce-colors`) and `correct-pixelart` (`/correct-pixelart`) — PixelLab's
|
|
6380
|
+
* "Cleanup" tier, a mechanical post-process on the source's own pixels
|
|
6381
|
+
* rather than a described edit. `outpaint` does not: there is no
|
|
6278
6382
|
* canvas-expansion endpoint in the API, matching docs/REVISIONS.md's note
|
|
6279
6383
|
* that no provider ships a tested outpaint path yet.
|
|
6280
6384
|
*/
|
|
6281
6385
|
supportsRevision(mode2) {
|
|
6282
|
-
return mode2 === "inpaint" || mode2 === "image-to-image";
|
|
6386
|
+
return mode2 === "inpaint" || mode2 === "image-to-image" || mode2 === "reduce-colors" || mode2 === "correct-pixelart";
|
|
6283
6387
|
}
|
|
6284
6388
|
/** PixelLab's own constraints: submissions must be >2s apart, and
|
|
6285
6389
|
* background jobs in flight are capped by subscription tier (Tier 1=8,
|
|
@@ -6301,6 +6405,9 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6301
6405
|
return dir;
|
|
6302
6406
|
}
|
|
6303
6407
|
estimate(spec) {
|
|
6408
|
+
if (spec.revision?.mode === "reduce-colors" || spec.revision?.mode === "correct-pixelart") {
|
|
6409
|
+
return { unit: "generations", amount: 0.1, candidates: 1 };
|
|
6410
|
+
}
|
|
6304
6411
|
if (spec.revision) {
|
|
6305
6412
|
const width = spec.revision.sourceWidth ?? spec.width;
|
|
6306
6413
|
const height = spec.revision.sourceHeight ?? spec.height;
|
|
@@ -6328,6 +6435,20 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6328
6435
|
throw new Error(`PixelLab inpaint source is ${width}x${height}; the API takes 32 to 512 pixels per side`);
|
|
6329
6436
|
}
|
|
6330
6437
|
}
|
|
6438
|
+
if (spec.revision?.mode === "reduce-colors") {
|
|
6439
|
+
const { sourceWidth: width, sourceHeight: height } = spec.revision;
|
|
6440
|
+
if (width != null && height != null && width * height > 512 * 512) {
|
|
6441
|
+
throw new Error(
|
|
6442
|
+
`PixelLab reduce-colors source is ${width}x${height} (${width * height}px\xB2); the API takes at most 512x512 worth of pixels per call`
|
|
6443
|
+
);
|
|
6444
|
+
}
|
|
6445
|
+
}
|
|
6446
|
+
if (spec.revision?.mode === "correct-pixelart") {
|
|
6447
|
+
const { sourceWidth: width, sourceHeight: height } = spec.revision;
|
|
6448
|
+
if (width != null && height != null && (width > 1024 || height > 1024)) {
|
|
6449
|
+
throw new Error(`PixelLab correct-pixelart source is ${width}x${height}; the API takes at most 1024 pixels per side`);
|
|
6450
|
+
}
|
|
6451
|
+
}
|
|
6331
6452
|
if (spec.generator === "1dir" && (spec.width < 32 || spec.width > 256)) {
|
|
6332
6453
|
throw new Error("PixelLab 1dir dimensions must be between 32 and 256 pixels");
|
|
6333
6454
|
}
|
|
@@ -7120,6 +7241,35 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
7120
7241
|
});
|
|
7121
7242
|
return { jobId: res2.background_job_id };
|
|
7122
7243
|
}
|
|
7244
|
+
if (revision.mode === "reduce-colors") {
|
|
7245
|
+
let paletteImage;
|
|
7246
|
+
if (revision.paletteImageFile) {
|
|
7247
|
+
if (!revision.paletteImageSha256 || !revision.paletteImageFormat) {
|
|
7248
|
+
throw new Error(`${spec.styleId}/${spec.assetId}: revision palette image is not ready`);
|
|
7249
|
+
}
|
|
7250
|
+
const paletteBytes = readFileSync2(revision.paletteImageFile);
|
|
7251
|
+
if (sha256(paletteBytes) !== revision.paletteImageSha256) {
|
|
7252
|
+
throw new Error(`${spec.styleId}/${spec.assetId}: revision palette image changed after the manifest was resolved`);
|
|
7253
|
+
}
|
|
7254
|
+
paletteImage = { base64: paletteBytes.toString("base64"), format: revision.paletteImageFormat };
|
|
7255
|
+
}
|
|
7256
|
+
const res2 = await this.client.reduceColors({
|
|
7257
|
+
image,
|
|
7258
|
+
numColors: revision.numColors,
|
|
7259
|
+
paletteImage,
|
|
7260
|
+
dithering: revision.dithering,
|
|
7261
|
+
ditheringStrength: revision.ditheringStrength
|
|
7262
|
+
});
|
|
7263
|
+
const jobId = randomUUID3();
|
|
7264
|
+
writeFileSync(path12.join(_PixelLabProvider.cacheDir(), `${jobId}.png`), res2.png);
|
|
7265
|
+
return { jobId, metadata: { revisionUsage: res2.usage } };
|
|
7266
|
+
}
|
|
7267
|
+
if (revision.mode === "correct-pixelart") {
|
|
7268
|
+
const res2 = await this.client.correctPixelart({ image, strength: revision.strength });
|
|
7269
|
+
const jobId = randomUUID3();
|
|
7270
|
+
writeFileSync(path12.join(_PixelLabProvider.cacheDir(), `${jobId}.png`), res2.png);
|
|
7271
|
+
return { jobId, metadata: { revisionUsage: res2.usage } };
|
|
7272
|
+
}
|
|
7123
7273
|
if (revision.strength != null) {
|
|
7124
7274
|
throw new Error(
|
|
7125
7275
|
`${spec.styleId}/${spec.assetId}: PixelLab image-to-image revisions take no strength; edit-images-v2 always applies the full instruction`
|
|
@@ -7151,6 +7301,10 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
7151
7301
|
}
|
|
7152
7302
|
}
|
|
7153
7303
|
async poll(jobId, generator, context) {
|
|
7304
|
+
const revisionMode = context?.spec?.revision?.mode;
|
|
7305
|
+
if (revisionMode === "reduce-colors" || revisionMode === "correct-pixelart") {
|
|
7306
|
+
return this.pollCachedRevision(jobId, context);
|
|
7307
|
+
}
|
|
7154
7308
|
if (context?.spec?.revision) return this.pollRevision(jobId);
|
|
7155
7309
|
if (generator === "pixflux") {
|
|
7156
7310
|
const file = path12.join(_PixelLabProvider.cacheDir(), `${jobId}.png`);
|
|
@@ -7186,6 +7340,27 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
7186
7340
|
etaSeconds: obj.eta_seconds ?? null
|
|
7187
7341
|
};
|
|
7188
7342
|
}
|
|
7343
|
+
/**
|
|
7344
|
+
* `reduce-colors` and `correct-pixelart` results are already on disk by
|
|
7345
|
+
* the time `poll` is first called — `submitRevision` wrote them
|
|
7346
|
+
* synchronously, the same way `pixflux`'s poll branch above checks its own
|
|
7347
|
+
* cache file rather than a provider resource. The billed amount, if any,
|
|
7348
|
+
* travels through `context.metadata.revisionUsage` since there is no
|
|
7349
|
+
* background job to ask afterwards the way `billedForJob` does for async
|
|
7350
|
+
* work.
|
|
7351
|
+
*/
|
|
7352
|
+
async pollCachedRevision(jobId, context) {
|
|
7353
|
+
const file = path12.join(_PixelLabProvider.cacheDir(), `${jobId}.png`);
|
|
7354
|
+
if (!existsSync7(file)) {
|
|
7355
|
+
return {
|
|
7356
|
+
status: "failed",
|
|
7357
|
+
error: "revision result is no longer cached locally; re-run submit for this asset"
|
|
7358
|
+
};
|
|
7359
|
+
}
|
|
7360
|
+
const sourceUrl = `file://${file}`;
|
|
7361
|
+
const usage = context?.metadata?.revisionUsage;
|
|
7362
|
+
return { status: "ready", objectId: jobId, sourceUrl, sources: [{ url: sourceUrl }], billed: billedFromUsage(usage) };
|
|
7363
|
+
}
|
|
7189
7364
|
/**
|
|
7190
7365
|
* `/inpaint-v3` and `/edit-images-v2` both hand back a plain background
|
|
7191
7366
|
* job with no resource of its own, polled generically at
|
|
@@ -9040,6 +9215,8 @@ async function resolveSpecs(loaded, filter) {
|
|
|
9040
9215
|
`Revision mask for ${styleId}/${assetId} is ${maskImage.width}x${maskImage.height}; source ${asset.revision.from} is ${sourceImage.width}x${sourceImage.height}`
|
|
9041
9216
|
);
|
|
9042
9217
|
}
|
|
9218
|
+
const paletteImageFile = asset.revision.paletteImage ? path13.resolve(root, asset.revision.paletteImage) : void 0;
|
|
9219
|
+
const paletteImage = paletteImageFile ? await optionalRevisionImage(paletteImageFile, "revision palette image", "png") : null;
|
|
9043
9220
|
resolved.revision = {
|
|
9044
9221
|
mode: asset.revision.mode,
|
|
9045
9222
|
sourceAssetId: asset.revision.from,
|
|
@@ -9056,7 +9233,17 @@ async function resolveSpecs(loaded, filter) {
|
|
|
9056
9233
|
maskHeight: maskImage?.height ?? null,
|
|
9057
9234
|
maskFormat: maskImage?.format ?? null
|
|
9058
9235
|
} : {},
|
|
9059
|
-
...asset.revision.strength == null ? {} : { strength: asset.revision.strength }
|
|
9236
|
+
...asset.revision.strength == null ? {} : { strength: asset.revision.strength },
|
|
9237
|
+
...asset.revision.numColors == null ? {} : { numColors: asset.revision.numColors },
|
|
9238
|
+
...paletteImageFile ? {
|
|
9239
|
+
paletteImageFile,
|
|
9240
|
+
paletteImageSha256: paletteImage?.hash ?? null,
|
|
9241
|
+
paletteImageWidth: paletteImage?.width ?? null,
|
|
9242
|
+
paletteImageHeight: paletteImage?.height ?? null,
|
|
9243
|
+
paletteImageFormat: paletteImage?.format ?? null
|
|
9244
|
+
} : {},
|
|
9245
|
+
...asset.revision.dithering ? { dithering: asset.revision.dithering } : {},
|
|
9246
|
+
...asset.revision.ditheringStrength == null ? {} : { ditheringStrength: asset.revision.ditheringStrength }
|
|
9060
9247
|
};
|
|
9061
9248
|
}
|
|
9062
9249
|
resolved.specHash = specHash(
|
|
@@ -11426,6 +11613,25 @@ var AssetPatchSchema = z5.object({
|
|
|
11426
11613
|
size: z5.number().int().nullable().optional(),
|
|
11427
11614
|
tags: z5.array(z5.string()).optional()
|
|
11428
11615
|
}).strict();
|
|
11616
|
+
var NewStateSchema = z5.object({
|
|
11617
|
+
/** Asset id of the parent this states; must already exist. */
|
|
11618
|
+
of: z5.string().min(1),
|
|
11619
|
+
paletteFromReference: z5.boolean().optional(),
|
|
11620
|
+
canvas: z5.object({ width: z5.number().int().min(16).max(256), height: z5.number().int().min(16).max(256) }).strict().optional()
|
|
11621
|
+
}).strict();
|
|
11622
|
+
var NewAnimationSchema = z5.object({
|
|
11623
|
+
/** Asset id of the parent this animates; must already exist. */
|
|
11624
|
+
of: z5.string().min(1),
|
|
11625
|
+
/** A PixelLab template id (`character` only; `objectPro` has no template concept). */
|
|
11626
|
+
template: z5.string().min(1).optional(),
|
|
11627
|
+
direction: CharacterDirectionSchema.optional(),
|
|
11628
|
+
frames: z5.number().int().min(4).max(16).optional(),
|
|
11629
|
+
fps: z5.number().int().min(1).max(60).optional(),
|
|
11630
|
+
mode: CharacterAnimationModeSchema.optional(),
|
|
11631
|
+
/** What is being animated, when the parent's own description would mislead the model (`character` only). */
|
|
11632
|
+
subject: z5.string().min(1).optional(),
|
|
11633
|
+
enhancePrompt: z5.boolean().optional()
|
|
11634
|
+
}).strict();
|
|
11429
11635
|
var NewAssetSchema = z5.object({
|
|
11430
11636
|
prompt: z5.string(),
|
|
11431
11637
|
category: z5.string().optional(),
|
|
@@ -11446,8 +11652,16 @@ var NewAssetSchema = z5.object({
|
|
|
11446
11652
|
/** Asset id of the parent this revises; must already exist. */
|
|
11447
11653
|
from: z5.string().min(1),
|
|
11448
11654
|
strength: z5.number().min(0).max(1).optional()
|
|
11449
|
-
}).strict().optional()
|
|
11450
|
-
|
|
11655
|
+
}).strict().optional(),
|
|
11656
|
+
/** A pose or outfit of an existing `character`/`objectPro` base or state. */
|
|
11657
|
+
state: NewStateSchema.optional(),
|
|
11658
|
+
/** A loop of an existing `character`/`objectPro` base or state. */
|
|
11659
|
+
animation: NewAnimationSchema.optional()
|
|
11660
|
+
}).strict().refine((asset) => !(asset.revision && (asset.state || asset.animation)), {
|
|
11661
|
+
message: "an asset is a revision, a state, or an animation \u2014 not more than one"
|
|
11662
|
+
}).refine((asset) => !(asset.state && asset.animation), {
|
|
11663
|
+
message: "an asset is a state or an animation \u2014 not both"
|
|
11664
|
+
});
|
|
11451
11665
|
var CANDIDATE_OPTION = {
|
|
11452
11666
|
retrodiffusion: "numImages",
|
|
11453
11667
|
comfyui: "numImages",
|
|
@@ -11615,6 +11829,12 @@ function applyEdit(raw, edit) {
|
|
|
11615
11829
|
if (edit.asset.revision && !Object.hasOwn(raw.assets, edit.asset.revision.from)) {
|
|
11616
11830
|
throw new ManifestEditError(`revision parent "${edit.asset.revision.from}" is not declared by the manifest`);
|
|
11617
11831
|
}
|
|
11832
|
+
if (edit.asset.state && !Object.hasOwn(raw.assets, edit.asset.state.of)) {
|
|
11833
|
+
throw new ManifestEditError(`state parent "${edit.asset.state.of}" is not declared by the manifest`);
|
|
11834
|
+
}
|
|
11835
|
+
if (edit.asset.animation && !Object.hasOwn(raw.assets, edit.asset.animation.of)) {
|
|
11836
|
+
throw new ManifestEditError(`animation parent "${edit.asset.animation.of}" is not declared by the manifest`);
|
|
11837
|
+
}
|
|
11618
11838
|
raw.assets[edit.assetId] = asset2;
|
|
11619
11839
|
return;
|
|
11620
11840
|
}
|
|
@@ -12265,27 +12485,54 @@ async function samePixels(a, b) {
|
|
|
12265
12485
|
}
|
|
12266
12486
|
var metadataFps = (entry) => entry ? frameSetFps(entry) : null;
|
|
12267
12487
|
function describeCharacter(spec, entry) {
|
|
12268
|
-
const
|
|
12488
|
+
const recordedCharacter = entry?.providerMetadata?.[entry.provider]?.character;
|
|
12269
12489
|
if (spec?.character) {
|
|
12270
12490
|
const character = spec.character;
|
|
12271
12491
|
return {
|
|
12492
|
+
generator: "character",
|
|
12272
12493
|
kind: character.kind,
|
|
12273
12494
|
parentKey: character.parentAssetId ? lockKey(spec.styleId, character.parentAssetId) : null,
|
|
12274
12495
|
mode: character.kind === "animation" ? character.animation.mode : character.mode,
|
|
12275
12496
|
directions: character.directions,
|
|
12276
12497
|
direction: character.animation?.direction ?? null,
|
|
12277
|
-
characterId:
|
|
12498
|
+
characterId: recordedCharacter?.characterId ?? entry?.objectId?.split("#")[0] ?? null
|
|
12499
|
+
};
|
|
12500
|
+
}
|
|
12501
|
+
if (spec?.objectPro) {
|
|
12502
|
+
const objectPro = spec.objectPro;
|
|
12503
|
+
return {
|
|
12504
|
+
generator: "objectPro",
|
|
12505
|
+
kind: objectPro.kind,
|
|
12506
|
+
parentKey: objectPro.parentAssetId ? lockKey(spec.styleId, objectPro.parentAssetId) : null,
|
|
12507
|
+
mode: objectPro.kind === "animation" ? objectPro.animation.mode : "pro-flash",
|
|
12508
|
+
directions: objectPro.directions,
|
|
12509
|
+
direction: objectPro.animation?.direction ?? null,
|
|
12510
|
+
characterId: entry?.objectId?.split("#")[0] ?? null
|
|
12278
12511
|
};
|
|
12279
12512
|
}
|
|
12280
12513
|
if (entry?.generator === "character") {
|
|
12281
|
-
const kind =
|
|
12514
|
+
const kind = recordedCharacter?.kind === "animation" || entry.outputs.some((o) => o.role?.startsWith("frame-")) ? "animation" : "base";
|
|
12282
12515
|
return {
|
|
12516
|
+
generator: "character",
|
|
12283
12517
|
kind,
|
|
12284
12518
|
parentKey: null,
|
|
12285
|
-
mode:
|
|
12286
|
-
directions:
|
|
12287
|
-
direction:
|
|
12288
|
-
characterId:
|
|
12519
|
+
mode: recordedCharacter?.mode ?? "standard",
|
|
12520
|
+
directions: recordedCharacter?.directions ?? entry.outputs.length,
|
|
12521
|
+
direction: recordedCharacter?.direction ?? null,
|
|
12522
|
+
characterId: recordedCharacter?.characterId ?? entry.objectId?.split("#")[0] ?? null
|
|
12523
|
+
};
|
|
12524
|
+
}
|
|
12525
|
+
if (entry?.generator === "objectPro") {
|
|
12526
|
+
const recordedObject = entry.providerMetadata?.[entry.provider]?.objectPro;
|
|
12527
|
+
const kind = recordedObject?.kind === "animation" || entry.outputs.some((o) => o.role?.startsWith("frame-")) ? "animation" : "base";
|
|
12528
|
+
return {
|
|
12529
|
+
generator: "objectPro",
|
|
12530
|
+
kind,
|
|
12531
|
+
parentKey: null,
|
|
12532
|
+
mode: "pro-flash",
|
|
12533
|
+
directions: recordedObject?.directions ?? entry.outputs.length,
|
|
12534
|
+
direction: recordedObject?.direction ?? null,
|
|
12535
|
+
characterId: entry.objectId?.split("#")[0] ?? null
|
|
12289
12536
|
};
|
|
12290
12537
|
}
|
|
12291
12538
|
return null;
|
|
@@ -12621,7 +12868,7 @@ async function buildGallerySnapshot(opts) {
|
|
|
12621
12868
|
view: style?.view ?? null,
|
|
12622
12869
|
noBackground: style?.noBackground ?? true,
|
|
12623
12870
|
quality: Boolean(style?.quality),
|
|
12624
|
-
characters: style?.generator === "character" ? {
|
|
12871
|
+
characters: style?.generator === "character" || style?.generator === "objectPro" ? {
|
|
12625
12872
|
bases: styleItems.filter((item) => item.character?.kind === "base").length,
|
|
12626
12873
|
states: styleItems.filter((item) => item.character?.kind === "state").length,
|
|
12627
12874
|
animations: styleItems.filter((item) => item.character?.kind === "animation").length
|
|
@@ -13352,7 +13599,11 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
|
|
|
13352
13599
|
sourceAssetId: spec.revision.sourceAssetId,
|
|
13353
13600
|
sourceSha256: spec.revision.sourceSha256,
|
|
13354
13601
|
...spec.revision.maskSha256 ? { maskSha256: spec.revision.maskSha256 } : {},
|
|
13355
|
-
...spec.revision.strength == null ? {} : { strength: spec.revision.strength }
|
|
13602
|
+
...spec.revision.strength == null ? {} : { strength: spec.revision.strength },
|
|
13603
|
+
...spec.revision.numColors == null ? {} : { numColors: spec.revision.numColors },
|
|
13604
|
+
...spec.revision.paletteImageSha256 ? { paletteImageSha256: spec.revision.paletteImageSha256 } : {},
|
|
13605
|
+
...spec.revision.dithering ? { dithering: spec.revision.dithering } : {},
|
|
13606
|
+
...spec.revision.ditheringStrength == null ? {} : { ditheringStrength: spec.revision.ditheringStrength }
|
|
13356
13607
|
} : null,
|
|
13357
13608
|
status: "pending",
|
|
13358
13609
|
jobId: previousJobId ?? null,
|