pixelkiln 0.53.4 → 0.54.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 +143 -13
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +145 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +284 -79
- package/dist/index.d.ts +284 -79
- package/dist/index.js +144 -13
- package/dist/index.js.map +1 -1
- package/docs/ENDPOINTS.md +47 -2
- package/docs/GENERATORS.md +40 -0
- package/docs/MANIFEST.md +1 -1
- package/package.json +1 -1
- package/schema/manifest.schema.json +34 -2
- package/schema/recipe.schema.json +17 -1
- package/skills/pixelkiln/references/pixellab-roadmap.md +18 -0
- package/skills/pixelkiln/references/pixellab.md +30 -0
package/dist/cli.js
CHANGED
|
@@ -653,6 +653,8 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
|
|
|
653
653
|
tileView: spec.tileView,
|
|
654
654
|
tileFeature: spec.tileFeature,
|
|
655
655
|
outlineMode: spec.outlineMode,
|
|
656
|
+
isometricTileSize: spec.isometricTileSize,
|
|
657
|
+
isometricTileShape: spec.isometricTileShape,
|
|
656
658
|
styleImages: styleImageHashes,
|
|
657
659
|
// A character family: the engine and rotations of a base, the parent's
|
|
658
660
|
// generated bytes for a state or animation (so a regenerated parent
|
|
@@ -707,7 +709,7 @@ import path2 from "path";
|
|
|
707
709
|
// src/types.ts
|
|
708
710
|
import { z } from "zod";
|
|
709
711
|
var MediaTypeSchema = z.enum(["image/png", "image/gif"]);
|
|
710
|
-
var GeneratorSchema = z.enum(["1dir", "map", "pixflux", "tiles", "animation", "frames", "character", "terrain", "imagePro"]);
|
|
712
|
+
var GeneratorSchema = z.enum(["1dir", "map", "pixflux", "tiles", "animation", "frames", "character", "terrain", "imagePro", "isometricTile"]);
|
|
711
713
|
var GridConfidenceSchema = z.enum(["low", "medium", "high"]);
|
|
712
714
|
var RevisionModeSchema = z.enum(["image-to-image", "inpaint", "outpaint"]);
|
|
713
715
|
function tileVariationCount(descriptions) {
|
|
@@ -741,6 +743,9 @@ function tilesCost(tileSize, variations) {
|
|
|
741
743
|
if (px <= 2048) return 25;
|
|
742
744
|
return 40;
|
|
743
745
|
}
|
|
746
|
+
function isometricTileCost() {
|
|
747
|
+
return 1;
|
|
748
|
+
}
|
|
744
749
|
function terrainTileCount(transitionSize) {
|
|
745
750
|
return transitionSize === 1 ? 25 : 16;
|
|
746
751
|
}
|
|
@@ -1070,6 +1075,20 @@ var StyleObjectSchema = z.object({
|
|
|
1070
1075
|
/** `terrain` generator only. Camera angle; the API default is `high
|
|
1071
1076
|
* top-down`. */
|
|
1072
1077
|
terrainView: z.enum(["low top-down", "high top-down"]).optional(),
|
|
1078
|
+
/**
|
|
1079
|
+
* `isometricTile` generator only. `/create-isometric-tile`'s own tile
|
|
1080
|
+
* grid size, distinct from `size` (the generation canvas, 16-64px — the
|
|
1081
|
+
* API's own guidance is that sizes above 24px "often produce better
|
|
1082
|
+
* quality results"). The API default is 16.
|
|
1083
|
+
*/
|
|
1084
|
+
isometricTileSize: z.union([z.literal(16), z.literal(32)]).optional(),
|
|
1085
|
+
/**
|
|
1086
|
+
* `isometricTile` generator only. Vertical thickness, i.e. how much
|
|
1087
|
+
* height/elevation variation the tile can represent on a map: `"thin
|
|
1088
|
+
* tile"` (~15% of canvas height), `"thick tile"` (~25%), or `"block"`
|
|
1089
|
+
* (~50%, the API default).
|
|
1090
|
+
*/
|
|
1091
|
+
isometricTileShape: z.enum(["thin tile", "thick tile", "block"]).optional(),
|
|
1073
1092
|
/**
|
|
1074
1093
|
* `pixflux` only. Whether to strip the generated background.
|
|
1075
1094
|
*
|
|
@@ -5249,6 +5268,15 @@ var TilesetGetSchema = z2.object({
|
|
|
5249
5268
|
}).passthrough(),
|
|
5250
5269
|
usage: UsageSchema
|
|
5251
5270
|
}).passthrough();
|
|
5271
|
+
var IsometricTileSubmitSchema = z2.object({
|
|
5272
|
+
tile_id: z2.string().min(1),
|
|
5273
|
+
background_job_id: z2.string().min(1),
|
|
5274
|
+
status: z2.literal("processing").default("processing")
|
|
5275
|
+
}).passthrough();
|
|
5276
|
+
var IsometricTileGetSchema = z2.object({
|
|
5277
|
+
image: z2.object({ base64: z2.string().min(1), format: z2.string().default("png") }).passthrough(),
|
|
5278
|
+
usage: UsageSchema
|
|
5279
|
+
}).passthrough();
|
|
5252
5280
|
var RevisionJobSubmitSchema = z2.object({
|
|
5253
5281
|
background_job_id: z2.string().min(1),
|
|
5254
5282
|
status: z2.string().default("processing")
|
|
@@ -5534,6 +5562,33 @@ var PixelLabClient = class {
|
|
|
5534
5562
|
);
|
|
5535
5563
|
return { tileset: res.tileset, usage: res.usage ?? null };
|
|
5536
5564
|
}
|
|
5565
|
+
/** A single standalone isometric tile — no connectable set, no candidates. */
|
|
5566
|
+
async createIsometricTile(args) {
|
|
5567
|
+
const body = { description: args.description };
|
|
5568
|
+
if (args.imageWidth != null && args.imageHeight != null) {
|
|
5569
|
+
body.image_size = { width: args.imageWidth, height: args.imageHeight };
|
|
5570
|
+
}
|
|
5571
|
+
if (args.tileSize != null) body.isometric_tile_size = args.tileSize;
|
|
5572
|
+
if (args.tileShape) body.isometric_tile_shape = args.tileShape;
|
|
5573
|
+
if (args.outline) body.outline = args.outline;
|
|
5574
|
+
if (args.shading) body.shading = args.shading;
|
|
5575
|
+
if (args.detail) body.detail = args.detail;
|
|
5576
|
+
if (args.seed != null) body.seed = args.seed;
|
|
5577
|
+
return validateResponse(
|
|
5578
|
+
IsometricTileSubmitSchema,
|
|
5579
|
+
await this.request("/create-isometric-tile", { method: "POST", body: JSON.stringify(body) }),
|
|
5580
|
+
"create isometric tile"
|
|
5581
|
+
);
|
|
5582
|
+
}
|
|
5583
|
+
/** Throws PixelLabError(423) while the tile is still processing. */
|
|
5584
|
+
async getIsometricTile(tileId) {
|
|
5585
|
+
const res = await validateResponse(
|
|
5586
|
+
IsometricTileGetSchema,
|
|
5587
|
+
await this.request(`/isometric-tiles/${tileId}`),
|
|
5588
|
+
"get isometric tile"
|
|
5589
|
+
);
|
|
5590
|
+
return { image: res.image, usage: res.usage ?? null };
|
|
5591
|
+
}
|
|
5537
5592
|
/**
|
|
5538
5593
|
* Synchronous single-image generation. Returns the PNG inline rather than a
|
|
5539
5594
|
* job id, and is the only endpoint that honours a forced palette;
|
|
@@ -6000,7 +6055,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6000
6055
|
return new _PixelLabProvider(new PixelLabClient("download-only"));
|
|
6001
6056
|
}
|
|
6002
6057
|
supports(generator) {
|
|
6003
|
-
return generator === "1dir" || generator === "map" || generator === "pixflux" || generator === "tiles" || generator === "terrain" || generator === "imagePro" || generator === "character";
|
|
6058
|
+
return generator === "1dir" || generator === "map" || generator === "pixflux" || generator === "tiles" || generator === "terrain" || generator === "imagePro" || generator === "character" || generator === "isometricTile";
|
|
6004
6059
|
}
|
|
6005
6060
|
/**
|
|
6006
6061
|
* `inpaint` (`/inpaint-v3`, a mask) and `image-to-image` (`/edit-images-v2`,
|
|
@@ -6036,7 +6091,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6036
6091
|
const height = spec.revision.sourceHeight ?? spec.height;
|
|
6037
6092
|
return { unit: "generations", amount: generationCost(width, height, "1dir"), candidates: 1 };
|
|
6038
6093
|
}
|
|
6039
|
-
if (spec.generator === "tiles" || spec.generator === "terrain") {
|
|
6094
|
+
if (spec.generator === "tiles" || spec.generator === "terrain" || spec.generator === "isometricTile") {
|
|
6040
6095
|
return { unit: "generations", amount: spec.cost, candidates: spec.candidates };
|
|
6041
6096
|
}
|
|
6042
6097
|
if (spec.generator === "character") {
|
|
@@ -6067,19 +6122,19 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6067
6122
|
);
|
|
6068
6123
|
}
|
|
6069
6124
|
if (spec.generator === "map") {
|
|
6070
|
-
requirePixelLabOption("view", spec.view, ["low top-down", "high top-down", "side"]);
|
|
6071
|
-
requirePixelLabOption("outline", spec.outline, [
|
|
6125
|
+
requirePixelLabOption("map", "view", spec.view, ["low top-down", "high top-down", "side"]);
|
|
6126
|
+
requirePixelLabOption("map", "outline", spec.outline, [
|
|
6072
6127
|
"single color outline",
|
|
6073
6128
|
"selective outline",
|
|
6074
6129
|
"lineless"
|
|
6075
6130
|
]);
|
|
6076
|
-
requirePixelLabOption("shading", spec.shading, [
|
|
6131
|
+
requirePixelLabOption("map", "shading", spec.shading, [
|
|
6077
6132
|
"flat shading",
|
|
6078
6133
|
"basic shading",
|
|
6079
6134
|
"medium shading",
|
|
6080
6135
|
"detailed shading"
|
|
6081
6136
|
]);
|
|
6082
|
-
requirePixelLabOption("detail", spec.detail, [
|
|
6137
|
+
requirePixelLabOption("map", "detail", spec.detail, [
|
|
6083
6138
|
"low detail",
|
|
6084
6139
|
"medium detail",
|
|
6085
6140
|
"high detail"
|
|
@@ -6087,7 +6142,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6087
6142
|
}
|
|
6088
6143
|
if (spec.generator === "terrain") {
|
|
6089
6144
|
if (spec.outline) {
|
|
6090
|
-
requirePixelLabOption("outline", spec.outline, [
|
|
6145
|
+
requirePixelLabOption("terrain", "outline", spec.outline, [
|
|
6091
6146
|
"single color black outline",
|
|
6092
6147
|
"single color outline",
|
|
6093
6148
|
"selective outline",
|
|
@@ -6095,7 +6150,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6095
6150
|
]);
|
|
6096
6151
|
}
|
|
6097
6152
|
if (spec.shading) {
|
|
6098
|
-
requirePixelLabOption("shading", spec.shading, [
|
|
6153
|
+
requirePixelLabOption("terrain", "shading", spec.shading, [
|
|
6099
6154
|
"flat shading",
|
|
6100
6155
|
"basic shading",
|
|
6101
6156
|
"medium shading",
|
|
@@ -6104,7 +6159,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6104
6159
|
]);
|
|
6105
6160
|
}
|
|
6106
6161
|
if (spec.detail) {
|
|
6107
|
-
requirePixelLabOption("detail", spec.detail, ["low detail", "medium detail", "highly detailed"]);
|
|
6162
|
+
requirePixelLabOption("terrain", "detail", spec.detail, ["low detail", "medium detail", "highly detailed"]);
|
|
6108
6163
|
}
|
|
6109
6164
|
if (spec.terrainShapeStyle && spec.terrainMode === "pro") {
|
|
6110
6165
|
throw new Error(
|
|
@@ -6125,6 +6180,30 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6125
6180
|
);
|
|
6126
6181
|
}
|
|
6127
6182
|
}
|
|
6183
|
+
if (spec.generator === "isometricTile") {
|
|
6184
|
+
if (spec.outline) {
|
|
6185
|
+
requirePixelLabOption("isometricTile", "outline", spec.outline, [
|
|
6186
|
+
"single color outline",
|
|
6187
|
+
"selective outline",
|
|
6188
|
+
"lineless"
|
|
6189
|
+
]);
|
|
6190
|
+
}
|
|
6191
|
+
if (spec.shading) {
|
|
6192
|
+
requirePixelLabOption("isometricTile", "shading", spec.shading, [
|
|
6193
|
+
"flat shading",
|
|
6194
|
+
"basic shading",
|
|
6195
|
+
"medium shading",
|
|
6196
|
+
"detailed shading",
|
|
6197
|
+
"highly detailed shading"
|
|
6198
|
+
]);
|
|
6199
|
+
}
|
|
6200
|
+
if (spec.detail) {
|
|
6201
|
+
requirePixelLabOption("isometricTile", "detail", spec.detail, ["low detail", "medium detail", "highly detailed"]);
|
|
6202
|
+
}
|
|
6203
|
+
if (spec.width < 16 || spec.width > 64) {
|
|
6204
|
+
throw new Error(`PixelLab isometricTile: size must be 16 to 64 pixels, got ${spec.width}`);
|
|
6205
|
+
}
|
|
6206
|
+
}
|
|
6128
6207
|
if (spec.generator === "character") this.validateCharacter(spec, styleImages);
|
|
6129
6208
|
if ((spec.generator === "map" || spec.generator === "pixflux") && styleImages.length) {
|
|
6130
6209
|
throw new Error(`PixelLab ${spec.generator} does not support style images`);
|
|
@@ -6139,6 +6218,11 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6139
6218
|
"PixelLab imagePro does not support style images yet; /generate-image-v2's own reference_images and style_image are not modeled here"
|
|
6140
6219
|
);
|
|
6141
6220
|
}
|
|
6221
|
+
if (spec.generator === "isometricTile" && styleImages.length) {
|
|
6222
|
+
throw new Error(
|
|
6223
|
+
"PixelLab isometricTile does not support style images; /create-isometric-tile has no such field (its own init_image/color_image are not modeled here yet)"
|
|
6224
|
+
);
|
|
6225
|
+
}
|
|
6142
6226
|
for (const image of styleImages) {
|
|
6143
6227
|
if (image.width > 256 || image.height > 256) {
|
|
6144
6228
|
throw new Error(
|
|
@@ -6521,6 +6605,20 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6521
6605
|
});
|
|
6522
6606
|
return { jobId: res2.tileset_id, metadata: { backgroundJobId: res2.background_job_id } };
|
|
6523
6607
|
}
|
|
6608
|
+
if (spec.generator === "isometricTile") {
|
|
6609
|
+
const res2 = await this.client.createIsometricTile({
|
|
6610
|
+
description: spec.prompt,
|
|
6611
|
+
imageWidth: spec.width,
|
|
6612
|
+
imageHeight: spec.height,
|
|
6613
|
+
tileSize: spec.isometricTileSize,
|
|
6614
|
+
tileShape: spec.isometricTileShape,
|
|
6615
|
+
outline: spec.outline,
|
|
6616
|
+
shading: spec.shading,
|
|
6617
|
+
detail: spec.detail,
|
|
6618
|
+
seed: spec.seed
|
|
6619
|
+
});
|
|
6620
|
+
return { jobId: res2.tile_id, metadata: { backgroundJobId: res2.background_job_id } };
|
|
6621
|
+
}
|
|
6524
6622
|
if (spec.generator === "imagePro") {
|
|
6525
6623
|
const res2 = await this.client.createImagePro({
|
|
6526
6624
|
description: spec.prompt,
|
|
@@ -6637,6 +6735,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6637
6735
|
if (generator === "map") return this.pollMap(jobId, context);
|
|
6638
6736
|
if (generator === "tiles") return this.pollTiles(jobId, Boolean(context?.tileFeature), context);
|
|
6639
6737
|
if (generator === "terrain") return this.pollTerrain(jobId, context);
|
|
6738
|
+
if (generator === "isometricTile") return this.pollIsometricTile(jobId, context);
|
|
6640
6739
|
if (generator === "imagePro") return this.pollImagePro(jobId);
|
|
6641
6740
|
if (generator === "character") return this.pollCharacter(jobId, context);
|
|
6642
6741
|
const backgroundJobId = context?.metadata?.backgroundJobId;
|
|
@@ -6847,6 +6946,31 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
6847
6946
|
throw err;
|
|
6848
6947
|
}
|
|
6849
6948
|
}
|
|
6949
|
+
/**
|
|
6950
|
+
* `/create-isometric-tile` reports progress the same way `/create-tileset`
|
|
6951
|
+
* does (423 while drawing, 200 once finished, no `status` field to poll),
|
|
6952
|
+
* and its image also comes back embedded as base64 rather than a
|
|
6953
|
+
* `storage_urls` link. One call is one tile with nothing to review, so
|
|
6954
|
+
* this goes straight to "ready" like a connectable `tiles`/`terrain` set.
|
|
6955
|
+
*/
|
|
6956
|
+
async pollIsometricTile(tileId, context) {
|
|
6957
|
+
try {
|
|
6958
|
+
const { image, usage } = await this.client.getIsometricTile(tileId);
|
|
6959
|
+
const backgroundJobId = context?.metadata?.backgroundJobId;
|
|
6960
|
+
const billed = billedFromUsage(usage) ?? await this.billedForJob(backgroundJobId);
|
|
6961
|
+
const file = path12.join(_PixelLabProvider.cacheDir(), `${tileId}.png`);
|
|
6962
|
+
writeFileSync(file, Buffer.from(image.base64, "base64"));
|
|
6963
|
+
return {
|
|
6964
|
+
status: "ready",
|
|
6965
|
+
objectId: tileId,
|
|
6966
|
+
sourceUrl: `file://${file}`,
|
|
6967
|
+
billed
|
|
6968
|
+
};
|
|
6969
|
+
} catch (err) {
|
|
6970
|
+
if (err instanceof PixelLabError && err.status === 423) return { status: "processing" };
|
|
6971
|
+
throw err;
|
|
6972
|
+
}
|
|
6973
|
+
}
|
|
6850
6974
|
async selectCandidate(jobId, index, commonTag, generator) {
|
|
6851
6975
|
if (generator === "tiles") {
|
|
6852
6976
|
const set = await this.client.getTilesPro(jobId);
|
|
@@ -6963,9 +7087,9 @@ function remoteCharacter(character) {
|
|
|
6963
7087
|
animationCount: character.animation_count
|
|
6964
7088
|
};
|
|
6965
7089
|
}
|
|
6966
|
-
function requirePixelLabOption(name, value, allowed) {
|
|
7090
|
+
function requirePixelLabOption(generator, name, value, allowed) {
|
|
6967
7091
|
if (value != null && !allowed.includes(value)) {
|
|
6968
|
-
throw new Error(`PixelLab
|
|
7092
|
+
throw new Error(`PixelLab ${generator} ${name} must be one of: ${allowed.join(", ")}`);
|
|
6969
7093
|
}
|
|
6970
7094
|
}
|
|
6971
7095
|
function tilesInIndexOrder(urls) {
|
|
@@ -8206,6 +8330,10 @@ async function resolveSpecs(loaded, filter) {
|
|
|
8206
8330
|
size = style.terrainTileSize ?? 16;
|
|
8207
8331
|
width = size;
|
|
8208
8332
|
height = size;
|
|
8333
|
+
} else if (generator === "isometricTile") {
|
|
8334
|
+
size = asset.size ?? style.size ?? 32;
|
|
8335
|
+
width = size;
|
|
8336
|
+
height = size;
|
|
8209
8337
|
} else {
|
|
8210
8338
|
width = asset.width ?? style.size ?? 64;
|
|
8211
8339
|
height = asset.height ?? style.size ?? 64;
|
|
@@ -8299,8 +8427,10 @@ async function resolveSpecs(loaded, filter) {
|
|
|
8299
8427
|
terrainRaggedness: generator === "terrain" ? style.terrainRaggedness : void 0,
|
|
8300
8428
|
terrainTransitionSize: generator === "terrain" ? style.terrainTransitionSize : void 0,
|
|
8301
8429
|
terrainView: generator === "terrain" ? style.terrainView : void 0,
|
|
8430
|
+
isometricTileSize: generator === "isometricTile" ? style.isometricTileSize : void 0,
|
|
8431
|
+
isometricTileShape: generator === "isometricTile" ? style.isometricTileShape : void 0,
|
|
8302
8432
|
...generator === "character" ? { character: await resolveCharacterShape(asset, style, characterKind, { root, load: loadStyleImage }) } : {},
|
|
8303
|
-
cost: generator === "tiles" ? tilesCost(tileSize, tileVariations) : generator === "terrain" ? tilesCost(size, terrainTiles) : generationCost(width, height, generator),
|
|
8433
|
+
cost: generator === "tiles" ? tilesCost(tileSize, tileVariations) : generator === "terrain" ? tilesCost(size, terrainTiles) : generator === "isometricTile" ? isometricTileCost() : generationCost(width, height, generator),
|
|
8304
8434
|
costUnit: "generations",
|
|
8305
8435
|
candidates: generator === "tiles" ? tileVariations : generator === "terrain" ? terrainTiles : generator === "1dir" || generator === "imagePro" ? candidateCount(size) : 1
|
|
8306
8436
|
};
|