Skip to main content
Glama
README.md
# mc-asset

[![CI](https://img.shields.io/github/actions/workflow/status/smile-minecraft/mc-asset/ci.yml?branch=main)](https://github.com/smile-minecraft/mc-asset/actions/workflows/ci.yml)
[![Release](https://img.shields.io/github/v/release/smile-minecraft/mc-asset)](https://github.com/smile-minecraft/mc-asset/releases)
[![License](https://img.shields.io/github/license/smile-minecraft/mc-asset)](https://github.com/smile-minecraft/mc-asset/blob/main/LICENSE)
[![npm](https://img.shields.io/npm/v/mc-asset)](https://www.npmjs.com/package/mc-asset)

[English](https://github.com/smile-minecraft/mc-asset/blob/main/README.md) | [繁體中文](https://github.com/smile-minecraft/mc-asset/blob/main/README.zh-TW.md) | [简体中文](https://github.com/smile-minecraft/mc-asset/blob/main/README.zh-CN.md)

![mc-asset banner](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/banner.png)

`mc-asset` is a texture and model tool for Minecraft Java Edition resource packs, built for both creators and AI agents over the command line (CLI) or MCP.

Language models can't place pixels by eye, so `mc-asset` turns texture work into text and commands: draw a sprite as a character grid, pixelize reference art, generate tiling textures, pack animation sheets, preview cuboid models, and validate a whole resource pack, from a shell or over MCP. The same input and seed always produce identical files.

![A sword, pickaxe, apple, potion, sapphire, and key, each a 16×16 sprite in the vanilla style](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/items.png)

*Six 16×16 items, each written as a text grid and drawn by `mc-asset render` (shown ×6), following the vanilla style rules in the [`minecraft-pixel-art`](https://github.com/smile-minecraft/mc-asset/tree/main/skills/minecraft-pixel-art) skill. The grids are in [`docs/assets/showcase/items/`](https://github.com/smile-minecraft/mc-asset/tree/main/docs/assets/showcase/items).*

---

## Contents

- [What It Does](#what-it-does)
- [Highlights](#highlights)
- [Showcase](#showcase)
- [Installation](#installation)
- [For AI agents](#for-ai-agents)
- [Quickstart](#quickstart)
- [Practical Recipes](#practical-recipes)
- [MCP Server](#mcp-server)
- [Command Reference](#command-reference)
- [Batch Operations (`--operations`)](#batch-operations---operations)
- [Architecture & Reliability Guarantees](#architecture--reliability-guarantees)
- [Development](#development)
- [License](#license)

---

## What It Does

- Draw textures from text character grids (`render`)
- Downsample reference art into pixel art (`pixelize`) and reduce colors (`quantize`)
- Fan one sprite out into material variants (`variant`)
- Generate and seam-check tiling textures (`generate`, `tile`)
- Pack animation sprite sheets and write `.mcmeta` files (`animate`, `mcmeta`)
- Scale GUI sprites with nine-slice borders (`gui-scale`)
- Compare two PNGs pixel by pixel (`compare`)
- Validate a single texture or a whole resource pack (`validate`, `validate-pack`)
- Losslessly compress PNGs (`optimize`)
- Create, validate, and preview Java block models (`model`)
- Author complete resource packs from declarative recipes, audit styles, catalog vanilla assets, and export reproducible zips (`pack`, `style`)
- Expose all capabilities to AI agents over an MCP server (`mcp`)

---

## Highlights

- **Text in, texture out.** Sprites are character grids (`.grid`) or editable multi-layer sources (`.mcpx`) that build to PNG. See [`docs/mcpx-format.md`](https://github.com/smile-minecraft/mc-asset/blob/main/docs/mcpx-format.md).
- **Identical output.** No unseeded randomness and integer-only color blending, so PNG and `.mcpx` output is identical run to run and between Bun and Node.
- **One engine, two front ends.** The CLI and the stdio MCP server call the same core, so an agent gets the exact same result as a shell script.
- **Uniform JSON output.** `--json` always returns `{ success, result, error }` with a stable error code, and logs never mix into stdout data.
- **No surprise writes.** Every output path is explicit, existing files need `--force`, and each file is written to a temp file before being renamed into place.

---

## Showcase

Every image below is produced by `mc-asset` itself, with fixed seeds for the generated textures, so the whole set is reproducible. The commands live in [`docs/assets/showcase/README.md`](https://github.com/smile-minecraft/mc-asset/blob/main/docs/assets/showcase/README.md).

| Pixelize | Quantize |
|---|---|
| ![pixelize before](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/pixelize-before.png) → ![pixelize after](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/pixelize-after.png) | ![quantize before](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/quantize-before.png) → ![quantize after](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/quantize-after.png) |
| A detailed reference image (128px, shown ×2) reduced to 16px (shown ×16): the grain coarsens and shapes snap to a tidy pixel grid. | A 64-color gradient reduced to 8 colors (both ×4): the color count drops and the result settles into clear steps. |

**Material variants** — the sword from the top of this page fanned out into all nine built-in materials (`copper`, `crystal`, `diamond`, `gold`, `iron`, `netherite`, `oxidized_copper`, `stone`, `wood`, shown ×5). Its palette gives each color a role, so the blade and guard take the new ramp while the darkest outline, the white glint, the wooden grip, and the guard's gem keep their colors:

![the sword recolored into nine materials](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/variants.png)

**Generated patterns** — every `generate` pattern as a 16px swatch from a fixed seed (shown ×4):

| `noise` | `clustered-noise` | `stripes` | `checker` | `gradient` |
|:-:|:-:|:-:|:-:|:-:|
| ![noise](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/patterns/noise.png) | ![clustered-noise](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/patterns/clustered-noise.png) | ![stripes](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/patterns/stripes.png) | ![checker](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/patterns/checker.png) | ![gradient](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/patterns/gradient.png) |
| `brick` | `spots` | `veins` | `cracks` | `grain` |
| ![brick](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/patterns/brick.png) | ![spots](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/patterns/spots.png) | ![veins](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/patterns/veins.png) | ![cracks](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/patterns/cracks.png) | ![grain](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/patterns/grain.png) |

**Seamless tiling** — a 16px brick block face (left, ×8) and a 4×4 wall of it (right, ×4); the mortar lines continue across every edge:

![tile source](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/tile-pattern.png) ![4x4 tiled wall](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/tile-preview.png)

**Block textures** — stone, dirt, and oak planks as 16×16 textures (left, ×8) that tile cleanly across all four edges. On the right is a 4×4 wall of the planks texture (×4):

![three block faces](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/blocks.png) ![4x4 planks wall](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/blocks-wall.png)

**Animation sheet** — four frames of a glowing ore block packed into one vertical strip (×4), the layout Minecraft reads with an `.mcmeta` animation:

![animation sprite sheet](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/anim-sheet.png)

**Potion variants and compare** — the potion recolored into `crystal`, `gold`, and `iron` (×5) while the glass bottle, wooden cork, and white glint keep their colors; `compare` of the iron and gold variants finds 72 changed liquid pixels, marked in magenta on the diagnostic (×8):

![the potion recolored into three materials](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/potion-variants.png) ![compare diagnostic of two potion variants](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/compare-diff.png)

**Button nine-slice** — a 16px button frame (left, ×4) scaled to 48×16 with nine-slice (middle, ×4) and with plain stretch (right, ×4); the nine-slice keeps the corners and bevels crisp while the stretch smears them:

![button source](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/gui/button.png) ![button nine-slice result](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/gui/button-nine-slice.png) ![button stretched result](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/gui/button-stretch.png)

**Java model three-view preview** — a five-cuboid stepped shrine model ([`model-shrine.json`](https://github.com/smile-minecraft/mc-asset/blob/main/docs/assets/showcase/model-shrine.json)) using the brick, planks, stone, and glowing ore textures shown above. `model preview --size 128` looks at it three times: from the front (north, `front`), from the side (east, `right`), and from above (`top`):

![three-view diagnostic preview of a stepped shrine block model](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/model-preview.png)

---

## Installation

### Via npm (recommended)

Run the server straight from the registry — no local install needed:

```sh
npx -y mc-asset mcp
```

Install the CLI globally to get the `mc-asset` command on your PATH:

```sh
npm install -g mc-asset
mc-asset --version
```

### Via Homebrew (macOS / Linux)

```sh
brew tap smile-minecraft/tap
brew install smile-minecraft/tap/mc-asset
mc-asset --version
```

### Via Bun or Node.js (From Source)

```sh
git clone https://github.com/smile-minecraft/mc-asset.git
cd mc-asset
bun install --frozen-lockfile
bun run build
./bin/mc-asset.js --version
```

*Prerequisites*: tested with [Node.js](https://nodejs.org) 22 and [Bun](https://bun.sh) 1.3. `bun run build` needs Bun and `./bin/mc-asset.js` needs Node.js; with Bun alone, run `bun ./bin/mc-asset.js`.

---

## For AI agents

- [`llms.txt`](https://github.com/smile-minecraft/mc-asset/blob/main/llms.txt) — a compact index of the repository for agents.
- [`llms-full.txt`](https://github.com/smile-minecraft/mc-asset/blob/main/llms-full.txt) — the same material as a single file: install, the twenty-five MCP tools, batch operations, the error model, and the limits.
- [`docs/cli-surface.md`](https://github.com/smile-minecraft/mc-asset/blob/main/docs/cli-surface.md) — the frozen CLI commands, the batch operations specification, and the exit-code registry.
- [`docs/mcpx-format.md`](https://github.com/smile-minecraft/mc-asset/blob/main/docs/mcpx-format.md) — the editable multi-layer `.mcpx` and `.grid` grammar and specification.
- [`docs/mcp-guide.md`](https://github.com/smile-minecraft/mc-asset/blob/main/docs/mcp-guide.md) — registration, one verbatim capture per MCP tool, and the error model.
- [`docs/mcp-surface.md`](https://github.com/smile-minecraft/mc-asset/blob/main/docs/mcp-surface.md) — the frozen MCP surface: tool names, inputs, and the read/write contract.
- [`AGENTS.md`](https://github.com/smile-minecraft/mc-asset/blob/main/AGENTS.md) — the rules for changing this repository.

### Agent skills

The repository ships two [Agent Skills](https://skills.sh/) in [`skills/`](https://github.com/smile-minecraft/mc-asset/tree/main/skills), installable with the skills CLI:

```sh
npx skills add smile-minecraft/mc-asset
```

- [`mc-asset`](https://github.com/smile-minecraft/mc-asset/tree/main/skills/mc-asset) — the draw → render → preview → measure → validate loop with this tool, the CLI/MCP command map, and how palette roles drive recoloring.
- [`minecraft-pixel-art`](https://github.com/smile-minecraft/mc-asset/tree/main/skills/minecraft-pixel-art) — the vanilla style rules for items, blocks, GUI sprites, and animations: palettes and hue-shifted ramps, material outlines, top-left light, tiling, and an anti-pattern review checklist.

Add `--skill mc-asset` or `--skill minecraft-pixel-art` to install only one.

---

## Quickstart

### From a Text Grid to a Validated Texture

Draw a 16×16 gem as a character grid, one character per pixel:

```sh
mkdir -p /tmp/mc-asset-demo
cat << 'EOF' > /tmp/mc-asset-demo/gem.grid
[palette]
. = transparent
o = #0E1846FF
s = #1E3A8CFF
D = #2448A8FF
m = #3569D0FF
l = #5A92EEFF
t = #7FB2F6FF
T = #A9D2FFFF
W = #FFFFFFFF

[grid]
................
................
......sssss.....
.....sTTTTTo....
....sTTWWTTto...
...sTTWWTTttto..
..slllTTTtttmmo.
..slllllmmmmmDo.
..slllllmmmmmDo.
..slllllmmmmDDo.
...olllmmmmDDo..
....ollmmmDDo...
.....olmmmDo....
......ommDo.....
.......ooo......
................
EOF
```

Render the grid into a PNG texture and save the editable `.mcpx` source:

```sh
mc-asset render /tmp/mc-asset-demo/gem.grid \
  --output /tmp/mc-asset-demo/gem.png \
  --source /tmp/mc-asset-demo/gem.mcpx
# ok render profile=generic applied=0 output=/tmp/mc-asset-demo/gem.png source=/tmp/mc-asset-demo/gem.mcpx
```

The rendered `gem.png`, shown ×8:

![the rendered gem](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/quickstart-gem.png)

Check its colors and alpha:

```sh
mc-asset analyze /tmp/mc-asset-demo/gem.png
# dimensions: 16x16
# colors: 9
# alpha: predicted cutout (opaque=119 transparent=137 partial=0)
# dominant: #00000000 x137 (0.5352), #3569D0FF x28 (0.1094), #5A92EEFF x24 (0.0938), #0E1846FF x18 (0.0703), #A9D2FFFF x16 (0.0625), #1E3A8CFF x12 (0.0469), #2448A8FF x10 (0.0391), #7FB2F6FF x7 (0.0273)
# profile: predicted profile generic has no Minecraft-specific restrictions.
# palette: colorCount=9 alphaLevels=2 transparent=137 partial=0
# pixel-art: 16x16 aspect=1:1 isolated=0 semiTransparent=0 tileFriendly=true
# recommended: quantize.colors=16 cleanup=none resize=nearest
```

Validate it as a Minecraft item texture:

```sh
mc-asset validate /tmp/mc-asset-demo/gem.png --profile minecraft:item
# verdict: pass
# dimensions: 16x16
# colors: 9
# alpha: predicted cutout (opaque=119 transparent=137 partial=0)
# profile: predicted profile minecraft:item prefers the items atlas without mipmaps.
```

---

## Practical Recipes

### Recipe 1: Downsampling Reference Art (`pixelize`)

Turn a high-resolution reference image into a 16×16 item texture. The same image and preset always give the same pixels:

```sh
mc-asset pixelize reference.png \
  --size 16 \
  --preset item \
  --profile minecraft:item \
  --output item_texture.png
```

- `--preset item` sets a 16-color budget and turns on the crop, background, subject, edge, and cluster stages.
- The other presets are `block`, `gui`, `particle`, and `generic`.

### Recipe 2: Procedural Textures & Seam Tiling (`generate` & `tile`)

Generate a stone texture from a fixed seed, then check whether it tiles:

```sh
mc-asset generate noise \
  --size 16 \
  --palette stone \
  --seed 42 \
  --output stone.png

# Seam scores: horizontal, vertical, corner (lower is smoother)
mc-asset tile stone.png
# ok tile profile=generic seam=h:0.065196 v:0.096051 c:0.003604 repeat=0.908038

# Match the opposite edges and preview a 4x4 repeat
mc-asset tile stone.png \
  --edge-match both \
  --preview 4x4 \
  --output stone_preview.png
```

### Recipe 3: Palette Quantization & Artifact Cleanup (`quantize` & `cleanup`)

Cut a sprite down to 8 colors, then remove the stray pixels left behind:

```sh
mc-asset quantize sprite.png --colors 8 --output quantized.png

mc-asset cleanup quantized.png \
  --fix isolated,noise \
  --allow-render-pass-change \
  --output clean.png
```

These fix classes can change alpha, and with it the render pass the texture needs, so `cleanup` refuses them without `--allow-render-pass-change`.

### Recipe 4: Material Variants (`variant` & `recolor`)

Fan one source out into several material tiers, or recolor it to a single
material. The source can be an editable `.mcpx` or a flat PNG (a PNG
carries no palette roles, so its pixels map by integer luminance bands
with no invented layer roles):

```sh
mc-asset variant sword.mcpx \
  --materials iron,copper,gold \
  --output-dir ./dist_variants \
  --mkdir
# Writes sword_iron.png, sword_iron.mcpx, sword_copper.png, etc.

mc-asset recolor sword.mcpx --material gold --output sword_gold.png
```

### Recipe 5: Animated Sprite Sheets (`animate`)

Pack a folder of frames into a vertical sheet, then check it against its `.mcmeta`:

```sh
mc-asset animate pack \
  --frames-dir ./textures/fire_frames \
  --layout vertical \
  --output ./textures/fire.png

mc-asset validate ./textures/fire.png --mcmeta ./textures/fire.png.mcmeta
```

### Recipe 6: Full Resource Pack Validation (`validate-pack`)

Scan a whole resource pack for missing textures, bad namespaces, orphaned textures, broken model references, and reference cycles. `--minecraft-version` picks the pack format to check against:

```sh
mc-asset validate-pack ./MyResourcePack \
  --minecraft-version 26.3 \
  --json
```

### Recipe 7: Batch Edits with Visual Feedback (`build` & `apply_asset_operations`)

Edit the Quickstart gem in one batch: a 4×4 gold square framed by a 6×6 black outline. The CLI applies the batch and writes a PNG:

```sh
cat << 'EOF' > /tmp/mc-asset-demo/ops.json
[
  { "type": "fillRect", "rect": { "x": 6, "y": 6, "width": 4, "height": 4 }, "color": "#FFD700FF" },
  { "type": "drawRect", "rect": { "x": 5, "y": 5, "width": 6, "height": 6 }, "color": "#000000FF" }
]
EOF

mc-asset build /tmp/mc-asset-demo/gem.mcpx \
  --operations /tmp/mc-asset-demo/ops.json \
  --output /tmp/mc-asset-demo/gem_modified.png
# ok build profile=generic applied=2 output=/tmp/mc-asset-demo/gem_modified.png
```

Before and after the batch (both ×8):

![gem before the batch](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/quickstart-gem.png) → ![gem after the batch](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/batch-edit-gem.png)

Over MCP, `apply_asset_operations` runs the same batch and can send back a picture of what changed:

```json
{
  "sourcePath": "/tmp/mc-asset-demo/gem.mcpx",
  "operations": [
    { "type": "fillRect", "rect": { "x": 6, "y": 6, "width": 4, "height": 4 }, "color": "#FFD700FF" },
    { "type": "drawRect", "rect": { "x": 5, "y": 5, "width": 6, "height": 6 }, "color": "#000000FF" }
  ],
  "outputPngPath": "/tmp/mc-asset-demo/gem_feedback.png",
  "feedback": { "image": "changed", "scale": 8, "diff": "summary" }
}
```

With `feedback`, the result keeps its usual fields and adds a PNG image block cropped to the changed area and upscaled by `scale` (1–16), plus a `diff` summary (`raw`, `composited`, `structural`, `outsideSelectionUnchanged`). An edit with no visible change returns `noVisibleChange` instead of an image. The agent sees its edit without pulling the whole canvas. The output path differs from the CLI run because MCP tools never overwrite an existing file.

### Recipe 8: Nine-Slice GUI Scaling (`gui-scale`)

Resize a GUI frame without smearing its border. With `nine_slice`, the corners copy 1:1 and the edges and center tile (or stretch, with `stretch_inner: true`). The 16×16 `dialog.png` declares a 4px border in `dialog.png.mcmeta`:

```json
{ "gui": { "scaling": { "type": "nine_slice", "width": 16, "height": 16, "border": 4 } } }
```

```sh
mc-asset gui-scale ./textures/gui/dialog.png \
  --mcmeta ./textures/gui/dialog.png.mcmeta \
  --size 48x32 \
  --output ./textures/gui/dialog_large.png
# ok gui-scale profile=generic size=48x32 scaling=nine_slice output=./textures/gui/dialog_large.png
```

`gui-scale` never picks up a sibling `.mcmeta` on its own; without `--mcmeta` it stretches the whole sprite.

| Source, 16×16 | `nine_slice`, 48×32 | No `--mcmeta` (stretch), 48×32 |
|:-:|:-:|:-:|
| ![dialog source](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/gui/dialog.png) | ![nine-slice result](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/gui/nine-slice.png) | ![stretched result](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/gui/stretch.png) |

All three are shown ×4. With the mcmeta the cut corners and the 2px bevels copy 1:1 and keep their width; the plain stretch thickens the bevels unevenly and smears the corners.

### Recipe 9: Lossless PNG Optimization & Java Models (`optimize` & `model`)

`optimize` re-encodes PNGs into the smallest encoding that holds the same pixels exactly, or keeps the source when nothing is smaller. It takes explicit PNG paths (up to 256 files) or a whole directory (`--input-dir`, up to 4096 PNGs, optional `--recursive`, preserving relative paths). It never rewrites its inputs; pick `--output`, `--output-dir`, `--stdout`, or `--dry-run`.

```sh
mc-asset optimize ./gem.png --dry-run
# ok optimize input=./gem.png output=- status=optimized source=184 result=102 mode=rgba
mc-asset optimize ./gem.png ./sword.png --output-dir ./optimized --mkdir
mc-asset optimize --input-dir ./textures --recursive --output-dir ./optimized --mkdir
```

`model` works on Java block/item model JSON (cuboid `elements` only). Create a model, edit it with typed operations, and validate it against a pack:

```sh
mc-asset model create --spec ./docs/assets/showcase/model-shrine.json \
  --output ./pack/assets/mypack/models/block/shrine.json --mkdir --resource-pack-version 75
mc-asset model validate ./pack/assets/mypack/models/block/shrine.json \
  --pack ./pack --resource-pack-version 75
mc-asset validate-pack ./pack --resource-pack-version 75
```

`model apply` takes `--operations` and applies all of them or none; `model export` places the model and, with `--binding`, writes an item definition and a blockstate next to it. The checks cover structure and reference validity. No Minecraft client renders the result, so appearance and in-game behavior are not verified.

`model preview` renders a fixed diagnostic image from cuboid `elements`: three square panels side by side (`front` = north face, `right` = east face, `top` = up face with north at the top), each `--size` pixels (64, 128, or 256; default 64):

```sh
mc-asset model preview ./pack/assets/mypack/models/block/shrine.json \
  --pack ./pack --size 128 --output ./shrine-preview.png --resource-pack-version 75
```

![three-view diagnostic preview of a stepped shrine block model](https://raw.githubusercontent.com/smile-minecraft/mc-asset/main/docs/assets/showcase/model-preview.png)

Exactly one of `--output` or `--stdout` is required. The report carries panel names and coordinates, the input range, `coverage`, and `warnings`. A missing texture renders as a fixed checkerboard with a warning; element rotation, non-1/256 coordinates, translucent faces, and unresolvable textures are listed as `partial` coverage. `display` transforms and game lighting are not applied: this is a diagnostic view, not a game renderer.

---

## MCP Server

`mc-asset mcp` starts a stdio MCP server on the same core as the CLI, so a tool call and the matching command return the same result. It exposes 27 tools.

### Exposed MCP Tools

| Tool | Capability |
|---|---|
| `analyze_asset` | Read-only inspection: dimensions, palette distribution, alpha classification, pixel-art heuristics. |
| `pixelize_asset` | Converts raster inputs (PNG, JPEG, WebP) into pixel art; returns PNG bytes or `.mcpx` source. |
| `render_pixel_asset` | Compiles inline ASCII grid strings or `.grid` files with optional batch operations. |
| `apply_asset_operations`| Applies atomic batch pixel/layer/region mutations to `.mcpx` text. |
| `recolor_asset` | Remaps texture palettes to built-in material ramps (`iron`, `gold`, `stone`, etc.). |
| `create_variants` | Fans out a source asset into per-material variants in an output directory. |
| `validate_asset` | Checks single texture and `.mcmeta` conformance against Minecraft requirements. |
| `import_asset` | Decodes raster inputs (PNG, JPEG, WebP) into the pixel canvas with an optional batch. |
| `build_asset` | Builds `.mcpx` sources into PNG bytes or re-serialized source with an optional batch. |
| `transform_asset` | Applies one geometry operation (flip, rotate, crop, pad, resize, translate) to a raster or `.mcpx` input. |
| `scale_gui_asset` | Scales a GUI sprite with the mcmeta stretch/tile/nine_slice mapping; PNG only. |
| `quantize_asset` | Reduces distinct colors to a target count or an explicit palette, keeping chosen RGBA colors. |
| `cleanup_asset` | Detects or fixes pixel defects (`isolated`, `noise`, `cluster`, `fringe`, `outlier`, `hole`, `aa`). |
| `palette_asset` | Read-only palette `extract` / `inspect` reports (unique colors, distribution, roles, contrast). |
| `material_asset` | Read-only `list` / `show` reports over the built-in material set. |
| `tile_asset` | Seam, edge-repetition, and brightness analysis with an optional tiled preview PNG. |
| `generate_asset` | Deterministic procedural texture generation (pattern, size, palette, seed). |
| `preview_asset` | `ascii` / `palette-map` reports, `scale` and `nine-slice` guide PNGs. |
| `mcmeta_asset` | Generate animation or GUI scaling metadata from PNG. |
| `animate_asset` | Animation `pack` / `unpack` / `reorder` / `resize` / `validate` / `preview` over frame sets. |
| `validate_pack_asset` | Read-only whole-pack scan: namespaces, models, textures, atlases, version targeting. |
| `inspect_asset` | Read-only `structure` (layers, regions, color usage, overlaps) or `view` (composited PNG image block plus metadata); takes `inputPath`. |
| `optimize_asset` | Lossless PNG re-encoding into the smallest exact encoding (or the source kept); per-file report, `dryRun`, explicit `outputPath` / `outputDir`, or whole-directory scan (`inputDir`, `recursive`, 4096 PNG limit). |
| `model_asset` | Java block/item model JSON: `inspect`, `validate`, `create`, `apply`, `export` (with item definition and blockstate bindings), and `preview` (fixed diagnostic three-view PNG via `size` / `outputPngPath`). Reports structure and references, not rendered appearance. |
| `compare_assets` | Compares same-size PNGs; reports raw RGBA and visible differences, bounds, and optional diagnostic diff image. |
| `style_asset` | Style presets, custom style authoring, palette exports, linting, and texture family audits. |
| `pack_asset` | Resource pack projects: scaffolding (`init`), recipe batch builds (`build`), texture cataloging (`catalog`), asset extraction (`extract`), whole-pack check with prioritized fixes (`check`), and reproducible zip packaging (`package`). |

`inspect_asset` has two modes: `structure` reports layers, regions, color usage, and overlaps; `view` returns the composited canvas as a PNG image block, with optional `crop` and `scale` (1–16). A view wider than 1024px is refused with a crop hint instead of being downscaled. `apply_asset_operations` takes an optional `feedback` object ([Recipe 7](#recipe-7-batch-edits-with-visual-feedback-build--apply_asset_operations)); without it the result is unchanged. [`docs/mcp-guide.md`](https://github.com/smile-minecraft/mc-asset/blob/main/docs/mcp-guide.md) has one captured call per tool.

### Configuration

Every client runs the same stdio command, `npx -y mc-asset mcp`. Config file locations change between client versions, so check the client's own docs if one below has moved.

#### Claude Code

```sh
claude mcp add mc-asset -- npx -y mc-asset mcp
```

#### Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "mc-asset": {
      "command": "npx",
      "args": ["-y", "mc-asset", "mcp"]
    }
  }
}
```

#### Cursor

Add to `.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "mc-asset": {
      "command": "npx",
      "args": ["-y", "mc-asset", "mcp"]
    }
  }
}
```

#### OpenCode

Add to `opencode.json` or `opencode.jsonc`:

```jsonc
{
  "mcp": {
    "mc-asset": {
      "type": "local",
      "command": ["npx", "-y", "mc-asset", "mcp"],
      "enabled": true
    }
  }
}
```

---

## Command Reference

| Category | Command | Description |
|---|---|---|
| **Intake & Build** | `import <image>` | Decodes PNG, JPEG, or WebP to PNG and/or `.mcpx`. |
| | `render <grid>` | Compiles ASCII grid (`.grid`) to PNG and/or `.mcpx`. |
| | `build [source]` | Builds `.mcpx` source file or stdin (`--stdin`) to PNG. |
| **Transform & Geometry** | `transform <input>` | Spatial operations: `--flip`, `--rotate`, `--crop`, `--pad`, `--resize`, `--translate`. |
| **Color & Cleanup** | `quantize <input>` | Color reduction to a count (`--colors <N>`) or an explicit palette (`--palette`), with `--keep-color`. |
| | `cleanup <input>` | Artifact removal (`--fix isolated,noise,outlier`). |
| | `palette extract` | Extracts palette from image. |
| | `palette inspect` | Detailed palette analysis and role mapping. |
| | `material list` | Lists built-in Minecraft materials. |
| | `material show` | Shows color ramps for a material. |
| | `recolor <source>` | Remaps `.mcpx` colors using a material ramp. |
| | `variant <source>` | Generates multiple material variants into `--output-dir`. |
| **Generation & Tiles** | `generate <pattern>` | Deterministic procedural texture generation (`--seed <int>`). |
| | `tile <input>` | Seam measurement and automatic tile correction. |
| | `preview <input>` | Visual previews: `--ascii`, `--palette-map`, `--scale <N>`, `--nine-slice`. |
| | `gui-scale <input>` | Scales a GUI sprite to `--size <N\|WxH>` with the mcmeta stretch/tile/nine_slice mapping. |
| **Animation** | `animate pack` | Packs frame directory into sprite sheet. |
| | `animate unpack` | Unpacks sprite sheet into frame directory. |
| | `animate reorder` | Re-sequences animation frames. |
| | `animate resize` | Rescales animation frames. |
| | `animate validate`| Validates frame counts and layout against `.mcmeta`. |
| | `animate preview` | ASCII or diagnostic preview of animation sequence. |
| | `mcmeta animation\|gui` | Generates `.mcmeta` animation or GUI scaling document from PNG dimensions (`--output`, `--stdout`). |
| **Validation** | `analyze <image>` | Read-only metric analysis (colors, alpha, dimensions). |
| | `inspect <input>` | Read-only structure report or composited view (`--mode structure\|view`, `--crop`, `--scale`). |
| | `validate <asset>` | Validates single asset texture and optional `.mcmeta`. |
| | `validate-pack <path>`| Validates entire resource pack root directory. |
| | `compare <before> <after>` | Compares two same-size PNGs; reports raw RGBA and visible differences with optional diagnostic PNG (`--output`, `--stdout`, `--scale`). |
| **Optimization & Models** | `optimize <input...>` or `--input-dir <dir>` | Lossless PNG re-encoding into the smallest exact encoding, or the source bytes kept (`--output`, `--output-dir`, `--stdout`, `--dry-run`, `--mode`, `--ancillary`, `--recursive`). |
| | `model inspect\|validate <file>` | Read-only report on a Java block/item model JSON (structure, UV, rotation, display, references). |
| | `model create\|apply\|export` | Builds, edits, or places a Java model (cuboid `elements`) and its item definition and blockstate. |
| | `model preview <file>` | Fixed diagnostic three-view PNG (`front`, `right`, `top` panels, `--size 64\|128\|256`, `--output` or `--stdout`); partial coverage for unsupported content, never a game render. |
| **Agent Interface** | `mcp` | Starts the stdio MCP server. |

### Generate animation and GUI metadata (`mcmeta`)

```sh
mc-asset mcmeta animation sheet.png --frame-size 16 --frametime 2 --frames '[0,{"index":1,"time":4},0]' --minecraft-version 1.21.2 --output sheet.png.mcmeta
mc-asset mcmeta gui panel.png --type nine_slice --border 4 --stretch-inner --resource-pack-version 42 --stdout
```

- **`animation`**
  - Required: `--frame-size <N|WxH>` (a single row or column of equal frames dividing the PNG; grids are not accepted).
  - Optional: `--frametime <int>` (default `1`), `--frames <json>` (frame indices or `{index,time}` objects with positive integer times), `--interpolate`.
- **`gui`**
  - Required: `--type <stretch|tile|nine_slice>`; `nine_slice` also requires `--border <N|json>` with non-negative `left`, `top`, `right`, `bottom` and a positive center.
  - Optional: `--stretch-inner` (`nine_slice` only). GUI scaling requires pack format `16.0` (`stretch_inner` requires `42.0`); see [`docs/cli-surface.md`](https://github.com/smile-minecraft/mc-asset/blob/main/docs/cli-surface.md) for version gates and output options.

### Compare PNG changes (`compare`)

```sh
mc-asset compare before.png after.png --json
mc-asset compare before.png after.png --output diff.png --scale 4
mc-asset compare before.png after.png --stdout --json > diff.png
```

Compares two same-size PNGs and reports `rawChangedPixels`, `visibleChangedPixels`, `rawBounds`, and `visibleBounds`. With `--output` or `--stdout` (`--scale 1..16`, longest edge at most 1024px), it writes a diagnostic marker PNG where visible changes are magenta (`255,0,255,255`), raw-only alpha-zero RGB changes are cyan (`0,255,255,255`), and unchanged pixels are transparent.

---

## Batch Operations (`--operations`)

The `import`, `render`, and `build` commands support batch pixel edits via `--operations <path>` or `--operations -` (stdin).

```json
[
  { "type": "setPixel", "x": 0, "y": 0, "color": "#FF0000FF" },
  { "type": "drawLine", "from": [0, 0], "to": [15, 15], "color": "#00FF00FF" },
  { "type": "fillRect", "rect": { "x": 2, "y": 2, "width": 4, "height": 4 }, "color": "#FFFF00FF" },
  { "type": "floodFill", "x": 5, "y": 5, "color": "#0000FFFF" },
  { "type": "clearPixel", "x": 0, "y": 0 }
]
```

- **Atomicity**: Execution is all-or-nothing. If an operation fails (e.g. out of bounds), all preceding operations in the batch roll back.
- **Color Values**: Accepts `transparent`, `#RRGGBB`, or `#RRGGBBAA`.
- **Vocabulary**: 25 typed variants, including 9 pixel operations (`setPixel`, `clearPixel`, `drawLine`, `drawRect`, `fillRect`, `floodFill`, `ellipse`, `polygonFill`, `strokeMask`) plus layer, region, `stampRect`, and `regionFromSelection` operations. The full per-type table lives in [`docs/cli-surface.md`](https://github.com/smile-minecraft/mc-asset/blob/main/docs/cli-surface.md).
- **Shapes**: `ellipse` fills or outlines the ellipse inside a `rect`; `polygonFill` takes up to 4096 integer `[x, y]` points (more is `RESOURCE_LIMIT_EXCEEDED`; a self-intersecting ring is `SELF_INTERSECTING_POLYGON`; no holes); `strokeMask` outlines a `source` selection on one layer.
- **Selection**: Pixel operations accept an optional `selection` expression; an empty match refuses the write with `EMPTY_SELECTION` and rolls the batch back.

---

## Architecture & Reliability Guarantees

```text
                  ┌─────────────────────────────────┐
                  │          mc-asset Core          │
                  │  PixelCanvas • IO • Algorithms  │
                  └───────────────┬─────────────────┘
                                  │
                 ┌────────────────┴────────────────┐
                 │                                 │
     ┌───────────▼───────────┐         ┌───────────▼───────────┐
     │     CLI Interface     │         │   Native MCP Server   │
     │  (Terminal & Scripts) │         │  (Stdio Agent Bridge) │
     └───────────────────────┘         └───────────────────────┘
```

### Determinism Model

1. **Byte-Identical PNG Encoding**: Uses fixed deflate levels and filter strategies (`src/io/png.ts`) with pure integer color blending. Output files do not embed timestamps or host metadata.
2. **Seed-Driven PRNG**: Procedural generation relies exclusively on an integer xorshift32 PRNG initialized via `--seed`.
3. **Cross-Runtime Consistency**: Output bytes produced under Bun match bytes produced under Node.js byte for byte for the commands covered by the `scripts/compare-runtime.mjs` matrix.

### File & Channel Safety

- **Atomic Writes**: Every output file is written to a unique temporary file (`.tmp-<pid>-<counter>-<randomhex>-<original name>`) in the target directory and committed via atomic rename.
- **Collision Protection**: Paths are resolved to absolute normalized paths folded with Unicode NFC and case-folding. Aliasing the input without `--in-place` or defining duplicate output targets fails before any bytes land on disk.
- **Channel Isolation**:
  - Without `--stdout`: Human logs route to stdout. With `--json`, a structured `{ success, result, error }` envelope routes to stdout and logs route to stderr.
  - With `--stdout`: Raw artifact bytes exclusively own stdout. Envelope and logs route to stderr.

### Standardized Exit Codes

| Exit Code | Category | Meaning |
|---|---|---|
| **0** | Success | Operation completed successfully. |
| **1** | Internal Error | Unhandled engine failure (`INTERNAL_ERROR`). |
| **2** | Invalid Invocation | Syntax error, conflicting options, missing parameters (`INVALID_ARGUMENT`). |
| **3** | Validation Failure | Engine succeeded, but asset or pack failed validation (`VALIDATION_FAILED`). |
| **4** | Filesystem Error | Output exists without `--force`, missing directory without `--mkdir`, or an unreadable input. |
| **5** | Unsupported / Limit | Unsupported file type, or a size or resource limit exceeded. |

---

## Development

```sh
# Run test suite
bun test

# Run TypeScript type check
bun run test:typecheck

# Run linter
bun run lint

# Build standalone distribution bundles
bun run build

# Verify cross-runtime byte parity (Bun vs Node)
node scripts/compare-runtime.mjs

# Check doc links, anchors, and stray release versions
bun run check:docs
```

---

## License

[MIT](https://github.com/smile-minecraft/mc-asset/blob/main/LICENSE) © 2026 Smile Minecraft Project