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/CONTRIBUTING.md +6 -0
- package/dist/cli.js +33 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +33 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +33 -5
- package/dist/index.js.map +1 -1
- package/docs/CHARACTERS.md +9 -0
- package/docs/ENDPOINTS.md +36 -2
- package/docs/GENERATORS.md +1 -1
- package/docs/PIXELLAB.md +6 -5
- package/package.json +1 -1
- package/skills/pixelkiln/references/pixellab-roadmap.md +6 -3
- package/skills/pixelkiln/references/pixellab.md +8 -3
package/CONTRIBUTING.md
CHANGED
|
@@ -42,6 +42,12 @@ npm run website:dev
|
|
|
42
42
|
The site reads canonical Markdown from `docs/` and the root policy files at
|
|
43
43
|
build time. Do not create a second documentation copy under `website/`.
|
|
44
44
|
|
|
45
|
+
The home page's "Latest updates from our providers" section reads
|
|
46
|
+
`website/app/lib/provider-updates.ts`. When a provider ships a feature
|
|
47
|
+
PixelKiln can use, add an entry at the top of that list. The newest entry
|
|
48
|
+
shows its figures and code sample; earlier ones collapse to a short row. Show
|
|
49
|
+
only output from a real call, with the bill the docs record.
|
|
50
|
+
|
|
45
51
|
Website sprites are generated from `website/art/pixelkiln.manifest.json`.
|
|
46
52
|
Treat those requests as paid work: run `plan` and `audit` first, use an explicit
|
|
47
53
|
hard budget, and commit the manifest, lockfile, and reviewed outputs together.
|
package/dist/cli.js
CHANGED
|
@@ -6704,7 +6704,8 @@ var PixelLabClient = class {
|
|
|
6704
6704
|
});
|
|
6705
6705
|
const text = await res.text();
|
|
6706
6706
|
if (!res.ok) {
|
|
6707
|
-
|
|
6707
|
+
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' : "";
|
|
6708
|
+
throw new PixelLabError(`${init?.method ?? "GET"} ${path53} \u2192 ${res.status}${hint}`, res.status, text);
|
|
6708
6709
|
}
|
|
6709
6710
|
if (!text) return {};
|
|
6710
6711
|
try {
|
|
@@ -9598,6 +9599,11 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
9598
9599
|
if (character.animation.mode !== "template" && character.animation.mode !== "skeleton-v3" && !spec.prompt.trim()) {
|
|
9599
9600
|
throw new Error(`${spec.styleId}/${spec.assetId} needs a prompt describing the motion, or a template`);
|
|
9600
9601
|
}
|
|
9602
|
+
if (character.animation.mode === "skeleton-v3" && character.mode === "standard") {
|
|
9603
|
+
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`
|
|
9605
|
+
);
|
|
9606
|
+
}
|
|
9601
9607
|
}
|
|
9602
9608
|
}
|
|
9603
9609
|
validateObjectPro(spec, styleImages = []) {
|
|
@@ -9904,7 +9910,10 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
9904
9910
|
stateName: character.state_name ?? null,
|
|
9905
9911
|
directions: character.directions,
|
|
9906
9912
|
size: character.size,
|
|
9907
|
-
updatedAt: character.updated_at ?? null
|
|
9913
|
+
updatedAt: character.updated_at ?? null,
|
|
9914
|
+
// Kept: this metadata replaces the submit-time `character` entry,
|
|
9915
|
+
// and the job id is the only way to read the bill again later.
|
|
9916
|
+
...backgroundJobId ? { backgroundJobId } : {}
|
|
9908
9917
|
}
|
|
9909
9918
|
},
|
|
9910
9919
|
billed: await this.billedForJob(backgroundJobId)
|
|
@@ -10555,7 +10564,12 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
10555
10564
|
if (!backgroundJobId) return null;
|
|
10556
10565
|
try {
|
|
10557
10566
|
const job = await this.client.getBackgroundJob(backgroundJobId);
|
|
10558
|
-
|
|
10567
|
+
const nested = job.last_response?.billing_usage;
|
|
10568
|
+
for (const usage of [job.usage, nested]) {
|
|
10569
|
+
const billed = billedFromUsage(usage);
|
|
10570
|
+
if (billed && !(billed.unit === "usd" && billed.amount === 0)) return billed;
|
|
10571
|
+
}
|
|
10572
|
+
return null;
|
|
10559
10573
|
} catch {
|
|
10560
10574
|
return null;
|
|
10561
10575
|
}
|
|
@@ -19443,8 +19457,18 @@ GROUPS.forEach((g, gi) => {
|
|
|
19443
19457
|
preview.loading = 'lazy';
|
|
19444
19458
|
const index = document.createElement('span');
|
|
19445
19459
|
index.className = 'idx';
|
|
19446
|
-
|
|
19447
|
-
|
|
19460
|
+
// A frame's own size, not the manifest's: a 96px loop of a 64px
|
|
19461
|
+
// character is 96\xD796. Known up front for a cached file, else once loaded.
|
|
19462
|
+
const label = (w, h) => {
|
|
19463
|
+
index.textContent = (g.frameLabels?.[i] || String(i + 1)) + ' \xB7 ' + w + '\xD7' + h + ' \xB7 ' + scaleLabel;
|
|
19464
|
+
};
|
|
19465
|
+
const known = g.frameSizes?.[i];
|
|
19466
|
+
label(known ? known.width : g.width, known ? known.height : g.height);
|
|
19467
|
+
if (!known) {
|
|
19468
|
+
preview.addEventListener('load', () => {
|
|
19469
|
+
if (preview.naturalWidth && preview.naturalHeight) label(preview.naturalWidth, preview.naturalHeight);
|
|
19470
|
+
}, { once: true });
|
|
19471
|
+
}
|
|
19448
19472
|
c.append(preview, index);
|
|
19449
19473
|
if (g.recommendedIndex != null && i === recommended) {
|
|
19450
19474
|
const badge = document.createElement('span');
|
|
@@ -19625,12 +19649,15 @@ async function prepareReview(provider, lock, opts = {}) {
|
|
|
19625
19649
|
const urls = state.status === "review" ? state.candidateUrls : state.frameUrls;
|
|
19626
19650
|
const frameUrls = [];
|
|
19627
19651
|
const frameAssets = [];
|
|
19652
|
+
const frameSizes = [];
|
|
19628
19653
|
for (const [index, url] of urls.entries()) {
|
|
19629
19654
|
const cached = await cachedFrame(url);
|
|
19630
19655
|
if (!cached) {
|
|
19631
19656
|
frameUrls.push(url);
|
|
19657
|
+
frameSizes.push(null);
|
|
19632
19658
|
continue;
|
|
19633
19659
|
}
|
|
19660
|
+
frameSizes.push(cached.contentType === "image/png" ? pngSize(await readFile25(cached.path).catch(() => Buffer.alloc(0))) : null);
|
|
19634
19661
|
const route = `${prefix}/review-frame/${encodeURIComponent(String(groups.length))}/${index}`;
|
|
19635
19662
|
frameAssets.push([route, cached]);
|
|
19636
19663
|
frameUrls.push(route);
|
|
@@ -19656,6 +19683,7 @@ async function prepareReview(provider, lock, opts = {}) {
|
|
|
19656
19683
|
prompt: entry.prompt,
|
|
19657
19684
|
reviewObjectId: entry.reviewObjectId,
|
|
19658
19685
|
frameUrls,
|
|
19686
|
+
...frameSizes.some(Boolean) ? { frameSizes } : {},
|
|
19659
19687
|
width: entry.width,
|
|
19660
19688
|
height: entry.height,
|
|
19661
19689
|
...state.status === "review-set" ? {
|