pixelkiln 0.81.0 → 0.83.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 +132 -54
- package/dist/cli.js.map +1 -1
- package/dist/client/gallery.css +13 -0
- package/dist/client/gallery.js +375 -14
- package/dist/index.cjs +106 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +516 -8
- package/dist/index.d.ts +516 -8
- package/dist/index.js +101 -23
- package/dist/index.js.map +1 -1
- package/docs/AGENTS.md +4 -2
- package/docs/CHARACTERS.md +11 -3
- package/docs/CLI.md +7 -0
- package/docs/PIXELLAB.md +9 -1
- package/docs/REVISIONS.md +9 -4
- package/package.json +1 -1
- package/skills/pixelkiln/references/pixellab.md +11 -8
- package/skills/pixelkiln/references/revisions.md +13 -10
package/dist/cli.js
CHANGED
|
@@ -68,7 +68,7 @@ function exitCodeFor(err) {
|
|
|
68
68
|
|
|
69
69
|
// src/cli/main.ts
|
|
70
70
|
import { existsSync as existsSync37 } from "fs";
|
|
71
|
-
import { readFile as
|
|
71
|
+
import { readFile as readFile33 } from "fs/promises";
|
|
72
72
|
|
|
73
73
|
// src/cli/args.ts
|
|
74
74
|
import path from "path";
|
|
@@ -13945,10 +13945,10 @@ var NewAssetSchema = z6.object({
|
|
|
13945
13945
|
styles: z6.array(z6.string().min(1)).optional(),
|
|
13946
13946
|
/**
|
|
13947
13947
|
* A controlled regeneration of another asset in the same manifest,
|
|
13948
|
-
* instead of a fresh generation. `inpaint` needs a mask upload
|
|
13949
|
-
* gallery does not offer
|
|
13950
|
-
*
|
|
13951
|
-
*
|
|
13948
|
+
* instead of a fresh generation. `inpaint` needs a mask upload and
|
|
13949
|
+
* `interpolate` an ending-keyframe image the gallery does not offer, so
|
|
13950
|
+
* those two are hand-edited; every other mode can be created here
|
|
13951
|
+
* (`animate-skeleton` after the gallery writes its keypoints file).
|
|
13952
13952
|
*/
|
|
13953
13953
|
revision: z6.discriminatedUnion("mode", [
|
|
13954
13954
|
z6.object({
|
|
@@ -13957,6 +13957,29 @@ var NewAssetSchema = z6.object({
|
|
|
13957
13957
|
from: z6.string().min(1),
|
|
13958
13958
|
strength: z6.number().min(0).max(1).optional()
|
|
13959
13959
|
}).strict(),
|
|
13960
|
+
z6.object({
|
|
13961
|
+
mode: z6.literal("reduce-colors"),
|
|
13962
|
+
from: z6.string().min(1),
|
|
13963
|
+
/** A target colour count; the gallery leaves PixelLab's default when this is omitted. */
|
|
13964
|
+
numColors: z6.number().int().min(2).max(256).optional(),
|
|
13965
|
+
dithering: RevisionDitheringSchema.optional(),
|
|
13966
|
+
ditheringStrength: z6.number().min(0).max(10).optional()
|
|
13967
|
+
}).strict(),
|
|
13968
|
+
z6.object({ mode: z6.literal("correct-pixelart"), from: z6.string().min(1), strength: z6.number().min(0).max(1).optional() }).strict(),
|
|
13969
|
+
z6.object({
|
|
13970
|
+
mode: z6.enum(["animate", "animate-pixminimax"]),
|
|
13971
|
+
from: z6.string().min(1),
|
|
13972
|
+
frames: z6.number().int().min(4).max(40).refine((n) => n % 2 === 0, "frames must be even").optional(),
|
|
13973
|
+
fps: z6.number().int().min(1).max(60).optional(),
|
|
13974
|
+
enhancePrompt: z6.boolean().optional(),
|
|
13975
|
+
/** `animate-pixminimax` only; the loader refuses it on `animate`. */
|
|
13976
|
+
direction: CharacterDirectionSchema.optional()
|
|
13977
|
+
}).strict(),
|
|
13978
|
+
z6.object({
|
|
13979
|
+
mode: z6.literal("edit-animation"),
|
|
13980
|
+
from: z6.string().min(1),
|
|
13981
|
+
fps: z6.number().int().min(1).max(60).optional()
|
|
13982
|
+
}).strict(),
|
|
13960
13983
|
z6.object({
|
|
13961
13984
|
mode: z6.literal("animate-skeleton"),
|
|
13962
13985
|
from: z6.string().min(1),
|
|
@@ -14628,10 +14651,11 @@ import { existsSync as existsSync26 } from "fs";
|
|
|
14628
14651
|
// src/gallery/snapshot.ts
|
|
14629
14652
|
import { createHash as createHash3 } from "crypto";
|
|
14630
14653
|
import { existsSync as existsSync21 } from "fs";
|
|
14631
|
-
import { readFile as
|
|
14654
|
+
import { readFile as readFile19, stat as stat2 } from "fs/promises";
|
|
14632
14655
|
import path30 from "path";
|
|
14633
14656
|
|
|
14634
14657
|
// src/gallery/edit.ts
|
|
14658
|
+
import { readFile as readFile18, rename as rename9, writeFile as writeFile14 } from "fs/promises";
|
|
14635
14659
|
import path28 from "path";
|
|
14636
14660
|
import { z as z10 } from "zod";
|
|
14637
14661
|
|
|
@@ -14876,9 +14900,62 @@ var HandEditRequestSchema = z10.discriminatedUnion("action", [
|
|
|
14876
14900
|
protocol: z10.number().int().positive()
|
|
14877
14901
|
}).strict()
|
|
14878
14902
|
]);
|
|
14903
|
+
var UNDO_DEPTH = 20;
|
|
14904
|
+
var UndoRequestSchema = z10.object({
|
|
14905
|
+
action: z10.literal("undo-edit"),
|
|
14906
|
+
project: z10.string().min(1).optional(),
|
|
14907
|
+
/** The manifest as the page last saw it; undo refuses a manifest someone else has changed since. */
|
|
14908
|
+
expectedSha256: z10.string().regex(/^[0-9a-f]{64}$/)
|
|
14909
|
+
}).strict();
|
|
14879
14910
|
function createGalleryEditHandler(opts) {
|
|
14880
14911
|
const log2 = opts.onProgress ?? (() => {
|
|
14881
14912
|
});
|
|
14913
|
+
const apply = createEditApplier(opts, log2);
|
|
14914
|
+
const history = /* @__PURE__ */ new Map();
|
|
14915
|
+
const manifestOf = async (project) => {
|
|
14916
|
+
try {
|
|
14917
|
+
return path28.resolve(await opts.manifestFor(typeof project === "string" ? project : void 0));
|
|
14918
|
+
} catch {
|
|
14919
|
+
return null;
|
|
14920
|
+
}
|
|
14921
|
+
};
|
|
14922
|
+
return async (body) => {
|
|
14923
|
+
const undo = UndoRequestSchema.safeParse(body);
|
|
14924
|
+
if (undo.success) {
|
|
14925
|
+
const manifestPath2 = await manifestOf(undo.data.project);
|
|
14926
|
+
if (!manifestPath2) throw new ManifestEditError("no manifest to undo an edit in");
|
|
14927
|
+
const current = await readFile18(manifestPath2, "utf8");
|
|
14928
|
+
if (sha256(current) !== undo.data.expectedSha256) throw new ManifestDriftError(manifestPath2);
|
|
14929
|
+
const stack = history.get(manifestPath2) ?? [];
|
|
14930
|
+
const last = stack[stack.length - 1];
|
|
14931
|
+
if (!last) throw new ManifestEditError("nothing to undo: this gallery has not changed the manifest");
|
|
14932
|
+
if (last.afterSha !== sha256(current)) {
|
|
14933
|
+
history.delete(manifestPath2);
|
|
14934
|
+
throw Object.assign(new Error("the manifest changed outside the gallery since its last edit; undo would discard that change"), { status: 409 });
|
|
14935
|
+
}
|
|
14936
|
+
const tmp = manifestPath2 + ".pixelkiln-undo";
|
|
14937
|
+
await writeFile14(tmp, last.before);
|
|
14938
|
+
await rename9(tmp, manifestPath2);
|
|
14939
|
+
stack.pop();
|
|
14940
|
+
log2(` manifest edit undone in ${path28.relative(process.cwd(), manifestPath2) || manifestPath2}`);
|
|
14941
|
+
return opts.reload();
|
|
14942
|
+
}
|
|
14943
|
+
const manifestPath = await manifestOf(body?.project);
|
|
14944
|
+
const before = manifestPath ? await readFile18(manifestPath, "utf8").catch(() => null) : null;
|
|
14945
|
+
const build = await apply(body);
|
|
14946
|
+
if (manifestPath && before !== null) {
|
|
14947
|
+
const after = await readFile18(manifestPath, "utf8").catch(() => null);
|
|
14948
|
+
if (after !== null && after !== before) {
|
|
14949
|
+
const stack = history.get(manifestPath) ?? [];
|
|
14950
|
+
stack.push({ before, afterSha: sha256(after) });
|
|
14951
|
+
if (stack.length > UNDO_DEPTH) stack.shift();
|
|
14952
|
+
history.set(manifestPath, stack);
|
|
14953
|
+
}
|
|
14954
|
+
}
|
|
14955
|
+
return build;
|
|
14956
|
+
};
|
|
14957
|
+
}
|
|
14958
|
+
function createEditApplier(opts, log2) {
|
|
14882
14959
|
return async (body) => {
|
|
14883
14960
|
const handEdit = HandEditRequestSchema.safeParse(body);
|
|
14884
14961
|
if (handEdit.success) {
|
|
@@ -15220,7 +15297,7 @@ function describeHistory(media, entry, cacheDir) {
|
|
|
15220
15297
|
var MAX_COMPARED_BYTES = 8 * 1024 * 1024;
|
|
15221
15298
|
async function samePixels(a, b) {
|
|
15222
15299
|
try {
|
|
15223
|
-
const [left, right] = await Promise.all([
|
|
15300
|
+
const [left, right] = await Promise.all([readFile19(a), readFile19(b)]);
|
|
15224
15301
|
if (left.length > MAX_COMPARED_BYTES || right.length > MAX_COMPARED_BYTES) return false;
|
|
15225
15302
|
const x = decodePng(left);
|
|
15226
15303
|
const y = decodePng(right);
|
|
@@ -15378,7 +15455,7 @@ async function buildGallerySnapshot(opts) {
|
|
|
15378
15455
|
const media = /* @__PURE__ */ new Map();
|
|
15379
15456
|
const plan = await buildPlan(specs, lock);
|
|
15380
15457
|
const items = [];
|
|
15381
|
-
const manifestText = await
|
|
15458
|
+
const manifestText = await readFile19(loaded.path, "utf8");
|
|
15382
15459
|
const manifestSha256 = sha256(manifestText);
|
|
15383
15460
|
const cacheDir = path30.resolve(path30.dirname(opts.lockPath), ".pixelkiln", "cache");
|
|
15384
15461
|
let rawStyles = {};
|
|
@@ -15730,7 +15807,7 @@ async function buildWorkspaceGallerySnapshot(opts) {
|
|
|
15730
15807
|
root: loaded.root,
|
|
15731
15808
|
provider: loaded.manifest.provider,
|
|
15732
15809
|
account: project.account ?? null,
|
|
15733
|
-
manifestSha256: manifestSha256 ?? sha256(await
|
|
15810
|
+
manifestSha256: manifestSha256 ?? sha256(await readFile19(manifestPath, "utf8")),
|
|
15734
15811
|
historyLimit: historyLimit(loaded.manifest),
|
|
15735
15812
|
entries: Object.keys(lock.entries).length,
|
|
15736
15813
|
items: projectItems.length,
|
|
@@ -15789,7 +15866,7 @@ async function buildWorkspaceGallerySnapshot(opts) {
|
|
|
15789
15866
|
// src/gallery/server.ts
|
|
15790
15867
|
import { randomBytes } from "crypto";
|
|
15791
15868
|
import { createServer as createServer2 } from "http";
|
|
15792
|
-
import { readFile as
|
|
15869
|
+
import { readFile as readFile20 } from "fs/promises";
|
|
15793
15870
|
|
|
15794
15871
|
// src/gallery/page.ts
|
|
15795
15872
|
import { existsSync as existsSync22, readFileSync as readFileSync4 } from "fs";
|
|
@@ -15900,6 +15977,7 @@ ${css}</style>
|
|
|
15900
15977
|
</header>
|
|
15901
15978
|
<main id="root"></main>
|
|
15902
15979
|
<div id="selbar" class="selbar" hidden></div>
|
|
15980
|
+
<div id="toast" class="toast" role="status" aria-live="polite" hidden></div>
|
|
15903
15981
|
<footer>
|
|
15904
15982
|
Click a sprite for its full record; press <kbd>?</kbd> for every keyboard shortcut. This page reads the manifest, lockfile,
|
|
15905
15983
|
and disk only. It never contacts a provider<span id="foot-edit"> and never writes anything</span><span id="foot-editing" hidden>.
|
|
@@ -16103,7 +16181,7 @@ async function serveGallery(opts) {
|
|
|
16103
16181
|
const asset = reviewAssets.get(jobId)?.get(url2.pathname);
|
|
16104
16182
|
if (!asset) return fail(404, "no such review asset");
|
|
16105
16183
|
try {
|
|
16106
|
-
const bytes = await
|
|
16184
|
+
const bytes = await readFile20(asset.path);
|
|
16107
16185
|
res.writeHead(200, {
|
|
16108
16186
|
"Content-Type": asset.contentType,
|
|
16109
16187
|
"Cache-Control": "no-store",
|
|
@@ -16186,7 +16264,7 @@ async function serveGallery(opts) {
|
|
|
16186
16264
|
if (!asset) return fail(404, "no such gallery media");
|
|
16187
16265
|
let bytes;
|
|
16188
16266
|
try {
|
|
16189
|
-
bytes = await
|
|
16267
|
+
bytes = await readFile20(asset.path);
|
|
16190
16268
|
} catch {
|
|
16191
16269
|
return fail(404, "gallery media is no longer on disk; refresh the page");
|
|
16192
16270
|
}
|
|
@@ -16642,10 +16720,10 @@ function ownedReferenceImageId(spec, lock, providerId) {
|
|
|
16642
16720
|
|
|
16643
16721
|
// src/pick/server.ts
|
|
16644
16722
|
import { existsSync as existsSync24 } from "fs";
|
|
16645
|
-
import { readFile as
|
|
16723
|
+
import { readFile as readFile22 } from "fs/promises";
|
|
16646
16724
|
|
|
16647
16725
|
// src/pipeline/init.ts
|
|
16648
|
-
import { readdir, readFile as
|
|
16726
|
+
import { readdir, readFile as readFile21, writeFile as writeFile15 } from "fs/promises";
|
|
16649
16727
|
import { existsSync as existsSync23 } from "fs";
|
|
16650
16728
|
import path31 from "path";
|
|
16651
16729
|
function pngSize(buf) {
|
|
@@ -16675,7 +16753,7 @@ async function scanAssets(root, opts = {}) {
|
|
|
16675
16753
|
const skipped = [];
|
|
16676
16754
|
const seen = /* @__PURE__ */ new Map();
|
|
16677
16755
|
for (const file of files.sort()) {
|
|
16678
|
-
const size = pngSize(await
|
|
16756
|
+
const size = pngSize(await readFile21(file));
|
|
16679
16757
|
if (!size) {
|
|
16680
16758
|
skipped.push(`${file} (not a readable PNG)`);
|
|
16681
16759
|
continue;
|
|
@@ -16743,7 +16821,7 @@ async function writeManifestFile(target, manifest) {
|
|
|
16743
16821
|
if (existsSync23(target)) {
|
|
16744
16822
|
throw new Error(`${target} already exists; refusing to overwrite an existing manifest.`);
|
|
16745
16823
|
}
|
|
16746
|
-
await
|
|
16824
|
+
await writeFile15(target, JSON.stringify(manifest, null, 2) + "\n");
|
|
16747
16825
|
}
|
|
16748
16826
|
|
|
16749
16827
|
// src/pick/sheet.ts
|
|
@@ -17162,7 +17240,7 @@ async function currentArt(entry, spec) {
|
|
|
17162
17240
|
let width = entry.width;
|
|
17163
17241
|
let height = entry.height;
|
|
17164
17242
|
if (contentType === "image/png") {
|
|
17165
|
-
const size = pngSize(await
|
|
17243
|
+
const size = pngSize(await readFile22(file));
|
|
17166
17244
|
if (size) ({ width, height } = size);
|
|
17167
17245
|
}
|
|
17168
17246
|
return { path: file, contentType, width, height };
|
|
@@ -17695,13 +17773,13 @@ function createGenerateHandlers(opts) {
|
|
|
17695
17773
|
}
|
|
17696
17774
|
|
|
17697
17775
|
// src/gallery/editor.ts
|
|
17698
|
-
import { readFile as
|
|
17776
|
+
import { readFile as readFile24 } from "fs/promises";
|
|
17699
17777
|
import path33 from "path";
|
|
17700
17778
|
|
|
17701
17779
|
// src/editor/install.ts
|
|
17702
17780
|
import { createHash as createHash4 } from "crypto";
|
|
17703
17781
|
import { existsSync as existsSync25 } from "fs";
|
|
17704
|
-
import { mkdir as mkdir12, readFile as
|
|
17782
|
+
import { mkdir as mkdir12, readFile as readFile23, rename as rename10, rm as rm10, stat as stat3, writeFile as writeFile16 } from "fs/promises";
|
|
17705
17783
|
import os2 from "os";
|
|
17706
17784
|
import path32 from "path";
|
|
17707
17785
|
|
|
@@ -17785,7 +17863,7 @@ function editorBaseUrl(pin = EDITOR_PIN) {
|
|
|
17785
17863
|
}
|
|
17786
17864
|
async function sha256Of(file) {
|
|
17787
17865
|
try {
|
|
17788
|
-
return createHash4("sha256").update(await
|
|
17866
|
+
return createHash4("sha256").update(await readFile23(file)).digest("hex");
|
|
17789
17867
|
} catch {
|
|
17790
17868
|
return null;
|
|
17791
17869
|
}
|
|
@@ -17859,8 +17937,8 @@ async function installEditor(opts = {}) {
|
|
|
17859
17937
|
const final = path32.join(dir, name);
|
|
17860
17938
|
const tmp = `${final}.${process.pid}.part`;
|
|
17861
17939
|
try {
|
|
17862
|
-
await
|
|
17863
|
-
await
|
|
17940
|
+
await writeFile16(tmp, bytes);
|
|
17941
|
+
await rename10(tmp, final);
|
|
17864
17942
|
} finally {
|
|
17865
17943
|
await rm10(tmp, { force: true });
|
|
17866
17944
|
}
|
|
@@ -17978,7 +18056,7 @@ function createGalleryEditorHandlers(opts = {}) {
|
|
|
17978
18056
|
if (!status.installed) return null;
|
|
17979
18057
|
let bytes;
|
|
17980
18058
|
try {
|
|
17981
|
-
bytes = await
|
|
18059
|
+
bytes = await readFile24(path33.join(dir, name));
|
|
17982
18060
|
} catch {
|
|
17983
18061
|
verified = null;
|
|
17984
18062
|
return null;
|
|
@@ -18445,7 +18523,7 @@ import { existsSync as existsSync28 } from "fs";
|
|
|
18445
18523
|
|
|
18446
18524
|
// src/pipeline/cache-health.ts
|
|
18447
18525
|
import { existsSync as existsSync27 } from "fs";
|
|
18448
|
-
import { readFile as
|
|
18526
|
+
import { readFile as readFile25, readdir as readdir2, rm as rm11 } from "fs/promises";
|
|
18449
18527
|
import path35 from "path";
|
|
18450
18528
|
async function inspectCaches(lock, lockPath, options = {}) {
|
|
18451
18529
|
if (options.prune && !existsSync27(lockPath)) {
|
|
@@ -18473,7 +18551,7 @@ async function inspectCaches(lock, lockPath, options = {}) {
|
|
|
18473
18551
|
await saveCache(remotePath, { version: 1, hashes: {} });
|
|
18474
18552
|
removed.resetRemoteHashCache = true;
|
|
18475
18553
|
} else if (remoteHashes.invalidIds.length) {
|
|
18476
|
-
const cache = parseCache(JSON.parse(await
|
|
18554
|
+
const cache = parseCache(JSON.parse(await readFile25(remotePath, "utf8")));
|
|
18477
18555
|
for (const id of remoteHashes.invalidIds) delete cache.hashes[id];
|
|
18478
18556
|
removed.remoteHashEntries = remoteHashes.invalidIds.length;
|
|
18479
18557
|
await saveCache(remotePath, cache);
|
|
@@ -18517,7 +18595,7 @@ async function inspectContentCache(contentDir, referenced) {
|
|
|
18517
18595
|
const expected = mediaType ? entry.name.slice(0, -4) : "";
|
|
18518
18596
|
let bytes;
|
|
18519
18597
|
try {
|
|
18520
|
-
bytes = await
|
|
18598
|
+
bytes = await readFile25(file);
|
|
18521
18599
|
report.bytes += bytes.length;
|
|
18522
18600
|
} catch (err) {
|
|
18523
18601
|
report.invalid.push({
|
|
@@ -18564,7 +18642,7 @@ async function inspectRemoteHashCache(remotePath) {
|
|
|
18564
18642
|
if (!report.exists) return report;
|
|
18565
18643
|
let cache;
|
|
18566
18644
|
try {
|
|
18567
|
-
cache = parseCache(JSON.parse(await
|
|
18645
|
+
cache = parseCache(JSON.parse(await readFile25(remotePath, "utf8")));
|
|
18568
18646
|
} catch (err) {
|
|
18569
18647
|
report.error = err instanceof Error ? err.message : String(err);
|
|
18570
18648
|
return report;
|
|
@@ -18891,7 +18969,7 @@ async function nearestExistingDirectory(start) {
|
|
|
18891
18969
|
}
|
|
18892
18970
|
|
|
18893
18971
|
// src/pipeline/audit.ts
|
|
18894
|
-
import { readFile as
|
|
18972
|
+
import { readFile as readFile26 } from "fs/promises";
|
|
18895
18973
|
import { existsSync as existsSync31 } from "fs";
|
|
18896
18974
|
import path38 from "path";
|
|
18897
18975
|
function paletteDistance(asset, reference) {
|
|
@@ -18934,7 +19012,7 @@ async function auditStyle(loaded, specs, styleId, lock) {
|
|
|
18934
19012
|
continue;
|
|
18935
19013
|
}
|
|
18936
19014
|
try {
|
|
18937
|
-
const png = decodePng(await
|
|
19015
|
+
const png = decodePng(await readFile26(output.absolutePath));
|
|
18938
19016
|
const palette = extractPalette(png, 12);
|
|
18939
19017
|
assets.push({
|
|
18940
19018
|
assetId: spec.assetId,
|
|
@@ -18961,7 +19039,7 @@ async function auditStyle(loaded, specs, styleId, lock) {
|
|
|
18961
19039
|
const abs = path38.resolve(loaded.root, img.path);
|
|
18962
19040
|
if (!existsSync31(abs)) continue;
|
|
18963
19041
|
try {
|
|
18964
|
-
refPalettes.push(extractPalette(decodePng(await
|
|
19042
|
+
refPalettes.push(extractPalette(decodePng(await readFile26(abs)), 12));
|
|
18965
19043
|
} catch {
|
|
18966
19044
|
}
|
|
18967
19045
|
}
|
|
@@ -19190,7 +19268,7 @@ async function runAudit(args) {
|
|
|
19190
19268
|
|
|
19191
19269
|
// src/cli/commands/pack.ts
|
|
19192
19270
|
import path40 from "path";
|
|
19193
|
-
import { readFile as
|
|
19271
|
+
import { readFile as readFile27 } from "fs/promises";
|
|
19194
19272
|
|
|
19195
19273
|
// src/pipeline/pack.ts
|
|
19196
19274
|
import { readFileSync as readFileSync5 } from "fs";
|
|
@@ -19903,7 +19981,7 @@ async function runPack(args) {
|
|
|
19903
19981
|
if (args.primaryOnly || args.outputRoles.length) {
|
|
19904
19982
|
throw new Error("--primary-only and --output-role require manifest-driven pack");
|
|
19905
19983
|
}
|
|
19906
|
-
const raw = JSON.parse(await
|
|
19984
|
+
const raw = JSON.parse(await readFile27(path40.resolve(args.inputs), "utf8"));
|
|
19907
19985
|
const inputs = resolvePackInputs(raw, args.inputs);
|
|
19908
19986
|
const { png, atlas, skipped, sources } = packSprites(inputs, { columns: args.columns });
|
|
19909
19987
|
const format = sheetFormat(args);
|
|
@@ -20132,7 +20210,7 @@ import path42 from "path";
|
|
|
20132
20210
|
|
|
20133
20211
|
// src/pixellab-utils.ts
|
|
20134
20212
|
import { existsSync as existsSync32 } from "fs";
|
|
20135
|
-
import { mkdir as mkdir13, readFile as
|
|
20213
|
+
import { mkdir as mkdir13, readFile as readFile28, writeFile as writeFile17 } from "fs/promises";
|
|
20136
20214
|
import path41 from "path";
|
|
20137
20215
|
var UNZOOM_MIN_SIDE = 256;
|
|
20138
20216
|
var UNZOOM_MAX_AREA = 2048 * 2048;
|
|
@@ -20144,7 +20222,7 @@ async function unzoomFile(client2, input, opts = {}) {
|
|
|
20144
20222
|
const out = path41.resolve(opts.out ?? defaultUnzoomOut(input));
|
|
20145
20223
|
if (path41.resolve(input) === out) throw new Error("unzoom will not overwrite its own input; pass a different --out");
|
|
20146
20224
|
if (existsSync32(out) && !opts.force) throw new Error(`${out} already exists; pass --force to replace it`);
|
|
20147
|
-
const bytes = await
|
|
20225
|
+
const bytes = await readFile28(input);
|
|
20148
20226
|
const metadata = imageMetadata(bytes);
|
|
20149
20227
|
if (!metadata) throw new Error(`${input} is not a readable PNG or JPEG`);
|
|
20150
20228
|
const { width, height, format } = metadata;
|
|
@@ -20158,7 +20236,7 @@ async function unzoomFile(client2, input, opts = {}) {
|
|
|
20158
20236
|
}
|
|
20159
20237
|
const res = await client2.unzoom({ image: { base64: bytes.toString("base64"), format }, quantize: opts.quantize });
|
|
20160
20238
|
await mkdir13(path41.dirname(out), { recursive: true });
|
|
20161
|
-
await
|
|
20239
|
+
await writeFile17(out, res.png);
|
|
20162
20240
|
return { out, original: res.originalSize, unzoomed: res.unzoomedSize, zoomFactor: res.zoomFactor, usage: res.usage };
|
|
20163
20241
|
}
|
|
20164
20242
|
var FONT_WEIGHTS = ["Bold", "Regular"];
|
|
@@ -20200,8 +20278,8 @@ async function generateFont(client2, opts) {
|
|
|
20200
20278
|
client2.download(job.download_atlas_url)
|
|
20201
20279
|
]);
|
|
20202
20280
|
await mkdir13(path41.dirname(ttf), { recursive: true });
|
|
20203
|
-
await
|
|
20204
|
-
await
|
|
20281
|
+
await writeFile17(ttf, ttfBytes);
|
|
20282
|
+
await writeFile17(atlas, atlasBytes);
|
|
20205
20283
|
return { jobId, ttf, atlas, glyphPx: job.glyph_px ?? null, usage: job.usage };
|
|
20206
20284
|
}
|
|
20207
20285
|
if (Date.now() - started > timeout) {
|
|
@@ -20282,12 +20360,12 @@ async function runFont(args) {
|
|
|
20282
20360
|
|
|
20283
20361
|
// src/cli/commands/quality.ts
|
|
20284
20362
|
import path44 from "path";
|
|
20285
|
-
import { readFile as
|
|
20363
|
+
import { readFile as readFile30 } from "fs/promises";
|
|
20286
20364
|
|
|
20287
20365
|
// src/pipeline/quality-regression.ts
|
|
20288
20366
|
import path43 from "path";
|
|
20289
20367
|
import { existsSync as existsSync33 } from "fs";
|
|
20290
|
-
import { readFile as
|
|
20368
|
+
import { readFile as readFile29 } from "fs/promises";
|
|
20291
20369
|
import { z as z12 } from "zod";
|
|
20292
20370
|
var SHA256_RE = /^[0-9a-f]{64}$/;
|
|
20293
20371
|
var HEX_RE = /^#[0-9a-f]{6}$/;
|
|
@@ -20443,7 +20521,7 @@ async function measureImageQuality(file) {
|
|
|
20443
20521
|
const absolute = path43.resolve(file);
|
|
20444
20522
|
let bytes;
|
|
20445
20523
|
try {
|
|
20446
|
-
bytes = await
|
|
20524
|
+
bytes = await readFile29(absolute);
|
|
20447
20525
|
} catch (error) {
|
|
20448
20526
|
throw new Error(`Cannot read quality image ${absolute}: ${message4(error)}`, { cause: error });
|
|
20449
20527
|
}
|
|
@@ -20530,7 +20608,7 @@ async function snapshotQualityBaseline(inputs, baselinePath, options = {}) {
|
|
|
20530
20608
|
});
|
|
20531
20609
|
const data = Buffer.from(JSON.stringify(baseline, null, 2) + "\n");
|
|
20532
20610
|
if (existsSync33(absolute) && !options.force) {
|
|
20533
|
-
const current = await
|
|
20611
|
+
const current = await readFile29(absolute);
|
|
20534
20612
|
if (!current.equals(data)) {
|
|
20535
20613
|
throw new OverwriteRefusedError(
|
|
20536
20614
|
`Quality baseline already exists with different content: ${absolute}. Pass --force to replace it.`,
|
|
@@ -20545,7 +20623,7 @@ async function readQualityBaseline(baselinePath) {
|
|
|
20545
20623
|
const absolute = path43.resolve(baselinePath);
|
|
20546
20624
|
let raw;
|
|
20547
20625
|
try {
|
|
20548
|
-
raw = JSON.parse(await
|
|
20626
|
+
raw = JSON.parse(await readFile29(absolute, "utf8"));
|
|
20549
20627
|
} catch (error) {
|
|
20550
20628
|
throw new Error(`Could not read quality baseline ${absolute}: ${message4(error)}`, { cause: error });
|
|
20551
20629
|
}
|
|
@@ -20675,7 +20753,7 @@ async function runQuality(args) {
|
|
|
20675
20753
|
if (!args.out) throw new Error("quality snapshot needs --out <pixelkiln.quality.json>.");
|
|
20676
20754
|
let raw;
|
|
20677
20755
|
try {
|
|
20678
|
-
raw = JSON.parse(await
|
|
20756
|
+
raw = JSON.parse(await readFile30(path44.resolve(args.inputs), "utf8"));
|
|
20679
20757
|
} catch (error) {
|
|
20680
20758
|
throw new Error(
|
|
20681
20759
|
`Could not read quality inputs ${path44.resolve(args.inputs)}: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -20727,7 +20805,7 @@ import path46 from "path";
|
|
|
20727
20805
|
// src/recipes.ts
|
|
20728
20806
|
import path45 from "path";
|
|
20729
20807
|
import { existsSync as existsSync34 } from "fs";
|
|
20730
|
-
import { readdir as readdir3, readFile as
|
|
20808
|
+
import { readdir as readdir3, readFile as readFile31 } from "fs/promises";
|
|
20731
20809
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
20732
20810
|
import { z as z13 } from "zod";
|
|
20733
20811
|
var SHA256_RE2 = /^[0-9a-f]{64}$/;
|
|
@@ -20915,7 +20993,7 @@ async function readRecipeFile(recipePath, bundled) {
|
|
|
20915
20993
|
const absolute = path45.resolve(recipePath);
|
|
20916
20994
|
let raw;
|
|
20917
20995
|
try {
|
|
20918
|
-
raw = JSON.parse(await
|
|
20996
|
+
raw = JSON.parse(await readFile31(absolute, "utf8"));
|
|
20919
20997
|
} catch (error) {
|
|
20920
20998
|
throw new Error(`Could not read recipe ${absolute}: ${message5(error)}`, { cause: error });
|
|
20921
20999
|
}
|
|
@@ -21057,12 +21135,12 @@ async function installRecipe(target, options = {}) {
|
|
|
21057
21135
|
];
|
|
21058
21136
|
const files = await Promise.all(sources.map(async (file) => ({
|
|
21059
21137
|
path: path45.join(destination, ...file.path.split("/")),
|
|
21060
|
-
data: await
|
|
21138
|
+
data: await readFile31(file.source)
|
|
21061
21139
|
})));
|
|
21062
21140
|
if (!options.force) {
|
|
21063
21141
|
for (const file of files) {
|
|
21064
21142
|
if (!existsSync34(file.path)) continue;
|
|
21065
|
-
const current = await
|
|
21143
|
+
const current = await readFile31(file.path);
|
|
21066
21144
|
if (!current.equals(file.data)) {
|
|
21067
21145
|
throw new OverwriteRefusedError(
|
|
21068
21146
|
`Recipe destination has local changes: ${file.path}. Choose another --out or pass --force to replace declared recipe files.`,
|
|
@@ -21302,7 +21380,7 @@ async function runRefine(args) {
|
|
|
21302
21380
|
// src/cli/commands/skeleton.ts
|
|
21303
21381
|
import path48 from "path";
|
|
21304
21382
|
import { existsSync as existsSync35 } from "fs";
|
|
21305
|
-
import { readFile as
|
|
21383
|
+
import { readFile as readFile32, writeFile as writeFile18 } from "fs/promises";
|
|
21306
21384
|
|
|
21307
21385
|
// src/skeleton-preview.ts
|
|
21308
21386
|
var RIGHT = [255, 140, 40, 255];
|
|
@@ -21418,7 +21496,7 @@ async function runEstimateSkeleton(args) {
|
|
|
21418
21496
|
}
|
|
21419
21497
|
loadEnvFiles(path48.dirname(path48.resolve(args.manifest)));
|
|
21420
21498
|
loadEnvFiles(process.cwd());
|
|
21421
|
-
const bytes = await
|
|
21499
|
+
const bytes = await readFile32(path48.resolve(image));
|
|
21422
21500
|
const metadata = imageMetadata(bytes);
|
|
21423
21501
|
if (!metadata) throw new UsageError(`${image} is not a readable PNG or JPEG`);
|
|
21424
21502
|
const sizeProblem = estimateSkeletonSizeProblem(metadata.width, metadata.height);
|
|
@@ -21430,7 +21508,7 @@ async function runEstimateSkeleton(args) {
|
|
|
21430
21508
|
const frames = args.frames ?? DEFAULT_SCAFFOLD_FRAMES;
|
|
21431
21509
|
const json = JSON.stringify(scaffoldSkeletonSet(res.keypoints, frames), null, 2);
|
|
21432
21510
|
if (args.out) {
|
|
21433
|
-
await
|
|
21511
|
+
await writeFile18(path48.resolve(args.out), json + "\n");
|
|
21434
21512
|
log(` wrote ${args.out}: the estimated pose and ${frames} frames to edit`);
|
|
21435
21513
|
log(` preview it with: pixelkiln skeleton-preview ${args.out} --from ${image}`);
|
|
21436
21514
|
} else {
|
|
@@ -21462,7 +21540,7 @@ async function runSkeletonPreview(args) {
|
|
|
21462
21540
|
if (!existsSync35(keypointsFile)) throw new UsageError(`Keypoints file does not exist yet: ${keypointsFile}`);
|
|
21463
21541
|
let json;
|
|
21464
21542
|
try {
|
|
21465
|
-
json = JSON.parse(await
|
|
21543
|
+
json = JSON.parse(await readFile32(keypointsFile, "utf8"));
|
|
21466
21544
|
} catch (error) {
|
|
21467
21545
|
throw new UsageError(`${keypointsFile} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
21468
21546
|
}
|
|
@@ -21472,13 +21550,13 @@ async function runSkeletonPreview(args) {
|
|
|
21472
21550
|
if (!existsSync35(sourceFile)) {
|
|
21473
21551
|
log(` source image does not exist yet, drawing on a plain ground: ${sourceFile}`);
|
|
21474
21552
|
} else {
|
|
21475
|
-
const bytes = await
|
|
21553
|
+
const bytes = await readFile32(sourceFile);
|
|
21476
21554
|
if (imageMetadata(bytes)?.format !== "png") throw new UsageError(`${sourceFile} must be a PNG to preview over`);
|
|
21477
21555
|
source = decodePng(bytes);
|
|
21478
21556
|
}
|
|
21479
21557
|
}
|
|
21480
21558
|
const out = path48.resolve(args.out ?? keypointsFile.replace(/\.json$/, "") + ".preview.png");
|
|
21481
|
-
await
|
|
21559
|
+
await writeFile18(out, renderSkeletonSheet(set, { source }));
|
|
21482
21560
|
log(` ${label}: ${set.frames.length} frames after the starting pose`);
|
|
21483
21561
|
const shown = path48.relative(process.cwd(), out);
|
|
21484
21562
|
log(` wrote ${shown.startsWith("..") ? out : shown}`);
|
|
@@ -21664,7 +21742,7 @@ async function runVersion() {
|
|
|
21664
21742
|
for (const up of ["../package.json", "../../package.json"]) {
|
|
21665
21743
|
const url = new URL(up, import.meta.url);
|
|
21666
21744
|
if (!existsSync37(url)) continue;
|
|
21667
|
-
const pkg = JSON.parse(await
|
|
21745
|
+
const pkg = JSON.parse(await readFile33(url, "utf8"));
|
|
21668
21746
|
if (pkg.name === "pixelkiln") {
|
|
21669
21747
|
log(`${pkg.name} ${pkg.version}`);
|
|
21670
21748
|
return;
|