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 +205 -35
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +204 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +674 -73
- package/dist/index.d.ts +674 -73
- package/dist/index.js +204 -34
- package/dist/index.js.map +1 -1
- package/docs/GENERATORS.md +1 -0
- package/docs/MANIFEST.md +42 -12
- package/package.json +1 -1
- package/schema/manifest.schema.json +56 -2
- package/schema/recipe.schema.json +24 -1
- package/skills/pixelkiln/references/pixellab.md +5 -2
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
|
-
|
|
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
|
|
993
|
-
*
|
|
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.
|
|
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)
|
|
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
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
item.
|
|
3862
|
-
|
|
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 === "
|
|
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(
|
|
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
|
|
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
|
-
|
|
5745
|
-
|
|
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
|
-
|
|
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 (
|
|
5753
|
-
throw new Error(`PixelLab
|
|
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.
|
|
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: "
|
|
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: "
|
|
12941
|
-
bytes:
|
|
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
|
}
|