pixelkiln 0.82.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 +27 -4
- package/dist/cli.js.map +1 -1
- package/dist/client/gallery.js +105 -7
- package/dist/index.cjs +27 -4
- 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 +27 -4
- package/dist/index.js.map +1 -1
- package/docs/AGENTS.md +4 -2
- package/docs/CHARACTERS.md +4 -3
- 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/client/gallery.js
CHANGED
|
@@ -887,6 +887,23 @@
|
|
|
887
887
|
setTimeout(() => id.focus(), 0);
|
|
888
888
|
return form;
|
|
889
889
|
}
|
|
890
|
+
function revisionModesFor(item) {
|
|
891
|
+
if (item.provider !== "pixellab") return [["image-to-image", "edit with a text instruction"]];
|
|
892
|
+
if (item.outputs.length > 1) {
|
|
893
|
+
return [
|
|
894
|
+
["edit-animation", "one text edit across every frame"],
|
|
895
|
+
["reduce-colors", "fewer colours, across every frame"],
|
|
896
|
+
["correct-pixelart", "clean up the pixel grid, across every frame"]
|
|
897
|
+
];
|
|
898
|
+
}
|
|
899
|
+
return [
|
|
900
|
+
["image-to-image", "edit with a text instruction"],
|
|
901
|
+
["animate", "animate it from a text description"],
|
|
902
|
+
["animate-pixminimax", "animate it, holding the facing direction"],
|
|
903
|
+
["reduce-colors", "fewer colours, optional dithering"],
|
|
904
|
+
["correct-pixelart", "clean up the pixel grid"]
|
|
905
|
+
];
|
|
906
|
+
}
|
|
890
907
|
function newRevisionForm(item) {
|
|
891
908
|
const pr = projectOf(item);
|
|
892
909
|
const form = el("form", "edit");
|
|
@@ -897,18 +914,83 @@
|
|
|
897
914
|
id.required = true;
|
|
898
915
|
id.autocomplete = "off";
|
|
899
916
|
id.pattern = "[^\\/\\\\]+";
|
|
917
|
+
const modes = revisionModesFor(item);
|
|
918
|
+
const mode = el("select");
|
|
919
|
+
for (const [value, label] of modes) mode.append(new Option(value + ": " + label, value));
|
|
900
920
|
const prompt = el("textarea");
|
|
901
|
-
prompt.placeholder = 'Edit instruction, e.g. "add snow on the roof".';
|
|
902
|
-
prompt.required = true;
|
|
903
921
|
const strength = el("input");
|
|
904
922
|
strength.type = "number";
|
|
905
923
|
strength.min = "0";
|
|
906
924
|
strength.max = "1";
|
|
907
925
|
strength.step = "0.05";
|
|
908
926
|
strength.placeholder = "provider default";
|
|
927
|
+
const frames = el("input");
|
|
928
|
+
frames.type = "number";
|
|
929
|
+
frames.min = "4";
|
|
930
|
+
frames.max = "40";
|
|
931
|
+
frames.step = "2";
|
|
932
|
+
frames.placeholder = "provider default";
|
|
933
|
+
const fps = el("input");
|
|
934
|
+
fps.type = "number";
|
|
935
|
+
fps.min = "1";
|
|
936
|
+
fps.max = "60";
|
|
937
|
+
fps.step = "1";
|
|
938
|
+
fps.placeholder = "playback rate";
|
|
939
|
+
const enhance = el("input");
|
|
940
|
+
enhance.type = "checkbox";
|
|
941
|
+
const enhanceField = el("label", "field check");
|
|
942
|
+
enhanceField.append(enhance, el("span", null, "let PixelLab expand the motion description first"));
|
|
943
|
+
const direction = el("select");
|
|
944
|
+
for (const d of ["south", "south-east", "east", "north-east", "north", "north-west", "west", "south-west"]) direction.append(new Option(d, d));
|
|
945
|
+
const numColors = el("input");
|
|
946
|
+
numColors.type = "number";
|
|
947
|
+
numColors.min = "2";
|
|
948
|
+
numColors.max = "256";
|
|
949
|
+
numColors.step = "1";
|
|
950
|
+
numColors.placeholder = "PixelLab default";
|
|
951
|
+
const dithering = el("select");
|
|
952
|
+
for (const d of ["", "none", "2x2", "4x4", "8x8"]) dithering.append(new Option(d || "default", d));
|
|
909
953
|
const row1 = el("div", "row");
|
|
910
|
-
row1.append(field("new asset id", id), field("
|
|
911
|
-
|
|
954
|
+
row1.append(field("new asset id", id), field("mode", mode));
|
|
955
|
+
const promptField = field("instruction", prompt);
|
|
956
|
+
const strengthField = field("strength", strength, "PixelLab rejects an explicit strength for image-to-image; leave this blank there. Optional for correct-pixelart.");
|
|
957
|
+
const framesField = field("frames", frames, "Even, 4 to 40; animate allows up to 16.");
|
|
958
|
+
const fpsField = field("fps", fps, "Recorded with the frames; PixelLab does not store one.");
|
|
959
|
+
const directionField = field("facing", direction, "Holds the sprite's facing while the motion is expanded.");
|
|
960
|
+
const colorsField = field("colours", numColors);
|
|
961
|
+
const ditherField = field("dithering", dithering);
|
|
962
|
+
const grids = el("div", "row");
|
|
963
|
+
grids.append(framesField, fpsField);
|
|
964
|
+
const cleanup = el("div", "row");
|
|
965
|
+
cleanup.append(colorsField, ditherField);
|
|
966
|
+
form.append(row1, promptField, strengthField, grids, directionField, enhanceField, cleanup);
|
|
967
|
+
const hints = {
|
|
968
|
+
"image-to-image": ["edit instruction", "add snow on the roof", "The style still adds its prefix and suffix."],
|
|
969
|
+
animate: ["motion", "the chest wobbling gently", "Describes the movement; the parent image is the first frame."],
|
|
970
|
+
"animate-pixminimax": ["motion", "the chest wobbling gently", "Describes the movement; the parent image is the first frame."],
|
|
971
|
+
"edit-animation": ["edit instruction", "add a red cape", "Applied across every frame in one call, so the change stays consistent."],
|
|
972
|
+
"reduce-colors": ["note", "optional", "Cleanup only: the text is kept as a label, not sent."],
|
|
973
|
+
"correct-pixelart": ["note", "optional", "Cleanup only: the text is kept as a label, not sent."]
|
|
974
|
+
};
|
|
975
|
+
const sync = () => {
|
|
976
|
+
const m = mode.value;
|
|
977
|
+
const [label, placeholder, hint] = hints[m];
|
|
978
|
+
promptField.querySelector("span").textContent = label;
|
|
979
|
+
promptField.querySelector("small")?.remove();
|
|
980
|
+
promptField.append(el("small", null, hint));
|
|
981
|
+
prompt.placeholder = placeholder;
|
|
982
|
+
prompt.required = m !== "reduce-colors" && m !== "correct-pixelart";
|
|
983
|
+
strengthField.hidden = m !== "image-to-image" && m !== "correct-pixelart";
|
|
984
|
+
grids.hidden = !(m === "animate" || m === "animate-pixminimax" || m === "edit-animation");
|
|
985
|
+
framesField.hidden = !(m === "animate" || m === "animate-pixminimax");
|
|
986
|
+
fpsField.hidden = grids.hidden;
|
|
987
|
+
directionField.hidden = !(m === "animate-pixminimax" && enhance.checked);
|
|
988
|
+
enhanceField.hidden = !(m === "animate" || m === "animate-pixminimax");
|
|
989
|
+
cleanup.hidden = m !== "reduce-colors";
|
|
990
|
+
};
|
|
991
|
+
mode.onchange = sync;
|
|
992
|
+
enhance.onchange = sync;
|
|
993
|
+
sync();
|
|
912
994
|
const actions = el("div", "actions");
|
|
913
995
|
const save = el("button", "primary", "Create revision");
|
|
914
996
|
save.type = "submit";
|
|
@@ -926,9 +1008,19 @@
|
|
|
926
1008
|
save.disabled = true;
|
|
927
1009
|
msg.className = "msg";
|
|
928
1010
|
msg.textContent = "saving…";
|
|
929
|
-
const
|
|
930
|
-
|
|
931
|
-
|
|
1011
|
+
const m = mode.value;
|
|
1012
|
+
const revision = { mode: m, from: item.assetId };
|
|
1013
|
+
if ((m === "image-to-image" || m === "correct-pixelart") && strength.value.trim() !== "") revision.strength = Number(strength.value);
|
|
1014
|
+
if ((m === "animate" || m === "animate-pixminimax") && frames.value.trim() !== "") revision.frames = Number(frames.value);
|
|
1015
|
+
if ((m === "animate" || m === "animate-pixminimax" || m === "edit-animation") && fps.value.trim() !== "") revision.fps = Number(fps.value);
|
|
1016
|
+
if ((m === "animate" || m === "animate-pixminimax") && enhance.checked) revision.enhancePrompt = true;
|
|
1017
|
+
if (m === "animate-pixminimax" && enhance.checked) revision.direction = direction.value;
|
|
1018
|
+
if (m === "reduce-colors") {
|
|
1019
|
+
if (numColors.value.trim() !== "") revision.numColors = Number(numColors.value);
|
|
1020
|
+
if (dithering.value) revision.dithering = dithering.value;
|
|
1021
|
+
}
|
|
1022
|
+
const text = prompt.value.trim() || (m === "reduce-colors" ? "reduce colours" : m === "correct-pixelart" ? "correct pixel art" : "");
|
|
1023
|
+
const asset = { prompt: text, styles: [item.styleId], revision };
|
|
932
1024
|
try {
|
|
933
1025
|
const body = { action: "add-asset", assetId: id.value.trim(), expectedSha256: pr.manifestSha256, asset };
|
|
934
1026
|
if (item.project) body.project = item.project;
|
|
@@ -4373,6 +4465,12 @@
|
|
|
4373
4465
|
if (item.revision.maskSha256) row(dl, "mask sha256", item.revision.maskSha256.slice(0, 16) + "…", { mono: true, copy: item.revision.maskSha256 });
|
|
4374
4466
|
if (item.revision.strength !== void 0) row(dl, "strength", item.revision.strength);
|
|
4375
4467
|
}
|
|
4468
|
+
const declared = item.asset && item.asset.revision;
|
|
4469
|
+
if (declared) {
|
|
4470
|
+
for (const [label, key] of [["facing", "direction"], ["looks like", "description"], ["body template", "skeletonTemplate"], ["frames", "frames"], ["fps", "fps"], ["colours", "numColors"], ["dithering", "dithering"]]) {
|
|
4471
|
+
if (declared[key] !== void 0) row(dl, label, declared[key]);
|
|
4472
|
+
}
|
|
4473
|
+
}
|
|
4376
4474
|
if (item.skeleton) {
|
|
4377
4475
|
row(dl, "keypoints", item.skeleton.keypointsFile, { mono: true });
|
|
4378
4476
|
if (item.skeleton.set) {
|
package/dist/index.cjs
CHANGED
|
@@ -15450,10 +15450,10 @@ var NewAssetSchema = import_zod8.z.object({
|
|
|
15450
15450
|
styles: import_zod8.z.array(import_zod8.z.string().min(1)).optional(),
|
|
15451
15451
|
/**
|
|
15452
15452
|
* A controlled regeneration of another asset in the same manifest,
|
|
15453
|
-
* instead of a fresh generation. `inpaint` needs a mask upload
|
|
15454
|
-
* gallery does not offer
|
|
15455
|
-
*
|
|
15456
|
-
*
|
|
15453
|
+
* instead of a fresh generation. `inpaint` needs a mask upload and
|
|
15454
|
+
* `interpolate` an ending-keyframe image the gallery does not offer, so
|
|
15455
|
+
* those two are hand-edited; every other mode can be created here
|
|
15456
|
+
* (`animate-skeleton` after the gallery writes its keypoints file).
|
|
15457
15457
|
*/
|
|
15458
15458
|
revision: import_zod8.z.discriminatedUnion("mode", [
|
|
15459
15459
|
import_zod8.z.object({
|
|
@@ -15462,6 +15462,29 @@ var NewAssetSchema = import_zod8.z.object({
|
|
|
15462
15462
|
from: import_zod8.z.string().min(1),
|
|
15463
15463
|
strength: import_zod8.z.number().min(0).max(1).optional()
|
|
15464
15464
|
}).strict(),
|
|
15465
|
+
import_zod8.z.object({
|
|
15466
|
+
mode: import_zod8.z.literal("reduce-colors"),
|
|
15467
|
+
from: import_zod8.z.string().min(1),
|
|
15468
|
+
/** A target colour count; the gallery leaves PixelLab's default when this is omitted. */
|
|
15469
|
+
numColors: import_zod8.z.number().int().min(2).max(256).optional(),
|
|
15470
|
+
dithering: RevisionDitheringSchema.optional(),
|
|
15471
|
+
ditheringStrength: import_zod8.z.number().min(0).max(10).optional()
|
|
15472
|
+
}).strict(),
|
|
15473
|
+
import_zod8.z.object({ mode: import_zod8.z.literal("correct-pixelart"), from: import_zod8.z.string().min(1), strength: import_zod8.z.number().min(0).max(1).optional() }).strict(),
|
|
15474
|
+
import_zod8.z.object({
|
|
15475
|
+
mode: import_zod8.z.enum(["animate", "animate-pixminimax"]),
|
|
15476
|
+
from: import_zod8.z.string().min(1),
|
|
15477
|
+
frames: import_zod8.z.number().int().min(4).max(40).refine((n) => n % 2 === 0, "frames must be even").optional(),
|
|
15478
|
+
fps: import_zod8.z.number().int().min(1).max(60).optional(),
|
|
15479
|
+
enhancePrompt: import_zod8.z.boolean().optional(),
|
|
15480
|
+
/** `animate-pixminimax` only; the loader refuses it on `animate`. */
|
|
15481
|
+
direction: CharacterDirectionSchema.optional()
|
|
15482
|
+
}).strict(),
|
|
15483
|
+
import_zod8.z.object({
|
|
15484
|
+
mode: import_zod8.z.literal("edit-animation"),
|
|
15485
|
+
from: import_zod8.z.string().min(1),
|
|
15486
|
+
fps: import_zod8.z.number().int().min(1).max(60).optional()
|
|
15487
|
+
}).strict(),
|
|
15465
15488
|
import_zod8.z.object({
|
|
15466
15489
|
mode: import_zod8.z.literal("animate-skeleton"),
|
|
15467
15490
|
from: import_zod8.z.string().min(1),
|