pixelkiln 0.44.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/cli.js CHANGED
@@ -676,7 +676,10 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
676
676
  textGuidanceScale: spec.character.textGuidanceScale,
677
677
  isometric: spec.character.isometric,
678
678
  enhancePrompt: spec.character.enhancePrompt,
679
- reference: spec.character.reference ? Object.fromEntries(Object.entries(spec.character.reference).map(([direction, image]) => [direction, image.sha256])) : void 0
679
+ styleTraits: spec.character.styleTraits,
680
+ reference: spec.character.reference ? Object.fromEntries(Object.entries(spec.character.reference).map(([direction, image]) => [direction, image.sha256])) : void 0,
681
+ concept: spec.character.concept?.sha256,
682
+ styleAnchor: spec.character.styleAnchor ? { of: spec.character.styleAnchor.assetId, sha256: spec.character.styleAnchor.sha256 } : void 0
680
683
  } : void 0,
681
684
  // A mirror's bytes come from its source's recorded outputs; the plan
682
685
  // compares those directly, so only the choice of source is identity.
@@ -793,7 +796,7 @@ var MIRRORED_DIRECTION = {
793
796
  west: "east",
794
797
  "south-west": "south-east"
795
798
  };
796
- var CharacterModeSchema = z.enum(["standard", "v3", "pro"]);
799
+ var CharacterModeSchema = z.enum(["standard", "v3", "pro", "pro-flash"]);
797
800
  var CHARACTER_PROPORTION_PRESETS = ["default", "chibi", "cartoon", "stylized", "realistic_male", "realistic_female", "heroic"];
798
801
  var CharacterProportionsSchema = z.union([
799
802
  z.enum(CHARACTER_PROPORTION_PRESETS),
@@ -989,14 +992,27 @@ var StyleObjectSchema = z.object({
989
992
  /**
990
993
  * `character` only. `standard` draws from a skeleton template for 1
991
994
  * generation; `v3` is the highest quality at 2 to 9 by size; `pro` is a
992
- * reference-based engine at 20 to 40 by size. States inherit the
993
- * parent's engine; animations choose their own.
995
+ * reference-based engine at 20 to 40 by size; `pro-flash` draws a
996
+ * south sprite with PixelLab's newest image model and rotates it with
997
+ * v3, 6 to 17 by size, or the rotations alone (1 at 64px) from a
998
+ * `reference`. States inherit the parent's engine; animations choose
999
+ * their own.
994
1000
  */
995
1001
  mode: CharacterModeSchema.optional(),
996
- /** `character` only. Rotations per base or state. `v3` and `pro` always draw 8. */
1002
+ /** `character` only. Rotations per base or state. Every engine but `standard` draws 8. */
997
1003
  directions: z.union([z.literal(4), z.literal(8)]).optional(),
998
- /** `character` only. Body template: `mannequin` (default) or a quadruped (`bear`, `cat`, `dog`, `horse`, `lion`). */
1004
+ /** `character` only. Body template: `mannequin` (default), a quadruped (`bear`, `cat`, `dog`, `horse`, `lion`), or `custom` for `pro-flash`. */
999
1005
  template: z.string().min(1).optional(),
1006
+ /**
1007
+ * `character` only, `pro-flash` bases with a style image: which traits
1008
+ * the style image lends. Each defaults to true.
1009
+ */
1010
+ styleTraits: z.object({
1011
+ palette: z.boolean().optional(),
1012
+ outline: z.boolean().optional(),
1013
+ detail: z.boolean().optional(),
1014
+ shading: z.boolean().optional()
1015
+ }).strict().optional(),
1000
1016
  /** `character` only, `standard` humanoid bases. A preset or multipliers; an asset may override it. */
1001
1017
  proportions: CharacterProportionsSchema.optional(),
1002
1018
  /**
@@ -1009,6 +1025,12 @@ var StyleObjectSchema = z.object({
1009
1025
  isometric: z.boolean().optional(),
1010
1026
  /** `character` only, `v3` bases: let PixelLab expand the prompt into a fuller one before drawing. */
1011
1027
  enhancePrompt: z.boolean().optional(),
1028
+ /**
1029
+ * `character` only, `pro` bases: the asset id of a generated 8-direction
1030
+ * character in this style whose look every base drawn from text or a
1031
+ * concept follows. An asset may override it; the anchor itself ignores it.
1032
+ */
1033
+ styleCharacter: z.string().min(1).optional(),
1012
1034
  /** Fixed seed for reproducibility where the endpoint supports it. */
1013
1035
  seed: z.number().int().optional(),
1014
1036
  /**
@@ -1181,6 +1203,15 @@ var AssetSchema = z.object({
1181
1203
  * still guides the result.
1182
1204
  */
1183
1205
  reference: z.union([z.string().min(1), z.record(CharacterDirectionSchema, z.string().min(1))]).optional(),
1206
+ /**
1207
+ * `character` styles, `pro` bases only: a manifest-relative concept
1208
+ * image (a painting, a photo, a sketch; up to 1024px) that seeds the
1209
+ * design instead of the prompt alone. A style image or `styleCharacter`
1210
+ * may still anchor the look.
1211
+ */
1212
+ concept: z.string().min(1).optional(),
1213
+ /** `character` styles, `pro` bases: this base's style anchor, over the style's. */
1214
+ styleCharacter: z.string().min(1).optional(),
1184
1215
  /**
1185
1216
  * Another asset of the same style flipped left to right, made locally
1186
1217
  * from that asset's downloaded files at no generation cost.
@@ -1262,6 +1293,20 @@ var AssetSchema = z.object({
1262
1293
  path: ["reference"]
1263
1294
  });
1264
1295
  }
1296
+ if (asset.concept && (asset.state || asset.animation || asset.mirror)) {
1297
+ context.addIssue({
1298
+ code: z.ZodIssueCode.custom,
1299
+ message: "a concept image belongs on a base; a state, animation, or mirror takes its look from its parent",
1300
+ path: ["concept"]
1301
+ });
1302
+ }
1303
+ if (asset.concept && asset.reference) {
1304
+ context.addIssue({
1305
+ code: z.ZodIssueCode.custom,
1306
+ message: "concept and reference are mutually exclusive: a concept seeds a new design, a reference is the sprite to rotate",
1307
+ path: ["concept"]
1308
+ });
1309
+ }
1265
1310
  if (typeof asset.reference === "object" && !Object.keys(asset.reference).length) {
1266
1311
  context.addIssue({ code: z.ZodIssueCode.custom, message: "a reference needs at least a south image", path: ["reference"] });
1267
1312
  }
@@ -3629,9 +3674,24 @@ import path8 from "path";
3629
3674
  async function inspectRevisionReadiness(spec, lock) {
3630
3675
  if (spec.mirror) return inspectMirror(spec, lock, /* @__PURE__ */ new Set());
3631
3676
  if (spec.character?.parentSpec) return inspectCharacterParent(spec, lock, /* @__PURE__ */ new Set());
3677
+ if (spec.character?.styleAnchor) return inspectStyleAnchor(spec, lock, /* @__PURE__ */ new Set());
3632
3678
  if (!spec.revision) return null;
3633
3679
  return inspectRevision(spec, lock, /* @__PURE__ */ new Set());
3634
3680
  }
3681
+ async function inspectStyleAnchor(spec, lock, seen) {
3682
+ const anchor = spec.character.styleAnchor;
3683
+ const label = `style anchor ${spec.styleId}/${anchor.assetId}`;
3684
+ const dependency = await inspectParent(anchor.spec, lock, seen);
3685
+ if (!dependency.ready) return { ready: false, reason: `${label} is not ready: ${dependency.reason}` };
3686
+ if (!anchor.sha256 || !existsSync4(anchor.file)) return { ready: false, reason: `${label} has no generated south-facing file yet` };
3687
+ if (await sha256File(anchor.file) !== anchor.sha256) {
3688
+ return { ready: false, reason: `${label} changed after the manifest was resolved` };
3689
+ }
3690
+ if (!lock.entries[lockKey(anchor.spec.styleId, anchor.spec.assetId)]?.objectId) {
3691
+ return { ready: false, reason: `${label} has no PixelLab character id recorded` };
3692
+ }
3693
+ return { ready: true, reason: `${label} is current` };
3694
+ }
3635
3695
  async function inspectMirror(spec, lock, seen) {
3636
3696
  const source = spec.mirror.sourceSpec;
3637
3697
  const label = `mirror source ${spec.styleId}/${spec.mirror.sourceAssetId}`;
@@ -3703,6 +3763,10 @@ async function inspectParent(spec, lock, seen) {
3703
3763
  const inputs = await inspectCharacterParent(spec, lock, nextSeen);
3704
3764
  if (!inputs.ready) return inputs;
3705
3765
  }
3766
+ if (spec.character?.styleAnchor) {
3767
+ const inputs = await inspectStyleAnchor(spec, lock, nextSeen);
3768
+ if (!inputs.ready) return inputs;
3769
+ }
3706
3770
  if (spec.quality) {
3707
3771
  const quality = await inspectQualityProfile(spec, lock);
3708
3772
  return quality?.state === "approved" ? { ready: true, reason: "approved quality output is current" } : {
@@ -3742,6 +3806,14 @@ async function anyOutputModified(entry, spec) {
3742
3806
  }
3743
3807
  return false;
3744
3808
  }
3809
+ function dependencies(spec) {
3810
+ return [
3811
+ spec.mirror?.sourceSpec,
3812
+ spec.revision?.sourceSpec,
3813
+ spec.character?.parentSpec,
3814
+ spec.character?.styleAnchor?.spec
3815
+ ].filter((parent) => Boolean(parent));
3816
+ }
3745
3817
  function resumeCommandForStatus(status) {
3746
3818
  if (status === "pending" || status === "processing") return "poll";
3747
3819
  if (status === "review") return "pick";
@@ -3850,16 +3922,19 @@ async function buildPlan(specs, lock, opts = {}) {
3850
3922
  const stateOf = new Map(items.map((i) => [i.key, i.state]));
3851
3923
  for (const item of items) {
3852
3924
  if (!isActionable(item)) continue;
3853
- const parent = item.spec.mirror?.sourceSpec ?? item.spec.revision?.sourceSpec ?? item.spec.character?.parentSpec;
3854
- if (!parent) continue;
3855
- const parentKey = lockKey(parent.styleId, parent.assetId);
3856
- const parentState = stateOf.get(parentKey);
3857
- if (parentState && isActionable({ state: parentState })) {
3858
- item.state = "blocked";
3859
- item.reason = `parent ${parentKey} is being generated in this run; this follows in the next wave`;
3860
- } else if (item.spec.mirror && (parentState === "recoverable" || parentState === "in-flight")) {
3861
- item.state = "blocked";
3862
- item.reason = `mirror source ${parentKey} is ${parentState}; this follows in the next wave`;
3925
+ for (const parent of dependencies(item.spec)) {
3926
+ const parentKey = lockKey(parent.styleId, parent.assetId);
3927
+ const parentState = stateOf.get(parentKey);
3928
+ if (parentState && isActionable({ state: parentState })) {
3929
+ item.state = "blocked";
3930
+ item.reason = `parent ${parentKey} is being generated in this run; this follows in the next wave`;
3931
+ break;
3932
+ }
3933
+ if (item.spec.mirror && (parentState === "recoverable" || parentState === "in-flight")) {
3934
+ item.state = "blocked";
3935
+ item.reason = `mirror source ${parentKey} is ${parentState}; this follows in the next wave`;
3936
+ break;
3937
+ }
3863
3938
  }
3864
3939
  }
3865
3940
  const actionable = items.filter(isActionable);
@@ -5381,6 +5456,29 @@ var PixelLabClient = class {
5381
5456
  ...south ? { reference_image: encode(south) } : {},
5382
5457
  ...args.enhancePrompt ? { enhance_prompt: true } : {}
5383
5458
  };
5459
+ } else if (args.mode === "pro-flash") {
5460
+ path45 = "/create-character-pro-flash";
5461
+ const traits = args.styleTraits;
5462
+ body = {
5463
+ description: args.description,
5464
+ template_id: args.template,
5465
+ n_directions: 8,
5466
+ // The author's sprite sets the canvas; a size only applies to text creation.
5467
+ ...south ? { first_frame: encode(south) } : { image_size: imageSize },
5468
+ ...args.view ? { view: args.view } : {},
5469
+ ...args.seed != null ? { seed: args.seed } : {},
5470
+ ...args.styleReference && args.styleReferenceSize ? {
5471
+ style_image: { image: encode(args.styleReference), size: args.styleReferenceSize },
5472
+ ...traits ? {
5473
+ style_options: {
5474
+ ...traits.palette !== void 0 ? { color_palette: traits.palette } : {},
5475
+ ...traits.outline !== void 0 ? { outline: traits.outline } : {},
5476
+ ...traits.detail !== void 0 ? { detail: traits.detail } : {},
5477
+ ...traits.shading !== void 0 ? { shading: traits.shading } : {}
5478
+ }
5479
+ } : {}
5480
+ } : {}
5481
+ };
5384
5482
  } else if (args.mode === "pro") {
5385
5483
  path45 = "/create-character-pro";
5386
5484
  body = {
@@ -5388,10 +5486,12 @@ var PixelLabClient = class {
5388
5486
  image_size: imageSize,
5389
5487
  template_id: args.template,
5390
5488
  no_background: args.noBackground ?? true,
5391
- method: south ? "rotate_character" : "create_with_style",
5489
+ method: south ? "rotate_character" : args.concept ? "create_from_concept" : "create_with_style",
5392
5490
  ...args.view ? { view: args.view } : {},
5393
5491
  ...args.seed != null ? { seed: args.seed } : {},
5394
- ...south ? { reference_image: encode(south) } : args.styleReference ? { reference_image: encode(args.styleReference) } : {}
5492
+ ...south ? { reference_image: encode(south) } : args.styleReference ? { reference_image: encode(args.styleReference) } : {},
5493
+ ...!south && args.concept ? { concept_image: encode(args.concept) } : {},
5494
+ ...!south && args.styleCharacterId ? { style_character_id: args.styleCharacterId } : {}
5395
5495
  };
5396
5496
  } else {
5397
5497
  path45 = args.directions === 4 ? "/create-character-with-4-directions" : "/create-character-with-8-directions";
@@ -5556,12 +5656,24 @@ function characterCost(spec) {
5556
5656
  if (character.kind === "state") return generationCost(spec.width, spec.height, "1dir");
5557
5657
  if (character.mode === "standard") return 1;
5558
5658
  if (character.mode === "v3") return 1 + Math.max(1, Math.ceil(px * 8 / 65536));
5659
+ if (character.mode === "pro-flash") {
5660
+ const south = character.reference?.south;
5661
+ return south ? proFlashCharacterCost(south.width, south.height, true) : proFlashCharacterCost(spec.width, spec.height, false);
5662
+ }
5559
5663
  return generationCost(spec.width, spec.height, "1dir");
5560
5664
  }
5665
+ function proFlashCharacterCost(width, height, fromReference) {
5666
+ const side = Math.max(32, Math.ceil(Math.max(width, height) / 4) * 4);
5667
+ const rotations = Math.max(1, Math.ceil(side * side * 8 / 65536));
5668
+ if (fromReference) return rotations;
5669
+ const image = side <= 96 ? 5 : side <= 208 ? 6 : 9;
5670
+ return image + rotations;
5671
+ }
5561
5672
  function characterAnimationName(spec) {
5562
5673
  return `pixelkiln:${spec.styleId}/${spec.assetId}`;
5563
5674
  }
5564
5675
  var CHARACTER_TEMPLATES = ["mannequin", "bear", "cat", "dog", "horse", "lion"];
5676
+ var PRO_FLASH_TEMPLATES = [...CHARACTER_TEMPLATES, "custom"];
5565
5677
  function encodeAnimationJob(job) {
5566
5678
  return `character-animation:${Buffer.from(JSON.stringify(job)).toString("base64url")}`;
5567
5679
  }
@@ -5702,12 +5814,25 @@ var PixelLabProvider = class _PixelLabProvider {
5702
5814
  }
5703
5815
  }
5704
5816
  }
5817
+ if (character.concept) {
5818
+ if (character.mode !== "pro") throw new Error(`${label}: a concept image is a pro input; the ${character.mode} engine draws from text or a reference`);
5819
+ if (character.concept.width > 1024 || character.concept.height > 1024) {
5820
+ throw new Error(`${label}: concept image is ${character.concept.width}x${character.concept.height}; PixelLab pro takes up to 1024px`);
5821
+ }
5822
+ }
5823
+ if (character.styleAnchor) {
5824
+ if (character.mode !== "pro") throw new Error(`${label}: styleCharacter is a pro input; the ${character.mode} engine has no style anchor`);
5825
+ if (character.reference) throw new Error(`${label}: a pro base rotating its own reference takes no styleCharacter`);
5826
+ if (character.styleAnchor.spec.character?.directions !== 8) {
5827
+ throw new Error(`${label}: styleCharacter ${character.styleAnchor.assetId} has ${character.styleAnchor.spec.character?.directions} directions; PixelLab wants an 8-direction anchor`);
5828
+ }
5829
+ }
5705
5830
  if (character.reference) {
5706
5831
  const given = Object.keys(character.reference);
5707
5832
  if (!character.reference.south) throw new Error(`${label}: a reference needs a south-facing sprite`);
5708
5833
  if (character.mode !== "standard") {
5709
5834
  if (given.length > 1) throw new Error(`${label}: PixelLab ${character.mode} rotates one south-facing reference; drop the other directions`);
5710
- const limit = character.mode === "v3" ? 256 : 168;
5835
+ const limit = character.mode === "pro" ? 168 : 256;
5711
5836
  const south = character.reference.south;
5712
5837
  if (south.width > limit || south.height > limit) {
5713
5838
  throw new Error(`${label}: reference is ${south.width}x${south.height}; PixelLab ${character.mode} takes up to ${limit}px`);
@@ -5731,26 +5856,39 @@ var PixelLabProvider = class _PixelLabProvider {
5731
5856
  }
5732
5857
  }
5733
5858
  if (styleImages.length) {
5734
- if (character.mode !== "pro") {
5859
+ if (character.mode !== "pro" && character.mode !== "pro-flash") {
5735
5860
  throw new Error(
5736
- `PixelLab ${character.mode} characters take no style images; give a base its own sprite with \`reference\`, or use mode pro for a style anchor`
5861
+ `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`
5737
5862
  );
5738
5863
  }
5739
- if (styleImages.length > 1) throw new Error("PixelLab pro characters take one style image");
5864
+ if (styleImages.length > 1) throw new Error(`PixelLab ${character.mode} characters take one style image`);
5740
5865
  if (character.kind === "base" && character.reference) {
5741
- throw new Error(`${label}: a pro base rotating its own reference takes no style image`);
5866
+ throw new Error(`${label}: a ${character.mode} base rotating its own reference takes no style image`);
5742
5867
  }
5743
5868
  const image = styleImages[0];
5744
- if (image.width > 168 || image.height > 168) {
5745
- throw new Error(`PixelLab pro character style image is ${image.width}x${image.height}; the limit is 168px`);
5869
+ const limit = character.mode === "pro" ? 168 : 256;
5870
+ if (image.width > limit || image.height > limit) {
5871
+ throw new Error(`PixelLab ${character.mode} character style image is ${image.width}x${image.height}; the limit is ${limit}px`);
5872
+ }
5873
+ if (character.mode === "pro-flash" && (image.width > spec.width || image.height > spec.height)) {
5874
+ throw new Error(
5875
+ `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`
5876
+ );
5746
5877
  }
5747
5878
  }
5748
- const maxSize = character.mode === "v3" ? 256 : 128;
5879
+ if (character.styleTraits && character.mode !== "pro-flash") {
5880
+ throw new Error(`${label}: styleTraits choose what a pro-flash style image lends; the ${character.mode} engine does not take them`);
5881
+ }
5882
+ const maxSize = character.mode === "v3" || character.mode === "pro-flash" ? 256 : 128;
5749
5883
  if (spec.width < 16 || spec.height < 16 || spec.width > maxSize || spec.height > maxSize) {
5750
5884
  throw new Error(`PixelLab ${character.mode} characters must be between 16 and ${maxSize} pixels`);
5751
5885
  }
5752
- if (!CHARACTER_TEMPLATES.includes(character.template)) {
5753
- throw new Error(`PixelLab character template must be one of: ${CHARACTER_TEMPLATES.join(", ")}`);
5886
+ if (character.mode === "pro-flash" && character.kind === "base" && (spec.width % 4 || spec.height % 4)) {
5887
+ throw new Error(`PixelLab pro-flash characters are sized in multiples of 4 pixels; ${spec.width}x${spec.height} is not`);
5888
+ }
5889
+ const templates = character.mode === "pro-flash" ? PRO_FLASH_TEMPLATES : CHARACTER_TEMPLATES;
5890
+ if (!templates.includes(character.template)) {
5891
+ throw new Error(`PixelLab ${character.mode} character template must be one of: ${templates.join(", ")}`);
5754
5892
  }
5755
5893
  const views = character.mode === "standard" ? ["low top-down", "high top-down", "side", "perspective", "oblique"] : ["low top-down", "high top-down", "side"];
5756
5894
  if (!views.includes(spec.view)) {
@@ -5803,7 +5941,11 @@ var PixelLabProvider = class _PixelLabProvider {
5803
5941
  isometric: character.isometric,
5804
5942
  reference: character.reference ? readReference(spec, character.reference) : void 0,
5805
5943
  styleReference: styleImage ? { base64: styleImage.base64, format: styleImage.format } : void 0,
5806
- enhancePrompt: character.enhancePrompt
5944
+ enhancePrompt: character.enhancePrompt,
5945
+ concept: character.concept ? readPose(spec, "concept image", character.concept) : void 0,
5946
+ styleCharacterId: character.styleAnchor ? requireStyleObjectId(spec, context) : void 0,
5947
+ styleReferenceSize: styleImage ? { width: styleImage.width, height: styleImage.height } : void 0,
5948
+ styleTraits: character.styleTraits
5807
5949
  });
5808
5950
  return { jobId: res2.character_id, metadata: { character: { kind: "base", characterId: res2.character_id, mode: character.mode, directions: character.directions, backgroundJobId: res2.background_job_id } } };
5809
5951
  }
@@ -6223,6 +6365,14 @@ function readReference(spec, reference) {
6223
6365
  }
6224
6366
  return images;
6225
6367
  }
6368
+ function requireStyleObjectId(spec, context) {
6369
+ if (!context?.styleObjectId) {
6370
+ throw new Error(
6371
+ `${spec.styleId}/${spec.assetId} anchors its style on ${spec.character.styleAnchor.assetId}, which has no PixelLab character id in the lockfile yet; generate the anchor first`
6372
+ );
6373
+ }
6374
+ return context.styleObjectId;
6375
+ }
6226
6376
  function readPose(spec, what, image) {
6227
6377
  const bytes = readFileSync2(image.path);
6228
6378
  if (sha256(bytes) !== image.sha256) {
@@ -7544,6 +7694,18 @@ async function resolveSpecs(loaded, filter) {
7544
7694
  finalized.add(assetId);
7545
7695
  return resolved;
7546
7696
  }
7697
+ const anchorId = asset.styleCharacter ?? style.styleCharacter;
7698
+ if (resolved.character?.kind === "base" && anchorId && anchorId !== assetId) {
7699
+ const anchorSpec = await finalize(anchorId);
7700
+ if (!anchorSpec.character || anchorSpec.character.kind === "animation") {
7701
+ throw new Error(`assets.${assetId}: styleCharacter ${anchorId} is not a character base or state`);
7702
+ }
7703
+ const file = memberPath(anchorSpec.outFile, "south", 0, anchorSpec.character.directions, MediaType.PNG);
7704
+ resolved.character = {
7705
+ ...resolved.character,
7706
+ styleAnchor: { assetId: anchorId, spec: anchorSpec, file, sha256: existsSync8(file) ? await sha256File(file) : null }
7707
+ };
7708
+ }
7547
7709
  const characterParent = asset.state?.of ?? asset.animation?.of;
7548
7710
  if (resolved.character && characterParent) {
7549
7711
  const parentSpec = await finalize(characterParent);
@@ -7691,8 +7853,13 @@ async function resolveCharacterShape(asset, style, kind, files) {
7691
7853
  ...proportions !== void 0 ? { proportions } : {},
7692
7854
  ...style.textGuidanceScale !== void 0 ? { textGuidanceScale: style.textGuidanceScale } : {},
7693
7855
  ...style.isometric !== void 0 ? { isometric: style.isometric } : {},
7694
- ...style.enhancePrompt !== void 0 ? { enhancePrompt: style.enhancePrompt } : {}
7856
+ ...style.enhancePrompt !== void 0 ? { enhancePrompt: style.enhancePrompt } : {},
7857
+ ...style.styleTraits ? { styleTraits: style.styleTraits } : {}
7695
7858
  };
7859
+ if (asset.concept) {
7860
+ const image = await files.load(asset.concept, "Concept image");
7861
+ shape.concept = { path: path13.resolve(files.root, asset.concept), sha256: image.hash, width: image.width, height: image.height, format: image.format };
7862
+ }
7696
7863
  if (asset.reference) {
7697
7864
  const byDirection = typeof asset.reference === "string" ? { south: asset.reference } : asset.reference;
7698
7865
  shape.reference = {};
@@ -11827,10 +11994,13 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
11827
11994
  try {
11828
11995
  const refs = styleImages.get(spec.styleId) ?? [];
11829
11996
  const parentEntry = spec.character?.parentSpec ? lock.entries[lockKey(spec.character.parentSpec.styleId, spec.character.parentSpec.assetId)] : void 0;
11997
+ const anchor = spec.character?.styleAnchor;
11998
+ const anchorEntry = anchor ? lock.entries[lockKey(anchor.spec.styleId, anchor.spec.assetId)] : void 0;
11830
11999
  const replacedMetadata = previousEntry?.providerMetadata?.[provider.id];
11831
12000
  const { jobId, metadata } = await provider.submit(spec, refs, {
11832
12001
  ...previousJobId ? { previousJobId } : {},
11833
12002
  ...parentEntry?.objectId ? { parentObjectId: parentEntry.objectId } : {},
12003
+ ...anchorEntry?.objectId ? { styleObjectId: anchorEntry.objectId } : {},
11834
12004
  ...replacedMetadata ? { replacedMetadata } : {},
11835
12005
  ...previousMetadata ? { previousMetadata } : {},
11836
12006
  checkpoint: async (checkpoint) => {
@@ -12910,7 +13080,7 @@ var pin_default = {
12910
13080
  godot: "4.7.2",
12911
13081
  extensionsApi: 9,
12912
13082
  protocol: 4,
12913
- release: "editor-pixelorama-v1.2.2-pk.18",
13083
+ release: "editor-pixelorama-v1.2.2-pk.26",
12914
13084
  files: {
12915
13085
  "index.apple-touch-icon.png": {
12916
13086
  sha256: "ee5434873e0fed91e9a888c3ea5a8b79beac25999308be7a6eb41bf4ce640d27",
@@ -12925,7 +13095,7 @@ var pin_default = {
12925
13095
  bytes: 7298
12926
13096
  },
12927
13097
  "index.html": {
12928
- sha256: "d9adf06036660c4b76ef5386e872bc03dc0d5b0628fd6ac660d480893ee1f47a",
13098
+ sha256: "326101ab02bb4a29a7964214c9307c7dff26e9d66b8ebaaf6e7a3987e84a05b2",
12929
13099
  bytes: 5442
12930
13100
  },
12931
13101
  "index.icon.png": {
@@ -12937,8 +13107,8 @@ var pin_default = {
12937
13107
  bytes: 279815
12938
13108
  },
12939
13109
  "index.pck": {
12940
- sha256: "a41d9c3a39aa99ea5ee49ddcedfeb8b092006aa75c0de67139f13297c17f42e4",
12941
- bytes: 6431692
13110
+ sha256: "e26292650bb996965acd1ba70e74d2b4020b063d14f1276701312c1d34cb0a83",
13111
+ bytes: 6431932
12942
13112
  },
12943
13113
  "index.png": {
12944
13114
  sha256: "6e3ca3eb4a99e4c07bdd89ebc873b440ec0ffd66ce1955160da9e7ed80d538d7",
@@ -13557,7 +13727,7 @@ async function runLifecycle(args, wave, spent) {
13557
13727
  log(` Packaging stays blocked until each refined PNG has a current human approval.`);
13558
13728
  }
13559
13729
  }
13560
- return args.command === "gen" && submitted > 0 && total.downloaded > 0 && !total.failed && specs.some((spec) => spec.character?.parentSpec || spec.revision || spec.mirror);
13730
+ return args.command === "gen" && submitted > 0 && total.downloaded > 0 && !total.failed && specs.some((spec) => spec.character?.parentSpec || spec.character?.styleAnchor || spec.revision || spec.mirror);
13561
13731
  }
13562
13732
  return false;
13563
13733
  }