pixelkiln 0.70.1 → 0.72.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/PROVIDERS.md +1 -1
- package/dist/cli.js +70 -15
- package/dist/cli.js.map +1 -1
- package/dist/client/gallery.css +15 -0
- package/dist/client/gallery.js +369 -9
- package/dist/index.cjs +70 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +88 -55
- package/dist/index.d.ts +88 -55
- package/dist/index.js +70 -15
- package/dist/index.js.map +1 -1
- package/docs/CHARACTERS.md +13 -0
- package/docs/GENERATORS.md +1 -1
- package/docs/REVISIONS.md +11 -3
- package/package.json +1 -1
- package/schema/manifest.schema.json +1 -0
- package/skills/pixelkiln/references/pixellab-roadmap.md +6 -0
- package/skills/pixelkiln/references/pixellab.md +8 -1
- package/skills/pixelkiln/references/revisions.md +3 -2
package/dist/index.js
CHANGED
|
@@ -125,7 +125,7 @@ var CharacterProportionsSchema = z.union([
|
|
|
125
125
|
hipWidth: z.number().min(0.5).max(2).optional()
|
|
126
126
|
}).strict()
|
|
127
127
|
]);
|
|
128
|
-
var CharacterAnimationModeSchema = z.enum(["template", "v3", "pro"]);
|
|
128
|
+
var CharacterAnimationModeSchema = z.enum(["template", "skeleton-v3", "v3", "pro"]);
|
|
129
129
|
var UiPieceSchema = z.discriminatedUnion("kind", [
|
|
130
130
|
z.object({
|
|
131
131
|
id: z.string().min(1),
|
|
@@ -239,7 +239,11 @@ var CharacterAnimationSchema = z.object({
|
|
|
239
239
|
fps: z.number().int().min(1).max(60).default(8),
|
|
240
240
|
/** v3 only: keep the resting pose as frame 0, so `frames` generated frames land as `frames + 1` files. */
|
|
241
241
|
keepFirstFrame: z.boolean().default(true),
|
|
242
|
-
/**
|
|
242
|
+
/**
|
|
243
|
+
* `template` when a template is named, otherwise `v3`; `skeleton-v3`
|
|
244
|
+
* poses a template with PixelLab's skeleton model instead; `pro` for the
|
|
245
|
+
* sequential high-quality engine.
|
|
246
|
+
*/
|
|
243
247
|
mode: CharacterAnimationModeSchema.optional(),
|
|
244
248
|
/**
|
|
245
249
|
* v3 only: a manifest-relative image of the pose to start from, instead
|
|
@@ -276,7 +280,7 @@ var CharacterAnimationSchema = z.object({
|
|
|
276
280
|
if (animation[key] !== void 0 && mode2 !== "v3") {
|
|
277
281
|
context.addIssue({
|
|
278
282
|
code: z.ZodIssueCode.custom,
|
|
279
|
-
message: `${key} is for v3 loops; a ${mode2} loop ${mode2 === "template" ? "starts from the character's rotation and follows its template" : "takes neither"}`,
|
|
283
|
+
message: `${key} is for v3 loops; a ${mode2} loop ${mode2 === "template" || mode2 === "skeleton-v3" ? "starts from the character's rotation and follows its template" : "takes neither"}`,
|
|
280
284
|
path: [key]
|
|
281
285
|
});
|
|
282
286
|
}
|
|
@@ -286,10 +290,10 @@ var CharacterAnimationSchema = z.object({
|
|
|
286
290
|
context.addIssue({ code: z.ZodIssueCode.custom, message: `${key} overrides apply to template loops only`, path: [key] });
|
|
287
291
|
}
|
|
288
292
|
}
|
|
289
|
-
if (animation.template && animation.mode && animation.mode !== "template") {
|
|
293
|
+
if (animation.template && animation.mode && animation.mode !== "template" && animation.mode !== "skeleton-v3") {
|
|
290
294
|
context.addIssue({
|
|
291
295
|
code: z.ZodIssueCode.custom,
|
|
292
|
-
message: `a template animation cannot use mode "${animation.mode}"`,
|
|
296
|
+
message: `a template animation cannot use mode "${animation.mode}"; use "template" or "skeleton-v3"`,
|
|
293
297
|
path: ["mode"]
|
|
294
298
|
});
|
|
295
299
|
}
|
|
@@ -300,8 +304,8 @@ var CharacterAnimationSchema = z.object({
|
|
|
300
304
|
path: ["frames"]
|
|
301
305
|
});
|
|
302
306
|
}
|
|
303
|
-
if (!animation.template && animation.mode === "template") {
|
|
304
|
-
context.addIssue({ code: z.ZodIssueCode.custom, message:
|
|
307
|
+
if (!animation.template && (animation.mode === "template" || animation.mode === "skeleton-v3")) {
|
|
308
|
+
context.addIssue({ code: z.ZodIssueCode.custom, message: `${animation.mode} mode needs a template`, path: ["template"] });
|
|
305
309
|
}
|
|
306
310
|
});
|
|
307
311
|
var RevisionDitheringSchema = z.enum(["none", "2x2", "4x4", "8x8"]);
|
|
@@ -2235,12 +2239,20 @@ var PixelLabClient = class {
|
|
|
2235
2239
|
}
|
|
2236
2240
|
/**
|
|
2237
2241
|
* One animation of one character. Template mode costs a generation per
|
|
2238
|
-
* direction and fixes the frame count; v3
|
|
2239
|
-
* the
|
|
2242
|
+
* direction and fixes the frame count; skeleton-v3 poses the same template
|
|
2243
|
+
* with the skeleton video model (2-4 generations per direction); v3 draws
|
|
2244
|
+
* `frameCount` frames from the action text; pro is the sequential engine.
|
|
2245
|
+
* One job per direction.
|
|
2246
|
+
*
|
|
2247
|
+
* Every mode but skeleton-v3 goes to `/animate-character`, the path whose
|
|
2248
|
+
* shapes were measured live. skeleton-v3 is documented only on
|
|
2249
|
+
* `/characters/animations`, which takes the same request and answers with
|
|
2250
|
+
* the same job list (plus an `animation_group_id`).
|
|
2240
2251
|
*/
|
|
2241
2252
|
async animateCharacter(args) {
|
|
2242
2253
|
const encode = (image) => ({ type: "base64", base64: image.base64, format: image.format });
|
|
2243
|
-
const
|
|
2254
|
+
const endpoint = args.mode === "skeleton-v3" ? "/characters/animations" : "/animate-character";
|
|
2255
|
+
const raw = await this.request(endpoint, {
|
|
2244
2256
|
method: "POST",
|
|
2245
2257
|
body: JSON.stringify({
|
|
2246
2258
|
character_id: args.characterId,
|
|
@@ -2264,7 +2276,7 @@ var PixelLabClient = class {
|
|
|
2264
2276
|
...args.seed != null ? { seed: args.seed } : {}
|
|
2265
2277
|
})
|
|
2266
2278
|
});
|
|
2267
|
-
return validateResponse(AnimateSubmitSchema, raw,
|
|
2279
|
+
return validateResponse(AnimateSubmitSchema, raw, endpoint.slice(1));
|
|
2268
2280
|
}
|
|
2269
2281
|
/**
|
|
2270
2282
|
* A full-body sprite in, a bust portrait out (or the reverse, unused
|
|
@@ -3557,6 +3569,7 @@ function characterCost(spec) {
|
|
|
3557
3569
|
if (character.kind === "animation") {
|
|
3558
3570
|
const animation = character.animation;
|
|
3559
3571
|
if (animation.mode === "template") return 1;
|
|
3572
|
+
if (animation.mode === "skeleton-v3") return 4;
|
|
3560
3573
|
if (animation.mode === "v3") return Math.max(1, Math.ceil(px * animation.frames / 65536));
|
|
3561
3574
|
return generationCost(spec.width, spec.height, "1dir");
|
|
3562
3575
|
}
|
|
@@ -4149,7 +4162,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
4149
4162
|
`${spec.styleId}/${spec.assetId} animates "${character.animation.direction}", but its character has ${character.directions} directions: ${allowed.join(", ")}`
|
|
4150
4163
|
);
|
|
4151
4164
|
}
|
|
4152
|
-
if (character.animation.mode !== "template" && !spec.prompt.trim()) {
|
|
4165
|
+
if (character.animation.mode !== "template" && character.animation.mode !== "skeleton-v3" && !spec.prompt.trim()) {
|
|
4153
4166
|
throw new Error(`${spec.styleId}/${spec.assetId} needs a prompt describing the motion, or a template`);
|
|
4154
4167
|
}
|
|
4155
4168
|
}
|
|
@@ -9077,8 +9090,8 @@ async function resolveObjectProShape(assetId, asset, style, kind, files) {
|
|
|
9077
9090
|
);
|
|
9078
9091
|
}
|
|
9079
9092
|
}
|
|
9080
|
-
if (asset.animation.mode === "template") {
|
|
9081
|
-
throw new Error(`assets.${assetId}: objectPro animations have no "
|
|
9093
|
+
if (asset.animation.mode === "template" || asset.animation.mode === "skeleton-v3") {
|
|
9094
|
+
throw new Error(`assets.${assetId}: objectPro animations have no "${asset.animation.mode}" mode; use "v3" or "pro"`);
|
|
9082
9095
|
}
|
|
9083
9096
|
const pose = async (rel, what) => {
|
|
9084
9097
|
const image = await files.load(rel, what);
|
|
@@ -15623,6 +15636,15 @@ var SkeletonAnimationRequestSchema = z10.object({
|
|
|
15623
15636
|
/** Replace an existing `keypointsFile` with `set`. */
|
|
15624
15637
|
overwrite: z10.boolean().optional()
|
|
15625
15638
|
}).strict();
|
|
15639
|
+
var SkeletonKeypointsUpdateSchema = z10.object({
|
|
15640
|
+
action: z10.literal("update-skeleton-keypoints"),
|
|
15641
|
+
project: z10.string().min(1).optional(),
|
|
15642
|
+
styleId: z10.string().min(1),
|
|
15643
|
+
assetId: z10.string().min(1),
|
|
15644
|
+
/** The file's SHA-256 when the page loaded it; anything else on disk is a concurrent edit. */
|
|
15645
|
+
expectedSha256: z10.string().regex(/^[0-9a-f]{64}$/),
|
|
15646
|
+
set: SkeletonSetSchema
|
|
15647
|
+
}).strict();
|
|
15626
15648
|
async function createSkeletonAnimation(manifestPath, request) {
|
|
15627
15649
|
const root = path28.dirname(path28.resolve(manifestPath));
|
|
15628
15650
|
const file = path28.resolve(root, request.keypointsFile);
|
|
@@ -15668,6 +15690,26 @@ async function createSkeletonAnimation(manifestPath, request) {
|
|
|
15668
15690
|
throw error;
|
|
15669
15691
|
}
|
|
15670
15692
|
}
|
|
15693
|
+
async function updateSkeletonKeypoints(ctx, request) {
|
|
15694
|
+
const key = lockKey(request.styleId, request.assetId);
|
|
15695
|
+
const spec = ctx.specs.find((candidate) => lockKey(candidate.styleId, candidate.assetId) === key);
|
|
15696
|
+
if (!spec) throw new ManifestEditError(`"${key}" is not declared by the manifest`);
|
|
15697
|
+
const file = spec.revision?.mode === "animate-skeleton" ? spec.revision.keypointsFile : void 0;
|
|
15698
|
+
if (!file) throw new ManifestEditError(`${key} is not an animate-skeleton revision`);
|
|
15699
|
+
const relative = path28.relative(ctx.loaded.root, file);
|
|
15700
|
+
if (relative.startsWith("..") || path28.isAbsolute(relative)) {
|
|
15701
|
+
throw new ManifestEditError(`${key}'s keypoints file is outside the project; edit it by hand`);
|
|
15702
|
+
}
|
|
15703
|
+
const current = existsSync23(file) ? sha256(await readFile21(file)) : null;
|
|
15704
|
+
if (current !== request.expectedSha256) {
|
|
15705
|
+
throw Object.assign(
|
|
15706
|
+
new Error(`${relative.split(path28.sep).join("/")} changed on disk since this page loaded it; press Refresh and edit again`),
|
|
15707
|
+
{ status: 409 }
|
|
15708
|
+
);
|
|
15709
|
+
}
|
|
15710
|
+
await writeFile12(file, JSON.stringify(request.set, null, 2) + "\n");
|
|
15711
|
+
return relative.split(path28.sep).join("/");
|
|
15712
|
+
}
|
|
15671
15713
|
|
|
15672
15714
|
// src/gallery/edit.ts
|
|
15673
15715
|
var Base64 = z11.string().regex(/^[A-Za-z0-9+/]*={0,2}$/).max(Math.ceil(MAX_HAND_EDIT_BYTES / 3) * 4);
|
|
@@ -15744,6 +15786,18 @@ function createGalleryEditHandler(opts) {
|
|
|
15744
15786
|
}
|
|
15745
15787
|
return opts.reload();
|
|
15746
15788
|
}
|
|
15789
|
+
const poses = SkeletonKeypointsUpdateSchema.safeParse(body);
|
|
15790
|
+
if (poses.success) {
|
|
15791
|
+
if (!opts.loadProject) throw new ManifestEditError("pose edits are not available in this gallery");
|
|
15792
|
+
const written = await updateSkeletonKeypoints(await opts.loadProject(poses.data.project), poses.data);
|
|
15793
|
+
log(` poses saved: ${written} (${poses.data.styleId}/${poses.data.assetId} is stale until generated again)`);
|
|
15794
|
+
return opts.reload();
|
|
15795
|
+
}
|
|
15796
|
+
if (body?.action === "update-skeleton-keypoints") {
|
|
15797
|
+
throw new ManifestEditError(
|
|
15798
|
+
"invalid pose edit: " + poses.error.issues.slice(0, 3).map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ")
|
|
15799
|
+
);
|
|
15800
|
+
}
|
|
15747
15801
|
const skeleton = SkeletonAnimationRequestSchema.safeParse(body);
|
|
15748
15802
|
if (skeleton.success) {
|
|
15749
15803
|
let manifestPath2;
|
|
@@ -16117,7 +16171,8 @@ async function buildGallerySnapshot(opts) {
|
|
|
16117
16171
|
mirrorOfKey: spec.mirror ? lockKey(spec.styleId, spec.mirror.sourceAssetId) : entry?.mirror ? lockKey(spec.styleId, entry.mirror.sourceAssetId) : null,
|
|
16118
16172
|
skeleton: spec.revision?.mode === "animate-skeleton" && spec.revision.keypointsFile ? {
|
|
16119
16173
|
keypointsFile: portableOutputPath(spec.revision.keypointsFile, root),
|
|
16120
|
-
set: spec.revision.skeleton ?? null
|
|
16174
|
+
set: spec.revision.skeleton ?? null,
|
|
16175
|
+
sha256: spec.revision.keypointsSha256 ?? null
|
|
16121
16176
|
} : null,
|
|
16122
16177
|
character: describeCharacter(spec, entry),
|
|
16123
16178
|
outputs,
|