pixelkiln 0.85.0 → 0.86.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/PROVIDERS.md +5 -5
- package/dist/cli.js +66 -7
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +66 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +82 -4
- package/dist/index.d.ts +82 -4
- package/dist/index.js +66 -7
- package/dist/index.js.map +1 -1
- package/docs/MANIFEST.md +2 -1
- package/docs/REVISIONS.md +39 -9
- package/docs/SCENARIO.md +116 -1
- package/package.json +1 -1
- package/schema/manifest.schema.json +4 -0
- package/skills/pixelkiln/references/revisions.md +4 -2
- package/skills/pixelkiln/references/scenario.md +10 -0
package/PROVIDERS.md
CHANGED
|
@@ -114,13 +114,13 @@ only the part that fits its existing still-image pipeline.
|
|
|
114
114
|
|
|
115
115
|
| Decision | Scenario through PixelKiln |
|
|
116
116
|
|---|---|
|
|
117
|
-
| Best fit today |
|
|
118
|
-
| PixelKiln generator | `map` stills |
|
|
117
|
+
| Best fit today | Large or illustrative art rendered big then reduced (render, Pixelate, cut out, refine), image-to-image edits of existing art, and a chain of models across styles, each with a hard CU ceiling. Poor for small native-size sprites. |
|
|
118
|
+
| PixelKiln generator | `map` stills, with `styleImages` and `image-to-image` revisions as reference uploads, and `revision.fromStyle` to chain styles |
|
|
119
119
|
| Output | One to four PNG candidates, 16–4096px; each model has its own bounds |
|
|
120
120
|
| Cost model | Manifest `maxComputeUnits`, command budget, then free authoritative preflight before each paid request |
|
|
121
121
|
| Recovery | Durable job and asset IDs refresh temporary signed original-file URLs |
|
|
122
122
|
| Account lifecycle | Read-only connectivity check; no balance, list, adopt, salvage, tag, or purge yet |
|
|
123
|
-
| Confidence | BFL Flux 2 Dev live-tested through quote, billing, single/two-output jobs, human selection, PNG download, and provider-backed restore;
|
|
123
|
+
| Confidence | BFL Flux 2 Dev live-tested through quote, billing, single/two-output jobs, human selection, PNG download, and provider-backed restore. Ten generation models, six tool models, reference-image edits, a three-style chain, and a game's landmarks and cover have each been run once; see the [Scenario page](./docs/SCENARIO.md). Other model schemas remain unverified. |
|
|
124
124
|
|
|
125
125
|
Scenario model schemas differ. The current adapter sends prompt, width, height,
|
|
126
126
|
output count, optional seed, and explicitly declared JSON parameters. Verify
|
|
@@ -134,8 +134,8 @@ background. That distinction matters more than raw canvas size.
|
|
|
134
134
|
|
|
135
135
|
| Asset type | PixelLab | Retro Diffusion | ComfyUI | Scenario |
|
|
136
136
|
|---|---|---|---|---|
|
|
137
|
-
| Isolated house, building, mountain, or landmark | Start with `map`: arbitrary dimensions up to 400×400 and a measured one-generation cost. Live benchmark outputs had opaque backgrounds, so plan for cleanup. Use `1dir` only when references or candidate variety justify 20–40 generations and a square canvas. | Start with `rd_plus__topdown_asset`, `rd_plus__isometric_asset`, or `rd_tile__scene_object`, depending on perspective. `rd_tile__scene_object` is intended for 64–384px objects placed on tile maps. | Choose a checkpoint or LoRA trained for the intended perspective, then keep background removal or segmentation in the workflow. For the tested Pixel Art XL stack, target 48–128px native components even though the adapter accepts larger working canvases. |
|
|
138
|
-
| Full scenic background | Use `pixflux` with `noBackground: false` when an exact palette matters, or `map` for a simple scene; both top out at 400×400. `imagePro` reaches 792 wide or 688 tall for a flat 40 generations. | `rd_plus__environment` targets one-point-perspective scenes; `rd_plus__topdown_map` targets 3/4 top-down maps. These styles support up to 384×384. | Use composition controls only to establish the scene. Recover and review native components, then compose them at 1× with one grid and palette. A large model canvas is not a large native pixel-art canvas. |
|
|
137
|
+
| Isolated house, building, mountain, or landmark | Start with `map`: arbitrary dimensions up to 400×400 and a measured one-generation cost. Live benchmark outputs had opaque backgrounds, so plan for cleanup. Use `1dir` only when references or candidate variety justify 20–40 generations and a square canvas. | Start with `rd_plus__topdown_asset`, `rd_plus__isometric_asset`, or `rd_tile__scene_object`, depending on perspective. `rd_tile__scene_object` is intended for 64–384px objects placed on tile maps. | Choose a checkpoint or LoRA trained for the intended perspective, then keep background removal or segmentation in the workflow. For the tested Pixel Art XL stack, target 48–128px native components even though the adapter accepts larger working canvases. | Raw model output is opaque and anti-aliased (the BFL smoke keep used 19,619 colors), but a chain of render at four times the size, Pixelate to the target grid, Birefnet, and `refine` took a 960 px render of an alpine lodge to a 240×208 native grid at high confidence with 63 colors, for 18 CU (a 1 CU render can be nearly as good). Details and the Pixelate grid caveat are in [Set up Scenario](./docs/SCENARIO.md#large-and-illustrative-art-render-big-pixelate-refine). One sample per subject. |
|
|
138
|
+
| Full scenic background | Use `pixflux` with `noBackground: false` when an exact palette matters, or `map` for a simple scene; both top out at 400×400. `imagePro` reaches 792 wide or 688 tall for a flat 40 generations. | `rd_plus__environment` targets one-point-perspective scenes; `rd_plus__topdown_map` targets 3/4 top-down maps. These styles support up to 384×384. | Use composition controls only to establish the scene. Recover and review native components, then compose them at 1× with one grid and palette. A large model canvas is not a large native pixel-art canvas. | GPT Image 2 at four times the target size, then Pixelate, turned a course-cover brief into a convincing pixel scene with 31 colors and legible title text. It has not been put through the shared benchmark. A large model canvas is not native pixel resolution: pixelate to the grid you need and check it with `refine`. |
|
|
139
139
|
| Style consistency across a set | `1dir` accepts a style reference and returns size-dependent candidates, but it is more expensive and capped at the square-object range. | RD Pro accepts up to nine references and has stronger prompt following, but its common styles top out at 256×256 and cost $0.18 per image. Environment-specific RD Plus styles trade references for a larger 384px canvas. | LoRAs, reference adapters, ControlNet, and shared latent settings can live in the committed workflow. Reproducibility also depends on external model and custom-node versions. | Scenario's project models and LoRAs are the main reason to use it for a set. PixelKiln can pin the model ID and parameters, but its first live run covers only the public BFL profile. |
|
|
140
140
|
| Very large final scene | Generate reusable objects, terrain, and background layers separately; assemble them deterministically and integer-upscale the result. | Use the same layered approach. The API has a 512px overall ceiling, but the useful environment and scene-object styles currently cap at 384px. | The graph can tile, upscale, or composite beyond hosted-provider limits, but memory and seam quality become workflow concerns. Prefer reusable layers unless the scene truly needs one render. | Scenario can request a larger raster from a compatible model, but the same rule applies: generate reusable layers at their useful native detail, compose at 1×, and integer-upscale only the final scene. |
|
|
141
141
|
|
package/dist/cli.js
CHANGED
|
@@ -777,6 +777,7 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
|
|
|
777
777
|
revision: spec.revision ? {
|
|
778
778
|
mode: spec.revision.mode,
|
|
779
779
|
from: spec.revision.sourceAssetId,
|
|
780
|
+
fromStyle: spec.revision.sourceStyleId,
|
|
780
781
|
sourceSha256: spec.revision.sourceSha256,
|
|
781
782
|
maskSha256: spec.revision.maskSha256,
|
|
782
783
|
strength: spec.revision.strength,
|
|
@@ -1126,8 +1127,16 @@ var RevisionDitheringSchema = z.enum(["none", "2x2", "4x4", "8x8"]);
|
|
|
1126
1127
|
var RevisionSchema = z.object({
|
|
1127
1128
|
/** What kind of controlled change the provider workflow performs. */
|
|
1128
1129
|
mode: RevisionModeSchema,
|
|
1129
|
-
/** Parent asset id in
|
|
1130
|
+
/** Parent asset id. It lives in this asset's own style unless `fromStyle` names another. */
|
|
1130
1131
|
from: z.string().min(1),
|
|
1132
|
+
/**
|
|
1133
|
+
* The style the parent lives in, when it is not this asset's own. The
|
|
1134
|
+
* parent is generated by that style's provider and model, and this
|
|
1135
|
+
* revision starts from its output file, so a chain (generate with one
|
|
1136
|
+
* model, clean up with another) is declared instead of restated by hand.
|
|
1137
|
+
* Styles may depend on one another but not in a cycle.
|
|
1138
|
+
*/
|
|
1139
|
+
fromStyle: z.string().min(1).optional(),
|
|
1131
1140
|
/** Manifest-relative black/white PNG. Required only for masked inpainting. */
|
|
1132
1141
|
mask: z.string().min(1).optional(),
|
|
1133
1142
|
/** Provider-neutral edit strength. The active adapter must bind it explicitly. */
|
|
@@ -1988,6 +1997,7 @@ var LockEntrySchema = z.object({
|
|
|
1988
1997
|
revision: z.object({
|
|
1989
1998
|
mode: RevisionModeSchema,
|
|
1990
1999
|
sourceAssetId: z.string().min(1),
|
|
2000
|
+
sourceStyleId: z.string().min(1).optional(),
|
|
1991
2001
|
sourceSha256: z.string().regex(/^[0-9a-f]{64}$/),
|
|
1992
2002
|
maskSha256: z.string().regex(/^[0-9a-f]{64}$/).optional(),
|
|
1993
2003
|
strength: z.number().min(0).max(1).optional(),
|
|
@@ -4405,7 +4415,7 @@ async function inspectRevision(spec, lock, seen) {
|
|
|
4405
4415
|
if (!dependency.ready) {
|
|
4406
4416
|
return {
|
|
4407
4417
|
ready: false,
|
|
4408
|
-
reason: `revision source ${spec.styleId}/${revision.sourceAssetId} is not ready: ${dependency.reason}`
|
|
4418
|
+
reason: `revision source ${revision.sourceStyleId ?? spec.styleId}/${revision.sourceAssetId} is not ready: ${dependency.reason}`
|
|
4409
4419
|
};
|
|
4410
4420
|
}
|
|
4411
4421
|
if (revision.sourceMembers) {
|
|
@@ -10836,13 +10846,24 @@ ${issues}`);
|
|
|
10836
10846
|
}
|
|
10837
10847
|
}
|
|
10838
10848
|
if (asset.revision) {
|
|
10839
|
-
|
|
10849
|
+
const parent = parsed.data.assets[asset.revision.from];
|
|
10850
|
+
if (!parent) {
|
|
10840
10851
|
unknownReferences.push(
|
|
10841
10852
|
`assets.${assetId}.revision.from: unknown asset "${asset.revision.from}"`
|
|
10842
10853
|
);
|
|
10843
10854
|
} else if (asset.revision.from === assetId) {
|
|
10844
10855
|
unknownReferences.push(`assets.${assetId}.revision.from: an asset cannot revise itself`);
|
|
10845
10856
|
}
|
|
10857
|
+
const fromStyle = asset.revision.fromStyle;
|
|
10858
|
+
if (fromStyle) {
|
|
10859
|
+
if (!styleIds.has(fromStyle)) {
|
|
10860
|
+
unknownReferences.push(`assets.${assetId}.revision.fromStyle: unknown style "${fromStyle}"`);
|
|
10861
|
+
} else if (parent && parent.styles.length && !parent.styles.includes(fromStyle)) {
|
|
10862
|
+
unknownReferences.push(
|
|
10863
|
+
`assets.${assetId}.revision.fromStyle: "${asset.revision.from}" is not in style "${fromStyle}"`
|
|
10864
|
+
);
|
|
10865
|
+
}
|
|
10866
|
+
}
|
|
10846
10867
|
}
|
|
10847
10868
|
for (const shape of ["state", "animation"]) {
|
|
10848
10869
|
const of = asset[shape]?.of;
|
|
@@ -10958,7 +10979,7 @@ async function resolveSpecs(loaded, filter) {
|
|
|
10958
10979
|
return provider;
|
|
10959
10980
|
};
|
|
10960
10981
|
const specs = [];
|
|
10961
|
-
const
|
|
10982
|
+
const requestedStyleIds = Object.keys(manifest.styles).filter(
|
|
10962
10983
|
(id) => !filter?.styles?.length || filter.styles.includes(id)
|
|
10963
10984
|
);
|
|
10964
10985
|
for (const unknownStyle of filter?.styles ?? []) {
|
|
@@ -10983,6 +11004,39 @@ async function resolveSpecs(loaded, filter) {
|
|
|
10983
11004
|
current = parentAssetId(manifest.assets[current]);
|
|
10984
11005
|
}
|
|
10985
11006
|
}
|
|
11007
|
+
const styleDependencies = /* @__PURE__ */ new Map();
|
|
11008
|
+
for (const styleId of Object.keys(manifest.styles)) {
|
|
11009
|
+
const needed = /* @__PURE__ */ new Set();
|
|
11010
|
+
for (const assetId of resolutionAssetIds) {
|
|
11011
|
+
const asset = manifest.assets[assetId];
|
|
11012
|
+
if (asset?.styles.length && !asset.styles.includes(styleId)) continue;
|
|
11013
|
+
const fromStyle = asset?.revision?.fromStyle;
|
|
11014
|
+
if (fromStyle && fromStyle !== styleId) needed.add(fromStyle);
|
|
11015
|
+
}
|
|
11016
|
+
styleDependencies.set(styleId, needed);
|
|
11017
|
+
}
|
|
11018
|
+
const styleIds = [];
|
|
11019
|
+
const emitStyles = new Set(requestedStyleIds);
|
|
11020
|
+
{
|
|
11021
|
+
const placed = /* @__PURE__ */ new Set();
|
|
11022
|
+
const visiting = [];
|
|
11023
|
+
const place = (styleId) => {
|
|
11024
|
+
if (placed.has(styleId)) return;
|
|
11025
|
+
const cycleStart = visiting.indexOf(styleId);
|
|
11026
|
+
if (cycleStart >= 0) {
|
|
11027
|
+
throw new Error(
|
|
11028
|
+
`Styles revise each other in a cycle: ${[...visiting.slice(cycleStart), styleId].join(" -> ")}. revision.fromStyle must form a chain, not a loop.`
|
|
11029
|
+
);
|
|
11030
|
+
}
|
|
11031
|
+
visiting.push(styleId);
|
|
11032
|
+
for (const dependency of styleDependencies.get(styleId) ?? []) place(dependency);
|
|
11033
|
+
visiting.pop();
|
|
11034
|
+
placed.add(styleId);
|
|
11035
|
+
styleIds.push(styleId);
|
|
11036
|
+
};
|
|
11037
|
+
for (const styleId of requestedStyleIds) place(styleId);
|
|
11038
|
+
}
|
|
11039
|
+
const styleFinalizers = /* @__PURE__ */ new Map();
|
|
10986
11040
|
const styleImageCache = /* @__PURE__ */ new Map();
|
|
10987
11041
|
async function loadStyleImage(rel, what = "Style image") {
|
|
10988
11042
|
const abs = path14.resolve(root, rel);
|
|
@@ -11370,7 +11424,8 @@ async function resolveSpecs(loaded, filter) {
|
|
|
11370
11424
|
`Provider "${activeProvider.id}" does not support ${asset.revision.mode} revisions`
|
|
11371
11425
|
);
|
|
11372
11426
|
}
|
|
11373
|
-
const
|
|
11427
|
+
const sourceStyleId = asset.revision.fromStyle && asset.revision.fromStyle !== styleId ? asset.revision.fromStyle : void 0;
|
|
11428
|
+
const sourceSpec = sourceStyleId ? await styleFinalizers.get(sourceStyleId)(asset.revision.from) : await finalize(asset.revision.from);
|
|
11374
11429
|
const sourceStem = sourceSpec.quality?.outFile ?? (sourceSpec.source ? path14.resolve(root, sourceSpec.source) : sourceSpec.outFile);
|
|
11375
11430
|
const sourceMembers = await revisionSourceMembers(sourceStem, `revision source ${asset.revision.from}`);
|
|
11376
11431
|
const sourceFile = sourceMembers?.[0]?.file ?? sourceStem;
|
|
@@ -11392,6 +11447,7 @@ async function resolveSpecs(loaded, filter) {
|
|
|
11392
11447
|
resolved.revision = {
|
|
11393
11448
|
mode: asset.revision.mode,
|
|
11394
11449
|
sourceAssetId: asset.revision.from,
|
|
11450
|
+
...sourceStyleId ? { sourceStyleId } : {},
|
|
11395
11451
|
sourceFile,
|
|
11396
11452
|
sourceSha256: sourceImage?.hash ?? null,
|
|
11397
11453
|
sourceWidth: sourceImage?.width ?? null,
|
|
@@ -11513,6 +11569,8 @@ async function resolveSpecs(loaded, filter) {
|
|
|
11513
11569
|
finalized.add(assetId);
|
|
11514
11570
|
return resolved;
|
|
11515
11571
|
};
|
|
11572
|
+
styleFinalizers.set(styleId, finalize);
|
|
11573
|
+
if (!emitStyles.has(styleId)) continue;
|
|
11516
11574
|
for (const assetId of Object.keys(manifest.assets)) {
|
|
11517
11575
|
if (!requestedAssetIds.has(assetId) || !styleSpecs.has(assetId)) continue;
|
|
11518
11576
|
specs.push(await finalize(assetId));
|
|
@@ -15913,7 +15971,7 @@ async function buildGallerySnapshot(opts) {
|
|
|
15913
15971
|
recordedSpecHash: entry?.specHash ?? null,
|
|
15914
15972
|
currentSpecHash: spec.specHash,
|
|
15915
15973
|
revision: entry?.revision ?? null,
|
|
15916
|
-
revisionParentKey: spec.revision ? lockKey(spec.styleId, spec.revision.sourceAssetId) : entry?.revision ? lockKey(spec.styleId, entry.revision.sourceAssetId) : null,
|
|
15974
|
+
revisionParentKey: spec.revision ? lockKey(spec.revision.sourceStyleId ?? spec.styleId, spec.revision.sourceAssetId) : entry?.revision ? lockKey(entry.revision.sourceStyleId ?? spec.styleId, entry.revision.sourceAssetId) : null,
|
|
15917
15975
|
mirrorOfKey: spec.mirror ? lockKey(spec.styleId, spec.mirror.sourceAssetId) : entry?.mirror ? lockKey(spec.styleId, entry.mirror.sourceAssetId) : null,
|
|
15918
15976
|
skeleton: spec.revision?.mode === "animate-skeleton" && spec.revision.keypointsFile ? {
|
|
15919
15977
|
keypointsFile: portableOutputPath(spec.revision.keypointsFile, root),
|
|
@@ -15983,7 +16041,7 @@ async function buildGallerySnapshot(opts) {
|
|
|
15983
16041
|
recordedSpecHash: entry.specHash,
|
|
15984
16042
|
currentSpecHash: null,
|
|
15985
16043
|
revision: entry.revision,
|
|
15986
|
-
revisionParentKey: entry.revision ? lockKey(entry.styleId, entry.revision.sourceAssetId) : null,
|
|
16044
|
+
revisionParentKey: entry.revision ? lockKey(entry.revision.sourceStyleId ?? entry.styleId, entry.revision.sourceAssetId) : null,
|
|
15987
16045
|
mirrorOfKey: entry.mirror ? lockKey(entry.styleId, entry.mirror.sourceAssetId) : null,
|
|
15988
16046
|
skeleton: null,
|
|
15989
16047
|
character: describeCharacter(void 0, entry),
|
|
@@ -16919,6 +16977,7 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
|
|
|
16919
16977
|
revision: spec.revision ? {
|
|
16920
16978
|
mode: spec.revision.mode,
|
|
16921
16979
|
sourceAssetId: spec.revision.sourceAssetId,
|
|
16980
|
+
...spec.revision.sourceStyleId ? { sourceStyleId: spec.revision.sourceStyleId } : {},
|
|
16922
16981
|
sourceSha256: spec.revision.sourceSha256,
|
|
16923
16982
|
...spec.revision.maskSha256 ? { maskSha256: spec.revision.maskSha256 } : {},
|
|
16924
16983
|
...spec.revision.strength == null ? {} : { strength: spec.revision.strength },
|