pixelkiln 0.51.0 → 0.52.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 +94 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +94 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +126 -81
- package/dist/index.d.ts +126 -81
- package/dist/index.js +94 -5
- package/dist/index.js.map +1 -1
- package/docs/ENDPOINTS.md +8 -0
- package/package.json +1 -1
- package/schema/manifest.schema.json +4 -2
- package/schema/recipe.schema.json +2 -1
- package/skills/pixelkiln/references/pixellab-roadmap.md +9 -9
- package/skills/pixelkiln/references/pixellab.md +22 -1
package/dist/cli.js
CHANGED
|
@@ -707,7 +707,7 @@ import path2 from "path";
|
|
|
707
707
|
// src/types.ts
|
|
708
708
|
import { z } from "zod";
|
|
709
709
|
var MediaTypeSchema = z.enum(["image/png", "image/gif"]);
|
|
710
|
-
var GeneratorSchema = z.enum(["1dir", "map", "pixflux", "tiles", "animation", "frames", "character", "terrain"]);
|
|
710
|
+
var GeneratorSchema = z.enum(["1dir", "map", "pixflux", "tiles", "animation", "frames", "character", "terrain", "imagePro"]);
|
|
711
711
|
var GridConfidenceSchema = z.enum(["low", "medium", "high"]);
|
|
712
712
|
var RevisionModeSchema = z.enum(["image-to-image", "inpaint", "outpaint"]);
|
|
713
713
|
function tileVariationCount(descriptions) {
|
|
@@ -729,6 +729,7 @@ function candidateCount(size) {
|
|
|
729
729
|
}
|
|
730
730
|
function generationCost(width, height, generator = "map") {
|
|
731
731
|
if (generator === "map" || generator === "pixflux") return 1;
|
|
732
|
+
if (generator === "imagePro") return 40;
|
|
732
733
|
const px = width * height;
|
|
733
734
|
if (px <= 1024) return 20;
|
|
734
735
|
if (px <= 2048) return 25;
|
|
@@ -1227,7 +1228,7 @@ var AssetSchema = z.object({
|
|
|
1227
1228
|
prompt: z.string().optional(),
|
|
1228
1229
|
/** Subdirectory under the style's outDir. Optional. */
|
|
1229
1230
|
category: z.string().optional(),
|
|
1230
|
-
/** Overrides the style default. `map`
|
|
1231
|
+
/** Overrides the style default. `map`, `pixflux`, and `imagePro` only. */
|
|
1231
1232
|
width: z.number().int().min(16).max(8192).optional(),
|
|
1232
1233
|
height: z.number().int().min(16).max(8192).optional(),
|
|
1233
1234
|
/** Overrides the style default. `1dir` generator only. */
|
|
@@ -5833,6 +5834,34 @@ var PixelLabClient = class {
|
|
|
5833
5834
|
"edit-images-v2"
|
|
5834
5835
|
);
|
|
5835
5836
|
}
|
|
5837
|
+
/**
|
|
5838
|
+
* PixelLab's Pro image tier, `/generate-image-v2`: a flat 40 generations
|
|
5839
|
+
* (docs/ENDPOINTS.md, "Single-image generators, measured") for real style
|
|
5840
|
+
* transfer and non-square canvases up to 792x688, where `pixflux` is
|
|
5841
|
+
* limited to 400x400 and no style reference. Like a revision, this hands
|
|
5842
|
+
* back a plain background job with no resource of its own; unlike a
|
|
5843
|
+
* revision, one call returns several candidate images to pick from (the
|
|
5844
|
+
* same 4/16/64-by-size tiering as `1dir`), not a single result, and its
|
|
5845
|
+
* completed shape has not been exercised live yet — `pollImagePro` in
|
|
5846
|
+
* pixellab.ts fails loudly rather than guess if `last_response.images`
|
|
5847
|
+
* turns out not to be the real field name.
|
|
5848
|
+
*
|
|
5849
|
+
* Reference images and a style image (`reference_images`, `style_image` +
|
|
5850
|
+
* `style_options`) exist on this endpoint but are not modeled here yet.
|
|
5851
|
+
*/
|
|
5852
|
+
async createImagePro(args) {
|
|
5853
|
+
const body = {
|
|
5854
|
+
description: args.description,
|
|
5855
|
+
image_size: { width: args.width, height: args.height }
|
|
5856
|
+
};
|
|
5857
|
+
if (args.noBackground != null) body.no_background = args.noBackground;
|
|
5858
|
+
if (args.seed != null) body.seed = args.seed;
|
|
5859
|
+
return validateResponse(
|
|
5860
|
+
RevisionJobSubmitSchema,
|
|
5861
|
+
await this.request("/generate-image-v2", { method: "POST", body: JSON.stringify(body) }),
|
|
5862
|
+
"generate-image-v2"
|
|
5863
|
+
);
|
|
5864
|
+
}
|
|
5836
5865
|
async getBackgroundJob(jobId) {
|
|
5837
5866
|
const raw = await this.request(`/background-jobs/${encodeURIComponent(jobId)}`);
|
|
5838
5867
|
return validateResponse(BackgroundJobSchema, raw, "background-jobs/{id}");
|
|
@@ -5971,7 +6000,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
5971
6000
|
return new _PixelLabProvider(new PixelLabClient("download-only"));
|
|
5972
6001
|
}
|
|
5973
6002
|
supports(generator) {
|
|
5974
|
-
return generator === "1dir" || generator === "map" || generator === "pixflux" || generator === "tiles" || generator === "terrain" || generator === "character";
|
|
6003
|
+
return generator === "1dir" || generator === "map" || generator === "pixflux" || generator === "tiles" || generator === "terrain" || generator === "imagePro" || generator === "character";
|
|
5975
6004
|
}
|
|
5976
6005
|
/**
|
|
5977
6006
|
* `inpaint` (`/inpaint-v3`, a mask) and `image-to-image` (`/edit-images-v2`,
|
|
@@ -6016,7 +6045,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6016
6045
|
return {
|
|
6017
6046
|
unit: "generations",
|
|
6018
6047
|
amount: generationCost(spec.width, spec.height, spec.generator),
|
|
6019
|
-
candidates: spec.generator === "1dir" ? candidateCount(spec.size) : 1
|
|
6048
|
+
candidates: spec.generator === "1dir" || spec.generator === "imagePro" ? candidateCount(spec.size) : 1
|
|
6020
6049
|
};
|
|
6021
6050
|
}
|
|
6022
6051
|
validate(spec, styleImages) {
|
|
@@ -6032,6 +6061,11 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6032
6061
|
if ((spec.generator === "map" || spec.generator === "pixflux") && (spec.width < 16 || spec.height < 16 || spec.width > 400 || spec.height > 400)) {
|
|
6033
6062
|
throw new Error(`PixelLab ${spec.generator} dimensions must be between 16 and 400 pixels`);
|
|
6034
6063
|
}
|
|
6064
|
+
if (spec.generator === "imagePro" && (spec.width < 16 || spec.height < 16 || spec.width > 792 || spec.height > 688)) {
|
|
6065
|
+
throw new Error(
|
|
6066
|
+
`PixelLab imagePro is ${spec.width}x${spec.height}; the API takes 16 to 792 wide and 16 to 688 tall (the exact ceiling also depends on aspect ratio)`
|
|
6067
|
+
);
|
|
6068
|
+
}
|
|
6035
6069
|
if (spec.generator === "map") {
|
|
6036
6070
|
requirePixelLabOption("view", spec.view, ["low top-down", "high top-down", "side"]);
|
|
6037
6071
|
requirePixelLabOption("outline", spec.outline, [
|
|
@@ -6100,6 +6134,11 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6100
6134
|
"PixelLab terrain does not support style images yet; use color_image/reference images directly against /create-tileset if this becomes a real need"
|
|
6101
6135
|
);
|
|
6102
6136
|
}
|
|
6137
|
+
if (spec.generator === "imagePro" && styleImages.length) {
|
|
6138
|
+
throw new Error(
|
|
6139
|
+
"PixelLab imagePro does not support style images yet; /generate-image-v2's own reference_images and style_image are not modeled here"
|
|
6140
|
+
);
|
|
6141
|
+
}
|
|
6103
6142
|
for (const image of styleImages) {
|
|
6104
6143
|
if (image.width > 256 || image.height > 256) {
|
|
6105
6144
|
throw new Error(
|
|
@@ -6482,6 +6521,16 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6482
6521
|
});
|
|
6483
6522
|
return { jobId: res2.tileset_id, metadata: { backgroundJobId: res2.background_job_id } };
|
|
6484
6523
|
}
|
|
6524
|
+
if (spec.generator === "imagePro") {
|
|
6525
|
+
const res2 = await this.client.createImagePro({
|
|
6526
|
+
description: spec.prompt,
|
|
6527
|
+
width: spec.width,
|
|
6528
|
+
height: spec.height,
|
|
6529
|
+
noBackground: spec.noBackground,
|
|
6530
|
+
seed: spec.seed
|
|
6531
|
+
});
|
|
6532
|
+
return { jobId: res2.background_job_id };
|
|
6533
|
+
}
|
|
6485
6534
|
if (spec.generator === "1dir") {
|
|
6486
6535
|
const res2 = await this.client.create1Direction({
|
|
6487
6536
|
description: spec.prompt,
|
|
@@ -6588,6 +6637,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6588
6637
|
if (generator === "map") return this.pollMap(jobId, context);
|
|
6589
6638
|
if (generator === "tiles") return this.pollTiles(jobId, Boolean(context?.tileFeature), context);
|
|
6590
6639
|
if (generator === "terrain") return this.pollTerrain(jobId, context);
|
|
6640
|
+
if (generator === "imagePro") return this.pollImagePro(jobId);
|
|
6591
6641
|
if (generator === "character") return this.pollCharacter(jobId, context);
|
|
6592
6642
|
const backgroundJobId = context?.metadata?.backgroundJobId;
|
|
6593
6643
|
const obj = await this.client.getObject(jobId);
|
|
@@ -6658,6 +6708,40 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6658
6708
|
error: `Invalid PixelLab response for revision job ${jobId}: completed with no recognized image field (got: ${Object.keys(done).join(", ") || "no keys"}); update pollRevision in src/providers/pixellab.ts with the real shape`
|
|
6659
6709
|
};
|
|
6660
6710
|
}
|
|
6711
|
+
/**
|
|
6712
|
+
* `/generate-image-v2` hands back a plain background job, the same as a
|
|
6713
|
+
* revision, but a completed one carries several candidate images to
|
|
6714
|
+
* review rather than a single result: the Python client's own usage
|
|
6715
|
+
* sample reads `response.images`, and `edit-images-v2` (a sibling Pro
|
|
6716
|
+
* endpoint) confirmed live that its own array lands at
|
|
6717
|
+
* `last_response.images` with each entry `extractBase64`-shaped, so this
|
|
6718
|
+
* assumes the same field name and shape here. That assumption is
|
|
6719
|
+
* UNVERIFIED for this specific endpoint — no live call has been made to
|
|
6720
|
+
* it — so an unrecognized response still fails loudly rather than
|
|
6721
|
+
* guessing, exactly like pollRevision.
|
|
6722
|
+
*/
|
|
6723
|
+
async pollImagePro(jobId) {
|
|
6724
|
+
const job = await this.client.getBackgroundJob(jobId);
|
|
6725
|
+
if (job.status === "failed") return { status: "failed", error: "imagePro job failed upstream" };
|
|
6726
|
+
if (job.status !== "completed") return { status: "processing" };
|
|
6727
|
+
const billed = billedFromUsage(job.usage);
|
|
6728
|
+
const done = job.last_response ?? {};
|
|
6729
|
+
if (Array.isArray(done.images) && done.images.length) {
|
|
6730
|
+
const urls = [];
|
|
6731
|
+
for (const [index, candidate] of done.images.entries()) {
|
|
6732
|
+
const base64 = extractBase64(candidate);
|
|
6733
|
+
if (!base64) continue;
|
|
6734
|
+
const file = path12.join(_PixelLabProvider.cacheDir(), `${jobId}-${index}.png`);
|
|
6735
|
+
writeFileSync(file, Buffer.from(base64, "base64"));
|
|
6736
|
+
urls.push(`file://${file}`);
|
|
6737
|
+
}
|
|
6738
|
+
if (urls.length) return { status: "review", candidateUrls: urls, billed };
|
|
6739
|
+
}
|
|
6740
|
+
return {
|
|
6741
|
+
status: "failed",
|
|
6742
|
+
error: `Invalid PixelLab response for imagePro job ${jobId}: completed with no recognized images array (got: ${Object.keys(done).join(", ") || "no keys"}); this endpoint's completed shape has not been exercised live yet -- update pollImagePro in src/providers/pixellab.ts with the real shape`
|
|
6743
|
+
};
|
|
6744
|
+
}
|
|
6661
6745
|
/**
|
|
6662
6746
|
* Map objects need their own path because the `/map-objects/{id}` record is
|
|
6663
6747
|
* deleted upstream roughly 8 hours after creation while the image survives in
|
|
@@ -6770,6 +6854,11 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6770
6854
|
if (!url) throw new Error(`tiles job ${jobId} has no variation at index ${index}`);
|
|
6771
6855
|
return { objectId: `${jobId}#${index}`, sourceUrl: url };
|
|
6772
6856
|
}
|
|
6857
|
+
if (generator === "imagePro") {
|
|
6858
|
+
const file = path12.join(_PixelLabProvider.cacheDir(), `${jobId}-${index}.png`);
|
|
6859
|
+
if (!existsSync7(file)) throw new Error(`imagePro job ${jobId} has no cached candidate at index ${index}`);
|
|
6860
|
+
return { objectId: `${jobId}#${index}`, sourceUrl: `file://${file}` };
|
|
6861
|
+
}
|
|
6773
6862
|
const promoted = await this.client.selectFrames(jobId, [index], commonTag);
|
|
6774
6863
|
const objectId = promoted.created_object_ids?.[0];
|
|
6775
6864
|
if (!objectId) {
|
|
@@ -8206,7 +8295,7 @@ async function resolveSpecs(loaded, filter) {
|
|
|
8206
8295
|
...generator === "character" ? { character: await resolveCharacterShape(asset, style, characterKind, { root, load: loadStyleImage }) } : {},
|
|
8207
8296
|
cost: generator === "tiles" ? tilesCost(tileSize, tileVariations) : generator === "terrain" ? tilesCost(size, terrainTiles) : generationCost(width, height, generator),
|
|
8208
8297
|
costUnit: "generations",
|
|
8209
|
-
candidates: generator === "tiles" ? tileVariations : generator === "terrain" ? terrainTiles : generator === "1dir" ? candidateCount(size) : 1
|
|
8298
|
+
candidates: generator === "tiles" ? tileVariations : generator === "terrain" ? terrainTiles : generator === "1dir" || generator === "imagePro" ? candidateCount(size) : 1
|
|
8210
8299
|
};
|
|
8211
8300
|
const tags = [
|
|
8212
8301
|
.../* @__PURE__ */ new Set([
|