SCHEMAXIS · Declared work. Results you can check.Documentation ↗ · Contact
schemaxis/Agent’s Hands

Documentation / aseprite.md
Core 11629ae · View or edit Markdown on GitHub ↗

Aseprite adaptor

schemaxis.aseprite/1 creates small editable RGB sprites with normal image layers, animation frames, a palette, filled raster shapes and animation tags. Host imports, planning and schema generation require only Python 3.10+ and the existing Schemaxis package. Native execution uses the separately installed, user-licensed Aseprite.

The adaptor is available directly from schemaxis.adaptors.aseprite:

import json
from schemaxis.adaptors.aseprite import plan, run, verify, schema, DECLARATIONS

document = json.load(open('examples/schemaxis/aseprite-animation.json'))
prepared = plan(document)  # JSON-compatible; no native process or filesystem work
result = run(document, '/tmp/my-new-sprite-job',
             executable='/path/to/aseprite', timeout=60)
assert verify('/tmp/my-new-sprite-job')['verified']

ASEPRITE_EXE is the optional executable fallback. Supply an absolute executable path and a fresh output directory. The timeout is per native process, greater than zero and at most 600 seconds. Shared registry, CLI, scheduled workflows, generated references and console integration are supported. See media handoffs for ordered publications and the Godot/FFmpeg examples. The conventional declarations module is schemaxis.adaptors.aseprite.adaptor.

Document contract#

A document has exactly version, nodes and output. Each node has an id, filter, options and, except for the first node, inputs: {"sprite": "previousId"}. All operations return kind sprite. Start with exactly one sprite node, use a linear chain and select its final node as output. Branches are rejected because native mutations operate on one editable sprite. Unknown keys and operations fail before launching Aseprite; authored scripts and native reflection are unsupported.

Filter Options and meaning
sprite Required width, height; initial layer defaults to base; durationMS defaults to 100; colours defaults to transparent and white.
layer Required unique name; appends a visible normal layer above existing layers.
frame Appends an empty frame; durationMS defaults to 100. No implicit frame copying.
palette Required colours; replaces the global palette without changing RGB pixel values.
pixel Required layer, x, y, colour; frame defaults to 1.
rect Pixel options plus required positive width, height; filled rectangle.
circle Pixel options plus required nonnegative integer radius; filled integer disk centred at (x,y).
importImage Required absolute PNG source, exact width, height, existing layer, and x, y; frame defaults to 1. Replaces the cel rectangle including transparency.
tag Required unique name, fromFrame, toFrame; optional direction: forward, reverse, pingPong, pingPongReverse.

Coordinates are zero-based canvas pixels; frame indices and tag endpoints are one-based and inclusive. Rectangle coverage is [x,x+width) by [y,y+height). A circle includes pixels whose squared distance from its centre is at most the squared radius; radius zero draws one pixel. Shapes must fit wholly inside the canvas. Draw operations replace pixels in the selected cel. RGBA colours are four integer bytes, with alpha restricted to 255 or transparent [0,0,0,0]. Transparent drawing erases pixels. Partial alpha, blend modes, indexed colour, groups, unbounded image formats, fonts and arbitrary Lua are outside this version's contract.

Limits: 256 nodes, 256×256 canvas, 16 layers, 32 frames, 256 palette entries, 64-character layer/tag names, 1–65535 ms frame durations, and 262144 total canvas×layer×frame pixels. schema() exposes structural validation; plan() also enforces dependencies, bounds, resource limits and supported colour semantics.

Import captured PNG artwork#

importImage turns prepared raster assets into editable artwork cels. Start with the import example, replace both /path/to/badge.png placeholders with the absolute path of badge.png, then run normally. The 6×4 example keeps a blue background below imported artwork, places the same 3×2 asset in two frames, and adds a procedural highlight after import. The variant uses badge-variant.png, changes placement and second-frame duration; the clipping example fails with INVALID_DRAW before opening any source or launching Aseprite.

Placement is replacement, including transparent pixels: the image rectangle replaces earlier pixels in the selected cel. Transparent samples erase earlier pixels in that cel; they reveal lower layers when flattened. Repeated imports into the same cel apply in node order. Every other pixel is preserved. Import into an empty cel creates it, while the named layer and one-based frame must already exist. Later procedural drawing can paint or erase the imported artwork. There is no implicit frame copying, scaling, cropping, clipping or source-over blending.

Declare the source's exact pixel width and height (1–256), and integer x, y for its top-left canvas corner (zero-based, right/down). Planning validates declared bounds and a total limit of 1048576 imported pixels; execution independently checks captured dimensions before native launch. Sources must be absolute local .png regular files, no symlinks, at most 2 MiB each and 16 MiB in total. Only noninterlaced RGBA8 PNG containing IHDR, consecutive IDAT and IEND is accepted. Palette, grayscale, 16-bit, animation, ancillary metadata (including ICC/gamma/sRGB profiles) and partial alpha are rejected with UNSUPPORTED_IMAGE. Prepare plain RGBA sample PNGs beforehand. No colour conversion is performed or promised.

Alpha must be 0 or 255. RGB channels hidden behind alpha zero are normalised to zero for verification because native cel trimming can discard them. Captured original bytes remain unchanged. Opaque channels are compared exactly. The adaptor never interprets embedded profiles, scales images or rounds partial alpha. A wrong dimension raises IMAGE_DIMENSIONS; correct the assertion or the source, then execute in a fresh directory. A missing/nonregular path raises INVALID_RESOURCE. Relative paths and control characters fail planning.

Every run retains input-manifest.json; imports additionally retain inputs/source-NNN.png with node identity, original source path, dimensions and SHA-256 in the manifest. Native Image{fromFile=...} reads only these generated capture names. Offline verification needs the captures, never the original source location. Workflow reuse fingerprints the actual validated source bytes, so changed artwork invalidates reuse. The PNG handoff example places a separately verified procedural icon preview into another editable sprite. Keep captures with exported/copied runs; do not hand-edit their manifest. Fresh runs use this capture contract, including an empty manifest for procedural documents. Earlier procedural evidence without a manifest remains verifiable only with the exact previous trusted worker SHA-256 and all original result/publication/readback checks. Imports always require the new capture contract; a missing or malformed manifest cannot downgrade them. Earlier source-bound qualification receipts remain historical and become stale when adaptor source changes.

Outputs and evidence#

Each job retains authored.json, plan.json, the exact trusted worker.lua, separate build.log and reopen.log, and a structured result.json. Outputs are:

  • sprite.aseprite: editable layers, frames, palette and tags.
  • preview.png: the first composited frame.
  • sheet.png: all composited frames in one horizontal row, untrimmed.
  • sheet.json: schemaxis.aseprite.sheet/1 metadata with sheet dimensions, per-frame rectangles and durations, and named tags with inclusive one-based endpoints.

The Lua worker is a fixed Python string packaged in native_source.py, copied to the job directory. It reads authored values from validated JSON, without source interpolation, load, shell commands or authored paths. The shared schemaxis.dispatch.SubprocessRunner runs a trusted Python launcher that changes to the job directory and replaces itself with Aseprite using os.execv. This preserves the runner's process-group ownership, resource environment and cooperative cancellation. Calls use argument arrays and no shell. Cancellation, timeout and failed execution retain the structured RUNNER_CANCELLED, RUNNER_TIMED_OUT and RUNNER_FAILED faults in result.json. Stage transcripts remain available along with the runner's full logs, resource metrics and successful build-submission.json / reopen-submission.json reports. Aseprite remains a trusted local executable, not a sandbox for hostile plugins or altered worker files.

A second native process reopens the .aseprite and both PNGs. Its independent verification.json records runtime version, dimensions, layer order, frame durations, palette, tags, every cel's canvas pixels and both PNGs' decoded pixels. Cel trimming and absent empty cels are normalised to full transparent canvases. A dependency-free host PNG decoder also checks every preview and sheet pixel directly against the independently decoded captured sources and procedural model. The host compares this readback with a separately implemented Python integer raster model, including normal-layer compositing and sheet frame placement. Neither process exit zero nor file existence is accepted as success.

verify(directory) rechecks the authored plan, independent model, native receipt, sheet metadata and SHA-256 digests of every publication, receipt and retained worker. It is offline verification of retained evidence, not a new native reopen and not a cryptographic attestation against coordinated evidence forgery. Missing, altered, incomplete and invalid evidence fails with structured Schemaxis faults.

Qualification#

ASEPRITE_EXE=/path/to/aseprite \
  PYTHONPATH=src python3 -m unittest discover -s tests/unit -p test_schemaxis_aseprite.py -v
PYTHONPATH=src python3 tools/qualify_aseprite.py \
  --executable /path/to/aseprite \
  --output-directory /tmp/aseprite-qualification-new

The qualification exercises aseprite-icon.json (8×8, transparent cutout) and aseprite-animation.json (16×16, two layers, two frames, palette and ping-pong tag). It also reopens each editable file, adds a layer and known pixel, saves an editable copy, and verifies that change in another fresh native process. Original verified artifacts remain intact. A structured qualification.json summarises the checks. This is bounded CPU batch acceptance; it does not claim GUI appearance review, GPU support or exhaustive Aseprite feature coverage.

Primary API references#

Implementation uses the official batch CLI, Sprite, Image, Cel, Palette, Tag and JSON APIs. Keep machine-specific installation guidance and smoke-test locations in private installation notes, following installation.

Development admission#

This adaptor now provides the development kit delivery contract, operation selection guidance, explicit optional-feature decisions and an editable acceptance example. Run the common host/native conformance recipe and inspect its scoped source-bound receipt; structural admission alone is not native qualification. The current audit records native availability and exact qualification limits.