pixelkiln 0.59.0 → 0.60.1
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 +174 -6
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +178 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1030 -135
- package/dist/index.d.ts +1030 -135
- package/dist/index.js +176 -6
- package/dist/index.js.map +1 -1
- package/docs/CHARACTERS.md +8 -2
- package/docs/ENDPOINTS.md +68 -5
- package/docs/GENERATORS.md +46 -0
- package/docs/MANIFEST.md +3 -1
- package/docs/PIXELLAB.md +5 -0
- package/docs/README.md +0 -1
- package/docs/REVISIONS.md +12 -0
- package/package.json +1 -2
- package/schema/manifest.schema.json +156 -2
- package/schema/recipe.schema.json +6 -1
- package/skills/pixelkiln/references/pixellab-roadmap.md +150 -21
- package/skills/pixelkiln/references/pixellab.md +76 -1
- package/skills/pixelkiln/references/revisions.md +6 -1
- package/NAMING.md +0 -87
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/types.ts
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
var MediaTypeSchema = z.enum(["image/png", "image/gif"]);
|
|
4
|
-
var GeneratorSchema = z.enum(["1dir", "map", "pixflux", "tiles", "animation", "frames", "character", "terrain", "imagePro", "isometricTile", "objectPro"]);
|
|
4
|
+
var GeneratorSchema = z.enum(["1dir", "map", "pixflux", "tiles", "animation", "frames", "character", "terrain", "imagePro", "isometricTile", "objectPro", "uiAsset"]);
|
|
5
5
|
var GridConfidenceSchema = z.enum(["low", "medium", "high"]);
|
|
6
6
|
var RevisionModeSchema = z.enum([
|
|
7
7
|
"image-to-image",
|
|
@@ -123,6 +123,50 @@ var CharacterProportionsSchema = z.union([
|
|
|
123
123
|
}).strict()
|
|
124
124
|
]);
|
|
125
125
|
var CharacterAnimationModeSchema = z.enum(["template", "v3", "pro"]);
|
|
126
|
+
var UiPieceSchema = z.discriminatedUnion("kind", [
|
|
127
|
+
z.object({
|
|
128
|
+
id: z.string().min(1),
|
|
129
|
+
kind: z.literal("rounded_rect"),
|
|
130
|
+
label: z.string().optional(),
|
|
131
|
+
x: z.number(),
|
|
132
|
+
y: z.number(),
|
|
133
|
+
w: z.number(),
|
|
134
|
+
h: z.number(),
|
|
135
|
+
radius: z.number().min(0).optional()
|
|
136
|
+
}).strict(),
|
|
137
|
+
z.object({
|
|
138
|
+
id: z.string().min(1),
|
|
139
|
+
kind: z.literal("circle"),
|
|
140
|
+
label: z.string().optional(),
|
|
141
|
+
x: z.number(),
|
|
142
|
+
y: z.number(),
|
|
143
|
+
r: z.number()
|
|
144
|
+
}).strict(),
|
|
145
|
+
z.object({
|
|
146
|
+
id: z.string().min(1),
|
|
147
|
+
kind: z.literal("polygon"),
|
|
148
|
+
label: z.string().optional(),
|
|
149
|
+
x: z.number(),
|
|
150
|
+
y: z.number(),
|
|
151
|
+
r: z.number(),
|
|
152
|
+
sides: z.number().int().min(3),
|
|
153
|
+
phase: z.number().optional()
|
|
154
|
+
}).strict()
|
|
155
|
+
]);
|
|
156
|
+
var UiElementSchema = z.enum([
|
|
157
|
+
"button",
|
|
158
|
+
"icon_button",
|
|
159
|
+
"toolbar",
|
|
160
|
+
"tab",
|
|
161
|
+
"panel",
|
|
162
|
+
"window",
|
|
163
|
+
"health_bar",
|
|
164
|
+
"avatar",
|
|
165
|
+
"triangle",
|
|
166
|
+
"pentagon",
|
|
167
|
+
"hexagon",
|
|
168
|
+
"octagon"
|
|
169
|
+
]);
|
|
126
170
|
var AssetBatchSchema = z.object({
|
|
127
171
|
/** The batch leader: another `1dir` asset in the same style. */
|
|
128
172
|
of: z.string().min(1),
|
|
@@ -425,6 +469,12 @@ var StyleObjectSchema = z.object({
|
|
|
425
469
|
* in place of `terrainShapeStyle`. The API default is `standard`.
|
|
426
470
|
*/
|
|
427
471
|
terrainMode: z.enum(["standard", "pro"]).optional(),
|
|
472
|
+
/**
|
|
473
|
+
* `uiAsset` generator only. A natural-language palette hint sent as-is
|
|
474
|
+
* (e.g. "brown and gold"), distinct from `palette`'s hex-color array —
|
|
475
|
+
* this is a prompt-level steer, not a local quantization target.
|
|
476
|
+
*/
|
|
477
|
+
uiColorPalette: z.string().max(200).optional(),
|
|
428
478
|
/**
|
|
429
479
|
* `terrain` generator only, `terrainMode: "standard"`. Procedural
|
|
430
480
|
* boundary geometry: `square` or `round`, 16px or 32px tiles only.
|
|
@@ -708,6 +758,10 @@ var AssetSchema = z.object({
|
|
|
708
758
|
* `AssetBatchSchema`.
|
|
709
759
|
*/
|
|
710
760
|
batch: AssetBatchSchema.optional(),
|
|
761
|
+
/** `uiAsset` styles: precise shape regions the panel is composited from. Combine with `elements`; omit both for a default full-canvas panel. */
|
|
762
|
+
pieces: z.array(UiPieceSchema).min(1).optional(),
|
|
763
|
+
/** `uiAsset` styles: named, auto-positioned UI element scaffolds. Combine with `pieces`; omit both for a default full-canvas panel. */
|
|
764
|
+
elements: z.array(UiElementSchema).min(1).optional(),
|
|
711
765
|
/** `character` styles, `standard` humanoid bases: this character's proportions, over the style's. */
|
|
712
766
|
proportions: CharacterProportionsSchema.optional(),
|
|
713
767
|
/**
|
|
@@ -1225,6 +1279,19 @@ var IsometricTileGetSchema = z2.object({
|
|
|
1225
1279
|
image: z2.object({ base64: z2.string().min(1), format: z2.string().default("png") }).passthrough(),
|
|
1226
1280
|
usage: UsageSchema
|
|
1227
1281
|
}).passthrough();
|
|
1282
|
+
var UiAssetSubmitSchema = z2.object({
|
|
1283
|
+
ui_asset_id: z2.string().min(1),
|
|
1284
|
+
background_job_id: z2.string().min(1),
|
|
1285
|
+
status: z2.string().default("processing"),
|
|
1286
|
+
usage: UsageSchema
|
|
1287
|
+
}).passthrough();
|
|
1288
|
+
var UiAssetGetSchema = z2.object({
|
|
1289
|
+
id: z2.string().min(1),
|
|
1290
|
+
status: z2.string().nullable().default(null),
|
|
1291
|
+
image_url: z2.string().nullable().optional(),
|
|
1292
|
+
progress_percent: z2.number().nullable().optional(),
|
|
1293
|
+
eta_seconds: z2.number().nullable().optional()
|
|
1294
|
+
}).passthrough();
|
|
1228
1295
|
var RevisionJobSubmitSchema = z2.object({
|
|
1229
1296
|
background_job_id: z2.string().min(1),
|
|
1230
1297
|
status: z2.string().default("processing")
|
|
@@ -1585,6 +1652,48 @@ var PixelLabClient = class {
|
|
|
1585
1652
|
);
|
|
1586
1653
|
return { image: res.image, usage: res.usage ?? null };
|
|
1587
1654
|
}
|
|
1655
|
+
/**
|
|
1656
|
+
* `/create-ui-asset`: one composited panel image from a shape template —
|
|
1657
|
+
* `pieces` (precise rect/circle/polygon regions on a virtual 0–512
|
|
1658
|
+
* editor canvas) and/or named `elements` (auto-positioned scaffolds:
|
|
1659
|
+
* button, icon_button, toolbar, tab, panel, window, health_bar, avatar,
|
|
1660
|
+
* triangle, pentagon, hexagon, octagon), or neither for a default
|
|
1661
|
+
* full-canvas rounded-rect panel. Unlike every other generator here, the
|
|
1662
|
+
* result is one flat image with no per-piece sub-regions or nine-slice
|
|
1663
|
+
* metadata returned — cropping a `pieces` layout into separate files
|
|
1664
|
+
* would be pixelkiln's own local work, not modeled yet.
|
|
1665
|
+
*/
|
|
1666
|
+
async createUiAsset(args) {
|
|
1667
|
+
const body = {
|
|
1668
|
+
description: args.description,
|
|
1669
|
+
image_size: { width: args.width, height: args.height }
|
|
1670
|
+
};
|
|
1671
|
+
if (args.pieces?.length) body.pieces = args.pieces;
|
|
1672
|
+
if (args.elements?.length) body.elements = args.elements;
|
|
1673
|
+
if (args.styleImage) body.style_image = args.styleImage;
|
|
1674
|
+
if (args.colorPalette) body.color_palette = args.colorPalette;
|
|
1675
|
+
if (args.noBackground != null) body.no_background = args.noBackground;
|
|
1676
|
+
if (args.seed != null) body.seed = args.seed;
|
|
1677
|
+
const res = await validateResponse(
|
|
1678
|
+
UiAssetSubmitSchema,
|
|
1679
|
+
await this.request("/create-ui-asset", { method: "POST", body: JSON.stringify(body) }),
|
|
1680
|
+
"create ui asset"
|
|
1681
|
+
);
|
|
1682
|
+
return { ui_asset_id: res.ui_asset_id, background_job_id: res.background_job_id, usage: res.usage };
|
|
1683
|
+
}
|
|
1684
|
+
async getUiAsset(uiAssetId) {
|
|
1685
|
+
const res = await validateResponse(
|
|
1686
|
+
UiAssetGetSchema,
|
|
1687
|
+
await this.request(`/ui-assets/${encodeURIComponent(uiAssetId)}`),
|
|
1688
|
+
"get ui asset"
|
|
1689
|
+
);
|
|
1690
|
+
return {
|
|
1691
|
+
status: res.status,
|
|
1692
|
+
imageUrl: res.image_url ?? null,
|
|
1693
|
+
progressPercent: res.progress_percent ?? null,
|
|
1694
|
+
etaSeconds: res.eta_seconds ?? null
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1588
1697
|
/**
|
|
1589
1698
|
* Synchronous single-image generation. Returns the PNG inline rather than a
|
|
1590
1699
|
* job id, and is the only endpoint that honours a forced palette;
|
|
@@ -2722,16 +2831,20 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
|
|
|
2722
2831
|
detail: spec.detail ?? null,
|
|
2723
2832
|
seed: spec.seed ?? null,
|
|
2724
2833
|
palette: spec.palette,
|
|
2725
|
-
// `noBackground` only reaches the wire for pixflux; the
|
|
2726
|
-
// undefined for every other generator. `tileSize` is
|
|
2727
|
-
// absent; width/height are derived from it, so it is
|
|
2728
|
-
|
|
2834
|
+
// `noBackground` only reaches the wire for pixflux and uiAsset; the
|
|
2835
|
+
// tile fields are undefined for every other generator. `tileSize` is
|
|
2836
|
+
// intentionally absent; width/height are derived from it, so it is
|
|
2837
|
+
// already covered.
|
|
2838
|
+
noBackground: spec.generator === "pixflux" || spec.generator === "uiAsset" || spec.provider !== "pixellab" ? spec.noBackground : void 0,
|
|
2729
2839
|
tileType: spec.tileType,
|
|
2730
2840
|
tileView: spec.tileView,
|
|
2731
2841
|
tileFeature: spec.tileFeature,
|
|
2732
2842
|
outlineMode: spec.outlineMode,
|
|
2733
2843
|
isometricTileSize: spec.isometricTileSize,
|
|
2734
2844
|
isometricTileShape: spec.isometricTileShape,
|
|
2845
|
+
uiPieces: spec.uiPieces,
|
|
2846
|
+
uiElements: spec.uiElements,
|
|
2847
|
+
uiColorPalette: spec.uiColorPalette,
|
|
2735
2848
|
styleImages: styleImageHashes,
|
|
2736
2849
|
// A character family: the engine and rotations of a base, the parent's
|
|
2737
2850
|
// generated bytes for a state or animation (so a regenerated parent
|
|
@@ -2929,7 +3042,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2929
3042
|
return new _PixelLabProvider(new PixelLabClient("download-only"));
|
|
2930
3043
|
}
|
|
2931
3044
|
supports(generator) {
|
|
2932
|
-
return generator === "1dir" || generator === "map" || generator === "pixflux" || generator === "tiles" || generator === "terrain" || generator === "imagePro" || generator === "character" || generator === "isometricTile" || generator === "objectPro";
|
|
3045
|
+
return generator === "1dir" || generator === "map" || generator === "pixflux" || generator === "tiles" || generator === "terrain" || generator === "imagePro" || generator === "character" || generator === "isometricTile" || generator === "objectPro" || generator === "uiAsset";
|
|
2933
3046
|
}
|
|
2934
3047
|
/**
|
|
2935
3048
|
* `inpaint` (`/inpaint-v3`, a mask) and `image-to-image` (`/edit-images-v2`,
|
|
@@ -3045,6 +3158,11 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
3045
3158
|
`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)`
|
|
3046
3159
|
);
|
|
3047
3160
|
}
|
|
3161
|
+
if (spec.generator === "uiAsset" && (spec.width < 192 || spec.height < 192 || spec.width > 688 || spec.height > 688)) {
|
|
3162
|
+
throw new Error(
|
|
3163
|
+
`PixelLab uiAsset is ${spec.width}x${spec.height}; the API takes 192 to 688 pixels per side (the exact ceiling also depends on aspect ratio \u2014 square tops out at 512, 16:9 at 688x384, 9:16 at 384x688, 4:3 at 600x448, 3:4 at 448x600)`
|
|
3164
|
+
);
|
|
3165
|
+
}
|
|
3048
3166
|
if (spec.generator === "map") {
|
|
3049
3167
|
requirePixelLabOption("map", "view", spec.view, ["low top-down", "high top-down", "side"]);
|
|
3050
3168
|
requirePixelLabOption("map", "outline", spec.outline, [
|
|
@@ -3682,6 +3800,20 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
3682
3800
|
if (spec.revision) return this.submitRevision(spec);
|
|
3683
3801
|
if (spec.generator === "character") return this.submitCharacter(spec, styleImages, context);
|
|
3684
3802
|
if (spec.generator === "objectPro") return this.submitObjectPro(spec, styleImages, context);
|
|
3803
|
+
if (spec.generator === "uiAsset") {
|
|
3804
|
+
const res2 = await this.client.createUiAsset({
|
|
3805
|
+
description: spec.prompt,
|
|
3806
|
+
width: spec.width,
|
|
3807
|
+
height: spec.height,
|
|
3808
|
+
pieces: spec.uiPieces,
|
|
3809
|
+
elements: spec.uiElements,
|
|
3810
|
+
styleImage: styleImages[0] ? { base64: styleImages[0].base64, format: styleImages[0].format } : void 0,
|
|
3811
|
+
colorPalette: spec.uiColorPalette,
|
|
3812
|
+
noBackground: spec.noBackground,
|
|
3813
|
+
seed: spec.seed
|
|
3814
|
+
});
|
|
3815
|
+
return { jobId: res2.ui_asset_id, metadata: { backgroundJobId: res2.background_job_id } };
|
|
3816
|
+
}
|
|
3685
3817
|
if (spec.generator === "pixflux") {
|
|
3686
3818
|
const swatch = spec.palette.length ? paletteSwatch(spec.palette).toString("base64") : void 0;
|
|
3687
3819
|
const { png } = await this.client.createImagePixflux({
|
|
@@ -3958,6 +4090,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
3958
4090
|
if (generator === "imagePro") return this.pollImagePro(jobId);
|
|
3959
4091
|
if (generator === "character") return this.pollCharacter(jobId, context);
|
|
3960
4092
|
if (generator === "objectPro") return this.pollObjectPro(jobId, context);
|
|
4093
|
+
if (generator === "uiAsset") return this.pollUiAsset(jobId, context);
|
|
3961
4094
|
const backgroundJobId = context?.metadata?.backgroundJobId;
|
|
3962
4095
|
const obj = await this.client.getObject(jobId);
|
|
3963
4096
|
if (obj.status === "review") {
|
|
@@ -4277,6 +4410,29 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
4277
4410
|
throw err;
|
|
4278
4411
|
}
|
|
4279
4412
|
}
|
|
4413
|
+
/**
|
|
4414
|
+
* `/ui-assets/{id}` reports progress with its own `status` field
|
|
4415
|
+
* ("processing"/"completed"/"failed") rather than a 423, and its result is
|
|
4416
|
+
* one flat composited image at a hosted `image_url` — no per-piece
|
|
4417
|
+
* sub-images, no nine-slice metadata, confirmed absent from the response
|
|
4418
|
+
* schema. There is nothing to review: one job is one ready image, like
|
|
4419
|
+
* `isometricTile`.
|
|
4420
|
+
*/
|
|
4421
|
+
async pollUiAsset(uiAssetId, context) {
|
|
4422
|
+
const asset = await this.client.getUiAsset(uiAssetId);
|
|
4423
|
+
if (asset.status === "failed") return { status: "failed", error: "UI asset generation failed upstream" };
|
|
4424
|
+
if (asset.status !== "completed" || !asset.imageUrl) {
|
|
4425
|
+
return { status: "processing", progressPercent: asset.progressPercent, etaSeconds: asset.etaSeconds };
|
|
4426
|
+
}
|
|
4427
|
+
const backgroundJobId = context?.metadata?.backgroundJobId;
|
|
4428
|
+
return {
|
|
4429
|
+
status: "ready",
|
|
4430
|
+
objectId: uiAssetId,
|
|
4431
|
+
sourceUrl: asset.imageUrl,
|
|
4432
|
+
sources: [{ url: asset.imageUrl }],
|
|
4433
|
+
billed: await this.billedForJob(backgroundJobId)
|
|
4434
|
+
};
|
|
4435
|
+
}
|
|
4280
4436
|
async selectCandidate(jobId, index, commonTag, generator) {
|
|
4281
4437
|
if (generator === "tiles") {
|
|
4282
4438
|
const set = await this.client.getTilesPro(jobId);
|
|
@@ -7057,6 +7213,10 @@ async function resolveSpecs(loaded, filter) {
|
|
|
7057
7213
|
size = asset.size ?? style.size ?? 64;
|
|
7058
7214
|
width = size;
|
|
7059
7215
|
height = size;
|
|
7216
|
+
} else if (generator === "uiAsset") {
|
|
7217
|
+
width = asset.width ?? style.size ?? 256;
|
|
7218
|
+
height = asset.height ?? style.size ?? 256;
|
|
7219
|
+
size = Math.max(width, height);
|
|
7060
7220
|
} else {
|
|
7061
7221
|
width = asset.width ?? style.size ?? 64;
|
|
7062
7222
|
height = asset.height ?? style.size ?? 64;
|
|
@@ -7067,6 +7227,11 @@ async function resolveSpecs(loaded, filter) {
|
|
|
7067
7227
|
`assets.${assetId}: ${asset.state ? "state" : "animation"} needs a character or objectPro style; "${styleId}" generates ${generator}`
|
|
7068
7228
|
);
|
|
7069
7229
|
}
|
|
7230
|
+
if ((asset.pieces || asset.elements) && generator !== "uiAsset") {
|
|
7231
|
+
throw new Error(
|
|
7232
|
+
`assets.${assetId}: ${asset.pieces ? "pieces" : "elements"} needs a uiAsset style; "${styleId}" generates ${generator}`
|
|
7233
|
+
);
|
|
7234
|
+
}
|
|
7070
7235
|
const characterKind = asset.animation ? "animation" : asset.state ? "state" : "base";
|
|
7071
7236
|
const subject = asset.promptByStyle[styleId] ?? asset.prompt ?? "";
|
|
7072
7237
|
let terrainLowerDescription;
|
|
@@ -7113,6 +7278,9 @@ async function resolveSpecs(loaded, filter) {
|
|
|
7113
7278
|
shading: style.shading,
|
|
7114
7279
|
detail: style.detail,
|
|
7115
7280
|
seed: style.seed,
|
|
7281
|
+
uiPieces: generator === "uiAsset" ? asset.pieces : void 0,
|
|
7282
|
+
uiElements: generator === "uiAsset" ? asset.elements : void 0,
|
|
7283
|
+
uiColorPalette: generator === "uiAsset" ? style.uiColorPalette : void 0,
|
|
7116
7284
|
palette: style.palette,
|
|
7117
7285
|
enforcePalette: style.enforcePalette,
|
|
7118
7286
|
noBackground: style.noBackground,
|
|
@@ -16223,6 +16391,8 @@ export {
|
|
|
16223
16391
|
ScenarioProvider,
|
|
16224
16392
|
StyleInputSchema,
|
|
16225
16393
|
StyleSchema,
|
|
16394
|
+
UiElementSchema,
|
|
16395
|
+
UiPieceSchema,
|
|
16226
16396
|
UnsupportedCapabilityError,
|
|
16227
16397
|
UsageError,
|
|
16228
16398
|
WorkspaceProjectSchema,
|