pixel · diff
git:20261014.71d43e0 to git:20261014.6153eb2
39 added, 45 removed. Audit A to A.
---
name: pixel
description: >
- Snap generated images to a pixel grid, remove flat backgrounds into hard-alpha
- cutouts, and join ordered managed-image poses into a shared-grid sprite strip.
+ Turn generated images into true pixel-art sprites: pixel.sprites cuts a
+ generated sheet into pieces at the density it was drawn at (with an outline
+ check), pixel.snap / pixel.cutout / pixel.strip for single images, cutouts and
+ animation strips. Decide a sprite's density in the generation prompt; never
+ resample to hit an on-screen size.
---
- # Pixel — Agent Guide
-
- ## When to Use This Pack
-
- Use this pack when a generated image should become true pixel art (hard
- edges, one colour per logical cell, optional brand palette) or needs a
- transparent cutout. Typical source: Codex `gpt-image` output, which looks
- pixelated but has soft edges, non-integer block sizes, and an opaque background.
-
- Do not use it to generate images (use `generation`) or to smooth or upscale art
- (`generation.generate_image_upscale` smooths edges, which is the wrong direction).
-
- ## Entrypoints
+ # Pixel — make sprites from a generated sheet
- Both actions take a media handle as `image`: a generation output row
- (`gen.output("generated_images")`), `"run:<run_id>/generated_images#n"`, or the
- `"sha256:<digest>"` of a file you imported with `python3 -m astrid media import`.
+ Choose each sprite's density when generating it. At the film's one integer
+ art-pixel scale, native width determines on-screen width. Prompt for the
+ target cell count, for example: **"each icon about 44 pixels wide, every pixel
+ a perfect square of identical size"**. Then use `pixel.sprites` on the sheet
+ and place its native RGBA outputs on the timeline at that one scale. Never
+ resample a finished sprite to hit an on-screen size; that breaks 1-px outlines.
```python
import astrid.sdk as sdk
- from astrid.sdk import AstridClient
- with AstridClient.open_from_launcher() as client: # sdk.invoke needs an explicit client
- snapped = sdk.invoke("pixel.snap", kind="action", project="almost-ready", client=client, wait=True,
- inputs={"image": "run:<run_id>/generated_images#0", "grid_width": 48, "grid_height": 48, "fit": "none"})
- cutout = sdk.invoke("pixel.cutout", kind="action", project="almost-ready", client=client, wait=True,
- inputs={"image": "run:<run_id>/generated_images#0", "mode": "flat", "grid": "48x48", "fit": "none"})
- native = snapped.output("native") # a handle: pass it on, or client.media.read_bytes(native["digest"])
+ result = sdk.invoke(
+ "pixel.sprites", kind="action", project="almost-ready", wait=True,
+ inputs={"image": "run:<run_id>/generated_images#0", "mode": "chroma",
+ "cells": "4x2", "scale": 5},
+ )
+ result.raise_for_error()
+ print(result.outputs["artifacts"]) # sprites#0..n, preview, report
```
- Invocations are admitted as tasks. Identical inputs reuse the existing task,
- so after a fix re-run with `python3 -m astrid tasks retry <task-id> --project almost-ready`.
-
- Pass `crop` as JSON text containing {x, y, width, height} in source pixels to
- either action to cut a region first, for example a character pose out of a
- reference sheet.
-
- ## Actions
+ `image` accepts a generation output row, `run:<run_id>/<port>#n`, or an imported
+ `sha256:<digest>` media handle. `pixel.sprites` detects the drawn block or accepts
+ `block` in source pixels, snaps at that density, reuses cutout's `chroma`,
+ `flat`, or `luma` background removal, and splits connected pieces. Use
+ `cells: "4x2"` for a regular sheet; omit it for connected components.
+ `merge_distance` (default 3 native cells) keeps nearby detached details with
+ their piece. `padding` (default 2) is transparent native cells. The indexed
+ contact sheet is `preview`; `report` gives source boxes, native and on-screen
+ sizes at `scale`, and each sprite's dark-outline boundary fraction.
- | Action | What it does |
- |---|---|
- | `pixel.snap` | Mode-downsamples onto an explicit grid (`grid_width`/`grid_height`, `fit`) or a detected lattice (`auto_grid`). Optional `palette` (`astrid` preset or hex list) or `max_colors`. Outputs `native` (grid size), `preview` (scaled), `report`. |
- | `pixel.cutout` | Removes a background (`chroma`, `flat`, or `luma`) into hard alpha. Optional `grid` snaps first so alpha is per logical pixel. Trims, drops specks. Outputs `cutout` (RGBA) and `report`. |
- | `pixel.strip` | Aligns ordered cutout poses, snaps them to one shared grid and palette, and writes a strip plus `am-sprite` metadata. |
+ ## Other entrypoints
- ## Choosing a grid
+ | Action | Use |
+ | --- | --- |
+ | `pixel.snap` | Snap one image to its drawn lattice (`auto_grid: true`) or an explicit grid; optional palette and nearest-neighbour preview. A grid over 20% coarser than the detected art is refused unless `allow_lossy: true`. |
+ | `pixel.cutout` | Remove chroma, flat, or light background into hard alpha. `grid: "auto"` snaps first; `trim` defaults true. `holes: true` also removes enclosed key colour. |
+ | `pixel.strip` | Align two or more frame handles on a common cell and join them horizontally for `am-sprite`. |
- - Already-pixelated sprite on an exact lattice (for example a 4x upscale): `auto_grid: true`.
- - gpt-image output: the blocks are non-integer, so auto detection is often
- unreliable. Pick the grid from the sprite's block size, for example 1254 px ÷ 26.1 px
- = 48 cells. The `report.grid.*.hint` field of an `auto_grid` run suggests a block size.
- - Use `fit: none` when the grid already matches the aspect; `contain` for cutouts so
- the whole subject survives.
+ When auto detection cannot establish a square lattice, the error reports the
+ best block hint and an explicit grid recovery. If x and y runs differ, the
+ report says so and uses their joint square estimate; inspect the preview.
+ An intentional coarse conversion needs `allow_lossy: true`, and its report
+ records the override. Prefer regenerating at the target density.