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/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 tile fields are
2726
- // undefined for every other generator. `tileSize` is intentionally
2727
- // absent; width/height are derived from it, so it is already covered.
2728
- noBackground: spec.generator === "pixflux" || spec.provider !== "pixellab" ? spec.noBackground : void 0,
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,