lenkraster 0.1.0__tar.gz
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.
- lenkraster-0.1.0/ASSET_LICENSE.md +34 -0
- lenkraster-0.1.0/CHANGELOG.md +43 -0
- lenkraster-0.1.0/CONTRIBUTING.md +44 -0
- lenkraster-0.1.0/LICENSE +20 -0
- lenkraster-0.1.0/MANIFEST.in +19 -0
- lenkraster-0.1.0/PKG-INFO +412 -0
- lenkraster-0.1.0/PYPI_README.md +375 -0
- lenkraster-0.1.0/README.md +375 -0
- lenkraster-0.1.0/SECURITY.md +52 -0
- lenkraster-0.1.0/THIRD_PARTY_NOTICES.md +41 -0
- lenkraster-0.1.0/docs/examples/README.md +21 -0
- lenkraster-0.1.0/docs/name-clearance.md +29 -0
- lenkraster-0.1.0/docs/release-checklist.md +59 -0
- lenkraster-0.1.0/mcp/lenkraster_mcp.py +15 -0
- lenkraster-0.1.0/pyproject.toml +53 -0
- lenkraster-0.1.0/requirements/ci.txt +10 -0
- lenkraster-0.1.0/requirements/release.in +10 -0
- lenkraster-0.1.0/requirements/release.txt +710 -0
- lenkraster-0.1.0/scripts/audit_legal_content.py +189 -0
- lenkraster-0.1.0/scripts/audit_public_tree.py +201 -0
- lenkraster-0.1.0/setup.cfg +4 -0
- lenkraster-0.1.0/skills/pixel-color-ramps/SKILL.md +47 -0
- lenkraster-0.1.0/skills/pixel-craft-critique/SKILL.md +51 -0
- lenkraster-0.1.0/skills/references/craft-rules.md +98 -0
- lenkraster-0.1.0/skills/references/motion-timing.md +62 -0
- lenkraster-0.1.0/src/lenkraster/__init__.py +23 -0
- lenkraster-0.1.0/src/lenkraster/aseprite.py +815 -0
- lenkraster-0.1.0/src/lenkraster/cli.py +237 -0
- lenkraster-0.1.0/src/lenkraster/critic.py +539 -0
- lenkraster-0.1.0/src/lenkraster/cycle.py +413 -0
- lenkraster-0.1.0/src/lenkraster/data/palettes/lenk-cinder-16.json +1 -0
- lenkraster-0.1.0/src/lenkraster/data/palettes/lenk-fern-4.json +1 -0
- lenkraster-0.1.0/src/lenkraster/data/palettes/lenk-signal-16.json +1 -0
- lenkraster-0.1.0/src/lenkraster/data/palettes/lenk-studio-32.json +1 -0
- lenkraster-0.1.0/src/lenkraster/mcp_main.py +7 -0
- lenkraster-0.1.0/src/lenkraster/mcp_server.py +931 -0
- lenkraster-0.1.0/src/lenkraster/palette.py +428 -0
- lenkraster-0.1.0/src/lenkraster/shadow.py +644 -0
- lenkraster-0.1.0/src/lenkraster.egg-info/PKG-INFO +412 -0
- lenkraster-0.1.0/src/lenkraster.egg-info/SOURCES.txt +52 -0
- lenkraster-0.1.0/src/lenkraster.egg-info/dependency_links.txt +1 -0
- lenkraster-0.1.0/src/lenkraster.egg-info/entry_points.txt +3 -0
- lenkraster-0.1.0/src/lenkraster.egg-info/requires.txt +11 -0
- lenkraster-0.1.0/src/lenkraster.egg-info/top_level.txt +1 -0
- lenkraster-0.1.0/tests/test_aseprite.py +433 -0
- lenkraster-0.1.0/tests/test_aseprite_real.py +128 -0
- lenkraster-0.1.0/tests/test_cli.py +246 -0
- lenkraster-0.1.0/tests/test_critic.py +298 -0
- lenkraster-0.1.0/tests/test_cycle.py +499 -0
- lenkraster-0.1.0/tests/test_mcp.py +764 -0
- lenkraster-0.1.0/tests/test_mcp_wheel.py +194 -0
- lenkraster-0.1.0/tests/test_palette.py +369 -0
- lenkraster-0.1.0/tests/test_release_configuration.py +234 -0
- lenkraster-0.1.0/tests/test_shadow.py +507 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Asset license
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ryan Lenk.
|
|
4
|
+
|
|
5
|
+
Unless a file states otherwise, every repository-authored visual asset, palette JSON,
|
|
6
|
+
example fixture, and documentation image in this repository is licensed under the
|
|
7
|
+
MIT License in [`LICENSE`](LICENSE), to the extent the material is protected by copyright.
|
|
8
|
+
This permission includes the four built-in palettes:
|
|
9
|
+
|
|
10
|
+
- Lenk Cinder 16
|
|
11
|
+
- Lenk Fern 4
|
|
12
|
+
- Lenk Signal 16
|
|
13
|
+
- Lenk Studio 32
|
|
14
|
+
|
|
15
|
+
Those palettes were created specifically for LenkRaster from independently selected RGB
|
|
16
|
+
values. They are not derived from or compatible-name copies of a third-party palette.
|
|
17
|
+
Their `author` field identifies Ryan Lenk. The exact release-candidate files are pinned
|
|
18
|
+
here so later changes are visible:
|
|
19
|
+
|
|
20
|
+
| File | SHA-256 |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `lenk-cinder-16.json` | `ce0fbb4c6e96b814356da83e23bb1fac536026a5bab198449008d1e37bf666d1` |
|
|
23
|
+
| `lenk-fern-4.json` | `9e3a08c13a530ce442085c6d724e57cd61f198db9bb456124fe2e25973a60683` |
|
|
24
|
+
| `lenk-signal-16.json` | `07eb4c2220e3cf72be559907ffc1dcc6d92401bf44b8716fe350e610018bd8fb` |
|
|
25
|
+
| `lenk-studio-32.json` | `d5570602f593d4d2645d142c81b06cb38892b85eb5873b36bde95915fc68f51a` |
|
|
26
|
+
|
|
27
|
+
The demonstration artwork was created at Ryan Lenk's direction with OpenAI image-generation
|
|
28
|
+
tools and without an external character, logo, or artwork reference. The license grant
|
|
29
|
+
above applies to any rights Ryan Lenk can license in those outputs. It does not claim
|
|
30
|
+
exclusive rights in unprotectable, public-domain, or third-party material.
|
|
31
|
+
|
|
32
|
+
The embedded content-credentials metadata in generated images is provenance information,
|
|
33
|
+
not an additional license or endorsement. Aseprite was used only as an operator-installed
|
|
34
|
+
editing/export tool and is not bundled with these assets.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to LenkRaster will be documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases
|
|
6
|
+
use semantic versioning once the first public tag is created.
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Optional, bounded Aseprite CLI export and direct cycle-QA integration.
|
|
13
|
+
- Two Aseprite MCP tools and matching CLI/Python APIs.
|
|
14
|
+
- Public security policy, contributing guide, release checklist, dependency audit, and
|
|
15
|
+
secret/path artifact checks.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Adopt the pre-release `LenkRaster` identity across the distribution, import package,
|
|
20
|
+
command-line entry points, local MCP server, repository links, and environment variables.
|
|
21
|
+
- Replace all previously bundled palettes with four original Ryan Lenk palettes and add
|
|
22
|
+
explicit asset licensing, provenance, third-party notices, and a name-screen record.
|
|
23
|
+
|
|
24
|
+
### Security
|
|
25
|
+
|
|
26
|
+
- Require an explicit MCP trusted root for every tool call.
|
|
27
|
+
- Require Python 3.10+, Pillow 12.3+, and a current reproducible CI dependency set.
|
|
28
|
+
- Validate Aseprite metadata and PNG sheets before publishing or analysis.
|
|
29
|
+
- Keep Aseprite invocation fixed, non-shell, time-bounded, and create-only.
|
|
30
|
+
- Contain user-owned palette files below an explicit trusted root and validate their
|
|
31
|
+
schema, encoded size, metadata, color count, and unique RGB values before image work.
|
|
32
|
+
|
|
33
|
+
### Removed
|
|
34
|
+
|
|
35
|
+
- Private project-specific calibration reports, adapter code, tests, and handoff material
|
|
36
|
+
from the public source tree.
|
|
37
|
+
- All externally authored palette data and ambiguous palette provenance; users may supply
|
|
38
|
+
lawfully obtained values through the bounded custom-palette interface.
|
|
39
|
+
|
|
40
|
+
## [0.1.0] - Unreleased
|
|
41
|
+
|
|
42
|
+
- Initial bounded critic, palette lab, animation QA, golden-corpus runner, CLI, and local
|
|
43
|
+
stdio MCP server.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
LenkRaster welcomes small, evidence-backed improvements to its deterministic pixel-art
|
|
4
|
+
engines and trusted-local interfaces.
|
|
5
|
+
|
|
6
|
+
## Development setup
|
|
7
|
+
|
|
8
|
+
Use Python 3.10 or newer in an isolated environment:
|
|
9
|
+
|
|
10
|
+
```console
|
|
11
|
+
python -m venv .venv
|
|
12
|
+
python -m pip install --upgrade pip
|
|
13
|
+
python -m pip install -c requirements/ci.txt -e ".[dev]"
|
|
14
|
+
python -m pytest tests -q
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Before submitting a change, also run:
|
|
18
|
+
|
|
19
|
+
```console
|
|
20
|
+
python -m pip check
|
|
21
|
+
python -m pip_audit --skip-editable
|
|
22
|
+
python -m bandit -q -r src
|
|
23
|
+
python scripts/audit_public_tree.py
|
|
24
|
+
python -m build
|
|
25
|
+
python scripts/audit_public_tree.py dist
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Engineering expectations
|
|
29
|
+
|
|
30
|
+
- Reproduce defects with a failing test before changing implementation.
|
|
31
|
+
- Keep all file, image, animation, JSON, request, and subprocess work explicitly bounded.
|
|
32
|
+
- Preserve trusted-root containment, path-free public failures, and create-only outputs.
|
|
33
|
+
- Use argument vectors with `shell=False`; never accept arbitrary subprocess flags or
|
|
34
|
+
scripts through MCP.
|
|
35
|
+
- Keep the MCP server local stdio only.
|
|
36
|
+
- Preserve advisory semantics. A score or cycle result is not art approval.
|
|
37
|
+
- Add synthetic fixtures in tests. Never commit private, client-owned, or proprietary art.
|
|
38
|
+
- Do not vendor or redistribute Aseprite, its binaries, or licensed sample content.
|
|
39
|
+
- Do not add secrets, workstation paths, personal email addresses, or `.env` files.
|
|
40
|
+
|
|
41
|
+
## Pull requests
|
|
42
|
+
|
|
43
|
+
Describe the original scenario, the new test, security-boundary impact, and the exact
|
|
44
|
+
verification performed. Keep unrelated refactors separate.
|
lenkraster-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ryan Lenk
|
|
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, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
|
20
|
+
OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
include CHANGELOG.md
|
|
2
|
+
include ASSET_LICENSE.md
|
|
3
|
+
include CONTRIBUTING.md
|
|
4
|
+
include LICENSE
|
|
5
|
+
include README.md
|
|
6
|
+
include PYPI_README.md
|
|
7
|
+
include SECURITY.md
|
|
8
|
+
include THIRD_PARTY_NOTICES.md
|
|
9
|
+
recursive-include docs *.md
|
|
10
|
+
recursive-include mcp *.py
|
|
11
|
+
recursive-include requirements *.in *.txt
|
|
12
|
+
recursive-include scripts *.py
|
|
13
|
+
recursive-include skills *.md
|
|
14
|
+
recursive-include tests *.py
|
|
15
|
+
global-exclude *.py[cod]
|
|
16
|
+
global-exclude .DS_Store
|
|
17
|
+
prune .claude
|
|
18
|
+
prune build
|
|
19
|
+
prune dist
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lenkraster
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Bounded pixel-art critique, palette, animation QA, Aseprite, and local MCP tools.
|
|
5
|
+
Author: Ryan Lenk
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/itsryanlenk/lenkraster
|
|
8
|
+
Project-URL: Documentation, https://github.com/itsryanlenk/lenkraster#readme
|
|
9
|
+
Project-URL: Issues, https://github.com/itsryanlenk/lenkraster/issues
|
|
10
|
+
Project-URL: Security, https://github.com/itsryanlenk/lenkraster/security/policy
|
|
11
|
+
Keywords: pixel-art,sprites,aseprite,game-dev,mcp,color,critique
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Artistic Software
|
|
21
|
+
Classifier: Topic :: Games/Entertainment
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
License-File: ASSET_LICENSE.md
|
|
26
|
+
License-File: THIRD_PARTY_NOTICES.md
|
|
27
|
+
Requires-Dist: numpy<3,>=2.0
|
|
28
|
+
Requires-Dist: Pillow<13,>=12.3
|
|
29
|
+
Provides-Extra: mcp
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: bandit==1.9.4; extra == "dev"
|
|
32
|
+
Requires-Dist: build==1.5.0; extra == "dev"
|
|
33
|
+
Requires-Dist: pip-audit==2.10.1; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest==9.1.1; extra == "dev"
|
|
35
|
+
Requires-Dist: setuptools==84.0.0; extra == "dev"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# LenkRaster
|
|
39
|
+
|
|
40
|
+

|
|
41
|
+
|
|
42
|
+
LenkRaster is a deterministic, bounded toolkit for inspecting and preparing pixel art.
|
|
43
|
+
It combines craft critique, palette operations, animation-cycle QA, an optional Aseprite
|
|
44
|
+
CLI bridge, a command-line interface, a Python API, and a trusted-local stdio MCP server.
|
|
45
|
+
|
|
46
|
+
LenkRaster is designed for agent workflows without turning an agent into an art director:
|
|
47
|
+
its reports are advisory evidence and retry hints. It does not approve artwork, replace
|
|
48
|
+
human review, or replace a project's composition, provenance, and release gates.
|
|
49
|
+
|
|
50
|
+
## What it does
|
|
51
|
+
|
|
52
|
+
- Scores bounded PNG sprites against explainable pixel-craft checks.
|
|
53
|
+
- Builds OKLCH hue-shifted material ramps.
|
|
54
|
+
- Quantizes PNGs against original built-ins or bounded user-owned palette JSON without
|
|
55
|
+
overwriting existing files.
|
|
56
|
+
- Reports same-hue contrast and palette structure.
|
|
57
|
+
- Measures animation motion and visibility using rendered-pixel math.
|
|
58
|
+
- Exports and directly checks trusted local `.ase`/`.aseprite` documents through a
|
|
59
|
+
separately installed Aseprite CLI.
|
|
60
|
+
- Exposes the same bounded operations to local MCP clients over stdio.
|
|
61
|
+
- Replays user-owned, SHA-256-pinned golden corpora without promoting results to approval.
|
|
62
|
+
|
|
63
|
+
No GPU, API key, model download, browser, network service, or persistent daemon is
|
|
64
|
+
required.
|
|
65
|
+
|
|
66
|
+
## See it in action
|
|
67
|
+
|
|
68
|
+
These are real outputs from the current LenkRaster CLI. The public source art and its
|
|
69
|
+
provenance are documented in
|
|
70
|
+
[docs/examples](https://github.com/itsryanlenk/lenkraster/blob/main/docs/examples/README.md).
|
|
71
|
+
|
|
72
|
+
### One fixed palette across an animation
|
|
73
|
+
|
|
74
|
+
Palette normalization is constraint enforcement for asset pipelines, not an attempt to
|
|
75
|
+
"improve" an artist's source image. This four-frame hammer cycle intentionally contains
|
|
76
|
+
frame-exclusive RGB variation. LenkRaster maps it to one repository-owned 48-color target
|
|
77
|
+
without changing the poses or overwriting the source.
|
|
78
|
+
|
|
79
|
+
| Source cycle | Fixed target | Verified output |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| 77,766 distinct visible RGB values | 48 user-owned colors | 48/48 used; every visible output color belongs to the target |
|
|
82
|
+
|
|
83
|
+

|
|
84
|
+
|
|
85
|
+
<details>
|
|
86
|
+
<summary>Inspect the unnormalized source strip</summary>
|
|
87
|
+
|
|
88
|
+

|
|
89
|
+
|
|
90
|
+
</details>
|
|
91
|
+
|
|
92
|
+
```console
|
|
93
|
+
lenkraster quantize docs/examples/hammer-cycle-source.png \
|
|
94
|
+
--palette-file docs/examples/hammer-cycle-palette.json \
|
|
95
|
+
--root <absolute-path-to-repository> \
|
|
96
|
+
--out hammer-cycle-local-output.png
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Use the same palette file and settings for separately stored frames. `cycle` measures
|
|
100
|
+
rendered-pixel motion and visibility; it does not claim to judge visual quality or prove
|
|
101
|
+
palette membership.
|
|
102
|
+
|
|
103
|
+
### Aseprite export and cycle QA
|
|
104
|
+
|
|
105
|
+
The same four poses were assembled into a tagged `hammer` animation and exercised through
|
|
106
|
+
the separately installed, SHA-256-pinned Aseprite CLI bridge:
|
|
107
|
+
|
|
108
|
+
| Validated export | Advisory cycle report |
|
|
109
|
+
|---|---|
|
|
110
|
+
| 4 frames; 543x724 each; 120 ms per frame | `PASS`; 3/3 adjacent transitions detected; no issues |
|
|
111
|
+
|
|
112
|
+
LenkRaster exported the horizontal sheet and sanitized metadata into a new directory, then
|
|
113
|
+
ran the cycle check from a separate transient export. The `.aseprite` working document is
|
|
114
|
+
not distributed in the package or public repository.
|
|
115
|
+
|
|
116
|
+
### Color construction
|
|
117
|
+
|
|
118
|
+
| Seven-stop OKLCH material ramp | Ordered 4x4 Bayer dither |
|
|
119
|
+
|---|---|
|
|
120
|
+
|  |  |
|
|
121
|
+
|
|
122
|
+
```console
|
|
123
|
+
lenkraster ramp --color "#FF6B35" --stops 7 --drift -10 \
|
|
124
|
+
--out docs/examples/material-ramp.png
|
|
125
|
+
lenkraster dither --a "#2196F3" --b "#FFEB3B" --size 256 --order 4 \
|
|
126
|
+
--out docs/examples/ordered-dither.png
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
These examples demonstrate deterministic transformations, not artwork approval; critique
|
|
130
|
+
and animation QA remain advisory evidence for human review.
|
|
131
|
+
|
|
132
|
+
## Security model
|
|
133
|
+
|
|
134
|
+
LenkRaster processes image files, so limits and containment are part of its public
|
|
135
|
+
contract:
|
|
136
|
+
|
|
137
|
+
- MCP file operations require an explicit, existing `LENKRASTER_TRUSTED_ROOT`.
|
|
138
|
+
- Resolved inputs and outputs must remain beneath that root; traversal and symlink escapes
|
|
139
|
+
fail closed.
|
|
140
|
+
- PNG encoded bytes, decoded pixels, dimensions, frame discovery, frame count, total
|
|
141
|
+
pixels, pair work, JSON size, and MCP request size are bounded.
|
|
142
|
+
- Quantized and Aseprite exports are create-only. Existing files and directories are never
|
|
143
|
+
overwritten.
|
|
144
|
+
- Public errors are fixed messages and do not include local paths or subprocess output.
|
|
145
|
+
- The server is trusted-local stdio only. It is not a network service and must not be
|
|
146
|
+
exposed as public HTTP.
|
|
147
|
+
|
|
148
|
+
The optional Aseprite bridge executes a native application and is not an operating-system
|
|
149
|
+
sandbox. Only process documents you trust. Use an OS sandbox for hostile or untrusted
|
|
150
|
+
Aseprite files.
|
|
151
|
+
|
|
152
|
+
See [SECURITY.md](https://github.com/itsryanlenk/lenkraster/blob/main/SECURITY.md) for
|
|
153
|
+
reporting and the maintained threat boundary.
|
|
154
|
+
|
|
155
|
+
## Requirements
|
|
156
|
+
|
|
157
|
+
- Python 3.10 or newer
|
|
158
|
+
- NumPy 2.x
|
|
159
|
+
- Pillow 12.3 or newer within the 12.x line
|
|
160
|
+
- Optional: Aseprite 1.3.17.2 or newer in the 1.3 line for `.ase`/`.aseprite`
|
|
161
|
+
integration
|
|
162
|
+
|
|
163
|
+
Aseprite is not bundled, downloaded, or redistributed by LenkRaster. It is a separate
|
|
164
|
+
product with its own license. LenkRaster is compatible with its documented CLI and is not
|
|
165
|
+
affiliated with or endorsed by Aseprite.
|
|
166
|
+
|
|
167
|
+
## Install
|
|
168
|
+
|
|
169
|
+
From PyPI:
|
|
170
|
+
|
|
171
|
+
```console
|
|
172
|
+
python -m pip install lenkraster
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The distribution and installed Python package are both `lenkraster`. The command-line
|
|
176
|
+
entry points are `lenkraster` and `lenkraster-mcp`.
|
|
177
|
+
|
|
178
|
+
From a checked-out source tree:
|
|
179
|
+
|
|
180
|
+
```console
|
|
181
|
+
python -m venv .venv
|
|
182
|
+
.venv/Scripts/python -m pip install --upgrade pip
|
|
183
|
+
.venv/Scripts/python -m pip install .
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
On macOS or Linux, use `.venv/bin/python` in place of
|
|
187
|
+
`.venv/Scripts/python`.
|
|
188
|
+
|
|
189
|
+
For development:
|
|
190
|
+
|
|
191
|
+
```console
|
|
192
|
+
python -m pip install -c requirements/ci.txt -e ".[dev]"
|
|
193
|
+
python -m pytest tests -q
|
|
194
|
+
python -m pip check
|
|
195
|
+
python -m pip_audit --skip-editable
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## CLI
|
|
199
|
+
|
|
200
|
+
```console
|
|
201
|
+
lenkraster critique sprite.png
|
|
202
|
+
lenkraster critique sheet.png --json report.json
|
|
203
|
+
lenkraster ramp --color "#d77643" --stops 5 --drift -8 --out swatches.png
|
|
204
|
+
lenkraster dither --a "#ac530b" --b "#ffe0cc" --order 4 --out gradient.png
|
|
205
|
+
lenkraster check --file sprite.png
|
|
206
|
+
lenkraster quantize frame.png --palette lenk-studio-32 --out snapped.png
|
|
207
|
+
lenkraster quantize frame.png --palette-file palettes/my-palette.json \
|
|
208
|
+
--root <absolute-path-to-sprite-workspace> --out snapped-custom.png
|
|
209
|
+
lenkraster palettes
|
|
210
|
+
lenkraster cycle "frame-*.png"
|
|
211
|
+
lenkraster shadow corpus/manifest.json --manifest-sha256 <sha256>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
`cycle` returns exit code 0 for `PASS` and 1 for `REVIEW`. A review result is
|
|
215
|
+
not a release rejection unless your project has separately adopted that policy.
|
|
216
|
+
|
|
217
|
+
### User-owned palette files
|
|
218
|
+
|
|
219
|
+
`lenkraster palettes` lists the four original built-ins: `lenk-cinder-16`, `lenk-fern-4`,
|
|
220
|
+
`lenk-signal-16`, and `lenk-studio-32`. A user-owned palette is a UTF-8 JSON file below an
|
|
221
|
+
explicit trusted root:
|
|
222
|
+
|
|
223
|
+
| Built-in | Colors | Intended use |
|
|
224
|
+
|---|---:|---|
|
|
225
|
+
| `lenk-fern-4` | 4 | Compact moss-and-ink monochrome work |
|
|
226
|
+
| `lenk-cinder-16` | 16 | Warm industrial sprites and environment tiles |
|
|
227
|
+
| `lenk-signal-16` | 16 | High-contrast characters and UI accents |
|
|
228
|
+
| `lenk-studio-32` | 32 | General-purpose multi-material sprite work |
|
|
229
|
+
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"name": "My fixed palette",
|
|
233
|
+
"author": "Local user",
|
|
234
|
+
"colors": ["102030", "f0e0d0"]
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Palette files are limited to 16 KiB, 2-64 unique six-digit RGB colors, exact keys, and
|
|
239
|
+
bounded path-free metadata. MCP callers use `palette_file` relative to
|
|
240
|
+
`LENKRASTER_TRUSTED_ROOT`; CLI callers use `--palette-file` with `--root`.
|
|
241
|
+
|
|
242
|
+
Common 4-, 16-, and 32-color external palette workflows were exercised during
|
|
243
|
+
pre-publication compatibility testing. Users may place any lawfully obtained palette in
|
|
244
|
+
their own local JSON file and use the same `palette_file` interface. Users remain
|
|
245
|
+
responsible for the provenance and permitted use of supplied palettes.
|
|
246
|
+
|
|
247
|
+
### Optional Aseprite bridge
|
|
248
|
+
|
|
249
|
+
Set the executable to an absolute path:
|
|
250
|
+
|
|
251
|
+
```console
|
|
252
|
+
LENKRASTER_ASEPRITE_EXECUTABLE=<absolute-path-to-aseprite>
|
|
253
|
+
LENKRASTER_ASEPRITE_SHA256=<sha256-of-that-executable>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
The SHA-256 pin is strongly recommended. LenkRaster checks it before the version probe
|
|
257
|
+
and again immediately before export, and rejects unsupported Aseprite versions. Recompute
|
|
258
|
+
the pin whenever Aseprite is intentionally updated.
|
|
259
|
+
|
|
260
|
+
Export a horizontal sheet and sanitized manifest into a directory that does not yet exist:
|
|
261
|
+
|
|
262
|
+
```console
|
|
263
|
+
lenkraster aseprite-export hero.aseprite \
|
|
264
|
+
--root <absolute-path-to-sprite-workspace> \
|
|
265
|
+
--out-dir exports/hero \
|
|
266
|
+
--tag walk
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Run cycle QA without retaining exported files:
|
|
270
|
+
|
|
271
|
+
```console
|
|
272
|
+
lenkraster aseprite-cycle hero.aseprite \
|
|
273
|
+
--root <absolute-path-to-sprite-workspace> \
|
|
274
|
+
--tag walk \
|
|
275
|
+
--motion-threshold 12 \
|
|
276
|
+
--min-motion-pixels 6
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
The bridge passes a fixed argument vector to Aseprite batch mode. Callers cannot supply
|
|
280
|
+
scripts, arbitrary flags, output filenames, or shell fragments. Tag and layer selections
|
|
281
|
+
are optional bounded labels; nested layers use `/` (for example,
|
|
282
|
+
`characters/hero body`) and Unicode names are supported. Each invocation uses a fresh
|
|
283
|
+
disposable Aseprite user/configuration folder and a snapshotted input document, so the
|
|
284
|
+
operator's normal Aseprite extensions and preferences are not loaded. Validated output is
|
|
285
|
+
written to a hidden staging directory and becomes visible with one final create-only
|
|
286
|
+
directory rename.
|
|
287
|
+
|
|
288
|
+
## MCP server
|
|
289
|
+
|
|
290
|
+
Any MCP-speaking client can launch the installed one-shot stdio server. Always use
|
|
291
|
+
absolute paths in the client configuration:
|
|
292
|
+
|
|
293
|
+
```json
|
|
294
|
+
{
|
|
295
|
+
"mcpServers": {
|
|
296
|
+
"lenkraster": {
|
|
297
|
+
"command": "<absolute-path-to-venv>/Scripts/lenkraster-mcp.exe",
|
|
298
|
+
"args": [],
|
|
299
|
+
"env": {
|
|
300
|
+
"LENKRASTER_TRUSTED_ROOT": "<absolute-path-to-disposable-sprite-workspace>",
|
|
301
|
+
"LENKRASTER_ASEPRITE_EXECUTABLE": "<absolute-path-to-aseprite>",
|
|
302
|
+
"LENKRASTER_ASEPRITE_SHA256": "<sha256-of-that-executable>"
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
The Aseprite variables are optional when those tools are not used. The trusted-root
|
|
310
|
+
variable is required for every tool call. MCP clients cannot override the configured
|
|
311
|
+
executable or its SHA-256 pin.
|
|
312
|
+
|
|
313
|
+
LenkRaster exposes seven tools:
|
|
314
|
+
|
|
315
|
+
| Tool | Purpose |
|
|
316
|
+
|---|---|
|
|
317
|
+
| `critique_sprite` | Score one bounded PNG and return findings/retry hints. |
|
|
318
|
+
| `make_ramp` | Generate a bounded OKLCH material ramp. |
|
|
319
|
+
| `palette_quantize` | Create a new PNG using an original built-in or trusted user palette. |
|
|
320
|
+
| `contrast_report` | Report same-hue lightness separation. |
|
|
321
|
+
| `qa_cycle` | Check 2-32 same-size PNG frames matched by a relative glob. |
|
|
322
|
+
| `aseprite_export` | Create a validated sheet and path-free manifest. |
|
|
323
|
+
| `qa_aseprite_cycle` | Export transiently and run bounded cycle QA. |
|
|
324
|
+
|
|
325
|
+
Project-specific adapters and private art corpora are intentionally outside the MCP
|
|
326
|
+
surface and the distribution.
|
|
327
|
+
|
|
328
|
+
## Python API
|
|
329
|
+
|
|
330
|
+
```python
|
|
331
|
+
from lenkraster import (
|
|
332
|
+
critique,
|
|
333
|
+
export_aseprite_document,
|
|
334
|
+
load_palette_file,
|
|
335
|
+
make_ramp,
|
|
336
|
+
qa_aseprite_document,
|
|
337
|
+
qa_cycle,
|
|
338
|
+
quantize_file,
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
report = critique("sprite.png")
|
|
342
|
+
print(report["score"], report["retry_hints"])
|
|
343
|
+
|
|
344
|
+
ramp = make_ramp("#d77643", stops=5, drift=-8.0)
|
|
345
|
+
quantize_file("frame.png", "lenk-studio-32", "snapped.png")
|
|
346
|
+
load_palette_file("palettes/my-palette.json", trusted_root="sprite-workspace")
|
|
347
|
+
quantize_file(
|
|
348
|
+
"frame.png",
|
|
349
|
+
None,
|
|
350
|
+
"snapped-custom.png",
|
|
351
|
+
palette_file="palettes/my-palette.json",
|
|
352
|
+
palette_root="sprite-workspace",
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
motion = qa_cycle(
|
|
356
|
+
["base.png", "frame-1.png", "frame-2.png"],
|
|
357
|
+
roi=(12, 8, 44, 40),
|
|
358
|
+
transition_groups={"walk": [(0, 1), (1, 2)]},
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
export_manifest = export_aseprite_document(
|
|
362
|
+
"hero.aseprite",
|
|
363
|
+
"exports/hero",
|
|
364
|
+
trusted_root="sprite-workspace",
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
aseprite_motion = qa_aseprite_document(
|
|
368
|
+
"hero.aseprite",
|
|
369
|
+
trusted_root="sprite-workspace",
|
|
370
|
+
tag="walk",
|
|
371
|
+
)
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
For the Aseprite Python API, configure `LENKRASTER_ASEPRITE_EXECUTABLE` or pass an
|
|
375
|
+
absolute executable path through the trusted local API. MCP clients cannot choose the
|
|
376
|
+
executable.
|
|
377
|
+
|
|
378
|
+
## Design laws
|
|
379
|
+
|
|
380
|
+
- **Rendered-pixel law:** RGB beneath fully transparent pixels does not affect critique,
|
|
381
|
+
contrast, quantization, or motion.
|
|
382
|
+
- **Shared-palette law:** animation frames should use the same fixed target palette and
|
|
383
|
+
settings.
|
|
384
|
+
- **Motion-group law:** every authored gesture group must independently contain a
|
|
385
|
+
qualifying transition.
|
|
386
|
+
- **Vision-is-not-QA law:** animation correctness is computed from pixels, not inferred
|
|
387
|
+
from thumbnails.
|
|
388
|
+
- **Bounded-work law:** encoded bytes, decoded pixels, frames, discovery, and comparisons
|
|
389
|
+
fail closed at explicit ceilings.
|
|
390
|
+
- **Advisory law:** LenkRaster produces evidence and retry hints, never art approval.
|
|
391
|
+
|
|
392
|
+
## Golden-corpus regression
|
|
393
|
+
|
|
394
|
+
`lenkraster shadow` accepts a bounded, caller-hash-pinned manifest containing
|
|
395
|
+
user-owned PNG fixtures. Automated cases report `BASELINE_MATCH` or `DRIFT`;
|
|
396
|
+
contextual cases remain `HUMAN_REVIEW`. Do not commit proprietary or private artwork to
|
|
397
|
+
this public repository.
|
|
398
|
+
|
|
399
|
+
## Development and release
|
|
400
|
+
|
|
401
|
+
Contributions are welcome; read
|
|
402
|
+
[CONTRIBUTING.md](https://github.com/itsryanlenk/lenkraster/blob/main/CONTRIBUTING.md).
|
|
403
|
+
Public artifact checks
|
|
404
|
+
and release provenance steps are documented in
|
|
405
|
+
[docs/release-checklist.md](https://github.com/itsryanlenk/lenkraster/blob/main/docs/release-checklist.md).
|
|
406
|
+
|
|
407
|
+
The source and repository-authored assets are MIT licensed. See
|
|
408
|
+
[ASSET_LICENSE.md](https://github.com/itsryanlenk/lenkraster/blob/main/ASSET_LICENSE.md)
|
|
409
|
+
for palette and image scope, and
|
|
410
|
+
[THIRD_PARTY_NOTICES.md](https://github.com/itsryanlenk/lenkraster/blob/main/THIRD_PARTY_NOTICES.md)
|
|
411
|
+
for dependency, method, and optional-tool notices. User-supplied palettes and Aseprite
|
|
412
|
+
itself are not part of this distribution.
|