pixelkiln 0.89.2 → 0.89.4

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/index.d.cts CHANGED
@@ -21159,6 +21159,11 @@ interface SheetGroup {
21159
21159
  height: number;
21160
21160
  mode?: "candidates" | "frame-set";
21161
21161
  frameLabels?: string[];
21162
+ /** Each frame's own size where it could be read (a locally cached PNG); null or absent, the sheet reads it off the loaded image. */
21163
+ frameSizes?: ({
21164
+ width: number;
21165
+ height: number;
21166
+ } | null)[];
21162
21167
  fps?: number;
21163
21168
  revision?: {
21164
21169
  mode: RevisionMode;
package/dist/index.d.ts CHANGED
@@ -21159,6 +21159,11 @@ interface SheetGroup {
21159
21159
  height: number;
21160
21160
  mode?: "candidates" | "frame-set";
21161
21161
  frameLabels?: string[];
21162
+ /** Each frame's own size where it could be read (a locally cached PNG); null or absent, the sheet reads it off the loaded image. */
21163
+ frameSizes?: ({
21164
+ width: number;
21165
+ height: number;
21166
+ } | null)[];
21162
21167
  fps?: number;
21163
21168
  revision?: {
21164
21169
  mode: RevisionMode;
package/dist/index.js CHANGED
@@ -2056,7 +2056,8 @@ var PixelLabClient = class {
2056
2056
  });
2057
2057
  const text = await res.text();
2058
2058
  if (!res.ok) {
2059
- throw new PixelLabError(`${init?.method ?? "GET"} ${path39} \u2192 ${res.status}`, res.status, text);
2059
+ const hint = res.status === 500 && text.includes("Failed to start any animation jobs") ? '; a skeleton-v3 loop needs a character with a stored 3D skeleton (a v3 base), use mode: "template" on a standard one' : "";
2060
+ throw new PixelLabError(`${init?.method ?? "GET"} ${path39} \u2192 ${res.status}${hint}`, res.status, text);
2060
2061
  }
2061
2062
  if (!text) return {};
2062
2063
  try {
@@ -5682,6 +5683,11 @@ var PixelLabProvider = class _PixelLabProvider {
5682
5683
  if (character.animation.mode !== "template" && character.animation.mode !== "skeleton-v3" && !spec.prompt.trim()) {
5683
5684
  throw new Error(`${spec.styleId}/${spec.assetId} needs a prompt describing the motion, or a template`);
5684
5685
  }
5686
+ if (character.animation.mode === "skeleton-v3" && character.mode === "standard") {
5687
+ throw new Error(
5688
+ `${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`
5689
+ );
5690
+ }
5685
5691
  }
5686
5692
  }
5687
5693
  validateObjectPro(spec, styleImages = []) {
@@ -5988,7 +5994,10 @@ var PixelLabProvider = class _PixelLabProvider {
5988
5994
  stateName: character.state_name ?? null,
5989
5995
  directions: character.directions,
5990
5996
  size: character.size,
5991
- updatedAt: character.updated_at ?? null
5997
+ updatedAt: character.updated_at ?? null,
5998
+ // Kept: this metadata replaces the submit-time `character` entry,
5999
+ // and the job id is the only way to read the bill again later.
6000
+ ...backgroundJobId ? { backgroundJobId } : {}
5992
6001
  }
5993
6002
  },
5994
6003
  billed: await this.billedForJob(backgroundJobId)
@@ -6639,7 +6648,12 @@ var PixelLabProvider = class _PixelLabProvider {
6639
6648
  if (!backgroundJobId) return null;
6640
6649
  try {
6641
6650
  const job = await this.client.getBackgroundJob(backgroundJobId);
6642
- return billedFromUsage(job.usage);
6651
+ const nested = job.last_response?.billing_usage;
6652
+ for (const usage of [job.usage, nested]) {
6653
+ const billed = billedFromUsage(usage);
6654
+ if (billed && !(billed.unit === "usd" && billed.amount === 0)) return billed;
6655
+ }
6656
+ return null;
6643
6657
  } catch {
6644
6658
  return null;
6645
6659
  }
@@ -16639,8 +16653,18 @@ GROUPS.forEach((g, gi) => {
16639
16653
  preview.loading = 'lazy';
16640
16654
  const index = document.createElement('span');
16641
16655
  index.className = 'idx';
16642
- index.textContent = (g.frameLabels?.[i] || String(i + 1)) + ' \xB7 ' +
16643
- g.width + '\xD7' + g.height + ' \xB7 ' + scaleLabel;
16656
+ // A frame's own size, not the manifest's: a 96px loop of a 64px
16657
+ // character is 96\xD796. Known up front for a cached file, else once loaded.
16658
+ const label = (w, h) => {
16659
+ index.textContent = (g.frameLabels?.[i] || String(i + 1)) + ' \xB7 ' + w + '\xD7' + h + ' \xB7 ' + scaleLabel;
16660
+ };
16661
+ const known = g.frameSizes?.[i];
16662
+ label(known ? known.width : g.width, known ? known.height : g.height);
16663
+ if (!known) {
16664
+ preview.addEventListener('load', () => {
16665
+ if (preview.naturalWidth && preview.naturalHeight) label(preview.naturalWidth, preview.naturalHeight);
16666
+ }, { once: true });
16667
+ }
16644
16668
  c.append(preview, index);
16645
16669
  if (g.recommendedIndex != null && i === recommended) {
16646
16670
  const badge = document.createElement('span');
@@ -16902,12 +16926,15 @@ async function prepareReview(provider, lock, opts = {}) {
16902
16926
  const urls = state.status === "review" ? state.candidateUrls : state.frameUrls;
16903
16927
  const frameUrls = [];
16904
16928
  const frameAssets = [];
16929
+ const frameSizes = [];
16905
16930
  for (const [index, url] of urls.entries()) {
16906
16931
  const cached = await cachedFrame(url);
16907
16932
  if (!cached) {
16908
16933
  frameUrls.push(url);
16934
+ frameSizes.push(null);
16909
16935
  continue;
16910
16936
  }
16937
+ frameSizes.push(cached.contentType === "image/png" ? pngSize(await readFile18(cached.path).catch(() => Buffer.alloc(0))) : null);
16911
16938
  const route = `${prefix}/review-frame/${encodeURIComponent(String(groups.length))}/${index}`;
16912
16939
  frameAssets.push([route, cached]);
16913
16940
  frameUrls.push(route);
@@ -16933,6 +16960,7 @@ async function prepareReview(provider, lock, opts = {}) {
16933
16960
  prompt: entry.prompt,
16934
16961
  reviewObjectId: entry.reviewObjectId,
16935
16962
  frameUrls,
16963
+ ...frameSizes.some(Boolean) ? { frameSizes } : {},
16936
16964
  width: entry.width,
16937
16965
  height: entry.height,
16938
16966
  ...state.status === "review-set" ? {