pixelkiln 0.46.1 → 0.47.1
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/README.md +5 -5
- package/dist/cli.js +29 -7
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +25 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -5
- package/dist/index.d.ts +34 -5
- package/dist/index.js +25 -6
- package/dist/index.js.map +1 -1
- package/docs/AGENTS.md +1 -1
- package/docs/ARCHITECTURE.md +21 -10
- package/docs/ARTIFACTS.md +8 -1
- package/docs/CHARACTERS.md +313 -0
- package/docs/CLI.md +24 -3
- package/docs/COMFYUI.md +68 -0
- package/docs/ENDPOINTS.md +33 -2
- package/docs/GENERATORS.md +6 -6
- package/docs/GETTING_STARTED.md +25 -1
- package/docs/MANIFEST.md +144 -437
- package/docs/PIXELLAB.md +18 -11
- package/docs/README.md +3 -2
- package/docs/RETRO_DIFFUSION.md +96 -2
- package/docs/SCENARIO.md +46 -0
- package/package.json +1 -1
- package/skills/pixelkiln/SKILL.md +7 -0
- package/skills/pixelkiln/references/pixellab.md +1 -1
package/README.md
CHANGED
|
@@ -54,6 +54,7 @@ provenance and no long-lived npm token.
|
|
|
54
54
|
| Generate and review | Resumable submit/poll/pick/fetch pipeline, exact next-step hints, candidate or atomic frame-set review, and a provenance gallery that can edit intent, generate under a budget, and compare records. |
|
|
55
55
|
| Hand edits | Touch-ups in your own editor or a pinned in-browser Pixelorama, kept beside the generated art with the generation still the record; frame and tile sets member by member. |
|
|
56
56
|
| Controlled inputs | Hashed image-to-image/inpaint lineage, fail-closed parent approval, source-versus-candidate review, and content-addressed per-asset ComfyUI bindings. |
|
|
57
|
+
| Characters | A base in 4 or 8 directions from a prompt or your own sprite (four PixelLab engines), poses and loops as dependent assets generated in waves, free mirrored directions, account adoption, and SpriteFrames export. |
|
|
57
58
|
| Existing-art onboarding | Manifest scaffolding, exact-hash account adoption, and prompt recovery. |
|
|
58
59
|
| Recovery | Safe stale-output replacement, validated caches, durable references, resumable paid jobs, and per-asset generation history with free restores. |
|
|
59
60
|
| Shared-account safety | Cross-project claim files or a registered workspace catalog, sibling-style exclusion, reviewed salvage, keep/discard tags, separate confirmed purge. |
|
|
@@ -177,8 +178,8 @@ packaging layer.
|
|
|
177
178
|
"styles": {
|
|
178
179
|
"base": {
|
|
179
180
|
"generator": "map",
|
|
180
|
-
"promptPrefix": "
|
|
181
|
-
"promptSuffix": "
|
|
181
|
+
"promptPrefix": "pixel-art game prop",
|
|
182
|
+
"promptSuffix": "isolated, transparent background",
|
|
182
183
|
"outDir": "assets/generated/base",
|
|
183
184
|
"tags": ["my-game"]
|
|
184
185
|
}
|
|
@@ -390,9 +391,8 @@ package share one source. Policies: [Contributing](./CONTRIBUTING.md),
|
|
|
390
391
|
|
|
391
392
|
## Scope
|
|
392
393
|
|
|
393
|
-
Salvaging characters,
|
|
394
|
-
|
|
395
|
-
are deferred. See the open [roadmap issues](https://github.com/gfargo/pixelkiln/issues).
|
|
394
|
+
Salvaging characters, PixelLab's portrait and outfit tools, cross-project
|
|
395
|
+
cache reuse, and `workspace find` are not implemented; see the open [issues](https://github.com/gfargo/pixelkiln/issues).
|
|
396
396
|
|
|
397
397
|
## License
|
|
398
398
|
|
package/dist/cli.js
CHANGED
|
@@ -5641,6 +5641,10 @@ function pixelLabObjectUrl(generator, objectId) {
|
|
|
5641
5641
|
const setId = objectId.split("#")[0];
|
|
5642
5642
|
return setId ? `https://www.pixellab.ai/maps/tiles/${encodeURIComponent(setId)}` : null;
|
|
5643
5643
|
}
|
|
5644
|
+
if (generator === "character") {
|
|
5645
|
+
const characterId = objectId.split("#")[0];
|
|
5646
|
+
return characterId ? `https://www.pixellab.ai/create-character/${encodeURIComponent(characterId)}` : null;
|
|
5647
|
+
}
|
|
5644
5648
|
return null;
|
|
5645
5649
|
}
|
|
5646
5650
|
function characterCost(spec) {
|
|
@@ -14597,15 +14601,27 @@ function packSprites(inputs, options = {}) {
|
|
|
14597
14601
|
const sheetH = rows * cellH;
|
|
14598
14602
|
const rgba = Buffer.alloc(sheetW * sheetH * 4);
|
|
14599
14603
|
const frames = [];
|
|
14604
|
+
const pivot = options.pivot ?? "top-left";
|
|
14600
14605
|
sprites.forEach((sprite, i) => {
|
|
14601
|
-
const
|
|
14602
|
-
const
|
|
14606
|
+
const cellOx = i % columns * cellW;
|
|
14607
|
+
const cellOy = Math.floor(i / columns) * cellH;
|
|
14608
|
+
const offsetX = pivot === "bottom-center" ? Math.floor((cellW - sprite.width) / 2) : 0;
|
|
14609
|
+
const offsetY = pivot === "bottom-center" ? cellH - sprite.height : 0;
|
|
14610
|
+
const ox = cellOx + offsetX;
|
|
14611
|
+
const oy = cellOy + offsetY;
|
|
14603
14612
|
for (let y = 0; y < sprite.height; y++) {
|
|
14604
14613
|
const src = y * sprite.width * 4;
|
|
14605
14614
|
const dst = ((oy + y) * sheetW + ox) * 4;
|
|
14606
14615
|
sprite.pixels.copy(rgba, dst, src, src + sprite.width * 4);
|
|
14607
14616
|
}
|
|
14608
|
-
frames.push({
|
|
14617
|
+
frames.push({
|
|
14618
|
+
id: sprite.id,
|
|
14619
|
+
x: ox,
|
|
14620
|
+
y: oy,
|
|
14621
|
+
width: sprite.width,
|
|
14622
|
+
height: sprite.height,
|
|
14623
|
+
...offsetX || offsetY ? { offsetX, offsetY } : {}
|
|
14624
|
+
});
|
|
14609
14625
|
});
|
|
14610
14626
|
return {
|
|
14611
14627
|
png: encodeRgbaPng(sheetW, sheetH, rgba),
|
|
@@ -15122,12 +15138,15 @@ function renderAsepriteSheet(atlas, opts) {
|
|
|
15122
15138
|
}
|
|
15123
15139
|
const frames = {};
|
|
15124
15140
|
for (const frame of atlas.frames) {
|
|
15141
|
+
const offsetX = frame.offsetX ?? 0;
|
|
15142
|
+
const offsetY = frame.offsetY ?? 0;
|
|
15143
|
+
const pivoted = offsetX !== 0 || offsetY !== 0;
|
|
15125
15144
|
frames[frame.id] = {
|
|
15126
15145
|
frame: { x: frame.x, y: frame.y, w: frame.width, h: frame.height },
|
|
15127
15146
|
rotated: false,
|
|
15128
|
-
trimmed:
|
|
15129
|
-
spriteSourceSize: { x: 0, y: 0, w: frame.width, h: frame.height },
|
|
15130
|
-
sourceSize: { w: frame.width, h: frame.height },
|
|
15147
|
+
trimmed: pivoted,
|
|
15148
|
+
spriteSourceSize: pivoted ? { x: offsetX, y: offsetY, w: frame.width, h: frame.height } : { x: 0, y: 0, w: frame.width, h: frame.height },
|
|
15149
|
+
sourceSize: pivoted ? { w: atlas.cell.width, h: atlas.cell.height } : { w: frame.width, h: frame.height },
|
|
15131
15150
|
duration: durations.get(frame.id) ?? ASEPRITE_DEFAULT_DURATION_MS
|
|
15132
15151
|
};
|
|
15133
15152
|
}
|
|
@@ -15232,16 +15251,18 @@ async function runPack(args) {
|
|
|
15232
15251
|
const manifestDir = path38.dirname(path38.resolve(args.manifest));
|
|
15233
15252
|
const styleIds = args.styles.length ? args.styles : Object.keys(loaded.manifest.styles);
|
|
15234
15253
|
for (const styleId of styleIds) {
|
|
15254
|
+
const style = loaded.manifest.styles[styleId];
|
|
15255
|
+
const pivot = style?.generator === "character" ? "bottom-center" : "top-left";
|
|
15235
15256
|
const packagingSpecs = await resolveSpecs(loaded, { styles: [styleId] });
|
|
15236
15257
|
const qualitySources = await requireApprovedQualitySources(packagingSpecs, lock);
|
|
15237
15258
|
const { png, atlas, skipped, sources } = packStyle(lock, styleId, manifestDir, {
|
|
15238
15259
|
columns: args.columns,
|
|
15239
15260
|
outputRoles: args.outputRoles,
|
|
15240
15261
|
primaryOnly: args.primaryOnly,
|
|
15262
|
+
pivot,
|
|
15241
15263
|
sourceOverrides: qualitySources,
|
|
15242
15264
|
sources: manifestSources(loaded.manifest, styleId)
|
|
15243
15265
|
});
|
|
15244
|
-
const style = loaded.manifest.styles[styleId];
|
|
15245
15266
|
const base = args.out ? path38.resolve(args.out.replace(/\.(?:png|json|tres)$/i, "")) : path38.resolve(manifestDir, style.outDir, `${styleId}-sheet`);
|
|
15246
15267
|
const format = sheetFormat(args);
|
|
15247
15268
|
const { extension, document } = renderSheetDocument(format, atlas, { imageName: path38.basename(`${base}.png`) });
|
|
@@ -15268,6 +15289,7 @@ async function runPack(args) {
|
|
|
15268
15289
|
format,
|
|
15269
15290
|
order: "id",
|
|
15270
15291
|
outputRoles: [...args.outputRoles].sort(),
|
|
15292
|
+
pivot,
|
|
15271
15293
|
primaryOnly: args.primaryOnly,
|
|
15272
15294
|
style: styleId
|
|
15273
15295
|
}
|