pixelkiln 0.45.0 → 0.46.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/index.js CHANGED
@@ -90,7 +90,7 @@ var MIRRORED_DIRECTION = {
90
90
  west: "east",
91
91
  "south-west": "south-east"
92
92
  };
93
- var CharacterModeSchema = z.enum(["standard", "v3", "pro"]);
93
+ var CharacterModeSchema = z.enum(["standard", "v3", "pro", "pro-flash"]);
94
94
  var CHARACTER_PROPORTION_PRESETS = ["default", "chibi", "cartoon", "stylized", "realistic_male", "realistic_female", "heroic"];
95
95
  var CharacterProportionsSchema = z.union([
96
96
  z.enum(CHARACTER_PROPORTION_PRESETS),
@@ -286,14 +286,27 @@ var StyleObjectSchema = z.object({
286
286
  /**
287
287
  * `character` only. `standard` draws from a skeleton template for 1
288
288
  * generation; `v3` is the highest quality at 2 to 9 by size; `pro` is a
289
- * reference-based engine at 20 to 40 by size. States inherit the
290
- * parent's engine; animations choose their own.
289
+ * reference-based engine at 20 to 40 by size; `pro-flash` draws a
290
+ * south sprite with PixelLab's newest image model and rotates it with
291
+ * v3, 6 to 17 by size, or the rotations alone (1 at 64px) from a
292
+ * `reference`. States inherit the parent's engine; animations choose
293
+ * their own.
291
294
  */
292
295
  mode: CharacterModeSchema.optional(),
293
- /** `character` only. Rotations per base or state. `v3` and `pro` always draw 8. */
296
+ /** `character` only. Rotations per base or state. Every engine but `standard` draws 8. */
294
297
  directions: z.union([z.literal(4), z.literal(8)]).optional(),
295
- /** `character` only. Body template: `mannequin` (default) or a quadruped (`bear`, `cat`, `dog`, `horse`, `lion`). */
298
+ /** `character` only. Body template: `mannequin` (default), a quadruped (`bear`, `cat`, `dog`, `horse`, `lion`), or `custom` for `pro-flash`. */
296
299
  template: z.string().min(1).optional(),
300
+ /**
301
+ * `character` only, `pro-flash` bases with a style image: which traits
302
+ * the style image lends. Each defaults to true.
303
+ */
304
+ styleTraits: z.object({
305
+ palette: z.boolean().optional(),
306
+ outline: z.boolean().optional(),
307
+ detail: z.boolean().optional(),
308
+ shading: z.boolean().optional()
309
+ }).strict().optional(),
297
310
  /** `character` only, `standard` humanoid bases. A preset or multipliers; an asset may override it. */
298
311
  proportions: CharacterProportionsSchema.optional(),
299
312
  /**
@@ -1262,6 +1275,29 @@ var PixelLabClient = class {
1262
1275
  ...south ? { reference_image: encode(south) } : {},
1263
1276
  ...args.enhancePrompt ? { enhance_prompt: true } : {}
1264
1277
  };
1278
+ } else if (args.mode === "pro-flash") {
1279
+ path33 = "/create-character-pro-flash";
1280
+ const traits = args.styleTraits;
1281
+ body = {
1282
+ description: args.description,
1283
+ template_id: args.template,
1284
+ n_directions: 8,
1285
+ // The author's sprite sets the canvas; a size only applies to text creation.
1286
+ ...south ? { first_frame: encode(south) } : { image_size: imageSize },
1287
+ ...args.view ? { view: args.view } : {},
1288
+ ...args.seed != null ? { seed: args.seed } : {},
1289
+ ...args.styleReference && args.styleReferenceSize ? {
1290
+ style_image: { image: encode(args.styleReference), size: args.styleReferenceSize },
1291
+ ...traits ? {
1292
+ style_options: {
1293
+ ...traits.palette !== void 0 ? { color_palette: traits.palette } : {},
1294
+ ...traits.outline !== void 0 ? { outline: traits.outline } : {},
1295
+ ...traits.detail !== void 0 ? { detail: traits.detail } : {},
1296
+ ...traits.shading !== void 0 ? { shading: traits.shading } : {}
1297
+ }
1298
+ } : {}
1299
+ } : {}
1300
+ };
1265
1301
  } else if (args.mode === "pro") {
1266
1302
  path33 = "/create-character-pro";
1267
1303
  body = {
@@ -2036,6 +2072,7 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
2036
2072
  textGuidanceScale: spec.character.textGuidanceScale,
2037
2073
  isometric: spec.character.isometric,
2038
2074
  enhancePrompt: spec.character.enhancePrompt,
2075
+ styleTraits: spec.character.styleTraits,
2039
2076
  reference: spec.character.reference ? Object.fromEntries(Object.entries(spec.character.reference).map(([direction, image]) => [direction, image.sha256])) : void 0,
2040
2077
  concept: spec.character.concept?.sha256,
2041
2078
  styleAnchor: spec.character.styleAnchor ? { of: spec.character.styleAnchor.assetId, sha256: spec.character.styleAnchor.sha256 } : void 0
@@ -2079,12 +2116,24 @@ function characterCost(spec) {
2079
2116
  if (character.kind === "state") return generationCost(spec.width, spec.height, "1dir");
2080
2117
  if (character.mode === "standard") return 1;
2081
2118
  if (character.mode === "v3") return 1 + Math.max(1, Math.ceil(px * 8 / 65536));
2119
+ if (character.mode === "pro-flash") {
2120
+ const south = character.reference?.south;
2121
+ return south ? proFlashCharacterCost(south.width, south.height, true) : proFlashCharacterCost(spec.width, spec.height, false);
2122
+ }
2082
2123
  return generationCost(spec.width, spec.height, "1dir");
2083
2124
  }
2125
+ function proFlashCharacterCost(width, height, fromReference) {
2126
+ const side = Math.max(32, Math.ceil(Math.max(width, height) / 4) * 4);
2127
+ const rotations = Math.max(1, Math.ceil(side * side * 8 / 65536));
2128
+ if (fromReference) return rotations;
2129
+ const image = side <= 96 ? 5 : side <= 208 ? 6 : 9;
2130
+ return image + rotations;
2131
+ }
2084
2132
  function characterAnimationName(spec) {
2085
2133
  return `pixelkiln:${spec.styleId}/${spec.assetId}`;
2086
2134
  }
2087
2135
  var CHARACTER_TEMPLATES = ["mannequin", "bear", "cat", "dog", "horse", "lion"];
2136
+ var PRO_FLASH_TEMPLATES = [...CHARACTER_TEMPLATES, "custom"];
2088
2137
  function encodeAnimationJob(job) {
2089
2138
  return `character-animation:${Buffer.from(JSON.stringify(job)).toString("base64url")}`;
2090
2139
  }
@@ -2243,7 +2292,7 @@ var PixelLabProvider = class _PixelLabProvider {
2243
2292
  if (!character.reference.south) throw new Error(`${label}: a reference needs a south-facing sprite`);
2244
2293
  if (character.mode !== "standard") {
2245
2294
  if (given.length > 1) throw new Error(`${label}: PixelLab ${character.mode} rotates one south-facing reference; drop the other directions`);
2246
- const limit = character.mode === "v3" ? 256 : 168;
2295
+ const limit = character.mode === "pro" ? 168 : 256;
2247
2296
  const south = character.reference.south;
2248
2297
  if (south.width > limit || south.height > limit) {
2249
2298
  throw new Error(`${label}: reference is ${south.width}x${south.height}; PixelLab ${character.mode} takes up to ${limit}px`);
@@ -2267,26 +2316,39 @@ var PixelLabProvider = class _PixelLabProvider {
2267
2316
  }
2268
2317
  }
2269
2318
  if (styleImages.length) {
2270
- if (character.mode !== "pro") {
2319
+ if (character.mode !== "pro" && character.mode !== "pro-flash") {
2271
2320
  throw new Error(
2272
- `PixelLab ${character.mode} characters take no style images; give a base its own sprite with \`reference\`, or use mode pro for a style anchor`
2321
+ `PixelLab ${character.mode} characters take no style images; give a base its own sprite with \`reference\`, or use mode pro or pro-flash for a style anchor`
2273
2322
  );
2274
2323
  }
2275
- if (styleImages.length > 1) throw new Error("PixelLab pro characters take one style image");
2324
+ if (styleImages.length > 1) throw new Error(`PixelLab ${character.mode} characters take one style image`);
2276
2325
  if (character.kind === "base" && character.reference) {
2277
- throw new Error(`${label}: a pro base rotating its own reference takes no style image`);
2326
+ throw new Error(`${label}: a ${character.mode} base rotating its own reference takes no style image`);
2278
2327
  }
2279
2328
  const image = styleImages[0];
2280
- if (image.width > 168 || image.height > 168) {
2281
- throw new Error(`PixelLab pro character style image is ${image.width}x${image.height}; the limit is 168px`);
2329
+ const limit = character.mode === "pro" ? 168 : 256;
2330
+ if (image.width > limit || image.height > limit) {
2331
+ throw new Error(`PixelLab ${character.mode} character style image is ${image.width}x${image.height}; the limit is ${limit}px`);
2332
+ }
2333
+ if (character.mode === "pro-flash" && (image.width > spec.width || image.height > spec.height)) {
2334
+ throw new Error(
2335
+ `PixelLab pro-flash style image is ${image.width}x${image.height} but the character is ${spec.width}x${spec.height}; crop the image to its subject or raise the style's size`
2336
+ );
2282
2337
  }
2283
2338
  }
2284
- const maxSize = character.mode === "v3" ? 256 : 128;
2339
+ if (character.styleTraits && character.mode !== "pro-flash") {
2340
+ throw new Error(`${label}: styleTraits choose what a pro-flash style image lends; the ${character.mode} engine does not take them`);
2341
+ }
2342
+ const maxSize = character.mode === "v3" || character.mode === "pro-flash" ? 256 : 128;
2285
2343
  if (spec.width < 16 || spec.height < 16 || spec.width > maxSize || spec.height > maxSize) {
2286
2344
  throw new Error(`PixelLab ${character.mode} characters must be between 16 and ${maxSize} pixels`);
2287
2345
  }
2288
- if (!CHARACTER_TEMPLATES.includes(character.template)) {
2289
- throw new Error(`PixelLab character template must be one of: ${CHARACTER_TEMPLATES.join(", ")}`);
2346
+ if (character.mode === "pro-flash" && character.kind === "base" && (spec.width % 4 || spec.height % 4)) {
2347
+ throw new Error(`PixelLab pro-flash characters are sized in multiples of 4 pixels; ${spec.width}x${spec.height} is not`);
2348
+ }
2349
+ const templates = character.mode === "pro-flash" ? PRO_FLASH_TEMPLATES : CHARACTER_TEMPLATES;
2350
+ if (!templates.includes(character.template)) {
2351
+ throw new Error(`PixelLab ${character.mode} character template must be one of: ${templates.join(", ")}`);
2290
2352
  }
2291
2353
  const views = character.mode === "standard" ? ["low top-down", "high top-down", "side", "perspective", "oblique"] : ["low top-down", "high top-down", "side"];
2292
2354
  if (!views.includes(spec.view)) {
@@ -2341,7 +2403,9 @@ var PixelLabProvider = class _PixelLabProvider {
2341
2403
  styleReference: styleImage ? { base64: styleImage.base64, format: styleImage.format } : void 0,
2342
2404
  enhancePrompt: character.enhancePrompt,
2343
2405
  concept: character.concept ? readPose(spec, "concept image", character.concept) : void 0,
2344
- styleCharacterId: character.styleAnchor ? requireStyleObjectId(spec, context) : void 0
2406
+ styleCharacterId: character.styleAnchor ? requireStyleObjectId(spec, context) : void 0,
2407
+ styleReferenceSize: styleImage ? { width: styleImage.width, height: styleImage.height } : void 0,
2408
+ styleTraits: character.styleTraits
2345
2409
  });
2346
2410
  return { jobId: res2.character_id, metadata: { character: { kind: "base", characterId: res2.character_id, mode: character.mode, directions: character.directions, backgroundJobId: res2.background_job_id } } };
2347
2411
  }
@@ -5630,7 +5694,8 @@ async function resolveCharacterShape(asset, style, kind, files) {
5630
5694
  ...proportions !== void 0 ? { proportions } : {},
5631
5695
  ...style.textGuidanceScale !== void 0 ? { textGuidanceScale: style.textGuidanceScale } : {},
5632
5696
  ...style.isometric !== void 0 ? { isometric: style.isometric } : {},
5633
- ...style.enhancePrompt !== void 0 ? { enhancePrompt: style.enhancePrompt } : {}
5697
+ ...style.enhancePrompt !== void 0 ? { enhancePrompt: style.enhancePrompt } : {},
5698
+ ...style.styleTraits ? { styleTraits: style.styleTraits } : {}
5634
5699
  };
5635
5700
  if (asset.concept) {
5636
5701
  const image = await files.load(asset.concept, "Concept image");