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.cjs CHANGED
@@ -389,7 +389,7 @@ var MIRRORED_DIRECTION = {
389
389
  west: "east",
390
390
  "south-west": "south-east"
391
391
  };
392
- var CharacterModeSchema = import_zod.z.enum(["standard", "v3", "pro"]);
392
+ var CharacterModeSchema = import_zod.z.enum(["standard", "v3", "pro", "pro-flash"]);
393
393
  var CHARACTER_PROPORTION_PRESETS = ["default", "chibi", "cartoon", "stylized", "realistic_male", "realistic_female", "heroic"];
394
394
  var CharacterProportionsSchema = import_zod.z.union([
395
395
  import_zod.z.enum(CHARACTER_PROPORTION_PRESETS),
@@ -585,14 +585,27 @@ var StyleObjectSchema = import_zod.z.object({
585
585
  /**
586
586
  * `character` only. `standard` draws from a skeleton template for 1
587
587
  * generation; `v3` is the highest quality at 2 to 9 by size; `pro` is a
588
- * reference-based engine at 20 to 40 by size. States inherit the
589
- * parent's engine; animations choose their own.
588
+ * reference-based engine at 20 to 40 by size; `pro-flash` draws a
589
+ * south sprite with PixelLab's newest image model and rotates it with
590
+ * v3, 6 to 17 by size, or the rotations alone (1 at 64px) from a
591
+ * `reference`. States inherit the parent's engine; animations choose
592
+ * their own.
590
593
  */
591
594
  mode: CharacterModeSchema.optional(),
592
- /** `character` only. Rotations per base or state. `v3` and `pro` always draw 8. */
595
+ /** `character` only. Rotations per base or state. Every engine but `standard` draws 8. */
593
596
  directions: import_zod.z.union([import_zod.z.literal(4), import_zod.z.literal(8)]).optional(),
594
- /** `character` only. Body template: `mannequin` (default) or a quadruped (`bear`, `cat`, `dog`, `horse`, `lion`). */
597
+ /** `character` only. Body template: `mannequin` (default), a quadruped (`bear`, `cat`, `dog`, `horse`, `lion`), or `custom` for `pro-flash`. */
595
598
  template: import_zod.z.string().min(1).optional(),
599
+ /**
600
+ * `character` only, `pro-flash` bases with a style image: which traits
601
+ * the style image lends. Each defaults to true.
602
+ */
603
+ styleTraits: import_zod.z.object({
604
+ palette: import_zod.z.boolean().optional(),
605
+ outline: import_zod.z.boolean().optional(),
606
+ detail: import_zod.z.boolean().optional(),
607
+ shading: import_zod.z.boolean().optional()
608
+ }).strict().optional(),
596
609
  /** `character` only, `standard` humanoid bases. A preset or multipliers; an asset may override it. */
597
610
  proportions: CharacterProportionsSchema.optional(),
598
611
  /**
@@ -1561,6 +1574,29 @@ var PixelLabClient = class {
1561
1574
  ...south ? { reference_image: encode(south) } : {},
1562
1575
  ...args.enhancePrompt ? { enhance_prompt: true } : {}
1563
1576
  };
1577
+ } else if (args.mode === "pro-flash") {
1578
+ path33 = "/create-character-pro-flash";
1579
+ const traits = args.styleTraits;
1580
+ body = {
1581
+ description: args.description,
1582
+ template_id: args.template,
1583
+ n_directions: 8,
1584
+ // The author's sprite sets the canvas; a size only applies to text creation.
1585
+ ...south ? { first_frame: encode(south) } : { image_size: imageSize },
1586
+ ...args.view ? { view: args.view } : {},
1587
+ ...args.seed != null ? { seed: args.seed } : {},
1588
+ ...args.styleReference && args.styleReferenceSize ? {
1589
+ style_image: { image: encode(args.styleReference), size: args.styleReferenceSize },
1590
+ ...traits ? {
1591
+ style_options: {
1592
+ ...traits.palette !== void 0 ? { color_palette: traits.palette } : {},
1593
+ ...traits.outline !== void 0 ? { outline: traits.outline } : {},
1594
+ ...traits.detail !== void 0 ? { detail: traits.detail } : {},
1595
+ ...traits.shading !== void 0 ? { shading: traits.shading } : {}
1596
+ }
1597
+ } : {}
1598
+ } : {}
1599
+ };
1564
1600
  } else if (args.mode === "pro") {
1565
1601
  path33 = "/create-character-pro";
1566
1602
  body = {
@@ -2335,6 +2371,7 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
2335
2371
  textGuidanceScale: spec.character.textGuidanceScale,
2336
2372
  isometric: spec.character.isometric,
2337
2373
  enhancePrompt: spec.character.enhancePrompt,
2374
+ styleTraits: spec.character.styleTraits,
2338
2375
  reference: spec.character.reference ? Object.fromEntries(Object.entries(spec.character.reference).map(([direction, image]) => [direction, image.sha256])) : void 0,
2339
2376
  concept: spec.character.concept?.sha256,
2340
2377
  styleAnchor: spec.character.styleAnchor ? { of: spec.character.styleAnchor.assetId, sha256: spec.character.styleAnchor.sha256 } : void 0
@@ -2378,12 +2415,24 @@ function characterCost(spec) {
2378
2415
  if (character.kind === "state") return generationCost(spec.width, spec.height, "1dir");
2379
2416
  if (character.mode === "standard") return 1;
2380
2417
  if (character.mode === "v3") return 1 + Math.max(1, Math.ceil(px * 8 / 65536));
2418
+ if (character.mode === "pro-flash") {
2419
+ const south = character.reference?.south;
2420
+ return south ? proFlashCharacterCost(south.width, south.height, true) : proFlashCharacterCost(spec.width, spec.height, false);
2421
+ }
2381
2422
  return generationCost(spec.width, spec.height, "1dir");
2382
2423
  }
2424
+ function proFlashCharacterCost(width, height, fromReference) {
2425
+ const side = Math.max(32, Math.ceil(Math.max(width, height) / 4) * 4);
2426
+ const rotations = Math.max(1, Math.ceil(side * side * 8 / 65536));
2427
+ if (fromReference) return rotations;
2428
+ const image = side <= 96 ? 5 : side <= 208 ? 6 : 9;
2429
+ return image + rotations;
2430
+ }
2383
2431
  function characterAnimationName(spec) {
2384
2432
  return `pixelkiln:${spec.styleId}/${spec.assetId}`;
2385
2433
  }
2386
2434
  var CHARACTER_TEMPLATES = ["mannequin", "bear", "cat", "dog", "horse", "lion"];
2435
+ var PRO_FLASH_TEMPLATES = [...CHARACTER_TEMPLATES, "custom"];
2387
2436
  function encodeAnimationJob(job) {
2388
2437
  return `character-animation:${Buffer.from(JSON.stringify(job)).toString("base64url")}`;
2389
2438
  }
@@ -2542,7 +2591,7 @@ var PixelLabProvider = class _PixelLabProvider {
2542
2591
  if (!character.reference.south) throw new Error(`${label}: a reference needs a south-facing sprite`);
2543
2592
  if (character.mode !== "standard") {
2544
2593
  if (given.length > 1) throw new Error(`${label}: PixelLab ${character.mode} rotates one south-facing reference; drop the other directions`);
2545
- const limit = character.mode === "v3" ? 256 : 168;
2594
+ const limit = character.mode === "pro" ? 168 : 256;
2546
2595
  const south = character.reference.south;
2547
2596
  if (south.width > limit || south.height > limit) {
2548
2597
  throw new Error(`${label}: reference is ${south.width}x${south.height}; PixelLab ${character.mode} takes up to ${limit}px`);
@@ -2566,26 +2615,39 @@ var PixelLabProvider = class _PixelLabProvider {
2566
2615
  }
2567
2616
  }
2568
2617
  if (styleImages.length) {
2569
- if (character.mode !== "pro") {
2618
+ if (character.mode !== "pro" && character.mode !== "pro-flash") {
2570
2619
  throw new Error(
2571
- `PixelLab ${character.mode} characters take no style images; give a base its own sprite with \`reference\`, or use mode pro for a style anchor`
2620
+ `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`
2572
2621
  );
2573
2622
  }
2574
- if (styleImages.length > 1) throw new Error("PixelLab pro characters take one style image");
2623
+ if (styleImages.length > 1) throw new Error(`PixelLab ${character.mode} characters take one style image`);
2575
2624
  if (character.kind === "base" && character.reference) {
2576
- throw new Error(`${label}: a pro base rotating its own reference takes no style image`);
2625
+ throw new Error(`${label}: a ${character.mode} base rotating its own reference takes no style image`);
2577
2626
  }
2578
2627
  const image = styleImages[0];
2579
- if (image.width > 168 || image.height > 168) {
2580
- throw new Error(`PixelLab pro character style image is ${image.width}x${image.height}; the limit is 168px`);
2628
+ const limit = character.mode === "pro" ? 168 : 256;
2629
+ if (image.width > limit || image.height > limit) {
2630
+ throw new Error(`PixelLab ${character.mode} character style image is ${image.width}x${image.height}; the limit is ${limit}px`);
2631
+ }
2632
+ if (character.mode === "pro-flash" && (image.width > spec.width || image.height > spec.height)) {
2633
+ throw new Error(
2634
+ `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`
2635
+ );
2581
2636
  }
2582
2637
  }
2583
- const maxSize = character.mode === "v3" ? 256 : 128;
2638
+ if (character.styleTraits && character.mode !== "pro-flash") {
2639
+ throw new Error(`${label}: styleTraits choose what a pro-flash style image lends; the ${character.mode} engine does not take them`);
2640
+ }
2641
+ const maxSize = character.mode === "v3" || character.mode === "pro-flash" ? 256 : 128;
2584
2642
  if (spec.width < 16 || spec.height < 16 || spec.width > maxSize || spec.height > maxSize) {
2585
2643
  throw new Error(`PixelLab ${character.mode} characters must be between 16 and ${maxSize} pixels`);
2586
2644
  }
2587
- if (!CHARACTER_TEMPLATES.includes(character.template)) {
2588
- throw new Error(`PixelLab character template must be one of: ${CHARACTER_TEMPLATES.join(", ")}`);
2645
+ if (character.mode === "pro-flash" && character.kind === "base" && (spec.width % 4 || spec.height % 4)) {
2646
+ throw new Error(`PixelLab pro-flash characters are sized in multiples of 4 pixels; ${spec.width}x${spec.height} is not`);
2647
+ }
2648
+ const templates = character.mode === "pro-flash" ? PRO_FLASH_TEMPLATES : CHARACTER_TEMPLATES;
2649
+ if (!templates.includes(character.template)) {
2650
+ throw new Error(`PixelLab ${character.mode} character template must be one of: ${templates.join(", ")}`);
2589
2651
  }
2590
2652
  const views = character.mode === "standard" ? ["low top-down", "high top-down", "side", "perspective", "oblique"] : ["low top-down", "high top-down", "side"];
2591
2653
  if (!views.includes(spec.view)) {
@@ -2640,7 +2702,9 @@ var PixelLabProvider = class _PixelLabProvider {
2640
2702
  styleReference: styleImage ? { base64: styleImage.base64, format: styleImage.format } : void 0,
2641
2703
  enhancePrompt: character.enhancePrompt,
2642
2704
  concept: character.concept ? readPose(spec, "concept image", character.concept) : void 0,
2643
- styleCharacterId: character.styleAnchor ? requireStyleObjectId(spec, context) : void 0
2705
+ styleCharacterId: character.styleAnchor ? requireStyleObjectId(spec, context) : void 0,
2706
+ styleReferenceSize: styleImage ? { width: styleImage.width, height: styleImage.height } : void 0,
2707
+ styleTraits: character.styleTraits
2644
2708
  });
2645
2709
  return { jobId: res2.character_id, metadata: { character: { kind: "base", characterId: res2.character_id, mode: character.mode, directions: character.directions, backgroundJobId: res2.background_job_id } } };
2646
2710
  }
@@ -5929,7 +5993,8 @@ async function resolveCharacterShape(asset, style, kind, files) {
5929
5993
  ...proportions !== void 0 ? { proportions } : {},
5930
5994
  ...style.textGuidanceScale !== void 0 ? { textGuidanceScale: style.textGuidanceScale } : {},
5931
5995
  ...style.isometric !== void 0 ? { isometric: style.isometric } : {},
5932
- ...style.enhancePrompt !== void 0 ? { enhancePrompt: style.enhancePrompt } : {}
5996
+ ...style.enhancePrompt !== void 0 ? { enhancePrompt: style.enhancePrompt } : {},
5997
+ ...style.styleTraits ? { styleTraits: style.styleTraits } : {}
5933
5998
  };
5934
5999
  if (asset.concept) {
5935
6000
  const image = await files.load(asset.concept, "Concept image");