pixelkiln 0.89.6 → 0.90.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 CHANGED
@@ -1238,16 +1238,21 @@ var CharacterAnimationSchema = z.object({
1238
1238
  * `src/loop-directions.ts`.
1239
1239
  */
1240
1240
  directions: z.array(CharacterDirectionSchema).min(1).optional(),
1241
- /** Frames to generate without a template (v3). Even, 4 to 16. */
1242
- frames: z.number().int().min(4).max(16).optional(),
1241
+ /**
1242
+ * Frames to generate without a template. A v3 loop takes an even 4 to 16;
1243
+ * a sentence loop (`mode: "skeleton-v3"` with no `template`) takes 3 to 15.
1244
+ */
1245
+ frames: z.number().int().min(3).max(16).optional(),
1243
1246
  /** Playback rate recorded with the frames; PixelLab does not store one. */
1244
1247
  fps: z.number().int().min(1).max(60).default(8),
1245
1248
  /** v3 only: keep the resting pose as frame 0, so `frames` generated frames land as `frames + 1` files. */
1246
1249
  keepFirstFrame: z.boolean().default(true),
1247
1250
  /**
1248
1251
  * `template` when a template is named, otherwise `v3`; `skeleton-v3`
1249
- * poses a template with PixelLab's skeleton model instead; `pro` for the
1250
- * sequential high-quality engine.
1252
+ * poses a template with PixelLab's skeleton model instead, or, with no
1253
+ * template, animates the asset's prompt as a sentence written into one 3D
1254
+ * motion (a v3 base; 3-15 `frames`); `pro` for the sequential
1255
+ * high-quality engine.
1251
1256
  */
1252
1257
  mode: CharacterAnimationModeSchema.optional(),
1253
1258
  /**
@@ -1277,15 +1282,23 @@ var CharacterAnimationSchema = z.object({
1277
1282
  path: ["directions"]
1278
1283
  });
1279
1284
  }
1280
- if (animation.frames !== void 0 && animation.frames % 2 !== 0) {
1281
- context.addIssue({ code: z.ZodIssueCode.custom, message: "frames must be even", path: ["frames"] });
1285
+ const sentence = animation.mode === "skeleton-v3" && !animation.template;
1286
+ if (animation.frames !== void 0 && !sentence) {
1287
+ if (animation.frames % 2 !== 0) {
1288
+ context.addIssue({ code: z.ZodIssueCode.custom, message: "frames must be even", path: ["frames"] });
1289
+ } else if (animation.frames < 4) {
1290
+ context.addIssue({ code: z.ZodIssueCode.custom, message: "frames must be 4 to 16", path: ["frames"] });
1291
+ }
1292
+ }
1293
+ if (animation.frames !== void 0 && sentence && animation.frames > 15) {
1294
+ context.addIssue({ code: z.ZodIssueCode.custom, message: "a skeleton-v3 loop from a sentence takes 3 to 15 frames", path: ["frames"] });
1282
1295
  }
1283
1296
  const mode2 = animation.mode ?? (animation.template ? "template" : "v3");
1284
1297
  for (const key of ["startFrame", "endFrame", "enhancePrompt"]) {
1285
1298
  if (animation[key] !== void 0 && mode2 !== "v3") {
1286
1299
  context.addIssue({
1287
1300
  code: z.ZodIssueCode.custom,
1288
- 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"}`,
1301
+ message: `${key} is for v3 loops; a ${mode2} loop ${mode2 === "template" || mode2 === "skeleton-v3" ? `starts from the character's rotation and ${animation.template ? "follows its template" : "animates its sentence"}` : "takes neither"}`,
1289
1302
  path: [key]
1290
1303
  });
1291
1304
  }
@@ -1309,8 +1322,11 @@ var CharacterAnimationSchema = z.object({
1309
1322
  path: ["frames"]
1310
1323
  });
1311
1324
  }
1312
- if (!animation.template && (animation.mode === "template" || animation.mode === "skeleton-v3")) {
1313
- context.addIssue({ code: z.ZodIssueCode.custom, message: `${animation.mode} mode needs a template`, path: ["template"] });
1325
+ if (!animation.template && animation.mode === "template") {
1326
+ context.addIssue({ code: z.ZodIssueCode.custom, message: "template mode needs a template", path: ["template"] });
1327
+ }
1328
+ if (sentence && animation.subject !== void 0) {
1329
+ context.addIssue({ code: z.ZodIssueCode.custom, message: "subject does not apply to a skeleton-v3 loop from a sentence; describe the motion in the prompt", path: ["subject"] });
1314
1330
  }
1315
1331
  });
1316
1332
  var RevisionDitheringSchema = z.enum(["none", "2x2", "4x4", "8x8"]);
@@ -7258,7 +7274,10 @@ var PixelLabClient = class {
7258
7274
  * Every mode but skeleton-v3 goes to `/animate-character`, the path whose
7259
7275
  * shapes were measured live. skeleton-v3 is documented only on
7260
7276
  * `/characters/animations`, which takes the same request and answers with
7261
- * the same job list (plus an `animation_group_id`).
7277
+ * the same job list (plus an `animation_group_id`). With no `template` it
7278
+ * animates `actionDescription` as a sentence, 3 to 15 `frameCount` frames
7279
+ * written into one 3D motion; measured on a v3 character (8 frames, 64px:
7280
+ * 3 generations, frames back at 96x96).
7262
7281
  */
7263
7282
  async animateCharacter(args) {
7264
7283
  const encode = (image) => ({ type: "base64", base64: image.base64, format: image.format });
@@ -7273,7 +7292,8 @@ var PixelLabClient = class {
7273
7292
  ...args.template ? { template_animation_id: args.template } : {},
7274
7293
  ...args.actionDescription ? { action_description: args.actionDescription } : {},
7275
7294
  ...args.description ? { description: args.description } : {},
7276
- ...args.mode === "v3" && args.frameCount ? { frame_count: args.frameCount } : {},
7295
+ // A template fixes its own frame count; v3 and a skeleton-v3 sentence take one.
7296
+ ...(args.mode === "v3" || args.mode === "skeleton-v3" && !args.template) && args.frameCount ? { frame_count: args.frameCount } : {},
7277
7297
  ...args.mode === "v3" && args.keepFirstFrame === false ? { keep_first_frame: false } : {},
7278
7298
  ...args.mode === "v3" && args.startFrame ? { custom_start_frame: encode(args.startFrame) } : {},
7279
7299
  ...args.mode === "v3" && args.endFrame ? { end_frame: encode(args.endFrame) } : {},
@@ -9193,6 +9213,16 @@ var PixelLabProvider = class _PixelLabProvider {
9193
9213
  if (skeletonTemplate && !CHARACTER_TEMPLATES.includes(skeletonTemplate)) {
9194
9214
  throw new Error(`PixelLab animate-skeleton template "${skeletonTemplate}" is not one of ${CHARACTER_TEMPLATES.join(", ")}`);
9195
9215
  }
9216
+ if (!spec.revision.description?.trim()) {
9217
+ throw new Error(
9218
+ `${spec.styleId}/${spec.assetId}: an animate-skeleton revision needs revision.description, what the character looks like (for example "a knight in steel armour holding a sword"); PixelLab refuses the request without it`
9219
+ );
9220
+ }
9221
+ if (!spec.prompt.trim()) {
9222
+ throw new Error(
9223
+ `${spec.styleId}/${spec.assetId}: an animate-skeleton revision needs a prompt, a short motion label (for example "swinging the sword")`
9224
+ );
9225
+ }
9196
9226
  }
9197
9227
  if (spec.revision?.mode === "animate" || spec.revision?.mode === "animate-pixminimax") {
9198
9228
  const { sourceWidth: width, sourceHeight: height, mode: mode2, frames, lastFrameWidth, lastFrameHeight } = spec.revision;
@@ -9596,12 +9626,18 @@ var PixelLabProvider = class _PixelLabProvider {
9596
9626
  `${spec.styleId}/${spec.assetId} animates "${character.animation.direction}", but its character has ${character.directions} directions: ${allowed.join(", ")}`
9597
9627
  );
9598
9628
  }
9599
- if (character.animation.mode !== "template" && character.animation.mode !== "skeleton-v3" && !spec.prompt.trim()) {
9600
- throw new Error(`${spec.styleId}/${spec.assetId} needs a prompt describing the motion, or a template`);
9629
+ const sentence = character.animation.mode === "skeleton-v3" && !character.animation.template;
9630
+ if (character.animation.mode !== "template" && (character.animation.mode !== "skeleton-v3" || sentence) && !spec.prompt.trim()) {
9631
+ throw new Error(
9632
+ `${spec.styleId}/${spec.assetId} needs a prompt describing the motion, or a template` + (sentence ? ' (a skeleton-v3 loop with no template animates its prompt, e.g. "swinging a sword in a wide arc")' : "")
9633
+ );
9634
+ }
9635
+ if (sentence && (character.animation.frames < 3 || character.animation.frames > 15)) {
9636
+ throw new Error(`${spec.styleId}/${spec.assetId}: a skeleton-v3 loop from a sentence takes 3 to 15 frames; ${character.animation.frames} is out of range`);
9601
9637
  }
9602
9638
  if (character.animation.mode === "skeleton-v3" && character.mode === "standard") {
9603
9639
  throw new Error(
9604
- `${spec.styleId}/${spec.assetId}: skeleton-v3 poses a template onto a 3D skeleton, which a ${character.mode} character has none of; use a v3 base (style mode: "v3"), or mode: "template" for this loop`
9640
+ sentence ? `${spec.styleId}/${spec.assetId}: a skeleton-v3 loop from a sentence writes the motion onto a 3D skeleton, which a ${character.mode} character has none of; use a v3 base (style mode: "v3"), or mode: "template" with a template for this loop` : `${spec.styleId}/${spec.assetId}: skeleton-v3 poses a template onto a 3D skeleton, which a ${character.mode} character has none of; use a v3 base (style mode: "v3"), or mode: "template" for this loop`
9605
9641
  );
9606
9642
  }
9607
9643
  }
@@ -17029,7 +17065,8 @@ var SkeletonAnimationRequestSchema = z10.object({
17029
17065
  /** The motion, sent as PixelLab's `action`. */
17030
17066
  prompt: z10.string().min(1),
17031
17067
  direction: CharacterDirectionSchema,
17032
- description: z10.string().min(1).optional(),
17068
+ /** What the character looks like; PixelLab refuses the request without it. */
17069
+ description: z10.string().min(1),
17033
17070
  skeletonTemplate: z10.string().min(1).optional(),
17034
17071
  /** Manifest-relative JSON path inside the project. */
17035
17072
  keypointsFile: z10.string().min(1),
@@ -17136,7 +17173,7 @@ async function createSkeletonAnimation(manifestPath, request) {
17136
17173
  from: request.from,
17137
17174
  keypointsFile: relative.split(path31.sep).join("/"),
17138
17175
  direction: request.direction,
17139
- ...request.description ? { description: request.description } : {},
17176
+ description: request.description,
17140
17177
  ...request.skeletonTemplate ? { skeletonTemplate: request.skeletonTemplate } : {}
17141
17178
  }
17142
17179
  }