Claude
Skills
Sign in
Back

msw-painter

Included with Lifetime
$97 forever

When msw-search cannot find a suitable sprite RUID, draw a pixel art sprite directly with SVG / HTML5 Canvas / HTML code, render it to PNG, and upload it via msw-mcp `asset_create_resource_storage_item` to obtain a sprite RUID. Two style modes are supported: chunky pixel (retro / icon / tile feel) and maple cartoon (MapleStory-inspired character / NPC feel). Triggers: draw sprite directly, create sprite, image generation, custom graphic, pixel art, cartoon sprite, maple style, chibi character, painter, draw a sprite, make an icon, create NPC image directly, draw a slime, custom sprite.

Image & Videoscripts

What this skill does


# MSW Painter

A workflow for registering a hand-drawn pixel art sprite as a sprite resource. **Call `msw-search` first, and only invoke this skill when no suitable RUID is found.**

This skill is dedicated to the sprite category. It does not handle animation / audio / avatar / atlas.

The painter supports two pixel art **styles**: **chunky pixel** (retro, icon/tile feel) and **maple cartoon** (MapleStory-inspired, character/NPC feel). Pick one before writing code — see step 2 below.

---

## When to invoke

| Situation | Action |
|-----------|--------|
| User wants a specific sprite | First use `msw-search` (Resource search section, sprite category) |
| `msw-search` returns an RUID that matches the intent | Use that RUID directly. **Do not invoke painter.** |
| No search results, or all results are unsuitable | Invoke painter → create directly |
| User explicitly says "I need a hand-drawn looking character/icon" | Invoke painter directly |

---

## Workflow

1. **Choose the medium** — One of SVG / Canvas / HTML. See "Choosing the medium" below.
2. **Choose the style** — `chunky` or `maple`. See "Choosing the style" below.
3. **Decide the size** — See [references/size-guide.md](references/size-guide.md). Default is 128×128.
4. **Write the code** — Follow the rules for the chosen style:
   - `chunky` → [references/style-chunky-pixel.md](references/style-chunky-pixel.md)
   - `maple` → [references/style-maple-cartoon.md](references/style-maple-cartoon.md)
5. **Render to PNG** — Run `scripts/render.cjs`.
6. **Upload the resource** — `mcp__msw-mcp__asset_create_resource_storage_item` two-step pattern.
7. **Report the result** — RUID + a 1–2 sentence description (include which style was used). Entity placement / script application is outside the painter's scope.

---

## 1. Choosing the medium

| Medium | Recommended use | Strengths |
|--------|-----------------|-----------|
| **SVG** | Icons, logos, simple characters, shape-based pixel art | Intuitive code, easy to drop 1px `<rect>` dots |
| **Canvas** | Procedural patterns, iterative logic (loop-drawn textures / noise) | Generate complex patterns via JS programming logic |
| **HTML** | Composite layouts that can be styled quickly with CSS | Rarely used — SVG/Canvas is usually a better fit for pixel art |

### Minimal SVG template

```xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
     width="100%" height="100%" preserveAspectRatio="xMidYMid meet"
     style="image-rendering: pixelated;">
  <rect x="6" y="2" width="1" height="1" fill="#4A90D9"/>
  <!-- Place dots one by one with 1px rects -->
</svg>
```

> ⚠️ Use `width="100%" height="100%"` (NOT a fixed pixel count). The SVG element draws at its **own** declared size inside the render.cjs viewport — if you hard-code 128 but render at `--width 1024`, the SVG fills only the top-left 128px and the rest of the PNG is transparent. `100%` makes the SVG fill whatever canvas `--width`/`--height` specifies.

### Minimal Canvas template

```javascript
// `c` (canvas element) and `ctx` (2D context) are auto-exposed by render.cjs.
// ctx.imageSmoothingEnabled = false is applied automatically as well.
// IMPORTANT: derive scale from c.width, not a hard-coded constant — otherwise
// a different --width leaves the bottom-right of the canvas blank.
const GRID = 16;
const scale = c.width / GRID;  // 16×16 logical grid → canvas-sized output
ctx.fillStyle = '#4A90D9';
ctx.fillRect(6 * scale, 2 * scale, scale, scale);
```

### Minimal HTML template

```html
<!doctype html>
<html><body style="margin:0; image-rendering: pixelated;">
  <!-- Anything you like -->
</body></html>
```

---

## 2. Choosing the style

| Style | Recommended use | Look & feel | Logical grid | Outline | Shading |
|-------|-----------------|-------------|--------------|---------|---------|
| **`chunky`** | Icons, buttons, tiles, blocks, simple props | Retro / 8-bit / NES-SNES | Small (16×16, 32×32) | Black or white, 1px | 2–4 stepped levels, NO AA |
| **`maple`** | Characters, NPCs, monsters, cute mascots | MapleStory / storybook / cartoon | Larger (32×32 ~ 128×128) | **Selout** (darker version of fill color) | 4–6 stepped levels + **selective AA** on silhouette + optional 2×2 dithering |

### Defaults when in doubt

- Icon / button / tile / block → **`chunky`**
- Character / NPC / monster / mascot / "cute" requests / "draw a slime" → **`maple`**
- User says "retro" / "8-bit" / "NES" / "minimal" → **`chunky`**
- User says "MapleStory" / "cute" / "cartoon" / "chibi" / "illustrated" → **`maple`**

Full per-style rules:
- [references/style-chunky-pixel.md](references/style-chunky-pixel.md)
- [references/style-maple-cartoon.md](references/style-maple-cartoon.md)

Both styles share the same forbidden APIs (no curve APIs, no gradient APIs, no fractional coordinates, no `filter: blur`/`drop-shadow`). They differ in palette richness, outline color, AA, and working grid.

---

## 3. Size guide (summary)

| Use | Recommended size |
|-----|------------------|
| Icon / button | 48×48 ~ 64×64 |
| Character / item / NPC / monster | 96×96 ~ 128×128 |
| Tile / floor / block | 64×64 ~ 128×128 |
| Background / large object | 256×256 or larger (only on explicit request) |

The default is **128×128**. For style-specific working-grid tables (chunky uses a small logical grid like 16×16; maple uses a larger one like 64×64) and SD character proportions, see [references/size-guide.md](references/size-guide.md).

> If the requested output is **below 64×64**, the `maple` style does not have enough pixels for selout + AA + facial features — either bump the output size to 64+ or fall back to `chunky`.

---

## 4. PNG render — `render.cjs`

### One-time dependency install

```bash
cd scripts && npm ci
```

This installs `puppeteer` (~200MB including headless Chromium) from the committed `package-lock.json`. It is separate from other base skill dependencies, so run this only the first time you use painter.

> 🔒 Use `npm ci`, **not** `npm install`. `npm ci` installs exactly the versions pinned in `package-lock.json` and fails if the lockfile and `package.json` disagree — this is the supply-chain integrity guarantee for W012. Never edit `package-lock.json` by hand; if you need to bump puppeteer, run `npm install puppeteer@<version>` locally and commit the regenerated lockfile.

### Sandboxing & network isolation

`render.cjs` runs the headless Chromium with the OS sandbox **enabled** by default and blocks **all** network requests from the rendered page. The page is also served via a `data:` URL with a strict `Content-Security-Policy` (`default-src 'none'`), and the SVG / HTML input is sanitized to strip `<script>`, `<foreignObject>`, inline `on*` handlers, and non-`data:` URLs. You do not need to do anything to opt in — these protections are always on.

If you are in a constrained environment where Chromium cannot start its sandbox (some CI containers, certain WSL setups), set `PAINTER_DISABLE_SANDBOX=1` before invoking `render.cjs`. **Do not set this on a developer workstation.**

### Invocation

```bash
node scripts/render.cjs --type <svg|canvas|html> --in <code-file> --out <out.png> --width <W> --height <H>
```

Or pass the code via stdin:

```bash
echo "<svg ...>" | node scripts/render.cjs --type svg --out out.png --width 128 --height 128
```

Options:
- `--type`: One of `svg` / `canvas` / `html`. **Required**.
- `--in`: Path to the code file. Omit or use `-` for stdin.
- `--out`: Output PNG path. **Required**.
- `--width` / `--height`: Output pixel size. Default 128.

On success, the absolute path of the output PNG is printed to stdout on a single line and exit code is 0. On failure, the error is printed to stderr and exit code is 1.

The PNG defaults to a transparent background. If you need a background color, draw it explicitly inside the SVG/Canvas/HTML.

---

## 5. Resource upload — two-step pattern

`mcp__msw-mcp__asset_create_resource_storage_item` is called twice.

> 🔒 **Security — handling the presig

Related in Image & Video