pixelkiln 0.66.0 → 0.67.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 +730 -475
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +659 -441
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +671 -269
- package/dist/index.d.ts +671 -269
- package/dist/index.js +659 -441
- package/dist/index.js.map +1 -1
- package/docs/CLI.md +17 -0
- package/docs/MANIFEST.md +6 -3
- package/docs/PIXELLAB.md +15 -14
- package/docs/REVISIONS.md +98 -10
- package/package.json +1 -1
- package/schema/manifest.schema.json +13 -0
- package/skills/pixelkiln/references/pixellab-roadmap.md +38 -15
- package/skills/pixelkiln/references/pixellab.md +35 -20
package/dist/cli.js
CHANGED
|
@@ -68,7 +68,7 @@ function exitCodeFor(err) {
|
|
|
68
68
|
|
|
69
69
|
// src/cli/main.ts
|
|
70
70
|
import { existsSync as existsSync33 } from "fs";
|
|
71
|
-
import { readFile as
|
|
71
|
+
import { readFile as readFile31 } from "fs/promises";
|
|
72
72
|
|
|
73
73
|
// src/cli/args.ts
|
|
74
74
|
import path from "path";
|
|
@@ -157,6 +157,7 @@ var COMMANDS = [
|
|
|
157
157
|
"refine",
|
|
158
158
|
"recipe",
|
|
159
159
|
"workspace",
|
|
160
|
+
"estimate-skeleton",
|
|
160
161
|
"unzoom",
|
|
161
162
|
"font",
|
|
162
163
|
"help",
|
|
@@ -251,6 +252,10 @@ function parseArgs(argv) {
|
|
|
251
252
|
}
|
|
252
253
|
rest = rest.slice(1);
|
|
253
254
|
}
|
|
255
|
+
} else if (command === "estimate-skeleton") {
|
|
256
|
+
target = rest[0]?.startsWith("-") ? void 0 : rest[0];
|
|
257
|
+
if (target === void 0) throw new UsageError("estimate-skeleton needs an image path");
|
|
258
|
+
rest = rest.slice(1);
|
|
254
259
|
} else if (command === "refine") {
|
|
255
260
|
subcommand = rest[0]?.startsWith("-") || rest[0] === void 0 ? "run" : rest[0];
|
|
256
261
|
if (!REFINE_SUBCOMMANDS.includes(subcommand)) {
|
|
@@ -456,6 +461,11 @@ Commands
|
|
|
456
461
|
first. Local art is untouched.
|
|
457
462
|
tag Push manifest tags to the objects upstream (free).
|
|
458
463
|
balance Show the provider's remaining balance.
|
|
464
|
+
estimate-skeleton <image> [--out <file>]
|
|
465
|
+
PixelLab only: derive an 18-joint skeleton from an image, direct
|
|
466
|
+
and un-budgeted (like balance, not a generation). Prints the
|
|
467
|
+
keypoints JSON, or writes it with --out \u2014 the way to bootstrap
|
|
468
|
+
an animate-skeleton revision's keypointsFile.
|
|
459
469
|
status Summarise the lockfile.
|
|
460
470
|
edit Hand-edit an asset in your own editor: copies the generated PNG to
|
|
461
471
|
<outDir>/edits/, declares it as the asset's source, and opens it.
|
|
@@ -638,10 +648,10 @@ import { createReadStream } from "fs";
|
|
|
638
648
|
function sha256(data) {
|
|
639
649
|
return createHash("sha256").update(data).digest("hex");
|
|
640
650
|
}
|
|
641
|
-
async function sha256File(
|
|
651
|
+
async function sha256File(path48) {
|
|
642
652
|
return new Promise((resolve, reject) => {
|
|
643
653
|
const hash = createHash("sha256");
|
|
644
|
-
const stream = createReadStream(
|
|
654
|
+
const stream = createReadStream(path48);
|
|
645
655
|
stream.on("data", (chunk2) => hash.update(chunk2));
|
|
646
656
|
stream.on("error", reject);
|
|
647
657
|
stream.on("end", () => resolve(hash.digest("hex")));
|
|
@@ -757,6 +767,9 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
|
|
|
757
767
|
lastFrameSha256: spec.revision.lastFrameSha256,
|
|
758
768
|
direction: spec.revision.direction,
|
|
759
769
|
enhancePrompt: spec.revision.enhancePrompt,
|
|
770
|
+
keypointsSha256: spec.revision.keypointsSha256,
|
|
771
|
+
skeletonTemplate: spec.revision.skeletonTemplate,
|
|
772
|
+
description: spec.revision.description,
|
|
760
773
|
engine: spec.revision.engine
|
|
761
774
|
} : void 0
|
|
762
775
|
})
|
|
@@ -785,6 +798,7 @@ var RevisionModeSchema = z.enum([
|
|
|
785
798
|
"correct-pixelart",
|
|
786
799
|
"animate",
|
|
787
800
|
"animate-pixminimax",
|
|
801
|
+
"animate-skeleton",
|
|
788
802
|
"interpolate",
|
|
789
803
|
"edit-animation"
|
|
790
804
|
]);
|
|
@@ -1103,6 +1117,30 @@ var RevisionSchema = z.object({
|
|
|
1103
1117
|
direction: CharacterDirectionSchema.optional(),
|
|
1104
1118
|
/** `animate`/`animate-pixminimax` only: let PixelLab expand the action into a fuller motion description first. */
|
|
1105
1119
|
enhancePrompt: z.boolean().optional(),
|
|
1120
|
+
/**
|
|
1121
|
+
* `animate-skeleton` only: manifest-relative path to a committed
|
|
1122
|
+
* `SkeletonSet` JSON file (see `src/skeleton.ts`) — the pose the parent
|
|
1123
|
+
* image is already in, plus 3-15 per-frame poses for the motion.
|
|
1124
|
+
* Authored via `pixelkiln estimate-skeleton`, then hand-tweaked; never
|
|
1125
|
+
* inline in the manifest, the same reasoning `mask`/`lastFrame` are
|
|
1126
|
+
* committed files rather than inline pixel data.
|
|
1127
|
+
*/
|
|
1128
|
+
keypointsFile: z.string().min(1).optional(),
|
|
1129
|
+
/**
|
|
1130
|
+
* `animate-skeleton` only: the body a joint's missing `depth` is taken
|
|
1131
|
+
* from. PixelLab's default is `mannequin`; free string like `character`'s
|
|
1132
|
+
* own `template` field, validated at the provider layer against the
|
|
1133
|
+
* same `mannequin`/`bear`/`cat`/`dog`/`horse`/`lion` vocabulary.
|
|
1134
|
+
*/
|
|
1135
|
+
skeletonTemplate: z.string().min(1).optional(),
|
|
1136
|
+
/**
|
|
1137
|
+
* `animate-skeleton` only: what the character *looks like*, a noun
|
|
1138
|
+
* phrase (colours, clothing, held items) — distinct from the asset's
|
|
1139
|
+
* own `prompt`, which this mode sends as the motion's short label
|
|
1140
|
+
* (PixelLab's `action`), the same `prompt`-as-motion convention
|
|
1141
|
+
* `animate`/`animate-pixminimax` already use.
|
|
1142
|
+
*/
|
|
1143
|
+
description: z.string().min(1).optional(),
|
|
1106
1144
|
/**
|
|
1107
1145
|
* `image-to-image`/`inpaint` only: which provider engine draws the
|
|
1108
1146
|
* edit. `pro-flash` selects PixelLab's Pro Flash edit and inpaint tier
|
|
@@ -1193,18 +1231,41 @@ var RevisionSchema = z.object({
|
|
|
1193
1231
|
path: ["fps"]
|
|
1194
1232
|
});
|
|
1195
1233
|
}
|
|
1196
|
-
if (revision.direction !== void 0 && revision.mode !== "animate-pixminimax") {
|
|
1234
|
+
if (revision.direction !== void 0 && revision.mode !== "animate-pixminimax" && revision.mode !== "animate-skeleton") {
|
|
1235
|
+
context.addIssue({
|
|
1236
|
+
code: z.ZodIssueCode.custom,
|
|
1237
|
+
message: "direction applies to animate-pixminimax/animate-skeleton revisions only",
|
|
1238
|
+
path: ["direction"]
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
if (revision.mode === "animate-skeleton" && revision.direction === void 0) {
|
|
1197
1242
|
context.addIssue({
|
|
1198
1243
|
code: z.ZodIssueCode.custom,
|
|
1199
|
-
message: "
|
|
1244
|
+
message: "animate-skeleton revisions require a direction",
|
|
1200
1245
|
path: ["direction"]
|
|
1201
1246
|
});
|
|
1202
1247
|
}
|
|
1203
1248
|
if (revision.frames !== void 0 && revision.frames % 2 !== 0) {
|
|
1204
1249
|
context.addIssue({ code: z.ZodIssueCode.custom, message: "frames must be even", path: ["frames"] });
|
|
1205
1250
|
}
|
|
1251
|
+
if (revision.mode === "animate-skeleton" && !revision.keypointsFile) {
|
|
1252
|
+
context.addIssue({
|
|
1253
|
+
code: z.ZodIssueCode.custom,
|
|
1254
|
+
message: "animate-skeleton revisions require keypointsFile",
|
|
1255
|
+
path: ["keypointsFile"]
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
1258
|
+
for (const field of ["keypointsFile", "skeletonTemplate", "description"]) {
|
|
1259
|
+
if (revision[field] !== void 0 && revision.mode !== "animate-skeleton") {
|
|
1260
|
+
context.addIssue({
|
|
1261
|
+
code: z.ZodIssueCode.custom,
|
|
1262
|
+
message: `${field} applies to animate-skeleton revisions only`,
|
|
1263
|
+
path: [field]
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1206
1267
|
});
|
|
1207
|
-
var FRAME_SET_REVISION_MODES = ["animate", "animate-pixminimax", "interpolate", "edit-animation"];
|
|
1268
|
+
var FRAME_SET_REVISION_MODES = ["animate", "animate-pixminimax", "animate-skeleton", "interpolate", "edit-animation"];
|
|
1208
1269
|
var MEMBER_SET_REVISION_MODES = ["reduce-colors", "correct-pixelart", "edit-animation"];
|
|
1209
1270
|
var StyleObjectSchema = z.object({
|
|
1210
1271
|
/** Generation backend for this style. Omit to inherit the manifest default. */
|
|
@@ -1836,11 +1897,16 @@ var LockEntrySchema = z.object({
|
|
|
1836
1897
|
paletteImageSha256: z.string().regex(/^[0-9a-f]{64}$/).optional(),
|
|
1837
1898
|
dithering: RevisionDitheringSchema.optional(),
|
|
1838
1899
|
ditheringStrength: z.number().min(0).max(10).optional(),
|
|
1839
|
-
|
|
1900
|
+
// 4-40 for animate/animate-pixminimax; animate-skeleton's own 3-15
|
|
1901
|
+
// range extends the floor down to 3, hence min(3) here rather than 4.
|
|
1902
|
+
frames: z.number().int().min(3).max(40).optional(),
|
|
1840
1903
|
fps: z.number().int().min(1).max(60).optional(),
|
|
1841
1904
|
lastFrameSha256: z.string().regex(/^[0-9a-f]{64}$/).optional(),
|
|
1842
1905
|
direction: CharacterDirectionSchema.optional(),
|
|
1843
1906
|
enhancePrompt: z.boolean().optional(),
|
|
1907
|
+
keypointsSha256: z.string().regex(/^[0-9a-f]{64}$/).optional(),
|
|
1908
|
+
skeletonTemplate: z.string().min(1).optional(),
|
|
1909
|
+
description: z.string().min(1).optional(),
|
|
1844
1910
|
engine: z.enum(["pro-flash"]).optional()
|
|
1845
1911
|
}).strict().nullable().default(null),
|
|
1846
1912
|
/** For a mirror: the asset it flips and a hash over that asset's output hashes when this was made. */
|
|
@@ -4993,11 +5059,12 @@ var ComfyUIProvider = class _ComfyUIProvider {
|
|
|
4993
5059
|
/**
|
|
4994
5060
|
* Everything else resolves generically to whatever the user's own
|
|
4995
5061
|
* workflow does with `bindings.sourceImage`. The frame-set modes
|
|
4996
|
-
* (`animate`, `animate-pixminimax`, `
|
|
4997
|
-
* the exception: they produce an ordered frame set,
|
|
4998
|
-
* revision path always writes a single output image
|
|
4999
|
-
* below) — a real structural gap, not a missing
|
|
5000
|
-
* rejected here rather than only failing once
|
|
5062
|
+
* (`animate`, `animate-pixminimax`, `animate-skeleton`, `interpolate`,
|
|
5063
|
+
* `edit-animation`) are the exception: they produce an ordered frame set,
|
|
5064
|
+
* and this adapter's revision path always writes a single output image
|
|
5065
|
+
* (see `submit`/`fetch` below) — a real structural gap, not a missing
|
|
5066
|
+
* binding, so they are rejected here rather than only failing once
|
|
5067
|
+
* `validate` runs.
|
|
5001
5068
|
*/
|
|
5002
5069
|
supportsRevision(mode2) {
|
|
5003
5070
|
return !FRAME_SET_REVISION_MODES.includes(mode2);
|
|
@@ -5657,262 +5724,291 @@ import os from "os";
|
|
|
5657
5724
|
import path12 from "path";
|
|
5658
5725
|
|
|
5659
5726
|
// src/client.ts
|
|
5727
|
+
import { z as z3 } from "zod";
|
|
5728
|
+
|
|
5729
|
+
// src/skeleton.ts
|
|
5660
5730
|
import { z as z2 } from "zod";
|
|
5731
|
+
var SkeletonKeypointSchema = z2.object({
|
|
5732
|
+
label: z2.string().min(1),
|
|
5733
|
+
x: z2.number().min(0).max(1),
|
|
5734
|
+
y: z2.number().min(0).max(1),
|
|
5735
|
+
z_index: z2.number(),
|
|
5736
|
+
depth: z2.number().optional()
|
|
5737
|
+
}).strict();
|
|
5738
|
+
var SkeletonFrameSchema = z2.array(SkeletonKeypointSchema).length(18);
|
|
5739
|
+
var SkeletonSetSchema = z2.object({
|
|
5740
|
+
firstFrameKeypoints: SkeletonFrameSchema,
|
|
5741
|
+
frames: z2.array(SkeletonFrameSchema).min(3).max(15)
|
|
5742
|
+
}).strict();
|
|
5743
|
+
function parseSkeletonSet(json, file) {
|
|
5744
|
+
const result = SkeletonSetSchema.safeParse(json);
|
|
5745
|
+
if (!result.success) {
|
|
5746
|
+
const issues = result.error.issues.slice(0, 4).map((issue) => `${issue.path.join(".") || "root"}: ${issue.message}`).join("; ");
|
|
5747
|
+
throw new Error(`revision keypoints file ${file} does not match the expected shape: ${issues}`);
|
|
5748
|
+
}
|
|
5749
|
+
return result.data;
|
|
5750
|
+
}
|
|
5751
|
+
|
|
5752
|
+
// src/client.ts
|
|
5661
5753
|
var BASE = process.env.PIXELLAB_API_BASE ?? "https://api.pixellab.ai/v2";
|
|
5662
5754
|
var MAX_DOWNLOAD_BYTES = 64 * 1024 * 1024;
|
|
5663
|
-
var BalanceResponseSchema =
|
|
5664
|
-
credits:
|
|
5665
|
-
subscription:
|
|
5666
|
-
generations:
|
|
5667
|
-
total:
|
|
5668
|
-
plan:
|
|
5755
|
+
var BalanceResponseSchema = z3.object({
|
|
5756
|
+
credits: z3.object({ usd: z3.number() }).passthrough(),
|
|
5757
|
+
subscription: z3.object({
|
|
5758
|
+
generations: z3.number(),
|
|
5759
|
+
total: z3.number(),
|
|
5760
|
+
plan: z3.string().nullable().optional()
|
|
5669
5761
|
}).passthrough()
|
|
5670
5762
|
}).passthrough();
|
|
5671
|
-
var ObjectSubmitSchema =
|
|
5672
|
-
background_job_id:
|
|
5673
|
-
object_id:
|
|
5674
|
-
status:
|
|
5675
|
-
n_frames:
|
|
5763
|
+
var ObjectSubmitSchema = z3.object({
|
|
5764
|
+
background_job_id: z3.string().min(1),
|
|
5765
|
+
object_id: z3.string().min(1),
|
|
5766
|
+
status: z3.string().default("queued"),
|
|
5767
|
+
n_frames: z3.number().int().min(0)
|
|
5676
5768
|
}).passthrough();
|
|
5677
|
-
var MapSubmitSchema =
|
|
5678
|
-
background_job_id:
|
|
5679
|
-
object_id:
|
|
5680
|
-
status:
|
|
5769
|
+
var MapSubmitSchema = z3.object({
|
|
5770
|
+
background_job_id: z3.string().min(1),
|
|
5771
|
+
object_id: z3.string().min(1),
|
|
5772
|
+
status: z3.string().default("processing")
|
|
5681
5773
|
}).passthrough();
|
|
5682
|
-
var UsageSchema =
|
|
5683
|
-
type:
|
|
5684
|
-
usd:
|
|
5685
|
-
generations:
|
|
5774
|
+
var UsageSchema = z3.object({
|
|
5775
|
+
type: z3.string().optional(),
|
|
5776
|
+
usd: z3.number().nullable().optional(),
|
|
5777
|
+
generations: z3.number().nullable().optional()
|
|
5686
5778
|
}).passthrough().nullable().optional();
|
|
5687
|
-
var TilesSubmitSchema =
|
|
5688
|
-
tile_id:
|
|
5689
|
-
background_job_id:
|
|
5690
|
-
status:
|
|
5779
|
+
var TilesSubmitSchema = z3.object({
|
|
5780
|
+
tile_id: z3.string().min(1),
|
|
5781
|
+
background_job_id: z3.string().min(1),
|
|
5782
|
+
status: z3.literal("processing").default("processing")
|
|
5691
5783
|
}).passthrough();
|
|
5692
|
-
var TilesProSchema =
|
|
5693
|
-
storage_urls:
|
|
5694
|
-
kind:
|
|
5695
|
-
tile_rules:
|
|
5784
|
+
var TilesProSchema = z3.object({
|
|
5785
|
+
storage_urls: z3.record(z3.string()),
|
|
5786
|
+
kind: z3.string().nullable().default(null),
|
|
5787
|
+
tile_rules: z3.record(z3.unknown()).nullable().optional()
|
|
5696
5788
|
}).passthrough();
|
|
5697
|
-
var TilesetSubmitSchema =
|
|
5698
|
-
tileset_id:
|
|
5699
|
-
background_job_id:
|
|
5700
|
-
status:
|
|
5789
|
+
var TilesetSubmitSchema = z3.object({
|
|
5790
|
+
tileset_id: z3.string().min(1),
|
|
5791
|
+
background_job_id: z3.string().min(1),
|
|
5792
|
+
status: z3.literal("processing").default("processing")
|
|
5701
5793
|
}).passthrough();
|
|
5702
|
-
var TilesetTileSchema =
|
|
5703
|
-
id:
|
|
5704
|
-
name:
|
|
5705
|
-
image:
|
|
5706
|
-
corners:
|
|
5707
|
-
pattern_4x4:
|
|
5708
|
-
row_0:
|
|
5709
|
-
row_1:
|
|
5710
|
-
row_2:
|
|
5711
|
-
row_3:
|
|
5794
|
+
var TilesetTileSchema = z3.object({
|
|
5795
|
+
id: z3.string().min(1),
|
|
5796
|
+
name: z3.string(),
|
|
5797
|
+
image: z3.object({ base64: z3.string().min(1), format: z3.string().default("png") }).passthrough(),
|
|
5798
|
+
corners: z3.object({ NW: z3.string(), NE: z3.string(), SW: z3.string(), SE: z3.string() }).passthrough(),
|
|
5799
|
+
pattern_4x4: z3.object({
|
|
5800
|
+
row_0: z3.array(z3.number()),
|
|
5801
|
+
row_1: z3.array(z3.number()),
|
|
5802
|
+
row_2: z3.array(z3.number()),
|
|
5803
|
+
row_3: z3.array(z3.number())
|
|
5712
5804
|
}).passthrough()
|
|
5713
5805
|
}).passthrough();
|
|
5714
|
-
var TilesetGetSchema =
|
|
5715
|
-
tileset:
|
|
5716
|
-
total_tiles:
|
|
5717
|
-
tile_size:
|
|
5718
|
-
terrain_types:
|
|
5719
|
-
tiles:
|
|
5806
|
+
var TilesetGetSchema = z3.object({
|
|
5807
|
+
tileset: z3.object({
|
|
5808
|
+
total_tiles: z3.number().int().min(1),
|
|
5809
|
+
tile_size: z3.object({ width: z3.number().int().positive(), height: z3.number().int().positive() }).passthrough(),
|
|
5810
|
+
terrain_types: z3.array(z3.string()),
|
|
5811
|
+
tiles: z3.array(TilesetTileSchema).min(1)
|
|
5720
5812
|
}).passthrough(),
|
|
5721
5813
|
usage: UsageSchema
|
|
5722
5814
|
}).passthrough();
|
|
5723
|
-
var IsometricTileSubmitSchema =
|
|
5724
|
-
tile_id:
|
|
5725
|
-
background_job_id:
|
|
5726
|
-
status:
|
|
5815
|
+
var IsometricTileSubmitSchema = z3.object({
|
|
5816
|
+
tile_id: z3.string().min(1),
|
|
5817
|
+
background_job_id: z3.string().min(1),
|
|
5818
|
+
status: z3.literal("processing").default("processing")
|
|
5727
5819
|
}).passthrough();
|
|
5728
|
-
var IsometricTileGetSchema =
|
|
5729
|
-
image:
|
|
5820
|
+
var IsometricTileGetSchema = z3.object({
|
|
5821
|
+
image: z3.object({ base64: z3.string().min(1), format: z3.string().default("png") }).passthrough(),
|
|
5730
5822
|
usage: UsageSchema
|
|
5731
5823
|
}).passthrough();
|
|
5732
|
-
var UiAssetSubmitSchema =
|
|
5733
|
-
ui_asset_id:
|
|
5734
|
-
background_job_id:
|
|
5735
|
-
status:
|
|
5824
|
+
var UiAssetSubmitSchema = z3.object({
|
|
5825
|
+
ui_asset_id: z3.string().min(1),
|
|
5826
|
+
background_job_id: z3.string().min(1),
|
|
5827
|
+
status: z3.string().default("processing"),
|
|
5736
5828
|
usage: UsageSchema
|
|
5737
5829
|
}).passthrough();
|
|
5738
|
-
var UiAssetGetSchema =
|
|
5739
|
-
id:
|
|
5740
|
-
status:
|
|
5741
|
-
image_url:
|
|
5742
|
-
progress_percent:
|
|
5743
|
-
eta_seconds:
|
|
5830
|
+
var UiAssetGetSchema = z3.object({
|
|
5831
|
+
id: z3.string().min(1),
|
|
5832
|
+
status: z3.string().nullable().default(null),
|
|
5833
|
+
image_url: z3.string().nullable().optional(),
|
|
5834
|
+
progress_percent: z3.number().nullable().optional(),
|
|
5835
|
+
eta_seconds: z3.number().nullable().optional()
|
|
5744
5836
|
}).passthrough();
|
|
5745
|
-
var RevisionJobSubmitSchema =
|
|
5746
|
-
background_job_id:
|
|
5747
|
-
status:
|
|
5837
|
+
var RevisionJobSubmitSchema = z3.object({
|
|
5838
|
+
background_job_id: z3.string().min(1),
|
|
5839
|
+
status: z3.string().default("processing")
|
|
5748
5840
|
}).passthrough();
|
|
5749
|
-
var ObjectAnimationGroupSchema =
|
|
5750
|
-
animation_group_id:
|
|
5751
|
-
display_name:
|
|
5752
|
-
description:
|
|
5753
|
-
frame_count:
|
|
5754
|
-
directions:
|
|
5755
|
-
|
|
5756
|
-
direction:
|
|
5757
|
-
storage_urls:
|
|
5758
|
-
created_at:
|
|
5841
|
+
var ObjectAnimationGroupSchema = z3.object({
|
|
5842
|
+
animation_group_id: z3.string().min(1),
|
|
5843
|
+
display_name: z3.string().nullable().default(null),
|
|
5844
|
+
description: z3.string().default(""),
|
|
5845
|
+
frame_count: z3.number().int().default(0),
|
|
5846
|
+
directions: z3.array(
|
|
5847
|
+
z3.object({
|
|
5848
|
+
direction: z3.string(),
|
|
5849
|
+
storage_urls: z3.record(z3.unknown()).default({}),
|
|
5850
|
+
created_at: z3.string()
|
|
5759
5851
|
}).passthrough()
|
|
5760
5852
|
).default([])
|
|
5761
5853
|
}).passthrough();
|
|
5762
|
-
var PixelLabObjectSchema =
|
|
5763
|
-
id:
|
|
5764
|
-
name:
|
|
5765
|
-
state_name:
|
|
5766
|
-
prompt:
|
|
5767
|
-
size:
|
|
5768
|
-
directions:
|
|
5769
|
-
created_at:
|
|
5770
|
-
view:
|
|
5771
|
-
preview_url:
|
|
5772
|
-
rotation_urls:
|
|
5773
|
-
frame_urls:
|
|
5774
|
-
tags:
|
|
5775
|
-
status:
|
|
5776
|
-
progress_percent:
|
|
5777
|
-
eta_seconds:
|
|
5778
|
-
group_id:
|
|
5779
|
-
animations:
|
|
5854
|
+
var PixelLabObjectSchema = z3.object({
|
|
5855
|
+
id: z3.string().min(1),
|
|
5856
|
+
name: z3.string().nullable().default(null),
|
|
5857
|
+
state_name: z3.string().nullable().optional(),
|
|
5858
|
+
prompt: z3.string().default(""),
|
|
5859
|
+
size: z3.object({ width: z3.number().int().positive(), height: z3.number().int().positive() }),
|
|
5860
|
+
directions: z3.number().default(0),
|
|
5861
|
+
created_at: z3.string(),
|
|
5862
|
+
view: z3.string().nullable().default(null),
|
|
5863
|
+
preview_url: z3.string().nullable().optional(),
|
|
5864
|
+
rotation_urls: z3.record(z3.string().nullable()).nullable().optional(),
|
|
5865
|
+
frame_urls: z3.array(z3.string()).nullable().optional(),
|
|
5866
|
+
tags: z3.array(z3.string()).default([]),
|
|
5867
|
+
status: z3.string().nullable().default(null),
|
|
5868
|
+
progress_percent: z3.number().nullable().optional(),
|
|
5869
|
+
eta_seconds: z3.number().nullable().optional(),
|
|
5870
|
+
group_id: z3.string().nullable().optional(),
|
|
5871
|
+
animations: z3.array(ObjectAnimationGroupSchema).default([])
|
|
5872
|
+
}).passthrough();
|
|
5873
|
+
var MapObjectSchema = z3.object({
|
|
5874
|
+
object_id: z3.string().min(1),
|
|
5875
|
+
status: z3.string(),
|
|
5876
|
+
description: z3.string().nullable().default(null),
|
|
5877
|
+
width: z3.number().nullable().default(null),
|
|
5878
|
+
height: z3.number().nullable().default(null),
|
|
5879
|
+
download_url: z3.string().nullable().default(null)
|
|
5780
5880
|
}).passthrough();
|
|
5781
|
-
var
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5881
|
+
var ObjectListSchema = z3.object({ objects: z3.array(PixelLabObjectSchema), total: z3.number().int().min(0) }).passthrough();
|
|
5882
|
+
var PixfluxResponseSchema = z3.object({ image: z3.object({ base64: z3.string().min(1) }).passthrough(), usage: z3.unknown().optional() }).passthrough();
|
|
5883
|
+
var ReduceColorsResponseSchema = z3.object({
|
|
5884
|
+
images: z3.array(z3.object({ base64: z3.string().min(1) }).passthrough()).min(1),
|
|
5885
|
+
palette: z3.object({ base64: z3.string().min(1) }).passthrough(),
|
|
5886
|
+
n_colors: z3.number().int(),
|
|
5887
|
+
usage: z3.unknown().optional()
|
|
5788
5888
|
}).passthrough();
|
|
5789
|
-
var
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
images: z2.array(z2.object({ base64: z2.string().min(1) }).passthrough()).min(1),
|
|
5793
|
-
palette: z2.object({ base64: z2.string().min(1) }).passthrough(),
|
|
5794
|
-
n_colors: z2.number().int(),
|
|
5795
|
-
usage: z2.unknown().optional()
|
|
5889
|
+
var CorrectPixelartResponseSchema = z3.object({
|
|
5890
|
+
images: z3.array(z3.object({ base64: z3.string().min(1) }).passthrough()).min(1),
|
|
5891
|
+
usage: z3.unknown().optional()
|
|
5796
5892
|
}).passthrough();
|
|
5797
|
-
var
|
|
5798
|
-
|
|
5799
|
-
|
|
5893
|
+
var ProFlashImageSubmitSchema = z3.object({
|
|
5894
|
+
background_job_id: z3.string().min(1),
|
|
5895
|
+
image_id: z3.string().min(1),
|
|
5896
|
+
source_image_id: z3.string().min(1),
|
|
5897
|
+
status: z3.string().default("processing"),
|
|
5898
|
+
estimated_generations: z3.number().nullable().optional(),
|
|
5899
|
+
usage: z3.unknown().optional()
|
|
5800
5900
|
}).passthrough();
|
|
5801
|
-
var
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
usage: z2.unknown().optional()
|
|
5901
|
+
var UnzoomResponseSchema = z3.object({
|
|
5902
|
+
image: z3.object({ base64: z3.string().min(1) }).passthrough(),
|
|
5903
|
+
original_size: z3.object({ width: z3.number().int(), height: z3.number().int() }).passthrough(),
|
|
5904
|
+
unzoomed_size: z3.object({ width: z3.number().int(), height: z3.number().int() }).passthrough(),
|
|
5905
|
+
zoom_factor_detected: z3.number(),
|
|
5906
|
+
usage: z3.unknown().optional()
|
|
5808
5907
|
}).passthrough();
|
|
5809
|
-
var
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5908
|
+
var FontJobSchema = z3.object({
|
|
5909
|
+
job_id: z3.string().min(1),
|
|
5910
|
+
status: z3.string(),
|
|
5911
|
+
glyph_px: z3.number().int().nullable().optional(),
|
|
5912
|
+
download_atlas_url: z3.string().nullable().optional(),
|
|
5913
|
+
download_ttf_url: z3.string().nullable().optional(),
|
|
5914
|
+
usage: z3.unknown().optional()
|
|
5815
5915
|
}).passthrough();
|
|
5816
|
-
var
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
download_atlas_url: z2.string().nullable().optional(),
|
|
5821
|
-
download_ttf_url: z2.string().nullable().optional(),
|
|
5822
|
-
usage: z2.unknown().optional()
|
|
5916
|
+
var SelectFramesSchema = z3.object({ created_object_ids: z3.array(z3.string()) }).passthrough();
|
|
5917
|
+
var EstimateSkeletonResponseSchema = z3.object({
|
|
5918
|
+
keypoints: z3.array(SkeletonKeypointSchema).length(18),
|
|
5919
|
+
usage: z3.unknown().optional()
|
|
5823
5920
|
}).passthrough();
|
|
5824
|
-
var
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
status: z2.string().default("processing"),
|
|
5921
|
+
var CharacterSubmitSchema = z3.object({
|
|
5922
|
+
background_job_id: z3.string().min(1),
|
|
5923
|
+
character_id: z3.string().min(1),
|
|
5924
|
+
status: z3.string().default("processing"),
|
|
5829
5925
|
usage: UsageSchema
|
|
5830
5926
|
}).passthrough();
|
|
5831
|
-
var AnimateSubmitSchema =
|
|
5832
|
-
background_job_ids:
|
|
5833
|
-
directions:
|
|
5834
|
-
status:
|
|
5927
|
+
var AnimateSubmitSchema = z3.object({
|
|
5928
|
+
background_job_ids: z3.array(z3.string()),
|
|
5929
|
+
directions: z3.array(z3.string()),
|
|
5930
|
+
status: z3.string().default("processing"),
|
|
5835
5931
|
usage: UsageSchema
|
|
5836
5932
|
}).passthrough();
|
|
5837
|
-
var ObjectProSubmitSchema =
|
|
5838
|
-
object_id:
|
|
5839
|
-
background_job_id:
|
|
5840
|
-
status:
|
|
5933
|
+
var ObjectProSubmitSchema = z3.object({
|
|
5934
|
+
object_id: z3.string().min(1),
|
|
5935
|
+
background_job_id: z3.string().min(1),
|
|
5936
|
+
status: z3.string().default("processing"),
|
|
5841
5937
|
usage: UsageSchema
|
|
5842
5938
|
}).passthrough();
|
|
5843
|
-
var DirectionSubmissionSchema =
|
|
5844
|
-
direction:
|
|
5845
|
-
status:
|
|
5846
|
-
background_job_id:
|
|
5847
|
-
animation_id:
|
|
5939
|
+
var DirectionSubmissionSchema = z3.object({
|
|
5940
|
+
direction: z3.string(),
|
|
5941
|
+
status: z3.string(),
|
|
5942
|
+
background_job_id: z3.string().nullable().default(null),
|
|
5943
|
+
animation_id: z3.string().nullable().default(null)
|
|
5848
5944
|
}).passthrough();
|
|
5849
|
-
var AnimateObjectSubmitSchema =
|
|
5850
|
-
animation_group_id:
|
|
5851
|
-
object_id:
|
|
5852
|
-
mode:
|
|
5853
|
-
frame_count:
|
|
5854
|
-
display_name:
|
|
5855
|
-
description:
|
|
5856
|
-
submissions:
|
|
5945
|
+
var AnimateObjectSubmitSchema = z3.object({
|
|
5946
|
+
animation_group_id: z3.string().min(1),
|
|
5947
|
+
object_id: z3.string().min(1),
|
|
5948
|
+
mode: z3.string(),
|
|
5949
|
+
frame_count: z3.number().int(),
|
|
5950
|
+
display_name: z3.string().nullable().default(null),
|
|
5951
|
+
description: z3.string().default(""),
|
|
5952
|
+
submissions: z3.array(DirectionSubmissionSchema),
|
|
5857
5953
|
usage: UsageSchema
|
|
5858
5954
|
}).passthrough();
|
|
5859
|
-
var PortraitSubmitSchema =
|
|
5860
|
-
background_job_id:
|
|
5861
|
-
status:
|
|
5955
|
+
var PortraitSubmitSchema = z3.object({
|
|
5956
|
+
background_job_id: z3.string().min(1),
|
|
5957
|
+
status: z3.string().default("processing"),
|
|
5862
5958
|
usage: UsageSchema
|
|
5863
5959
|
}).passthrough();
|
|
5864
|
-
var PortraitJobSchema =
|
|
5865
|
-
status:
|
|
5866
|
-
download_url:
|
|
5867
|
-
width:
|
|
5868
|
-
height:
|
|
5960
|
+
var PortraitJobSchema = z3.object({
|
|
5961
|
+
status: z3.string(),
|
|
5962
|
+
download_url: z3.string().nullable().optional(),
|
|
5963
|
+
width: z3.number().int().nullable().optional(),
|
|
5964
|
+
height: z3.number().int().nullable().optional()
|
|
5869
5965
|
}).passthrough();
|
|
5870
|
-
var SetPortraitSchema =
|
|
5871
|
-
character_id:
|
|
5872
|
-
size:
|
|
5873
|
-
url:
|
|
5966
|
+
var SetPortraitSchema = z3.object({
|
|
5967
|
+
character_id: z3.string().min(1),
|
|
5968
|
+
size: z3.number().int().positive(),
|
|
5969
|
+
url: z3.string().min(1),
|
|
5874
5970
|
usage: UsageSchema
|
|
5875
5971
|
}).passthrough();
|
|
5876
|
-
var TransferOutfitSubmitSchema =
|
|
5877
|
-
background_job_id:
|
|
5878
|
-
status:
|
|
5972
|
+
var TransferOutfitSubmitSchema = z3.object({
|
|
5973
|
+
background_job_id: z3.string().min(1),
|
|
5974
|
+
status: z3.string().default("processing"),
|
|
5879
5975
|
usage: UsageSchema
|
|
5880
5976
|
}).passthrough();
|
|
5881
|
-
var CharacterAnimationDirectionSchema =
|
|
5882
|
-
direction:
|
|
5883
|
-
frame_count:
|
|
5884
|
-
frames:
|
|
5977
|
+
var CharacterAnimationDirectionSchema = z3.object({
|
|
5978
|
+
direction: z3.string(),
|
|
5979
|
+
frame_count: z3.number().int().min(0),
|
|
5980
|
+
frames: z3.array(z3.string())
|
|
5885
5981
|
}).passthrough();
|
|
5886
|
-
var CharacterAnimationSchema2 =
|
|
5887
|
-
animation_type:
|
|
5888
|
-
display_name:
|
|
5889
|
-
animation_group_id:
|
|
5890
|
-
directions:
|
|
5982
|
+
var CharacterAnimationSchema2 = z3.object({
|
|
5983
|
+
animation_type: z3.string(),
|
|
5984
|
+
display_name: z3.string().nullable().optional(),
|
|
5985
|
+
animation_group_id: z3.string().nullable().optional(),
|
|
5986
|
+
directions: z3.array(CharacterAnimationDirectionSchema)
|
|
5891
5987
|
}).passthrough();
|
|
5892
|
-
var CharacterSchema =
|
|
5893
|
-
id:
|
|
5894
|
-
name:
|
|
5895
|
-
state_name:
|
|
5896
|
-
prompt:
|
|
5897
|
-
size:
|
|
5898
|
-
directions:
|
|
5899
|
-
created_at:
|
|
5900
|
-
updated_at:
|
|
5901
|
-
animation_count:
|
|
5902
|
-
template_id:
|
|
5903
|
-
view:
|
|
5904
|
-
status:
|
|
5905
|
-
rotation_urls:
|
|
5906
|
-
tags:
|
|
5907
|
-
group_id:
|
|
5908
|
-
animations:
|
|
5909
|
-
preview_url:
|
|
5988
|
+
var CharacterSchema = z3.object({
|
|
5989
|
+
id: z3.string().min(1),
|
|
5990
|
+
name: z3.string().default(""),
|
|
5991
|
+
state_name: z3.string().nullable().optional(),
|
|
5992
|
+
prompt: z3.string().default(""),
|
|
5993
|
+
size: z3.object({ width: z3.number().int().positive(), height: z3.number().int().positive() }),
|
|
5994
|
+
directions: z3.number().int(),
|
|
5995
|
+
created_at: z3.string(),
|
|
5996
|
+
updated_at: z3.string().nullable().optional(),
|
|
5997
|
+
animation_count: z3.number().int().default(0),
|
|
5998
|
+
template_id: z3.string().default("mannequin"),
|
|
5999
|
+
view: z3.string().nullable().optional(),
|
|
6000
|
+
status: z3.string().default("completed"),
|
|
6001
|
+
rotation_urls: z3.record(z3.string().nullable()).nullable().optional(),
|
|
6002
|
+
tags: z3.array(z3.string()).default([]),
|
|
6003
|
+
group_id: z3.string().nullable().optional(),
|
|
6004
|
+
animations: z3.array(CharacterAnimationSchema2).default([]),
|
|
6005
|
+
preview_url: z3.string().nullable().optional()
|
|
5910
6006
|
}).passthrough();
|
|
5911
|
-
var CharacterListSchema =
|
|
5912
|
-
var BackgroundJobSchema =
|
|
5913
|
-
id:
|
|
5914
|
-
status:
|
|
5915
|
-
last_response:
|
|
6007
|
+
var CharacterListSchema = z3.object({ characters: z3.array(CharacterSchema), total: z3.number().int().min(0) }).passthrough();
|
|
6008
|
+
var BackgroundJobSchema = z3.object({
|
|
6009
|
+
id: z3.string(),
|
|
6010
|
+
status: z3.string(),
|
|
6011
|
+
last_response: z3.record(z3.unknown()).nullable().optional(),
|
|
5916
6012
|
/**
|
|
5917
6013
|
* The billed amount, confirmed live for a `map` object and a standard
|
|
5918
6014
|
* character base (docs/ENDPOINTS.md, "Limits and billing"); duplicated at
|
|
@@ -5920,7 +6016,7 @@ var BackgroundJobSchema = z2.object({
|
|
|
5920
6016
|
*/
|
|
5921
6017
|
usage: UsageSchema
|
|
5922
6018
|
}).passthrough();
|
|
5923
|
-
var DeleteAnimationsSchema =
|
|
6019
|
+
var DeleteAnimationsSchema = z3.object({ success: z3.boolean(), deleted_count: z3.number().int().default(0), error: z3.string().nullable().optional() }).passthrough();
|
|
5924
6020
|
function validateResponse(schema, raw, operation) {
|
|
5925
6021
|
const parsed = schema.safeParse(raw);
|
|
5926
6022
|
if (parsed.success) return parsed.data;
|
|
@@ -5966,9 +6062,9 @@ var PixelLabClient = class {
|
|
|
5966
6062
|
apiKey;
|
|
5967
6063
|
http;
|
|
5968
6064
|
/** Retries transport failures, 429, and 5xx; see http.ts for the policy. */
|
|
5969
|
-
async request(
|
|
6065
|
+
async request(path48, init) {
|
|
5970
6066
|
const auth = this.apiKey.startsWith("Bearer ") ? this.apiKey : `Bearer ${this.apiKey}`;
|
|
5971
|
-
const res = await this.http(`${BASE}${
|
|
6067
|
+
const res = await this.http(`${BASE}${path48}`, {
|
|
5972
6068
|
...init,
|
|
5973
6069
|
headers: {
|
|
5974
6070
|
Authorization: auth,
|
|
@@ -5978,13 +6074,13 @@ var PixelLabClient = class {
|
|
|
5978
6074
|
});
|
|
5979
6075
|
const text = await res.text();
|
|
5980
6076
|
if (!res.ok) {
|
|
5981
|
-
throw new PixelLabError(`${init?.method ?? "GET"} ${
|
|
6077
|
+
throw new PixelLabError(`${init?.method ?? "GET"} ${path48} \u2192 ${res.status}`, res.status, text);
|
|
5982
6078
|
}
|
|
5983
6079
|
if (!text) return {};
|
|
5984
6080
|
try {
|
|
5985
6081
|
return JSON.parse(text);
|
|
5986
6082
|
} catch {
|
|
5987
|
-
throw new Error(`${init?.method ?? "GET"} ${
|
|
6083
|
+
throw new Error(`${init?.method ?? "GET"} ${path48} returned invalid JSON`);
|
|
5988
6084
|
}
|
|
5989
6085
|
}
|
|
5990
6086
|
async balance() {
|
|
@@ -6370,10 +6466,10 @@ var PixelLabClient = class {
|
|
|
6370
6466
|
const palette = args.paletteSwatchBase64 ? { color_image: { type: "base64", base64: args.paletteSwatchBase64, format: "png" }, force_colors: true } : {};
|
|
6371
6467
|
const encode = (image) => ({ type: "base64", base64: image.base64, format: image.format });
|
|
6372
6468
|
const south = args.reference?.south;
|
|
6373
|
-
let
|
|
6469
|
+
let path48;
|
|
6374
6470
|
let body;
|
|
6375
6471
|
if (args.mode === "v3") {
|
|
6376
|
-
|
|
6472
|
+
path48 = "/create-character-v3";
|
|
6377
6473
|
body = {
|
|
6378
6474
|
description: args.description,
|
|
6379
6475
|
image_size: imageSize,
|
|
@@ -6387,7 +6483,7 @@ var PixelLabClient = class {
|
|
|
6387
6483
|
...args.enhancePrompt ? { enhance_prompt: true } : {}
|
|
6388
6484
|
};
|
|
6389
6485
|
} else if (args.mode === "pro-flash") {
|
|
6390
|
-
|
|
6486
|
+
path48 = "/create-character-pro-flash";
|
|
6391
6487
|
const traits = args.styleTraits;
|
|
6392
6488
|
body = {
|
|
6393
6489
|
description: args.description,
|
|
@@ -6411,7 +6507,7 @@ var PixelLabClient = class {
|
|
|
6411
6507
|
} : {}
|
|
6412
6508
|
};
|
|
6413
6509
|
} else if (args.mode === "pro") {
|
|
6414
|
-
|
|
6510
|
+
path48 = "/create-character-pro";
|
|
6415
6511
|
body = {
|
|
6416
6512
|
description: args.description,
|
|
6417
6513
|
image_size: imageSize,
|
|
@@ -6425,7 +6521,7 @@ var PixelLabClient = class {
|
|
|
6425
6521
|
...!south && args.styleCharacterId ? { style_character_id: args.styleCharacterId } : {}
|
|
6426
6522
|
};
|
|
6427
6523
|
} else {
|
|
6428
|
-
|
|
6524
|
+
path48 = args.directions === 4 ? "/create-character-with-4-directions" : "/create-character-with-8-directions";
|
|
6429
6525
|
body = {
|
|
6430
6526
|
description: args.description,
|
|
6431
6527
|
image_size: imageSize,
|
|
@@ -6442,8 +6538,8 @@ var PixelLabClient = class {
|
|
|
6442
6538
|
...palette
|
|
6443
6539
|
};
|
|
6444
6540
|
}
|
|
6445
|
-
const raw = await this.request(
|
|
6446
|
-
return validateResponse(CharacterSubmitSchema, raw,
|
|
6541
|
+
const raw = await this.request(path48, { method: "POST", body: JSON.stringify(body) });
|
|
6542
|
+
return validateResponse(CharacterSubmitSchema, raw, path48.slice(1));
|
|
6447
6543
|
}
|
|
6448
6544
|
/** A text edit of an existing character, applied to every direction and stored as a sibling. */
|
|
6449
6545
|
async createCharacterState(args) {
|
|
@@ -6951,6 +7047,61 @@ var PixelLabClient = class {
|
|
|
6951
7047
|
"animate-pixminimax"
|
|
6952
7048
|
);
|
|
6953
7049
|
}
|
|
7050
|
+
/**
|
|
7051
|
+
* `/animate-with-skeleton-v3`, beta (tier 1 subscription or higher): poses
|
|
7052
|
+
* one reference image frame-by-frame from a supplied skeleton per frame,
|
|
7053
|
+
* rather than a text motion description. Confirmed against the live
|
|
7054
|
+
* `animate_with_skeleton_v3` MCP tool schema (the same authoritative
|
|
7055
|
+
* source this codebase already treats as ground truth for the
|
|
7056
|
+
* character/object family) — `action`/`description` are both real,
|
|
7057
|
+
* optional wire fields, contrary to an initial guess that this endpoint
|
|
7058
|
+
* took no text input at all; `direction`/`keypoints`/`firstFrameKeypoints`
|
|
7059
|
+
* are required. The example keypoint from that same tool schema,
|
|
7060
|
+
* `{"label": "RIGHT KNEE", "x": 0.52, "y": 0.71, "z_index": 9}`, is what
|
|
7061
|
+
* `SkeletonKeypointSchema` (`src/skeleton.ts`) models. Same
|
|
7062
|
+
* unverified-completed-shape caveat as `animateWithTextV3`/
|
|
7063
|
+
* `animatePixminimax` above — this endpoint has never been called against
|
|
7064
|
+
* a live account by this codebase.
|
|
7065
|
+
*/
|
|
7066
|
+
async animateWithSkeletonV3(args) {
|
|
7067
|
+
const body = {
|
|
7068
|
+
first_frame: args.firstFrame,
|
|
7069
|
+
first_frame_keypoints: args.firstFrameKeypoints,
|
|
7070
|
+
keypoints: args.keypoints,
|
|
7071
|
+
direction: args.direction
|
|
7072
|
+
};
|
|
7073
|
+
if (args.templateId) body.template_id = args.templateId;
|
|
7074
|
+
if (args.action) body.action = args.action;
|
|
7075
|
+
if (args.description) body.description = args.description;
|
|
7076
|
+
if (args.seed != null) body.seed = args.seed;
|
|
7077
|
+
if (args.noBackground != null) body.no_background = args.noBackground;
|
|
7078
|
+
return validateResponse(
|
|
7079
|
+
RevisionJobSubmitSchema,
|
|
7080
|
+
await this.request("/animate-with-skeleton-v3", { method: "POST", body: JSON.stringify(body) }),
|
|
7081
|
+
"animate-with-skeleton-v3"
|
|
7082
|
+
);
|
|
7083
|
+
}
|
|
7084
|
+
/**
|
|
7085
|
+
* `/estimate-skeleton`: auto-derives a reference image's own 18-joint
|
|
7086
|
+
* keypoints, directly usable as `animateWithSkeletonV3`'s
|
|
7087
|
+
* `firstFrameKeypoints` (or, run against a candidate pose image, as one
|
|
7088
|
+
* entry of its `keypoints` sequence). Not called anywhere in this
|
|
7089
|
+
* codebase's own submit/poll pipeline — deliberately kept outside it (see
|
|
7090
|
+
* `runEstimateSkeleton` in `src/cli/commands`) so the only PixelLab
|
|
7091
|
+
* endpoint composed into `animate-with-skeleton-v3`'s submission is that
|
|
7092
|
+
* one endpoint itself, not two unverified calls chained together.
|
|
7093
|
+
* Synchronous per this endpoint's own framing; unverified against a live
|
|
7094
|
+
* account (see `EstimateSkeletonResponseSchema`'s own caveat).
|
|
7095
|
+
*/
|
|
7096
|
+
async estimateSkeleton(args) {
|
|
7097
|
+
const body = { image: args.image };
|
|
7098
|
+
const res = validateResponse(
|
|
7099
|
+
EstimateSkeletonResponseSchema,
|
|
7100
|
+
await this.request("/estimate-skeleton", { method: "POST", body: JSON.stringify(body) }),
|
|
7101
|
+
"estimate-skeleton"
|
|
7102
|
+
);
|
|
7103
|
+
return { keypoints: res.keypoints, usage: res.usage };
|
|
7104
|
+
}
|
|
6954
7105
|
async getBackgroundJob(jobId) {
|
|
6955
7106
|
const raw = await this.request(`/background-jobs/${encodeURIComponent(jobId)}`);
|
|
6956
7107
|
return validateResponse(BackgroundJobSchema, raw, "background-jobs/{id}");
|
|
@@ -7084,6 +7235,18 @@ function objectProCost(spec) {
|
|
|
7084
7235
|
const south = object.reference;
|
|
7085
7236
|
return south ? proFlashObjectCost(south.width, south.height, object.directions, true) : proFlashObjectCost(spec.width, spec.height, object.directions, false);
|
|
7086
7237
|
}
|
|
7238
|
+
function animateSkeletonCost(frames) {
|
|
7239
|
+
const anchors = [[3, 2], [8, 3], [15, 4]];
|
|
7240
|
+
for (let i = 0; i < anchors.length - 1; i++) {
|
|
7241
|
+
const [lowFrames, lowCost] = anchors[i];
|
|
7242
|
+
const [highFrames, highCost] = anchors[i + 1];
|
|
7243
|
+
if (frames >= lowFrames && frames <= highFrames) {
|
|
7244
|
+
const t = (frames - lowFrames) / (highFrames - lowFrames);
|
|
7245
|
+
return lowCost + t * (highCost - lowCost);
|
|
7246
|
+
}
|
|
7247
|
+
}
|
|
7248
|
+
return frames <= anchors[0][0] ? anchors[0][1] : anchors[anchors.length - 1][1];
|
|
7249
|
+
}
|
|
7087
7250
|
var CHARACTER_TEMPLATES = ["mannequin", "bear", "cat", "dog", "horse", "lion"];
|
|
7088
7251
|
var PRO_FLASH_TEMPLATES = [...CHARACTER_TEMPLATES, "custom"];
|
|
7089
7252
|
function encodeAnimationJob(job) {
|
|
@@ -7142,7 +7305,9 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
7142
7305
|
* rather than a described edit — and `animate`/`animate-pixminimax`
|
|
7143
7306
|
* (`/animate-with-text-v3`, `/animate-pixminimax`), which animate any loose
|
|
7144
7307
|
* image from a text description with no character/object resource
|
|
7145
|
-
* required —
|
|
7308
|
+
* required — `animate-skeleton` (`/animate-with-skeleton-v3`, posing the
|
|
7309
|
+
* source from a supplied per-frame skeleton instead of a text description)
|
|
7310
|
+
* — and `interpolate` (`/interpolation-v2`, the in-betweens
|
|
7146
7311
|
* from one keyframe to another) and `edit-animation`
|
|
7147
7312
|
* (`/edit-animation-v2`, one text edit applied across a whole frame set).
|
|
7148
7313
|
* `outpaint` does not: there is no canvas-expansion endpoint in the API,
|
|
@@ -7150,7 +7315,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
7150
7315
|
* outpaint path yet.
|
|
7151
7316
|
*/
|
|
7152
7317
|
supportsRevision(mode2) {
|
|
7153
|
-
return mode2 === "inpaint" || mode2 === "image-to-image" || mode2 === "reduce-colors" || mode2 === "correct-pixelart" || mode2 === "animate" || mode2 === "animate-pixminimax" || mode2 === "interpolate" || mode2 === "edit-animation";
|
|
7318
|
+
return mode2 === "inpaint" || mode2 === "image-to-image" || mode2 === "reduce-colors" || mode2 === "correct-pixelart" || mode2 === "animate" || mode2 === "animate-pixminimax" || mode2 === "animate-skeleton" || mode2 === "interpolate" || mode2 === "edit-animation";
|
|
7154
7319
|
}
|
|
7155
7320
|
/** PixelLab's own constraints: submissions must be >2s apart, and
|
|
7156
7321
|
* background jobs in flight are capped by subscription tier (Tier 1=8,
|
|
@@ -7181,6 +7346,10 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
7181
7346
|
if (spec.revision?.mode === "reduce-colors" || spec.revision?.mode === "correct-pixelart") {
|
|
7182
7347
|
return { unit: "generations", amount: 0.1, candidates: 1 };
|
|
7183
7348
|
}
|
|
7349
|
+
if (spec.revision?.mode === "animate-skeleton") {
|
|
7350
|
+
const frames = spec.revision.frames ?? 8;
|
|
7351
|
+
return { unit: "generations", amount: Math.ceil(animateSkeletonCost(frames)), candidates: 1 };
|
|
7352
|
+
}
|
|
7184
7353
|
if (spec.revision?.mode === "interpolate" || spec.revision?.mode === "edit-animation") {
|
|
7185
7354
|
const width = spec.revision.sourceWidth ?? spec.width;
|
|
7186
7355
|
const height = spec.revision.sourceHeight ?? spec.height;
|
|
@@ -7262,6 +7431,18 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
7262
7431
|
throw new Error(`PixelLab correct-pixelart source is ${width}x${height}; the API takes at most 1024 pixels per side`);
|
|
7263
7432
|
}
|
|
7264
7433
|
}
|
|
7434
|
+
if (spec.revision?.mode === "animate-skeleton") {
|
|
7435
|
+
const { sourceWidth: width, sourceHeight: height, frames, skeletonTemplate } = spec.revision;
|
|
7436
|
+
if (width != null && height != null && (width > 256 || height > 256)) {
|
|
7437
|
+
throw new Error(`PixelLab animate-skeleton source is ${width}x${height}; the API takes at most 256 pixels per side`);
|
|
7438
|
+
}
|
|
7439
|
+
if (frames != null && (frames < 3 || frames > 15)) {
|
|
7440
|
+
throw new Error(`PixelLab animate-skeleton takes 3 to 15 frames; the keypoints file has ${frames}`);
|
|
7441
|
+
}
|
|
7442
|
+
if (skeletonTemplate && !CHARACTER_TEMPLATES.includes(skeletonTemplate)) {
|
|
7443
|
+
throw new Error(`PixelLab animate-skeleton template "${skeletonTemplate}" is not one of ${CHARACTER_TEMPLATES.join(", ")}`);
|
|
7444
|
+
}
|
|
7445
|
+
}
|
|
7265
7446
|
if (spec.revision?.mode === "animate" || spec.revision?.mode === "animate-pixminimax") {
|
|
7266
7447
|
const { sourceWidth: width, sourceHeight: height, mode: mode2, frames, lastFrameWidth, lastFrameHeight } = spec.revision;
|
|
7267
7448
|
if (width != null && height != null && (width > 256 || height > 256)) {
|
|
@@ -8411,6 +8592,27 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
8411
8592
|
});
|
|
8412
8593
|
return { jobId: res2.background_job_id };
|
|
8413
8594
|
}
|
|
8595
|
+
if (revision.mode === "animate-skeleton") {
|
|
8596
|
+
if (!revision.keypointsFile || !revision.keypointsSha256 || !revision.skeleton) {
|
|
8597
|
+
throw new Error(`${spec.styleId}/${spec.assetId}: revision keypoints are not ready`);
|
|
8598
|
+
}
|
|
8599
|
+
const keypointsBytes = readFileSync2(revision.keypointsFile);
|
|
8600
|
+
if (sha256(keypointsBytes) !== revision.keypointsSha256) {
|
|
8601
|
+
throw new Error(`${spec.styleId}/${spec.assetId}: revision keypoints changed after the manifest was resolved`);
|
|
8602
|
+
}
|
|
8603
|
+
const res2 = await this.client.animateWithSkeletonV3({
|
|
8604
|
+
firstFrame: image,
|
|
8605
|
+
firstFrameKeypoints: revision.skeleton.firstFrameKeypoints,
|
|
8606
|
+
keypoints: revision.skeleton.frames,
|
|
8607
|
+
direction: revision.direction,
|
|
8608
|
+
templateId: revision.skeletonTemplate,
|
|
8609
|
+
action: spec.prompt,
|
|
8610
|
+
description: revision.description,
|
|
8611
|
+
seed: spec.seed,
|
|
8612
|
+
noBackground: spec.noBackground
|
|
8613
|
+
});
|
|
8614
|
+
return { jobId: res2.background_job_id };
|
|
8615
|
+
}
|
|
8414
8616
|
if (revision.strength != null) {
|
|
8415
8617
|
throw new Error(
|
|
8416
8618
|
`${spec.styleId}/${spec.assetId}: PixelLab image-to-image revisions take no strength; edit-images-v2 always applies the full instruction`
|
|
@@ -8476,7 +8678,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
8476
8678
|
if (revisionMode === "reduce-colors" || revisionMode === "correct-pixelart") {
|
|
8477
8679
|
return this.pollCachedRevision(jobId, context);
|
|
8478
8680
|
}
|
|
8479
|
-
if (revisionMode === "animate" || revisionMode === "animate-pixminimax" || revisionMode === "interpolate" || revisionMode === "edit-animation") {
|
|
8681
|
+
if (revisionMode === "animate" || revisionMode === "animate-pixminimax" || revisionMode === "animate-skeleton" || revisionMode === "interpolate" || revisionMode === "edit-animation") {
|
|
8480
8682
|
return this.pollAnimateRevision(jobId, context);
|
|
8481
8683
|
}
|
|
8482
8684
|
if (context?.spec?.revision) return this.pollRevision(jobId);
|
|
@@ -9166,9 +9368,9 @@ var RetroDiffusionClient = class {
|
|
|
9166
9368
|
if (!response.ok) throw new ProviderError("retrodiffusion", `Retro Diffusion download failed (${response.status})`, { status: response.status });
|
|
9167
9369
|
return Buffer.from(await response.arrayBuffer());
|
|
9168
9370
|
}
|
|
9169
|
-
async call(
|
|
9371
|
+
async call(path48, init = {}) {
|
|
9170
9372
|
if (!this.token) throw new Error("RD_API_KEY is not set");
|
|
9171
|
-
const response = await this.request(`${this.baseUrl}${
|
|
9373
|
+
const response = await this.request(`${this.baseUrl}${path48}`, {
|
|
9172
9374
|
...init,
|
|
9173
9375
|
headers: {
|
|
9174
9376
|
"Content-Type": "application/json",
|
|
@@ -10712,6 +10914,8 @@ async function resolveSpecs(loaded, filter) {
|
|
|
10712
10914
|
const paletteImage = paletteImageFile ? await optionalRevisionImage(paletteImageFile, "revision palette image", "png") : null;
|
|
10713
10915
|
const lastFrameFile = asset.revision.lastFrame ? path13.resolve(root, asset.revision.lastFrame) : void 0;
|
|
10714
10916
|
const lastFrame = lastFrameFile ? await optionalRevisionImage(lastFrameFile, "revision last frame") : null;
|
|
10917
|
+
const keypointsFile = asset.revision.keypointsFile ? path13.resolve(root, asset.revision.keypointsFile) : void 0;
|
|
10918
|
+
const keypoints = keypointsFile ? await optionalSkeletonSet(keypointsFile) : null;
|
|
10715
10919
|
resolved.revision = {
|
|
10716
10920
|
mode: asset.revision.mode,
|
|
10717
10921
|
sourceAssetId: asset.revision.from,
|
|
@@ -10752,6 +10956,18 @@ async function resolveSpecs(loaded, filter) {
|
|
|
10752
10956
|
} : {},
|
|
10753
10957
|
...asset.revision.direction ? { direction: asset.revision.direction } : {},
|
|
10754
10958
|
...asset.revision.enhancePrompt == null ? {} : { enhancePrompt: asset.revision.enhancePrompt },
|
|
10959
|
+
...keypointsFile ? {
|
|
10960
|
+
keypointsFile,
|
|
10961
|
+
keypointsSha256: keypoints?.hash ?? null,
|
|
10962
|
+
skeleton: keypoints?.skeleton ?? null,
|
|
10963
|
+
// The manifest's own `frames` field stays rejected for this
|
|
10964
|
+
// mode (superRefine, types.ts) — the real frame count comes
|
|
10965
|
+
// from the keypoints file once it exists, not a manifest
|
|
10966
|
+
// number, so plan can only know it once authored.
|
|
10967
|
+
...keypoints ? { frames: keypoints.skeleton.frames.length } : {}
|
|
10968
|
+
} : {},
|
|
10969
|
+
...asset.revision.skeletonTemplate ? { skeletonTemplate: asset.revision.skeletonTemplate } : {},
|
|
10970
|
+
...asset.revision.description ? { description: asset.revision.description } : {},
|
|
10755
10971
|
...asset.revision.engine ? { engine: asset.revision.engine } : {}
|
|
10756
10972
|
};
|
|
10757
10973
|
}
|
|
@@ -10873,6 +11089,17 @@ async function optionalRevisionImage(file, label, requiredFormat) {
|
|
|
10873
11089
|
}
|
|
10874
11090
|
return { hash: sha256(bytes), ...metadata };
|
|
10875
11091
|
}
|
|
11092
|
+
async function optionalSkeletonSet(file) {
|
|
11093
|
+
if (!existsSync8(file)) return null;
|
|
11094
|
+
const bytes = await readFile6(file);
|
|
11095
|
+
let json;
|
|
11096
|
+
try {
|
|
11097
|
+
json = JSON.parse(bytes.toString("utf8"));
|
|
11098
|
+
} catch (error) {
|
|
11099
|
+
throw new Error(`revision keypoints file ${file} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
11100
|
+
}
|
|
11101
|
+
return { hash: sha256(bytes), skeleton: parseSkeletonSet(json, file) };
|
|
11102
|
+
}
|
|
10876
11103
|
async function revisionSourceMembers(stem, label) {
|
|
10877
11104
|
if (existsSync8(stem)) return null;
|
|
10878
11105
|
const at = (role) => memberPath(stem, role, 0, 2, MediaType.PNG);
|
|
@@ -11408,11 +11635,11 @@ import path15 from "path";
|
|
|
11408
11635
|
import { mkdir as mkdir5, readFile as readFile8, rename as rename5, rm as rm5, writeFile as writeFile5 } from "fs/promises";
|
|
11409
11636
|
import { existsSync as existsSync10 } from "fs";
|
|
11410
11637
|
import pathModule from "path";
|
|
11411
|
-
import { z as
|
|
11412
|
-
var HashCacheSchema =
|
|
11413
|
-
version:
|
|
11638
|
+
import { z as z4 } from "zod";
|
|
11639
|
+
var HashCacheSchema = z4.object({
|
|
11640
|
+
version: z4.literal(1),
|
|
11414
11641
|
/** objectId → sha256 of that object's image bytes. */
|
|
11415
|
-
hashes:
|
|
11642
|
+
hashes: z4.record(z4.string())
|
|
11416
11643
|
});
|
|
11417
11644
|
var SHA256_HEX = /^[a-f0-9]{64}$/;
|
|
11418
11645
|
function isSha256Hash(value) {
|
|
@@ -11421,10 +11648,10 @@ function isSha256Hash(value) {
|
|
|
11421
11648
|
function parseCache(value) {
|
|
11422
11649
|
return HashCacheSchema.parse(value);
|
|
11423
11650
|
}
|
|
11424
|
-
async function loadCache(
|
|
11425
|
-
if (!existsSync10(
|
|
11651
|
+
async function loadCache(path48) {
|
|
11652
|
+
if (!existsSync10(path48)) return { version: 1, hashes: {} };
|
|
11426
11653
|
try {
|
|
11427
|
-
const parsed = HashCacheSchema.safeParse(JSON.parse(await readFile8(
|
|
11654
|
+
const parsed = HashCacheSchema.safeParse(JSON.parse(await readFile8(path48, "utf8")));
|
|
11428
11655
|
if (!parsed.success) return { version: 1, hashes: {} };
|
|
11429
11656
|
return {
|
|
11430
11657
|
version: 1,
|
|
@@ -11436,18 +11663,18 @@ async function loadCache(path47) {
|
|
|
11436
11663
|
return { version: 1, hashes: {} };
|
|
11437
11664
|
}
|
|
11438
11665
|
}
|
|
11439
|
-
async function saveCache(
|
|
11666
|
+
async function saveCache(path48, cache) {
|
|
11440
11667
|
const sorted = {};
|
|
11441
11668
|
for (const key of Object.keys(cache.hashes).sort()) {
|
|
11442
11669
|
const hash = cache.hashes[key];
|
|
11443
11670
|
if (!isSha256Hash(hash)) throw new Error(`Refusing to cache invalid SHA-256 for ${key}`);
|
|
11444
11671
|
sorted[key] = hash;
|
|
11445
11672
|
}
|
|
11446
|
-
await mkdir5(pathModule.dirname(pathModule.resolve(
|
|
11447
|
-
const tmp = `${
|
|
11673
|
+
await mkdir5(pathModule.dirname(pathModule.resolve(path48)), { recursive: true });
|
|
11674
|
+
const tmp = `${path48}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
11448
11675
|
try {
|
|
11449
11676
|
await writeFile5(tmp, JSON.stringify({ version: 1, hashes: sorted }, null, 2) + "\n");
|
|
11450
|
-
await rename5(tmp,
|
|
11677
|
+
await rename5(tmp, path48);
|
|
11451
11678
|
} finally {
|
|
11452
11679
|
await rm5(tmp, { force: true });
|
|
11453
11680
|
}
|
|
@@ -12205,20 +12432,20 @@ async function applyTags(provider, decisions, existing, opts = {}) {
|
|
|
12205
12432
|
import { mkdir as mkdir7, readFile as readFile12, rename as rename6, rm as rm6, writeFile as writeFile8 } from "fs/promises";
|
|
12206
12433
|
import { existsSync as existsSync14 } from "fs";
|
|
12207
12434
|
import path18 from "path";
|
|
12208
|
-
import { z as
|
|
12209
|
-
var WorkspaceProjectSchema =
|
|
12210
|
-
id:
|
|
12435
|
+
import { z as z5 } from "zod";
|
|
12436
|
+
var WorkspaceProjectSchema = z5.object({
|
|
12437
|
+
id: z5.string().min(1),
|
|
12211
12438
|
/** Manifest path, relative to the catalog file's own directory. */
|
|
12212
|
-
manifest:
|
|
12439
|
+
manifest: z5.string().min(1),
|
|
12213
12440
|
/** Lockfile path, relative to the catalog file's own directory. */
|
|
12214
|
-
lock:
|
|
12215
|
-
provider:
|
|
12441
|
+
lock: z5.string().min(1),
|
|
12442
|
+
provider: z5.string().min(1).default("pixellab"),
|
|
12216
12443
|
/** Free-form label for a shared account, e.g. distinguishing sandboxes. */
|
|
12217
|
-
account:
|
|
12444
|
+
account: z5.string().optional()
|
|
12218
12445
|
}).strict();
|
|
12219
|
-
var WorkspaceSchema =
|
|
12220
|
-
version:
|
|
12221
|
-
projects:
|
|
12446
|
+
var WorkspaceSchema = z5.object({
|
|
12447
|
+
version: z5.literal(1),
|
|
12448
|
+
projects: z5.array(WorkspaceProjectSchema).default([])
|
|
12222
12449
|
}).strict();
|
|
12223
12450
|
function parseWorkspace(raw) {
|
|
12224
12451
|
const parsed = WorkspaceSchema.safeParse(raw);
|
|
@@ -13403,62 +13630,62 @@ import path25 from "path";
|
|
|
13403
13630
|
import { existsSync as existsSync17 } from "fs";
|
|
13404
13631
|
import { copyFile, mkdir as mkdir9, readFile as readFile16, rename as rename8, rm as rm8, writeFile as writeFile11 } from "fs/promises";
|
|
13405
13632
|
import path24 from "path";
|
|
13406
|
-
import { z as
|
|
13633
|
+
import { z as z7 } from "zod";
|
|
13407
13634
|
|
|
13408
13635
|
// src/manifest-edit.ts
|
|
13409
13636
|
import { readFile as readFile15, rename as rename7, rm as rm7, writeFile as writeFile10 } from "fs/promises";
|
|
13410
13637
|
import path23 from "path";
|
|
13411
|
-
import { z as
|
|
13412
|
-
var HexSha =
|
|
13413
|
-
var AssetPatchSchema =
|
|
13414
|
-
prompt:
|
|
13638
|
+
import { z as z6 } from "zod";
|
|
13639
|
+
var HexSha = z6.string().regex(/^[0-9a-f]{64}$/);
|
|
13640
|
+
var AssetPatchSchema = z6.object({
|
|
13641
|
+
prompt: z6.string().optional(),
|
|
13415
13642
|
/** Per-style override for the style being viewed; null removes it. */
|
|
13416
|
-
promptForStyle:
|
|
13417
|
-
category:
|
|
13418
|
-
width:
|
|
13419
|
-
height:
|
|
13420
|
-
size:
|
|
13421
|
-
tags:
|
|
13643
|
+
promptForStyle: z6.object({ styleId: z6.string().min(1), prompt: z6.string().nullable() }).optional(),
|
|
13644
|
+
category: z6.string().nullable().optional(),
|
|
13645
|
+
width: z6.number().int().nullable().optional(),
|
|
13646
|
+
height: z6.number().int().nullable().optional(),
|
|
13647
|
+
size: z6.number().int().nullable().optional(),
|
|
13648
|
+
tags: z6.array(z6.string()).optional()
|
|
13422
13649
|
}).strict();
|
|
13423
|
-
var NewStateSchema =
|
|
13650
|
+
var NewStateSchema = z6.object({
|
|
13424
13651
|
/** Asset id of the parent this states; must already exist. */
|
|
13425
|
-
of:
|
|
13426
|
-
paletteFromReference:
|
|
13427
|
-
canvas:
|
|
13652
|
+
of: z6.string().min(1),
|
|
13653
|
+
paletteFromReference: z6.boolean().optional(),
|
|
13654
|
+
canvas: z6.object({ width: z6.number().int().min(16).max(256), height: z6.number().int().min(16).max(256) }).strict().optional()
|
|
13428
13655
|
}).strict();
|
|
13429
|
-
var NewAnimationSchema =
|
|
13656
|
+
var NewAnimationSchema = z6.object({
|
|
13430
13657
|
/** Asset id of the parent this animates; must already exist. */
|
|
13431
|
-
of:
|
|
13658
|
+
of: z6.string().min(1),
|
|
13432
13659
|
/** A PixelLab template id (`character` only; `objectPro` has no template concept). */
|
|
13433
|
-
template:
|
|
13660
|
+
template: z6.string().min(1).optional(),
|
|
13434
13661
|
direction: CharacterDirectionSchema.optional(),
|
|
13435
|
-
frames:
|
|
13436
|
-
fps:
|
|
13662
|
+
frames: z6.number().int().min(4).max(16).optional(),
|
|
13663
|
+
fps: z6.number().int().min(1).max(60).optional(),
|
|
13437
13664
|
mode: CharacterAnimationModeSchema.optional(),
|
|
13438
13665
|
/** What is being animated, when the parent's own description would mislead the model (`character` only). */
|
|
13439
|
-
subject:
|
|
13440
|
-
enhancePrompt:
|
|
13666
|
+
subject: z6.string().min(1).optional(),
|
|
13667
|
+
enhancePrompt: z6.boolean().optional()
|
|
13441
13668
|
}).strict();
|
|
13442
|
-
var NewAssetSchema =
|
|
13443
|
-
prompt:
|
|
13444
|
-
category:
|
|
13445
|
-
width:
|
|
13446
|
-
height:
|
|
13447
|
-
size:
|
|
13448
|
-
tags:
|
|
13669
|
+
var NewAssetSchema = z6.object({
|
|
13670
|
+
prompt: z6.string(),
|
|
13671
|
+
category: z6.string().optional(),
|
|
13672
|
+
width: z6.number().int().optional(),
|
|
13673
|
+
height: z6.number().int().optional(),
|
|
13674
|
+
size: z6.number().int().optional(),
|
|
13675
|
+
tags: z6.array(z6.string()).optional(),
|
|
13449
13676
|
/** Restrict to these styles; empty or omitted means every style. */
|
|
13450
|
-
styles:
|
|
13677
|
+
styles: z6.array(z6.string().min(1)).optional(),
|
|
13451
13678
|
/**
|
|
13452
13679
|
* A controlled regeneration of another asset in the same manifest,
|
|
13453
13680
|
* instead of a fresh generation. `inpaint` needs a mask upload the
|
|
13454
13681
|
* gallery does not offer yet, so only `image-to-image` can be created
|
|
13455
13682
|
* here; hand-edit the manifest for the other modes.
|
|
13456
13683
|
*/
|
|
13457
|
-
revision:
|
|
13458
|
-
mode:
|
|
13684
|
+
revision: z6.object({
|
|
13685
|
+
mode: z6.literal("image-to-image"),
|
|
13459
13686
|
/** Asset id of the parent this revises; must already exist. */
|
|
13460
|
-
from:
|
|
13461
|
-
strength:
|
|
13687
|
+
from: z6.string().min(1),
|
|
13688
|
+
strength: z6.number().min(0).max(1).optional()
|
|
13462
13689
|
}).strict().optional(),
|
|
13463
13690
|
/** A pose or outfit of an existing `character`/`objectPro` base or state. */
|
|
13464
13691
|
state: NewStateSchema.optional(),
|
|
@@ -13474,58 +13701,58 @@ var CANDIDATE_OPTION = {
|
|
|
13474
13701
|
comfyui: "numImages",
|
|
13475
13702
|
scenario: "numOutputs"
|
|
13476
13703
|
};
|
|
13477
|
-
var ManifestEditSchema =
|
|
13478
|
-
|
|
13479
|
-
action:
|
|
13704
|
+
var ManifestEditSchema = z6.discriminatedUnion("action", [
|
|
13705
|
+
z6.object({
|
|
13706
|
+
action: z6.literal("patch-asset"),
|
|
13480
13707
|
/** Workspace project id; omitted for a single-project gallery. */
|
|
13481
|
-
project:
|
|
13482
|
-
assetId:
|
|
13708
|
+
project: z6.string().min(1).optional(),
|
|
13709
|
+
assetId: z6.string().min(1),
|
|
13483
13710
|
/** Manifest bytes the page last saw; a mismatch refuses the write. */
|
|
13484
13711
|
expectedSha256: HexSha,
|
|
13485
13712
|
patch: AssetPatchSchema
|
|
13486
13713
|
}).strict(),
|
|
13487
|
-
|
|
13488
|
-
action:
|
|
13489
|
-
project:
|
|
13490
|
-
assetId:
|
|
13714
|
+
z6.object({
|
|
13715
|
+
action: z6.literal("add-asset"),
|
|
13716
|
+
project: z6.string().min(1).optional(),
|
|
13717
|
+
assetId: z6.string().min(1).regex(/^[^/\\]+$/, "asset ids cannot contain slashes"),
|
|
13491
13718
|
expectedSha256: HexSha,
|
|
13492
13719
|
asset: NewAssetSchema
|
|
13493
13720
|
}).strict(),
|
|
13494
|
-
|
|
13495
|
-
action:
|
|
13496
|
-
project:
|
|
13497
|
-
assetId:
|
|
13498
|
-
styleId:
|
|
13721
|
+
z6.object({
|
|
13722
|
+
action: z6.literal("set-source"),
|
|
13723
|
+
project: z6.string().min(1).optional(),
|
|
13724
|
+
assetId: z6.string().min(1),
|
|
13725
|
+
styleId: z6.string().min(1),
|
|
13499
13726
|
/** Manifest-relative path of the art that stands in for this asset in this style. */
|
|
13500
|
-
source:
|
|
13727
|
+
source: z6.string().min(1),
|
|
13501
13728
|
expectedSha256: HexSha
|
|
13502
13729
|
}).strict(),
|
|
13503
|
-
|
|
13504
|
-
action:
|
|
13505
|
-
project:
|
|
13506
|
-
assetId:
|
|
13507
|
-
styleId:
|
|
13730
|
+
z6.object({
|
|
13731
|
+
action: z6.literal("clear-source"),
|
|
13732
|
+
project: z6.string().min(1).optional(),
|
|
13733
|
+
assetId: z6.string().min(1),
|
|
13734
|
+
styleId: z6.string().min(1),
|
|
13508
13735
|
expectedSha256: HexSha
|
|
13509
13736
|
}).strict(),
|
|
13510
|
-
|
|
13511
|
-
action:
|
|
13512
|
-
project:
|
|
13513
|
-
styleId:
|
|
13737
|
+
z6.object({
|
|
13738
|
+
action: z6.literal("patch-style"),
|
|
13739
|
+
project: z6.string().min(1).optional(),
|
|
13740
|
+
styleId: z6.string().min(1),
|
|
13514
13741
|
expectedSha256: HexSha,
|
|
13515
|
-
patch:
|
|
13742
|
+
patch: z6.object({
|
|
13516
13743
|
/** Candidates per generation, written to the provider's own option. */
|
|
13517
|
-
candidates:
|
|
13744
|
+
candidates: z6.number().int().min(1).max(64).optional(),
|
|
13518
13745
|
/** Empty clears the style's own value (inherit, or the default). */
|
|
13519
|
-
promptPrefix:
|
|
13520
|
-
promptSuffix:
|
|
13746
|
+
promptPrefix: z6.string().optional(),
|
|
13747
|
+
promptSuffix: z6.string().optional(),
|
|
13521
13748
|
/** `#rrggbb` values; null or empty clears the style's own palette. */
|
|
13522
|
-
palette:
|
|
13749
|
+
palette: z6.array(z6.string().regex(/^#?[0-9a-f]{6}$/i, "expected a six-digit hex colour")).max(256).nullable().optional(),
|
|
13523
13750
|
/** Snap downloaded art to the palette; false clears the style's own value. */
|
|
13524
|
-
enforcePalette:
|
|
13751
|
+
enforcePalette: z6.boolean().optional(),
|
|
13525
13752
|
/** Provider view name (PixelLab: low top-down, high top-down, side); empty clears. */
|
|
13526
|
-
view:
|
|
13753
|
+
view: z6.string().max(64).nullable().optional(),
|
|
13527
13754
|
/** pixflux only; null clears the style's own value. */
|
|
13528
|
-
noBackground:
|
|
13755
|
+
noBackground: z6.boolean().nullable().optional()
|
|
13529
13756
|
}).strict().refine((patch) => Object.keys(patch).length > 0, { message: "nothing to change" })
|
|
13530
13757
|
}).strict()
|
|
13531
13758
|
]);
|
|
@@ -13808,35 +14035,35 @@ async function detachHandEdit(loaded, spec, opts = {}) {
|
|
|
13808
14035
|
});
|
|
13809
14036
|
return { manifestSha256: result.sha256, changed: result.changed };
|
|
13810
14037
|
}
|
|
13811
|
-
var CompanionOutputSchema =
|
|
14038
|
+
var CompanionOutputSchema = z7.object({
|
|
13812
14039
|
/** Output role for a set member; null for a single image. */
|
|
13813
|
-
role:
|
|
14040
|
+
role: z7.string().nullable(),
|
|
13814
14041
|
/** sha256 of the generated file this member started from; null when it started from untracked art. */
|
|
13815
|
-
basedOn:
|
|
14042
|
+
basedOn: z7.string().regex(/^[0-9a-f]{64}$/).nullable(),
|
|
13816
14043
|
/** sha256 of the member as saved, so a later change by another tool is visible. */
|
|
13817
|
-
sha256:
|
|
14044
|
+
sha256: z7.string().regex(/^[0-9a-f]{64}$/)
|
|
13818
14045
|
}).strict();
|
|
13819
|
-
var CompanionV2Schema =
|
|
13820
|
-
version:
|
|
14046
|
+
var CompanionV2Schema = z7.object({
|
|
14047
|
+
version: z7.literal(2),
|
|
13821
14048
|
/** Editor identity the bridge reported, e.g. `pixelorama@v1.2.2-stable`. */
|
|
13822
|
-
editor:
|
|
13823
|
-
protocol:
|
|
13824
|
-
savedAt:
|
|
14049
|
+
editor: z7.string().min(1),
|
|
14050
|
+
protocol: z7.number().int().positive(),
|
|
14051
|
+
savedAt: z7.string().datetime(),
|
|
13825
14052
|
/** Basename of the layered project file beside the edit, when one was kept. */
|
|
13826
|
-
project:
|
|
14053
|
+
project: z7.string().min(1).nullable(),
|
|
13827
14054
|
/** One entry per file, in output order. */
|
|
13828
|
-
outputs:
|
|
14055
|
+
outputs: z7.array(CompanionOutputSchema).min(1)
|
|
13829
14056
|
}).strict();
|
|
13830
|
-
var CompanionV1Schema =
|
|
13831
|
-
version:
|
|
13832
|
-
basedOn:
|
|
13833
|
-
sha256:
|
|
13834
|
-
editor:
|
|
13835
|
-
protocol:
|
|
13836
|
-
savedAt:
|
|
13837
|
-
project:
|
|
14057
|
+
var CompanionV1Schema = z7.object({
|
|
14058
|
+
version: z7.literal(1),
|
|
14059
|
+
basedOn: z7.string().regex(/^[0-9a-f]{64}$/).nullable(),
|
|
14060
|
+
sha256: z7.string().regex(/^[0-9a-f]{64}$/),
|
|
14061
|
+
editor: z7.string().min(1),
|
|
14062
|
+
protocol: z7.number().int().positive(),
|
|
14063
|
+
savedAt: z7.string().datetime(),
|
|
14064
|
+
project: z7.string().min(1).nullable()
|
|
13838
14065
|
}).strict();
|
|
13839
|
-
var HandEditCompanionSchema =
|
|
14066
|
+
var HandEditCompanionSchema = z7.union([CompanionV2Schema, CompanionV1Schema]).transform(
|
|
13840
14067
|
(value) => value.version === 2 ? value : {
|
|
13841
14068
|
version: 2,
|
|
13842
14069
|
editor: value.editor,
|
|
@@ -13995,41 +14222,41 @@ import path28 from "path";
|
|
|
13995
14222
|
|
|
13996
14223
|
// src/gallery/edit.ts
|
|
13997
14224
|
import path26 from "path";
|
|
13998
|
-
import { z as
|
|
13999
|
-
var Base64 =
|
|
14000
|
-
var HandEditRequestSchema =
|
|
14001
|
-
|
|
14002
|
-
action:
|
|
14003
|
-
project:
|
|
14004
|
-
assetId:
|
|
14005
|
-
styleId:
|
|
14006
|
-
expectedSha256:
|
|
14225
|
+
import { z as z8 } from "zod";
|
|
14226
|
+
var Base64 = z8.string().regex(/^[A-Za-z0-9+/]*={0,2}$/).max(Math.ceil(MAX_HAND_EDIT_BYTES / 3) * 4);
|
|
14227
|
+
var HandEditRequestSchema = z8.discriminatedUnion("action", [
|
|
14228
|
+
z8.object({
|
|
14229
|
+
action: z8.literal("start-edit"),
|
|
14230
|
+
project: z8.string().min(1).optional(),
|
|
14231
|
+
assetId: z8.string().min(1),
|
|
14232
|
+
styleId: z8.string().min(1),
|
|
14233
|
+
expectedSha256: z8.string().regex(/^[0-9a-f]{64}$/),
|
|
14007
14234
|
/** Also launch the author's editor on the file. */
|
|
14008
|
-
open:
|
|
14235
|
+
open: z8.boolean().optional()
|
|
14009
14236
|
}).strict(),
|
|
14010
|
-
|
|
14011
|
-
action:
|
|
14012
|
-
project:
|
|
14013
|
-
assetId:
|
|
14014
|
-
styleId:
|
|
14015
|
-
expectedSha256:
|
|
14237
|
+
z8.object({
|
|
14238
|
+
action: z8.literal("detach-edit"),
|
|
14239
|
+
project: z8.string().min(1).optional(),
|
|
14240
|
+
assetId: z8.string().min(1),
|
|
14241
|
+
styleId: z8.string().min(1),
|
|
14242
|
+
expectedSha256: z8.string().regex(/^[0-9a-f]{64}$/)
|
|
14016
14243
|
}).strict(),
|
|
14017
14244
|
/** From the in-browser editor: the page holds the bytes, the server validates and writes. */
|
|
14018
|
-
|
|
14019
|
-
action:
|
|
14020
|
-
project:
|
|
14021
|
-
assetId:
|
|
14022
|
-
styleId:
|
|
14023
|
-
expectedSha256:
|
|
14245
|
+
z8.object({
|
|
14246
|
+
action: z8.literal("save-edit"),
|
|
14247
|
+
project: z8.string().min(1).optional(),
|
|
14248
|
+
assetId: z8.string().min(1),
|
|
14249
|
+
styleId: z8.string().min(1),
|
|
14250
|
+
expectedSha256: z8.string().regex(/^[0-9a-f]{64}$/),
|
|
14024
14251
|
/** The flattened image; for a frame set, `frames` instead. */
|
|
14025
14252
|
png: Base64.min(1).optional(),
|
|
14026
14253
|
/** Every frame of a set, tagged with the role it was opened under (null for one added in the editor). */
|
|
14027
|
-
frames:
|
|
14254
|
+
frames: z8.array(z8.object({ role: z8.string().min(1).nullable(), png: Base64.min(1) }).strict()).min(1).max(256).optional(),
|
|
14028
14255
|
/** The editor's layered project file, kept beside the edit. */
|
|
14029
14256
|
pxo: Base64.optional(),
|
|
14030
14257
|
/** Editor identity from the bridge's ready message. */
|
|
14031
|
-
editor:
|
|
14032
|
-
protocol:
|
|
14258
|
+
editor: z8.string().min(1).max(200),
|
|
14259
|
+
protocol: z8.number().int().positive()
|
|
14033
14260
|
}).strict()
|
|
14034
14261
|
]);
|
|
14035
14262
|
function createGalleryEditHandler(opts) {
|
|
@@ -15213,7 +15440,7 @@ async function serveGallery(opts) {
|
|
|
15213
15440
|
|
|
15214
15441
|
// src/gallery/generate.ts
|
|
15215
15442
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
15216
|
-
import { z as
|
|
15443
|
+
import { z as z9 } from "zod";
|
|
15217
15444
|
|
|
15218
15445
|
// src/pipeline/poll.ts
|
|
15219
15446
|
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
@@ -15494,6 +15721,9 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
|
|
|
15494
15721
|
...spec.revision.lastFrameSha256 ? { lastFrameSha256: spec.revision.lastFrameSha256 } : {},
|
|
15495
15722
|
...spec.revision.direction ? { direction: spec.revision.direction } : {},
|
|
15496
15723
|
...spec.revision.enhancePrompt == null ? {} : { enhancePrompt: spec.revision.enhancePrompt },
|
|
15724
|
+
...spec.revision.keypointsSha256 ? { keypointsSha256: spec.revision.keypointsSha256 } : {},
|
|
15725
|
+
...spec.revision.skeletonTemplate ? { skeletonTemplate: spec.revision.skeletonTemplate } : {},
|
|
15726
|
+
...spec.revision.description ? { description: spec.revision.description } : {},
|
|
15497
15727
|
...spec.revision.engine ? { engine: spec.revision.engine } : {}
|
|
15498
15728
|
} : null,
|
|
15499
15729
|
outfit: spec.character?.kind === "outfit" && outfitParentEntry ? {
|
|
@@ -16310,26 +16540,26 @@ async function runPicker(provider, lock, lockPath, opts = {}) {
|
|
|
16310
16540
|
}
|
|
16311
16541
|
|
|
16312
16542
|
// src/gallery/generate.ts
|
|
16313
|
-
var GenerateRequestSchema =
|
|
16314
|
-
project:
|
|
16315
|
-
keys:
|
|
16543
|
+
var GenerateRequestSchema = z9.object({
|
|
16544
|
+
project: z9.string().min(1).optional(),
|
|
16545
|
+
keys: z9.array(z9.string().min(1)).min(1).max(500),
|
|
16316
16546
|
/**
|
|
16317
16547
|
* Regenerate work that is up to date, as `gen --force` does, and let the
|
|
16318
16548
|
* fetch replace a locally modified or untracked file. With `restore`, put
|
|
16319
16549
|
* the recorded bytes back over a modified file.
|
|
16320
16550
|
*/
|
|
16321
|
-
force:
|
|
16551
|
+
force: z9.boolean().optional(),
|
|
16322
16552
|
/** Advance in-flight, review, or selected work without submitting anything. */
|
|
16323
|
-
resume:
|
|
16553
|
+
resume: z9.boolean().optional(),
|
|
16324
16554
|
/** Re-download downloaded outputs and replace files whose object changed upstream. */
|
|
16325
|
-
refresh:
|
|
16555
|
+
refresh: z9.boolean().optional(),
|
|
16326
16556
|
/** Put recorded outputs back on disk from the cache or the provider, without generating. */
|
|
16327
|
-
restore:
|
|
16557
|
+
restore: z9.boolean().optional(),
|
|
16328
16558
|
/**
|
|
16329
16559
|
* Bring a replaced generation back: 1-based position in the record's
|
|
16330
16560
|
* history (newest first) or an output hash prefix. One key at a time.
|
|
16331
16561
|
*/
|
|
16332
|
-
revert:
|
|
16562
|
+
revert: z9.string().min(1).max(64).optional()
|
|
16333
16563
|
}).strict().refine((request) => [request.resume, request.refresh, request.restore, request.revert !== void 0].filter(Boolean).length <= 1, {
|
|
16334
16564
|
message: "resume, refresh, restore, and revert are exclusive"
|
|
16335
16565
|
}).refine((request) => request.revert === void 0 || request.keys.length === 1, { message: "revert takes one key" });
|
|
@@ -19215,11 +19445,11 @@ import { readFile as readFile28 } from "fs/promises";
|
|
|
19215
19445
|
import path41 from "path";
|
|
19216
19446
|
import { existsSync as existsSync30 } from "fs";
|
|
19217
19447
|
import { readFile as readFile27 } from "fs/promises";
|
|
19218
|
-
import { z as
|
|
19448
|
+
import { z as z10 } from "zod";
|
|
19219
19449
|
var SHA256_RE = /^[0-9a-f]{64}$/;
|
|
19220
19450
|
var HEX_RE = /^#[0-9a-f]{6}$/;
|
|
19221
19451
|
var MAX_REDMEAN_DISTANCE = 765;
|
|
19222
|
-
var QualityPathSchema =
|
|
19452
|
+
var QualityPathSchema = z10.string().min(1).refine(
|
|
19223
19453
|
(value) => !path41.posix.isAbsolute(value) && !value.includes("\\"),
|
|
19224
19454
|
"expected a portable relative path"
|
|
19225
19455
|
);
|
|
@@ -19233,53 +19463,53 @@ var DEFAULT_QUALITY_TOLERANCES = {
|
|
|
19233
19463
|
maxEdgeContrastDrop: 0.03,
|
|
19234
19464
|
maxIsolatedPixelIncrease: 5e-3
|
|
19235
19465
|
};
|
|
19236
|
-
var QualityToleranceSchema =
|
|
19237
|
-
requireExactHash:
|
|
19238
|
-
maxColorCountIncrease:
|
|
19239
|
-
maxNewColors:
|
|
19240
|
-
maxTransparencyDelta:
|
|
19241
|
-
maxPartialAlphaIncrease:
|
|
19242
|
-
maxEdgeDensityDelta:
|
|
19243
|
-
maxEdgeContrastDrop:
|
|
19244
|
-
maxIsolatedPixelIncrease:
|
|
19466
|
+
var QualityToleranceSchema = z10.object({
|
|
19467
|
+
requireExactHash: z10.boolean(),
|
|
19468
|
+
maxColorCountIncrease: z10.number().int().min(0),
|
|
19469
|
+
maxNewColors: z10.number().int().min(0),
|
|
19470
|
+
maxTransparencyDelta: z10.number().min(0).max(1),
|
|
19471
|
+
maxPartialAlphaIncrease: z10.number().min(0).max(1),
|
|
19472
|
+
maxEdgeDensityDelta: z10.number().min(0).max(1),
|
|
19473
|
+
maxEdgeContrastDrop: z10.number().min(0).max(1),
|
|
19474
|
+
maxIsolatedPixelIncrease: z10.number().min(0).max(1)
|
|
19245
19475
|
}).strict();
|
|
19246
|
-
var ImageQualityMetricsSchema =
|
|
19247
|
-
sha256:
|
|
19248
|
-
width:
|
|
19249
|
-
height:
|
|
19250
|
-
colorCount:
|
|
19251
|
-
colors:
|
|
19252
|
-
transparency:
|
|
19253
|
-
partialAlpha:
|
|
19254
|
-
edgeDensity:
|
|
19255
|
-
meanEdgeContrast:
|
|
19256
|
-
isolatedPixelRatio:
|
|
19476
|
+
var ImageQualityMetricsSchema = z10.object({
|
|
19477
|
+
sha256: z10.string().regex(SHA256_RE),
|
|
19478
|
+
width: z10.number().int().min(1),
|
|
19479
|
+
height: z10.number().int().min(1),
|
|
19480
|
+
colorCount: z10.number().int().min(0),
|
|
19481
|
+
colors: z10.array(z10.string().regex(HEX_RE)),
|
|
19482
|
+
transparency: z10.number().min(0).max(1),
|
|
19483
|
+
partialAlpha: z10.number().min(0).max(1),
|
|
19484
|
+
edgeDensity: z10.number().min(0).max(1),
|
|
19485
|
+
meanEdgeContrast: z10.number().min(0).max(1),
|
|
19486
|
+
isolatedPixelRatio: z10.number().min(0).max(1)
|
|
19257
19487
|
}).strict();
|
|
19258
|
-
var QualityBaselineCaseSchema =
|
|
19259
|
-
id:
|
|
19488
|
+
var QualityBaselineCaseSchema = z10.object({
|
|
19489
|
+
id: z10.string().regex(/^[a-z0-9][a-z0-9/_-]*$/),
|
|
19260
19490
|
file: QualityPathSchema,
|
|
19261
|
-
record:
|
|
19491
|
+
record: z10.object({
|
|
19262
19492
|
path: QualityPathSchema,
|
|
19263
|
-
sha256:
|
|
19493
|
+
sha256: z10.string().regex(SHA256_RE)
|
|
19264
19494
|
}).strict().optional(),
|
|
19265
19495
|
expected: ImageQualityMetricsSchema,
|
|
19266
19496
|
tolerances: QualityToleranceSchema
|
|
19267
19497
|
}).strict();
|
|
19268
|
-
var QualityBaselineSchema =
|
|
19269
|
-
$schema:
|
|
19270
|
-
format:
|
|
19271
|
-
schemaVersion:
|
|
19272
|
-
cases:
|
|
19498
|
+
var QualityBaselineSchema = z10.object({
|
|
19499
|
+
$schema: z10.string().url().optional(),
|
|
19500
|
+
format: z10.literal("pixelkiln-quality-baseline"),
|
|
19501
|
+
schemaVersion: z10.literal(1),
|
|
19502
|
+
cases: z10.array(QualityBaselineCaseSchema).min(1)
|
|
19273
19503
|
}).strict().superRefine((baseline, context) => {
|
|
19274
19504
|
const ids = baseline.cases.map((entry) => entry.id);
|
|
19275
19505
|
if (new Set(ids).size !== ids.length) {
|
|
19276
|
-
context.addIssue({ code:
|
|
19506
|
+
context.addIssue({ code: z10.ZodIssueCode.custom, path: ["cases"], message: "duplicate case id" });
|
|
19277
19507
|
}
|
|
19278
19508
|
});
|
|
19279
|
-
var QualityInputSchema =
|
|
19280
|
-
id:
|
|
19281
|
-
path:
|
|
19282
|
-
record:
|
|
19509
|
+
var QualityInputSchema = z10.object({
|
|
19510
|
+
id: z10.string().regex(/^[a-z0-9][a-z0-9/_-]*$/),
|
|
19511
|
+
path: z10.string().min(1),
|
|
19512
|
+
record: z10.string().min(1).optional(),
|
|
19283
19513
|
tolerances: QualityToleranceSchema.partial().optional()
|
|
19284
19514
|
}).strict();
|
|
19285
19515
|
function message4(error) {
|
|
@@ -19381,7 +19611,7 @@ async function measureImageQuality(file) {
|
|
|
19381
19611
|
}
|
|
19382
19612
|
}
|
|
19383
19613
|
function resolveQualityInputs(raw, inputsFilePath) {
|
|
19384
|
-
const parsed =
|
|
19614
|
+
const parsed = z10.array(QualityInputSchema).min(1).safeParse(raw);
|
|
19385
19615
|
if (!parsed.success) {
|
|
19386
19616
|
throw new Error(
|
|
19387
19617
|
"--inputs must be a non-empty JSON array of quality cases:\n" + parsed.error.issues.map((issue) => ` ${issue.path.join(".") || "$"}: ${issue.message}`).join("\n")
|
|
@@ -19656,47 +19886,47 @@ import path43 from "path";
|
|
|
19656
19886
|
import { existsSync as existsSync31 } from "fs";
|
|
19657
19887
|
import { readdir as readdir3, readFile as readFile29 } from "fs/promises";
|
|
19658
19888
|
import { fileURLToPath } from "url";
|
|
19659
|
-
import { z as
|
|
19889
|
+
import { z as z11 } from "zod";
|
|
19660
19890
|
var SHA256_RE2 = /^[0-9a-f]{64}$/;
|
|
19661
19891
|
var RECIPE_ID_RE = /^[a-z0-9][a-z0-9-]*\/[a-z0-9][a-z0-9-]*$/;
|
|
19662
19892
|
var VERSION_RE = /^\d+\.\d+\.\d+$/;
|
|
19663
19893
|
var RECIPE_FILE = "pixelkiln.recipe.json";
|
|
19664
19894
|
var RECIPE_DIR_TOKEN = "{{recipeDir}}";
|
|
19665
|
-
var PortablePathSchema =
|
|
19895
|
+
var PortablePathSchema = z11.string().min(1).refine((value) => {
|
|
19666
19896
|
if (value.includes("\\") || path43.posix.isAbsolute(value)) return false;
|
|
19667
19897
|
const parts = value.split("/");
|
|
19668
19898
|
return !parts.includes("") && !parts.includes(".") && !parts.includes("..");
|
|
19669
19899
|
}, "expected a portable relative path without '.', '..', or backslashes");
|
|
19670
|
-
var RecipeBindingSchema =
|
|
19671
|
-
nodeId:
|
|
19672
|
-
input:
|
|
19900
|
+
var RecipeBindingSchema = z11.object({
|
|
19901
|
+
nodeId: z11.string().min(1),
|
|
19902
|
+
input: z11.string().min(1)
|
|
19673
19903
|
}).strict();
|
|
19674
|
-
var RecipeSchema =
|
|
19675
|
-
$schema:
|
|
19676
|
-
format:
|
|
19677
|
-
schemaVersion:
|
|
19678
|
-
id:
|
|
19679
|
-
version:
|
|
19680
|
-
provider:
|
|
19681
|
-
summary:
|
|
19682
|
-
files:
|
|
19904
|
+
var RecipeSchema = z11.object({
|
|
19905
|
+
$schema: z11.string().url().optional(),
|
|
19906
|
+
format: z11.literal("pixelkiln-recipe"),
|
|
19907
|
+
schemaVersion: z11.literal(1),
|
|
19908
|
+
id: z11.string().regex(RECIPE_ID_RE, "expected provider/name"),
|
|
19909
|
+
version: z11.string().regex(VERSION_RE, "expected x.y.z"),
|
|
19910
|
+
provider: z11.string().regex(/^[a-z0-9][a-z0-9-]*$/),
|
|
19911
|
+
summary: z11.string().min(1).max(240),
|
|
19912
|
+
files: z11.array(z11.object({
|
|
19683
19913
|
path: PortablePathSchema,
|
|
19684
|
-
role:
|
|
19685
|
-
sha256:
|
|
19914
|
+
role: z11.enum(["workflow", "reference"]),
|
|
19915
|
+
sha256: z11.string().regex(SHA256_RE2)
|
|
19686
19916
|
}).strict()).default([]),
|
|
19687
|
-
models:
|
|
19917
|
+
models: z11.array(z11.object({
|
|
19688
19918
|
path: PortablePathSchema,
|
|
19689
|
-
sha256:
|
|
19690
|
-
source:
|
|
19691
|
-
license:
|
|
19919
|
+
sha256: z11.string().regex(SHA256_RE2),
|
|
19920
|
+
source: z11.string().url(),
|
|
19921
|
+
license: z11.string().min(1)
|
|
19692
19922
|
}).strict()).default([]),
|
|
19693
|
-
styleId:
|
|
19923
|
+
styleId: z11.string().regex(/^[a-z0-9][a-z0-9-]*$/),
|
|
19694
19924
|
style: StyleSchema,
|
|
19695
|
-
workflow:
|
|
19925
|
+
workflow: z11.object({
|
|
19696
19926
|
path: PortablePathSchema,
|
|
19697
|
-
outputNodeId:
|
|
19698
|
-
numImages:
|
|
19699
|
-
bindings:
|
|
19927
|
+
outputNodeId: z11.string().min(1),
|
|
19928
|
+
numImages: z11.number().int().min(1).max(16),
|
|
19929
|
+
bindings: z11.object({
|
|
19700
19930
|
prompt: RecipeBindingSchema,
|
|
19701
19931
|
width: RecipeBindingSchema.optional(),
|
|
19702
19932
|
height: RecipeBindingSchema.optional(),
|
|
@@ -19707,67 +19937,67 @@ var RecipeSchema = z10.object({
|
|
|
19707
19937
|
strength: RecipeBindingSchema.optional()
|
|
19708
19938
|
}).strict()
|
|
19709
19939
|
}).strict().optional(),
|
|
19710
|
-
quality:
|
|
19711
|
-
stage:
|
|
19712
|
-
workingCanvas:
|
|
19713
|
-
width:
|
|
19714
|
-
height:
|
|
19940
|
+
quality: z11.object({
|
|
19941
|
+
stage: z11.enum(["composition-source", "production-candidate"]),
|
|
19942
|
+
workingCanvas: z11.object({
|
|
19943
|
+
width: z11.number().int().min(16),
|
|
19944
|
+
height: z11.number().int().min(16)
|
|
19715
19945
|
}).strict(),
|
|
19716
|
-
recommendedNativeSize:
|
|
19717
|
-
min:
|
|
19718
|
-
max:
|
|
19946
|
+
recommendedNativeSize: z11.object({
|
|
19947
|
+
min: z11.number().int().min(1),
|
|
19948
|
+
max: z11.number().int().min(1)
|
|
19719
19949
|
}).strict(),
|
|
19720
|
-
paletteColors:
|
|
19721
|
-
min:
|
|
19722
|
-
max:
|
|
19950
|
+
paletteColors: z11.object({
|
|
19951
|
+
min: z11.number().int().min(1),
|
|
19952
|
+
max: z11.number().int().min(1)
|
|
19723
19953
|
}).strict(),
|
|
19724
|
-
background:
|
|
19725
|
-
checks:
|
|
19954
|
+
background: z11.enum(["opaque", "transparent", "full-bleed"]),
|
|
19955
|
+
checks: z11.array(z11.enum([
|
|
19726
19956
|
"prompt-coverage",
|
|
19727
19957
|
"native-grid",
|
|
19728
19958
|
"final-palette",
|
|
19729
19959
|
"alpha-edge",
|
|
19730
19960
|
"human-1x"
|
|
19731
19961
|
])).min(1),
|
|
19732
|
-
notes:
|
|
19962
|
+
notes: z11.array(z11.string().min(1)).default([])
|
|
19733
19963
|
}).strict(),
|
|
19734
|
-
integrity:
|
|
19735
|
-
algorithm:
|
|
19736
|
-
digest:
|
|
19964
|
+
integrity: z11.object({
|
|
19965
|
+
algorithm: z11.literal("sha256"),
|
|
19966
|
+
digest: z11.string().regex(SHA256_RE2)
|
|
19737
19967
|
}).strict()
|
|
19738
19968
|
}).strict().superRefine((recipe, context) => {
|
|
19739
19969
|
if (recipe.style.provider && recipe.style.provider !== recipe.provider) {
|
|
19740
19970
|
context.addIssue({
|
|
19741
|
-
code:
|
|
19971
|
+
code: z11.ZodIssueCode.custom,
|
|
19742
19972
|
path: ["style", "provider"],
|
|
19743
19973
|
message: "must match the recipe provider"
|
|
19744
19974
|
});
|
|
19745
19975
|
}
|
|
19746
19976
|
const filePaths = recipe.files.map((file) => file.path);
|
|
19747
19977
|
if (new Set(filePaths).size !== filePaths.length) {
|
|
19748
|
-
context.addIssue({ code:
|
|
19978
|
+
context.addIssue({ code: z11.ZodIssueCode.custom, path: ["files"], message: "duplicate file path" });
|
|
19749
19979
|
}
|
|
19750
19980
|
const modelPaths = recipe.models.map((model) => model.path);
|
|
19751
19981
|
if (new Set(modelPaths).size !== modelPaths.length) {
|
|
19752
|
-
context.addIssue({ code:
|
|
19982
|
+
context.addIssue({ code: z11.ZodIssueCode.custom, path: ["models"], message: "duplicate model path" });
|
|
19753
19983
|
}
|
|
19754
19984
|
if (filePaths.includes(RECIPE_FILE)) {
|
|
19755
19985
|
context.addIssue({
|
|
19756
|
-
code:
|
|
19986
|
+
code: z11.ZodIssueCode.custom,
|
|
19757
19987
|
path: ["files"],
|
|
19758
19988
|
message: `${RECIPE_FILE} cannot hash itself`
|
|
19759
19989
|
});
|
|
19760
19990
|
}
|
|
19761
19991
|
if (recipe.quality.recommendedNativeSize.min > recipe.quality.recommendedNativeSize.max) {
|
|
19762
19992
|
context.addIssue({
|
|
19763
|
-
code:
|
|
19993
|
+
code: z11.ZodIssueCode.custom,
|
|
19764
19994
|
path: ["quality", "recommendedNativeSize"],
|
|
19765
19995
|
message: "min cannot exceed max"
|
|
19766
19996
|
});
|
|
19767
19997
|
}
|
|
19768
19998
|
if (recipe.quality.paletteColors.min > recipe.quality.paletteColors.max) {
|
|
19769
19999
|
context.addIssue({
|
|
19770
|
-
code:
|
|
20000
|
+
code: z11.ZodIssueCode.custom,
|
|
19771
20001
|
path: ["quality", "paletteColors"],
|
|
19772
20002
|
message: "min cannot exceed max"
|
|
19773
20003
|
});
|
|
@@ -19776,7 +20006,7 @@ var RecipeSchema = z10.object({
|
|
|
19776
20006
|
(file) => file.path === recipe.workflow.path && file.role === "workflow"
|
|
19777
20007
|
)) {
|
|
19778
20008
|
context.addIssue({
|
|
19779
|
-
code:
|
|
20009
|
+
code: z11.ZodIssueCode.custom,
|
|
19780
20010
|
path: ["workflow", "path"],
|
|
19781
20011
|
message: "must name a file whose role is workflow"
|
|
19782
20012
|
});
|
|
@@ -19784,7 +20014,7 @@ var RecipeSchema = z10.object({
|
|
|
19784
20014
|
if (recipe.provider === "comfyui") {
|
|
19785
20015
|
if (!recipe.workflow) {
|
|
19786
20016
|
context.addIssue({
|
|
19787
|
-
code:
|
|
20017
|
+
code: z11.ZodIssueCode.custom,
|
|
19788
20018
|
path: ["workflow"],
|
|
19789
20019
|
message: "ComfyUI recipes require workflow metadata"
|
|
19790
20020
|
});
|
|
@@ -19793,7 +20023,7 @@ var RecipeSchema = z10.object({
|
|
|
19793
20023
|
const options = recipe.style.providerOptions.comfyui;
|
|
19794
20024
|
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
19795
20025
|
context.addIssue({
|
|
19796
|
-
code:
|
|
20026
|
+
code: z11.ZodIssueCode.custom,
|
|
19797
20027
|
path: ["style", "providerOptions", "comfyui"],
|
|
19798
20028
|
message: "ComfyUI recipes require ComfyUI provider options"
|
|
19799
20029
|
});
|
|
@@ -19807,7 +20037,7 @@ var RecipeSchema = z10.object({
|
|
|
19807
20037
|
};
|
|
19808
20038
|
if (JSON.stringify(canonical3(options)) !== JSON.stringify(canonical3(expected))) {
|
|
19809
20039
|
context.addIssue({
|
|
19810
|
-
code:
|
|
20040
|
+
code: z11.ZodIssueCode.custom,
|
|
19811
20041
|
path: ["style", "providerOptions", "comfyui"],
|
|
19812
20042
|
message: "must match workflow metadata and use {{recipeDir}} for workflowFile"
|
|
19813
20043
|
});
|
|
@@ -20226,6 +20456,30 @@ async function runRefine(args) {
|
|
|
20226
20456
|
if (result.failed) process.exitCode = 1;
|
|
20227
20457
|
}
|
|
20228
20458
|
|
|
20459
|
+
// src/cli/commands/skeleton.ts
|
|
20460
|
+
import path46 from "path";
|
|
20461
|
+
import { readFile as readFile30, writeFile as writeFile15 } from "fs/promises";
|
|
20462
|
+
async function runEstimateSkeleton(args) {
|
|
20463
|
+
const image = args.target;
|
|
20464
|
+
if (!image) throw new UsageError("estimate-skeleton needs an image path: pixelkiln estimate-skeleton <image> [--out keypoints.json]");
|
|
20465
|
+
loadEnvFiles(path46.dirname(path46.resolve(args.manifest)));
|
|
20466
|
+
loadEnvFiles(process.cwd());
|
|
20467
|
+
const bytes = await readFile30(path46.resolve(image));
|
|
20468
|
+
const metadata = imageMetadata(bytes);
|
|
20469
|
+
if (!metadata) throw new UsageError(`${image} is not a readable PNG or JPEG`);
|
|
20470
|
+
const client2 = clientFromEnv();
|
|
20471
|
+
const res = await client2.estimateSkeleton({
|
|
20472
|
+
image: { base64: bytes.toString("base64"), format: metadata.format }
|
|
20473
|
+
});
|
|
20474
|
+
const json = JSON.stringify(res.keypoints, null, 2);
|
|
20475
|
+
if (args.out) {
|
|
20476
|
+
await writeFile15(path46.resolve(args.out), json + "\n");
|
|
20477
|
+
log(` wrote ${res.keypoints.length} keypoints to ${args.out}`);
|
|
20478
|
+
} else {
|
|
20479
|
+
log(json);
|
|
20480
|
+
}
|
|
20481
|
+
}
|
|
20482
|
+
|
|
20229
20483
|
// src/cli/commands/tools.ts
|
|
20230
20484
|
async function runTools(args) {
|
|
20231
20485
|
const mb = (bytes) => bytes < 1e6 ? `${(bytes / 1e3).toFixed(0)} kB` : `${(bytes / 1e6).toFixed(1)} MB`;
|
|
@@ -20268,15 +20522,15 @@ async function runTools(args) {
|
|
|
20268
20522
|
}
|
|
20269
20523
|
|
|
20270
20524
|
// src/cli/commands/workspace.ts
|
|
20271
|
-
import
|
|
20525
|
+
import path47 from "path";
|
|
20272
20526
|
import { existsSync as existsSync32 } from "fs";
|
|
20273
20527
|
async function runWorkspace(args) {
|
|
20274
|
-
const workspacePath =
|
|
20275
|
-
const dir =
|
|
20528
|
+
const workspacePath = path47.resolve(args.workspace ?? "pixelkiln.workspace.json");
|
|
20529
|
+
const dir = path47.dirname(workspacePath);
|
|
20276
20530
|
if (args.subcommand === "add") {
|
|
20277
|
-
const manifestPath =
|
|
20531
|
+
const manifestPath = path47.resolve(args.target);
|
|
20278
20532
|
const loadedTarget = await loadManifest(manifestPath);
|
|
20279
|
-
const lockPath = args.explicitLock ?
|
|
20533
|
+
const lockPath = args.explicitLock ? path47.resolve(args.explicitLock) : path47.join(path47.dirname(manifestPath), "pixelkiln.lock.json");
|
|
20280
20534
|
const ws = await loadWorkspace(workspacePath);
|
|
20281
20535
|
const id = args.name ?? loadedTarget.manifest.name;
|
|
20282
20536
|
if (ws.projects.some((p) => p.id === id)) {
|
|
@@ -20296,7 +20550,7 @@ async function runWorkspace(args) {
|
|
|
20296
20550
|
...args.account ? { account: args.account } : {}
|
|
20297
20551
|
};
|
|
20298
20552
|
await saveWorkspace(workspacePath, { version: 1, projects: [...ws.projects, project] });
|
|
20299
|
-
log(` registered "${id}" in ${
|
|
20553
|
+
log(` registered "${id}" in ${path47.relative(process.cwd(), workspacePath)}`);
|
|
20300
20554
|
log(` manifest: ${project.manifest}`);
|
|
20301
20555
|
log(` lock: ${project.lock}`);
|
|
20302
20556
|
if (!existsSync32(lockPath)) {
|
|
@@ -20308,7 +20562,7 @@ async function runWorkspace(args) {
|
|
|
20308
20562
|
}
|
|
20309
20563
|
if (args.subcommand === "remove") {
|
|
20310
20564
|
const ws = await loadWorkspace(workspacePath);
|
|
20311
|
-
const resolvedTarget =
|
|
20565
|
+
const resolvedTarget = path47.resolve(args.target);
|
|
20312
20566
|
const match = ws.projects.find(
|
|
20313
20567
|
(p) => p.id === args.target || resolveProject(dir, p).manifestPath === resolvedTarget
|
|
20314
20568
|
);
|
|
@@ -20319,7 +20573,7 @@ async function runWorkspace(args) {
|
|
|
20319
20573
|
version: 1,
|
|
20320
20574
|
projects: ws.projects.filter((p) => p !== match)
|
|
20321
20575
|
});
|
|
20322
|
-
log(` removed "${match.id}" from ${
|
|
20576
|
+
log(` removed "${match.id}" from ${path47.relative(process.cwd(), workspacePath)}`);
|
|
20323
20577
|
return;
|
|
20324
20578
|
}
|
|
20325
20579
|
if (args.subcommand === "list") {
|
|
@@ -20331,9 +20585,9 @@ async function runWorkspace(args) {
|
|
|
20331
20585
|
if (args.json) {
|
|
20332
20586
|
log(JSON.stringify({ version: 1, workspace: workspacePath, projects: ws.projects, diagnostics }, null, 2));
|
|
20333
20587
|
} else if (!ws.projects.length) {
|
|
20334
|
-
log(` no projects registered in ${
|
|
20588
|
+
log(` no projects registered in ${path47.relative(process.cwd(), workspacePath)}`);
|
|
20335
20589
|
} else {
|
|
20336
|
-
log(` ${ws.projects.length} project(s) in ${
|
|
20590
|
+
log(` ${ws.projects.length} project(s) in ${path47.relative(process.cwd(), workspacePath)}:`);
|
|
20337
20591
|
for (const p of ws.projects) {
|
|
20338
20592
|
log(` ${p.id.padEnd(24)} ${p.manifest.padEnd(40)} (${p.provider}${p.account ? `, ${p.account}` : ""})`);
|
|
20339
20593
|
}
|
|
@@ -20351,7 +20605,7 @@ async function runWorkspace(args) {
|
|
|
20351
20605
|
if (args.json) {
|
|
20352
20606
|
log(JSON.stringify({ ...report, workspace: workspacePath }, null, 2));
|
|
20353
20607
|
} else {
|
|
20354
|
-
log(` workspace: ${
|
|
20608
|
+
log(` workspace: ${path47.relative(process.cwd(), workspacePath)}`);
|
|
20355
20609
|
for (const p of report.projects) {
|
|
20356
20610
|
if (p.error) {
|
|
20357
20611
|
log(`
|
|
@@ -20406,7 +20660,7 @@ async function runVersion() {
|
|
|
20406
20660
|
for (const up of ["../package.json", "../../package.json"]) {
|
|
20407
20661
|
const url = new URL(up, import.meta.url);
|
|
20408
20662
|
if (!existsSync33(url)) continue;
|
|
20409
|
-
const pkg = JSON.parse(await
|
|
20663
|
+
const pkg = JSON.parse(await readFile31(url, "utf8"));
|
|
20410
20664
|
if (pkg.name === "pixelkiln") {
|
|
20411
20665
|
log(`${pkg.name} ${pkg.version}`);
|
|
20412
20666
|
return;
|
|
@@ -20450,6 +20704,7 @@ var RUNNERS = {
|
|
|
20450
20704
|
refine: runRefine,
|
|
20451
20705
|
recipe: runRecipe,
|
|
20452
20706
|
workspace: runWorkspace,
|
|
20707
|
+
"estimate-skeleton": runEstimateSkeleton,
|
|
20453
20708
|
unzoom: runUnzoom,
|
|
20454
20709
|
font: runFont
|
|
20455
20710
|
};
|