pixelkiln 0.1.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.
@@ -0,0 +1,92 @@
1
+ # Contributing
2
+
3
+ Thanks for improving pixelkiln. The project is deliberately conservative around
4
+ paid generation, file ownership, and provider state: a convenient failure must
5
+ never widen a paid run, overwrite hand-edited art, or lose the identity of work
6
+ that already cost money.
7
+
8
+ ## Development setup
9
+
10
+ Requires Node.js 20 or newer.
11
+
12
+ ```bash
13
+ npm ci
14
+ npm run typecheck
15
+ npm run test:docs
16
+ npm test
17
+ npm run build
18
+ npm run test:package
19
+ ```
20
+
21
+ The Next.js marketing/documentation site is isolated in `website/`:
22
+
23
+ ```bash
24
+ npm ci --prefix website
25
+ npm run website:check
26
+ npm run website:lint
27
+ npm run website:build
28
+ npm run website:dev
29
+ ```
30
+
31
+ The site reads canonical Markdown from `docs/` and the root policy files at
32
+ build time. Do not create a second documentation copy under `website/`.
33
+
34
+ Website sprites are generated from `website/art/pixelkiln.manifest.json`.
35
+ Treat those requests as paid work: run `plan` and `audit` first, use an explicit
36
+ hard budget, and commit the manifest, lockfile, and reviewed outputs together.
37
+ The Review UI showcase should be captured at 1280×720 only after every asset
38
+ loads. Give a replacement capture a new public filename and update the page
39
+ reference so deployed image caches cannot retain the old version.
40
+
41
+ Run the source CLI without a global install:
42
+
43
+ ```bash
44
+ npm run pixelkiln -- help
45
+ npm run pixelkiln -- plan --manifest examples/minimal/pixelkiln.manifest.json
46
+ ```
47
+
48
+ Tests must not require a live provider account or API key. Use `FakeProvider`
49
+ for pipeline behavior and mocked HTTP responses for PixelLab wire contracts.
50
+
51
+ ## Change guidelines
52
+
53
+ - Start from `main` and keep one coherent change per pull request.
54
+ - Use conventional commit subjects (`feat:`, `fix:`, `docs:`, `refactor:`,
55
+ `test:`, `chore:`). Semantic Release derives versions from them.
56
+ - Add regression coverage for bug fixes and behavior coverage for new public
57
+ options or exports.
58
+ - Update README/help text and focused docs in the same change as user-facing
59
+ behavior.
60
+ - Keep README as the concise product landing page. Put durable reference and
61
+ workflow detail in `docs/`, and link every guide from `docs/README.md`.
62
+ - Run `npm run test:docs` after changing Markdown or the CLI command/flag
63
+ surface. It checks local links, the docs index, README size, and CLI coverage.
64
+ - Run the website lint and build checks when changing `website/` or the
65
+ canonical Markdown it renders.
66
+ - Run the package smoke test when changing exports, build configuration, the
67
+ executable, package metadata, or the `files` allowlist.
68
+
69
+ ## Architectural boundaries
70
+
71
+ - Provider-specific URLs, authentication, response schemas, and quirks belong
72
+ below `Provider`.
73
+ - Planning stays offline. Provider `supports()` and `estimate()` must perform no
74
+ I/O and estimates must carry their cost unit.
75
+ - Provider responses are untrusted input and need runtime validation before
76
+ entering the lockfile.
77
+ - Lockfile writes must remain atomic and resumable. Additive defaults should
78
+ preserve valid v2 files when extending lock entries.
79
+ - Unknown flags and ambiguous output selection are errors. Silent widening is
80
+ especially dangerous when a command can spend provider quota.
81
+ - Never overwrite a generated file whose current bytes differ from its recorded
82
+ hash, and never make deletion an implicit side effect of recovery/triage.
83
+
84
+ ## Pull requests
85
+
86
+ Describe the user-visible outcome, any compatibility impact, and the exact
87
+ checks run. Keep generated `dist/` files out of commits; packaging builds them
88
+ from source. If hosted CI is unavailable, include the local Node version and
89
+ full check results in the PR description.
90
+
91
+ Security-sensitive findings should follow [SECURITY.md](./SECURITY.md), not a
92
+ public issue with exploit details.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 gfargo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NAMING.md ADDED
@@ -0,0 +1,87 @@
1
+ # Naming — resolved: `pixelkiln`
2
+
3
+ **The name is settled.** The project ships as `pixelkiln`. `package.json` is
4
+ no longer `private`.
5
+
6
+ ## The original blocker was a factual error
7
+
8
+ The prior version of this file claimed `pixelkiln` "is an established npm
9
+ package (v3.5.1, the CSS spritesheet builder) and `pixelsmith` is its
10
+ engine," and blocked the name on that basis. Re-verified directly against
11
+ the npm registry (2026-08-18):
12
+
13
+ ```
14
+ GET https://registry.npmjs.org/pixelkiln → 404 "Not found"
15
+ GET https://registry.npmjs.org/spritesmith → 200, latest 3.5.1, "Utility that
16
+ takes images and creates a
17
+ spritesheet with JSON sprite data"
18
+ GET https://registry.npmjs.org/pixelsmith → 200, latest 2.6.0, "Node based
19
+ engine for spritesmith"
20
+ ```
21
+
22
+ `pixelkiln` was never published. The "v3.5.1 CSS spritesheet builder" is
23
+ **`spritesmith`**, a real and long-established package — `pixelsmith` really
24
+ is its engine, exactly as claimed, but neither of them is `pixelkiln`. The
25
+ original research conflated the two real packages into a collision that
26
+ didn't exist. (`pixelsmith` also appears, separately and correctly, in the
27
+ rejected-candidates list below — a real name in a different, adjacent
28
+ project — which should have been the tell.)
29
+
30
+ A GitHub search for `pixelkiln` returns nothing but this repository, and a
31
+ general web search turns up no product, tool, or project by that name
32
+ anywhere. Nothing else needs to change: `bin/pixelkiln.js`, `package.json`'s
33
+ `name`/`bin`, the README, `scripts/gen-schema.ts`'s schema title, and
34
+ heybud-admin's `package.json` badge scripts already all say `pixelkiln` —
35
+ there is no rename to do, only the `private: true` flag to drop, which is
36
+ done.
37
+
38
+ ## What the space already looks like
39
+
40
+ The "manifest-driven AI asset generation CLI" idea is not novel. Prior art found:
41
+
42
+ | Project | Overlap | Backend |
43
+ |---|---|---|
44
+ | [pickbitsai/sprite-generator](https://github.com/pickbitsai/sprite-generator) | Closest. JSON manifest, `assets[]` with id/category/description, `defaultStyle`, `--dry-run`, `--category`, `--concurrency` | OpenAI `gpt-image-1` |
45
+ | [mcp-tool-shop-org/sprite-foundry](https://github.com/mcp-tool-shop-org/sprite-foundry) | SQLite lifecycle tracking, review/accept/reject, provenance, deterministic export with manifest + checksums | ComfyUI (local GPU) |
46
+ | [lx-0/restyle-sprites](https://github.com/lx-0/restyle-sprites) | Restyle a whole pack from source + style reference | Gemini / OpenAI |
47
+ | [trebeljahr/sprite-tools](https://github.com/trebeljahr/sprite-tools) | Post-processing toolkit — atlas, collision, palette | n/a |
48
+ | [dt-pirate/openrender](https://github.com/dt-pirate/openrender) | Installs generated assets into engines, manifests, rollback | n/a |
49
+ | [freema/pixelforge-mcp](https://github.com/freema/pixelforge-mcp) | MCP server for pixel art | Gemini |
50
+ | [ralphy](https://ralphy.mintlify.app/advanced/asset-manifest) | `asset-manifest.json` slot pointers + `generations.jsonl` audit log | multi |
51
+
52
+ **Implication for naming:** the `sprite-*` namespace is crowded — `sprite-generator`,
53
+ `sprite-foundry`, `sprite-tools`, `restyle-sprites` all exist. Avoid it.
54
+
55
+ ## What is actually differentiated here
56
+
57
+ Worth knowing, because the name should point at it:
58
+
59
+ 1. **PixelLab-native.** Everything above wraps a general image model and
60
+ downscales. PixelLab generates on a real pixel grid. Nothing found targets it.
61
+ 2. **Exploits the candidate economics.** Cost is fixed per call while candidates
62
+ returned scale inversely with canvas size. Nothing found treats "generate
63
+ small, pick from 16" as the core loop.
64
+ 3. **`adopt`.** Retroactively reconciling an existing account and repo by image
65
+ hash. Not found anywhere.
66
+ 4. **A true lockfile.** `sprite-foundry` uses SQLite, `ralphy` uses a pointer
67
+ table plus a log. A committed, sorted, hash-on-both-sides lockfile in the npm
68
+ sense was not found.
69
+
70
+ ## Shortlist (historical — kept for context, decision is above)
71
+
72
+ All verified free on npm, zero GitHub repos by that name, no web presence
73
+ (checked 2026-07-29 for the alternates; `pixelkiln` itself re-verified
74
+ 2026-08-18 per the resolution above).
75
+
76
+ | Candidate | Note |
77
+ |---|---|
78
+ | **pixelkiln** ✅ **chosen** | Firing/baking metaphor fits pixel art, avoids the crowded `sprite-*` space. The npm collision this was shelved for turned out not to exist — see Resolution. |
79
+ | pixelquarry | Extraction metaphor — you quarry many candidates and keep the good ones. Still free, not needed. |
80
+ | pixelcrate | Packaging/inventory feel; leans toward the lockfile idea. Still free, not needed. |
81
+ | dithermill | Most pixel-art-native word available; "mill" carries batch production. Still free, not needed. |
82
+ | spriteledger | Points hardest at provenance, but inherits the crowded `sprite-` prefix. Still free, not needed. |
83
+
84
+ Rejected after checking: `pixelwright` (three live businesses use it — an AI app
85
+ builder, an iOS audit firm, a UI developer's brand), `spritefoundry` (taken by a
86
+ real project), `pixelsmith` (real package, `spritesmith`'s engine — see
87
+ Resolution), `spritemill`, `pixelloom`, `bitforge`, `spritelab`.
package/PROVIDERS.md ADDED
@@ -0,0 +1,96 @@
1
+ # Multi-provider — status and notes
2
+
3
+ **The seam is built.** `src/provider.ts` defines the interface;
4
+ `src/providers/pixellab.ts` is the reference implementation and
5
+ `src/providers/fake.ts` is the in-memory test double. Nothing above the
6
+ interface knows about PixelLab.
7
+
8
+ That is an architectural guarantee, not a compatibility claim: PixelLab is the
9
+ only production adapter and the only backend exercised against a live account
10
+ today. `FakeProvider` verifies the contract without network access. Until a
11
+ second production adapter ships, describe PixelKiln as **provider-neutral by
12
+ design and proven with PixelLab**, not as already multi-provider.
13
+
14
+ Both concerns this file previously flagged as blockers are resolved:
15
+
16
+ - **Cost is no longer assumed to be "generations."** `CostEstimate` carries a
17
+ `unit` of `generations | usd | free`, `plan` prints it, and `--budget` is
18
+ interpreted in it. `resolveSpecs(..., { provider })` asks the adapter for its
19
+ offline estimate, submission validates it again, and lock/status accounting
20
+ keeps fractional values separated by unit.
21
+ - **Free multi-candidate returns are no longer assumed universal.**
22
+ `estimate().candidates` is a provider property; `candidateCount()` moved
23
+ behind the interface.
24
+
25
+ What remains is writing a second adapter. This file records which one and why.
26
+
27
+ ## Midjourney is the wrong first target
28
+
29
+ Verified 2026-07-29: **Midjourney has no public developer API.** API keys are
30
+ restricted to the Enterprise dashboard and require applying for access. Every
31
+ third-party "Midjourney API" works by automating the Discord or web interface,
32
+ which violates Midjourney's terms of service and risks the underlying account
33
+ being banned.
34
+
35
+ Building that adapter would mean shipping something fragile, unsupported, and
36
+ capable of getting a user's account terminated. Not worth it.
37
+
38
+ ## The right first target: Retro Diffusion
39
+
40
+ [Retro Diffusion](https://retrodiffusion.ai/) is PixelLab's closest competitor
41
+ and the natural second provider:
42
+
43
+ - A real, documented developer API, with
44
+ [published examples](https://github.com/Retro-Diffusion/api-examples).
45
+ - Purpose-built for pixel art — grid-aligned output, no blur or anti-aliasing —
46
+ so it shares this tool's domain model rather than needing a downscale and
47
+ quantize pass bolted on.
48
+ - Supports seamless tiles, sprite-sheet animation, and free cost estimates,
49
+ which map onto `plan` almost directly.
50
+
51
+ Other candidates, in rough order of fit:
52
+
53
+ | Provider | API | Pixel-native | Notes |
54
+ |---|---|---|---|
55
+ | Retro Diffusion | yes | yes | Recommended first adapter |
56
+ | [Scenario](https://www.scenario.com/) | yes | partly | Game-asset focused, hosts Retro Diffusion models |
57
+ | OpenAI `gpt-image-1` | yes | no | Raster; needs downscale + palette quantization |
58
+ | Google Gemini image | yes | no | Same caveat |
59
+ | Local ComfyUI + pixel LoRA | n/a | yes | No per-call cost, but a GPU dependency |
60
+ | Midjourney | **no** | no | See above |
61
+
62
+ ## Resolved: the two economic assumptions
63
+
64
+ Both were global assumptions baked into `plan`; both are now provider-owned.
65
+ Kept here as the rationale, since a second adapter has to honour them.
66
+
67
+ 1. **Cost is not universally "generations".** `Plan.cost` used to be a bare
68
+ number meaning PixelLab subscription generations. It now carries a unit —
69
+ USD for OpenAI, generations for PixelLab, free for local — so `plan` prints
70
+ an honest figure and `--budget` means something in every backend.
71
+
72
+ 2. **Free candidates were a PixelLab quirk.** The core loop — generate small,
73
+ get 16 candidates for one fixed price, pick the best — works because
74
+ PixelLab charges per *call* and scales candidates inversely with canvas
75
+ size. OpenAI charges per *image*, so 16 candidates costs 16×. The picker
76
+ still works either way, but the strategy advice in the README does not
77
+ generalise, which is why `candidateCount()` moved behind the interface.
78
+
79
+ See `src/provider.ts` for the shipped interface. Lock entries carry a
80
+ `provider` field plus `costUnit`, defaulted to `pixellab` and `generations` so
81
+ pre-provider/pre-unit v2 lockfiles stay readable. The CLI reports both the
82
+ successful-submission estimate and the provider balance delta observed across
83
+ the run; those are deliberately separate because provider balances may settle
84
+ asynchronously.
85
+
86
+ ## Done: the integration tests it unblocked
87
+
88
+ `FakeProvider` turned out to be exactly the better test double predicted here.
89
+ 17 integration tests now cover `submit → poll → fetch`, `pushTags` and `adopt`
90
+ — the stages that spend money and previously had zero coverage, where four of
91
+ the five real bugs in this project lived. Verified non-vacuous by mutation:
92
+ breaking the output hashes, the budget check, or the v1 lock rejection each
93
+ fails tests.
94
+
95
+ The contact-sheet request paths are covered through the picker and salvage
96
+ integration tests as well as their HTML unit tests.
package/README.md ADDED
@@ -0,0 +1,333 @@
1
+ # pixelkiln
2
+
3
+ ![PixelKiln](https://wp.griffen.codes/wp-content/uploads/2026/08/download.png)
4
+
5
+ [Website](https://pixelkiln.griffen.codes) ·
6
+ [Documentation](https://pixelkiln.griffen.codes/docs) ·
7
+ [GitHub](https://github.com/gfargo/pixelkiln)
8
+
9
+ Manifest-driven pixel-art generation, review, recovery, quality control, and
10
+ game-ready asset packaging.
11
+
12
+ PixelKiln treats generated art like a build pipeline: declare assets once,
13
+ preview cost and drift, generate only the missing work, review candidates in a
14
+ local contact sheet, and commit exact provenance beside the files. No LLM is in
15
+ the orchestration loop; provider calls, polling, hashing, downloads, and filing
16
+ are deterministic software mechanics.
17
+
18
+ The orchestration layer is provider-neutral by design. PixelLab is currently
19
+ the only production adapter and the only live-tested generation backend;
20
+ `FakeProvider` exercises the same contract deterministically in tests. A second
21
+ production adapter is roadmap work, not current compatibility.
22
+
23
+ > **Release status:** the package is pre-1.0 and the first npm publication is
24
+ > tracked in [issue #1](https://github.com/gfargo/pixelkiln/issues/1). Until it
25
+ > is live, use a repository checkout.
26
+
27
+ ## Why PixelKiln
28
+
29
+ A typical image-generation account becomes two unrelated piles: remote objects
30
+ that cost money and local files with no durable explanation of where they came
31
+ from. Handwritten prompts drift, failed downloads look like failed generations,
32
+ and regenerating a whole set is easier than determining what is actually stale.
33
+
34
+ PixelKiln supplies the missing project model:
35
+
36
+ - a committed manifest defines assets, styles, generators, budgets, and output;
37
+ - a committed lockfile maps each style/asset to paid provider work and exact
38
+ output hashes;
39
+ - planning distinguishes missing, stale, recoverable, in-flight, untracked, and
40
+ manually changed files before money is spent;
41
+ - local review keeps human judgment where it matters—choosing artwork;
42
+ - content-addressed recovery prevents a transient URL failure from buying the
43
+ same image twice;
44
+ - derived artifact bundles retain source provenance and recover across ordinary
45
+ write failures or abrupt process termination.
46
+
47
+ ## Capabilities
48
+
49
+ | Workflow | What PixelKiln provides |
50
+ |---|---|
51
+ | Plan and budget | Offline manifest/lock/disk diff, provider-unit estimates, hard `--budget` ceiling, JSON/CI gate. |
52
+ | Generate and review | Resumable submit/poll/pick/fetch pipeline with a fast local candidate sheet. |
53
+ | Existing-art onboarding | Manifest scaffolding, exact-hash account adoption, and prompt recovery. |
54
+ | Recovery | Validated local content cache, provider URL restore, account object-hash cache, and resumable jobs. |
55
+ | Shared-account safety | Cross-project claim files, sibling-style exclusion, reviewed salvage, keep/discard tags, separate confirmed purge. |
56
+ | Quality control | Palette distance, transparency, color-count, relative outlier, cache-integrity, and doctor gates. |
57
+ | Sprite packaging | Deterministic RGBA packing, stable-cell mounting, explicit external input lists, structural output roles. |
58
+ | Engine export | Lossless generic tile contract, Tiled Wang sets, and Godot 4 terrain sets. |
59
+ | Artifact integrity | Portable source/output hashes, canonical fingerprints, manual-edit protection, transactional promotion, crash journal recovery. |
60
+ | Library/extension | Public TypeScript primitives, provider capability interface, and deterministic `FakeProvider`. |
61
+
62
+ ### Human review, kept local
63
+
64
+ `pixelkiln pick` opens an actual local candidate sheet; the orchestration layer
65
+ never asks a model to choose artwork for you.
66
+
67
+ ![PixelKiln candidate review UI](./website/public/review-ui-showcase.jpg)
68
+
69
+ Use Left/Right to inspect alternatives, Enter or 1–9 to select, and 0 to leave
70
+ a row unresolved. Nothing is applied when the window is closed without using
71
+ **Apply selections**. See the [CLI reference](docs/CLI.md#pick) for the complete
72
+ review workflow.
73
+
74
+ ## Install from a checkout
75
+
76
+ Requires Node.js 20 or newer.
77
+
78
+ ```bash
79
+ git clone https://github.com/gfargo/pixelkiln.git
80
+ cd pixelkiln
81
+ npm ci
82
+ npm run pixelkiln -- help
83
+ npm test
84
+ ```
85
+
86
+ `npm run pixelkiln -- …` executes the TypeScript source. `npm run build`
87
+ creates the ESM, CommonJS, declarations, and CLI distribution used by the
88
+ published package.
89
+
90
+ ## Five-minute start
91
+
92
+ Copy the minimal example into a project and edit its output path and prompts:
93
+
94
+ ```bash
95
+ cp examples/minimal/pixelkiln.manifest.json ../my-game/pixelkiln.manifest.json
96
+ cd ../my-game
97
+ ```
98
+
99
+ Put the provider credential in `.env.local` beside the manifest:
100
+
101
+ ```dotenv
102
+ PIXELLAB_API_KEY=...
103
+ ```
104
+
105
+ Validate locally, inspect exact work/cost, then generate with a hard ceiling:
106
+
107
+ ```bash
108
+ /path/to/pixelkiln/node_modules/.bin/tsx /path/to/pixelkiln/src/cli.ts doctor --dry-run
109
+ /path/to/pixelkiln/node_modules/.bin/tsx /path/to/pixelkiln/src/cli.ts plan
110
+ /path/to/pixelkiln/node_modules/.bin/tsx /path/to/pixelkiln/src/cli.ts gen --budget 120
111
+ ```
112
+
113
+ Once installed from npm, those commands become `pixelkiln doctor`,
114
+ `pixelkiln plan`, and `pixelkiln gen`.
115
+
116
+ `gen` submits, polls, opens the candidate-review sheet when necessary,
117
+ downloads validated output, populates the recovery cache, and updates
118
+ `pixelkiln.lock.json`. Commit the manifest, lockfile, generated art, and any
119
+ derived artifact companions. Do not commit credentials or `.pixelkiln/`.
120
+
121
+ For an existing art tree:
122
+
123
+ ```bash
124
+ pixelkiln init --from assets/sprites --exclude characters,gifs --generator map
125
+ pixelkiln adopt --write-prompts
126
+ pixelkiln plan
127
+ ```
128
+
129
+ See [Getting started](./docs/GETTING_STARTED.md) for new and existing projects.
130
+
131
+ ## Agent skill
132
+
133
+ Install the official PixelKiln skill so Codex, Claude Code, Cursor, and other
134
+ compatible agents know the safe plan → budget → generate → review → recover
135
+ workflow:
136
+
137
+ ```bash
138
+ npx skills add gfargo/pixelkiln@pixelkiln
139
+ ```
140
+
141
+ The skill guides an agent around PixelKiln; it does not replace a generation
142
+ provider. PixelLab's MCP server is a complementary direct-generation surface,
143
+ while PixelKiln remains the project state, budget, provenance, review, and
144
+ packaging layer.
145
+
146
+ ## Manifest
147
+
148
+ ```jsonc
149
+ {
150
+ "$schema": "./node_modules/pixelkiln/schema/manifest.schema.json",
151
+ "name": "my-game",
152
+ "styles": {
153
+ "base": {
154
+ "generator": "map",
155
+ "promptPrefix": "Pixel-art game prop: ",
156
+ "promptSuffix": ", isolated, transparent background",
157
+ "outDir": "assets/generated/base",
158
+ "tags": ["my-game"]
159
+ }
160
+ },
161
+ "assets": {
162
+ "anvil": { "prompt": "a compact blacksmith anvil" },
163
+ "hammer": { "prompt": "a worn forging hammer" }
164
+ }
165
+ }
166
+ ```
167
+
168
+ Styles are namespaces. Adding a second style re-derives the same asset ids into
169
+ a separate output directory and separate lock keys without clobbering the first
170
+ set. Generator choice, reference-image bytes, dimensions, palette, seed, and
171
+ prompt settings participate in deterministic spec identity.
172
+
173
+ The schema rejects unknown fields and invalid generator combinations before
174
+ planning. See the [Manifest reference](./docs/MANIFEST.md).
175
+
176
+ ## Everyday workflow
177
+
178
+ ```bash
179
+ # Free: validate and inspect drift, recovery, and estimated spend.
180
+ pixelkiln doctor --dry-run
181
+ pixelkiln plan
182
+
183
+ # Generate only an intended slice with a provider-unit ceiling.
184
+ pixelkiln gen --style base --only anvil,hammer --budget 80
185
+
186
+ # Repair paid output without regenerating.
187
+ pixelkiln restore
188
+
189
+ # Optional local gates.
190
+ pixelkiln audit --check --max-distance 35 --min-transparency 0.1
191
+ pixelkiln cache --check
192
+ ```
193
+
194
+ Repeated `--style`, `--only`, `--claims`, and `--output-role` filters
195
+ accumulate; comma-separated values also work. Unknown flags are hard errors, so
196
+ a typo cannot silently widen paid work.
197
+
198
+ ## Choose the right generator
199
+
200
+ Measured PixelLab economics vary by 40×:
201
+
202
+ | Need | Generator | Measured cost |
203
+ |---|---|---:|
204
+ | Standalone arbitrary-size prop/icon | `map` (default) | 1 generation |
205
+ | Exact closed palette | `pixflux` | 1 generation |
206
+ | Candidate variety/reference anchoring/future animation | `1dir` | 20–40 generations |
207
+ | Independent or connectable ground tiles | `tiles` | 20–40 generations |
208
+
209
+ Start with the required capability, not the most expensive endpoint. Forty
210
+ `map` re-rolls cost the same as one 64×64 `1dir` call; conversely, `map` cannot
211
+ replace a hard palette or reference-image constraint. See
212
+ [Generator selection](./docs/GENERATORS.md) and the
213
+ [measured endpoint reference](./docs/ENDPOINTS.md).
214
+
215
+ ## Derived artifacts
216
+
217
+ ```bash
218
+ # Deterministic sheet + atlas + provenance.
219
+ pixelkiln pack --style base
220
+
221
+ # Stable declared cells in an existing sheet.
222
+ pixelkiln mount --style ground
223
+
224
+ # Structural atlas + engine metadata + provenance.
225
+ pixelkiln export --style ground --only terrain --format tiled
226
+ ```
227
+
228
+ Pack, mount, and export write managed bundles. A `.pixelkiln.json` companion
229
+ records portable source paths/hashes, layout/export options, output hashes, and
230
+ a canonical fingerprint. Existing unowned output is adopted only when already
231
+ byte-identical; manual edits stop the whole write unless `--force` explicitly
232
+ takes ownership.
233
+
234
+ All changing members stage before promotion. Ordinary failures roll back.
235
+ Abrupt termination leaves a validated transaction journal: the next invocation
236
+ restores an incomplete old bundle or finishes cleanup for a committed new one.
237
+ See [Derived artifacts](./docs/ARTIFACTS.md) and
238
+ [Tiles and engine exports](./docs/TILES.md).
239
+
240
+ ## Recovery and shared accounts
241
+
242
+ ```bash
243
+ # Reconcile existing files with account objects.
244
+ pixelkiln adopt --write-prompts
245
+
246
+ # Review paid account objects no known project claims.
247
+ pixelkiln salvage --claims ../other-game/pixelkiln.lock.json --dry-run
248
+ pixelkiln salvage --claims ../other-game/pixelkiln.lock.json
249
+
250
+ # Deletion is deliberately separate and confirmed.
251
+ pixelkiln purge --dry-run
252
+ pixelkiln purge
253
+ ```
254
+
255
+ Salvage imports, keeps, or tags discard; it never deletes. On shared accounts,
256
+ pass every other project lockfile via `--claims` so shipped art cannot appear
257
+ unowned. Purge only targets objects already tagged discard and requires an
258
+ explicit confirmation. See [Recovery and account safety](./docs/RECOVERY.md).
259
+
260
+ ## Automation
261
+
262
+ ```bash
263
+ pixelkiln doctor --dry-run --json
264
+ pixelkiln plan --json --check
265
+ pixelkiln audit --json --check --max-distance 35 --max-colors 128
266
+ pixelkiln cache --check
267
+ ```
268
+
269
+ Pipeline stages exit nonzero after partial failures or timeouts. JSON modes
270
+ separate machine output from human diagnostics where necessary. Generation
271
+ should remain an explicit budgeted action; CI should prove committed state and
272
+ artifacts agree rather than regenerate them. See
273
+ [Quality and automation gates](./docs/QUALITY.md).
274
+
275
+ ## TypeScript library
276
+
277
+ ```ts
278
+ import {
279
+ buildPlan,
280
+ loadLock,
281
+ loadManifest,
282
+ PixelLabProvider,
283
+ resolveSpecs,
284
+ } from "pixelkiln"
285
+
286
+ const loaded = await loadManifest("pixelkiln.manifest.json")
287
+ const provider = PixelLabProvider.forOffline()
288
+ const specs = await resolveSpecs(loaded, { provider })
289
+ const plan = await buildPlan(specs, await loadLock("pixelkiln.lock.json"))
290
+
291
+ console.log(plan.cost, plan.costUnit, plan.actionable.length)
292
+ ```
293
+
294
+ The package also exports audit gates, lock/output helpers, provider contracts,
295
+ pipeline stages, sprite packing/mounting, tile exporters, managed artifact
296
+ writes, and offline provenance verification. See [Library API](./docs/LIBRARY.md).
297
+
298
+ ## Documentation
299
+
300
+ | Guide | Covers |
301
+ |---|---|
302
+ | [Documentation index](./docs/README.md) | All user, workflow, reference, and architecture guides. |
303
+ | [Getting started](./docs/GETTING_STARTED.md) | First project, existing-art onboarding, everyday workflow, and what to commit. |
304
+ | [CLI reference](./docs/CLI.md) | Every command, flag, JSON mode, and exit contract. |
305
+ | [Manifest reference](./docs/MANIFEST.md) | Every style/asset field and generator constraint. |
306
+ | [Agent workflows](./docs/AGENTS.md) | Official skill install, operating model, and PixelLab MCP pairing. |
307
+ | [Generators](./docs/GENERATORS.md) | Capability choice, measured costs, palettes, style references, and tiles. |
308
+ | [Derived artifacts](./docs/ARTIFACTS.md) | Pack, mount, export, provenance, ownership, transactions, and recovery. |
309
+ | [Recovery](./docs/RECOVERY.md) | Restore, caches, adopt, salvage, claims, and purge safety. |
310
+ | [Quality gates](./docs/QUALITY.md) | Plan, doctor, audit, cache, JSON, and CI. |
311
+ | [Architecture](./docs/ARCHITECTURE.md) | State model, lockfile, providers, concurrency, and output identity. |
312
+ | [Library API](./docs/LIBRARY.md) | Public TypeScript contracts and examples. |
313
+ | [Tiles](./docs/TILES.md) | Structural outputs and generic/Tiled/Godot formats. |
314
+ | [Endpoint research](./docs/ENDPOINTS.md) | Measured PixelLab API behavior and recipes. |
315
+
316
+ The [public documentation site](https://pixelkiln.griffen.codes/docs) is built by
317
+ the application in [`website/`](./website/README.md). It reads these Markdown
318
+ files directly at build time, so the website and published package share one
319
+ documentation source.
320
+
321
+ Project policies: [Contributing](./CONTRIBUTING.md),
322
+ [Security](./SECURITY.md), and [provider notes](./PROVIDERS.md).
323
+
324
+ ## Scope
325
+
326
+ Animated eight-direction characters and their ZIP/engine-resource export are not
327
+ currently implemented. See the open
328
+ [roadmap issues](https://github.com/gfargo/pixelkiln/issues) for provider and
329
+ workspace-catalog work.
330
+
331
+ ## License
332
+
333
+ [MIT](./LICENSE)
package/SECURITY.md ADDED
@@ -0,0 +1,38 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ Until the first npm release, security fixes are applied to `main`. After
6
+ publication, the latest released line and `main` are supported; older versions
7
+ may be asked to upgrade before a fix is backported.
8
+
9
+ ## Reporting a vulnerability
10
+
11
+ Please use GitHub's private vulnerability report for this repository when it is
12
+ available under the **Security** tab. If that option is unavailable, open a
13
+ minimal issue asking for a private contact channel and do not include exploit
14
+ steps, credentials, private URLs, or affected user data in the issue.
15
+
16
+ Useful reports include:
17
+
18
+ - the affected version or commit;
19
+ - the smallest safe reproduction;
20
+ - expected and observed behavior;
21
+ - impact and whether provider quota, local files, credentials, or account
22
+ objects are at risk;
23
+ - suggested mitigation, if known.
24
+
25
+ Please allow the maintainer time to reproduce and coordinate a fix before
26
+ public disclosure. Credit and disclosure timing will be coordinated with the
27
+ reporter.
28
+
29
+ ## Sensitive areas
30
+
31
+ Pixelkiln handles provider credentials, paid API actions, remote object deletion,
32
+ local output paths, a localhost review server, and generated HTML containing
33
+ provider data. Reports involving authentication leakage, path traversal,
34
+ cross-origin review actions, HTML/script injection, unsafe overwrite/delete
35
+ behavior, lockfile corruption, or budget bypass are security relevant.
36
+
37
+ Never attach a real `PIXELLAB_API_KEY`, `.env` file, private provider URL, or
38
+ unredacted lockfile from a confidential project to a public report.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../dist/cli.js"