pixelkiln 0.67.0 → 0.68.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 +81 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +86 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +434 -34
- package/dist/index.d.ts +434 -34
- package/dist/index.js +84 -2
- package/dist/index.js.map +1 -1
- package/docs/GENERATORS.md +31 -0
- package/docs/MANIFEST.md +1 -0
- package/docs/PIXELLAB.md +4 -1
- package/package.json +1 -1
- package/schema/manifest.schema.json +61 -0
- package/skills/pixelkiln/references/pixellab-roadmap.md +5 -2
- package/skills/pixelkiln/references/pixellab.md +7 -1
package/dist/index.js
CHANGED
|
@@ -200,6 +200,16 @@ var CharacterPortraitSchema = z.object({
|
|
|
200
200
|
of: z.string().min(1),
|
|
201
201
|
size: CharacterPortraitSizeSchema.default(64)
|
|
202
202
|
}).strict();
|
|
203
|
+
var MapScenePlacementSchema = z.union([
|
|
204
|
+
z.object({ oval: z.number().min(0.05).max(0.95) }).strict(),
|
|
205
|
+
z.object({ rectangle: z.number().min(0.05).max(0.95) }).strict(),
|
|
206
|
+
z.object({ mask: z.string().min(1) }).strict()
|
|
207
|
+
]);
|
|
208
|
+
var MapSceneSchema = z.object({
|
|
209
|
+
/** Manifest-relative PNG of the scene. Any earlier asset's output file works. */
|
|
210
|
+
image: z.string().min(1),
|
|
211
|
+
placement: MapScenePlacementSchema.default({ oval: 0.3 })
|
|
212
|
+
}).strict();
|
|
203
213
|
var CharacterOutfitSchema = z.object({
|
|
204
214
|
/** The loop (a character animation asset) to re-clothe, in the same style. */
|
|
205
215
|
of: z.string().min(1),
|
|
@@ -894,6 +904,8 @@ var AssetSchema = z.object({
|
|
|
894
904
|
portrait: CharacterPortraitSchema.optional(),
|
|
895
905
|
/** `character` styles: this asset re-clothes an existing loop's frames with a reference outfit. */
|
|
896
906
|
outfit: CharacterOutfitSchema.optional(),
|
|
907
|
+
/** `map` styles only: draw this object in the style of a scene image. See `MapSceneSchema`. */
|
|
908
|
+
scene: MapSceneSchema.optional(),
|
|
897
909
|
/** `character` styles, `standard` humanoid bases: this character's proportions, over the style's. */
|
|
898
910
|
proportions: CharacterProportionsSchema.optional(),
|
|
899
911
|
/**
|
|
@@ -970,7 +982,7 @@ var AssetSchema = z.object({
|
|
|
970
982
|
path: ["revision"]
|
|
971
983
|
});
|
|
972
984
|
}
|
|
973
|
-
const shapes = [asset.revision && "revision", asset.state && "state", asset.animation && "animation", asset.mirror && "mirror", asset.batch && "batch", asset.portrait && "portrait", asset.outfit && "outfit"].filter(Boolean);
|
|
985
|
+
const shapes = [asset.revision && "revision", asset.state && "state", asset.animation && "animation", asset.mirror && "mirror", asset.batch && "batch", asset.portrait && "portrait", asset.outfit && "outfit", asset.scene && "scene"].filter(Boolean);
|
|
974
986
|
if (shapes.length > 1) {
|
|
975
987
|
context.addIssue({
|
|
976
988
|
code: z.ZodIssueCode.custom,
|
|
@@ -1766,6 +1778,12 @@ var PixelLabClient = class {
|
|
|
1766
1778
|
if (args.shading) body.shading = args.shading;
|
|
1767
1779
|
if (args.detail) body.detail = args.detail;
|
|
1768
1780
|
if (args.seed != null) body.seed = args.seed;
|
|
1781
|
+
if (args.scene) {
|
|
1782
|
+
const encode = (image) => ({ type: "base64", base64: image.base64, format: image.format });
|
|
1783
|
+
const placement = args.scene.placement;
|
|
1784
|
+
body.background_image = encode(args.scene.image);
|
|
1785
|
+
body.inpainting = placement.type === "mask" ? { type: "mask", mask_image: encode(placement.mask) } : { type: placement.type, fraction: placement.fraction };
|
|
1786
|
+
}
|
|
1769
1787
|
return validateResponse(
|
|
1770
1788
|
MapSubmitSchema,
|
|
1771
1789
|
await this.request("/map-objects", { method: "POST", body: JSON.stringify(body) }),
|
|
@@ -3388,6 +3406,11 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
|
|
|
3388
3406
|
uiPieces: spec.uiPieces,
|
|
3389
3407
|
uiElements: spec.uiElements,
|
|
3390
3408
|
uiColorPalette: spec.uiColorPalette,
|
|
3409
|
+
// Scene and mask enter as their bytes' hashes, never their paths.
|
|
3410
|
+
scene: spec.scene ? {
|
|
3411
|
+
image: spec.scene.sha256,
|
|
3412
|
+
placement: spec.scene.placement.type === "mask" ? { type: "mask", mask: spec.scene.placement.sha256 } : spec.scene.placement
|
|
3413
|
+
} : void 0,
|
|
3391
3414
|
styleTraits: spec.styleTraits,
|
|
3392
3415
|
styleImages: styleImageHashes,
|
|
3393
3416
|
// A character family: the engine and rotations of a base, the parent's
|
|
@@ -3619,6 +3642,8 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
3619
3642
|
supports(generator) {
|
|
3620
3643
|
return generator === "1dir" || generator === "map" || generator === "pixflux" || generator === "tiles" || generator === "terrain" || generator === "imagePro" || generator === "character" || generator === "isometricTile" || generator === "objectPro" || generator === "uiAsset" || generator === "uiElement" || generator === "imageProFlash";
|
|
3621
3644
|
}
|
|
3645
|
+
/** `/map-objects` style matching: `background_image` plus `inpainting`. */
|
|
3646
|
+
supportsMapScene = true;
|
|
3622
3647
|
/**
|
|
3623
3648
|
* `inpaint` (`/inpaint-v3`, a mask) and `image-to-image` (`/edit-images-v2`,
|
|
3624
3649
|
* no mask) both exist on PixelLab, and so do `reduce-colors`
|
|
@@ -4764,7 +4789,8 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
4764
4789
|
outline: spec.outline,
|
|
4765
4790
|
shading: spec.shading,
|
|
4766
4791
|
detail: spec.detail,
|
|
4767
|
-
seed: spec.seed
|
|
4792
|
+
seed: spec.seed,
|
|
4793
|
+
scene: spec.scene ? mapScenePayload(spec) : void 0
|
|
4768
4794
|
});
|
|
4769
4795
|
return { jobId: res.object_id, metadata: { backgroundJobId: res.background_job_id } };
|
|
4770
4796
|
}
|
|
@@ -5641,6 +5667,21 @@ function findObjectAnimation(object, name, direction, animationId) {
|
|
|
5641
5667
|
}
|
|
5642
5668
|
return null;
|
|
5643
5669
|
}
|
|
5670
|
+
function mapScenePayload(spec) {
|
|
5671
|
+
const scene = spec.scene;
|
|
5672
|
+
const read = (file, hash, label) => {
|
|
5673
|
+
const bytes = readFileSync(file);
|
|
5674
|
+
if (!hash || sha256(bytes) !== hash) {
|
|
5675
|
+
throw new Error(`${spec.styleId}/${spec.assetId}: ${label} changed after the manifest was resolved`);
|
|
5676
|
+
}
|
|
5677
|
+
return { base64: bytes.toString("base64"), format: "png" };
|
|
5678
|
+
};
|
|
5679
|
+
const placement = scene.placement;
|
|
5680
|
+
return {
|
|
5681
|
+
image: read(scene.file, scene.sha256, "scene image"),
|
|
5682
|
+
placement: placement.type === "mask" ? { type: "mask", mask: read(placement.file, placement.sha256, "scene mask") } : placement
|
|
5683
|
+
};
|
|
5684
|
+
}
|
|
5644
5685
|
|
|
5645
5686
|
// src/providers/retrodiffusion.ts
|
|
5646
5687
|
var DEFAULT_BASE_URL = "https://api.retrodiffusion.ai/v1";
|
|
@@ -7420,6 +7461,7 @@ var FakeProvider = class {
|
|
|
7420
7461
|
supports(generator) {
|
|
7421
7462
|
return generator === "1dir" || generator === "map" || generator === "character";
|
|
7422
7463
|
}
|
|
7464
|
+
supportsMapScene = true;
|
|
7423
7465
|
supportsRevision(_mode) {
|
|
7424
7466
|
return true;
|
|
7425
7467
|
}
|
|
@@ -8750,6 +8792,7 @@ async function resolveSpecs(loaded, filter) {
|
|
|
8750
8792
|
};
|
|
8751
8793
|
}
|
|
8752
8794
|
}
|
|
8795
|
+
if (asset.scene) resolved.scene = await resolveMapScene(root, styleId, assetId, resolved.generator, asset.scene, activeProvider);
|
|
8753
8796
|
resolved.specHash = specHash(
|
|
8754
8797
|
resolved,
|
|
8755
8798
|
styleImageHashes,
|
|
@@ -8808,6 +8851,32 @@ function pngPath(file) {
|
|
|
8808
8851
|
const extension = path5.extname(file);
|
|
8809
8852
|
return extension ? `${file.slice(0, -extension.length)}.png` : `${file}.png`;
|
|
8810
8853
|
}
|
|
8854
|
+
async function resolveMapScene(root, styleId, assetId, generator, scene, provider) {
|
|
8855
|
+
if (generator !== "map") {
|
|
8856
|
+
throw new Error(`assets.${assetId}.scene: only a map object can be drawn into a scene; style "${styleId}" uses "${generator}"`);
|
|
8857
|
+
}
|
|
8858
|
+
if (!provider.supportsMapScene) {
|
|
8859
|
+
throw new Error(`assets.${assetId}.scene: provider "${provider.id}" cannot draw into a scene; PixelLab's /map-objects can`);
|
|
8860
|
+
}
|
|
8861
|
+
const file = path5.resolve(root, scene.image);
|
|
8862
|
+
const image = await optionalRevisionImage(file, "scene image", "png");
|
|
8863
|
+
const base = { file, sha256: image?.hash ?? null, width: image?.width ?? null, height: image?.height ?? null };
|
|
8864
|
+
const placement = scene.placement;
|
|
8865
|
+
if ("mask" in placement) {
|
|
8866
|
+
const maskFile = path5.resolve(root, placement.mask);
|
|
8867
|
+
const mask = await optionalRevisionImage(maskFile, "scene mask", "png");
|
|
8868
|
+
if (image && mask && (image.width !== mask.width || image.height !== mask.height)) {
|
|
8869
|
+
throw new Error(
|
|
8870
|
+
`assets.${assetId}.scene: the mask is ${mask.width}x${mask.height}; the scene ${scene.image} is ${image.width}x${image.height}`
|
|
8871
|
+
);
|
|
8872
|
+
}
|
|
8873
|
+
return {
|
|
8874
|
+
...base,
|
|
8875
|
+
placement: { type: "mask", file: maskFile, sha256: mask?.hash ?? null, width: mask?.width ?? null, height: mask?.height ?? null }
|
|
8876
|
+
};
|
|
8877
|
+
}
|
|
8878
|
+
return "oval" in placement ? { ...base, placement: { type: "oval", fraction: placement.oval } } : { ...base, placement: { type: "rectangle", fraction: placement.rectangle } };
|
|
8879
|
+
}
|
|
8811
8880
|
async function optionalRevisionImage(file, label, requiredFormat) {
|
|
8812
8881
|
if (!existsSync4(file)) return null;
|
|
8813
8882
|
const bytes = await readFile3(file);
|
|
@@ -10478,6 +10547,7 @@ async function inspectRevisionReadiness(spec, lock) {
|
|
|
10478
10547
|
if (spec.character?.parentSpec) return inspectCharacterParent(spec, lock, /* @__PURE__ */ new Set());
|
|
10479
10548
|
if (spec.character?.styleAnchor) return inspectStyleAnchor(spec, lock, /* @__PURE__ */ new Set());
|
|
10480
10549
|
if (spec.objectPro?.parentSpec) return inspectObjectProParent(spec, lock, /* @__PURE__ */ new Set());
|
|
10550
|
+
if (spec.scene) return inspectScene(spec);
|
|
10481
10551
|
if (!spec.revision) return null;
|
|
10482
10552
|
return inspectRevision(spec, lock, /* @__PURE__ */ new Set());
|
|
10483
10553
|
}
|
|
@@ -10495,6 +10565,16 @@ async function inspectStyleAnchor(spec, lock, seen) {
|
|
|
10495
10565
|
}
|
|
10496
10566
|
return { ready: true, reason: `${label} is current` };
|
|
10497
10567
|
}
|
|
10568
|
+
async function inspectScene(spec) {
|
|
10569
|
+
const scene = spec.scene;
|
|
10570
|
+
const files = [{ label: "scene image", file: scene.file, sha256: scene.sha256 }];
|
|
10571
|
+
if (scene.placement.type === "mask") files.push({ label: "scene mask", file: scene.placement.file, sha256: scene.placement.sha256 });
|
|
10572
|
+
for (const { label, file, sha256: sha2562 } of files) {
|
|
10573
|
+
if (!sha2562 || !existsSync7(file)) return { ready: false, reason: `${label} does not exist yet: ${file}` };
|
|
10574
|
+
if (await sha256File(file) !== sha2562) return { ready: false, reason: `${label} changed after the manifest was resolved` };
|
|
10575
|
+
}
|
|
10576
|
+
return { ready: true, reason: "scene is current" };
|
|
10577
|
+
}
|
|
10498
10578
|
async function inspectMirror(spec, lock, seen) {
|
|
10499
10579
|
const source = spec.mirror.sourceSpec;
|
|
10500
10580
|
const label = `mirror source ${spec.styleId}/${spec.mirror.sourceAssetId}`;
|
|
@@ -17863,6 +17943,8 @@ export {
|
|
|
17863
17943
|
ManifestEditSchema,
|
|
17864
17944
|
ManifestInputSchema,
|
|
17865
17945
|
ManifestSchema,
|
|
17946
|
+
MapScenePlacementSchema,
|
|
17947
|
+
MapSceneSchema,
|
|
17866
17948
|
MediaType,
|
|
17867
17949
|
OverwriteRefusedError,
|
|
17868
17950
|
PIXEL_ART_FIXER_REVISION,
|