pixelkiln 0.66.0 → 0.68.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +811 -477
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +745 -443
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1105 -303
- package/dist/index.d.ts +1105 -303
- package/dist/index.js +743 -443
- package/dist/index.js.map +1 -1
- package/docs/CLI.md +17 -0
- package/docs/GENERATORS.md +31 -0
- package/docs/MANIFEST.md +7 -3
- package/docs/PIXELLAB.md +19 -15
- package/docs/REVISIONS.md +98 -10
- package/package.json +1 -1
- package/schema/manifest.schema.json +74 -0
- package/skills/pixelkiln/references/pixellab-roadmap.md +43 -17
- package/skills/pixelkiln/references/pixellab.md +42 -21
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ var RevisionModeSchema = z.enum([
|
|
|
11
11
|
"correct-pixelart",
|
|
12
12
|
"animate",
|
|
13
13
|
"animate-pixminimax",
|
|
14
|
+
"animate-skeleton",
|
|
14
15
|
"interpolate",
|
|
15
16
|
"edit-animation"
|
|
16
17
|
]);
|
|
@@ -199,6 +200,16 @@ var CharacterPortraitSchema = z.object({
|
|
|
199
200
|
of: z.string().min(1),
|
|
200
201
|
size: CharacterPortraitSizeSchema.default(64)
|
|
201
202
|
}).strict();
|
|
203
|
+
var MapScenePlacementSchema = z.union([
|
|
204
|
+
z.object({ oval: z.number().min(0.05).max(0.95) }).strict(),
|
|
205
|
+
z.object({ rectangle: z.number().min(0.05).max(0.95) }).strict(),
|
|
206
|
+
z.object({ mask: z.string().min(1) }).strict()
|
|
207
|
+
]);
|
|
208
|
+
var MapSceneSchema = z.object({
|
|
209
|
+
/** Manifest-relative PNG of the scene. Any earlier asset's output file works. */
|
|
210
|
+
image: z.string().min(1),
|
|
211
|
+
placement: MapScenePlacementSchema.default({ oval: 0.3 })
|
|
212
|
+
}).strict();
|
|
202
213
|
var CharacterOutfitSchema = z.object({
|
|
203
214
|
/** The loop (a character animation asset) to re-clothe, in the same style. */
|
|
204
215
|
of: z.string().min(1),
|
|
@@ -329,6 +340,30 @@ var RevisionSchema = z.object({
|
|
|
329
340
|
direction: CharacterDirectionSchema.optional(),
|
|
330
341
|
/** `animate`/`animate-pixminimax` only: let PixelLab expand the action into a fuller motion description first. */
|
|
331
342
|
enhancePrompt: z.boolean().optional(),
|
|
343
|
+
/**
|
|
344
|
+
* `animate-skeleton` only: manifest-relative path to a committed
|
|
345
|
+
* `SkeletonSet` JSON file (see `src/skeleton.ts`) — the pose the parent
|
|
346
|
+
* image is already in, plus 3-15 per-frame poses for the motion.
|
|
347
|
+
* Authored via `pixelkiln estimate-skeleton`, then hand-tweaked; never
|
|
348
|
+
* inline in the manifest, the same reasoning `mask`/`lastFrame` are
|
|
349
|
+
* committed files rather than inline pixel data.
|
|
350
|
+
*/
|
|
351
|
+
keypointsFile: z.string().min(1).optional(),
|
|
352
|
+
/**
|
|
353
|
+
* `animate-skeleton` only: the body a joint's missing `depth` is taken
|
|
354
|
+
* from. PixelLab's default is `mannequin`; free string like `character`'s
|
|
355
|
+
* own `template` field, validated at the provider layer against the
|
|
356
|
+
* same `mannequin`/`bear`/`cat`/`dog`/`horse`/`lion` vocabulary.
|
|
357
|
+
*/
|
|
358
|
+
skeletonTemplate: z.string().min(1).optional(),
|
|
359
|
+
/**
|
|
360
|
+
* `animate-skeleton` only: what the character *looks like*, a noun
|
|
361
|
+
* phrase (colours, clothing, held items) — distinct from the asset's
|
|
362
|
+
* own `prompt`, which this mode sends as the motion's short label
|
|
363
|
+
* (PixelLab's `action`), the same `prompt`-as-motion convention
|
|
364
|
+
* `animate`/`animate-pixminimax` already use.
|
|
365
|
+
*/
|
|
366
|
+
description: z.string().min(1).optional(),
|
|
332
367
|
/**
|
|
333
368
|
* `image-to-image`/`inpaint` only: which provider engine draws the
|
|
334
369
|
* edit. `pro-flash` selects PixelLab's Pro Flash edit and inpaint tier
|
|
@@ -419,18 +454,41 @@ var RevisionSchema = z.object({
|
|
|
419
454
|
path: ["fps"]
|
|
420
455
|
});
|
|
421
456
|
}
|
|
422
|
-
if (revision.direction !== void 0 && revision.mode !== "animate-pixminimax") {
|
|
457
|
+
if (revision.direction !== void 0 && revision.mode !== "animate-pixminimax" && revision.mode !== "animate-skeleton") {
|
|
423
458
|
context.addIssue({
|
|
424
459
|
code: z.ZodIssueCode.custom,
|
|
425
|
-
message: "direction applies to animate-pixminimax revisions only",
|
|
460
|
+
message: "direction applies to animate-pixminimax/animate-skeleton revisions only",
|
|
461
|
+
path: ["direction"]
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
if (revision.mode === "animate-skeleton" && revision.direction === void 0) {
|
|
465
|
+
context.addIssue({
|
|
466
|
+
code: z.ZodIssueCode.custom,
|
|
467
|
+
message: "animate-skeleton revisions require a direction",
|
|
426
468
|
path: ["direction"]
|
|
427
469
|
});
|
|
428
470
|
}
|
|
429
471
|
if (revision.frames !== void 0 && revision.frames % 2 !== 0) {
|
|
430
472
|
context.addIssue({ code: z.ZodIssueCode.custom, message: "frames must be even", path: ["frames"] });
|
|
431
473
|
}
|
|
474
|
+
if (revision.mode === "animate-skeleton" && !revision.keypointsFile) {
|
|
475
|
+
context.addIssue({
|
|
476
|
+
code: z.ZodIssueCode.custom,
|
|
477
|
+
message: "animate-skeleton revisions require keypointsFile",
|
|
478
|
+
path: ["keypointsFile"]
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
for (const field of ["keypointsFile", "skeletonTemplate", "description"]) {
|
|
482
|
+
if (revision[field] !== void 0 && revision.mode !== "animate-skeleton") {
|
|
483
|
+
context.addIssue({
|
|
484
|
+
code: z.ZodIssueCode.custom,
|
|
485
|
+
message: `${field} applies to animate-skeleton revisions only`,
|
|
486
|
+
path: [field]
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
}
|
|
432
490
|
});
|
|
433
|
-
var FRAME_SET_REVISION_MODES = ["animate", "animate-pixminimax", "interpolate", "edit-animation"];
|
|
491
|
+
var FRAME_SET_REVISION_MODES = ["animate", "animate-pixminimax", "animate-skeleton", "interpolate", "edit-animation"];
|
|
434
492
|
var MEMBER_SET_REVISION_MODES = ["reduce-colors", "correct-pixelart", "edit-animation"];
|
|
435
493
|
var StyleObjectSchema = z.object({
|
|
436
494
|
/** Generation backend for this style. Omit to inherit the manifest default. */
|
|
@@ -846,6 +904,8 @@ var AssetSchema = z.object({
|
|
|
846
904
|
portrait: CharacterPortraitSchema.optional(),
|
|
847
905
|
/** `character` styles: this asset re-clothes an existing loop's frames with a reference outfit. */
|
|
848
906
|
outfit: CharacterOutfitSchema.optional(),
|
|
907
|
+
/** `map` styles only: draw this object in the style of a scene image. See `MapSceneSchema`. */
|
|
908
|
+
scene: MapSceneSchema.optional(),
|
|
849
909
|
/** `character` styles, `standard` humanoid bases: this character's proportions, over the style's. */
|
|
850
910
|
proportions: CharacterProportionsSchema.optional(),
|
|
851
911
|
/**
|
|
@@ -922,7 +982,7 @@ var AssetSchema = z.object({
|
|
|
922
982
|
path: ["revision"]
|
|
923
983
|
});
|
|
924
984
|
}
|
|
925
|
-
const shapes = [asset.revision && "revision", asset.state && "state", asset.animation && "animation", asset.mirror && "mirror", asset.batch && "batch", asset.portrait && "portrait", asset.outfit && "outfit"].filter(Boolean);
|
|
985
|
+
const shapes = [asset.revision && "revision", asset.state && "state", asset.animation && "animation", asset.mirror && "mirror", asset.batch && "batch", asset.portrait && "portrait", asset.outfit && "outfit", asset.scene && "scene"].filter(Boolean);
|
|
926
986
|
if (shapes.length > 1) {
|
|
927
987
|
context.addIssue({
|
|
928
988
|
code: z.ZodIssueCode.custom,
|
|
@@ -1062,11 +1122,16 @@ var LockEntrySchema = z.object({
|
|
|
1062
1122
|
paletteImageSha256: z.string().regex(/^[0-9a-f]{64}$/).optional(),
|
|
1063
1123
|
dithering: RevisionDitheringSchema.optional(),
|
|
1064
1124
|
ditheringStrength: z.number().min(0).max(10).optional(),
|
|
1065
|
-
|
|
1125
|
+
// 4-40 for animate/animate-pixminimax; animate-skeleton's own 3-15
|
|
1126
|
+
// range extends the floor down to 3, hence min(3) here rather than 4.
|
|
1127
|
+
frames: z.number().int().min(3).max(40).optional(),
|
|
1066
1128
|
fps: z.number().int().min(1).max(60).optional(),
|
|
1067
1129
|
lastFrameSha256: z.string().regex(/^[0-9a-f]{64}$/).optional(),
|
|
1068
1130
|
direction: CharacterDirectionSchema.optional(),
|
|
1069
1131
|
enhancePrompt: z.boolean().optional(),
|
|
1132
|
+
keypointsSha256: z.string().regex(/^[0-9a-f]{64}$/).optional(),
|
|
1133
|
+
skeletonTemplate: z.string().min(1).optional(),
|
|
1134
|
+
description: z.string().min(1).optional(),
|
|
1070
1135
|
engine: z.enum(["pro-flash"]).optional()
|
|
1071
1136
|
}).strict().nullable().default(null),
|
|
1072
1137
|
/** For a mirror: the asset it flips and a hash over that asset's output hashes when this was made. */
|
|
@@ -1253,7 +1318,7 @@ function exitCodeFor(err) {
|
|
|
1253
1318
|
}
|
|
1254
1319
|
|
|
1255
1320
|
// src/client.ts
|
|
1256
|
-
import { z as
|
|
1321
|
+
import { z as z3 } from "zod";
|
|
1257
1322
|
|
|
1258
1323
|
// src/http.ts
|
|
1259
1324
|
var MAX_RETRIES = 4;
|
|
@@ -1303,262 +1368,289 @@ function fetchWithRetry(request, opts = {}) {
|
|
|
1303
1368
|
};
|
|
1304
1369
|
}
|
|
1305
1370
|
|
|
1371
|
+
// src/skeleton.ts
|
|
1372
|
+
import { z as z2 } from "zod";
|
|
1373
|
+
var SkeletonKeypointSchema = z2.object({
|
|
1374
|
+
label: z2.string().min(1),
|
|
1375
|
+
x: z2.number().min(0).max(1),
|
|
1376
|
+
y: z2.number().min(0).max(1),
|
|
1377
|
+
z_index: z2.number(),
|
|
1378
|
+
depth: z2.number().optional()
|
|
1379
|
+
}).strict();
|
|
1380
|
+
var SkeletonFrameSchema = z2.array(SkeletonKeypointSchema).length(18);
|
|
1381
|
+
var SkeletonSetSchema = z2.object({
|
|
1382
|
+
firstFrameKeypoints: SkeletonFrameSchema,
|
|
1383
|
+
frames: z2.array(SkeletonFrameSchema).min(3).max(15)
|
|
1384
|
+
}).strict();
|
|
1385
|
+
function parseSkeletonSet(json, file) {
|
|
1386
|
+
const result = SkeletonSetSchema.safeParse(json);
|
|
1387
|
+
if (!result.success) {
|
|
1388
|
+
const issues = result.error.issues.slice(0, 4).map((issue) => `${issue.path.join(".") || "root"}: ${issue.message}`).join("; ");
|
|
1389
|
+
throw new Error(`revision keypoints file ${file} does not match the expected shape: ${issues}`);
|
|
1390
|
+
}
|
|
1391
|
+
return result.data;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1306
1394
|
// src/client.ts
|
|
1307
1395
|
var BASE = process.env.PIXELLAB_API_BASE ?? "https://api.pixellab.ai/v2";
|
|
1308
1396
|
var MAX_DOWNLOAD_BYTES = 64 * 1024 * 1024;
|
|
1309
|
-
var BalanceResponseSchema =
|
|
1310
|
-
credits:
|
|
1311
|
-
subscription:
|
|
1312
|
-
generations:
|
|
1313
|
-
total:
|
|
1314
|
-
plan:
|
|
1397
|
+
var BalanceResponseSchema = z3.object({
|
|
1398
|
+
credits: z3.object({ usd: z3.number() }).passthrough(),
|
|
1399
|
+
subscription: z3.object({
|
|
1400
|
+
generations: z3.number(),
|
|
1401
|
+
total: z3.number(),
|
|
1402
|
+
plan: z3.string().nullable().optional()
|
|
1315
1403
|
}).passthrough()
|
|
1316
1404
|
}).passthrough();
|
|
1317
|
-
var ObjectSubmitSchema =
|
|
1318
|
-
background_job_id:
|
|
1319
|
-
object_id:
|
|
1320
|
-
status:
|
|
1321
|
-
n_frames:
|
|
1405
|
+
var ObjectSubmitSchema = z3.object({
|
|
1406
|
+
background_job_id: z3.string().min(1),
|
|
1407
|
+
object_id: z3.string().min(1),
|
|
1408
|
+
status: z3.string().default("queued"),
|
|
1409
|
+
n_frames: z3.number().int().min(0)
|
|
1322
1410
|
}).passthrough();
|
|
1323
|
-
var MapSubmitSchema =
|
|
1324
|
-
background_job_id:
|
|
1325
|
-
object_id:
|
|
1326
|
-
status:
|
|
1411
|
+
var MapSubmitSchema = z3.object({
|
|
1412
|
+
background_job_id: z3.string().min(1),
|
|
1413
|
+
object_id: z3.string().min(1),
|
|
1414
|
+
status: z3.string().default("processing")
|
|
1327
1415
|
}).passthrough();
|
|
1328
|
-
var UsageSchema =
|
|
1329
|
-
type:
|
|
1330
|
-
usd:
|
|
1331
|
-
generations:
|
|
1416
|
+
var UsageSchema = z3.object({
|
|
1417
|
+
type: z3.string().optional(),
|
|
1418
|
+
usd: z3.number().nullable().optional(),
|
|
1419
|
+
generations: z3.number().nullable().optional()
|
|
1332
1420
|
}).passthrough().nullable().optional();
|
|
1333
|
-
var TilesSubmitSchema =
|
|
1334
|
-
tile_id:
|
|
1335
|
-
background_job_id:
|
|
1336
|
-
status:
|
|
1421
|
+
var TilesSubmitSchema = z3.object({
|
|
1422
|
+
tile_id: z3.string().min(1),
|
|
1423
|
+
background_job_id: z3.string().min(1),
|
|
1424
|
+
status: z3.literal("processing").default("processing")
|
|
1337
1425
|
}).passthrough();
|
|
1338
|
-
var TilesProSchema =
|
|
1339
|
-
storage_urls:
|
|
1340
|
-
kind:
|
|
1341
|
-
tile_rules:
|
|
1426
|
+
var TilesProSchema = z3.object({
|
|
1427
|
+
storage_urls: z3.record(z3.string()),
|
|
1428
|
+
kind: z3.string().nullable().default(null),
|
|
1429
|
+
tile_rules: z3.record(z3.unknown()).nullable().optional()
|
|
1342
1430
|
}).passthrough();
|
|
1343
|
-
var TilesetSubmitSchema =
|
|
1344
|
-
tileset_id:
|
|
1345
|
-
background_job_id:
|
|
1346
|
-
status:
|
|
1431
|
+
var TilesetSubmitSchema = z3.object({
|
|
1432
|
+
tileset_id: z3.string().min(1),
|
|
1433
|
+
background_job_id: z3.string().min(1),
|
|
1434
|
+
status: z3.literal("processing").default("processing")
|
|
1347
1435
|
}).passthrough();
|
|
1348
|
-
var TilesetTileSchema =
|
|
1349
|
-
id:
|
|
1350
|
-
name:
|
|
1351
|
-
image:
|
|
1352
|
-
corners:
|
|
1353
|
-
pattern_4x4:
|
|
1354
|
-
row_0:
|
|
1355
|
-
row_1:
|
|
1356
|
-
row_2:
|
|
1357
|
-
row_3:
|
|
1436
|
+
var TilesetTileSchema = z3.object({
|
|
1437
|
+
id: z3.string().min(1),
|
|
1438
|
+
name: z3.string(),
|
|
1439
|
+
image: z3.object({ base64: z3.string().min(1), format: z3.string().default("png") }).passthrough(),
|
|
1440
|
+
corners: z3.object({ NW: z3.string(), NE: z3.string(), SW: z3.string(), SE: z3.string() }).passthrough(),
|
|
1441
|
+
pattern_4x4: z3.object({
|
|
1442
|
+
row_0: z3.array(z3.number()),
|
|
1443
|
+
row_1: z3.array(z3.number()),
|
|
1444
|
+
row_2: z3.array(z3.number()),
|
|
1445
|
+
row_3: z3.array(z3.number())
|
|
1358
1446
|
}).passthrough()
|
|
1359
1447
|
}).passthrough();
|
|
1360
|
-
var TilesetGetSchema =
|
|
1361
|
-
tileset:
|
|
1362
|
-
total_tiles:
|
|
1363
|
-
tile_size:
|
|
1364
|
-
terrain_types:
|
|
1365
|
-
tiles:
|
|
1448
|
+
var TilesetGetSchema = z3.object({
|
|
1449
|
+
tileset: z3.object({
|
|
1450
|
+
total_tiles: z3.number().int().min(1),
|
|
1451
|
+
tile_size: z3.object({ width: z3.number().int().positive(), height: z3.number().int().positive() }).passthrough(),
|
|
1452
|
+
terrain_types: z3.array(z3.string()),
|
|
1453
|
+
tiles: z3.array(TilesetTileSchema).min(1)
|
|
1366
1454
|
}).passthrough(),
|
|
1367
1455
|
usage: UsageSchema
|
|
1368
1456
|
}).passthrough();
|
|
1369
|
-
var IsometricTileSubmitSchema =
|
|
1370
|
-
tile_id:
|
|
1371
|
-
background_job_id:
|
|
1372
|
-
status:
|
|
1457
|
+
var IsometricTileSubmitSchema = z3.object({
|
|
1458
|
+
tile_id: z3.string().min(1),
|
|
1459
|
+
background_job_id: z3.string().min(1),
|
|
1460
|
+
status: z3.literal("processing").default("processing")
|
|
1373
1461
|
}).passthrough();
|
|
1374
|
-
var IsometricTileGetSchema =
|
|
1375
|
-
image:
|
|
1462
|
+
var IsometricTileGetSchema = z3.object({
|
|
1463
|
+
image: z3.object({ base64: z3.string().min(1), format: z3.string().default("png") }).passthrough(),
|
|
1376
1464
|
usage: UsageSchema
|
|
1377
1465
|
}).passthrough();
|
|
1378
|
-
var UiAssetSubmitSchema =
|
|
1379
|
-
ui_asset_id:
|
|
1380
|
-
background_job_id:
|
|
1381
|
-
status:
|
|
1466
|
+
var UiAssetSubmitSchema = z3.object({
|
|
1467
|
+
ui_asset_id: z3.string().min(1),
|
|
1468
|
+
background_job_id: z3.string().min(1),
|
|
1469
|
+
status: z3.string().default("processing"),
|
|
1382
1470
|
usage: UsageSchema
|
|
1383
1471
|
}).passthrough();
|
|
1384
|
-
var UiAssetGetSchema =
|
|
1385
|
-
id:
|
|
1386
|
-
status:
|
|
1387
|
-
image_url:
|
|
1388
|
-
progress_percent:
|
|
1389
|
-
eta_seconds:
|
|
1472
|
+
var UiAssetGetSchema = z3.object({
|
|
1473
|
+
id: z3.string().min(1),
|
|
1474
|
+
status: z3.string().nullable().default(null),
|
|
1475
|
+
image_url: z3.string().nullable().optional(),
|
|
1476
|
+
progress_percent: z3.number().nullable().optional(),
|
|
1477
|
+
eta_seconds: z3.number().nullable().optional()
|
|
1390
1478
|
}).passthrough();
|
|
1391
|
-
var RevisionJobSubmitSchema =
|
|
1392
|
-
background_job_id:
|
|
1393
|
-
status:
|
|
1479
|
+
var RevisionJobSubmitSchema = z3.object({
|
|
1480
|
+
background_job_id: z3.string().min(1),
|
|
1481
|
+
status: z3.string().default("processing")
|
|
1394
1482
|
}).passthrough();
|
|
1395
|
-
var ObjectAnimationGroupSchema =
|
|
1396
|
-
animation_group_id:
|
|
1397
|
-
display_name:
|
|
1398
|
-
description:
|
|
1399
|
-
frame_count:
|
|
1400
|
-
directions:
|
|
1401
|
-
|
|
1402
|
-
direction:
|
|
1403
|
-
storage_urls:
|
|
1404
|
-
created_at:
|
|
1483
|
+
var ObjectAnimationGroupSchema = z3.object({
|
|
1484
|
+
animation_group_id: z3.string().min(1),
|
|
1485
|
+
display_name: z3.string().nullable().default(null),
|
|
1486
|
+
description: z3.string().default(""),
|
|
1487
|
+
frame_count: z3.number().int().default(0),
|
|
1488
|
+
directions: z3.array(
|
|
1489
|
+
z3.object({
|
|
1490
|
+
direction: z3.string(),
|
|
1491
|
+
storage_urls: z3.record(z3.unknown()).default({}),
|
|
1492
|
+
created_at: z3.string()
|
|
1405
1493
|
}).passthrough()
|
|
1406
1494
|
).default([])
|
|
1407
1495
|
}).passthrough();
|
|
1408
|
-
var PixelLabObjectSchema =
|
|
1409
|
-
id:
|
|
1410
|
-
name:
|
|
1411
|
-
state_name:
|
|
1412
|
-
prompt:
|
|
1413
|
-
size:
|
|
1414
|
-
directions:
|
|
1415
|
-
created_at:
|
|
1416
|
-
view:
|
|
1417
|
-
preview_url:
|
|
1418
|
-
rotation_urls:
|
|
1419
|
-
frame_urls:
|
|
1420
|
-
tags:
|
|
1421
|
-
status:
|
|
1422
|
-
progress_percent:
|
|
1423
|
-
eta_seconds:
|
|
1424
|
-
group_id:
|
|
1425
|
-
animations:
|
|
1496
|
+
var PixelLabObjectSchema = z3.object({
|
|
1497
|
+
id: z3.string().min(1),
|
|
1498
|
+
name: z3.string().nullable().default(null),
|
|
1499
|
+
state_name: z3.string().nullable().optional(),
|
|
1500
|
+
prompt: z3.string().default(""),
|
|
1501
|
+
size: z3.object({ width: z3.number().int().positive(), height: z3.number().int().positive() }),
|
|
1502
|
+
directions: z3.number().default(0),
|
|
1503
|
+
created_at: z3.string(),
|
|
1504
|
+
view: z3.string().nullable().default(null),
|
|
1505
|
+
preview_url: z3.string().nullable().optional(),
|
|
1506
|
+
rotation_urls: z3.record(z3.string().nullable()).nullable().optional(),
|
|
1507
|
+
frame_urls: z3.array(z3.string()).nullable().optional(),
|
|
1508
|
+
tags: z3.array(z3.string()).default([]),
|
|
1509
|
+
status: z3.string().nullable().default(null),
|
|
1510
|
+
progress_percent: z3.number().nullable().optional(),
|
|
1511
|
+
eta_seconds: z3.number().nullable().optional(),
|
|
1512
|
+
group_id: z3.string().nullable().optional(),
|
|
1513
|
+
animations: z3.array(ObjectAnimationGroupSchema).default([])
|
|
1426
1514
|
}).passthrough();
|
|
1427
|
-
var MapObjectSchema =
|
|
1428
|
-
object_id:
|
|
1429
|
-
status:
|
|
1430
|
-
description:
|
|
1431
|
-
width:
|
|
1432
|
-
height:
|
|
1433
|
-
download_url:
|
|
1515
|
+
var MapObjectSchema = z3.object({
|
|
1516
|
+
object_id: z3.string().min(1),
|
|
1517
|
+
status: z3.string(),
|
|
1518
|
+
description: z3.string().nullable().default(null),
|
|
1519
|
+
width: z3.number().nullable().default(null),
|
|
1520
|
+
height: z3.number().nullable().default(null),
|
|
1521
|
+
download_url: z3.string().nullable().default(null)
|
|
1434
1522
|
}).passthrough();
|
|
1435
|
-
var ObjectListSchema =
|
|
1436
|
-
var PixfluxResponseSchema =
|
|
1437
|
-
var ReduceColorsResponseSchema =
|
|
1438
|
-
images:
|
|
1439
|
-
palette:
|
|
1440
|
-
n_colors:
|
|
1441
|
-
usage:
|
|
1523
|
+
var ObjectListSchema = z3.object({ objects: z3.array(PixelLabObjectSchema), total: z3.number().int().min(0) }).passthrough();
|
|
1524
|
+
var PixfluxResponseSchema = z3.object({ image: z3.object({ base64: z3.string().min(1) }).passthrough(), usage: z3.unknown().optional() }).passthrough();
|
|
1525
|
+
var ReduceColorsResponseSchema = z3.object({
|
|
1526
|
+
images: z3.array(z3.object({ base64: z3.string().min(1) }).passthrough()).min(1),
|
|
1527
|
+
palette: z3.object({ base64: z3.string().min(1) }).passthrough(),
|
|
1528
|
+
n_colors: z3.number().int(),
|
|
1529
|
+
usage: z3.unknown().optional()
|
|
1442
1530
|
}).passthrough();
|
|
1443
|
-
var CorrectPixelartResponseSchema =
|
|
1444
|
-
images:
|
|
1445
|
-
usage:
|
|
1531
|
+
var CorrectPixelartResponseSchema = z3.object({
|
|
1532
|
+
images: z3.array(z3.object({ base64: z3.string().min(1) }).passthrough()).min(1),
|
|
1533
|
+
usage: z3.unknown().optional()
|
|
1446
1534
|
}).passthrough();
|
|
1447
|
-
var ProFlashImageSubmitSchema =
|
|
1448
|
-
background_job_id:
|
|
1449
|
-
image_id:
|
|
1450
|
-
source_image_id:
|
|
1451
|
-
status:
|
|
1452
|
-
estimated_generations:
|
|
1453
|
-
usage:
|
|
1535
|
+
var ProFlashImageSubmitSchema = z3.object({
|
|
1536
|
+
background_job_id: z3.string().min(1),
|
|
1537
|
+
image_id: z3.string().min(1),
|
|
1538
|
+
source_image_id: z3.string().min(1),
|
|
1539
|
+
status: z3.string().default("processing"),
|
|
1540
|
+
estimated_generations: z3.number().nullable().optional(),
|
|
1541
|
+
usage: z3.unknown().optional()
|
|
1454
1542
|
}).passthrough();
|
|
1455
|
-
var UnzoomResponseSchema =
|
|
1456
|
-
image:
|
|
1457
|
-
original_size:
|
|
1458
|
-
unzoomed_size:
|
|
1459
|
-
zoom_factor_detected:
|
|
1460
|
-
usage:
|
|
1543
|
+
var UnzoomResponseSchema = z3.object({
|
|
1544
|
+
image: z3.object({ base64: z3.string().min(1) }).passthrough(),
|
|
1545
|
+
original_size: z3.object({ width: z3.number().int(), height: z3.number().int() }).passthrough(),
|
|
1546
|
+
unzoomed_size: z3.object({ width: z3.number().int(), height: z3.number().int() }).passthrough(),
|
|
1547
|
+
zoom_factor_detected: z3.number(),
|
|
1548
|
+
usage: z3.unknown().optional()
|
|
1461
1549
|
}).passthrough();
|
|
1462
|
-
var FontJobSchema =
|
|
1463
|
-
job_id:
|
|
1464
|
-
status:
|
|
1465
|
-
glyph_px:
|
|
1466
|
-
download_atlas_url:
|
|
1467
|
-
download_ttf_url:
|
|
1468
|
-
usage:
|
|
1550
|
+
var FontJobSchema = z3.object({
|
|
1551
|
+
job_id: z3.string().min(1),
|
|
1552
|
+
status: z3.string(),
|
|
1553
|
+
glyph_px: z3.number().int().nullable().optional(),
|
|
1554
|
+
download_atlas_url: z3.string().nullable().optional(),
|
|
1555
|
+
download_ttf_url: z3.string().nullable().optional(),
|
|
1556
|
+
usage: z3.unknown().optional()
|
|
1469
1557
|
}).passthrough();
|
|
1470
|
-
var SelectFramesSchema =
|
|
1471
|
-
var
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1558
|
+
var SelectFramesSchema = z3.object({ created_object_ids: z3.array(z3.string()) }).passthrough();
|
|
1559
|
+
var EstimateSkeletonResponseSchema = z3.object({
|
|
1560
|
+
keypoints: z3.array(SkeletonKeypointSchema).length(18),
|
|
1561
|
+
usage: z3.unknown().optional()
|
|
1562
|
+
}).passthrough();
|
|
1563
|
+
var CharacterSubmitSchema = z3.object({
|
|
1564
|
+
background_job_id: z3.string().min(1),
|
|
1565
|
+
character_id: z3.string().min(1),
|
|
1566
|
+
status: z3.string().default("processing"),
|
|
1475
1567
|
usage: UsageSchema
|
|
1476
1568
|
}).passthrough();
|
|
1477
|
-
var AnimateSubmitSchema =
|
|
1478
|
-
background_job_ids:
|
|
1479
|
-
directions:
|
|
1480
|
-
status:
|
|
1569
|
+
var AnimateSubmitSchema = z3.object({
|
|
1570
|
+
background_job_ids: z3.array(z3.string()),
|
|
1571
|
+
directions: z3.array(z3.string()),
|
|
1572
|
+
status: z3.string().default("processing"),
|
|
1481
1573
|
usage: UsageSchema
|
|
1482
1574
|
}).passthrough();
|
|
1483
|
-
var ObjectProSubmitSchema =
|
|
1484
|
-
object_id:
|
|
1485
|
-
background_job_id:
|
|
1486
|
-
status:
|
|
1575
|
+
var ObjectProSubmitSchema = z3.object({
|
|
1576
|
+
object_id: z3.string().min(1),
|
|
1577
|
+
background_job_id: z3.string().min(1),
|
|
1578
|
+
status: z3.string().default("processing"),
|
|
1487
1579
|
usage: UsageSchema
|
|
1488
1580
|
}).passthrough();
|
|
1489
|
-
var DirectionSubmissionSchema =
|
|
1490
|
-
direction:
|
|
1491
|
-
status:
|
|
1492
|
-
background_job_id:
|
|
1493
|
-
animation_id:
|
|
1581
|
+
var DirectionSubmissionSchema = z3.object({
|
|
1582
|
+
direction: z3.string(),
|
|
1583
|
+
status: z3.string(),
|
|
1584
|
+
background_job_id: z3.string().nullable().default(null),
|
|
1585
|
+
animation_id: z3.string().nullable().default(null)
|
|
1494
1586
|
}).passthrough();
|
|
1495
|
-
var AnimateObjectSubmitSchema =
|
|
1496
|
-
animation_group_id:
|
|
1497
|
-
object_id:
|
|
1498
|
-
mode:
|
|
1499
|
-
frame_count:
|
|
1500
|
-
display_name:
|
|
1501
|
-
description:
|
|
1502
|
-
submissions:
|
|
1587
|
+
var AnimateObjectSubmitSchema = z3.object({
|
|
1588
|
+
animation_group_id: z3.string().min(1),
|
|
1589
|
+
object_id: z3.string().min(1),
|
|
1590
|
+
mode: z3.string(),
|
|
1591
|
+
frame_count: z3.number().int(),
|
|
1592
|
+
display_name: z3.string().nullable().default(null),
|
|
1593
|
+
description: z3.string().default(""),
|
|
1594
|
+
submissions: z3.array(DirectionSubmissionSchema),
|
|
1503
1595
|
usage: UsageSchema
|
|
1504
1596
|
}).passthrough();
|
|
1505
|
-
var PortraitSubmitSchema =
|
|
1506
|
-
background_job_id:
|
|
1507
|
-
status:
|
|
1597
|
+
var PortraitSubmitSchema = z3.object({
|
|
1598
|
+
background_job_id: z3.string().min(1),
|
|
1599
|
+
status: z3.string().default("processing"),
|
|
1508
1600
|
usage: UsageSchema
|
|
1509
1601
|
}).passthrough();
|
|
1510
|
-
var PortraitJobSchema =
|
|
1511
|
-
status:
|
|
1512
|
-
download_url:
|
|
1513
|
-
width:
|
|
1514
|
-
height:
|
|
1602
|
+
var PortraitJobSchema = z3.object({
|
|
1603
|
+
status: z3.string(),
|
|
1604
|
+
download_url: z3.string().nullable().optional(),
|
|
1605
|
+
width: z3.number().int().nullable().optional(),
|
|
1606
|
+
height: z3.number().int().nullable().optional()
|
|
1515
1607
|
}).passthrough();
|
|
1516
|
-
var SetPortraitSchema =
|
|
1517
|
-
character_id:
|
|
1518
|
-
size:
|
|
1519
|
-
url:
|
|
1608
|
+
var SetPortraitSchema = z3.object({
|
|
1609
|
+
character_id: z3.string().min(1),
|
|
1610
|
+
size: z3.number().int().positive(),
|
|
1611
|
+
url: z3.string().min(1),
|
|
1520
1612
|
usage: UsageSchema
|
|
1521
1613
|
}).passthrough();
|
|
1522
|
-
var TransferOutfitSubmitSchema =
|
|
1523
|
-
background_job_id:
|
|
1524
|
-
status:
|
|
1614
|
+
var TransferOutfitSubmitSchema = z3.object({
|
|
1615
|
+
background_job_id: z3.string().min(1),
|
|
1616
|
+
status: z3.string().default("processing"),
|
|
1525
1617
|
usage: UsageSchema
|
|
1526
1618
|
}).passthrough();
|
|
1527
|
-
var CharacterAnimationDirectionSchema =
|
|
1528
|
-
direction:
|
|
1529
|
-
frame_count:
|
|
1530
|
-
frames:
|
|
1619
|
+
var CharacterAnimationDirectionSchema = z3.object({
|
|
1620
|
+
direction: z3.string(),
|
|
1621
|
+
frame_count: z3.number().int().min(0),
|
|
1622
|
+
frames: z3.array(z3.string())
|
|
1531
1623
|
}).passthrough();
|
|
1532
|
-
var CharacterAnimationSchema2 =
|
|
1533
|
-
animation_type:
|
|
1534
|
-
display_name:
|
|
1535
|
-
animation_group_id:
|
|
1536
|
-
directions:
|
|
1624
|
+
var CharacterAnimationSchema2 = z3.object({
|
|
1625
|
+
animation_type: z3.string(),
|
|
1626
|
+
display_name: z3.string().nullable().optional(),
|
|
1627
|
+
animation_group_id: z3.string().nullable().optional(),
|
|
1628
|
+
directions: z3.array(CharacterAnimationDirectionSchema)
|
|
1537
1629
|
}).passthrough();
|
|
1538
|
-
var CharacterSchema =
|
|
1539
|
-
id:
|
|
1540
|
-
name:
|
|
1541
|
-
state_name:
|
|
1542
|
-
prompt:
|
|
1543
|
-
size:
|
|
1544
|
-
directions:
|
|
1545
|
-
created_at:
|
|
1546
|
-
updated_at:
|
|
1547
|
-
animation_count:
|
|
1548
|
-
template_id:
|
|
1549
|
-
view:
|
|
1550
|
-
status:
|
|
1551
|
-
rotation_urls:
|
|
1552
|
-
tags:
|
|
1553
|
-
group_id:
|
|
1554
|
-
animations:
|
|
1555
|
-
preview_url:
|
|
1630
|
+
var CharacterSchema = z3.object({
|
|
1631
|
+
id: z3.string().min(1),
|
|
1632
|
+
name: z3.string().default(""),
|
|
1633
|
+
state_name: z3.string().nullable().optional(),
|
|
1634
|
+
prompt: z3.string().default(""),
|
|
1635
|
+
size: z3.object({ width: z3.number().int().positive(), height: z3.number().int().positive() }),
|
|
1636
|
+
directions: z3.number().int(),
|
|
1637
|
+
created_at: z3.string(),
|
|
1638
|
+
updated_at: z3.string().nullable().optional(),
|
|
1639
|
+
animation_count: z3.number().int().default(0),
|
|
1640
|
+
template_id: z3.string().default("mannequin"),
|
|
1641
|
+
view: z3.string().nullable().optional(),
|
|
1642
|
+
status: z3.string().default("completed"),
|
|
1643
|
+
rotation_urls: z3.record(z3.string().nullable()).nullable().optional(),
|
|
1644
|
+
tags: z3.array(z3.string()).default([]),
|
|
1645
|
+
group_id: z3.string().nullable().optional(),
|
|
1646
|
+
animations: z3.array(CharacterAnimationSchema2).default([]),
|
|
1647
|
+
preview_url: z3.string().nullable().optional()
|
|
1556
1648
|
}).passthrough();
|
|
1557
|
-
var CharacterListSchema =
|
|
1558
|
-
var BackgroundJobSchema =
|
|
1559
|
-
id:
|
|
1560
|
-
status:
|
|
1561
|
-
last_response:
|
|
1649
|
+
var CharacterListSchema = z3.object({ characters: z3.array(CharacterSchema), total: z3.number().int().min(0) }).passthrough();
|
|
1650
|
+
var BackgroundJobSchema = z3.object({
|
|
1651
|
+
id: z3.string(),
|
|
1652
|
+
status: z3.string(),
|
|
1653
|
+
last_response: z3.record(z3.unknown()).nullable().optional(),
|
|
1562
1654
|
/**
|
|
1563
1655
|
* The billed amount, confirmed live for a `map` object and a standard
|
|
1564
1656
|
* character base (docs/ENDPOINTS.md, "Limits and billing"); duplicated at
|
|
@@ -1566,7 +1658,7 @@ var BackgroundJobSchema = z2.object({
|
|
|
1566
1658
|
*/
|
|
1567
1659
|
usage: UsageSchema
|
|
1568
1660
|
}).passthrough();
|
|
1569
|
-
var DeleteAnimationsSchema =
|
|
1661
|
+
var DeleteAnimationsSchema = z3.object({ success: z3.boolean(), deleted_count: z3.number().int().default(0), error: z3.string().nullable().optional() }).passthrough();
|
|
1570
1662
|
function validateResponse(schema, raw, operation) {
|
|
1571
1663
|
const parsed = schema.safeParse(raw);
|
|
1572
1664
|
if (parsed.success) return parsed.data;
|
|
@@ -1686,6 +1778,12 @@ var PixelLabClient = class {
|
|
|
1686
1778
|
if (args.shading) body.shading = args.shading;
|
|
1687
1779
|
if (args.detail) body.detail = args.detail;
|
|
1688
1780
|
if (args.seed != null) body.seed = args.seed;
|
|
1781
|
+
if (args.scene) {
|
|
1782
|
+
const encode = (image) => ({ type: "base64", base64: image.base64, format: image.format });
|
|
1783
|
+
const placement = args.scene.placement;
|
|
1784
|
+
body.background_image = encode(args.scene.image);
|
|
1785
|
+
body.inpainting = placement.type === "mask" ? { type: "mask", mask_image: encode(placement.mask) } : { type: placement.type, fraction: placement.fraction };
|
|
1786
|
+
}
|
|
1689
1787
|
return validateResponse(
|
|
1690
1788
|
MapSubmitSchema,
|
|
1691
1789
|
await this.request("/map-objects", { method: "POST", body: JSON.stringify(body) }),
|
|
@@ -2597,6 +2695,61 @@ var PixelLabClient = class {
|
|
|
2597
2695
|
"animate-pixminimax"
|
|
2598
2696
|
);
|
|
2599
2697
|
}
|
|
2698
|
+
/**
|
|
2699
|
+
* `/animate-with-skeleton-v3`, beta (tier 1 subscription or higher): poses
|
|
2700
|
+
* one reference image frame-by-frame from a supplied skeleton per frame,
|
|
2701
|
+
* rather than a text motion description. Confirmed against the live
|
|
2702
|
+
* `animate_with_skeleton_v3` MCP tool schema (the same authoritative
|
|
2703
|
+
* source this codebase already treats as ground truth for the
|
|
2704
|
+
* character/object family) — `action`/`description` are both real,
|
|
2705
|
+
* optional wire fields, contrary to an initial guess that this endpoint
|
|
2706
|
+
* took no text input at all; `direction`/`keypoints`/`firstFrameKeypoints`
|
|
2707
|
+
* are required. The example keypoint from that same tool schema,
|
|
2708
|
+
* `{"label": "RIGHT KNEE", "x": 0.52, "y": 0.71, "z_index": 9}`, is what
|
|
2709
|
+
* `SkeletonKeypointSchema` (`src/skeleton.ts`) models. Same
|
|
2710
|
+
* unverified-completed-shape caveat as `animateWithTextV3`/
|
|
2711
|
+
* `animatePixminimax` above — this endpoint has never been called against
|
|
2712
|
+
* a live account by this codebase.
|
|
2713
|
+
*/
|
|
2714
|
+
async animateWithSkeletonV3(args) {
|
|
2715
|
+
const body = {
|
|
2716
|
+
first_frame: args.firstFrame,
|
|
2717
|
+
first_frame_keypoints: args.firstFrameKeypoints,
|
|
2718
|
+
keypoints: args.keypoints,
|
|
2719
|
+
direction: args.direction
|
|
2720
|
+
};
|
|
2721
|
+
if (args.templateId) body.template_id = args.templateId;
|
|
2722
|
+
if (args.action) body.action = args.action;
|
|
2723
|
+
if (args.description) body.description = args.description;
|
|
2724
|
+
if (args.seed != null) body.seed = args.seed;
|
|
2725
|
+
if (args.noBackground != null) body.no_background = args.noBackground;
|
|
2726
|
+
return validateResponse(
|
|
2727
|
+
RevisionJobSubmitSchema,
|
|
2728
|
+
await this.request("/animate-with-skeleton-v3", { method: "POST", body: JSON.stringify(body) }),
|
|
2729
|
+
"animate-with-skeleton-v3"
|
|
2730
|
+
);
|
|
2731
|
+
}
|
|
2732
|
+
/**
|
|
2733
|
+
* `/estimate-skeleton`: auto-derives a reference image's own 18-joint
|
|
2734
|
+
* keypoints, directly usable as `animateWithSkeletonV3`'s
|
|
2735
|
+
* `firstFrameKeypoints` (or, run against a candidate pose image, as one
|
|
2736
|
+
* entry of its `keypoints` sequence). Not called anywhere in this
|
|
2737
|
+
* codebase's own submit/poll pipeline — deliberately kept outside it (see
|
|
2738
|
+
* `runEstimateSkeleton` in `src/cli/commands`) so the only PixelLab
|
|
2739
|
+
* endpoint composed into `animate-with-skeleton-v3`'s submission is that
|
|
2740
|
+
* one endpoint itself, not two unverified calls chained together.
|
|
2741
|
+
* Synchronous per this endpoint's own framing; unverified against a live
|
|
2742
|
+
* account (see `EstimateSkeletonResponseSchema`'s own caveat).
|
|
2743
|
+
*/
|
|
2744
|
+
async estimateSkeleton(args) {
|
|
2745
|
+
const body = { image: args.image };
|
|
2746
|
+
const res = validateResponse(
|
|
2747
|
+
EstimateSkeletonResponseSchema,
|
|
2748
|
+
await this.request("/estimate-skeleton", { method: "POST", body: JSON.stringify(body) }),
|
|
2749
|
+
"estimate-skeleton"
|
|
2750
|
+
);
|
|
2751
|
+
return { keypoints: res.keypoints, usage: res.usage };
|
|
2752
|
+
}
|
|
2600
2753
|
async getBackgroundJob(jobId) {
|
|
2601
2754
|
const raw = await this.request(`/background-jobs/${encodeURIComponent(jobId)}`);
|
|
2602
2755
|
return validateResponse(BackgroundJobSchema, raw, "background-jobs/{id}");
|
|
@@ -3253,6 +3406,11 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
|
|
|
3253
3406
|
uiPieces: spec.uiPieces,
|
|
3254
3407
|
uiElements: spec.uiElements,
|
|
3255
3408
|
uiColorPalette: spec.uiColorPalette,
|
|
3409
|
+
// Scene and mask enter as their bytes' hashes, never their paths.
|
|
3410
|
+
scene: spec.scene ? {
|
|
3411
|
+
image: spec.scene.sha256,
|
|
3412
|
+
placement: spec.scene.placement.type === "mask" ? { type: "mask", mask: spec.scene.placement.sha256 } : spec.scene.placement
|
|
3413
|
+
} : void 0,
|
|
3256
3414
|
styleTraits: spec.styleTraits,
|
|
3257
3415
|
styleImages: styleImageHashes,
|
|
3258
3416
|
// A character family: the engine and rotations of a base, the parent's
|
|
@@ -3331,6 +3489,9 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
|
|
|
3331
3489
|
lastFrameSha256: spec.revision.lastFrameSha256,
|
|
3332
3490
|
direction: spec.revision.direction,
|
|
3333
3491
|
enhancePrompt: spec.revision.enhancePrompt,
|
|
3492
|
+
keypointsSha256: spec.revision.keypointsSha256,
|
|
3493
|
+
skeletonTemplate: spec.revision.skeletonTemplate,
|
|
3494
|
+
description: spec.revision.description,
|
|
3334
3495
|
engine: spec.revision.engine
|
|
3335
3496
|
} : void 0
|
|
3336
3497
|
})
|
|
@@ -3419,6 +3580,18 @@ function objectProCost(spec) {
|
|
|
3419
3580
|
const south = object.reference;
|
|
3420
3581
|
return south ? proFlashObjectCost(south.width, south.height, object.directions, true) : proFlashObjectCost(spec.width, spec.height, object.directions, false);
|
|
3421
3582
|
}
|
|
3583
|
+
function animateSkeletonCost(frames) {
|
|
3584
|
+
const anchors = [[3, 2], [8, 3], [15, 4]];
|
|
3585
|
+
for (let i = 0; i < anchors.length - 1; i++) {
|
|
3586
|
+
const [lowFrames, lowCost] = anchors[i];
|
|
3587
|
+
const [highFrames, highCost] = anchors[i + 1];
|
|
3588
|
+
if (frames >= lowFrames && frames <= highFrames) {
|
|
3589
|
+
const t = (frames - lowFrames) / (highFrames - lowFrames);
|
|
3590
|
+
return lowCost + t * (highCost - lowCost);
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
return frames <= anchors[0][0] ? anchors[0][1] : anchors[anchors.length - 1][1];
|
|
3594
|
+
}
|
|
3422
3595
|
var CHARACTER_TEMPLATES = ["mannequin", "bear", "cat", "dog", "horse", "lion"];
|
|
3423
3596
|
var PRO_FLASH_TEMPLATES = [...CHARACTER_TEMPLATES, "custom"];
|
|
3424
3597
|
function encodeAnimationJob(job) {
|
|
@@ -3469,6 +3642,8 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
3469
3642
|
supports(generator) {
|
|
3470
3643
|
return generator === "1dir" || generator === "map" || generator === "pixflux" || generator === "tiles" || generator === "terrain" || generator === "imagePro" || generator === "character" || generator === "isometricTile" || generator === "objectPro" || generator === "uiAsset" || generator === "uiElement" || generator === "imageProFlash";
|
|
3471
3644
|
}
|
|
3645
|
+
/** `/map-objects` style matching: `background_image` plus `inpainting`. */
|
|
3646
|
+
supportsMapScene = true;
|
|
3472
3647
|
/**
|
|
3473
3648
|
* `inpaint` (`/inpaint-v3`, a mask) and `image-to-image` (`/edit-images-v2`,
|
|
3474
3649
|
* no mask) both exist on PixelLab, and so do `reduce-colors`
|
|
@@ -3477,7 +3652,9 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
3477
3652
|
* rather than a described edit — and `animate`/`animate-pixminimax`
|
|
3478
3653
|
* (`/animate-with-text-v3`, `/animate-pixminimax`), which animate any loose
|
|
3479
3654
|
* image from a text description with no character/object resource
|
|
3480
|
-
* required —
|
|
3655
|
+
* required — `animate-skeleton` (`/animate-with-skeleton-v3`, posing the
|
|
3656
|
+
* source from a supplied per-frame skeleton instead of a text description)
|
|
3657
|
+
* — and `interpolate` (`/interpolation-v2`, the in-betweens
|
|
3481
3658
|
* from one keyframe to another) and `edit-animation`
|
|
3482
3659
|
* (`/edit-animation-v2`, one text edit applied across a whole frame set).
|
|
3483
3660
|
* `outpaint` does not: there is no canvas-expansion endpoint in the API,
|
|
@@ -3485,7 +3662,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
3485
3662
|
* outpaint path yet.
|
|
3486
3663
|
*/
|
|
3487
3664
|
supportsRevision(mode2) {
|
|
3488
|
-
return mode2 === "inpaint" || mode2 === "image-to-image" || mode2 === "reduce-colors" || mode2 === "correct-pixelart" || mode2 === "animate" || mode2 === "animate-pixminimax" || mode2 === "interpolate" || mode2 === "edit-animation";
|
|
3665
|
+
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";
|
|
3489
3666
|
}
|
|
3490
3667
|
/** PixelLab's own constraints: submissions must be >2s apart, and
|
|
3491
3668
|
* background jobs in flight are capped by subscription tier (Tier 1=8,
|
|
@@ -3516,6 +3693,10 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
3516
3693
|
if (spec.revision?.mode === "reduce-colors" || spec.revision?.mode === "correct-pixelart") {
|
|
3517
3694
|
return { unit: "generations", amount: 0.1, candidates: 1 };
|
|
3518
3695
|
}
|
|
3696
|
+
if (spec.revision?.mode === "animate-skeleton") {
|
|
3697
|
+
const frames = spec.revision.frames ?? 8;
|
|
3698
|
+
return { unit: "generations", amount: Math.ceil(animateSkeletonCost(frames)), candidates: 1 };
|
|
3699
|
+
}
|
|
3519
3700
|
if (spec.revision?.mode === "interpolate" || spec.revision?.mode === "edit-animation") {
|
|
3520
3701
|
const width = spec.revision.sourceWidth ?? spec.width;
|
|
3521
3702
|
const height = spec.revision.sourceHeight ?? spec.height;
|
|
@@ -3597,6 +3778,18 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
3597
3778
|
throw new Error(`PixelLab correct-pixelart source is ${width}x${height}; the API takes at most 1024 pixels per side`);
|
|
3598
3779
|
}
|
|
3599
3780
|
}
|
|
3781
|
+
if (spec.revision?.mode === "animate-skeleton") {
|
|
3782
|
+
const { sourceWidth: width, sourceHeight: height, frames, skeletonTemplate } = spec.revision;
|
|
3783
|
+
if (width != null && height != null && (width > 256 || height > 256)) {
|
|
3784
|
+
throw new Error(`PixelLab animate-skeleton source is ${width}x${height}; the API takes at most 256 pixels per side`);
|
|
3785
|
+
}
|
|
3786
|
+
if (frames != null && (frames < 3 || frames > 15)) {
|
|
3787
|
+
throw new Error(`PixelLab animate-skeleton takes 3 to 15 frames; the keypoints file has ${frames}`);
|
|
3788
|
+
}
|
|
3789
|
+
if (skeletonTemplate && !CHARACTER_TEMPLATES.includes(skeletonTemplate)) {
|
|
3790
|
+
throw new Error(`PixelLab animate-skeleton template "${skeletonTemplate}" is not one of ${CHARACTER_TEMPLATES.join(", ")}`);
|
|
3791
|
+
}
|
|
3792
|
+
}
|
|
3600
3793
|
if (spec.revision?.mode === "animate" || spec.revision?.mode === "animate-pixminimax") {
|
|
3601
3794
|
const { sourceWidth: width, sourceHeight: height, mode: mode2, frames, lastFrameWidth, lastFrameHeight } = spec.revision;
|
|
3602
3795
|
if (width != null && height != null && (width > 256 || height > 256)) {
|
|
@@ -4596,7 +4789,8 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
4596
4789
|
outline: spec.outline,
|
|
4597
4790
|
shading: spec.shading,
|
|
4598
4791
|
detail: spec.detail,
|
|
4599
|
-
seed: spec.seed
|
|
4792
|
+
seed: spec.seed,
|
|
4793
|
+
scene: spec.scene ? mapScenePayload(spec) : void 0
|
|
4600
4794
|
});
|
|
4601
4795
|
return { jobId: res.object_id, metadata: { backgroundJobId: res.background_job_id } };
|
|
4602
4796
|
}
|
|
@@ -4746,6 +4940,27 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
4746
4940
|
});
|
|
4747
4941
|
return { jobId: res2.background_job_id };
|
|
4748
4942
|
}
|
|
4943
|
+
if (revision.mode === "animate-skeleton") {
|
|
4944
|
+
if (!revision.keypointsFile || !revision.keypointsSha256 || !revision.skeleton) {
|
|
4945
|
+
throw new Error(`${spec.styleId}/${spec.assetId}: revision keypoints are not ready`);
|
|
4946
|
+
}
|
|
4947
|
+
const keypointsBytes = readFileSync(revision.keypointsFile);
|
|
4948
|
+
if (sha256(keypointsBytes) !== revision.keypointsSha256) {
|
|
4949
|
+
throw new Error(`${spec.styleId}/${spec.assetId}: revision keypoints changed after the manifest was resolved`);
|
|
4950
|
+
}
|
|
4951
|
+
const res2 = await this.client.animateWithSkeletonV3({
|
|
4952
|
+
firstFrame: image,
|
|
4953
|
+
firstFrameKeypoints: revision.skeleton.firstFrameKeypoints,
|
|
4954
|
+
keypoints: revision.skeleton.frames,
|
|
4955
|
+
direction: revision.direction,
|
|
4956
|
+
templateId: revision.skeletonTemplate,
|
|
4957
|
+
action: spec.prompt,
|
|
4958
|
+
description: revision.description,
|
|
4959
|
+
seed: spec.seed,
|
|
4960
|
+
noBackground: spec.noBackground
|
|
4961
|
+
});
|
|
4962
|
+
return { jobId: res2.background_job_id };
|
|
4963
|
+
}
|
|
4749
4964
|
if (revision.strength != null) {
|
|
4750
4965
|
throw new Error(
|
|
4751
4966
|
`${spec.styleId}/${spec.assetId}: PixelLab image-to-image revisions take no strength; edit-images-v2 always applies the full instruction`
|
|
@@ -4811,7 +5026,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
4811
5026
|
if (revisionMode === "reduce-colors" || revisionMode === "correct-pixelart") {
|
|
4812
5027
|
return this.pollCachedRevision(jobId, context);
|
|
4813
5028
|
}
|
|
4814
|
-
if (revisionMode === "animate" || revisionMode === "animate-pixminimax" || revisionMode === "interpolate" || revisionMode === "edit-animation") {
|
|
5029
|
+
if (revisionMode === "animate" || revisionMode === "animate-pixminimax" || revisionMode === "animate-skeleton" || revisionMode === "interpolate" || revisionMode === "edit-animation") {
|
|
4815
5030
|
return this.pollAnimateRevision(jobId, context);
|
|
4816
5031
|
}
|
|
4817
5032
|
if (context?.spec?.revision) return this.pollRevision(jobId);
|
|
@@ -5452,6 +5667,21 @@ function findObjectAnimation(object, name, direction, animationId) {
|
|
|
5452
5667
|
}
|
|
5453
5668
|
return null;
|
|
5454
5669
|
}
|
|
5670
|
+
function mapScenePayload(spec) {
|
|
5671
|
+
const scene = spec.scene;
|
|
5672
|
+
const read = (file, hash, label) => {
|
|
5673
|
+
const bytes = readFileSync(file);
|
|
5674
|
+
if (!hash || sha256(bytes) !== hash) {
|
|
5675
|
+
throw new Error(`${spec.styleId}/${spec.assetId}: ${label} changed after the manifest was resolved`);
|
|
5676
|
+
}
|
|
5677
|
+
return { base64: bytes.toString("base64"), format: "png" };
|
|
5678
|
+
};
|
|
5679
|
+
const placement = scene.placement;
|
|
5680
|
+
return {
|
|
5681
|
+
image: read(scene.file, scene.sha256, "scene image"),
|
|
5682
|
+
placement: placement.type === "mask" ? { type: "mask", mask: read(placement.file, placement.sha256, "scene mask") } : placement
|
|
5683
|
+
};
|
|
5684
|
+
}
|
|
5455
5685
|
|
|
5456
5686
|
// src/providers/retrodiffusion.ts
|
|
5457
5687
|
var DEFAULT_BASE_URL = "https://api.retrodiffusion.ai/v1";
|
|
@@ -6546,11 +6776,12 @@ var ComfyUIProvider = class _ComfyUIProvider {
|
|
|
6546
6776
|
/**
|
|
6547
6777
|
* Everything else resolves generically to whatever the user's own
|
|
6548
6778
|
* workflow does with `bindings.sourceImage`. The frame-set modes
|
|
6549
|
-
* (`animate`, `animate-pixminimax`, `
|
|
6550
|
-
* the exception: they produce an ordered frame set,
|
|
6551
|
-
* revision path always writes a single output image
|
|
6552
|
-
* below) — a real structural gap, not a missing
|
|
6553
|
-
* rejected here rather than only failing once
|
|
6779
|
+
* (`animate`, `animate-pixminimax`, `animate-skeleton`, `interpolate`,
|
|
6780
|
+
* `edit-animation`) are the exception: they produce an ordered frame set,
|
|
6781
|
+
* and this adapter's revision path always writes a single output image
|
|
6782
|
+
* (see `submit`/`fetch` below) — a real structural gap, not a missing
|
|
6783
|
+
* binding, so they are rejected here rather than only failing once
|
|
6784
|
+
* `validate` runs.
|
|
6554
6785
|
*/
|
|
6555
6786
|
supportsRevision(mode2) {
|
|
6556
6787
|
return !FRAME_SET_REVISION_MODES.includes(mode2);
|
|
@@ -7230,6 +7461,7 @@ var FakeProvider = class {
|
|
|
7230
7461
|
supports(generator) {
|
|
7231
7462
|
return generator === "1dir" || generator === "map" || generator === "character";
|
|
7232
7463
|
}
|
|
7464
|
+
supportsMapScene = true;
|
|
7233
7465
|
supportsRevision(_mode) {
|
|
7234
7466
|
return true;
|
|
7235
7467
|
}
|
|
@@ -8453,6 +8685,8 @@ async function resolveSpecs(loaded, filter) {
|
|
|
8453
8685
|
const paletteImage = paletteImageFile ? await optionalRevisionImage(paletteImageFile, "revision palette image", "png") : null;
|
|
8454
8686
|
const lastFrameFile = asset.revision.lastFrame ? path5.resolve(root, asset.revision.lastFrame) : void 0;
|
|
8455
8687
|
const lastFrame = lastFrameFile ? await optionalRevisionImage(lastFrameFile, "revision last frame") : null;
|
|
8688
|
+
const keypointsFile = asset.revision.keypointsFile ? path5.resolve(root, asset.revision.keypointsFile) : void 0;
|
|
8689
|
+
const keypoints = keypointsFile ? await optionalSkeletonSet(keypointsFile) : null;
|
|
8456
8690
|
resolved.revision = {
|
|
8457
8691
|
mode: asset.revision.mode,
|
|
8458
8692
|
sourceAssetId: asset.revision.from,
|
|
@@ -8493,6 +8727,18 @@ async function resolveSpecs(loaded, filter) {
|
|
|
8493
8727
|
} : {},
|
|
8494
8728
|
...asset.revision.direction ? { direction: asset.revision.direction } : {},
|
|
8495
8729
|
...asset.revision.enhancePrompt == null ? {} : { enhancePrompt: asset.revision.enhancePrompt },
|
|
8730
|
+
...keypointsFile ? {
|
|
8731
|
+
keypointsFile,
|
|
8732
|
+
keypointsSha256: keypoints?.hash ?? null,
|
|
8733
|
+
skeleton: keypoints?.skeleton ?? null,
|
|
8734
|
+
// The manifest's own `frames` field stays rejected for this
|
|
8735
|
+
// mode (superRefine, types.ts) — the real frame count comes
|
|
8736
|
+
// from the keypoints file once it exists, not a manifest
|
|
8737
|
+
// number, so plan can only know it once authored.
|
|
8738
|
+
...keypoints ? { frames: keypoints.skeleton.frames.length } : {}
|
|
8739
|
+
} : {},
|
|
8740
|
+
...asset.revision.skeletonTemplate ? { skeletonTemplate: asset.revision.skeletonTemplate } : {},
|
|
8741
|
+
...asset.revision.description ? { description: asset.revision.description } : {},
|
|
8496
8742
|
...asset.revision.engine ? { engine: asset.revision.engine } : {}
|
|
8497
8743
|
};
|
|
8498
8744
|
}
|
|
@@ -8546,6 +8792,7 @@ async function resolveSpecs(loaded, filter) {
|
|
|
8546
8792
|
};
|
|
8547
8793
|
}
|
|
8548
8794
|
}
|
|
8795
|
+
if (asset.scene) resolved.scene = await resolveMapScene(root, styleId, assetId, resolved.generator, asset.scene, activeProvider);
|
|
8549
8796
|
resolved.specHash = specHash(
|
|
8550
8797
|
resolved,
|
|
8551
8798
|
styleImageHashes,
|
|
@@ -8604,6 +8851,32 @@ function pngPath(file) {
|
|
|
8604
8851
|
const extension = path5.extname(file);
|
|
8605
8852
|
return extension ? `${file.slice(0, -extension.length)}.png` : `${file}.png`;
|
|
8606
8853
|
}
|
|
8854
|
+
async function resolveMapScene(root, styleId, assetId, generator, scene, provider) {
|
|
8855
|
+
if (generator !== "map") {
|
|
8856
|
+
throw new Error(`assets.${assetId}.scene: only a map object can be drawn into a scene; style "${styleId}" uses "${generator}"`);
|
|
8857
|
+
}
|
|
8858
|
+
if (!provider.supportsMapScene) {
|
|
8859
|
+
throw new Error(`assets.${assetId}.scene: provider "${provider.id}" cannot draw into a scene; PixelLab's /map-objects can`);
|
|
8860
|
+
}
|
|
8861
|
+
const file = path5.resolve(root, scene.image);
|
|
8862
|
+
const image = await optionalRevisionImage(file, "scene image", "png");
|
|
8863
|
+
const base = { file, sha256: image?.hash ?? null, width: image?.width ?? null, height: image?.height ?? null };
|
|
8864
|
+
const placement = scene.placement;
|
|
8865
|
+
if ("mask" in placement) {
|
|
8866
|
+
const maskFile = path5.resolve(root, placement.mask);
|
|
8867
|
+
const mask = await optionalRevisionImage(maskFile, "scene mask", "png");
|
|
8868
|
+
if (image && mask && (image.width !== mask.width || image.height !== mask.height)) {
|
|
8869
|
+
throw new Error(
|
|
8870
|
+
`assets.${assetId}.scene: the mask is ${mask.width}x${mask.height}; the scene ${scene.image} is ${image.width}x${image.height}`
|
|
8871
|
+
);
|
|
8872
|
+
}
|
|
8873
|
+
return {
|
|
8874
|
+
...base,
|
|
8875
|
+
placement: { type: "mask", file: maskFile, sha256: mask?.hash ?? null, width: mask?.width ?? null, height: mask?.height ?? null }
|
|
8876
|
+
};
|
|
8877
|
+
}
|
|
8878
|
+
return "oval" in placement ? { ...base, placement: { type: "oval", fraction: placement.oval } } : { ...base, placement: { type: "rectangle", fraction: placement.rectangle } };
|
|
8879
|
+
}
|
|
8607
8880
|
async function optionalRevisionImage(file, label, requiredFormat) {
|
|
8608
8881
|
if (!existsSync4(file)) return null;
|
|
8609
8882
|
const bytes = await readFile3(file);
|
|
@@ -8614,6 +8887,17 @@ async function optionalRevisionImage(file, label, requiredFormat) {
|
|
|
8614
8887
|
}
|
|
8615
8888
|
return { hash: sha256(bytes), ...metadata };
|
|
8616
8889
|
}
|
|
8890
|
+
async function optionalSkeletonSet(file) {
|
|
8891
|
+
if (!existsSync4(file)) return null;
|
|
8892
|
+
const bytes = await readFile3(file);
|
|
8893
|
+
let json;
|
|
8894
|
+
try {
|
|
8895
|
+
json = JSON.parse(bytes.toString("utf8"));
|
|
8896
|
+
} catch (error) {
|
|
8897
|
+
throw new Error(`revision keypoints file ${file} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
8898
|
+
}
|
|
8899
|
+
return { hash: sha256(bytes), skeleton: parseSkeletonSet(json, file) };
|
|
8900
|
+
}
|
|
8617
8901
|
async function revisionSourceMembers(stem, label) {
|
|
8618
8902
|
if (existsSync4(stem)) return null;
|
|
8619
8903
|
const at = (role) => memberPath(stem, role, 0, 2, MediaType.PNG);
|
|
@@ -10263,6 +10547,7 @@ async function inspectRevisionReadiness(spec, lock) {
|
|
|
10263
10547
|
if (spec.character?.parentSpec) return inspectCharacterParent(spec, lock, /* @__PURE__ */ new Set());
|
|
10264
10548
|
if (spec.character?.styleAnchor) return inspectStyleAnchor(spec, lock, /* @__PURE__ */ new Set());
|
|
10265
10549
|
if (spec.objectPro?.parentSpec) return inspectObjectProParent(spec, lock, /* @__PURE__ */ new Set());
|
|
10550
|
+
if (spec.scene) return inspectScene(spec);
|
|
10266
10551
|
if (!spec.revision) return null;
|
|
10267
10552
|
return inspectRevision(spec, lock, /* @__PURE__ */ new Set());
|
|
10268
10553
|
}
|
|
@@ -10280,6 +10565,16 @@ async function inspectStyleAnchor(spec, lock, seen) {
|
|
|
10280
10565
|
}
|
|
10281
10566
|
return { ready: true, reason: `${label} is current` };
|
|
10282
10567
|
}
|
|
10568
|
+
async function inspectScene(spec) {
|
|
10569
|
+
const scene = spec.scene;
|
|
10570
|
+
const files = [{ label: "scene image", file: scene.file, sha256: scene.sha256 }];
|
|
10571
|
+
if (scene.placement.type === "mask") files.push({ label: "scene mask", file: scene.placement.file, sha256: scene.placement.sha256 });
|
|
10572
|
+
for (const { label, file, sha256: sha2562 } of files) {
|
|
10573
|
+
if (!sha2562 || !existsSync7(file)) return { ready: false, reason: `${label} does not exist yet: ${file}` };
|
|
10574
|
+
if (await sha256File(file) !== sha2562) return { ready: false, reason: `${label} changed after the manifest was resolved` };
|
|
10575
|
+
}
|
|
10576
|
+
return { ready: true, reason: "scene is current" };
|
|
10577
|
+
}
|
|
10283
10578
|
async function inspectMirror(spec, lock, seen) {
|
|
10284
10579
|
const source = spec.mirror.sourceSpec;
|
|
10285
10580
|
const label = `mirror source ${spec.styleId}/${spec.mirror.sourceAssetId}`;
|
|
@@ -10736,47 +11031,47 @@ import path14 from "path";
|
|
|
10736
11031
|
import { existsSync as existsSync9 } from "fs";
|
|
10737
11032
|
import { readdir, readFile as readFile7 } from "fs/promises";
|
|
10738
11033
|
import { fileURLToPath } from "url";
|
|
10739
|
-
import { z as
|
|
11034
|
+
import { z as z4 } from "zod";
|
|
10740
11035
|
var SHA256_RE = /^[0-9a-f]{64}$/;
|
|
10741
11036
|
var RECIPE_ID_RE = /^[a-z0-9][a-z0-9-]*\/[a-z0-9][a-z0-9-]*$/;
|
|
10742
11037
|
var VERSION_RE = /^\d+\.\d+\.\d+$/;
|
|
10743
11038
|
var RECIPE_FILE = "pixelkiln.recipe.json";
|
|
10744
11039
|
var RECIPE_DIR_TOKEN = "{{recipeDir}}";
|
|
10745
|
-
var PortablePathSchema =
|
|
11040
|
+
var PortablePathSchema = z4.string().min(1).refine((value) => {
|
|
10746
11041
|
if (value.includes("\\") || path14.posix.isAbsolute(value)) return false;
|
|
10747
11042
|
const parts = value.split("/");
|
|
10748
11043
|
return !parts.includes("") && !parts.includes(".") && !parts.includes("..");
|
|
10749
11044
|
}, "expected a portable relative path without '.', '..', or backslashes");
|
|
10750
|
-
var RecipeBindingSchema =
|
|
10751
|
-
nodeId:
|
|
10752
|
-
input:
|
|
11045
|
+
var RecipeBindingSchema = z4.object({
|
|
11046
|
+
nodeId: z4.string().min(1),
|
|
11047
|
+
input: z4.string().min(1)
|
|
10753
11048
|
}).strict();
|
|
10754
|
-
var RecipeSchema =
|
|
10755
|
-
$schema:
|
|
10756
|
-
format:
|
|
10757
|
-
schemaVersion:
|
|
10758
|
-
id:
|
|
10759
|
-
version:
|
|
10760
|
-
provider:
|
|
10761
|
-
summary:
|
|
10762
|
-
files:
|
|
11049
|
+
var RecipeSchema = z4.object({
|
|
11050
|
+
$schema: z4.string().url().optional(),
|
|
11051
|
+
format: z4.literal("pixelkiln-recipe"),
|
|
11052
|
+
schemaVersion: z4.literal(1),
|
|
11053
|
+
id: z4.string().regex(RECIPE_ID_RE, "expected provider/name"),
|
|
11054
|
+
version: z4.string().regex(VERSION_RE, "expected x.y.z"),
|
|
11055
|
+
provider: z4.string().regex(/^[a-z0-9][a-z0-9-]*$/),
|
|
11056
|
+
summary: z4.string().min(1).max(240),
|
|
11057
|
+
files: z4.array(z4.object({
|
|
10763
11058
|
path: PortablePathSchema,
|
|
10764
|
-
role:
|
|
10765
|
-
sha256:
|
|
11059
|
+
role: z4.enum(["workflow", "reference"]),
|
|
11060
|
+
sha256: z4.string().regex(SHA256_RE)
|
|
10766
11061
|
}).strict()).default([]),
|
|
10767
|
-
models:
|
|
11062
|
+
models: z4.array(z4.object({
|
|
10768
11063
|
path: PortablePathSchema,
|
|
10769
|
-
sha256:
|
|
10770
|
-
source:
|
|
10771
|
-
license:
|
|
11064
|
+
sha256: z4.string().regex(SHA256_RE),
|
|
11065
|
+
source: z4.string().url(),
|
|
11066
|
+
license: z4.string().min(1)
|
|
10772
11067
|
}).strict()).default([]),
|
|
10773
|
-
styleId:
|
|
11068
|
+
styleId: z4.string().regex(/^[a-z0-9][a-z0-9-]*$/),
|
|
10774
11069
|
style: StyleSchema,
|
|
10775
|
-
workflow:
|
|
11070
|
+
workflow: z4.object({
|
|
10776
11071
|
path: PortablePathSchema,
|
|
10777
|
-
outputNodeId:
|
|
10778
|
-
numImages:
|
|
10779
|
-
bindings:
|
|
11072
|
+
outputNodeId: z4.string().min(1),
|
|
11073
|
+
numImages: z4.number().int().min(1).max(16),
|
|
11074
|
+
bindings: z4.object({
|
|
10780
11075
|
prompt: RecipeBindingSchema,
|
|
10781
11076
|
width: RecipeBindingSchema.optional(),
|
|
10782
11077
|
height: RecipeBindingSchema.optional(),
|
|
@@ -10787,67 +11082,67 @@ var RecipeSchema = z3.object({
|
|
|
10787
11082
|
strength: RecipeBindingSchema.optional()
|
|
10788
11083
|
}).strict()
|
|
10789
11084
|
}).strict().optional(),
|
|
10790
|
-
quality:
|
|
10791
|
-
stage:
|
|
10792
|
-
workingCanvas:
|
|
10793
|
-
width:
|
|
10794
|
-
height:
|
|
11085
|
+
quality: z4.object({
|
|
11086
|
+
stage: z4.enum(["composition-source", "production-candidate"]),
|
|
11087
|
+
workingCanvas: z4.object({
|
|
11088
|
+
width: z4.number().int().min(16),
|
|
11089
|
+
height: z4.number().int().min(16)
|
|
10795
11090
|
}).strict(),
|
|
10796
|
-
recommendedNativeSize:
|
|
10797
|
-
min:
|
|
10798
|
-
max:
|
|
11091
|
+
recommendedNativeSize: z4.object({
|
|
11092
|
+
min: z4.number().int().min(1),
|
|
11093
|
+
max: z4.number().int().min(1)
|
|
10799
11094
|
}).strict(),
|
|
10800
|
-
paletteColors:
|
|
10801
|
-
min:
|
|
10802
|
-
max:
|
|
11095
|
+
paletteColors: z4.object({
|
|
11096
|
+
min: z4.number().int().min(1),
|
|
11097
|
+
max: z4.number().int().min(1)
|
|
10803
11098
|
}).strict(),
|
|
10804
|
-
background:
|
|
10805
|
-
checks:
|
|
11099
|
+
background: z4.enum(["opaque", "transparent", "full-bleed"]),
|
|
11100
|
+
checks: z4.array(z4.enum([
|
|
10806
11101
|
"prompt-coverage",
|
|
10807
11102
|
"native-grid",
|
|
10808
11103
|
"final-palette",
|
|
10809
11104
|
"alpha-edge",
|
|
10810
11105
|
"human-1x"
|
|
10811
11106
|
])).min(1),
|
|
10812
|
-
notes:
|
|
11107
|
+
notes: z4.array(z4.string().min(1)).default([])
|
|
10813
11108
|
}).strict(),
|
|
10814
|
-
integrity:
|
|
10815
|
-
algorithm:
|
|
10816
|
-
digest:
|
|
11109
|
+
integrity: z4.object({
|
|
11110
|
+
algorithm: z4.literal("sha256"),
|
|
11111
|
+
digest: z4.string().regex(SHA256_RE)
|
|
10817
11112
|
}).strict()
|
|
10818
11113
|
}).strict().superRefine((recipe, context) => {
|
|
10819
11114
|
if (recipe.style.provider && recipe.style.provider !== recipe.provider) {
|
|
10820
11115
|
context.addIssue({
|
|
10821
|
-
code:
|
|
11116
|
+
code: z4.ZodIssueCode.custom,
|
|
10822
11117
|
path: ["style", "provider"],
|
|
10823
11118
|
message: "must match the recipe provider"
|
|
10824
11119
|
});
|
|
10825
11120
|
}
|
|
10826
11121
|
const filePaths = recipe.files.map((file) => file.path);
|
|
10827
11122
|
if (new Set(filePaths).size !== filePaths.length) {
|
|
10828
|
-
context.addIssue({ code:
|
|
11123
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["files"], message: "duplicate file path" });
|
|
10829
11124
|
}
|
|
10830
11125
|
const modelPaths = recipe.models.map((model) => model.path);
|
|
10831
11126
|
if (new Set(modelPaths).size !== modelPaths.length) {
|
|
10832
|
-
context.addIssue({ code:
|
|
11127
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["models"], message: "duplicate model path" });
|
|
10833
11128
|
}
|
|
10834
11129
|
if (filePaths.includes(RECIPE_FILE)) {
|
|
10835
11130
|
context.addIssue({
|
|
10836
|
-
code:
|
|
11131
|
+
code: z4.ZodIssueCode.custom,
|
|
10837
11132
|
path: ["files"],
|
|
10838
11133
|
message: `${RECIPE_FILE} cannot hash itself`
|
|
10839
11134
|
});
|
|
10840
11135
|
}
|
|
10841
11136
|
if (recipe.quality.recommendedNativeSize.min > recipe.quality.recommendedNativeSize.max) {
|
|
10842
11137
|
context.addIssue({
|
|
10843
|
-
code:
|
|
11138
|
+
code: z4.ZodIssueCode.custom,
|
|
10844
11139
|
path: ["quality", "recommendedNativeSize"],
|
|
10845
11140
|
message: "min cannot exceed max"
|
|
10846
11141
|
});
|
|
10847
11142
|
}
|
|
10848
11143
|
if (recipe.quality.paletteColors.min > recipe.quality.paletteColors.max) {
|
|
10849
11144
|
context.addIssue({
|
|
10850
|
-
code:
|
|
11145
|
+
code: z4.ZodIssueCode.custom,
|
|
10851
11146
|
path: ["quality", "paletteColors"],
|
|
10852
11147
|
message: "min cannot exceed max"
|
|
10853
11148
|
});
|
|
@@ -10856,7 +11151,7 @@ var RecipeSchema = z3.object({
|
|
|
10856
11151
|
(file) => file.path === recipe.workflow.path && file.role === "workflow"
|
|
10857
11152
|
)) {
|
|
10858
11153
|
context.addIssue({
|
|
10859
|
-
code:
|
|
11154
|
+
code: z4.ZodIssueCode.custom,
|
|
10860
11155
|
path: ["workflow", "path"],
|
|
10861
11156
|
message: "must name a file whose role is workflow"
|
|
10862
11157
|
});
|
|
@@ -10864,7 +11159,7 @@ var RecipeSchema = z3.object({
|
|
|
10864
11159
|
if (recipe.provider === "comfyui") {
|
|
10865
11160
|
if (!recipe.workflow) {
|
|
10866
11161
|
context.addIssue({
|
|
10867
|
-
code:
|
|
11162
|
+
code: z4.ZodIssueCode.custom,
|
|
10868
11163
|
path: ["workflow"],
|
|
10869
11164
|
message: "ComfyUI recipes require workflow metadata"
|
|
10870
11165
|
});
|
|
@@ -10873,7 +11168,7 @@ var RecipeSchema = z3.object({
|
|
|
10873
11168
|
const options = recipe.style.providerOptions.comfyui;
|
|
10874
11169
|
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
10875
11170
|
context.addIssue({
|
|
10876
|
-
code:
|
|
11171
|
+
code: z4.ZodIssueCode.custom,
|
|
10877
11172
|
path: ["style", "providerOptions", "comfyui"],
|
|
10878
11173
|
message: "ComfyUI recipes require ComfyUI provider options"
|
|
10879
11174
|
});
|
|
@@ -10887,7 +11182,7 @@ var RecipeSchema = z3.object({
|
|
|
10887
11182
|
};
|
|
10888
11183
|
if (JSON.stringify(canonical3(options)) !== JSON.stringify(canonical3(expected))) {
|
|
10889
11184
|
context.addIssue({
|
|
10890
|
-
code:
|
|
11185
|
+
code: z4.ZodIssueCode.custom,
|
|
10891
11186
|
path: ["style", "providerOptions", "comfyui"],
|
|
10892
11187
|
message: "must match workflow metadata and use {{recipeDir}} for workflowFile"
|
|
10893
11188
|
});
|
|
@@ -11325,11 +11620,11 @@ async function generateFont(client2, opts) {
|
|
|
11325
11620
|
import path17 from "path";
|
|
11326
11621
|
import { existsSync as existsSync12 } from "fs";
|
|
11327
11622
|
import { readFile as readFile10 } from "fs/promises";
|
|
11328
|
-
import { z as
|
|
11623
|
+
import { z as z5 } from "zod";
|
|
11329
11624
|
var SHA256_RE2 = /^[0-9a-f]{64}$/;
|
|
11330
11625
|
var HEX_RE = /^#[0-9a-f]{6}$/;
|
|
11331
11626
|
var MAX_REDMEAN_DISTANCE = 765;
|
|
11332
|
-
var QualityPathSchema =
|
|
11627
|
+
var QualityPathSchema = z5.string().min(1).refine(
|
|
11333
11628
|
(value) => !path17.posix.isAbsolute(value) && !value.includes("\\"),
|
|
11334
11629
|
"expected a portable relative path"
|
|
11335
11630
|
);
|
|
@@ -11343,53 +11638,53 @@ var DEFAULT_QUALITY_TOLERANCES = {
|
|
|
11343
11638
|
maxEdgeContrastDrop: 0.03,
|
|
11344
11639
|
maxIsolatedPixelIncrease: 5e-3
|
|
11345
11640
|
};
|
|
11346
|
-
var QualityToleranceSchema =
|
|
11347
|
-
requireExactHash:
|
|
11348
|
-
maxColorCountIncrease:
|
|
11349
|
-
maxNewColors:
|
|
11350
|
-
maxTransparencyDelta:
|
|
11351
|
-
maxPartialAlphaIncrease:
|
|
11352
|
-
maxEdgeDensityDelta:
|
|
11353
|
-
maxEdgeContrastDrop:
|
|
11354
|
-
maxIsolatedPixelIncrease:
|
|
11641
|
+
var QualityToleranceSchema = z5.object({
|
|
11642
|
+
requireExactHash: z5.boolean(),
|
|
11643
|
+
maxColorCountIncrease: z5.number().int().min(0),
|
|
11644
|
+
maxNewColors: z5.number().int().min(0),
|
|
11645
|
+
maxTransparencyDelta: z5.number().min(0).max(1),
|
|
11646
|
+
maxPartialAlphaIncrease: z5.number().min(0).max(1),
|
|
11647
|
+
maxEdgeDensityDelta: z5.number().min(0).max(1),
|
|
11648
|
+
maxEdgeContrastDrop: z5.number().min(0).max(1),
|
|
11649
|
+
maxIsolatedPixelIncrease: z5.number().min(0).max(1)
|
|
11355
11650
|
}).strict();
|
|
11356
|
-
var ImageQualityMetricsSchema =
|
|
11357
|
-
sha256:
|
|
11358
|
-
width:
|
|
11359
|
-
height:
|
|
11360
|
-
colorCount:
|
|
11361
|
-
colors:
|
|
11362
|
-
transparency:
|
|
11363
|
-
partialAlpha:
|
|
11364
|
-
edgeDensity:
|
|
11365
|
-
meanEdgeContrast:
|
|
11366
|
-
isolatedPixelRatio:
|
|
11651
|
+
var ImageQualityMetricsSchema = z5.object({
|
|
11652
|
+
sha256: z5.string().regex(SHA256_RE2),
|
|
11653
|
+
width: z5.number().int().min(1),
|
|
11654
|
+
height: z5.number().int().min(1),
|
|
11655
|
+
colorCount: z5.number().int().min(0),
|
|
11656
|
+
colors: z5.array(z5.string().regex(HEX_RE)),
|
|
11657
|
+
transparency: z5.number().min(0).max(1),
|
|
11658
|
+
partialAlpha: z5.number().min(0).max(1),
|
|
11659
|
+
edgeDensity: z5.number().min(0).max(1),
|
|
11660
|
+
meanEdgeContrast: z5.number().min(0).max(1),
|
|
11661
|
+
isolatedPixelRatio: z5.number().min(0).max(1)
|
|
11367
11662
|
}).strict();
|
|
11368
|
-
var QualityBaselineCaseSchema =
|
|
11369
|
-
id:
|
|
11663
|
+
var QualityBaselineCaseSchema = z5.object({
|
|
11664
|
+
id: z5.string().regex(/^[a-z0-9][a-z0-9/_-]*$/),
|
|
11370
11665
|
file: QualityPathSchema,
|
|
11371
|
-
record:
|
|
11666
|
+
record: z5.object({
|
|
11372
11667
|
path: QualityPathSchema,
|
|
11373
|
-
sha256:
|
|
11668
|
+
sha256: z5.string().regex(SHA256_RE2)
|
|
11374
11669
|
}).strict().optional(),
|
|
11375
11670
|
expected: ImageQualityMetricsSchema,
|
|
11376
11671
|
tolerances: QualityToleranceSchema
|
|
11377
11672
|
}).strict();
|
|
11378
|
-
var QualityBaselineSchema =
|
|
11379
|
-
$schema:
|
|
11380
|
-
format:
|
|
11381
|
-
schemaVersion:
|
|
11382
|
-
cases:
|
|
11673
|
+
var QualityBaselineSchema = z5.object({
|
|
11674
|
+
$schema: z5.string().url().optional(),
|
|
11675
|
+
format: z5.literal("pixelkiln-quality-baseline"),
|
|
11676
|
+
schemaVersion: z5.literal(1),
|
|
11677
|
+
cases: z5.array(QualityBaselineCaseSchema).min(1)
|
|
11383
11678
|
}).strict().superRefine((baseline, context) => {
|
|
11384
11679
|
const ids = baseline.cases.map((entry) => entry.id);
|
|
11385
11680
|
if (new Set(ids).size !== ids.length) {
|
|
11386
|
-
context.addIssue({ code:
|
|
11681
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["cases"], message: "duplicate case id" });
|
|
11387
11682
|
}
|
|
11388
11683
|
});
|
|
11389
|
-
var QualityInputSchema =
|
|
11390
|
-
id:
|
|
11391
|
-
path:
|
|
11392
|
-
record:
|
|
11684
|
+
var QualityInputSchema = z5.object({
|
|
11685
|
+
id: z5.string().regex(/^[a-z0-9][a-z0-9/_-]*$/),
|
|
11686
|
+
path: z5.string().min(1),
|
|
11687
|
+
record: z5.string().min(1).optional(),
|
|
11393
11688
|
tolerances: QualityToleranceSchema.partial().optional()
|
|
11394
11689
|
}).strict();
|
|
11395
11690
|
function message4(error) {
|
|
@@ -11491,7 +11786,7 @@ async function measureImageQuality(file) {
|
|
|
11491
11786
|
}
|
|
11492
11787
|
}
|
|
11493
11788
|
function resolveQualityInputs(raw, inputsFilePath) {
|
|
11494
|
-
const parsed =
|
|
11789
|
+
const parsed = z5.array(QualityInputSchema).min(1).safeParse(raw);
|
|
11495
11790
|
if (!parsed.success) {
|
|
11496
11791
|
throw new Error(
|
|
11497
11792
|
"--inputs must be a non-empty JSON array of quality cases:\n" + parsed.error.issues.map((issue) => ` ${issue.path.join(".") || "$"}: ${issue.message}`).join("\n")
|
|
@@ -11714,11 +12009,11 @@ import path20 from "path";
|
|
|
11714
12009
|
import { mkdir as mkdir5, readFile as readFile11, rename as rename4, rm as rm4, writeFile as writeFile5 } from "fs/promises";
|
|
11715
12010
|
import { existsSync as existsSync13 } from "fs";
|
|
11716
12011
|
import pathModule from "path";
|
|
11717
|
-
import { z as
|
|
11718
|
-
var HashCacheSchema =
|
|
11719
|
-
version:
|
|
12012
|
+
import { z as z6 } from "zod";
|
|
12013
|
+
var HashCacheSchema = z6.object({
|
|
12014
|
+
version: z6.literal(1),
|
|
11720
12015
|
/** objectId → sha256 of that object's image bytes. */
|
|
11721
|
-
hashes:
|
|
12016
|
+
hashes: z6.record(z6.string())
|
|
11722
12017
|
});
|
|
11723
12018
|
var SHA256_HEX = /^[a-f0-9]{64}$/;
|
|
11724
12019
|
function isSha256Hash(value) {
|
|
@@ -13266,6 +13561,9 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
|
|
|
13266
13561
|
...spec.revision.lastFrameSha256 ? { lastFrameSha256: spec.revision.lastFrameSha256 } : {},
|
|
13267
13562
|
...spec.revision.direction ? { direction: spec.revision.direction } : {},
|
|
13268
13563
|
...spec.revision.enhancePrompt == null ? {} : { enhancePrompt: spec.revision.enhancePrompt },
|
|
13564
|
+
...spec.revision.keypointsSha256 ? { keypointsSha256: spec.revision.keypointsSha256 } : {},
|
|
13565
|
+
...spec.revision.skeletonTemplate ? { skeletonTemplate: spec.revision.skeletonTemplate } : {},
|
|
13566
|
+
...spec.revision.description ? { description: spec.revision.description } : {},
|
|
13269
13567
|
...spec.revision.engine ? { engine: spec.revision.engine } : {}
|
|
13270
13568
|
} : null,
|
|
13271
13569
|
outfit: spec.character?.kind === "outfit" && outfitParentEntry ? {
|
|
@@ -14563,20 +14861,20 @@ import path29 from "path";
|
|
|
14563
14861
|
import { mkdir as mkdir7, readFile as readFile18, rename as rename6, rm as rm7, writeFile as writeFile9 } from "fs/promises";
|
|
14564
14862
|
import { existsSync as existsSync21 } from "fs";
|
|
14565
14863
|
import path25 from "path";
|
|
14566
|
-
import { z as
|
|
14567
|
-
var WorkspaceProjectSchema =
|
|
14568
|
-
id:
|
|
14864
|
+
import { z as z7 } from "zod";
|
|
14865
|
+
var WorkspaceProjectSchema = z7.object({
|
|
14866
|
+
id: z7.string().min(1),
|
|
14569
14867
|
/** Manifest path, relative to the catalog file's own directory. */
|
|
14570
|
-
manifest:
|
|
14868
|
+
manifest: z7.string().min(1),
|
|
14571
14869
|
/** Lockfile path, relative to the catalog file's own directory. */
|
|
14572
|
-
lock:
|
|
14573
|
-
provider:
|
|
14870
|
+
lock: z7.string().min(1),
|
|
14871
|
+
provider: z7.string().min(1).default("pixellab"),
|
|
14574
14872
|
/** Free-form label for a shared account, e.g. distinguishing sandboxes. */
|
|
14575
|
-
account:
|
|
14873
|
+
account: z7.string().optional()
|
|
14576
14874
|
}).strict();
|
|
14577
|
-
var WorkspaceSchema =
|
|
14578
|
-
version:
|
|
14579
|
-
projects:
|
|
14875
|
+
var WorkspaceSchema = z7.object({
|
|
14876
|
+
version: z7.literal(1),
|
|
14877
|
+
projects: z7.array(WorkspaceProjectSchema).default([])
|
|
14580
14878
|
}).strict();
|
|
14581
14879
|
function parseWorkspace(raw) {
|
|
14582
14880
|
const parsed = WorkspaceSchema.safeParse(raw);
|
|
@@ -14694,62 +14992,62 @@ function validateWorkspace(ws, dir) {
|
|
|
14694
14992
|
|
|
14695
14993
|
// src/gallery/edit.ts
|
|
14696
14994
|
import path28 from "path";
|
|
14697
|
-
import { z as
|
|
14995
|
+
import { z as z10 } from "zod";
|
|
14698
14996
|
|
|
14699
14997
|
// src/manifest-edit.ts
|
|
14700
14998
|
import { readFile as readFile19, rename as rename7, rm as rm8, writeFile as writeFile10 } from "fs/promises";
|
|
14701
14999
|
import path26 from "path";
|
|
14702
|
-
import { z as
|
|
14703
|
-
var HexSha =
|
|
14704
|
-
var AssetPatchSchema =
|
|
14705
|
-
prompt:
|
|
15000
|
+
import { z as z8 } from "zod";
|
|
15001
|
+
var HexSha = z8.string().regex(/^[0-9a-f]{64}$/);
|
|
15002
|
+
var AssetPatchSchema = z8.object({
|
|
15003
|
+
prompt: z8.string().optional(),
|
|
14706
15004
|
/** Per-style override for the style being viewed; null removes it. */
|
|
14707
|
-
promptForStyle:
|
|
14708
|
-
category:
|
|
14709
|
-
width:
|
|
14710
|
-
height:
|
|
14711
|
-
size:
|
|
14712
|
-
tags:
|
|
15005
|
+
promptForStyle: z8.object({ styleId: z8.string().min(1), prompt: z8.string().nullable() }).optional(),
|
|
15006
|
+
category: z8.string().nullable().optional(),
|
|
15007
|
+
width: z8.number().int().nullable().optional(),
|
|
15008
|
+
height: z8.number().int().nullable().optional(),
|
|
15009
|
+
size: z8.number().int().nullable().optional(),
|
|
15010
|
+
tags: z8.array(z8.string()).optional()
|
|
14713
15011
|
}).strict();
|
|
14714
|
-
var NewStateSchema =
|
|
15012
|
+
var NewStateSchema = z8.object({
|
|
14715
15013
|
/** Asset id of the parent this states; must already exist. */
|
|
14716
|
-
of:
|
|
14717
|
-
paletteFromReference:
|
|
14718
|
-
canvas:
|
|
15014
|
+
of: z8.string().min(1),
|
|
15015
|
+
paletteFromReference: z8.boolean().optional(),
|
|
15016
|
+
canvas: z8.object({ width: z8.number().int().min(16).max(256), height: z8.number().int().min(16).max(256) }).strict().optional()
|
|
14719
15017
|
}).strict();
|
|
14720
|
-
var NewAnimationSchema =
|
|
15018
|
+
var NewAnimationSchema = z8.object({
|
|
14721
15019
|
/** Asset id of the parent this animates; must already exist. */
|
|
14722
|
-
of:
|
|
15020
|
+
of: z8.string().min(1),
|
|
14723
15021
|
/** A PixelLab template id (`character` only; `objectPro` has no template concept). */
|
|
14724
|
-
template:
|
|
15022
|
+
template: z8.string().min(1).optional(),
|
|
14725
15023
|
direction: CharacterDirectionSchema.optional(),
|
|
14726
|
-
frames:
|
|
14727
|
-
fps:
|
|
15024
|
+
frames: z8.number().int().min(4).max(16).optional(),
|
|
15025
|
+
fps: z8.number().int().min(1).max(60).optional(),
|
|
14728
15026
|
mode: CharacterAnimationModeSchema.optional(),
|
|
14729
15027
|
/** What is being animated, when the parent's own description would mislead the model (`character` only). */
|
|
14730
|
-
subject:
|
|
14731
|
-
enhancePrompt:
|
|
15028
|
+
subject: z8.string().min(1).optional(),
|
|
15029
|
+
enhancePrompt: z8.boolean().optional()
|
|
14732
15030
|
}).strict();
|
|
14733
|
-
var NewAssetSchema =
|
|
14734
|
-
prompt:
|
|
14735
|
-
category:
|
|
14736
|
-
width:
|
|
14737
|
-
height:
|
|
14738
|
-
size:
|
|
14739
|
-
tags:
|
|
15031
|
+
var NewAssetSchema = z8.object({
|
|
15032
|
+
prompt: z8.string(),
|
|
15033
|
+
category: z8.string().optional(),
|
|
15034
|
+
width: z8.number().int().optional(),
|
|
15035
|
+
height: z8.number().int().optional(),
|
|
15036
|
+
size: z8.number().int().optional(),
|
|
15037
|
+
tags: z8.array(z8.string()).optional(),
|
|
14740
15038
|
/** Restrict to these styles; empty or omitted means every style. */
|
|
14741
|
-
styles:
|
|
15039
|
+
styles: z8.array(z8.string().min(1)).optional(),
|
|
14742
15040
|
/**
|
|
14743
15041
|
* A controlled regeneration of another asset in the same manifest,
|
|
14744
15042
|
* instead of a fresh generation. `inpaint` needs a mask upload the
|
|
14745
15043
|
* gallery does not offer yet, so only `image-to-image` can be created
|
|
14746
15044
|
* here; hand-edit the manifest for the other modes.
|
|
14747
15045
|
*/
|
|
14748
|
-
revision:
|
|
14749
|
-
mode:
|
|
15046
|
+
revision: z8.object({
|
|
15047
|
+
mode: z8.literal("image-to-image"),
|
|
14750
15048
|
/** Asset id of the parent this revises; must already exist. */
|
|
14751
|
-
from:
|
|
14752
|
-
strength:
|
|
15049
|
+
from: z8.string().min(1),
|
|
15050
|
+
strength: z8.number().min(0).max(1).optional()
|
|
14753
15051
|
}).strict().optional(),
|
|
14754
15052
|
/** A pose or outfit of an existing `character`/`objectPro` base or state. */
|
|
14755
15053
|
state: NewStateSchema.optional(),
|
|
@@ -14765,58 +15063,58 @@ var CANDIDATE_OPTION = {
|
|
|
14765
15063
|
comfyui: "numImages",
|
|
14766
15064
|
scenario: "numOutputs"
|
|
14767
15065
|
};
|
|
14768
|
-
var ManifestEditSchema =
|
|
14769
|
-
|
|
14770
|
-
action:
|
|
15066
|
+
var ManifestEditSchema = z8.discriminatedUnion("action", [
|
|
15067
|
+
z8.object({
|
|
15068
|
+
action: z8.literal("patch-asset"),
|
|
14771
15069
|
/** Workspace project id; omitted for a single-project gallery. */
|
|
14772
|
-
project:
|
|
14773
|
-
assetId:
|
|
15070
|
+
project: z8.string().min(1).optional(),
|
|
15071
|
+
assetId: z8.string().min(1),
|
|
14774
15072
|
/** Manifest bytes the page last saw; a mismatch refuses the write. */
|
|
14775
15073
|
expectedSha256: HexSha,
|
|
14776
15074
|
patch: AssetPatchSchema
|
|
14777
15075
|
}).strict(),
|
|
14778
|
-
|
|
14779
|
-
action:
|
|
14780
|
-
project:
|
|
14781
|
-
assetId:
|
|
15076
|
+
z8.object({
|
|
15077
|
+
action: z8.literal("add-asset"),
|
|
15078
|
+
project: z8.string().min(1).optional(),
|
|
15079
|
+
assetId: z8.string().min(1).regex(/^[^/\\]+$/, "asset ids cannot contain slashes"),
|
|
14782
15080
|
expectedSha256: HexSha,
|
|
14783
15081
|
asset: NewAssetSchema
|
|
14784
15082
|
}).strict(),
|
|
14785
|
-
|
|
14786
|
-
action:
|
|
14787
|
-
project:
|
|
14788
|
-
assetId:
|
|
14789
|
-
styleId:
|
|
15083
|
+
z8.object({
|
|
15084
|
+
action: z8.literal("set-source"),
|
|
15085
|
+
project: z8.string().min(1).optional(),
|
|
15086
|
+
assetId: z8.string().min(1),
|
|
15087
|
+
styleId: z8.string().min(1),
|
|
14790
15088
|
/** Manifest-relative path of the art that stands in for this asset in this style. */
|
|
14791
|
-
source:
|
|
15089
|
+
source: z8.string().min(1),
|
|
14792
15090
|
expectedSha256: HexSha
|
|
14793
15091
|
}).strict(),
|
|
14794
|
-
|
|
14795
|
-
action:
|
|
14796
|
-
project:
|
|
14797
|
-
assetId:
|
|
14798
|
-
styleId:
|
|
15092
|
+
z8.object({
|
|
15093
|
+
action: z8.literal("clear-source"),
|
|
15094
|
+
project: z8.string().min(1).optional(),
|
|
15095
|
+
assetId: z8.string().min(1),
|
|
15096
|
+
styleId: z8.string().min(1),
|
|
14799
15097
|
expectedSha256: HexSha
|
|
14800
15098
|
}).strict(),
|
|
14801
|
-
|
|
14802
|
-
action:
|
|
14803
|
-
project:
|
|
14804
|
-
styleId:
|
|
15099
|
+
z8.object({
|
|
15100
|
+
action: z8.literal("patch-style"),
|
|
15101
|
+
project: z8.string().min(1).optional(),
|
|
15102
|
+
styleId: z8.string().min(1),
|
|
14805
15103
|
expectedSha256: HexSha,
|
|
14806
|
-
patch:
|
|
15104
|
+
patch: z8.object({
|
|
14807
15105
|
/** Candidates per generation, written to the provider's own option. */
|
|
14808
|
-
candidates:
|
|
15106
|
+
candidates: z8.number().int().min(1).max(64).optional(),
|
|
14809
15107
|
/** Empty clears the style's own value (inherit, or the default). */
|
|
14810
|
-
promptPrefix:
|
|
14811
|
-
promptSuffix:
|
|
15108
|
+
promptPrefix: z8.string().optional(),
|
|
15109
|
+
promptSuffix: z8.string().optional(),
|
|
14812
15110
|
/** `#rrggbb` values; null or empty clears the style's own palette. */
|
|
14813
|
-
palette:
|
|
15111
|
+
palette: z8.array(z8.string().regex(/^#?[0-9a-f]{6}$/i, "expected a six-digit hex colour")).max(256).nullable().optional(),
|
|
14814
15112
|
/** Snap downloaded art to the palette; false clears the style's own value. */
|
|
14815
|
-
enforcePalette:
|
|
15113
|
+
enforcePalette: z8.boolean().optional(),
|
|
14816
15114
|
/** Provider view name (PixelLab: low top-down, high top-down, side); empty clears. */
|
|
14817
|
-
view:
|
|
15115
|
+
view: z8.string().max(64).nullable().optional(),
|
|
14818
15116
|
/** pixflux only; null clears the style's own value. */
|
|
14819
|
-
noBackground:
|
|
15117
|
+
noBackground: z8.boolean().nullable().optional()
|
|
14820
15118
|
}).strict().refine((patch) => Object.keys(patch).length > 0, { message: "nothing to change" })
|
|
14821
15119
|
}).strict()
|
|
14822
15120
|
]);
|
|
@@ -15010,7 +15308,7 @@ async function applyManifestEdit(manifestPath, edit) {
|
|
|
15010
15308
|
import { existsSync as existsSync22 } from "fs";
|
|
15011
15309
|
import { copyFile, mkdir as mkdir8, readFile as readFile20, rename as rename8, rm as rm9, writeFile as writeFile11 } from "fs/promises";
|
|
15012
15310
|
import path27 from "path";
|
|
15013
|
-
import { z as
|
|
15311
|
+
import { z as z9 } from "zod";
|
|
15014
15312
|
var HAND_EDIT_DIR = "edits";
|
|
15015
15313
|
function handEditPath(loaded, spec) {
|
|
15016
15314
|
const style = loaded.manifest.styles[spec.styleId];
|
|
@@ -15107,35 +15405,35 @@ async function detachHandEdit(loaded, spec, opts = {}) {
|
|
|
15107
15405
|
});
|
|
15108
15406
|
return { manifestSha256: result.sha256, changed: result.changed };
|
|
15109
15407
|
}
|
|
15110
|
-
var CompanionOutputSchema =
|
|
15408
|
+
var CompanionOutputSchema = z9.object({
|
|
15111
15409
|
/** Output role for a set member; null for a single image. */
|
|
15112
|
-
role:
|
|
15410
|
+
role: z9.string().nullable(),
|
|
15113
15411
|
/** sha256 of the generated file this member started from; null when it started from untracked art. */
|
|
15114
|
-
basedOn:
|
|
15412
|
+
basedOn: z9.string().regex(/^[0-9a-f]{64}$/).nullable(),
|
|
15115
15413
|
/** sha256 of the member as saved, so a later change by another tool is visible. */
|
|
15116
|
-
sha256:
|
|
15414
|
+
sha256: z9.string().regex(/^[0-9a-f]{64}$/)
|
|
15117
15415
|
}).strict();
|
|
15118
|
-
var CompanionV2Schema =
|
|
15119
|
-
version:
|
|
15416
|
+
var CompanionV2Schema = z9.object({
|
|
15417
|
+
version: z9.literal(2),
|
|
15120
15418
|
/** Editor identity the bridge reported, e.g. `pixelorama@v1.2.2-stable`. */
|
|
15121
|
-
editor:
|
|
15122
|
-
protocol:
|
|
15123
|
-
savedAt:
|
|
15419
|
+
editor: z9.string().min(1),
|
|
15420
|
+
protocol: z9.number().int().positive(),
|
|
15421
|
+
savedAt: z9.string().datetime(),
|
|
15124
15422
|
/** Basename of the layered project file beside the edit, when one was kept. */
|
|
15125
|
-
project:
|
|
15423
|
+
project: z9.string().min(1).nullable(),
|
|
15126
15424
|
/** One entry per file, in output order. */
|
|
15127
|
-
outputs:
|
|
15425
|
+
outputs: z9.array(CompanionOutputSchema).min(1)
|
|
15128
15426
|
}).strict();
|
|
15129
|
-
var CompanionV1Schema =
|
|
15130
|
-
version:
|
|
15131
|
-
basedOn:
|
|
15132
|
-
sha256:
|
|
15133
|
-
editor:
|
|
15134
|
-
protocol:
|
|
15135
|
-
savedAt:
|
|
15136
|
-
project:
|
|
15427
|
+
var CompanionV1Schema = z9.object({
|
|
15428
|
+
version: z9.literal(1),
|
|
15429
|
+
basedOn: z9.string().regex(/^[0-9a-f]{64}$/).nullable(),
|
|
15430
|
+
sha256: z9.string().regex(/^[0-9a-f]{64}$/),
|
|
15431
|
+
editor: z9.string().min(1),
|
|
15432
|
+
protocol: z9.number().int().positive(),
|
|
15433
|
+
savedAt: z9.string().datetime(),
|
|
15434
|
+
project: z9.string().min(1).nullable()
|
|
15137
15435
|
}).strict();
|
|
15138
|
-
var HandEditCompanionSchema =
|
|
15436
|
+
var HandEditCompanionSchema = z9.union([CompanionV2Schema, CompanionV1Schema]).transform(
|
|
15139
15437
|
(value) => value.version === 2 ? value : {
|
|
15140
15438
|
version: 2,
|
|
15141
15439
|
editor: value.editor,
|
|
@@ -15255,40 +15553,40 @@ function openInEditor(file, editor = process.env.PIXELKILN_EDITOR) {
|
|
|
15255
15553
|
}
|
|
15256
15554
|
|
|
15257
15555
|
// src/gallery/edit.ts
|
|
15258
|
-
var Base64 =
|
|
15259
|
-
var HandEditRequestSchema =
|
|
15260
|
-
|
|
15261
|
-
action:
|
|
15262
|
-
project:
|
|
15263
|
-
assetId:
|
|
15264
|
-
styleId:
|
|
15265
|
-
expectedSha256:
|
|
15556
|
+
var Base64 = z10.string().regex(/^[A-Za-z0-9+/]*={0,2}$/).max(Math.ceil(MAX_HAND_EDIT_BYTES / 3) * 4);
|
|
15557
|
+
var HandEditRequestSchema = z10.discriminatedUnion("action", [
|
|
15558
|
+
z10.object({
|
|
15559
|
+
action: z10.literal("start-edit"),
|
|
15560
|
+
project: z10.string().min(1).optional(),
|
|
15561
|
+
assetId: z10.string().min(1),
|
|
15562
|
+
styleId: z10.string().min(1),
|
|
15563
|
+
expectedSha256: z10.string().regex(/^[0-9a-f]{64}$/),
|
|
15266
15564
|
/** Also launch the author's editor on the file. */
|
|
15267
|
-
open:
|
|
15565
|
+
open: z10.boolean().optional()
|
|
15268
15566
|
}).strict(),
|
|
15269
|
-
|
|
15270
|
-
action:
|
|
15271
|
-
project:
|
|
15272
|
-
assetId:
|
|
15273
|
-
styleId:
|
|
15274
|
-
expectedSha256:
|
|
15567
|
+
z10.object({
|
|
15568
|
+
action: z10.literal("detach-edit"),
|
|
15569
|
+
project: z10.string().min(1).optional(),
|
|
15570
|
+
assetId: z10.string().min(1),
|
|
15571
|
+
styleId: z10.string().min(1),
|
|
15572
|
+
expectedSha256: z10.string().regex(/^[0-9a-f]{64}$/)
|
|
15275
15573
|
}).strict(),
|
|
15276
15574
|
/** From the in-browser editor: the page holds the bytes, the server validates and writes. */
|
|
15277
|
-
|
|
15278
|
-
action:
|
|
15279
|
-
project:
|
|
15280
|
-
assetId:
|
|
15281
|
-
styleId:
|
|
15282
|
-
expectedSha256:
|
|
15575
|
+
z10.object({
|
|
15576
|
+
action: z10.literal("save-edit"),
|
|
15577
|
+
project: z10.string().min(1).optional(),
|
|
15578
|
+
assetId: z10.string().min(1),
|
|
15579
|
+
styleId: z10.string().min(1),
|
|
15580
|
+
expectedSha256: z10.string().regex(/^[0-9a-f]{64}$/),
|
|
15283
15581
|
/** The flattened image; for a frame set, `frames` instead. */
|
|
15284
15582
|
png: Base64.min(1).optional(),
|
|
15285
15583
|
/** Every frame of a set, tagged with the role it was opened under (null for one added in the editor). */
|
|
15286
|
-
frames:
|
|
15584
|
+
frames: z10.array(z10.object({ role: z10.string().min(1).nullable(), png: Base64.min(1) }).strict()).min(1).max(256).optional(),
|
|
15287
15585
|
/** The editor's layered project file, kept beside the edit. */
|
|
15288
15586
|
pxo: Base64.optional(),
|
|
15289
15587
|
/** Editor identity from the bridge's ready message. */
|
|
15290
|
-
editor:
|
|
15291
|
-
protocol:
|
|
15588
|
+
editor: z10.string().min(1).max(200),
|
|
15589
|
+
protocol: z10.number().int().positive()
|
|
15292
15590
|
}).strict()
|
|
15293
15591
|
]);
|
|
15294
15592
|
function createGalleryEditHandler(opts) {
|
|
@@ -16622,27 +16920,27 @@ async function serveGallery(opts) {
|
|
|
16622
16920
|
|
|
16623
16921
|
// src/gallery/generate.ts
|
|
16624
16922
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
16625
|
-
import { z as
|
|
16626
|
-
var GenerateRequestSchema =
|
|
16627
|
-
project:
|
|
16628
|
-
keys:
|
|
16923
|
+
import { z as z11 } from "zod";
|
|
16924
|
+
var GenerateRequestSchema = z11.object({
|
|
16925
|
+
project: z11.string().min(1).optional(),
|
|
16926
|
+
keys: z11.array(z11.string().min(1)).min(1).max(500),
|
|
16629
16927
|
/**
|
|
16630
16928
|
* Regenerate work that is up to date, as `gen --force` does, and let the
|
|
16631
16929
|
* fetch replace a locally modified or untracked file. With `restore`, put
|
|
16632
16930
|
* the recorded bytes back over a modified file.
|
|
16633
16931
|
*/
|
|
16634
|
-
force:
|
|
16932
|
+
force: z11.boolean().optional(),
|
|
16635
16933
|
/** Advance in-flight, review, or selected work without submitting anything. */
|
|
16636
|
-
resume:
|
|
16934
|
+
resume: z11.boolean().optional(),
|
|
16637
16935
|
/** Re-download downloaded outputs and replace files whose object changed upstream. */
|
|
16638
|
-
refresh:
|
|
16936
|
+
refresh: z11.boolean().optional(),
|
|
16639
16937
|
/** Put recorded outputs back on disk from the cache or the provider, without generating. */
|
|
16640
|
-
restore:
|
|
16938
|
+
restore: z11.boolean().optional(),
|
|
16641
16939
|
/**
|
|
16642
16940
|
* Bring a replaced generation back: 1-based position in the record's
|
|
16643
16941
|
* history (newest first) or an output hash prefix. One key at a time.
|
|
16644
16942
|
*/
|
|
16645
|
-
revert:
|
|
16943
|
+
revert: z11.string().min(1).max(64).optional()
|
|
16646
16944
|
}).strict().refine((request) => [request.resume, request.refresh, request.restore, request.revert !== void 0].filter(Boolean).length <= 1, {
|
|
16647
16945
|
message: "resume, refresh, restore, and revert are exclusive"
|
|
16648
16946
|
}).refine((request) => request.revert === void 0 || request.keys.length === 1, { message: "revert takes one key" });
|
|
@@ -17645,6 +17943,8 @@ export {
|
|
|
17645
17943
|
ManifestEditSchema,
|
|
17646
17944
|
ManifestInputSchema,
|
|
17647
17945
|
ManifestSchema,
|
|
17946
|
+
MapScenePlacementSchema,
|
|
17947
|
+
MapSceneSchema,
|
|
17648
17948
|
MediaType,
|
|
17649
17949
|
OverwriteRefusedError,
|
|
17650
17950
|
PIXEL_ART_FIXER_REVISION,
|