pixelkiln 0.42.0 → 0.43.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 +182 -17
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +265 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +901 -7
- package/dist/index.d.ts +901 -7
- package/dist/index.js +255 -87
- package/dist/index.js.map +1 -1
- package/docs/GENERATORS.md +8 -4
- package/docs/MANIFEST.md +46 -3
- package/package.json +1 -1
- package/schema/manifest.schema.json +184 -0
- package/schema/recipe.schema.json +55 -0
- package/skills/pixelkiln/references/pixellab.md +5 -0
package/dist/cli.js
CHANGED
|
@@ -665,7 +665,12 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
|
|
|
665
665
|
parent: spec.character.parentAssetId,
|
|
666
666
|
parentSha256: spec.character.parentSha256 ?? null,
|
|
667
667
|
state: spec.character.state,
|
|
668
|
-
animation: spec.character.animation
|
|
668
|
+
animation: spec.character.animation,
|
|
669
|
+
// Absent keys keep the hashes of manifests that never set these.
|
|
670
|
+
proportions: spec.character.proportions,
|
|
671
|
+
textGuidanceScale: spec.character.textGuidanceScale,
|
|
672
|
+
isometric: spec.character.isometric,
|
|
673
|
+
reference: spec.character.reference ? Object.fromEntries(Object.entries(spec.character.reference).map(([direction, image]) => [direction, image.sha256])) : void 0
|
|
669
674
|
} : void 0,
|
|
670
675
|
// A mirror's bytes come from its source's recorded outputs; the plan
|
|
671
676
|
// compares those directly, so only the choice of source is identity.
|
|
@@ -783,6 +788,17 @@ var MIRRORED_DIRECTION = {
|
|
|
783
788
|
"south-west": "south-east"
|
|
784
789
|
};
|
|
785
790
|
var CharacterModeSchema = z.enum(["standard", "v3", "pro"]);
|
|
791
|
+
var CHARACTER_PROPORTION_PRESETS = ["default", "chibi", "cartoon", "stylized", "realistic_male", "realistic_female", "heroic"];
|
|
792
|
+
var CharacterProportionsSchema = z.union([
|
|
793
|
+
z.enum(CHARACTER_PROPORTION_PRESETS),
|
|
794
|
+
z.object({
|
|
795
|
+
headSize: z.number().min(0.5).max(2).optional(),
|
|
796
|
+
armsLength: z.number().min(0.5).max(2).optional(),
|
|
797
|
+
legsLength: z.number().min(0.5).max(2).optional(),
|
|
798
|
+
shoulderWidth: z.number().min(0.5).max(2).optional(),
|
|
799
|
+
hipWidth: z.number().min(0.5).max(2).optional()
|
|
800
|
+
}).strict()
|
|
801
|
+
]);
|
|
786
802
|
var CharacterAnimationModeSchema = z.enum(["template", "v3", "pro"]);
|
|
787
803
|
var CharacterStateSchema = z.object({
|
|
788
804
|
/** The base character, or another state, in the same style. */
|
|
@@ -941,6 +957,16 @@ var StyleObjectSchema = z.object({
|
|
|
941
957
|
directions: z.union([z.literal(4), z.literal(8)]).optional(),
|
|
942
958
|
/** `character` only. Body template: `mannequin` (default) or a quadruped (`bear`, `cat`, `dog`, `horse`, `lion`). */
|
|
943
959
|
template: z.string().min(1).optional(),
|
|
960
|
+
/** `character` only, `standard` humanoid bases. A preset or multipliers; an asset may override it. */
|
|
961
|
+
proportions: CharacterProportionsSchema.optional(),
|
|
962
|
+
/**
|
|
963
|
+
* `character` only. How closely a `standard` base and a template loop
|
|
964
|
+
* follow their text, 1 to 20; PixelLab's default is 8. The v3 and pro
|
|
965
|
+
* engines do not take it.
|
|
966
|
+
*/
|
|
967
|
+
textGuidanceScale: z.number().min(1).max(20).optional(),
|
|
968
|
+
/** `character` only. Draw `standard` bases and every loop in isometric view. */
|
|
969
|
+
isometric: z.boolean().optional(),
|
|
944
970
|
/** Fixed seed for reproducibility where the endpoint supports it. */
|
|
945
971
|
seed: z.number().int().optional(),
|
|
946
972
|
/**
|
|
@@ -1100,6 +1126,19 @@ var AssetSchema = z.object({
|
|
|
1100
1126
|
state: CharacterStateSchema.optional(),
|
|
1101
1127
|
/** `character` styles: this asset is a loop of another character asset in one direction. */
|
|
1102
1128
|
animation: CharacterAnimationSchema.optional(),
|
|
1129
|
+
/** `character` styles, `standard` humanoid bases: this character's proportions, over the style's. */
|
|
1130
|
+
proportions: CharacterProportionsSchema.optional(),
|
|
1131
|
+
/**
|
|
1132
|
+
* `character` styles, bases only: the character's own sprite, which
|
|
1133
|
+
* PixelLab rotates into the other directions instead of drawing from
|
|
1134
|
+
* the prompt. A manifest-relative PNG or JPEG of the south-facing
|
|
1135
|
+
* sprite, or an object keyed by direction (`{ "south": ..., "east":
|
|
1136
|
+
* ... }`); quadrupeds in `standard` mode need south and east, and only
|
|
1137
|
+
* `standard` takes more than south. `standard` wants each image at the
|
|
1138
|
+
* style's size; v3 accepts up to 256px, pro up to 168px. The prompt
|
|
1139
|
+
* still guides the result.
|
|
1140
|
+
*/
|
|
1141
|
+
reference: z.union([z.string().min(1), z.record(CharacterDirectionSchema, z.string().min(1))]).optional(),
|
|
1103
1142
|
/**
|
|
1104
1143
|
* Another asset of the same style flipped left to right, made locally
|
|
1105
1144
|
* from that asset's downloaded files at no generation cost.
|
|
@@ -1174,6 +1213,16 @@ var AssetSchema = z.object({
|
|
|
1174
1213
|
path: ["prompt"]
|
|
1175
1214
|
});
|
|
1176
1215
|
}
|
|
1216
|
+
if (asset.reference && (asset.state || asset.animation || asset.mirror)) {
|
|
1217
|
+
context.addIssue({
|
|
1218
|
+
code: z.ZodIssueCode.custom,
|
|
1219
|
+
message: "a reference sprite belongs on a base; a state, animation, or mirror takes its look from its parent",
|
|
1220
|
+
path: ["reference"]
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
if (typeof asset.reference === "object" && !Object.keys(asset.reference).length) {
|
|
1224
|
+
context.addIssue({ code: z.ZodIssueCode.custom, message: "a reference needs at least a south image", path: ["reference"] });
|
|
1225
|
+
}
|
|
1177
1226
|
});
|
|
1178
1227
|
var DEFAULT_HISTORY_LIMIT = 5;
|
|
1179
1228
|
var HistoryLimitSchema = z.number().int().min(0).max(100);
|
|
@@ -5016,6 +5065,17 @@ var PixelLabError = class extends ProviderError {
|
|
|
5016
5065
|
}
|
|
5017
5066
|
body;
|
|
5018
5067
|
};
|
|
5068
|
+
function proportionsPayload(proportions) {
|
|
5069
|
+
if (typeof proportions === "string") return { type: "preset", name: proportions };
|
|
5070
|
+
return {
|
|
5071
|
+
type: "custom",
|
|
5072
|
+
...proportions.headSize !== void 0 ? { head_size: proportions.headSize } : {},
|
|
5073
|
+
...proportions.armsLength !== void 0 ? { arms_length: proportions.armsLength } : {},
|
|
5074
|
+
...proportions.legsLength !== void 0 ? { legs_length: proportions.legsLength } : {},
|
|
5075
|
+
...proportions.shoulderWidth !== void 0 ? { shoulder_width: proportions.shoulderWidth } : {},
|
|
5076
|
+
...proportions.hipWidth !== void 0 ? { hip_width: proportions.hipWidth } : {}
|
|
5077
|
+
};
|
|
5078
|
+
}
|
|
5019
5079
|
var PixelLabClient = class {
|
|
5020
5080
|
constructor(apiKey, timeoutMs = 12e4) {
|
|
5021
5081
|
this.apiKey = apiKey;
|
|
@@ -5224,10 +5284,17 @@ var PixelLabClient = class {
|
|
|
5224
5284
|
* A base character. Standard mode picks the 4- or 8-direction template
|
|
5225
5285
|
* endpoint; v3 and pro have their own and always draw 8. Every one answers
|
|
5226
5286
|
* at once with the character id and a background job.
|
|
5287
|
+
*
|
|
5288
|
+
* A `reference` is the author's own sprite: standard takes one per
|
|
5289
|
+
* direction and draws the rest, v3 rotates the south one, and pro
|
|
5290
|
+
* switches to its rotate method for it. A `styleReference` is pro's style
|
|
5291
|
+
* anchor; the other engines have no such input.
|
|
5227
5292
|
*/
|
|
5228
5293
|
async createCharacter(args) {
|
|
5229
5294
|
const imageSize = { width: args.size, height: args.size };
|
|
5230
5295
|
const palette = args.paletteSwatchBase64 ? { color_image: { type: "base64", base64: args.paletteSwatchBase64, format: "png" }, force_colors: true } : {};
|
|
5296
|
+
const encode = (image) => ({ type: "base64", base64: image.base64, format: image.format });
|
|
5297
|
+
const south = args.reference?.south;
|
|
5231
5298
|
let path45;
|
|
5232
5299
|
let body;
|
|
5233
5300
|
if (args.mode === "v3") {
|
|
@@ -5240,7 +5307,8 @@ var PixelLabClient = class {
|
|
|
5240
5307
|
...args.view ? { view: args.view } : {},
|
|
5241
5308
|
...args.outline ? { outline: args.outline } : {},
|
|
5242
5309
|
...args.detail ? { detail: args.detail } : {},
|
|
5243
|
-
...args.seed != null ? { seed: args.seed } : {}
|
|
5310
|
+
...args.seed != null ? { seed: args.seed } : {},
|
|
5311
|
+
...south ? { reference_image: encode(south) } : {}
|
|
5244
5312
|
};
|
|
5245
5313
|
} else if (args.mode === "pro") {
|
|
5246
5314
|
path45 = "/create-character-pro";
|
|
@@ -5249,8 +5317,10 @@ var PixelLabClient = class {
|
|
|
5249
5317
|
image_size: imageSize,
|
|
5250
5318
|
template_id: args.template,
|
|
5251
5319
|
no_background: args.noBackground ?? true,
|
|
5320
|
+
method: south ? "rotate_character" : "create_with_style",
|
|
5252
5321
|
...args.view ? { view: args.view } : {},
|
|
5253
|
-
...args.seed != null ? { seed: args.seed } : {}
|
|
5322
|
+
...args.seed != null ? { seed: args.seed } : {},
|
|
5323
|
+
...south ? { reference_image: encode(south) } : args.styleReference ? { reference_image: encode(args.styleReference) } : {}
|
|
5254
5324
|
};
|
|
5255
5325
|
} else {
|
|
5256
5326
|
path45 = args.directions === 4 ? "/create-character-with-4-directions" : "/create-character-with-8-directions";
|
|
@@ -5263,6 +5333,10 @@ var PixelLabClient = class {
|
|
|
5263
5333
|
...args.shading ? { shading: args.shading } : {},
|
|
5264
5334
|
...args.detail ? { detail: args.detail } : {},
|
|
5265
5335
|
...args.seed != null ? { seed: args.seed } : {},
|
|
5336
|
+
...args.proportions !== void 0 ? { proportions: proportionsPayload(args.proportions) } : {},
|
|
5337
|
+
...args.textGuidanceScale !== void 0 ? { text_guidance_scale: args.textGuidanceScale } : {},
|
|
5338
|
+
...args.isometric !== void 0 ? { isometric: args.isometric } : {},
|
|
5339
|
+
...args.reference && Object.keys(args.reference).length ? { directions: Object.fromEntries(Object.entries(args.reference).flatMap(([direction, image]) => image ? [[direction, encode(image)]] : [])) } : {},
|
|
5266
5340
|
...palette
|
|
5267
5341
|
};
|
|
5268
5342
|
}
|
|
@@ -5302,6 +5376,8 @@ var PixelLabClient = class {
|
|
|
5302
5376
|
...args.actionDescription ? { action_description: args.actionDescription } : {},
|
|
5303
5377
|
...args.mode === "v3" && args.frameCount ? { frame_count: args.frameCount } : {},
|
|
5304
5378
|
...args.mode === "v3" && args.keepFirstFrame === false ? { keep_first_frame: false } : {},
|
|
5379
|
+
...args.mode === "template" && args.textGuidanceScale !== void 0 ? { text_guidance_scale: args.textGuidanceScale } : {},
|
|
5380
|
+
...args.isometric !== void 0 ? { isometric: args.isometric } : {},
|
|
5305
5381
|
...args.seed != null ? { seed: args.seed } : {}
|
|
5306
5382
|
})
|
|
5307
5383
|
});
|
|
@@ -5498,8 +5574,8 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
5498
5574
|
"high detail"
|
|
5499
5575
|
]);
|
|
5500
5576
|
}
|
|
5501
|
-
if (spec.generator === "character") this.validateCharacter(spec);
|
|
5502
|
-
if ((spec.generator === "map" || spec.generator === "pixflux"
|
|
5577
|
+
if (spec.generator === "character") this.validateCharacter(spec, styleImages);
|
|
5578
|
+
if ((spec.generator === "map" || spec.generator === "pixflux") && styleImages.length) {
|
|
5503
5579
|
throw new Error(`PixelLab ${spec.generator} does not support style images`);
|
|
5504
5580
|
}
|
|
5505
5581
|
for (const image of styleImages) {
|
|
@@ -5515,9 +5591,61 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
5515
5591
|
);
|
|
5516
5592
|
}
|
|
5517
5593
|
}
|
|
5518
|
-
validateCharacter(spec) {
|
|
5594
|
+
validateCharacter(spec, styleImages = []) {
|
|
5519
5595
|
const character = spec.character;
|
|
5520
5596
|
if (!character) throw new Error(`${spec.styleId}/${spec.assetId} has no character shape`);
|
|
5597
|
+
const label = `${spec.styleId}/${spec.assetId}`;
|
|
5598
|
+
if (character.kind === "base" && character.proportions !== void 0) {
|
|
5599
|
+
if (character.mode !== "standard") {
|
|
5600
|
+
throw new Error(`${label}: proportions apply to standard bases; the ${character.mode} engine has none to set`);
|
|
5601
|
+
}
|
|
5602
|
+
if (character.template !== "mannequin") {
|
|
5603
|
+
throw new Error(`${label}: proportions apply to the mannequin template; ${character.template} is a quadruped`);
|
|
5604
|
+
}
|
|
5605
|
+
}
|
|
5606
|
+
if (character.reference) {
|
|
5607
|
+
const given = Object.keys(character.reference);
|
|
5608
|
+
if (!character.reference.south) throw new Error(`${label}: a reference needs a south-facing sprite`);
|
|
5609
|
+
if (character.mode !== "standard") {
|
|
5610
|
+
if (given.length > 1) throw new Error(`${label}: PixelLab ${character.mode} rotates one south-facing reference; drop the other directions`);
|
|
5611
|
+
const limit = character.mode === "v3" ? 256 : 168;
|
|
5612
|
+
const south = character.reference.south;
|
|
5613
|
+
if (south.width > limit || south.height > limit) {
|
|
5614
|
+
throw new Error(`${label}: reference is ${south.width}x${south.height}; PixelLab ${character.mode} takes up to ${limit}px`);
|
|
5615
|
+
}
|
|
5616
|
+
} else {
|
|
5617
|
+
const allowed = character.directions === 4 ? CHARACTER_DIRECTIONS_4 : CHARACTER_DIRECTIONS_8;
|
|
5618
|
+
for (const direction of given) {
|
|
5619
|
+
if (!allowed.includes(direction)) {
|
|
5620
|
+
throw new Error(`${label}: reference "${direction}" is not one of this character's ${character.directions} directions`);
|
|
5621
|
+
}
|
|
5622
|
+
const image = character.reference[direction];
|
|
5623
|
+
if (image.width !== spec.width || image.height !== spec.height) {
|
|
5624
|
+
throw new Error(
|
|
5625
|
+
`${label}: reference (${direction}) is ${image.width}x${image.height}; standard mode wants each image at the style's size, ${spec.width}x${spec.height}`
|
|
5626
|
+
);
|
|
5627
|
+
}
|
|
5628
|
+
}
|
|
5629
|
+
if (character.template !== "mannequin" && !character.reference.east) {
|
|
5630
|
+
throw new Error(`${label}: a ${character.template} reference needs south and east images`);
|
|
5631
|
+
}
|
|
5632
|
+
}
|
|
5633
|
+
}
|
|
5634
|
+
if (styleImages.length) {
|
|
5635
|
+
if (character.mode !== "pro") {
|
|
5636
|
+
throw new Error(
|
|
5637
|
+
`PixelLab ${character.mode} characters take no style images; give a base its own sprite with \`reference\`, or use mode pro for a style anchor`
|
|
5638
|
+
);
|
|
5639
|
+
}
|
|
5640
|
+
if (styleImages.length > 1) throw new Error("PixelLab pro characters take one style image");
|
|
5641
|
+
if (character.kind === "base" && character.reference) {
|
|
5642
|
+
throw new Error(`${label}: a pro base rotating its own reference takes no style image`);
|
|
5643
|
+
}
|
|
5644
|
+
const image = styleImages[0];
|
|
5645
|
+
if (image.width > 168 || image.height > 168) {
|
|
5646
|
+
throw new Error(`PixelLab pro character style image is ${image.width}x${image.height}; the limit is 168px`);
|
|
5647
|
+
}
|
|
5648
|
+
}
|
|
5521
5649
|
const maxSize = character.mode === "v3" ? 256 : 128;
|
|
5522
5650
|
if (spec.width < 16 || spec.height < 16 || spec.width > maxSize || spec.height > maxSize) {
|
|
5523
5651
|
throw new Error(`PixelLab ${character.mode} characters must be between 16 and ${maxSize} pixels`);
|
|
@@ -5553,10 +5681,11 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
5553
5681
|
* asset so a later run can find it, and clears its own earlier take for
|
|
5554
5682
|
* that direction first, since PixelLab skips a direction that exists.
|
|
5555
5683
|
*/
|
|
5556
|
-
async submitCharacter(spec, context) {
|
|
5684
|
+
async submitCharacter(spec, styleImages, context) {
|
|
5557
5685
|
const character = spec.character;
|
|
5558
5686
|
if (character.kind === "base") {
|
|
5559
5687
|
const swatch = spec.palette.length && character.mode === "standard" ? paletteSwatch(spec.palette).toString("base64") : void 0;
|
|
5688
|
+
const styleImage = styleImages[0];
|
|
5560
5689
|
const res2 = await this.client.createCharacter({
|
|
5561
5690
|
mode: character.mode,
|
|
5562
5691
|
description: spec.prompt,
|
|
@@ -5569,7 +5698,12 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
5569
5698
|
detail: spec.detail,
|
|
5570
5699
|
seed: spec.seed,
|
|
5571
5700
|
noBackground: spec.noBackground,
|
|
5572
|
-
paletteSwatchBase64: swatch
|
|
5701
|
+
paletteSwatchBase64: swatch,
|
|
5702
|
+
proportions: character.proportions,
|
|
5703
|
+
textGuidanceScale: character.textGuidanceScale,
|
|
5704
|
+
isometric: character.isometric,
|
|
5705
|
+
reference: character.reference ? readReference(spec, character.reference) : void 0,
|
|
5706
|
+
styleReference: styleImage ? { base64: styleImage.base64, format: styleImage.format } : void 0
|
|
5573
5707
|
});
|
|
5574
5708
|
return { jobId: res2.character_id, metadata: { character: { kind: "base", characterId: res2.character_id, mode: character.mode, directions: character.directions, backgroundJobId: res2.background_job_id } } };
|
|
5575
5709
|
}
|
|
@@ -5611,7 +5745,9 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
5611
5745
|
frameCount: animation.frames,
|
|
5612
5746
|
keepFirstFrame: animation.keepFirstFrame,
|
|
5613
5747
|
directions: [animation.direction],
|
|
5614
|
-
seed: spec.seed
|
|
5748
|
+
seed: spec.seed,
|
|
5749
|
+
textGuidanceScale: character.textGuidanceScale,
|
|
5750
|
+
isometric: character.isometric
|
|
5615
5751
|
});
|
|
5616
5752
|
const job = { characterId: parentId, name, direction: animation.direction, jobIds: res.background_job_ids };
|
|
5617
5753
|
return {
|
|
@@ -5701,7 +5837,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
5701
5837
|
}
|
|
5702
5838
|
async submit(spec, styleImages, context) {
|
|
5703
5839
|
this.validate(spec, styleImages);
|
|
5704
|
-
if (spec.generator === "character") return this.submitCharacter(spec, context);
|
|
5840
|
+
if (spec.generator === "character") return this.submitCharacter(spec, styleImages, context);
|
|
5705
5841
|
if (spec.generator === "pixflux") {
|
|
5706
5842
|
const swatch = spec.palette.length ? paletteSwatch(spec.palette).toString("base64") : void 0;
|
|
5707
5843
|
const { png } = await this.client.createImagePixflux({
|
|
@@ -5968,6 +6104,17 @@ function firstUrl(urls) {
|
|
|
5968
6104
|
if (!urls) return null;
|
|
5969
6105
|
return Object.values(urls).find((u) => typeof u === "string") ?? null;
|
|
5970
6106
|
}
|
|
6107
|
+
function readReference(spec, reference) {
|
|
6108
|
+
const images = {};
|
|
6109
|
+
for (const [direction, image] of Object.entries(reference)) {
|
|
6110
|
+
const bytes = readFileSync2(image.path);
|
|
6111
|
+
if (sha256(bytes) !== image.sha256) {
|
|
6112
|
+
throw new Error(`${spec.styleId}/${spec.assetId}: reference (${direction}) changed after the manifest was resolved: ${image.path}`);
|
|
6113
|
+
}
|
|
6114
|
+
images[direction] = { base64: bytes.toString("base64"), format: image.format };
|
|
6115
|
+
}
|
|
6116
|
+
return images;
|
|
6117
|
+
}
|
|
5971
6118
|
function rotationSources(character) {
|
|
5972
6119
|
const order = character.directions === 4 ? CHARACTER_DIRECTIONS_4 : CHARACTER_DIRECTIONS_8;
|
|
5973
6120
|
const sources = [];
|
|
@@ -7087,16 +7234,16 @@ async function resolveSpecs(loaded, filter) {
|
|
|
7087
7234
|
}
|
|
7088
7235
|
}
|
|
7089
7236
|
const styleImageCache = /* @__PURE__ */ new Map();
|
|
7090
|
-
async function loadStyleImage(rel) {
|
|
7237
|
+
async function loadStyleImage(rel, what = "Style image") {
|
|
7091
7238
|
const abs = path13.resolve(root, rel);
|
|
7092
7239
|
let hit = styleImageCache.get(abs);
|
|
7093
7240
|
if (!hit) {
|
|
7094
|
-
if (!existsSync8(abs)) throw new Error(
|
|
7241
|
+
if (!existsSync8(abs)) throw new Error(`${what} not found: ${abs}`);
|
|
7095
7242
|
const buf = await readFile6(abs);
|
|
7096
7243
|
const metadata = imageMetadata(buf);
|
|
7097
|
-
if (!metadata) throw new Error(
|
|
7244
|
+
if (!metadata) throw new Error(`${what} is not a readable PNG or JPEG: ${abs}`);
|
|
7098
7245
|
if (metadata.width < 1 || metadata.height < 1) {
|
|
7099
|
-
throw new Error(
|
|
7246
|
+
throw new Error(`${what} has invalid dimensions: ${abs}`);
|
|
7100
7247
|
}
|
|
7101
7248
|
hit = { base64: buf.toString("base64"), hash: sha256(buf), ...metadata };
|
|
7102
7249
|
styleImageCache.set(abs, hit);
|
|
@@ -7203,7 +7350,7 @@ async function resolveSpecs(loaded, filter) {
|
|
|
7203
7350
|
tileView: generator === "tiles" ? style.tileView : void 0,
|
|
7204
7351
|
tileFeature: generator === "tiles" ? style.tileFeature : void 0,
|
|
7205
7352
|
outlineMode: generator === "tiles" ? style.outlineMode : void 0,
|
|
7206
|
-
...generator === "character" ? { character: resolveCharacterShape(asset, style, characterKind) } : {},
|
|
7353
|
+
...generator === "character" ? { character: await resolveCharacterShape(asset, style, characterKind, { root, load: loadStyleImage }) } : {},
|
|
7207
7354
|
cost: generator === "tiles" ? tilesCost(tileSize, tileVariations) : generationCost(width, height, generator),
|
|
7208
7355
|
costUnit: "generations",
|
|
7209
7356
|
candidates: generator === "tiles" ? tileVariations : generator === "1dir" ? candidateCount(size) : 1
|
|
@@ -7445,15 +7592,33 @@ function imageMetadata(buf) {
|
|
|
7445
7592
|
}
|
|
7446
7593
|
return null;
|
|
7447
7594
|
}
|
|
7448
|
-
function resolveCharacterShape(asset, style, kind) {
|
|
7595
|
+
async function resolveCharacterShape(asset, style, kind, files) {
|
|
7449
7596
|
const mode2 = style.mode ?? "standard";
|
|
7450
7597
|
const directions = mode2 === "standard" ? style.directions ?? 8 : 8;
|
|
7598
|
+
const proportions = asset.proportions ?? style.proportions;
|
|
7451
7599
|
const shape = {
|
|
7452
7600
|
kind,
|
|
7453
7601
|
mode: mode2,
|
|
7454
7602
|
directions,
|
|
7455
|
-
template: style.template ?? "mannequin"
|
|
7603
|
+
template: style.template ?? "mannequin",
|
|
7604
|
+
...proportions !== void 0 ? { proportions } : {},
|
|
7605
|
+
...style.textGuidanceScale !== void 0 ? { textGuidanceScale: style.textGuidanceScale } : {},
|
|
7606
|
+
...style.isometric !== void 0 ? { isometric: style.isometric } : {}
|
|
7456
7607
|
};
|
|
7608
|
+
if (asset.reference) {
|
|
7609
|
+
const byDirection = typeof asset.reference === "string" ? { south: asset.reference } : asset.reference;
|
|
7610
|
+
shape.reference = {};
|
|
7611
|
+
for (const [direction, rel] of Object.entries(byDirection)) {
|
|
7612
|
+
const image = await files.load(rel, `Reference sprite (${direction})`);
|
|
7613
|
+
shape.reference[direction] = {
|
|
7614
|
+
path: path13.resolve(files.root, rel),
|
|
7615
|
+
sha256: image.hash,
|
|
7616
|
+
width: image.width,
|
|
7617
|
+
height: image.height,
|
|
7618
|
+
format: image.format
|
|
7619
|
+
};
|
|
7620
|
+
}
|
|
7621
|
+
}
|
|
7457
7622
|
if (asset.state) {
|
|
7458
7623
|
shape.state = {
|
|
7459
7624
|
paletteFromReference: asset.state.paletteFromReference,
|